先决条件——自顶向下解析器的分类、FIRST Set、FOLLOW Set
自顶向下的解析器从非终结符的 start 开始,自顶向下构建解析树。自顶向下的解析器有两种类型:
- 具有回溯功能的自顶向下解析器
- 没有回溯的自上而下的解析器
没有回溯的自顶向下解析器可以进一步分为两部分:
在本文中,我们将讨论非递归下降,也称为 LL(1) 解析器。
LL(1) 解析:
这里第 1 个L表示将按照从左到右的方式对 Input 进行扫描,第二个L表示在这种解析技术中我们将使用最左派生树。最后, 1代表前瞻的数量,这意味着当您要做出决定时,您将看到多少个符号。
构建LL(1)解析表的算法:
步骤1:首先检查语法中是否存在左递归,如果语法中有左递归,则将其删除并转到步骤2。
第 2 步:计算所有非终结符的 First() 和 Follow()。
- First ():如果有一个变量,并且从那个变量开始,如果我们尝试驱动所有的字符串,那么开始的终端符号称为First。
- Follow():什么是推导过程中跟在变量后面的终结符。
第 3 步:对于每个产生式 A –> α。 (A 趋向于 alpha)
- 找到 First(α) 并对 First(α) 中的每个终端,在表中输入 A –> α。
- 如果 First(α) 包含 ε (epsilon) 作为终端比,找到 Follow(A) 并且对于 Follow(A) 中的每个终端,在表中输入 A –> α。
- 如果 First(α) 包含 ε 并且 Follow(A) 包含 $ 作为终结符,则在表中为 $ 输入 A –> α。
为了构造解析表,我们有两个函数:
在表中,行将包含非终端,列将包含终端符号。 Grammars 的所有Null产生式将在 Follow 元素下,其余产生式将在 First set 的元素下。
现在,让我们通过一个例子来理解。
示例 1:
考虑语法:
E --> TE'
E' --> +TE' | ε
T --> FT'
T' --> *FT' | ε
F --> id | (E)
*ε denotes epsilon
找到他们的 First 和 Follow 集合:
First | Follow | |
---|---|---|
E –> TE’ | { id, ( } | { $, ) } |
E’ –> +TE’/ε | { +, ε } | { $, ) } |
T –> FT’ | { id, ( } | { +, $, ) } |
T’ –> *FT’/ε | { *, ε } | { +, $, ) } |
F –> id/(E) | { id, ( } | { *, +, $, ) } |
现在,LL(1) 解析表是:
id | + | * | ( | ) | $ | |
---|---|---|---|---|---|---|
E | E –> TE’ | E –> TE’ | ||||
E’ | E’ –> +TE’ | E’ –> ε | E’ –> ε | |||
T | T –> FT’ | T –> FT’ | ||||
T’ | T’ –> ε | T’ –> *FT’ | T’ –> ε | T’ –> ε | ||
F | F –> id | F –> (E) |
如您所见,所有空产生式都放在该符号的 Follow 集合下,而所有剩余的产生式都位于该符号的 First 之下。
注意:对于 LL(1) 解析表,每种语法都不可行。一个单元格可能包含不止一种产品。
让我们看一个例子。
示例 2:
考虑语法
S --> A | a
A --> a
找到他们的 First 和 Follow 集合:
First | Follow | |
---|---|---|
S –> A/a | { a } | { $ } |
A –>a | { a } | { $ } |
解析表:
a | $ | |
---|---|---|
S | S –> A, S –> a | |
A | A –> a |
在这里,我们可以看到在同一个单元格中有两个产生式。因此,这种语法对于 LL(1) Parser 是不可行的。