我有一个简单的语法,它逐节解析键值对。
k1:1
k2:x
k3:3
k4:4
我的语法是:
start: section (_sep section)*
_sep: _NEWLINE _NEWLINE+
section: item (_NEWLINE item)*
item: NAME ":" VALUE
_NEWLINE: /\r?\n[\t ]*/
VALUE: /\w+/
NAME: /\w+/
但是,语法在使用earley 解析器时有效,但在使用lalr 解析器时无效。
使用以下代码:
from lark import Lark
import logging
from pathlib import Path
logging.basicConfig(level=logging.DEBUG)
my_grammar = Path("my_grammar.lark").read_text()
print(my_grammar)
early = Lark(my_grammar, debug=True)
print(my_grammar)
lalr = Lark(my_grammar, parser='lalr', debug=True)
text = """
k1:1
k2:x
k3:3
k4:4
"""
print(text.strip())
print(early.parse(text.strip()).pretty())
print(lalr.parse(text.strip()).pretty())
厄利解析器给了我有效的结果。
start
section
item
k1
1
item
k2
x
section
item
k3
3
item
k4
4
但是 lalr 解析器没有
lark.exceptions.UnexpectedCharacters: No terminal defined for '
' at line 3 col 1
^
Expecting: {'NAME'}
PS:问题出在_NEWLINE。
Lark-parser 语法在语法文件中配置词法分析器和解析器。在我上面的语法中,一行将被标记为 _NEWLINE。多个新行将被标记为 _NEWLINE.. _NEWLINE。它使解析器感到困惑。
更改_sep
为/\r?\n[\t ]*(\r?\n[\t ]*)/
. 多行将被标记为一个标记。lalr(1) 解析器可以顺利地处理它。
当我让它工作时。仍然好奇早期的解析器是如何做到正确的。