Токен парсер семантического действия - PullRequest
1 голос
/ 30 марта 2011

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

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

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

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

SET NAME xyz

выводит как я ожидаю

установить для оператора name: 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_1_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 в строку? Там нет бул, который я вижу.

1 Ответ

3 голосов
/ 30 марта 2011

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

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& параметру 'hit'

Самое простое решение в вашем случае - использовать 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)]
;
...