Что касается отладки, то можно использовать обычный подход к просмотру.Это затрудняется тем, как вы отформатировали правила.Если вы отформатируете по духу примеров (~ один синтаксический анализатор на строку, одно выражение феникса на строку), точки останова будут гораздо более информативными.
В вашей структуре данных нет способа отличить A()
отSOME
в том смысле, что они оба листья (дайте мне знать, если я что-то упустил).Из вашего варианта комментария я не думаю, что это было вашим намерением, поэтому, чтобы отличить эти два случая, я добавил переменную-член bool commandFlag
в MockExpressionNode (true для A()
и false для SOME
) с соответствующим слияниемАдаптерная строка.
Специально для кода необходимо передать правило запуска базовому конструктору, например:
InputGrammar() : InputGrammar::base_type(instruction) {...}
Это точка входа в грамматику, и поэтому выне получал никаких данных, проанализированных.Я удивлен, что это скомпилировано без него, я думал, что тип грамматики должен был соответствовать типу первого правила.Тем не менее, это удобное соглашение для подражания.
Для правила tag
на самом деле есть два синтаксических анализатора qi::char_("a-zA-Z_")
, который является _1 с типом char
и *qi::char_("a-zA-Z_0-9")
, который равен _2 с типом (в основном) vector<char>
.Невозможно привести их в строку без авторул, но это можно сделать, прикрепив правило к каждому разбираемому символу:
tag = qi::char_("a-zA-Z_")
[ at_c<0>(qi::_val) = qi::_1 ];
>> *qi::char_("a-zA-Z_0-9") //[] has precedence over *, so _1 is
[ at_c<0>(qi::_val) += qi::_1 ]; // a char rather than a vector<char>
Однако, гораздо проще очистить духом это преобразование.Поэтому определите новое правило:
qi::rule< Iterator , std::string(void) , ascii::space_type > identifier;
identifier %= qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9");
И не беспокойтесь об этом;).Затем тег становится
tag = identifier
[
at_c<0>(qi::_val) = qi::_1,
ph::at_c<2>(qi::_val) = false //commandFlag
]
Для команды первая часть в порядке, но есть пара проблем с (*instruction >> ",")[ push_back( at_c<1>(qi::_val) , qi::_1 ) ]
.Это будет анализировать ноль или несколько правил инструкций, сопровождаемых ",".Он также пытается push_back a vector<MockExpressionNode>
(не уверен, почему это скомпилировано, может быть, не было создано из-за отсутствующего правила запуска?).Я думаю, вам нужно следующее (с модификацией идентификатора):
command =
identifier
[
ph::at_c<0>(qi::_val) = qi::_1,
ph::at_c<2>(qi::_val) = true //commandFlag
]
>> "("
>> -(instruction % ",")
[
ph::at_c<1>(qi::_val) = qi::_1
]
>> ")";
При этом используется необязательный оператор -
и оператор списка %
, последний эквивалентен instruction >> *("," >> instruction)
.Затем выражение феникса просто присваивает вектор непосредственно члену структуры, но вы также можете прикрепить действие непосредственно к совпадению инструкции и использовать push_back.
Правило инструкции в порядке, я просто упомяну, что оноэквивалентно instruction %= (command|tag)
.
И последнее: если на самом деле нет различий между A()
и SOME
(т. е. исходной структурой без commandFlag
), вы можете написать этот анализатор, используя только авторулы:
template< typename Iterator , typename ExpressionAST >
struct InputGrammar : qi::grammar<Iterator, ExpressionAST(), ascii::space_type> {
InputGrammar() : InputGrammar::base_type( command ) {
identifier %=
qi::char_("a-zA-Z_")
>> *qi::char_("a-zA-Z_0-9");
command %=
identifier
>> -(
"("
>> -(command % ",")
>> ")");
}
qi::rule< Iterator , std::string(void) , ascii::space_type > identifier;
qi::rule< Iterator , ExpressionAST(void) , ascii::space_type > command;
};
Это большое преимущество использования обернутой структуры, которая тщательно моделирует входные данные.