Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
98 views
in Technique[技术] by (71.8m points)

c++ - How to add qi::symbols in grammar<Iterator,double()>?

I am trying to use Boost.Spirit (V. 2.5) library to create a mini-calculator. Features I want to implement : - basic calculus (+,-,/,*), that works - some functions (like min, max), that works too - declaring/assigning double variables, and there is the problem... when I add "[vars.add]" I get compilation error (template parameter ambiguious). I've tried "add(char_(_1)", "add(_1)",... and nothing seems to work. I am obviously missing something (not understanding something actually). If someone could help me on this I would me most gratefull!

Here is the source :

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/home/phoenix/statement/if.hpp>
#include <boost/spirit/home/phoenix/bind/bind_function.hpp>

#include <iostream>
#include <string>

namespace client
{
    namespace qi = boost::spirit::qi;
    namespace ascii = boost::spirit::ascii;
    namespace phx = boost::phoenix;

    struct vars_ : qi::symbols<char, double> {
        vars_() {
            add("ans" , 0);
        }
    } vars;

    template <typename Iterator>
    struct parser : qi::grammar<Iterator, double()>
    {
        parser() : parser::base_type(function)
        {
            using qi::eps;
            using qi::lit;
            using qi::_val;
            using qi::_1;
            using ascii::char_;
            using qi::double_;
            using qi::string;
            using qi::lexeme;
            using boost::phoenix::if_;
            using qi::alpha;
            using qi::alnum;

            MAX = lexeme[string("max") | string("MAX")]; //define max symbol

            MIN = lexeme[string("min") | string("MIN")]; //define min symbol

            D   = lexeme[string("d") | string("D")];     //define distance symbol

            ANS = lexeme[string("ans") | string("ANS")]; //not working yet

            function =
                expression                                      [_val = _1]
                | declaration
                | assignment
                | ( MAX >> "(" >> function                      [_val = _1] >> 
                        +(',' >> function                       [if_(_1 > _val)[_val = _1]]) >> ')') // call : max(function,...)
                | ( MIN >> "(" >> function                      [_val = _1] >>
                        +(',' >> function                       [if_(_1 < _val)[_val = _1]]) >> ')') // call : min(function,...)
                | ( D   >> "(" >> (function >> ',' >> function) >> ')');                             // call : d(point1,point2) not implemented yet

            expression =
                term                            [_val = _1]
                >> *(   ('+' >> term            [_val += _1])
                    |   ('-' >> term            [_val -= _1]));

            term =
                factor                          [_val = _1]
                >> *(   ('*' >> factor          [_val *= _1])
                    |   ('/' >> factor          [_val /= _1]));
            factor = 
                double_                         [_val = _1]
                | (vars                         [_val += _1] )
                |   '(' >> expression           [_val = _1] >> ')'
                |   ('-' >> factor              [_val = -_1])
                |   ('+' >> factor              [_val = _1])
                | declaration;
            ;

            assignment =
                vars >> '=' >> function;

            var_decl =
                lexeme [ qi::raw [  ( alpha >> *( alnum | '_' ) ) - vars  ] ] //[ phx::bind(vars.add, _1) ]
                    ;


            declaration =
                "var " >> var_decl >> *( ',' >> var_decl );
        }

        qi::rule<Iterator, double()> MAX, MIN, D, ANS, expression, term, factor, 
                                        function, assignment, var_decl, declaration;
    };
}

///////////////////////////////////////////////////////////////////////////////
//  Main program
///////////////////////////////////////////////////////////////////////////////
int main()
{
    std::cout << "**********************************************************" << std::endl;
    std::cout << "*                                                        *" << std::endl;
    std::cout << "*          Command interface for VideoTraction4          *" << std::endl;
    std::cout << "*                                                        *" << std::endl;
    std::cout << "**********************************************************" << std::endl << std::endl;
    std::cout << "Type an expression...or [q or Q] to quit" << std::endl << std::endl;

    typedef std::string::const_iterator iterator_type;
    typedef client::parser<iterator_type> parser;

    parser _parser; // Our grammar

    std::string str;
    double result;
    while (std::getline(std::cin, str))
    {
        if (str.empty() || str[0] == 'q' || str[0] == 'Q')
            break;

        std::string::const_iterator iter = str.begin();
        std::string::const_iterator end = str.end();

        bool r = parse(iter, end, _parser, result);

        if (r && iter == end)
        {
            std::cout << "-------------------------
";
            std::cout << "Parsing succeeded
";
            std::cout << "result = " << result << std::endl;
            std::cout << "-------------------------
";
            client::vars.remove("ans");
            client::vars.add("ans",result);
        }
        else
        {
            std::string rest(iter, end);
            std::cout << "-------------------------
";
            std::cout << "Parsing failed
";
            std::cout << "stopped at: ": " << rest << ""
";
            std::cout << "-------------------------
";
        }
    }

    std::cout << "Bye... :-) 

";
    return 0;
}

I would like to do things such as :

var i,j
i = 1
j = max(2*(i+1),5)
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Huh, I've never actually added symbols from directly inside Semantic Actions myself (I prefer to build ASTs, and then traverse those).

The fact that you wrote it like this and the absence of a SSCCE had me blindsided for a moment. Turns out, I should just have ignored the circumstantial 'evidence' and went straight for the docs + win:

var_decl =
    qi::as_string [ lexeme [ ( ( alpha >> *( alnum | '_' ) ) - vars ) ] ]
        [ phx::bind(vars.add, _1) ];

or

var_decl =
     lexeme [ qi::raw [  ( alpha >> *( alnum | '_' ) ) - vars  ] ]
        [ phx::bind(vars.add, _1) ];

and some similar incantations will apply

Edit Here is the complete source, compiled on MSVC 2010, with boost 1.47:

Output:

T:>cl /EHsc /I "c:Program Files (x86)oostoost_1_47" test.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

test.cpp
Microsoft (R) Incremental Linker Version 10.00.30319.01
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:test.exe
test.obj

T:>.est.exe
**********************************************************
*                                                        *
*          Command interface for VideoTraction4          *
*                                                        *
**********************************************************

Type an expression...or [q or Q] to quit

3*4+7
-------------------------
Parsing succeeded
result = 19
-------------------------

On a slightly unrelated note: it looks kind-a funny that the exposed attribute of the var_decl rule appears to be char?

You might want to read up on auto-rules and the %= operator; Without %=, the presence of a Semantic Action will suppress all automatic attribute propagation. That is helpful in case the required customization points do not exist. As written, the exposed attribute will always be unassigned-to.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...