In the grammar rule when<>, I'm not sure I can make a nested function
type like that. I'm trying to tell the grammar to match the children and
transform them, passing them to the ConstructBinary transformation to
build the Add subtree.
Any help is greatly appreciated. Thanks!
Here is a compilable testcase. Surprisingly, the nested function type seems
to compile. But how can I statically initialize a terminal that refers to a
boost::shared_ptr? I can't statically initialize the shared_ptr. Is there a
way to set a terminal's value after the fact?
-Dave
#include
#include
#include <string>
#include <iostream>
// The toy IR
struct Base {
virtual void print(std::ostream &) = 0;
};
class Reference : public Base {
std::string name;
public:
Reference(const std::string &n) : name(n) {};
const std::string &getName(void) const {
return name;
}
void print(std::ostream &out) {
out << getName();
}
};
class Add : public Base {
typedef boost::shared_ptr<Base> child_ptr;
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);
}
};
// Define grammar
struct ConstructGrammar;
// Convenience typedefs
typedef boost::proto::terminal::type Variable;
typedef boost::proto::plus AddRule;
// Semantic Actions
// Transform a one-operand node
template
struct ConstructUnary : boost::proto::callable {
typedef boost::shared_ptr<NodeType> 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 boost::shared_ptr<NodeType> result_type;
result_type operator()(Child left, Child right) {
return result_type(new NodeType(left, right));
}
};
// Grammar rules
struct ConstructGrammarCases {
// The primary template matches nothing:
template<typename Tag>
struct case_ : boost::proto::not_boost::proto::_ {};
};
template<>
struct ConstructGrammarCases::case_boost::proto::tag::terminal
: boost::proto::or_<
boost::proto::when<
Variable,
boost::proto::_value> > {};
template<>
struct ConstructGrammarCases::case_boost::proto::tag::plus
: boost::proto::when<
AddRule,
ConstructBinary<
Add,
boost::shared_ptr<Base> >(ConstructGrammar(boost::proto::_left),
ConstructGrammar(boost::proto::_right))> {};
struct ConstructGrammar : boost::proto::switch_<ConstructGrammarCases> {};
template<typename Expr>
boost::shared_ptr<Base> translate(const Expr &expr) {
ConstructGrammar trans;
return trans(expr);
}
int main(void)
{
boost::shared_ptr<Base> a(new Reference("a"));
boost::shared_ptr<Base> b(new Reference("b"));
boost::shared_ptr<Base> c(new Reference("c"));
boost::shared_ptr<Base> expr1(new Add(b, c));
boost::shared_ptr<Base> expr2(new Add(a, expr1));
expr2->print(std::cout);
std::cout << '\n';
// How to initialize?
Variable av = {};
Variable bv = {};
Variable cv = {};
// These compile, but don't appear to do anything.
av = new Reference("a");
bv = new Reference("b");
cv = new Reference("c");
boost::shared_ptr<Base> expr3 = translate(av + (bv + cv));
// This faults with a null shared_ptr.
expr3->print(std::cout);
std::cout << '\n';
return 0;
}