为同一种语言生成 LR(1) 语法很容易。诀窍是找到一个具有相似解析树的解析树,或者至少可以轻松地从中恢复原始解析树。
这是一个手动生成的语法,它是从一般算法略微简化的。实际上,我们重写了正则表达式:
(id:id<sup>*</sup>)<sup>+</sup>
到:
id(:id<sup>+</sup>)<sup>*</sup>:id<sup>*</sup>
引出语法:
S → id G $
G → P G | P'
P' → : R'
P → : R
R' → ε | id R'
R → ε | id R
这是 LALR(1)。
实际上,我们只是将所有产生式向右移动了一个标记,并且有一个通用算法可用于从LR(k+1) 语法为任何k≥1 创建LR(1) 语法。 (我使用的这个算法的版本来自 S. Sippu 和 E. Soisalon-Soininen 的 Parsing Theory,第二卷,第 6.7 节。)
新语法的非终结符将具有(x, V, y) 的形式,其中V 是原始语法的符号(终结符或非终结符),x 和y 是终结符序列最大长度k 使得:
y ∈ FOLLOWk(V)
x ∈ FIRSTk(Vy)
(如果输入的结尾包含在后续集中,y 和因此x 的长度可能小于k。有些人通过添加k 结束符号来避免这个问题,但我认为这个版本同样简单。)
非终结符(x, V, y) 将生成从原始语法中派生自Vy 的字符串的x-导数。非正式地,整个语法向右移动k标记;每个非终结符都匹配一个缺少第一个 k 标记但增加了以下 k 标记的字符串。
这些作品是从原始作品中机械生成的。首先,我们添加一个新的开始符号,S' 和产生式:
S' → x (x, S, ε)
对于每个x ∈ FIRST<sub>k</sub>(S)。然后,对于每个生产
T → V<sub>0</sub> V<sub>1</sub> … V<sub>m</sub>
我们生成一组产品:
(x<sub>0</sub>,T,x<sub>m+1</sub>) → (x<sub>0</sub>,V<sub>0</sub>,x<sub>1</sub>) (x<sub>1</sub>,V<sub>1</sub>,x<sub>2</sub>) … (x<sub>m</sub>,V<sub>m</sub>,x<sub>m+1</sub>)
对于每个终端A,我们生成一组产品
(Ax,A,xB) → B if |x| = k
(Ax,A,x) → ε if |x| ≤ k
由于新语法中的产生式与旧语法中的产生式之间存在明显的同态性,因此我们可以直接创建原始解析树,尽管我们需要对语义值进行一些技巧才能正确附加它们到解析树。