#include #include #include #include #include #include #include #include using std::tr1::bind; using std::tr1::placeholders::_1; using std::tr1::shared_ptr; // The toy IR struct Base { virtual void print(std::ostream &) = 0; }; class Variable : public Base { std::string name; public: Variable(const std::string &n) : name(n) {}; const std::string &getName(void) const { return name; } void print(std::ostream &out) { out << getName(); } }; struct NameEqual : public std::binary_function, const std::string &, bool> { bool operator()(shared_ptr var, const std::string &name) { return var->getName() == name; } }; struct SymbolTable { typedef std::list > VariableList; std::list table; shared_ptr lookup(const std::string &name) { VariableList::iterator v = std::find_if(table.back().begin(), table.back().end(), std::tr1::bind(NameEqual(), _1, name)); if (v == table.back().end()) { std::cerr << "Did not find variable " << name << '\n'; return shared_ptr(new Variable(name + "_not_found")); } return *v; } void addVariable(shared_ptr v) { table.back().push_back(v); } }; inline std::ostream &operator<<(std::ostream &o, const SymbolTable::VariableList &vars) { o << "scopeval("; for (SymbolTable::VariableList::const_iterator i = vars.begin(), iend = vars.end(); i != iend; /* NULL */) { o << (*i)->getName(); if (++i != iend) { o << ", "; } } o << ")"; return o; } class Add : public Base { public: typedef shared_ptr child_ptr; private: child_ptr left; child_ptr right; public: Add(child_ptr l, child_ptr r) : left(l), right(r) {}; void print(std::ostream &out) { out << "+ "; left->print(out); out << " "; right->print(out); } }; class Assign : public Base { public: typedef shared_ptr child_ptr; private: child_ptr left; child_ptr right; public: Assign(child_ptr l, child_ptr r) : left(l), right(r) {}; void print(std::ostream &out) { out << "= "; left->print(out); out << " "; right->print(out); } }; // Define grammar struct ConstructExpressionGrammar; struct ConstructStatementGrammar; struct ConstructGrammar; class Domain; // Expression wrapper template struct Wrapper { BOOST_PROTO_EXTENDS(Expr, Wrapper, Domain) }; namespace keyword { struct scope { friend std::ostream& operator<<(std::ostream& sout, scope) { return sout << "scope"; } }; } // Convenience typedefs typedef Wrapper::type> Reference; typedef boost::proto::plus AddRule; typedef boost::proto::assign AssignRule; typedef Wrapper::type> ScopeTerminal; typedef Wrapper > ScopeValueTerminal; typedef boost::proto::subscript< boost::proto::function< ScopeTerminal, ScopeValueTerminal >, ConstructStatementGrammar > ScopeRule; // Semantic Actions struct PassThroughUnary : boost::proto::callable { typedef shared_ptr result_type; result_type operator()(shared_ptr expr) { return expr; } }; // Transform a one-operand node template struct ConstructUnary : boost::proto::callable { typedef shared_ptr result_type; result_type operator()(Child child) { return result_type(new NodeType(child)); } }; // Transform a two-operand node template struct ConstructBinary : boost::proto::callable { typedef shared_ptr result_type; result_type operator()(Child left, Child right) { return result_type(new NodeType(left, right)); } }; // Add a scope struct AddScope : boost::proto::callable { typedef shared_ptr result_type; result_type operator()(shared_ptr symtab, SymbolTable::VariableList &scope) { symtab->table.push_back(scope); return symtab; } }; // Lookup a symbol template struct LookupSymbol : boost::proto::callable { typedef shared_ptr result_type; result_type operator()(shared_ptr symtab, const std::string &name) { return symtab->lookup(name); } }; // Grammar rules struct ConstructExpressionGrammarCases { // The primary template matches nothing: template struct case_ : boost::proto::not_ {}; }; template<> struct ConstructExpressionGrammarCases::case_ : boost::proto::or_< boost::proto::when< Reference, LookupSymbol<>(boost::proto::_data, boost::proto::_value)> > {}; template<> struct ConstructExpressionGrammarCases::case_ : boost::proto::when< AddRule, ConstructBinary< Add, shared_ptr >(ConstructExpressionGrammar(boost::proto::_left), ConstructExpressionGrammar(boost::proto::_right))> {}; struct ConstructExpressionGrammar : boost::proto::switch_ {}; struct ConstructStatementGrammarCases { // The primary template matches nothing: template struct case_ : boost::proto::not_ {}; }; template<> struct ConstructStatementGrammarCases::case_ : boost::proto::when< AssignRule, ConstructBinary< Assign, shared_ptr >(ConstructExpressionGrammar(boost::proto::_left), ConstructExpressionGrammar(boost::proto::_right))> {}; template<> struct ConstructStatementGrammarCases::case_ : boost::proto::when< ScopeRule, PassThroughUnary(ConstructStatementGrammar( boost::proto::_right, boost::proto::_state, AddScope(boost::proto::_data, boost::proto::_value( boost::proto::_right( boost::proto::_left)))))> {}; struct ConstructStatementGrammar : boost::proto::switch_ {}; // General IR grammar. struct ConstructGrammar : boost::proto::or_< ConstructExpressionGrammar, ConstructStatementGrammar> {}; struct Domain : boost::proto::domain > {}; const ScopeTerminal scope = {{}}; template shared_ptr translate(const Expr &expr) { shared_ptr symtab(new SymbolTable); symtab->table.push_back(SymbolTable::VariableList()); // Set up the global scope to resolve references to a, b and c. shared_ptr av(new Variable("a")); shared_ptr bv(new Variable("b")); shared_ptr cv(new Variable("c")); symtab->addVariable(av); symtab->addVariable(bv); symtab->addVariable(cv); ConstructGrammar trans; return trans(expr, 0, symtab); } int main(void) { Reference a = {"a"}; Reference b = {"b"}; Reference c = {"c"}; Reference d = {"d"}; // Set up a 2nd scope level to resolve references to d. shared_ptr dv(new Variable("d")); SymbolTable::VariableList localScope; localScope.push_back(dv); boost::proto::display_expr( a = a + c ); boost::proto::display_expr( scope(boost::proto::lit(localScope)) [ a = a + d ] ); shared_ptr expr = translate( a = a + c ); expr->print(std::cout); std::cout << '\n'; #if 0 expr = translate( scope(boost::proto::lit(localScope)) [ a = a + d ] ); expr->print(std::cout); std::cout << '\n'; #endif return 0; }