Для грамматики ANTLR4 (просто MWE)
grammar T;
sequence: ( a | b )*;
a: FORWARD;
b: RIGHT;
FORWARD: 'f';
RIGHT: 'r';
бэкэнд ANTLR4 C ++ генерирует парсер TParser
вытекающий из antlr4::Parser
, Я заинтересован в классе TParser::SequenceContext
, происходит от antlr4::ParserRuleContext
:
class SequenceContext : public antlr4::ParserRuleContext {
public:
SequenceContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
antlr4::tree::TerminalNode *EOF();
std::vector<AContext *> a();
AContext* a(size_t i);
std::vector<BContext *> b();
BContext* b(size_t i);
virtual void enterRule(antlr4::tree::ParseTreeListener *listener) override;
virtual void exitRule(antlr4::tree::ParseTreeListener *listener) override;
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
};
Моя проблема в том, что порядок из случаев a
а также b
теряется, когда я использую только std::vector<>
с возвращенными SequenceContext::a()
а также SequenceContext::b()
функции-члены. Что лучшая практика в формулировке ANTLR4, чтобы сохранить порядок? Или есть другой способ получить заказ из дерева разбора? Обратите внимание, что я не хочу широко использовать интерфейсы посетителя или слушателя, а скорее сам иду по дереву разбора.
Подобный пример будет похож на грамматику (показаны только соответствующие части):
grammar U;
for_statement: 'for' '(' expr? ';' expr? ';' expr? ')' statement
Контекст для правила предоставит пользователю только список выражений. Если дано только последнее выражение, контекст дает нам только вектор expr
с размером 1 и без простого, почему бы определить, было ли дано первое, второе или третье выражение.
После того, как вы определили, что ваши входные данные синтаксически верны (анализируя их), вы можете просто использовать поток токенов, чтобы просмотреть все входящие токены. Они находятся в точном порядке, как указано изначально. использование CommonTokenStream::getTokens()
для списка.
Я решил основной пример, используя следующие модификации грамматики:
grammar T;
sequence: direction*;
direction: a | b;
a: FORWARD;
b: RIGHT;
FORWARD: 'f';
RIGHT: 'r';
который дает вектор direction
правила контекстов в sequence
контекст. в direction
контекст правила, либо a
или же b
установлено (a() != nullptr
или же b() != nullptr
).
В последнем примере грамматику можно изменить, используя специальную функцию грамматики ANTLR, которая позволяет нам называть разные expr
части:
grammar U;
for_statement: 'for' '(' first_expr=expr? ';' second_expr=expr? ';' third_expr=expr? ')' statement
for_statement
контекст тогда имеет first_expr() != nullptr
если первое выражение было дано. first_expr()
возвращает указатель на тип UParser::First_exprContext
и обеспечивает нормальный expr
контекст. В грамматике ANTLR4 есть несколько таких полезных функций, которые могут сделать обход дерева синтаксического анализа более надежным с точки зрения необходимости только изменения небольших частей в коде, который использует дерево синтаксического анализа, когда грамматика изменяется.