LR Parse

LR Parse

个人学习理解,可能有许多理解或者表达上的错误,若有发现错误,欢迎帮我纠正~

L: left to right parsing
R: rightmost derivation

LR 分析器结构

  • Table-based
  • Actions
    • Shift (移进)
    • Reduce (归约)
  • Data Structures
    • Stack of states/symbols {s}
    • Action table: action[s, a]; a是终结符
    • Goto table: goto[s, X]; X是非终结符

LR(K) 代表: 从左至右分析、最右边推导、超前查看 k 个单词

Bottom-up 自底向上的分析

Bottom-up 方式,最终得到的是开始符号s, 换句话讲,构建语法分析树的时候,从叶子结点得到根,如图

LR 就是一种常见的使用 bottom-up分析的 语法分析器。

Bottom-up 语法分析器的分类

LR(0) -> SLR(1) -> LR(1) -> LALR(1)

Shift & Reduce

移进(Shift)、归约(Reduce)是 LR 分析器工作中对输入符号进行处理的两种操作。

移进(Shift)操作:将输入的符号压入到 LR 分析栈。
归约 (Reduce)操作:将 LR 分析栈顶部的某一项或多项用某个产生式归约。换句话说,若栈顶的某些项符合某条产生式的右部,则将这几项出栈,然后将产生式的左部入栈。例如,栈顶有 ABC 三项, 有产生式P -> A B C 则将 A B C 出栈,将 P 入栈,最终栈中只剩下 P。

Action table 和 Goto table 用来指导 LR 分析器进行 Shift 还是 Reduce 操作。

Action & Goto Table

这就有点像有限自动机了, LR 分析栈中的值实际上是状态的 ID。

action 表的说明: action[s, a]

s: State ,类似 DFA 中的状态,输入符号可以转移状态。
a: 符号,类似 DFA 中的符号,输入符号可以转移状态。

每一行都是一个状态( State ), 列是非终结符和终结符组成,非终结符部分构成 Goto 表,用来记录归约后切换的目标状态。

action 表的值有 4 种类型:

  • SX : Shift X X代表状态的 ID
    • push state X 把 X 状态压入到分析栈
    • read new a 读取一个新的字符 a
  • RX: Reduce X
    • 使用产生式 X: $P->Y_1Y_2…Y_k$ 归约
    • 弹出栈中 k 项,后取栈顶状态 u
    • 压栈: goto [ u, P ]
  • A: Accept 识别句子成功
  • 无值:语法错误

Goto 表,goto [ u, p ]

u 是归约后栈顶的状态 ID,P 是非终结符,其实就相当于切换到状态 u 中 P 非终结符的表格的值对应的状态。

Action/Goto 表的构造算法

这一块很抽象,涉及到很多离散数学中的理论,目前我还没系统学习离散数学,理解和表达可能有一些偏差和错误。

构造思路与 NFA 转 DFA 所采用的子集构造法类似。首先找出文法中独立的状态,然后计算每个状态对字母表中每一个字符的转移状态,最后合成一张表。

Configuration Set

  • 每一个集合代表一个状态

“点” 记号

$T->T·F$

这里的 ·是记号,在 F 的左侧,可以预测所有 F 可以推出的产生式,例如:
$T->T·F$
$F->·(T)$
$F->·id$
这些产生式构成的集合就是 Configuration Set

Closure

  • Closure 性质
    如果 $T->X_1…X_i·X_{i+1}…X_n$ 在集合中,$X_{i+1}$是非终结符,那么$X_{i+1}->·Y_1Y_2…Y_n$ 也在该集合中。

    若 $Y_1$ 是非终结符,则继续像集合中添加 $Y_1->·Z_1Z_2Z_3…Z_n$ 直到 ·遇到终结符。

  • Configuration 初始: $closure(S’->·S)$

  • Compute as fixed point

Closure 计算例子

Successor(I, X)

移动 Configuration Set 中点的位置。

  • 保留所有“点”后面是 X 的产生式,$$X \in (N \cup T)$$
  • 将“点”向右移动一个字符
  • 重新计算闭包

例如 Successor(I, ‘(‘) 这里的 I 是 Closure 例子中 I 集合

I 中只有 $F->·(T)$ 满足“点”后面的字符是“(” ,将“点”的位置向右移动 1 个字符,计算 $closure({F->(·T)})$ 作为结果

合在一起,求 G 的所有 states

构造例子

构造的Action/Goto表如下

Viable Prefix in Bottom-up (不知道这个有什么用,先挂这)

两个概念

  • Viable Prefix
  • Handle

例子

1
2
A=>B+id=>(E)+id  
(rightmost derivation)
Operation performed Stack Comments
(.E)+id ( shift (
(E.)+id ( E shift E
(E).+id ( E ) shift )
B.+id B reduce (E) to B
B+.id B + shift +
B+id. B + id shift id
A A reduce B + id to A

得到 (E).+id 的下一步 (E)+ 不在 Stack 中,取而代之的是 B + , 这是因为 (E) 是一个 handle , Stack 中的所有元素不能在 handle 的上入栈。

(,(E,(E) 都是 (E) handleviable prefix

Shift Reduce Parser 的 Stack 中只能放 viable prefix, 遇到 handle 要进行 reduce 操作。

通俗点讲,Parser 在工作的时候,对输入符号序列执行 shift 操作,直到遇到一个 handle。遇到 一个 handle 用相应的产生式(production)把 handle 替换成对应的非终结符,Bottom-upright-side 替换 left-side

viable prefixes 用来辅助 Parser 决定 shift / reduce 操作。

Referrence

https://www.geeksforgeeks.org/viable-prefix-in-bottom-up-parsing/

https://www.geeksforgeeks.org/shift-reduce-parser-compiler/

http://anoopsarkar.github.io/compilers-class/assets/lectures/lr2-lr_0-parsing.pdf


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!