编译器设计-解析类型
编译器设计-解析类型
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)中的终端开始的任何字符串。