Boost::spirit::qi defining a calculator for nullaries

前端 未结 1 1360
陌清茗
陌清茗 2020-12-21 03:56

I\'m trying to write a parser for math expressions where named variables are nullaries in boost::spirit (version 1_51_0), to which I\'m completely new. I defin

1条回答
  •  無奈伤痛
    2020-12-21 04:19

    The parser expression looks okay.

    What you are confused over is on constructing the AST. Apparently, you have decided to use Semantic Actions to do so, but your effort is too sketchy for me to see just how (or even decide what sample you are basing this on).

    In essence: What is it that you want to do with the instances of 'ADD'/'SUB' that you seem to magically "will" into your rules?

    Right now, you just use the instance directly as a semantic action. This leads to the error message shown, which tells you, directly, that the instance is not valid as a semantic action.

    I assume you really wanted to use Phoenix assignment to assign the binary operation to the exposed attribute, instead. This looks like:

    expression = term
         >> *( (lit('+') >> term[ _val = phx::construct(_val, _1)])
             | (lit('-') >> term[ _val = phx::construct(_val, _1)])
             );
    

    You'll see this matches much more closely with traditional expression grammars.

    For fun I adapted a complete expression parser based on your Value type and created this working demonstration: http://liveworkspace.org/code/3kgPJR$0

    #include 
    #include 
    #include 
    
    namespace qi    = boost::spirit::qi;
    namespace karma = boost::spirit::karma;
    namespace phx   = boost::phoenix;
    
    typedef std::function Value;
    
    #define BINARY_FUNCTOR(name, op)                        \
    struct name                                             \
    {                                                       \
      name(Value x, Value y): x_(x), y_(y) {}               \
      double operator()() { return x_() op y_(); }          \
      Value x_, y_;                                         \
    }; 
    
    BINARY_FUNCTOR(ADD, +)
    BINARY_FUNCTOR(SUB, -)
    BINARY_FUNCTOR(MUL, *)
    BINARY_FUNCTOR(DIV, /)
    
    struct LIT
    {
      LIT(double x): x_(x) {}
      double operator()() { return x_; }
      double x_;
    }; 
    
    struct NEG
    {
      NEG(Value x): x_(x) {}
      double operator()() { return -x_(); }
      Value x_;
    }; 
    
    
    template 
        struct parser : qi::grammar
    {
        parser() : parser::base_type(expression)
        {
            using namespace qi;
            expression =
                term                    [_val = _1]
                >> *( ('+' >> term  [_val = phx::construct(_val, _1)])
                    | ('-' >> term  [_val = phx::construct(_val, _1)])
                    );
    
            term =
                factor                [_val = _1]
                >> *( ('*' >> factor  [_val = phx::construct(_val, _1)])
                    | ('/' >> factor  [_val = phx::construct
    (_val, _1)]) ); factor = double_ [_val = phx::construct(_1)] | '(' >> expression [_val = _1] >> ')' | ('-' >> factor [_val = phx::construct(_1)]) | ('+' >> factor [_val = _1]); BOOST_SPIRIT_DEBUG_NODE(expression); BOOST_SPIRIT_DEBUG_NODE(term); BOOST_SPIRIT_DEBUG_NODE(factor); } private: qi::rule expression, term, factor; }; Value doParse(const std::string& input) { typedef std::string::const_iterator It; parser p; Value eval; auto f(begin(input)), l(end(input)); if (!qi::phrase_parse(f,l,p,qi::space,eval)) std::cerr << "parse failed: '" << std::string(f,l) << "'\n"; if (f!=l) std::cerr << "trailing unparsed: '" << std::string(f,l) << "'\n"; return eval; } int main() { auto area = doParse("2 * (3.1415927 * (10*10))"); std::cout << "Area of a circle r=10: " << area() << "\n"; }

    It will print

    Area of a circle r=10: 628.319
    

    0 讨论(0)
提交回复
热议问题