经过词法分析的程序,我们能保证词法分析器识别了下面几种单词符号:
关键字:if、else、int、double、…
标识符:函数名、变量名、数组名
界符:各种括号
运算符:+、-、*、/、…
常数:整形、布尔型…
接下来进行的语法分析我们需要保证它的语法是正确的,比如下面的语句在词法分析时是正确的:
int double 2;
词法分析程序会将语句判断为:
<值,类型>
<int,key>
<double,key>
<2,number>
<;,->
词法分析是没有错误的,但是明显它是一个有语法错误的语句。接下来要说的语法分析叫做自上向下分析的方法。它的目的就是将我们的一个输入语句看能否从开始符号按照语法规则推导出来,如果可以,那它就是一个合法的语句。
自上而下分析是对于任何的输入串,从开始符号建立一棵语法树,一旦能建立一棵唯一的语法树,那对于输入的语句,只要能通过语法树推导出来,那么就是合法的,建立语法树的过程是一个不断尝试的过程,因为在匹配的过程中,由于一个非终结符可能对应不同路径,比如T->**|*
,那么如果第一次选择用T->**
将A
替换,一旦不能满足条件,我们需要回溯,再去走T->*
,这样的回溯可能在别的非终结符号中进行的更多,为了防止这种现象,我们希望通过某种途径直接建立唯一的语法树,让语句在判断过程中走它规定好的路线,即不会产生任何回溯,路线唯一
,我们需要在构建语法树之前完成这两个步骤:
一:消除左递归
设想如果存在下面的式子:
P=>Pa (式子1)
那这个分析过程遇到P会一直递归深入,永远不会结束。我们的目的是:没有蛀牙(别闹,没有左递归),那怎么修改呢?举个栗子:
P->Pa|b(式子2)
则:
(式子3)
p->bp`
p`->ap`| e
备注:e表示空
为什么可以这么转换呢?因为上面的式子2中通过P可以最终得到的式子为baaaaa...
,通过下面的式子3可以得到的最终式子也是baaaaa...
,所以,显而易见。我们可以用他们来替换,替换之后就消除左递归了。
二:消除回溯
消除回溯必须达到:对文法的任何非终结符号,让它去匹配输入串的时候,能够根据它面临的输入符号准确的让一个候选产生式去工作。
这时候就需要引入First集和Follow集的概念:
First集:对于一个文法中所有的非终结符号,它能推出的所有直接终结符号。
eg:F->(E)|i
First(F) 为:{ ( , i }
Follow集:
Follow集的计算参见这篇博客:
http://blog.csdn.net/yangbodong22011/article/details/52950436
通过以上两个步骤我们我们可以确定一个LL(1)文法,即消除了左递归和回溯的文法,之后我们可以根据没有左递归的文法和First集合构建预测分析表。然后就可以分析语法了。栗子以后在补吧…
2016-11-30 补充栗子
http://blog.csdn.net/yangbodong22011/article/details/53415401