Lark解析器语法适用于Earley,但不适用于LALR

2024-06-25 23:24:48 发布

您现在位置:Python中文网/ 问答频道 /正文

考虑一下Python Lark parser的这个简单测试:

GRAMMAR = '''
start: container*

container: string ":" "{" (container | attribute | attribute_value)* "}"
attribute: attribute_name "=" (attribute_value | container)
attribute_value: string ":" _value ("," _value)*
_value: number | string

attribute_name: /[A-Za-z_][A-Za-z_#0-9]*/

string: /[A-Za-z_#0-9]+/
number: /[0-9]+/

    %import common.WS
    %ignore WS
'''

data = '''outer : {
 inner : {
 }
}'''

parser = Lark(GRAMMAR, parser='lalr')
parser.parse(data)

这对parser='earley'有效,但对parser='lalr'无效。我不明白为什么。错误消息是:

UnexpectedCharacters: No terminal defined for '{' at line 2 col 12

inner : {

这只是一个中景。我的实际语法也有同样的问题。你知道吗


Tags: nameparsernumberdatastringwsvaluecontainer
1条回答
网友
1楼 · 发布于 2024-06-25 23:24:48

LALR失败的原因是它的lookahead为1(不像Earley,它有无限的lookahead),并且它在attribute_namestring之间混淆了。一旦它匹配了另一个规则(在本例中是attribute_name),它就不可能回溯并匹配不同的规则。你知道吗

如果您对属性名称终端使用较低的优先级,它将起作用。例如:

attribute_name: ATTR

ATTR.0: /[A-Za-z_][A-Za-z_#0-9]*/

但建议的做法是,如果可能的话,对两者使用相同的终端,这样解析器就可以替您思考,而不是lexer。如果需要,可以在解析完成后添加额外的验证。你知道吗

这两种方法(更改优先级或合并终端)都可以解决您的问题。你知道吗

相关问题 更多 >