语法分析
回顾一下语法分析方法:
分为两大类: 自顶向下分析 和 自底向上分析 其中前者又细分为 递归下降分析法(包含回溯的递归下降分析法和不含回溯的递归下降分析法)和非递归的预测分析法(LL分析法) 后者分为算符优先分析法和LR分析法。
(一)包含回溯的递归下降分析法:
思想:
从语法的开始符号出发,试探使用不同产生式,寻找匹配于输入符号串的推导。或者说,从对应文法开始符号的根结点出发,自顶向下为输入符号串建立一棵分析树。这种分析方法实质上是一种试探过程,是因为文法中,对于某个非终结符号的规则其右部有多个选择,并根据所面临的输入符号不能准确 的确定所要选择时,就可能出现回溯。
例如:
(二)LL(1)分析法:
LL(1)分析法是一种自上而下的分析法,使用显示栈而不是递归调用来实现分析。第一个L指的是语法分析按从左到右的顺序扫描输入字符串。第二个L指在语法分析过程中产生句子的最左推导。“1”表示在分析过程中,每一步推导,最多只要向右扫描一个输入字符。
LL(1)分析器的逻辑结构(由总控程序,LL(1)分析表和分析栈三部分组成):
其中分析表是一个二维矩阵(形如 M【A,a】,A是非终结符号,a是终结符号)
分析栈用于存放分析过程中的文法符号。分析栈初始化时在栈底压入一个“#”,然后在次栈底底放入文法的开始符号。
总控程序的作用是依据分析表和分析栈联合控制输入字符串的识别和分析。
举个例子来看下详细的过程:已知
首先我们要构造文法分析表(此处默认已构造好,具体的构造过程在后面记录)
文法分析表如下:
第一步:进行初始化:把#入栈,然后把文法开始符号E入栈,读入输入字符串第一个符号id
第二步:查表E,id 得到 E—>TE ' 然后将E弹出栈,然后将TE’反向压入栈中 即此时栈中元素从底到顶是 # E' T
第三步:查表T,id 得到 T—>FT' 然后将T弹出栈,然后将FT'反向压入栈中
第四步:查表F,id 得到 F—>id 然后将F弹出栈,然后将id反向压入栈中
第五步:栈顶是终结符号,无需查表,直接比较它和读入的符号,得id == id 将栈顶元素id出栈,然后读入下一个符号+
第六步:查表T',+ 得到 T'—>e ,将T'弹出栈
第七步:查表E',+ 得到 E'—>+TE' 然后将E'弹出栈,将+TE'反向压入栈中
第八步:栈顶元素+ 和读入的符号相同,+出栈,读入下一个符号 id
第九步:查表T,id 得到 T—>FT' 然后将T出栈,然后将FT'反向压入栈中
第十步:查表F,id 得到 F—>id 然后F出栈 然后id入栈
第十一步:id == id ,id出栈,读入下一个符号*
第十二步:查表T',* 得到T’ —>*FT' 然后T‘出栈 将*FT’反向压入栈中
第十三步:* == * ,* 出栈 然后读入下一个符号id
第十四步:查表F,id 得到F—>id F出栈,id入栈
第十五步:id == id id出栈,读入下一个符号#
第十六步:查表T',# 得到T'—>e T'出栈
第十七步:查表E',# 得到E'—>e E'出栈
第十八步:# == # 表示分析成功 停止分析过程
LL(1)分析表的构造:
从上面看出整个过程就是一个查表判断不断循环的过程,关键在于LL(1)表的构造。
给出算法:LL(1)分析表的构造
输入:文法G;文法G的FIRST和FOLLOW集
输出:文法G的LL(1)分析表
for 文法G的每个产生式A—>y1|y2|y3|...|ym|
{
if a属于FIRST(yi) 置M[A,a]为"A->yi";
if 空集属于FIRST(yi)
for 任何a属于FOLLOW(A)
{
置M[A,a]为"A->yi"
}
}
置所有无定义的M[A,a]为出错
关于FIRST集的构造:
关于FOLLOW集得构造:
例如:
文法: E —>TE’
E’ —>+TE’ | e
T —>F T’
T’ —>*FT’ | e
F —>(E) | id
计算 Follow(E), Follow(E’) , Follow(T) ,Follow(T’) , Follow(F)
解析:
先看FOLLOW(E) 因为E是文法的开始符号,所以#加入FOLLOW(E)中。)位于E之后,所以)加入FOLLOW(E)
所以FOLLOW(E)= { #, ) }
FOLLOW(E'),因为E —>TE’ 所以FOLLOW(E)加入 FOLLOW(E‘),所以FOLLOW(E’)= { #,)}
FOLLOW(T) 由第一条规则 FIRST(E')加入其中(即 + ) 由第二条规则 FOLLOW(E')加入其中 FOLLOW(T)= { + ,#,) }
FOLLOW(T’)由三条规则,FOLLOW(T )加入其中,FOLLOW(T‘)= { +,#,)}
FOLLOW(F)有第三四条规则,FOLLOW(T)加入其中,FIRST(T')加入其中,FOLLOW(F) = { +,#,),* }
有了FIRST和FOLLOW集,我们就很容易构造分析表了。
这里要注意,再进行计算前必须先消除左递归,不然在构造分析表时表中某些项会出现多个情况,这就不属于LL(1)文法了。
所以要证明一个文法是LL(1)文法,只需给出其文法分析表即可。