📜  非递归预测解析算法

📅  最后修改于: 2021-09-27 22:40:16             🧑  作者: Mango

先决条件 – 自顶向下解析器的分类
预测解析是递归下降解析的一种特殊形式,不需要回溯,因此可以预测使用哪些乘积来替换输入字符串。
非递归预测解析或表驱动也称为 LL(1) 解析器。此解析器遵循最左派生 (LMD)。

LL(1):
here, first L is for Left to Right scanning of inputs,
 the second L is for left most derivation procedure,
  1 = Number of Look Ahead Symbols 

预测解析期间的主要问题是确定要应用于非终结符的产生式。
这个非递归解析器在解析表中查找要应用的乘积。 LL(1) 解析器具有以下组件:

(1) buffer: an input buffer which contains the string to be passed 
(2) stack: a pushdown stack which contains a sequence of grammar symbols 
(3) A parsing table: a 2d array M[A, a] 
    where
    A->non-terminal, a->terminal or $
(4) output stream:
 end of the stack and an end of the input symbols are both denoted with $ 

非递归预测解析算法:
主要概念 -> 借助 FIRST() 和 FOLLOW() 集,可以仅使用避免递归调用的堆栈来完成此解析。

对于每个规则,语法 G 中的 A->x:

  1. 对于包含在 FIRST(A) 中的每个终端 ‘a’,如果 x 派生 ‘a’ 作为第一个符号,则将 A->x 添加到解析表中的 M[A, a]。
  2. 如果 FIRST(A) 包含 FOLLOW(A) 中每个终端 ‘b’ 的空产生式,则将此产生式 (A->null) 添加到解析表中的 M[A, b]。

程序,流程:

  1. 一开始,下推栈保存着文法 G 的起始符号。
  2. 在每一步,一个符号 X 从堆栈中弹出:
    如果 X 是一个终端,那么它与前瞻匹配并且前瞻前进一步,
    如果 X 是非终结符,则使用前瞻和解析表(实现 FIRST 集)选择产生式并将其右侧推入堆栈。
  3. 此过程重复进行,直到堆栈和输入字符串变为空(空)。

表驱动解析算法:

输入:字符串w 和 G 的解析表 M。

tos 栈顶 Stack[tos++] <-$ Stack[tos++] <-Start Symbol token <-next_token() X <-Stack[tos] 如果 X 是终端或 $ then if X = token 然后弹出 X token是 token() 的下一个 else error() else /* X 是非终结符 */ 如果 M[x, token] = X -> y1y2…yk then pop x push Yk, Yk-1, ...., Y1 else error() X Stack[tos] 直到 X = $

// 非递归解析器模型图:

所以根据给定的图非递归解析算法。

输入:输入字符串’w’ 和语法 G 的解析表(’M’)。
输出:如果 w 在 L(G) 中,则 w 的 LMD;否则错误指示。

设置输入指针指向字符串$的第一个符号;重复设X为栈指针指向的符号, a为输入指针所指向的符号;如果 X 是终端或 $ 那么如果 X=a 然后从堆栈中弹出 X 并增加输入指针; else error() end if else /*if X 是非终结符 */ if M[X, a]= x->y1 y2 ...yk然后开始从堆栈中弹出 X;推yk, yk-1, ..., y1进入堆栈,Y1 在顶部;输出生产X->y1y2...yk end else error() end if end if until X=$ /* 栈为空 */

示例:考虑随后的 LL(1) 语法:

S -> A 
S -> ( S * A) 
A  -> id 

现在让我们解析给定的输入:

( id * id ) 

解析表:

  • row-> 对于每个非终结符,
  • column-> 用于每个终端(包括特殊终端)。

此表的每个单元格最多包含给定语法的一条规则:

现在让我们看看使用算法,解析器如何使用这个解析表来处理给定的输入。

程序:

解析器因此结束,因为它的堆栈和输入流上都只剩下“$”。在这种情况下,解析器报告它已接受输入字符串并将以下规则列表写入输出流:

S -> ( S * A), 
S -> A, 
A -> id, 
A -> id 

这确实是输入字符串的 LMD 规则列表,即:

S -> ( S * A ) -> ( A * A ) -> ( id * A ) -> ( id * id )