这节课的目的是教大家如何使用K的内置特性来消除歧义,将歧义语法规范转换成明确表达AST的语法规范。
优先级块
在实践中,很少有自然语言处理领域之外的形式化语言是模棱两可的。主要原因是,解析明确的语言比解析模糊的语言要快得多。相反,编程语言设计者通常使用运算符优先级和关联的概念来使表达式语法规范没有歧义。这些机制的工作原理是,在出现歧义时,指示解析器拒绝某些AST,而采用其他AST; 通常,使用这些技术可以消除语法规范中的“所有”歧义。
虽然有时可以显式地重写语法规范来删除这些解析,但由于K语言的语法规范和AST生成是不可避免地联系在一起的,所以通常不鼓励这样做。相反,我们使用显式表示不同操作符,在不同情况下拥有相应优先级的方法来解决歧义。
例如,在C语言中,&&
要优先于||
,这就意味着表达式true && false || false
只会有一个有效的AST:(true && false) || false
下面我们就来看看,基于语法规范的第3次迭代(lesson-04-a.k
):
module LESSON-04-A
syntax Boolean ::= "true" | "false"
| "(" Boolean ")" [bracket]
> "!" Boolean [function]
> Boolean "&&" Boolean [function]
> Boolean "^" Boolean [function]
> Boolean "||" Boolean [function]
endmodule
在本例中,在单个块中分隔生产的一些|
符号已被替换为>
。这是用来描述与这个生产块关联的优先级组。
在这个例子中,第一个优先级组由语言的原子组成:true
, false
和括号操作符。通常,优先级组从::=
或>
操作符开始,扩展到下一个>
操作符或生产块的末尾。因此,我们可以看到,该语法规范中的第二、第三、第四和第五优先级组都由一个生产组成。
在解析程序时,这些优先级组的含义变得明确显起来:具有较小优先级的符号(即,绑定较松的的符号)不能作为具有较高优先级的符号的直接子级(即,绑定较紧的的符号)出现。在这种情况下,>
操作符可以被看作是一个大于的操作符,描述了对生产块中的生产的可传递的部分排序,表达了它们的相对优先级。
为了更具体地了解这一点,让我们再次看看程序true && false || false
。如前所述,以前这个程序是不明确的,因为解析器可以选择&&
是||
的子元素,反之亦然。然而,由于优先级较低的符号(即||
)不能作为优先级较高的符号(即&&
)的直接子元素出