Boost::Spirit How to Parse and Call C++ Function-Like Expressions

Boost::spirit how to parse and call c++ function-like expressions

Second Answer (more pragmatic)

Here's a second take, for comparison:

Just in case you really didn't want to parse into an abstract syntax tree representation, but rather evaluate the functions on-the-fly during parsing, you can simplify the grammar.

It comes in at 92 lines as opposed to 209 lines in the first answer. It really depends on what you're implementing which approach is more suitable.

This shorter approach has some downsides:

  • less flexible (not reusable)
  • less robust (if functions have side effects, they will happen even if parsing fails halfway)
  • less extensible (the supported functions are hardwired into the grammar1)

Full code:

//#define BOOST_SPIRIT_DEBUG
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/phoenix/function.hpp>

namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;

typedef boost::variant<int, std::string> value;

//////////////////////////////////////////////////
// Demo functions:
value AnswerToLTUAE() {
return 42;
}

value ReverseString(value const& input) {
auto& as_string = boost::get<std::string>(input);
return std::string(as_string.rbegin(), as_string.rend());
}

value Concatenate(value const& a, value const& b) {
std::ostringstream oss;
oss << a << b;
return oss.str();
}

BOOST_PHOENIX_ADAPT_FUNCTION_NULLARY(value, AnswerToLTUAE_, AnswerToLTUAE)
BOOST_PHOENIX_ADAPT_FUNCTION(value, ReverseString_, ReverseString, 1)
BOOST_PHOENIX_ADAPT_FUNCTION(value, Concatenate_, Concatenate, 2)

//////////////////////////////////////////////////
// Parser grammar
template <typename It, typename Skipper = qi::space_type>
struct parser : qi::grammar<It, value(), Skipper>
{
parser() : parser::base_type(expr_)
{
using namespace qi;

function_call_ =
(lit("AnswerToLTUAE") > '(' > ')')
[ _val = AnswerToLTUAE_() ]
| (lit("ReverseString") > '(' > expr_ > ')')
[ _val = ReverseString_(_1) ]
| (lit("Concatenate") > '(' > expr_ > ',' > expr_ > ')')
[ _val = Concatenate_(_1, _2) ]
;
string_ = as_string [
lexeme [ "'" >> *~char_("'") >> "'" ]
];
value_ = int_ | string_;

expr_ = function_call_ | value_;

on_error<fail> ( expr_, std::cout
<< phx::val("Error! Expecting ") << _4 << phx::val(" here: \"")
<< phx::construct<std::string>(_3, _2) << phx::val("\"\n"));

BOOST_SPIRIT_DEBUG_NODES((expr_)(function_call_)(value_)(string_))
}

private:
qi::rule<It, value(), Skipper> value_, function_call_, expr_, string_;
};

int main()
{
for (const std::string input: std::vector<std::string> {
"-99",
"'string'",
"AnswerToLTUAE()",
"ReverseString('string')",
"Concatenate('string', 987)",
"Concatenate('The Answer Is ', AnswerToLTUAE())",
})
{
auto f(std::begin(input)), l(std::end(input));
const static parser<decltype(f)> p;

value direct_eval;
bool ok = qi::phrase_parse(f,l,p,qi::space,direct_eval);

if (!ok)
std::cout << "invalid input\n";
else
{
std::cout << "input:\t" << input << "\n";
std::cout << "eval:\t" << direct_eval << "\n\n";
}

if (f!=l) std::cout << "unparsed: '" << std::string(f,l) << "'\n";
}
}

Note how, instead of using BOOST_PHOENIX_ADAPT_FUNCTION* we could have directly used boost::phoenix::bind.

The output is still the same:

input:  -99
eval: -99

input: 'string'
eval: string

input: AnswerToLTUAE()
eval: 42

input: ReverseString('string')
eval: gnirts

input: Concatenate('string', 987)
eval: string987

input: Concatenate('The Answer Is ', AnswerToLTUAE())
eval: The Answer Is 42

1 This last downside is easily remedied by using the 'Nabialek Trick'

Boost::Spirit expression parser with defined functions

Following sehe suggestions, I added rules for parameters and functions. For function I build 3 lists “qi::symbols” depending on the number of arguments.
The parser works fine.

custom_fold_directive.hpp

namespace custom
{
namespace tag
{
struct fold { BOOST_SPIRIT_IS_TAG() };
}

template <typename Exposed, typename Expr>
boost::spirit::stateful_tag_type<Expr, tag::fold, Exposed>
fold(Expr const& expr)
{
return boost::spirit::stateful_tag_type<Expr, tag::fold, Exposed>(expr);
}

}

namespace boost { namespace spirit
{
template <typename Expr, typename Exposed>
struct use_directive<qi::domain
, tag::stateful_tag<Expr, custom::tag::fold, Exposed> >
: mpl::true_ {};
}}

namespace custom
{
template <typename Exposed, typename InitialParser, typename RepeatingParser>
struct fold_directive
{
fold_directive(InitialParser const& initial, RepeatingParser const& repeating):initial(initial),repeating(repeating){}

template <typename Context, typename Iterator>
struct attribute
{
typedef typename boost::spirit::traits::attribute_of<InitialParser,Context,Iterator>::type type;//This works in this case but is not generic
};

template <typename Iterator, typename Context
, typename Skipper, typename Attribute>
bool parse(Iterator& first, Iterator const& last
, Context& context, Skipper const& skipper, Attribute& attr_) const
{
Iterator start = first;

typename boost::spirit::traits::attribute_of<InitialParser,Context,Iterator>::type initial_attr;

if (!initial.parse(first, last, context, skipper, initial_attr))
{
first=start;
return false;
}

typename boost::spirit::traits::attribute_of<RepeatingParser,Context,Iterator>::type repeating_attr;

if(!repeating.parse(first, last, context, skipper, repeating_attr))
{
boost::spirit::traits::assign_to(initial_attr, attr_);
return true;
}
Exposed current_attr(initial_attr,repeating_attr);

while(repeating.parse(first, last, context, skipper, repeating_attr))
{
boost::spirit::traits::assign_to(Exposed(current_attr,repeating_attr),current_attr);
}
boost::spirit::traits::assign_to(current_attr,attr_);
return true;
}

template <typename Context>
boost::spirit::info what(Context& context) const
{
return boost::spirit::info("fold");
}

InitialParser initial;
RepeatingParser repeating;
};
}

namespace boost { namespace spirit { namespace qi
{
template <typename Expr, typename Exposed, typename Subject, typename Modifiers>
struct make_directive<
tag::stateful_tag<Expr, custom::tag::fold, Exposed>, Subject, Modifiers>
{
typedef custom::fold_directive<Exposed, Expr, Subject> result_type;

template <typename Terminal>
result_type operator()(Terminal const& term, Subject const& subject, Modifiers const&) const
{
typedef tag::stateful_tag<
Expr, custom::tag::fold, Exposed> tag_type;
using spirit::detail::get_stateful_data;

return result_type(get_stateful_data<tag_type>::call(term),subject);
}
};
}}}

main.cpp

#include <boost/mpl/list.hpp>

//#define BOOST_SPIRIT_DEBUG
#include <iostream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include "custom_fold_directive.hpp"

namespace qi = boost::spirit::qi;

// Expression::triop <fun_generic>

// DEFINING TYPES
struct op_not {};
struct op_or {};
struct op_and {};
struct op_xor {};
struct op_equal {};
struct op_unequal {};
struct op_sum {};
struct op_difference {};
struct op_factor {};
struct op_division {};
struct op_power{};
struct op_powerTen{};
struct op_plusSign {};
struct op_minusSign {};
struct op_const {};
struct fun_three{};
struct fun_two{};
struct fun_one{};

namespace Expression{

typedef std::string var;
template <typename tag> struct binop;
template <typename tag> struct unop;
template <typename tag> struct triop;
template <typename tag> struct forop;

/*
* tree structure definition
*/
typedef boost::variant<var,
boost::recursive_wrapper<unop <op_not> >,
boost::recursive_wrapper<binop<op_equal> >,
boost::recursive_wrapper<binop<op_unequal> >,
boost::recursive_wrapper<binop<op_and> >,
boost::recursive_wrapper<binop<op_xor> >,
boost::recursive_wrapper<binop<op_or> >,
boost::recursive_wrapper<binop<op_difference> >,
boost::recursive_wrapper<binop<op_sum> >,
boost::recursive_wrapper<binop<op_factor> >,
boost::recursive_wrapper<binop<op_division> >,
boost::recursive_wrapper<binop<op_power> >,
boost::recursive_wrapper<binop<op_powerTen> >,
boost::recursive_wrapper<unop<op_minusSign> >,
boost::recursive_wrapper<unop<op_plusSign> >,
boost::recursive_wrapper<unop<op_const> >,
boost::recursive_wrapper<binop<fun_one> >,
boost::recursive_wrapper<triop<fun_two> >,
boost::recursive_wrapper<forop<fun_three> >
> expressionContainer;

template <typename tag> struct binop
{
explicit binop(const expressionContainer& l
, const expressionContainer& r)
: oper1(l), oper2(r) { }
expressionContainer oper1, oper2;
};

template <typename tag> struct unop
{
explicit unop(const expressionContainer& o) : oper1(o) { }
expressionContainer oper1;

};

template <typename tag> struct triop
{
explicit triop(const expressionContainer& functionId,
const expressionContainer& l
, const expressionContainer& r)
: oper1(functionId), oper2(l), oper3(r) { }
expressionContainer oper1, oper2, oper3;
};

template <typename tag> struct forop
{
explicit forop(const expressionContainer& functionId,
const expressionContainer& l,
const expressionContainer& m,
const expressionContainer& r)
: oper1(functionId), oper2(l), oper3(m),oper4(r) { }
expressionContainer oper1, oper2, oper3,oper4;
};

struct printer : boost::static_visitor<void>
{
printer(std::ostream& os) : _os(os) {}
std::ostream& _os;

void operator()(const var& v) const { _os << v; }

// Logical
void operator()(const binop<op_and>& b) const { print(" & ", b.oper1, b.oper2); }
void operator()(const binop<op_or >& b) const { print(" || ", b.oper1, b.oper2); }
void operator()(const binop<op_xor>& b) const { print(" | ", b.oper1, b.oper2); }
void operator()(const binop<op_equal>& b) const { print(" == ", b.oper1, b.oper2); }
void operator()(const binop<op_unequal>& b) const { print(" != ", b.oper1, b.oper2); }

//Math operators
void operator()(const binop<op_difference>& b) const { print("-", b.oper1, b.oper2); }
void operator()(const binop<op_sum>& b) const { print("+", b.oper1, b.oper2); }
void operator()(const binop<op_factor>& b) const { print("*", b.oper1, b.oper2); }
void operator()(const binop<op_division>& b) const { print("/", b.oper1, b.oper2); }

//Power Math operators
void operator()(const binop<op_power>& b) const { print("pow", b.oper1, b.oper2); }
void operator()(const binop<op_powerTen>& b) const { printPower("e", b.oper1, b.oper2); }

//unique operators
void operator()(const unop<op_not>& u) const{printUnique("!",u.oper1);}
void operator()(const unop<op_plusSign>& u) const{printUnique("",u.oper1);}
void operator()(const unop<op_minusSign>& u) const{printUnique("-",u.oper1);}
void operator()(const unop<op_const>& u) const{printUnique("",u.oper1);}

// print Functions
void operator()(const forop<fun_three>& b) const { printFunctionThree(b.oper1, b.oper2, b.oper3, b.oper4); }
void operator()(const triop<fun_two>& b) const { printFunctionTwo(b.oper1, b.oper2, b.oper3); }
void operator()(const binop<fun_one>& b) const { printFunctionOne(b.oper1, b.oper2); }

//Printer
void print(const std::string& op, const expressionContainer& l, const expressionContainer& r) const
{
_os << "(";
boost::apply_visitor(*this, l);
_os << op;
boost::apply_visitor(*this, r);
_os << ")";
}

void printUnique(const std::string& op, const expressionContainer& l) const
{
_os << op;
boost::apply_visitor(*this, l);
}
void printPower(const std::string& op, const expressionContainer& l, const expressionContainer& r) const
{
boost::apply_visitor(*this, l);
_os << op;
boost::apply_visitor(*this, r);
}
void printOutSide(const std::string& op, const expressionContainer& l, const expressionContainer& r) const
{
_os << op;
_os << "(";
boost::apply_visitor(*this, l);
_os << ",";
boost::apply_visitor(*this, r);
_os << ")";
}
void printFunctionThree(const expressionContainer& functionId, const expressionContainer& l, const expressionContainer& m, const expressionContainer& r) const
{
boost::apply_visitor(*this, functionId);
_os << "(";
boost::apply_visitor(*this, l);
_os << ',';
boost::apply_visitor(*this, m);
_os << ',';
boost::apply_visitor(*this, r);
_os << ")";
}

void printFunctionTwo(const expressionContainer& functionId, const expressionContainer& l, const expressionContainer& r) const
{
boost::apply_visitor(*this, functionId);
_os << "(";
boost::apply_visitor(*this, l);
_os << ',';
boost::apply_visitor(*this, r);
_os << ")";
}

void printFunctionOne(const expressionContainer& functionId, const expressionContainer& l) const
{
boost::apply_visitor(*this, functionId);
_os << "(";
boost::apply_visitor(*this, l);
_os << ")";
}

};

std::ostream& operator<<(std::ostream& os, const expressionContainer& e)
{ boost::apply_visitor(printer(os), e); return os; }

}

/*
* EXPRESSION PARSER DEFINITION
*/
template <typename It, typename Skipper = boost::spirit::standard_wide::space_type>
struct parserExpression : qi::grammar<It, Expression::expressionContainer(), Skipper>
{
parserExpression() : parserExpression::base_type(expr_)
{
using namespace qi;
using namespace Expression;
using custom::fold;

expr_ = or_.alias();

// Logical Operators
or_ = fold<binop<op_or> >(and_.alias())[orOperator_ >> and_];
and_ = fold<binop<op_and> >(equal_.alias())[andOperator_ >> equal_];
equal_ = fold<binop<op_equal> >(unequal_.alias())[equalOperator_ >> unequal_];
unequal_ = fold<binop<op_unequal> >(sum_.alias())[unequalOperator_ >>sum_];

// Numerical Operators
sum_ = fold<binop<op_sum> >(difference_.alias())[sumOperator_ >> difference_];
difference_ = fold<binop<op_difference> >(factor_.alias())[differenceOperator_ >> factor_];
factor_ = fold<binop<op_factor> >(division_.alias())[factorOperator_ >> division_];
division_ = fold<binop<op_division> >(functions_.alias())[divisionOperator_ >> functions_];
functions_ = (threeArgsFunction>>"(">>funArgs_>>componentOperator_>>funArgs_>>componentOperator_>>funArgs_>>")")[_val= boost::phoenix::construct<Expression::forop <fun_three>>(_1,_2,_3,_4)] ||
(twoArgsFunction>>"(">>funArgs_>>componentOperator_>>funArgs_>>")")[_val= boost::phoenix::construct<Expression::triop <fun_two>>(_1,_2,_3)]||
(oneArgsFunction>>"(">>funArgs_>>")")[_val= boost::phoenix::construct<Expression::binop <fun_one>>(_1,_2)]|not_[_val=_1];

// UNARY OPERATION
not_ = (notOperator_ > param_) [_val = boost::phoenix::construct<Expression::unop <op_not>>(_1)] | param_[_val=_1];
param_= (definedParams >>('(' >> (spectArgs_|vectorArgs_)>>')'))[_val='$'+_1+"("+qi::_2+")"] ||
definedParams[_val='$'+_1]| simple[_val = _1];

funArgs_=((expr_ |var_) |functions_);
simple = (('(' > expr_ > ')') | var_);

var_ = (+qi::char_('0','9') >> -qi::char_('.') >> -(+qi::char_('0','9'))) | ((qi::char_('.') >> +qi::char_('0','9')));
vectorArgs_%=qi::raw[qi::int_ > -(qi::char_(',')>>qi::int_) ];
spectArgs_ %=qi::raw[(qi::int_>>qi::char_(',')>>'*')|(qi::char_('*')>>qi::char_(',')>>qi::int_)];
notOperator_ = qi::char_('!');
andOperator_ = qi::string("&&");
orOperator_ = qi::string("||");
xorOperator_ = qi::char_("^");
equalOperator_ = qi::string("==");
unequalOperator_ = qi::string("!=");
sumOperator_ = qi::char_("+");
differenceOperator_ = qi::char_("-");
factorOperator_ = qi::char_("*");
divisionOperator_ = qi::char_("/");
greaterOperator_ = qi::char_(">");
greaterOrEqualOperator_ = qi::string(">=");
lowerOrEqualOperator_ = qi::string("<=");
lowerOperator_ = qi::char_("<");
componentOperator_=qi::char_(",");

// Defined Function
std::map<std::string, std::string> oneFunctions;
oneFunctions["fun1_1"] = "f11";
oneFunctions["fun1_2"] = "f12";
for(auto const&x:oneFunctions){
oneArgsFunction.add (x.first, x.second) ;
}

std::map<std::string, std::string> twoFunctions;
twoFunctions["fun2_1"] = "f21";
twoFunctions["fun2_2"] = "f22";
for(auto const&x:twoFunctions){
twoArgsFunction.add (x.first, x.second) ;
}

std::map<std::string, std::string> threeFunctions;
threeFunctions["fun3_1"] = "f31";
threeFunctions["fun3_2"] = "f32";
for(auto const&x:threeFunctions){
threeArgsFunction.add (x.first, x.second) ;
}
//defined parameters
std::map<std::string, std::string> paramsList;
paramsList["imf"] = "imf";
paramsList["param"] = "param";
for(auto const&x:paramsList){
definedParams.add (x.first, x.second) ;
}

BOOST_SPIRIT_DEBUG_NODES((expr_)(or_)(xor_)(and_)(equal_)(unequal_)(sum_)(difference_)(factor_)(division_)
(simple)(notOperator_)(andOperator_)(orOperator_)(xorOperator_)(equalOperator_)(unequalOperator_)
(sumOperator_)(differenceOperator_)(factorOperator_)(divisionOperator_)(functions_));

}

private:
qi::rule<It, Expression::var(), Skipper> var_, vectorArgs_, spectArgs_;
qi::rule<It, Expression::expressionContainer(), Skipper> not_
, and_
, xor_
, or_
, equal_
, unequal_
, sum_
, difference_
, factor_
, division_
, simple
, expr_
,plusSign_
,minusSign_
,greater_
,greaterOrEqual_
,lowerOrEqual_
,lower_
,functions_
,param_
,funArgs_;

qi::rule<It, Skipper> notOperator_
, andOperator_
, orOperator_
, xorOperator_
, equalOperator_
, unequalOperator_
, sumOperator_
, differenceOperator_
, factorOperator_
, divisionOperator_
, greaterOperator_
, greaterOrEqualOperator_
,lowerOrEqualOperator_
,lowerOperator_
,componentOperator_;
qi::symbols<char, std::string> twoArgsFunction;
qi::symbols<char, std::string> oneArgsFunction;
qi::symbols<char, std::string> threeArgsFunction;
qi::symbols<char, std::string> definedParams;
};

void parse(const std::string& str)
{
std::string::const_iterator iter = str.begin(), end = str.end();

parserExpression<std::string::const_iterator,qi::space_type> parser;
Expression::expressionContainer expr;

bool result = qi::phrase_parse(iter,end,parser,qi::space, expr);

if(result && iter==end)
{
std::cout << "Success." << std::endl;
std::cout << str << " => " << expr << std::endl;
}
else
{
std::cout << "Failure." << std::endl;
}
}

int main()
{
parse("1");
parse("1+1");
parse("(1+1)");
//
parse("fun1_1((1))");
//
parse("fun2_1(1,2)");
parse("fun2_1( (fun2_1(1,1)), (2))");
//
parse("fun3_1(fun1_1(1),fun2_1(2,3),imf(1,1))");

}

output

Success.
1 => 1

Success.
imf => $imf

Success.
imf(1) => $imf(1)

Success.
(1+1) => (1+1)

Success.
fun1_1((1)) => f11(1)

Success.
fun2_1(1,2) => f21(1,2)

Success.
fun2_1( (fun2_1(1,1)), (2)) => f21(f21(1,1),2)

Success.
fun3_1(fun1_1(1),fun2_1(2,3),imf(1,1)) => f31(f11(1),f21(2,3),$imf(1,1))

How to parse a mathematical expression with boost::spirit and bind it to a function

You're going to learn Spirit. Great!

It seems you're biting off more than you can chew here, though.

Firstly, your grammar doesn't actually parse an expression yet. And it certainly doesn't result in a function that you can then bind.

  1. In fact you're parsing the input using a grammar that is not producing any result. It only creates a side-effect (which is to print the result of the simple binary expression with immediate simple operands to the console). This /resembles/ interpreted languages, although it would soon break up when

    • you try to parse an expression like 2*8 + 9
    • you would have input that backtracks (oops, the side effect already fired)
  2. Next up you're binding func (which is redundant by the way; you're not binding any arguments so you could just say function_Type multiplication(func); here), and calling it. While cool, this has literally nothing to do with the parsing input.

  3. Finally, your question is about a third thing, that wasn't even touched upon anywhere in the above. This question is about symbol tables and identifier lookup.

    • This would imply you should parse the source for actual identifiers (x or t, e.g.)
    • you'd need to store these into a symbol table so they could be mapped to a value (and perhaps a scope/lifetime)
    • There is a gaping logic hole in the question where you don't define the source of the "formal parameter list" (you mention it in the text here: function = x*t; but the parser doesn't deal with it, neither did you hardcode any such metadata); so there is no way we could even start to map the x and t things to the formal argument list (because it doesn't exist).

      Let's assume for the moment that in fact arguments are positional (as they are, and you seem to want this as you call the bound function with positional arguments anyways. (So we don't have to worry about a name because no one will ever see a name.)

    • the caller should pass in a context to the functions, so that values can be looked up by identifier name during evaluation.

So, while I could try to sit you down and talk you through all the nuts and bolts that need to be created first before you can even dream of glueing it together in fantastic ways like you are asking for, let's not.

It would take me too much time and you would likely be overwhelmed.

Suggestions

I can only suggest to look at simpler resources. Start with the tutorials

  • The calculator series of tutorials is nice. In this answer I list the calculator samples with short descriptions of what techniques they demonstrate: What is the most efficient way to recalculate attributes of a Boost Spirit parse with a different symbol table?
  • The compiler tutorials actually do everything you're trying for, but they're a bit advanced

Ask freely if you have any questions along the way and you're at risk of getting stuck. But at least then we have a question that is answerable and answers that genuinely help you.

For now, look at some other answers of mine where I actually implemented grammars like this (somewhat ordered by increasing complexity):

  • Nice for comparison: This answer to Boost::spirit how to parse and call c++ function-like expressions interprets the parsed expressions on-the-fly (this mimics the approach with [std::cout << "Parse multiplication: " << (qi::_1 * qi::_2)] in your own parser)

  • The other answer there (Boost::spirit how to parse and call c++ function-like expressions) achieves the goal but using a dedicated AST representation, and a separate interpretation phase.

The benefits of each approach are described in these answers. These parsers do not have a symbol table nor a evaluation context.

More examples:

  • a simple boolean expression grammar evaluator (which supports only literals, not variables)
  • Building a Custom Expression Tree in Spirit:Qi (Without Utree or Boost::Variant)

Parsing a grammar with Boost Spirit

As far as debugging, its possible to use a normal break and watch approach. This is made difficult by how you've formatted the rules though. If you format per the spirit examples (~one parser per line, one phoenix statement per line), break points will be much more informative.

Your data structure doesn't have a way to distinguish A() from SOME in that they are both leaves (let me know if I'm missing something). From your variant comment, I don't think this was your intention, so to distinguish these two cases, I added a bool commandFlag member variable to MockExpressionNode (true for A() and false for SOME), with a corresponding fusion adapter line.

For the code specifically, you need to pass the start rule to the base constructor, i.e.:

InputGrammar() : InputGrammar::base_type(instruction) {...}

This is the entry point in the grammar, and is why you were not getting any data parsed. I'm surprised it compiled without it, I thought that the grammar type was required to match the type of the first rule. Even so, this is a convenient convention to follow.

For the tag rule, there are actually two parsers qi::char_("a-zA-Z_"), which is _1 with type char and *qi::char_("a-zA-Z_0-9") which is _2 with type (basically) vector<char>. Its not possible to coerce these into a string without autorules, But it can be done by attaching a rule to each parsed char:

tag =   qi::char_("a-zA-Z_")
[ at_c<0>(qi::_val) = qi::_1 ];
>> *qi::char_("a-zA-Z_0-9") //[] has precedence over *, so _1 is
[ at_c<0>(qi::_val) += qi::_1 ]; // a char rather than a vector<char>

However, its much cleaner to let spirit do this conversion. So define a new rule:

qi::rule< Iterator , std::string(void) , ascii::space_type > identifier;
identifier %= qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9");

And don't worry about it ;). Then tag becomes

tag = identifier
[
at_c<0>(qi::_val) = qi::_1,
ph::at_c<2>(qi::_val) = false //commandFlag
]

For command, the first part is fine, but theres a couple problems with (*instruction >> ",")[ push_back( at_c<1>(qi::_val) , qi::_1 ) ]. This will parse zero or multiple instruction rules followed by a ",". It also attempts to push_back a vector<MockExpressionNode> (not sure why this compiled either, maybe not instantiated because of the missing start rule?). I think you want the following (with the identifier modification):

command =
identifier
[
ph::at_c<0>(qi::_val) = qi::_1,
ph::at_c<2>(qi::_val) = true //commandFlag
]
>> "("
>> -(instruction % ",")
[
ph::at_c<1>(qi::_val) = qi::_1
]
>> ")";

This uses the optional operator - and the list operator %.



Related Topics



Leave a reply



Submit