Lark解析器解析多行语句报UnexpectedCharacters错误
问题原因
报错和多行输入本身无关,核心是你写的Lark语法存在循环引用歧义,附带几处语法定义不严谨的问题:
expr规则最后一个分支匹配rest,但rest的第一个分支又反向匹配expr,两个规则形成无限递归的等价关系,解析器处理完第一条语句的分号后,无法明确下一个起始token的归约路径,就会抛出字符不匹配的错误。单行输入能解析成功属于路径巧合,不是语法本身没有问题。- 集合差运算的规则别名拼写错误:
differnce应为difference - 集合字面量
content规则存在冗余的嵌套可选括号,定义不严谨 - 运算规则没有做原子项隔离,后续扩展运算优先级时会出现归约冲突
修复方案
删掉存在循环引用的rest层,新增独立的原子表达式层atom作为最小匹配单元,只匹配集合字面量和变量名,不反向引用上层运算规则,让解析路径清晰无歧义。修复后的完整可运行代码如下:
from lark import Lark class SetLanguageLarkParser(): def __init__(self): self.setParser = Lark(r""" start: statement+ statement : "DISP" expr ";" -> display | name "=" expr ";" -> assign expr : expr "+" atom -> union | expr "-" atom -> difference | expr "*" atom -> cross | expr "|" atom -> intersection | atom atom : content | name content : "{" [ (NUMBER|WORD) ("," (NUMBER|WORD))* ] "}" name : WORD %import common.WORD %import common.NUMBER %import common.WS %ignore WS """, start='start') def main(): data = """ x = {0}; S = {1,2,3}; DISP S + x; """ setLangP = SetLanguageLarkParser() print(setLangP.setParser.parse(data).pretty()) if __name__ == "__main__": main()
验证说明
修复后不管是单行单语句、多行多语句,还是带集合运算的DISP语句,都可以正常解析,不会再出现UnexpectedCharacters: No terminal matches 'S' in the current parser context报错。
内容的提问来源于stack exchange,提问作者Stephen Rodriguez
相关产品推荐
相关产品推荐

