Boost logo

Boost Users :

Subject: [Boost-users] concise error messages
From: Manjunath Kudlur (keveman_at_[hidden])
Date: 2010-01-22 17:46:42


Hello,

I wrote a small DSEL with proto. An example program can be found in
the main function below. I use BOOST_MPL_ASSERT_MSG to check an
expression against a grammar, and can make the compiler output a small
string if the syntax is wrong. But I can do it only for the entire
program. Is there a way to do finer grain grammar checking with proto?
For example, I haven't defined the "<" operator for expressions, but
when I use it in the DSEL code, I get 10 pages of error messages from
g++, with the SYNTAX_NOT_CORRECT string somewhere. I would like to get
somewhat more accurate than this. Any pointers?

Thanks,
Manjunath

#include <boost/proto/proto.hpp>
#include <boost/mpl/assert.hpp>

#include <iostream>
#include <sstream>
#include <string>

using namespace boost;
using namespace std;

unsigned int ids;

template<typename VT>
struct Var {
  unsigned int id;
  Var() {
    id = ++ids;
  }
};

struct if_fun {};
struct program {};

struct VarName : proto::callable {
  typedef string result_type;

  template<typename T>
  result_type operator()(const Var<T> &v) {
    stringstream s;
    s << "V" << v.id;
    return string(s.str());
  }

  result_type construct(string &l, string op, string &r) {
    return string(l + op + r);
  }

  result_type operator()(proto::tag::plus, string l, string r) {
    return construct(l, string(" + "), r);
  }
  result_type operator()(proto::tag::minus, string l, string r) {
    return construct(l, string(" - "), r);
  }

  result_type operator()(proto::tag::divides, string l, string r) {
    return construct(l, string(" / "), r);
  }
  result_type operator()(proto::tag::multiplies, string l, string r) {
    return construct(l, string(" * "), r);
  }
  result_type operator()(proto::tag::assign, string l, string r) {
    return string(construct(l, string(" = "), r) + string(";"));
  }
  result_type operator()(const int &x) {
    stringstream s;
    s << x;
    return string(s.str());
  }
  result_type operator()(const if_fun&) {
    return string("if");
  }

  result_type operator()(const program&) {
    return string("program");
  }

  result_type operator()(proto::tag::function, string l, string r) {
    stringstream s;
    s << l << "(" << r << ")";
    return string(s.str());
  }

  result_type operator()(proto::tag::subscript, string l, string r) {
    stringstream s;
    s << l << " [\n";
    s << r;
    s << "\n]\n";
    return string(s.str());
  }

  result_type operator()(proto::tag::comma, string l, string r) {
    stringstream s;
    s << l << "\n";
    s << r;
    return string(s.str());
  }

};

struct napl_grammar;

struct expr_grammar;

struct bb_grammar;

struct if_grammar :
  proto::or_<
  proto::when<proto::terminal<if_fun>, VarName(proto::_value)>,
  proto::when<proto::function<proto::terminal<if_fun>, expr_grammar>,
VarName(proto::tag_of<proto::_expr>(), if_grammar(proto::_left),
expr_grammar(proto::_right))>
> {
};

struct expr_grammar :
  proto::or_<
  proto::when<proto::plus< expr_grammar, expr_grammar>,
VarName(proto::tag_of<proto::_expr>(), expr_grammar(proto::_left),
expr_grammar(proto::_right))>,
  proto::when<proto::minus< expr_grammar, expr_grammar>,
VarName(proto::tag_of<proto::_expr>(), expr_grammar(proto::_left),
expr_grammar(proto::_right))>,
  proto::when<proto::multiplies< expr_grammar, expr_grammar>,
VarName(proto::tag_of<proto::_expr>(), expr_grammar(proto::_left),
expr_grammar(proto::_right))>,
  proto::when<proto::divides< expr_grammar, expr_grammar>,
VarName(proto::tag_of<proto::_expr>(), expr_grammar(proto::_left),
expr_grammar(proto::_right))>,
  proto::when<proto::assign< proto::terminal<Var<int> >,
expr_grammar>, VarName(proto::tag_of<proto::_expr>(),
expr_grammar(proto::_left), expr_grammar(proto::_right))>,
  proto::when<proto::terminal<Var<int> >, VarName(proto::_value)>,
  proto::when<proto::terminal<int>, VarName(proto::_value)>,
  proto::when<proto::subscript<if_grammar, bb_grammar>,
VarName(proto::tag_of<proto::_expr>(), if_grammar(proto::_left),
bb_grammar(proto::_right))>
> {
};

struct bb_grammar :
  proto::or_<
  proto::when<expr_grammar, expr_grammar(proto::_expr)>,
  proto::when<proto::comma<bb_grammar, expr_grammar>,
VarName(proto::tag_of<proto::_expr>(), bb_grammar(proto::_left),
expr_grammar(proto::_right))>
> {
};

struct napl_grammar :
  proto::or_<
  proto::when<proto::terminal<program>, VarName(proto::_value)>,
  proto::when<proto::subscript<proto::terminal<program>, bb_grammar>,
VarName(proto::tag_of<proto::_expr>(), napl_grammar(proto::_left),
bb_grammar(proto::_right))>
> {
};

template<typename Expr>
void check_grammar(const Expr &e)
{
  BOOST_MPL_ASSERT_MSG((proto::matches<Expr, napl_grammar>::value),
                       SYNTAX_NOT_CORRECT,
                       (void));
  cout << napl_grammar()(e) << "\n";
}

template<typename Expr>
void check_if_grammar(const Expr&)
{
  BOOST_MPL_ASSERT_MSG((proto::matches<Expr, if_grammar>::value),
                       IF_SYNTAX_NOT_CORRECT,
                       (if_grammar));
}

template<typename Expr>
void check_expr_grammar(const Expr &e)
{
  BOOST_MPL_ASSERT_MSG((proto::matches<Expr, expr_grammar>::value),
                       EXPR_SYNTAX_NOT_CORRECT,
                       (expr_grammar));

  cout << expr_grammar()(e) << "\n";
}

template<typename Expr>
void check_bb_grammar(const Expr &e)
{
  BOOST_MPL_ASSERT_MSG((proto::matches<Expr, bb_grammar>::value),
                       BB_SYNTAX_NOT_CORRECT,
                       (bb_grammar));

  cout << bb_grammar()(e) << "\n";
}

int main()
{
  proto::terminal<Var<int> >::type i1, i2, i3, i4, i5;
  proto::terminal<program>::type Program;
  proto::terminal<if_fun>::type if_;

  check_grammar(
    Program[
            i2 = 1 + i2,
            i3 = i3 * i3,
            i3=i4/i4,
            i3=i5-23,
            if_(i1) [
                     i2=1, i2,
              if_(i2) [
                i3=1,
                i3=i5,
                if_(i3) [
                  i1=1,
                  i4=42+i4
                ]
              ]
            ]
    ]
   );
  /*
  check_if_grammar(
                   if_(i1));

  check_bb_grammar((i4=i1+i2+42, i2=2, i3=i2/42, if_(i1)[i2=3, i3=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