Boost logo

Boost Users :

Subject: Re: [Boost-users] Proto Help
From: David A. Greene (greened_at_[hidden])
Date: 2009-12-30 23:42:54


> 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 <boost/proto/proto.hpp>
#include <boost/shared_ptr.hpp>

#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<boost::shared_ptr<Reference> >::type Variable;
typedef boost::proto::plus<ConstructGrammar, ConstructGrammar> AddRule;

// Semantic Actions
// Transform a one-operand node
template<typename NodeType,
         typename Child = typename NodeType::child_ptr,
         typename Dummy = boost::proto::callable>
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<typename NodeType,
         typename Child,
         typename Dummy = boost::proto::callable>
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;
}


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net