这可以被 LALR(1) 解析器解析吗?
Can this be parsed by a LALR(1) parser?
我正在用 Bison 为一种具有以下构造的语言编写解析器:
- 自发货:[
identifier
arguments
]
- 调度:[
expression
。 identifier
arguments
]
- 字符串切片:
expression
[expression
,expression
] - 类似于Python.
arguments
是逗号分隔的表达式列表,也可以为空。以上所有内容也是它们自己的表达方式。
我的问题是我不确定如何解析 [method [other_method]]
和 [someString[idx1, idx2].toInt]
,或者是否可以使用 LALR(1) 解析器完全解析。
更准确地说,让我们来看下面的例子:[a[b]]
(调用方法a
,方法b
的结果)。当它到达状态 [a
时。 [b]]
(lookahead是第二个[
),不知道是否要将a
(已经缩减为identifier
)缩减为expression
因为 a[b,c]
之类的东西可能会跟随(它本身可以减少到 expression
并继续上面的第二个构造)或保留它 identifier
(并移动它)因为列表 arguments
将跟随(例如本例中的 [b]
)。
这种 shift/reduce 冲突是由于我表达此语法的方式造成的,还是无法使用 LALR(1) 解析器解析所有这些结构?
还有一个更普遍的问题,如何证明一种语言 is/is 不能被特定类型的解析器解析?
假设你的语法是明确的(你描述的部分似乎是)那么你最好的选择是指定一个 %glr-parser
。因为在大多数情况下,正确的解析将在几个标记之后被强制执行,开销应该不会很明显,优点是您不需要使语法或 AST 的构造复杂化。
一个缺点是 bison 无法验证语法是否无歧义——一般来说,这是不可能的——而且不容易证明。如果发现某些输入不明确,GLR 解析器将产生错误,因此一个好的测试套件很重要。
证明该语言不是 LR(1) 会很棘手,我怀疑这是不可能的,因为该语言可能 可识别 具有 LALR(1) 解析器. (不过,如果不看整个语法就无法判断。)但是解析(在 CS 理论之外)需要创建一个正确的解析树才能有用,并且生成 LR 语法所需的修改类型也会修改 AST ,需要 post-parse 修正。从
之间的优先级差异创建正确的 AST spring 的困难
a[b[c],d]
和
[a[b[c],d]]
在第一个(子集)情况下,b
绑定到它的参数列表 [c]
并且逗号具有较低的优先级;最后,b[c]
和 d
是该切片的兄弟姐妹。在第二种情况(方法调用)中,逗号是参数列表的一部分,并且比方法应用程序绑定得更紧密; b
、[c]
和 d
是方法应用程序中的兄弟。但是在任意长的输入之前你不能决定解析树的形状(因为 d
可以是任何表达式)。
由于 "precedence" 无法正式定义,所以这有点手忙脚乱,并且有一些 hack 可以调整树。由于LR 属性 不是真正可组合的,因此确实可以提供更严格的分析。但无论如何,GLR 解析器可能是最简单、最可靠的解决方案。
一点供日后参考:CFG不仅仅是一种编程工具;它们还有助于清楚地传达所讨论的语法。通常,如果您想描述您的语言,最好使用清晰的 CFG,而不是试图非正式地描述。当然,有意义的非终结符名称会有所帮助,并且一些示例也无妨,但语法的本质在于正式描述和省略,这使得其他人更难 "be helpful".
我正在用 Bison 为一种具有以下构造的语言编写解析器:
- 自发货:[
identifier
arguments
] - 调度:[
expression
。identifier
arguments
] - 字符串切片:
expression
[expression
,expression
] - 类似于Python.
arguments
是逗号分隔的表达式列表,也可以为空。以上所有内容也是它们自己的表达方式。
我的问题是我不确定如何解析 [method [other_method]]
和 [someString[idx1, idx2].toInt]
,或者是否可以使用 LALR(1) 解析器完全解析。
更准确地说,让我们来看下面的例子:[a[b]]
(调用方法a
,方法b
的结果)。当它到达状态 [a
时。 [b]]
(lookahead是第二个[
),不知道是否要将a
(已经缩减为identifier
)缩减为expression
因为 a[b,c]
之类的东西可能会跟随(它本身可以减少到 expression
并继续上面的第二个构造)或保留它 identifier
(并移动它)因为列表 arguments
将跟随(例如本例中的 [b]
)。
这种 shift/reduce 冲突是由于我表达此语法的方式造成的,还是无法使用 LALR(1) 解析器解析所有这些结构?
还有一个更普遍的问题,如何证明一种语言 is/is 不能被特定类型的解析器解析?
假设你的语法是明确的(你描述的部分似乎是)那么你最好的选择是指定一个 %glr-parser
。因为在大多数情况下,正确的解析将在几个标记之后被强制执行,开销应该不会很明显,优点是您不需要使语法或 AST 的构造复杂化。
一个缺点是 bison 无法验证语法是否无歧义——一般来说,这是不可能的——而且不容易证明。如果发现某些输入不明确,GLR 解析器将产生错误,因此一个好的测试套件很重要。
证明该语言不是 LR(1) 会很棘手,我怀疑这是不可能的,因为该语言可能 可识别 具有 LALR(1) 解析器. (不过,如果不看整个语法就无法判断。)但是解析(在 CS 理论之外)需要创建一个正确的解析树才能有用,并且生成 LR 语法所需的修改类型也会修改 AST ,需要 post-parse 修正。从
之间的优先级差异创建正确的 AST spring 的困难a[b[c],d]
和
[a[b[c],d]]
在第一个(子集)情况下,b
绑定到它的参数列表 [c]
并且逗号具有较低的优先级;最后,b[c]
和 d
是该切片的兄弟姐妹。在第二种情况(方法调用)中,逗号是参数列表的一部分,并且比方法应用程序绑定得更紧密; b
、[c]
和 d
是方法应用程序中的兄弟。但是在任意长的输入之前你不能决定解析树的形状(因为 d
可以是任何表达式)。
由于 "precedence" 无法正式定义,所以这有点手忙脚乱,并且有一些 hack 可以调整树。由于LR 属性 不是真正可组合的,因此确实可以提供更严格的分析。但无论如何,GLR 解析器可能是最简单、最可靠的解决方案。
一点供日后参考:CFG不仅仅是一种编程工具;它们还有助于清楚地传达所讨论的语法。通常,如果您想描述您的语言,最好使用清晰的 CFG,而不是试图非正式地描述。当然,有意义的非终结符名称会有所帮助,并且一些示例也无妨,但语法的本质在于正式描述和省略,这使得其他人更难 "be helpful".