python - Lark 解析器语法适用于 Earley,但不适用于 LALR
问题描述
考虑一下Python Lark 解析器的这个简单测试:
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:在第 2 列第 12 行没有为“{”定义终端
内部:{
这只是一个 MWE。我的实际语法也遇到了同样的问题。
解决方案
LALR 失败的原因是它的前瞻为 1(不像 Earley,它具有无限的前瞻),并且在attribute_name
和之间混淆string
。一旦它与另一个匹配(在本例中为attribute_name
),它就不可能回溯并匹配不同的规则。
如果您对 attribute_name 终端使用较低的优先级,它将起作用。例如:
attribute_name: ATTR
ATTR.0: /[A-Za-z_][A-Za-z_#0-9]*/
但建议的做法是尽可能为两者使用相同的终端,以便解析器代替词法分析器为您进行思考。如果需要,您可以在解析完成后添加额外的验证。
两种方法(更改优先级或合并终端)都可以解决您的问题。
推荐阅读
- javascript - 停止等待 setTimeOut 函数
- android - 什么版本的 Android Studio 与 Androidx (Android Jetpack) 源代码一起使用
- copy - 在 Amazon EC2 实例中通过 RDP 复制文件
- r - ggplot 版本的 matplot
- angular - 显示参数传递的组件
- ajax - 在 Laravel 上使用 Modal 更新数据
- javascript - 使用 event.target 返回一组项目(全局 div)中的修改项目
- typescript - 打字稿 - 重复标识符错误 - const x: ({ y: string, z: string }) => string;
- r - 如何使用 ggplot2 中的 shapefile 从第一个绘图中保留 scale_fill_color
- java - 为什么我仍然得到一个 ArrayList。
在 for 循环中使用 ArrayList.add(Object) 时出错?