LR(1)文法中的核心项目和搜索符

一、Kernel(核心项目):项目集的“骨架”

1. 什么是核心项目?

核心项目是指在 LR(1) 项目集中,不是通过“闭包运算”生成的项目。它们是项目集的初始成员,其他项目(非核心项目)都是由核心项目通过闭包规则扩展而来的。

具体来说,核心项目包括:

  • 拓广文法的初始项目 [S' → ·S, #](这是整个分析的起点);

  • 所有通过“状态转换”生成的项目(即 GOTO 运算后,· 移动到下一个位置的项目)。

例如:
如果有项目 [A → α·Xβ, a],通过 GOTO 运算(遇到符号 X 时移动 ·)得到 [A → αX·β, a],这个新项目就是核心项目。

2. 核心项目的作用

  • 作为项目集的“种子”:每个项目集都是围绕核心项目展开的,非核心项目只是核心项目的“附属品”(通过闭包规则添加)。

  • 简化项目集的表示:在实际构建 LR(1) 项目集时,只需记录核心项目即可,非核心项目可以通过闭包运算动态生成,减少冗余。

二、搜索符(Lookahead):解决冲突的“指南针”

1. 什么是搜索符?

搜索符是 LR(1) 项目中逗号后面的符号(终结符或 ## 表示输入结束),格式为 [A → α·β, a] 中的 a。它的作用是指示“当前项目完成后,下一个可能出现的符号”,用于精确判断分析动作(移进或归约)。

2. 搜索符的来源

搜索符的产生遵循严格的规则,主要来自两个场景:

(1)初始项目的搜索符

拓广文法的初始项目 [S' → ·S, #] 中,搜索符固定为 #(表示输入结束),因为整个分析的最终目标是推导出 S 并遇到结束符。

(2)闭包运算中生成的搜索符

当通过闭包规则扩展项目集时,新项目的搜索符由“父项目”的信息推导而来:

  • 若父项目是 [A → α·Bβ, a](其中 B 是非终结符),则对于 B 的产生式 B → γ,新生成的项目 [B → ·γ, b] 中,bFirst(βa) 中的所有终结符(First 集表示 βa 能推导出的第一个终结符集合)。

简单说:子项目的搜索符,是父项目中“· 后面的符号串 + 父项目的搜索符”所能推导出的首个终结符

示例:
父项目 [A → α·Bβ, a],B 有产生式 B → γ

  • 计算 First(βa)(β 后面跟 a 能产生的第一个终结符),假设结果为 {b, c}

  • 则闭包运算会生成项目 [B → ·γ, b][B → ·γ, c],搜索符 bc 来自 First(βa)

(3)状态转换中继承的搜索符

当通过 GOTO 运算(移动 ·)生成新的核心项目时,搜索符与原项目保持一致
例如:
原项目 [A → α·Xβ, a],通过 GOTO(X) 生成 [A → αX·β, a],新项目的搜索符仍是 a

3. 搜索符的作用

  • 精确区分归约条件:避免 LR(0) 中“盲目归约”的问题。例如,两个归约项目 [A → α·, a][B → β·, b],只有当搜索符匹配当前输入符号时才执行归约,若 a ≠ b 则不会冲突。

  • 解决移进-归约冲突:例如,项目 [A → α·aβ, b](移进 a)和 [B → γ·, b](归约),若当前输入符号是 a 则移进,是 b 则归约,通过搜索符明确区分。