最近用Antlr4开发解释器,在识别带减号“-”的表达式遭遇语法错误,例如
a = 2-1
原因是将“2-1”识别为了2和-1两个token,而我的预期是2、-、1三个token
当然,我也知道之所以这样识别,是因为我定义数字字面量的规则时,支持负号
LiteralInt: '-'?[0-9]+;
当然,我也可以通过如下语法规避此问题,即负号和1之间加个空格,但这样毕竟不易用
a = 2 - 1
我在token规则层面上想了好久都没有解决办法,后来我想到了查看一下python解释器是如何区分的,这也让我找到了答案
import ast
root = ast.parse("a=2-1")
root1 = ast.parse("a=1")
root2 = ast.parse("a=-1")
print(ast.dump(root))
print(ast.dump(root1))
print(ast.dump(root2))
结果如下:
Module(body=[Assign(targets=[Name(id='a', ctx=Store())], value=BinOp(left=Constant(value=2), op=Sub(), right=Constant(value=1)))], type_ignores=[])
Module(body=[Assign(targets=[Name(id='a', ctx=Store())], value=Constant(value=1))], type_ignores=[])
Module(body=[Assign(targets=[Name(id='a', ctx=Store())], value=UnaryOp(op=USub(), operand=Constant(value=1)))], type_ignores=[])
通过三个表达式的解析结果,我发现表达式a=-1中,-1并不是与1一样识别为constant,而是UnaryOp(op=USub(), operand=Constant(value=1)),即一元运算符“-”和常量1
这让我茅塞顿开,马上开始修改我定义的语法
unaryOp: ('+'|'-') expr;
expr
: constant
| ...
;
constant
: LiteralInt
| LiteralFloat
;
// 定义数字字面量,没有负号
LiteralInt: [0-9]+;
至此, 问题解决~