Lark解析器中无赋值的define语句未被识别,如何解决?
问题分析与解决
你的问题根源在于关键字未被正确识别,以及语法规则的匹配顺序问题:
- 关键字识别问题:
define字符串符合NAME(CNAME)的定义,Lark的tokenizer默认会将其识别为identifiertoken,而非define规则所需的字面量关键字。 - 规则匹配顺序:
expr规则中identifier排在define前面,解析器会优先尝试匹配单个identifier,而非多token的define规则。
解决方法
方法1:显式定义关键字token
在语法中显式定义define、function等关键字,让tokenizer优先识别它们:
import lark parser = lark.Lark(""" ?start: statements ?statements: ((expr (";" | NEWLINE) | NEWLINE ) )* expr? // 调整expr规则顺序,优先匹配关键字相关规则 ?expr: define | assignment | functioncall | function | identifier | number ?functioncall: identifier "(" arguments? ")" ?arguments: expr ("," expr)* // 使用DEFINE关键字代替字面量 ?define: DEFINE identifier ("=" expr)? ?assignment: identifier "=" expr // 使用FUNCTION关键字代替字面量 ?function: FUNCTION "(" parameters? ")" "->" identifier block ?parameters: identifier ("," identifier)* ?block: "{" statements "}" ?identifier: NAME -> identifier ?number: NUMBER -> number // 显式定义关键字token DEFINE: "define" FUNCTION: "function" %import common.NEWLINE %import common.CNAME -> NAME %import common.NUMBER %import common.WS_INLINE %ignore WS_INLINE COMMENT: "/*" /(.|\n)+/x "*/" | "//" /.+/ NEWLINE? %ignore COMMENT """)
方法2:使用Lark的keywords参数
创建Lark实例时直接指定关键字集合,无需修改语法中的字面量:
import lark parser = lark.Lark(""" ?start: statements ?statements: ((expr (";" | NEWLINE) | NEWLINE ) )* expr? // 调整expr规则顺序,优先匹配关键字相关规则 ?expr: define | assignment | functioncall | function | identifier | number ?functioncall: identifier "(" arguments? ")" ?arguments: expr ("," expr)* ?define: "define" identifier ("=" expr)? ?assignment: identifier "=" expr ?function: "function" "(" parameters? ")" "->" identifier block ?parameters: identifier ("," identifier)* ?block: "{" statements "}" ?identifier: NAME -> identifier ?number: NUMBER -> number %import common.NEWLINE %import common.CNAME -> NAME %import common.NUMBER %import common.WS_INLINE %ignore WS_INLINE COMMENT: "/*" /(.|\n)+/x "*/" | "//" /.+/ NEWLINE? %ignore COMMENT """, keywords={"define", "function"})
关键调整点
- 关键字优先级:确保
define等字符串被识别为关键字,而非普通标识符。 - 规则顺序:将
define、assignment等多token规则放在identifier前面,让解析器优先尝试匹配这些规则。
修改后运行你的测试代码,parser.parse("define b")会正确生成define类型的语法树,符合预期。
内容的提问来源于stack exchange,提问作者Mstrdav
相关产品推荐
相关产品推荐

