Boost Spirit Qi: ошибка компиляции при небольшом изменении правила

Я пишу небольшой компилятор просто для удовольствия и использую Boost Spirit Qi для описания своей грамматики. Теперь я хочу внести небольшие изменения в грамматику, чтобы подготовить некоторые дальнейшие дополнения. К сожалению, эти изменения не будут компилироваться, и я хотел бы понять, почему это так.

Вот фрагмент кода, который я хочу изменить. Надеюсь, предоставленной информации достаточно, чтобы понять идею. Полный код немного велик, но если вы хотите взглянуть на него или даже протестировать (предоставляется Makefile и Travis CI), см. https://github.com/Kruecke/BFGenerator/blob/8f66aa5./bf/compiler.cpp#L433.

typedef boost::variant<
    function_call_t,
    variable_declaration_t,
    variable_assignment_t,
    // ...
> instruction_t;

struct grammar : qi::grammar<iterator, program_t(), ascii::space_type> {
    grammar() : grammar::base_type(program) {
        instruction = function_call
                    | variable_declaration
                    | variable_assignment
                 // | ...
                    ;

        function_call = function_name >> '(' > -(variable_name % ',') > ')' > ';';
        // ...
    }

    qi::rule<iterator, instruction::instruction_t(),   ascii::space_type> instruction;
    qi::rule<iterator, instruction::function_call_t(), ascii::space_type> function_call;
    // ...
};

Пока все работает нормально. Теперь я хочу переместить анализ конечной точки с запятой (> ';') из правила function_call в правило instruction. Теперь мой код выглядит так:

struct grammar : qi::grammar<iterator, program_t(), ascii::space_type> {
    grammar() : grammar::base_type(program) {
        instruction = (function_call > ';') // Added trailing semicolon
                    | variable_declaration
                    | variable_assignment
                 // | ...
                    ;

        // Removed trailing semicolon here:
        function_call = function_name >> '(' > -(variable_name % ',') > ')';
        // ...
    }

Насколько я понимаю, правила на самом деле не изменились, потому что синтаксический анализатор ';' не дает никаких атрибутов, и поэтому не должно иметь значения, где расположен этот синтаксический анализатор. Однако это изменение не будет компилироваться:

/usr/include/boost/spirit/home/support/container.hpp:278:13: error: no matching function for call to ‘std::basic_string<char>::insert(std::basic_string<char>::iterator, const bf::instruction::function_call_t&)’
             c.insert(c.end(), val);
             ^

(Эта ошибка возникает из строки instruction = ....)

Почему это изменение не компилируется? Я скорее ищу объяснение, чтобы понять, что происходит, чем обходной путь.


person Florian Klemme    schedule 04.04.2016    source источник


Ответы (1)


Хорошо, поэтому, внимательно посмотрев на это, вы пытаетесь вставить несколько строк в свой тип function_call_t, который представляет собой последовательность слияния, которую можно преобразовать в одну std :: string. Однако вы, вероятно, столкнетесь с проблемами с вашим правилом function_call, потому что его атрибут на самом деле tuple <std::string, optional <vector <std::string>>>. Я предполагаю, что у духа есть проблемы с выравниванием этой структуры, и это вызывает вашу проблему, однако у меня нет компилятора, чтобы проверить это на данный момент.

person Zack    schedule 04.04.2016
comment
Вы абсолютно правы! Я никогда не планировал иметь только один std::string в function_call_t, поэтому я очень удивлен, что мой предыдущий код сработал в первую очередь! Я добавил std::vector<std::string> variable_names в свою структуру, и это сразу решает проблему. Большое спасибо! - person Florian Klemme; 04.04.2016