Antlr4 意外停止解析表达式

Antlr4 unexpectedly stops parsing expression

我正在使用公式语法开发一个简单的计算器:

grammar Formula ;
expr : <assoc=right> expr POW expr             # pow
     | MINUS expr                              # unaryMinus
     | PLUS expr                               # unaryPlus
     | expr PERCENT                            # percent
     | expr op=(MULTIPLICATION|DIVISION) expr  # multiplyDivide
     | expr op=(PLUS|MINUS) expr               # addSubtract
     | ABS '(' expr ')'                        # abs
     | '|' expr '|'                            # absParenthesis
     | MAX '(' expr ( ',' expr )* ')'          # max
     | MIN '(' expr ( ',' expr )* ')'          # min
     | '(' expr  ')'                           # parenthesis
     | NUMBER                                  # number
     | '"' COLUMN '"'                          # column
     ;

MULTIPLICATION: '*' ;
DIVISION: '/' ;
PLUS: '+' ;
MINUS: '-' ;
PERCENT: '%' ;
POW: '^' ;
ABS: [aA][bB][sS] ;
MAX: [mM][aA][xX] ;
MIN: [mM][iI][nN] ;
NUMBER: [0-9]+('.'[0-9]+)? ;
COLUMN: (~[\r\n"])+ ;
WS : [ \t\r\n]+ -> skip ;

"column a"*"column b" 输入按预期给了我以下树:

但是 "column a" * "column b" 输入意外停止解析:

我错过了什么?

您的 WS 规则被 COLUMN 规则打破,后者具有更高的 。更准确地说,问题是 ~[\r\n"] 也匹配 space 个字符。

"column a"*"column b" 词法如下:'"' COLUMN '"' MULTIPLICATION '"' COLUMN '"'

"column a" * "column b" 词法如下:'"' COLUMN '"' COLUMN '"' COLUMN '"'

是的,“space star space”被词法化为 COLUMN 标记,因为这就是 ANTLR 词法分析器规则的工作方式:更长的标记匹配优先。

如您所见,此令牌流 匹配整个 expr 规则,因此 expr 尽可能多地匹配,这是 '"' COLUMN '"'.

像您一样声明仅包含否定规则的词法分析器规则总是一个坏主意。拥有单独的 '"' 令牌也不适合我。

您应该做的是将引号包含在 COLUMN 规则中,因为它们在逻辑上是标记的一部分:

COLUMN: '"' (~["\r\n])* '"';

然后从您的解析器规则中删除独立引号。您可以稍后在处理解析树时取消对文本的引用,或者更改词法分析器中的令牌发射逻辑以更改令牌的基础值。

并且为了不忽略尾随输入,添加另一条规则以确保您已经消耗了整个输入:

formula: expr EOF;

然后在调用解析器时使用此规则而不是 expr 作为入口规则。

But "column a" * "column b" input unexpectedly stops parsing

如果我 运行 你的语法使用 ANTLR 4.6,它不会停止解析,它会解析整个文件并以粉红色显示解析器无法匹配的内容:

圆点代表空格。

还有一条重要的错误信息:

line 1:10 mismatched input ' * ' expecting {<EOF>, '*', '/', '+', '-', '%', '^'}

正如我解释的那样 一旦出现 "mismatched" 错误,请将 -tokens 添加到 g运行.

"column a"*"column b":

$ grun Formula expr -tokens -diagnostics t1.text
[@0,0:0='"',<'"'>,1:0]
[@1,1:8='column a',<COLUMN>,1:1]
[@2,9:9='"',<'"'>,1:9]
[@3,10:10='*',<'*'>,1:10]
[@4,11:11='"',<'"'>,1:11]
[@5,12:19='column b',<COLUMN>,1:12]
[@6,20:20='"',<'"'>,1:20]
[@7,22:21='<EOF>',<EOF>,2:0]

"column a" * "column b":

$ grun Formula expr -tokens -diagnostics t2.text
[@0,0:0='"',<'"'>,1:0]
[@1,1:8='column a',<COLUMN>,1:1]
[@2,9:9='"',<'"'>,1:9]
[@3,10:12=' * ',<COLUMN>,1:10]
[@4,13:13='"',<'"'>,1:13]
[@5,14:21='column b',<COLUMN>,1:14]
[@6,22:22='"',<'"'>,1:22]
[@7,24:23='<EOF>',<EOF>,2:0]
line 1:10 mismatched input ' * ' expecting {<EOF>, '*', '/', '+', '-', '%', '^'}

您会立即看到 " * " 被解释为 COLUMN

最近几天有人问了很多关于匹配输入与词法分析器规则的问题:

卢卡斯多次发布了一个错误的问题,只是为了做出一个总结所有问题的答案: