Cyan's Blog

Search

Search IconIcon to open search

Compiler-4-2_LR(0)_Parse

Last updated Oct 15, 2022 Edit Source

# LR (0) Parse

# LR (0) 项目 - LR (0) Item

# 构建转化规则: DFA

这涉及到两个操作

这里可以联系形式语言与自动机的知识: 构成 DFA 有两种不同的思路: 我们可以先根据产生式构造一个 LR 项的 NFA, 然后再转化为 DFA1; 或者我们也可以直接构造 DFA. 不过 LR 分析的时候我们通常都采用后一种方法: 即从初始状态出发, 不断地根据所有可能的输入求闭包, 生成新的状态集, 直到状态数不变.

下面我们详细解释这两种操作:

# Closure (a set of items)

这是算法: 400

直观的来说, 这通常会让这个项 $$\mathrm{S} \rightarrow . \mathrm{L} \alpha$$ 变成这个集合: $$\begin{aligned} &\mathrm{S} \rightarrow . \mathrm{L} \alpha \\ &\mathrm{L} \rightarrow .(\mathrm{L}) \\ &\mathrm{L} \rightarrow . \mathrm{\beta} \end{aligned}$$ 可是, 为什么下面这两个新加进来的项会和上面的项拥有相同的地位呢?

我们从闭包的角度来考虑这个问题:2

所以我们上面的例子可以这样理解: CLOSURE

# Goto (a set, a character)

这是算法: 300 即对于每一个 LR 项目, 尝试向后移动一个符号 (包括终结符和非终结符), 然后再取这个转移的闭包.

# 构建 DFA

说明了两个基本操作, 接下来便是从初始状态出发, 不断"转移, 取闭包, 转移, 取闭包……“直到整个 DFA 没有变化. 这和 NFA 转 DFA 时候的思想很相似.

590

# 构建转移表 DFA → ACTION & GOTO tables

500

# Start Parsing

相比维护符号栈和状态栈两个栈, 我们也可以只维护一个栈, 将状态和对应的符号都压到这个栈里面, 只是需要注意这样 reduce 的时候需要 pop 两倍于 RHS (产生式右侧) 长度的元素.

# LR (0) 文法的不足

# 移进-归约冲突

# 归约-归约冲突

同理, 要是有个状态里面有两个不同的完全识别的句柄: $P\rightarrow\alpha\space \cdot$ 与 $Q\rightarrow\beta\space \cdot$ 那么就出现了归约-归约冲突.


  1. 见CCP&P Page155 ↩︎

  2. 见CCP&P 5.2.2节 ↩︎

  3. 见 CCP&P 5.2.3 节 ↩︎