2

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 << "-------------------------\n";
            std::cout << "Parsing succeeded\n";
            std::cout << "result = " << result << std::endl;
            std::cout << "-------------------------\n";
            client::vars.remove("ans");
            client::vars.add("ans",result);
        }
        else
        {
            std::string rest(iter, end);
            std::cout << "-------------------------\n";
            std::cout << "Parsing failed\n";
            std::cout << "stopped at: \": " << rest << "\"\n";
            std::cout << "-------------------------\n";
        }
    }

    std::cout << "Bye... :-) \n\n";
    return 0;
}

I would like to do things such as :

var i,j
i = 1
j = max(2*(i+1),5)
cHeWeE-_-
  • 68
  • 7
  • please specify the _exact_ compilation message – sehe Jan 08 '12 at 20:57
  • if that can help you @sehe, the exact message is : 'Erreur 2 error C2782: 'const boost::spirit::qi::symbols::adder &boost::spirit::qi::symbols::adder::operator ()(const Iterator &,const Iterator &,const T &) const' : template parameter 'Iterator' is ambiguous D:\Programming\Librairies\Boost\boost_1_47_0\boost\spirit\home\support\action_dispatch.hpp 162)' – cHeWeE-_- Jan 08 '12 at 21:08
  • Ok, since you're using MSVC, what version of it is that? Can you post a [SSCCE](http://meta.stackexchange.com/questions/22754/sscce-how-to-provide-examples-for-programming-questions/22762#22762)? So we can rule out things like BOOST_SPIRIT_USE_PHOENIX_V3 – sehe Jan 08 '12 at 22:45
  • @sehe : I have posted the whole working source code and few commands. the first one is working but the vars are not created so the next two doesn't. – cHeWeE-_- Jan 08 '12 at 23:24

1 Answers1

2

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)\boost\boost_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:\>.\test.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.

Community
  • 1
  • 1
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Even though I thought you had the solution, it still doesn't work -_- ... The message is a bit similar (still template ambiguity) : Erreur 10 error C2784: 'boost::phoenix::actor,boost::phoenix::detail::function_ptr<1,RT,RT(__cdecl *)(T0)>,A0>::type> boost::phoenix::bind(RT (__cdecl *)(T0),const A0 &)' : could not deduce template argument for 'RT (__cdecl *)(T0)' from 'boost::spirit::qi::symbols::adder' D:\Desktop\vt4\src\test\other_parser_test.cpp 111 – cHeWeE-_- Jan 08 '12 at 22:15
  • I really don't understand what we are missing... Especially because I found the idea in a working project, see [link](http://www.codeproject.com/KB/stl/introduction_spirit.aspx), -> syntax.h – cHeWeE-_- Jan 08 '12 at 22:16
  • @cHeWeE-_- ah. Why not post the link in the question next time? That article is from 2004. Quite likely it used Spirit Classical, or at least an old version. I'll have a look at that if you want – sehe Jan 08 '12 at 22:47
  • I should have, just forgot. I don't want you to waste your time but basically in the linked project var declaration is working and expression parsed, but operations are not evaluated. It is almost the same as I do without all the [_val = ...] and with the deprecated headers. Oh ! And they use spirit::grammar instead of spirit::qi::grammar. – cHeWeE-_- Jan 08 '12 at 23:29
  • @cHeWeE-_- - I noticed you edited the Q with a SSCCE: thanks! You were only missing an include, now. Add `#include ` and it compiles – sehe Jan 09 '12 at 09:07
  • Edited question with compilation and running demo on MSVC 2010, Hope that helps – sehe Jan 09 '12 at 09:29
  • Working fine ! Thanks a lot !! I thought that 'phoenix/bind/bind_function.hpp' was enough... At least your first answer was totally correct, and I understand it :) I am definitely grateful ! – cHeWeE-_- Jan 09 '12 at 12:00
  • would you happen to have a simple example of AST grammar with symbol handling ? The examples I found in spirit documentation are to difficult for me :) and they do not mention any symbols anyway... It might help me understand how they work. – cHeWeE-_- Jan 17 '12 at 08:52
  • @cHeWeE-_- Have you looked at the examples in the library source tree as well? They seem to be more complete than the documentation if you are looking for end-to-end usage samples. – sehe Jan 17 '12 at 09:04
  • I was looking for something else when I did. I will check again ! – cHeWeE-_- Jan 17 '12 at 09:20