编译器设计-解析类型

编译器设计-解析类型

Compiler Design - Types of Parsing

语法分析器遵循由上下文无关语法定义的产生式规则。生成规则的实现方式(派生)将解析分为两种类型:自上而下解析和自下而上解析。

自顶向下分析Top-down Parsing             

当解析器开始从开始符号构造解析树,然后尝试将开始符号转换为输入时,称为自顶向下解析。             

递归下降解析:它是自顶向下解析的一种常见形式。它被称为递归,因为它使用递归过程来处理输入。递归下降解析受到回溯的影响。             

回溯:这意味着,如果产品的一个派生失败,语法分析器将使用同一产品的不同规则重新启动进程。这种技术可以多次处理输入字符串以确定正确的生产。             

自下而上分析Bottom-up Parsing             

顾名思义,自底向上的解析从输入符号开始,并尝试构建解析树直至开始符号。

Example:

Input string : a + b * c

Production rules:

S → E

E → E + T

E → E * T

E → T

T → id

Let us start bottom-up parsing

a + b * c

读取输入并检查是否有任何生产与输入匹配:

a + b * c
T + b * c
E + b * c
E + T * c
E * c
E * T
E
S

在上一章中,我们了解到自顶向下解析技术解析输入,并开始从根节点逐渐向下移动到叶节点构建解析树。

递归下降分析Recursive Descent Parsing             

递归下降是一种自顶向下的解析技术,它从顶部构造解析树,从左到右读取输入。它对每个终端和非终端实体使用过程。这种解析技术递归地解析输入以生成解析树,这可能需要也可能不需要回溯。但与之相关联的语法(如果没有保留因子)不能避免回溯。一种不需要任何回溯的递归下降解析称为预测解析。             

这种解析技术被认为是递归的,因为它使用的上下文无关语法本质上是递归的。             

回溯Back-tracking             

自上而下的解析器从根节点(开始符号)开始,并根据生产规则匹配输入字符串以替换它们(如果匹配)。要理解这一点,请以CFG为例:

S  rXd | rZd
X  oa | ea
Z  ai

对于输入字符串:read,自上而下的解析器,其行为如下:             

它将从生产规则中的S开始,并将其收益率与输入的最左边的字母(即“r”)匹配。S(S→rXd)的产生与之相匹配。所以自上而下的解析器前进到下一个输入字母(即“e”)。解析器尝试展开非终端“X”,并从左侧检查其结果(X→oa)。它与下一个输入符号不匹配。所以自上而下的解析器回溯以获得X的下一个产生式规则(X→ea)。             

现在解析器按顺序匹配所有输入字母。接受字符串。

预测分析器 Predictive parser            

Predictive parser是一种递归下降解析器,它能够预测将使用哪个产品来替换输入字符串。预测解析器不受回溯的影响。             

为了完成它的任务,预测解析器使用一个前瞻指针,它指向下一个输入符号。为了使解析器无需回溯,预测解析器对语法施加一些约束,只接受一类称为LL(k)语法的语法。

预测性分析使用堆栈和分析表来分析输入并生成分析树。堆栈和输入都包含一个结束符号$,表示堆栈为空并且输入被消耗。解析器引用解析表来决定输入和堆栈元素的组合。

在递归下降解析中,对于单个输入实例,解析器可能有多个产品可供选择,而在预测解析器中,每个步骤最多有一个产品可供选择。可能存在没有与输入字符串匹配的产品的实例,从而导致分析过程失败。             

LL分析器LL Parser             

LL语法分析器接受LL语法。LL文法是上下文无关文法的一个子集,但有一定的限制,要得到简化的版本,才能实现容易。LL语法可以通过递归下降和表驱动两种算法来实现。             

LL解析器表示为LL(k)。第一个L in LL(k)从左到右解析输入,第二个L in LL(k)表示最左边的派生,k本身表示look ahead的数量。一般k=1,所以LL(k)也可以写成LL(1)。

LL解析算法 LL Parser Algorithm            

对于解析器的解释,我们可以使用确定性的LL(1),因为表的大小随着k的值呈指数增长。其次,如果给定的语法不是LL(1),那么对于任何给定的k,通常都不是LL(k)。              

下面给出了LL(1)解析的算法:

Input:
   string ω
   parsing table M for grammar G
 
Output:
   If ω is in L(G) then left-most derivation of ω,
   error otherwise.
 
Initial State : $S on stack (with S being start symbol)
   ω$ in the input buffer
 
SET ip to point the first symbol of ω$.
 
repeat
   let X be the top stack symbol and a the symbol pointed by ip.
 
   if X∈ Vt or $
      if X = a
         POP X and advance ip.
      else
         error()
      endif
      
   else       /* X is non-terminal */
      if M[X,a] = X  Y1, Y2,... Yk    
         POP X
         PUSH Yk, Yk-1,... Y1 /* Y1 on top */
         Output the production X  Y1, Y2,... Yk
      else
         error()
      endif
   endif
until X =/* empty stack */

如果A→α|β是G的两个不同乘积,则语法G是LL(1):             

对于无终端,α和β都导出以a开头的字符串。             

α和β中至多有一个可以导出空字符串。             

如果β→t,则α不导出以跟随(a)中的终端开始的任何字符串。

posted @ 2020-06-23 18:14  吴建明wujianming  阅读(338)  评论(0编辑  收藏  举报