I have a parser that basically prints out the actions of a stack machine with my operator precedence given some expression. My goal is to optimize for speed as much as possible. I have read an article concerning qi optimizations that provides this example code. I understand the gist of the optimizations described in the main article, however I am unclear how to integrate this into my code.
Here is a following working example of my parser. I have already tried to optimize it somewhat by using raw[]
to provide base iterators. The phoenix action calls must be given strings or iterators by which they can create strings; the real versions of these functions are not trivial and their functionality can not yet be evaluated in parsing-time:
#include <iostream>
#include <vector>
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_char.hpp>
#include <boost/spirit/include/qi_parse.hpp>
#include <boost/spirit/include/phoenix_bind.hpp>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
using std::endl;
using std::cout;
using std::string;
using std::vector;
void fPushOp(const char* op){
cout << "PushOp: " << op << endl;
}
void fPushInt(const boost::iterator_range<string::const_iterator>& my_str){
cout << "PushInt: " << my_str << endl;
}
template<typename Iterator, typename Skipper = qi::space_type>
struct Calculator : public qi::grammar<Iterator, Skipper> {
qi::rule<Iterator, Skipper>
expression, logical_or_expression, logical_and_expression, negate_expression, series_expression,
single_expression, inclusive_or_expression, exclusive_or_expression, and_expression, equality_expression,
relational_expression, shift_expression, additive_expression, multiplicative_expression,
term, complement_factor, factor, result, integer, variable, variable_combo, word, prefix;
qi::rule<Iterator> number;
Calculator() : Calculator::base_type(result)
{
number =
qi::raw[
("0x" >> +qi::char_("0-9a-fA-F"))
| ("0b" >> +qi::char_("0-1"))
| ("0" >> +qi::char_("0-7"))
| (+qi::char_("0-9"))
] [phx::bind(&fPushInt, qi::_1)]
;
integer =
number
| ('-' >> number) [phx::bind(&fPushOp, "OP_UNARY_MINUS")]
;
variable =
((qi::alpha | qi::char_('_'))
>> *(qi::alnum | qi::char_('_'))
>> '['
>> (+(qi::alnum | qi::char_('_') | qi::char_(','))
| ('\'' >> *~qi::char_('\'') >> '\''))
>> ']')
| ((qi::alpha | qi::char_('_')) >> *(qi::alnum | qi::char_('_')))
;
variable_combo =
qi::raw [
variable >> *(qi::char_('.') >> variable)
] [phx::bind(&fPushInt, qi::_1)]
;
word =
qi::raw[
variable
] [phx::bind(&fPushInt, qi::_1)]
;
factor =
("ceil(" >> expression >> ')') [phx::bind(&fPushOp, "OP_CEIL")]
| ("wrap(" >> expression >> ')') [phx::bind(&fPushOp, "OP_WRAP")]
| ("abs(" >> expression >> ')') [phx::bind(&fPushOp, "OP_ABS")]
| ("count1(" >> expression >> ')') [phx::bind(&fPushOp, "OP_COUNT1")]
| ("pick(" >> expression >> ')') [phx::bind(&fPushOp, "OP_PICK")]
| ("defined(" >> expression >> ')') [phx::bind(&fPushOp, "OP_DEF")]
| ("string_equal(" >> word >> ',' >> word >> ')') [phx::bind(&fPushOp, "OP_STREQ")]
| ("string_contains(" >> word >> ',' >> word >> ')') [phx::bind(&fPushOp, "OP_STRCON")]
| ("lsl(" >> single_expression >> ',' >> single_expression >> ',' >> number >> ')') [phx::bind(&fPushOp, "OP_LSL")]
| ("lsr(" >> single_expression >> ',' >> single_expression >> ')') [phx::bind(&fPushOp, "OP_LSR")]
| ("asr(" >> single_expression >> ',' >> single_expression >> ',' >> number >> ')') [phx::bind(&fPushOp, "OP_ASR")]
| ("ror(" >> single_expression >> ',' >> single_expression >> ',' >> number >> ')') [phx::bind(&fPushOp, "OP_ROR")]
| ("rrx(" >> single_expression >> ',' >> single_expression >> ',' >> single_expression >> ',' >> number >> ')')[phx::bind(&fPushOp, "OP_RRX")]
| ('(' >> expression >> ')')
| variable_combo
| integer
;
complement_factor = factor
| ('~' >> factor) [phx::bind(&fPushOp, "OP_COMPLEMENT")]
;
term = complement_factor
>> *( (".." >> complement_factor) [phx::bind(&fPushOp, "OP_LEGER")]
| ('\\' >> complement_factor) [phx::bind(&fPushOp, "OP_MASK")]
);
multiplicative_expression = term
>> *( ('/' >> term) [phx::bind(&fPushOp, "OP_DIV")]
| ('%' >> term) [phx::bind(&fPushOp, "OP_MOD")]
| ('*' >> term) [phx::bind(&fPushOp, "OP_MUL")]
);
additive_expression = multiplicative_expression
>> *( ('+' >> multiplicative_expression) [phx::bind(&fPushOp, "OP_ADD")]
| ('-' >> multiplicative_expression) [phx::bind(&fPushOp, "OP_SUB")]
);
shift_expression = additive_expression
>> *( (">>" >> additive_expression) [phx::bind(&fPushOp, "OP_SRL")]
| ("<<" >> additive_expression) [phx::bind(&fPushOp, "OP_SLL")]
);
relational_expression = shift_expression
>> *( ('<' >> shift_expression) [phx::bind(&fPushOp, "OP_LT")]
| ('>' >> shift_expression) [phx::bind(&fPushOp, "OP_GT")]
| ("<=" >> shift_expression)[phx::bind(&fPushOp, "OP_LET")]
| (">=" >> shift_expression)[phx::bind(&fPushOp, "OP_GET")]
);
equality_expression = relational_expression
>> *( ("==" >> relational_expression)[phx::bind(&fPushOp, "OP_EQ")]
| ("!=" >> relational_expression)[phx::bind(&fPushOp, "OP_NEQ")]
);
and_expression = equality_expression
>> *(('&' >> equality_expression) [phx::bind(&fPushOp, "OP_AND")]);
exclusive_or_expression = and_expression
>> *(('^' >> and_expression) [phx::bind(&fPushOp, "OP_XOR")]);
inclusive_or_expression = exclusive_or_expression
>> *(('|' >> exclusive_or_expression) [phx::bind(&fPushOp, "OP_OR")]);
single_expression = inclusive_or_expression;
series_expression = inclusive_or_expression
>> *((',' >> inclusive_or_expression) [phx::bind(&fPushOp, "OP_SERIES")]);
negate_expression = series_expression
| ('!' >> series_expression) [phx::bind(&fPushOp, "OP_NEGATE")];
logical_and_expression = negate_expression
>> *(("&&" >> negate_expression) [phx::bind(&fPushOp, "OP_LOGICAL_AND")]);
logical_or_expression = logical_and_expression
>> *(("||" >> logical_and_expression) [phx::bind(&fPushOp, "OP_LOGICAL_OR")]);
expression = logical_or_expression;
result = expression;
}
};
int main(){
Calculator<string::const_iterator> calc;
const string expr("0xff0000 >> 3 && 3 + (!9) | (0,200)");
cout << "Expression: " << expr << endl;
string::const_iterator it = expr.begin();
phrase_parse(it, expr.end(), calc, qi::space);
cout << "Remaining: " << (string(it,expr.end())) << endl;
return 0;
}
Additionally, I read the slides from this pdf concerning utree and am trying to figure out how, if possible, to use the utree
output instead of semantic actions since apparently such things are evil. Can someone provide or point me to a simple example on how to construct a utree
that can then be fed to a stack machine to print out operations in order?