Семантическое действие парсера токенов

Я написал рабочий парсер токенов на основе кода, показанного на spirit lex, пример 4

Одно из моих правил выглядит так

    set_name 
        =   (   tok.set_ >> tok.name_ >> tok.identifier )
            [
                std::cout << val("set name statement to: ") << _3 << "\n"
            ]
        ;

Это хорошо работает. При представлении

SET NAME xyz

он выводит, как я ожидал

установить оператор имени на: xyz

Теперь я хочу сделать что-нибудь полезное, сохранить найденное имя в классе. Работа с семантическими примерами синтаксического анализатора я пишу этот код

  class writer
    {
    public:
        void print(string const& s) const
        {
            std::cout << s << std::endl;
        }
    };

  writer w;

  ...

    set_name 
        =   (   tok.set_ >> tok.name_ >> tok.identifier )
            [
                boost::bind( &writer::print, &w, ::_3 )
            ]
        ;

Это не компилируется

1>C:\Program Files\boost\boost
    set_name 
        =   (   tok.set_ >> tok.name_ >> tok.identifier )
            [
                std::cout << val("set name statement to: ") << _3 << "\n"
            ]
        ;
44\boost/bind/bind.hpp(318) : error C2664: 'R boost::_mfi::cmf1::operator ()(const U &,A1) const' : cannot convert parameter 2 from 'bool' to 'const std::basic_string ' 1> with 1> [ 1> R=void, 1> T=eCrew::rule::writer, 1> A1=const std::string &, 1> U=eCrew::rule::writer * 1> ] 1> and 1> [ 1> _Elem=char, 1> _Traits=std::char_traits, 1> _Ax=std::allocator 1> ] 1> Reason: cannot convert from 'bool' to 'const std::string' 1> No constructor could take the source type, or constructor overload resolution was ambiguous

Почему компилятор жалуется на попытку преобразования из bool в строку? Я не вижу никакого bool.


person ravenspoint    schedule 29.03.2011    source источник
comment
In ... объявляется ли w как bool? Что произойдет, если вы используете более уникальное имя переменной для писателя?   -  person jon-hanson    schedule 30.03.2011
comment
@jon изменил w на the_writer. Тот же результат.   -  person ravenspoint    schedule 30.03.2011


Ответы (1)


Заполнитель в

std::cout << val("set name statement to: ") << _3 << "\n"

относится к boost::spirit::_3, который является заполнителем boost.phoenix v2. Заполнитель в

boost::bind(&writer::print, &w, ::_3)

- это заполнитель boost.bind (естественно).

Эти заполнители различаются и даже ссылаются на одни и те же данные. Заполнители Phoenix в форме _ N относятся к N-му податрибуту вашего синтаксического анализатора, в то время как заполнители привязки имеют другое значение:

  • _1 относится к атрибуту вашего парсера в целом
  • _2 относится к контексту парсера
  • _3 относится к bool& параметру 'попадания'

Самое простое решение в вашем случае - использовать boost::phoenix::bind вместо boost::bind, чтобы вы могли продолжать использовать _3 для ссылки на третий податрибут вашего синтаксического анализатора вместо того, чтобы выбирать его вручную внутри writer::print.

В качестве альтернативы, прикрепите семантическое действие только к tok.identifier, чтобы ::_1 boost.bind работал так, как вы ожидаете:

set_name
  = tok.set_
    >> tok.name_
    >> tok.identifier[boost::bind(&writer::print, &w, ::_1)]
;
person ildjarn    schedule 29.03.2011
comment
Звучит как хорошая идея. Я попробую и вернусь к вам. - person ravenspoint; 30.03.2011