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
#include
#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, VarName(proto::_value)>,
proto::when, expr_grammar>,
VarName(proto::tag_ofproto::_expr(), if_grammar(proto::_left),
expr_grammar(proto::_right))>
{
};
struct expr_grammar :
proto::or_<
proto::when,
VarName(proto::tag_ofproto::_expr(), expr_grammar(proto::_left),
expr_grammar(proto::_right))>,
proto::when,
VarName(proto::tag_ofproto::_expr(), expr_grammar(proto::_left),
expr_grammar(proto::_right))>,
proto::when,
VarName(proto::tag_ofproto::_expr(), expr_grammar(proto::_left),
expr_grammar(proto::_right))>,
proto::when,
VarName(proto::tag_ofproto::_expr(), expr_grammar(proto::_left),
expr_grammar(proto::_right))>,
proto::when,
expr_grammar>, VarName(proto::tag_ofproto::_expr(),
expr_grammar(proto::_left), expr_grammar(proto::_right))>,
proto::when, VarName(proto::_value)>,
proto::when,
proto::when,
VarName(proto::tag_ofproto::_expr(), if_grammar(proto::_left),
bb_grammar(proto::_right))>
{
};
struct bb_grammar :
proto::or_<
proto::when,
proto::when,
VarName(proto::tag_ofproto::_expr(), bb_grammar(proto::_left),
expr_grammar(proto::_right))>
{
};
struct napl_grammar :
proto::or_<
proto::when,
proto::when,
VarName(proto::tag_ofproto::_expr(), napl_grammar(proto::_left),
bb_grammar(proto::_right))>
{
};
template<typename Expr>
void check_grammar(const Expr &e)
{
BOOST_MPL_ASSERT_MSG((proto::matches::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::value),
IF_SYNTAX_NOT_CORRECT,
(if_grammar));
}
template<typename Expr>
void check_expr_grammar(const Expr &e)
{
BOOST_MPL_ASSERT_MSG((proto::matches::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::value),
BB_SYNTAX_NOT_CORRECT,
(bb_grammar));
cout << bb_grammar()(e) << "\n";
}
int main()
{
proto::terminal::type i1, i2, i3, i4, i5;
proto::terminal<program>::type Program;
proto::terminal::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]));
*/
}