Как добавить qi::symbols в грамматику‹Iterator,double()›?

Я пытаюсь использовать библиотеку Boost.Spirit (V. 2.5) для создания мини-калькулятора. Возможности, которые я хочу реализовать: - базовое исчисление (+,-,/,*), которое работает - некоторые функции (например, min, max), которые тоже работают - объявление/назначение двойных переменных, и есть проблема... когда Я добавляю "[vars.add]" и получаю ошибку компиляции (неоднозначный параметр шаблона). Я пробовал "добавить (char_ (_1)", "добавить (_1)",... и, кажется, ничего не работает. Я явно что-то упускаю (на самом деле чего-то не понимаю). Если бы кто-то мог помочь мне в этом, я бы я очень благодарен!

Вот источник:

#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;
}

Я хотел бы сделать такие вещи, как:

var i,j
i = 1
j = max(2*(i+1),5)

person cHeWeE-_-    schedule 08.01.2012    source источник
comment
укажите точное сообщение компиляции   -  person sehe    schedule 09.01.2012
comment
если это может вам помочь @sehe, точное сообщение: «Ошибка 2 ошибка C2782: 'const boost::spirit::qi::symbols‹Char,T›::adder &boost::spirit::qi::symbols‹ Char,T›::adder::operator ()(const Iterator &,const Iterator &,const T &) const' : параметр шаблона Iterator неоднозначен D:\Programming\Librairies\Boost\boost_1_47_0\boost\spirit\ главная\поддержка\action_dispatch.hpp 162)'   -  person cHeWeE-_-    schedule 09.01.2012
comment
Хорошо, поскольку вы используете MSVC, какая это версия? Можете ли вы опубликовать SSCCE? Таким образом, мы можем исключить такие вещи, как BOOST_SPIRIT_USE_PHOENIX_V3.   -  person sehe    schedule 09.01.2012
comment
@sehe: я разместил весь рабочий исходный код и несколько команд. первый работает, но переменные не создаются, поэтому следующие два не работают.   -  person cHeWeE-_-    schedule 09.01.2012


Ответы (1)


Да, на самом деле я никогда не добавлял символы непосредственно из Semantic Actions (я предпочитаю создавать AST, а затем проходить их).

Тот факт, что вы написали это так, и отсутствие SSCCE на мгновение ошеломил меня. Оказывается, я должен был просто проигнорировать косвенные «доказательства» и сразу перейти к документам + выиграть:

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) ];

и некоторые подобные заклинания будут применяться

Правка Вот полный исходный код, скомпилированный на MSVC 2010 с Boost 1.47:

Выход:

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
-------------------------

Немного не относящееся к теме примечание: выглядит довольно-таки забавно, что открытый атрибут правила var_decl выглядит как char?

Возможно, вы захотите прочитать об автоматических правилах и операторе %=; Без %= наличие семантического действия подавляет все автоматическое распространение атрибутов. Это полезно, если необходимые точки настройки не существуют. Как написано, открытый атрибут всегда будет неназначенным.

person sehe    schedule 08.01.2012
comment
Хотя я думал, что у вас есть решение, оно все еще не работает -_- ... Сообщение немного похоже (все еще неоднозначность шаблона): Erreur 10 error C2784: 'boost::phoenix::actor‹as_composite‹boost ::phoenix::detail::function_eval‹1›,boost::phoenix::detail::function_ptr‹1,RT,RT(__cdecl *)(T0)›,A0›::type› boost::phoenix:: bind(RT (__cdecl *)(T0),const A0 &)': не удалось вывести аргумент шаблона для 'RT (__cdecl *)(T0)' из 'boost::spirit::qi::symbols‹Char,T› ::adder' D:\Desktop\vt4\src\test\other_parser_test.cpp 111 - person cHeWeE-_-; 09.01.2012
comment
Я действительно не понимаю, чего нам не хватает... Тем более, что я нашел идею в рабочем проекте, см. ссылка, -› синтаксис.h - person cHeWeE-_-; 09.01.2012
comment
@cHeWeE-_- а. Почему бы не опубликовать ссылку в вопросе в следующий раз? Эта статья 2004 года. Вполне вероятно, что она использовала Spirit Classical или, по крайней мере, старую версию. Я посмотрю на это, если вы хотите - person sehe; 09.01.2012
comment
Я должен был, просто забыл. Я не хочу, чтобы вы тратили свое время, но в основном в связанном проекте объявление var работает и выражение анализируется, но операции не оцениваются. Это почти то же самое, что я делаю без всех [_val = ...] и с устаревшими заголовками. Ой ! И они используют spirit::grammar вместо spirit::qi::grammar. - person cHeWeE-_-; 09.01.2012
comment
@cHeWeE-_- - Я заметил, что вы отредактировали вопрос с помощью SSCCE: спасибо! Теперь вам не хватало только включения. Добавьте #include <boost/spirit/include/phoenix.hpp> и он скомпилируется - person sehe; 09.01.2012
comment
Отредактированный вопрос с компиляцией и запуском демонстрации на MSVC 2010, надеюсь, что это поможет - person sehe; 09.01.2012
comment
Работает нормально! Большое спасибо !! Я думал, что "phoenix/bind/bind_function.hpp" было достаточно... По крайней мере, ваш первый ответ был абсолютно правильным, и я его понимаю :) Я определенно благодарен! - person cHeWeE-_-; 09.01.2012
comment
может у вас есть простой пример грамматики AST с обработкой символов? Примеры, которые я нашел в документации по духу, слишком сложны для меня :), и в любом случае они не упоминают никаких символов... Это может помочь мне понять, как они работают. - person cHeWeE-_-; 17.01.2012
comment
@cHeWeE-_- Вы тоже смотрели примеры в дереве исходного кода библиотеки? Они кажутся более полными, чем документация, если вы ищете сквозные примеры использования. - person sehe; 17.01.2012
comment
Я искал что-то другое, когда я это сделал. проверю еще раз! - person cHeWeE-_-; 17.01.2012