我正在使用ANTLR 4.8为SML构建一个解析器,由于某种原因,生成的解析器会因为整型字面值而卡住:
# CLASSPATH=bin ./scripts/grun SML expression -tree <<<'1'
line 1:0 mismatched input '1' expecting {'(', 'let', 'op', '{', '()', '[', '#', 'raise', 'if', 'while', 'case', 'fn', LONGID, CONSTANT}
(expression 1)我已经尽可能地修剪了语法,以仍然显示这个问题,这看起来非常奇怪。这个语法显示了这个问题(尽管甚至没有使用LABEL ):
grammar SML_Small;
Whitespace : [ \t\r\n]+ -> skip ;
expression : CONSTANT ;
LABEL : [1-9] NUM* ;
CONSTANT : INT ;
INT : '~'? NUM ;
NUM : DIGIT+ ;
DIGIT : [0-9] ;另一方面,删除LABEL会使正数再次工作:
grammar SML_Small;
Whitespace : [ \t\r\n]+ -> skip ;
expression : CONSTANT ;
CONSTANT : INT ;
INT : '~'? NUM ;
NUM : DIGIT+ ;
DIGIT : [0-9] ;我曾尝试用DIGIT?和类似的变体替换NUM*,但这并没有解决我的问题。
我真的不确定发生了什么,所以我怀疑这是比我使用的语法更深层次的东西。
发布于 2020-08-25 15:27:53
正如Rici在评论中提到的: lexer尝试匹配尽可能多的字符,当2个或更多规则匹配相同的字符时,首先定义的规则“获胜”。因此,有了这样的规则:
LABEL : [1-9] NUM* ;
CONSTANT : INT ;
INT : '~'? NUM ;
NUM : DIGIT+ ;
DIGIT : [0-9] ;输入1将始终成为LABEL。而像0这样的输入永远是一个CONSTANT。仅当遇到后跟某些数字的~时,才会创建INT令牌。NUM和DIGIT永远不会生成令牌,因为它之前的规则将是匹配的。NUM和DIGIT本身永远不能成为令牌,这一事实使它们成为fragment tokens的候选对象
fragment NUM : DIGIT+ ;
fragment DIGIT : [0-9] ;这样,您就不会意外地在解析器规则中使用这些标记。
此外,让~成为令牌的一部分通常不是可行的方法。您可能还希望~(1 + 2)是一个有效的表达式。因此,在解析器规则expression : '~' expression | ... ;中通常更好地使用像~这样的一元运算符。
最后,如果你想区分一个非零整数值作为标签,你可以这样做:
grammar SML_Small;
expression
: '(' expression ')'
| '~' expression
| integer
;
integer
: INT
| INT_NON_ZERO
;
label
: INT_NON_ZERO
;
INT_NON_ZERO : [1-9] DIGIT* ;
INT : DIGIT+ ;
SPACES : [ \t\r\n]+ -> skip ;
fragment DIGIT : [0-9] ;https://stackoverflow.com/questions/63570019
复制相似问题