我如何确定 ANTLR 4 用来解析表达式的规则?

How can I determine the rule which is used by ANTLR 4 to parse the expression?

我正在尝试从 ANTLR 4 创建的解析树创建构建 AST(我的自定义 class 层次结构中的抽象语法树)的 Java class。我正在做这是一阶逻辑语言 https://github.com/antlr/grammars-v4/blob/master/fol/fol.g4

具体来说,我正在寻找 formula:

的规则
 formula
   : formula bin_connective formula 
   | NOT formula bin_connective formula
   | NOT formula 
   | FORALL LPAREN variable RPAREN formula 
   | EXISTS LPAREN variable RPAREN formula
   | pred_constant LPAREN term (separator term)* RPAREN
   | term EQUAL term
   ;

ANTLR 4 为 formula 生成了以下 class,我在这里只展示了一部分(为了简洁起见,我删除了实现 - 它是标准的,由 ANTLR 4 生成,并且只是调用一些技术方法):

public static class FormulaContext extends ParserRuleContext {
        public TerminalNode NOT() { ... }
        public List<FormulaContext> formula() { ... }
        public FormulaContext formula(int i) { ... }
        public Bin_connectiveContext bin_connective() { ... }
        public TerminalNode FORALL() { ... }
        public TerminalNode LPAREN() { ... }
        public VariableContext variable() { ... }
        public TerminalNode RPAREN() { ... }
        public TerminalNode EXISTS() { ... }
        public Pred_constantContext pred_constant() { ... }
        public List<TermContext> term() { ... }
        public TermContext term(int i) { ...  }
        public List<SeparatorContext> separator() { ... }
        public SeparatorContext separator(int i) { ... }
        public TerminalNode EQUAL() { ... }
        public FormulaContext(ParserRuleContext parent, int invokingState) {
            super(parent, invokingState);
        }
        @Override public int getRuleIndex() { return RULE_formula; }
        @Override
        public void enterRule(ParseTreeListener listener) {
            if ( listener instanceof FOLListener ) ((FOLListener)listener).enterFormula(this);
        }
        @Override
        public void exitRule(ParseTreeListener listener) {
            if ( listener instanceof FOLListener ) ((FOLListener)listener).exitFormula(this);
        }
    } 

所以-可以看出:如果有包含NOT的规则,则有方法TerminalNode NOT,是否有一个或多个方法包含一个或多个公式,则有有 2 种方法 - 一种 returns FormulaContext 和另一种 returns ArrayList<FormulaContext>。没有更多有价值的方法了。

假设我有 FormulaContext 个实例,我想进一步检查它。 我该怎么办? 我的期望是知道 FormulaContext 这个实例的构造规则,然后我知道哪些方法 (e.t。formula(0); bin_connective(); formula(1); 对于第一条规则)我可以调用并且我可以安全地调用这些方法。

问题是 - 我找不到确定用于构造的规则的方法,这是非终结符吗?当然,我可以尝试为每个规则(例如 testRule1、testRule2 等)创建测试方法,它调用上述方法并检查公式、NOT、bin_connective 和所有这些子项的可用性,然后可以推断使用了哪个规则,然后进一步消化正在考虑的实例。

但是这样的测试方法是正确的方法吗?我简直不敢相信这一切都如此简陋。此外,此类测试方法可以由 ANTLR 4 自动生成,有关于它们的所有信息,但仍然 - ANTLR 没有此类功能。

那么 - 推断非终结符规则的最佳做法是什么 class?

您可以 label your alternatives 使用 # 运算符,如下所示:

formula
    : formula bin_connective formula #BinaryFormula
    | NOT formula                    #Negation
    | ...
    ;

这将创建继承自 FormulaContext 的 classes NegationContext 等。因此,您可以根据得到的 class 判断选择了哪个备选方案。在访问者和听众中,您现在可以重载 visitNegation(NegationContext) 等来访问特定类型的公式。