为什么 Antlr 默认使用某些替代方案?

Why does Antlr default to certain alternatives over others?

我正在使用 IntelliJ 的 antlr4 插件为我正在处理的项目创建语法。在学习如何使用antlr的过程中,我看了下Github用户shmatov的简单antlr4计算器,如下所示。

grammar Calculator;
INT    : [0-9]+;
DOUBLE : [0-9]+'.'[0-9]+;
PI     : 'pi';
E      : 'e';
POW    : '^';
NL     : '\n';
WS     : [ \t\r]+ -> skip;
ID     : [a-zA-Z_][a-zA-Z_0-9]*;

PLUS  : '+';
EQUAL : '=';
MINUS : '-';
MULT  : '*';
DIV   : '/';
LPAR  : '(';
RPAR  : ')';

input
    : plusOrMinus NL? EOF # Calculate
    ;

plusOrMinus 
    : plusOrMinus PLUS multOrDiv  # Plus
    | plusOrMinus MINUS multOrDiv # Minus
    | multOrDiv                   # ToMultOrDiv
    ;

multOrDiv
    : multOrDiv MULT pow # Multiplication
    | multOrDiv DIV pow  # Division
    | pow                # ToPow
    ;

pow
    : unaryMinus (POW pow)? # Power
    ;

unaryMinus
    : MINUS unaryMinus # ChangeSign
    | atom             # ToAtom
    ;

atom
    : PI                    # ConstantPI
    | E                     # ConstantE
    | DOUBLE                # Double
    | INT                   # Int
    | ID                    # Variable
    | LPAR plusOrMinus RPAR # Braces
    ;

有趣的是,当输入单个数字时,例如整数“5”,生成的分析树显示#Plus 和#Multiplication 标签是运行。这对我来说没有多大意义。输入中没有 +* 运算符。我在下面上传了一张解析树的图片,以便更好地理解我在说什么。

似乎 antlr 只是默认规则中的第一个选项是什么,但是计算器直接通过标签 # Calculate -> # ToMultOrDiv -> # ToPow -> # ToAtom -> # Int 不是更有意义吗?如果没有正确的运算符,它如何通过#Plus 和#Multiplication?

好观察!我猜 ANTLR 插件没有正确显示标签。你可以在这里打开一个问题:https://github.com/antlr/intellij-plugin-v4/issues (EDIT, opened an issue myself: https://github.com/antlr/antlr4/issues/2222)

当您让输入 "5" 通过侦听器时,您将看到显示的正确路径:

import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTreeWalker;

public class Main {

    static class Listener extends CalculatorBaseListener {

        @Override
        public void enterCalculate(CalculatorParser.CalculateContext ctx) {
            System.out.println("Calculate");
        }

        @Override
        public void enterToMultOrDiv(CalculatorParser.ToMultOrDivContext ctx) {
            System.out.println("ToMultOrDiv");
        }

        @Override
        public void enterToPow(CalculatorParser.ToPowContext ctx) {
            System.out.println("ToPow");
        }

        @Override
        public void enterPower(CalculatorParser.PowerContext ctx) {
            System.out.println("Power");
        }

        @Override
        public void enterToAtom(CalculatorParser.ToAtomContext ctx) {
            System.out.println("ToAtom");
        }

        @Override
        public void enterInt(CalculatorParser.IntContext ctx) {
            System.out.println("Int");
        }
    }

    public static void main(String[] args) {
        CalculatorLexer lexer = new CalculatorLexer(CharStreams.fromString("5"));
        CalculatorParser parser = new CalculatorParser(new CommonTokenStream(lexer));
        ParseTreeWalker.DEFAULT.walk(new Listener(), parser.input());
    }
}

这将打印:

Calculate
ToMultOrDiv
ToPow
Power
ToAtom
Int