保留 ANTLR4 语法中的顺序

Retaining order in ANTLR4 grammars

对于 ANTLR4 语法(只是一个 MWE)

grammar T;

sequence: ( a | b )*;

a: FORWARD;
b: RIGHT;

FORWARD: 'f';
RIGHT: 'r';

ANTLR4 C++ 后端生成从 antlr4::Parser 派生的解析器 TParser。我对来自 antlr4::ParserRuleContext:

的 class TParser::SequenceContext 感兴趣
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;
};

我的问题是,当我只使用返回的 std::vector<> 时,出现 ab 顺序 丢失了通过 SequenceContext::a()SequenceContext::b() 成员函数。 ANTLR4 语法公式中保留顺序的最佳实践 是什么?还是有另一种方法可以从解析树中获取顺序?请注意,我不想广泛使用访问者或侦听器接口,而是自己遍历解析树。

一个类似的例子是这样的语法(只显示相关部分):

grammar U;

for_statement: 'for' '(' expr? ';' expr? ';' expr? ')' statement

规则的上下文将只向用户显示一个表达式列表。如果只给出最后一个表达式,上下文只给我们一个大小为 1 的 expr 向量,并且没有简单的原因来确定是否给出了第一个、第二个或第三个表达式。

一旦您确定您的输入在语法上是正确的(通过解析),您可以简单地使用您的令牌流遍历所有传入的令牌。它们的顺序与最初给出的顺序完全一致。使用 CommonTokenStream::getTokens() 作为列表。

我使用以下语法修改解决了主要示例:

grammar T;

sequence: direction*;

direction: a | b;

a: FORWARD;
b: RIGHT;

FORWARD: 'f';
RIGHT: 'r';

sequence 上下文中给出了 direction 规则上下文的向量。在 direction 规则上下文中,设置了 aba() != nullptrb() != nullptr)。

对于后一个例子,可以使用 ANTLR 语法的特殊函数修改语法,该函数允许我们命名不同的 expr 部分:

grammar U;

for_statement: 'for' '(' first_expr=expr? ';' second_expr=expr? ';' third_expr=expr? ')' statement

如果给出第一个表达式,for_statement 上下文就会有 first_expr() != nullptrfirst_expr() returns 指向类型 UParser::First_exprContext 的指针并提供正常的 expr 上下文。 ANTLR4 语法中有几个这样的有用函数,可以使遍历解析树更加健壮,因为当语法发生变化时,只需更改使用解析树的代码中的一小部分。