一.自下而上语法分析基本问题
1.移进归约
1.1基本思想
用一个寄存符号的先进后出栈,把输入符号一个一个地移进到栈里,当栈顶形成某个产生式的候选式时,即把栈顶的这一部分替换成(归约为)该产生式的左部符号。
1.2归约
是指根据文法的产生式规则,把产生式的右部替换成左部符号
2.规范归约
2.1短语
定义:令G是一个文法,S是文法的开始符号,假定αβδ是文法G的一个句型
其中α,β,δ∈(VN∪VT)*,A∈VN ,如果有S*=>αAδ且A+=>β.则β称是句型αβδ相对于非终结符A的短语。
注意:
因为句型是由开始符号推出来的,而短语是由非终结符号推出来的。所以,短语是句型的一部份或全部符号串。
2.2直接短语
特别是,如果有A=>β,则称β是句型αβδ相对于规则A->β的直接短语。
2.3.句柄:一个句型的最左直接短语称为该句型的句柄。
2.4规范归约
定义:假定α是文法G的一个句子,我们称序列
αn, αn-1,......,α0
是α的一个规范归约,如果此序列满足:
(1) αn= α
(2) α0为文法的开始符号,即α0=S
(3) 对任何i,0 < i <=n, αi-1是从αi经把句柄替换成为相应产生式左部符号而得到的
注意:(1)S => aAcBe=> aAcde => aAbcde => abbcde显然这是一个最右推导
规范归约 是关于是一个 最右推导 的逆过程
最左归约 规范推导由规范推导推出的句型称为规范句型。
(2)由于规范句型由最右推导推出的句型,故该句型的句柄右边只含有终结符号
2.5修剪语法树
使用修剪语法树的方法来加深对自下而上语法分析的理解。
(1)子树:是由该树的某个结点(子树的根)连同它的所有子孙组成。
(2)简单子树:只有单层分支的子树(只有父子两代没有第三代)
(3) 对语法树有如下结论
①每个句型都有一棵语法树与之对应
②每棵语法树的叶结点自左至右排列就组成一个句型
③每棵子树的叶结点自左至右排列就组成一个短语
④每棵简单子树的叶结点自左至右排列就组成一个直接短语
⑤每棵最左简单子树的叶结点自左至右排列就组成一个句柄
3.用符号栈进行自下而上的语法分析
3.1‘#’的使用
(1)在分析开始时,将‘#’预先进栈,作为栈底符号
(2)将‘# ’作为输入串的结束符
3.2 分析过程
自左向右对输入串ω不断向栈中进行移进——归约。
二.算符优先分析法
1.算符优先文法及优先表构造
1.1算符优先文法
(1)算符文法
一个文法,如果它的任一产生式的右部都不含两个相继(并列)的非终结符,即不含如下形式的产生式右部:…QR… 则我们称该文法为算符文法,也称OG文法 (Operater Grammar) 。
约定:
a、b代表任意终结符;
P、Q、R代表任意非终结符;
‘…’代表由终结符和非终结符组成的任意序列,包括空字
(2)定义终结符之间的优先关系
假定G是一个不含产生式的算符文法。对于任何一对终结符a、b,我们说:
1. a =. b 当且仅当文法G中含有形如P→…ab…或P→…aQb…的产生式;
2. a <. b 当且仅当G中含有形如P→…aR…的产生式, 而R b…或R Qb…;
3. a>.b 当且仅当G中含有形如P→…Rb…的产生式,而 R …a或R …aQ。
(3)如果一个算符文法G中的任何终结符对(a,b)至多只满足下述三关系之一:a=.b a>.b a<.b 则称G是一个算符优先文法(OPG文法)。
2. 构造算符优先关系表
2.1通过检查产生式的每一个候选式可以找出满足a=.b
(即P→…ab…或P→…aQb…的产生式)
2.2为了满足<.和>.,需对G中每个非终结符P构造两个集合FIRSTVT(P)和LASTVT(P):
2.3构造集合FIRSTVT(P)的算法
按其定义,可用下面两条规则来构造集合FIRSTVT(P):
① 若有产生式P→a…或P→Qa…,
则a∈FIRSTVT(P);
② 若a∈FIRSTVT(Q),且有产生式P→Q…,
则a∈FIRSTVT(P)。
2.4同理构造构造集合LASTVT(P)的算法
按其定义,可用下面两条规则来构造集合LASTVT(P):
① 若有产生式P→… a或P→… aQ ,
则a∈LASTVT(P);
② 若a∈ LASTVT(Q),且有产生式P→… Q ,
则a∈LASTVT(P)。
2.5有了这两个集合之后,就可以通过检查每个产生式的候选式确定满足关系<.和>.的所有终结符对。
(1)假定有个产生式的一个候选形为 …aP… 那么,对任何b∈FIRSTVT(P),有a <. b。
(2)假定有个产生式的一个候选形为 …Pb… 那么,对任何a∈LASTVT(P),有a >. b。
3、算符优先分析算法的设计
3.1.问题的提出
自下而上分析
移进-归约法:句柄为可归纳串
算符优先分析法:最左素短语为可归纳串
3.2.素短语
指一个句型的短语,它至少包括有一个终结符号且除去它本身之外不再含任何更小的素短语
3.3.最左素短语
处在句型最左端那个素短语成为最左素短语
3.4.算符优先分析算法和设计
(1)句型的一般表示形式: #N1a1N2a2…NnanNn+1#
其中,每个ai都是终结符,Ni是可有可无的非终结符
(2)定理:
一个算符优先文法G的任何句型的最左素短语是满足如下条件的最左子串 Njaj…NiaiNi+1,
aj-1 <. aj
aj =. aj+1,aj+1 =. aj+2,…,ai-1 =. ai
ai >. ai+1
注意:出现在左端或右端的非终结符一定属于这个素短语
4.优先函数
4.1.优先函数的定义
把每个终结符与两个自然数f(θ)与g(θ)相对应,使得
若θ1 <. θ2,则f(θ1) < g(θ2)
若θ1 =. θ2,则f(θ1) = g(θ2)
若θ1 >. θ2,则f(θ1) > g(θ2)
f称为入栈优先函数,g称为比较优先函数。
(1)优点:便于比较,节省空间;
(2)缺点:原来不存在优先关系的两个终结符,由于自然数相对应,变成可以比较的。要进行一些特殊的判断。
4.2.优先函数的构造方法
如果优先函数存在,则可以通过以下三个步骤从优先表构造优先函数:
(1)对于每个终结符a,令其对应两个符号fa和ga,画一张以所有符号fa和ga为结点的方向图。如果a>.b,则从fa画一条弧至gb如果a<.b,则从gb画一条弧至fa 。
(2)对每个结点都赋予一个数,此数等于从该结点出发所能到达的结点(包括出发点自身)。赋给fa的数作为f(a)赋给ga的数作为g(a)。
(3)检查所构造出来的函数f和g是否与原来的关系矛盾。若没有矛盾,则f和g就是要求的优先函数,若有矛盾,则不存在优先函数。
4.3.构造方法证明
现在必须证明:
若a=.b,则f(a)=g(b);若a<.b,则f(a)< g(b);若a>.b,则f(a)> g(b)。
第一个关系可从函数的构造直接获得。因为,若a=.b,则既有从fa到gb的弧,又有从gb到fa的弧。所以,fa和gb所能到达的结是全同的。
至于a<.b和a>.b的情形,只须证明其一。
如果a>.b,则有从fa到gb的弧。也就是gb能到达的任何结fa也能到达。因此,f(a) g(b)。所需证明的是,在这种情况下,f(a)=g(b)不应成立。
三.LR分析法
1.LR分析方法
LR分析方法是一种自下而上的分析方法
LR分析法的归约过程是规范推导的逆过程,所以LR分析过程是一种规范归约过程LR分析方法是一种适用于一大类上下文无关文法的分析方法
比较复杂,不适于用手工实现,可借助于YACC/bison实现
根据归约过程中向前看输入符号串中字符的个数,定义不同的LR(k)分析方法,通常,k=0,1
2.LR分析方法和LL分析方法的比较
3.LR分析方法--分析器结构
4.LR分析器栈的结构_动作表和状态转换表
动作表:ACTION[s,a]:当状态s面临输入符号a时,应采取什么动作
状态转换表:GOTO[s,X]:状态s面对文法符号X时,下一状态是什么
(1)ACTION[s,a]:当状态s面临输入符号a时,应采取什么动作
每一项ACTION[s,a]所规定的四种动作:
<1>. 移进:把(s,a)的下一状态s’=GOTO[s,a] 和输入符号a推进栈,下一输入符号变成现行输入符号.
<2>. 归约 : 指用某产生式A->β进行归约. 假若β的长度为r, 归约动作是A, 去除栈顶r个项,使状态sm-r变成栈顶状态,然后把(sm-r, A)的下一状态s’=GOTO[sm-r, A]和文法符号A推进栈.
<3>. 接受 : 宣布分析成功,停止分析器工作
<4>. 报错 : 发现源程序含有错误,调用出错处理程序
si:移进,并将状态i进栈。
ri:用第i个产生式归约,同时状态栈与符号栈退出相应个符号,根据GOTO表将相应状态入栈。
5.LR分析过程
第一步 分析开始时,首先将初始状态SO及句子左界符#推入分析栈中。
第二步 设在分析的某一步,分析栈及余留的输入符号串处于如下的格局。
则以栈顶的状态及正扫视的输入符号ai组成符号对(Sm,ai)去查分析动作表,并根据表元ACTION[Sm,ai]的指示完成相应的分析动作。每一分析表元所规定的动作,仅能是下列四种动作之一:
(1)若ACTION[Sm,ai]=“移进”,这表明句柄尚未在栈顶部形成,此时正期待继续移进输入符号以形成句柄,故将当前的输入符号推入栈中:
然后,以符号对(Sm,ai)查状态转移表,设相应的表元GOTO [Sm,ai]= Sm+1,再将此新的状态(即要转移到的下一状态)推入栈中,则有如下的格局:
(2)若ACTION[Sm,ai]= rj ,其中rj意指按文法的第j个产生式A→Xm-r+1 Xm-r+2…Xm进行归约。
将分析栈从顶向下的r个符号(因为该产生式右部符号串的长度为r)退出,然后再将文法符号A推入栈中,此时分析栈的格局为:
然后,以(Sm-r ,A)查状态转移表,设GOTO [Sm-r,A]=Sl,将此新状态推入栈中,则有如下的格局:
须注意的是,当完成归约动作之后,输入串指示器不向前推进,它仍然指向动作前的位置。
(3)若ACTION[Sm,ai]=“接受”,则表明当前的输入串已被成功地分析完毕,应中止分析器的工作。
(4)若ACTION[Sm,ai]=ERROR,则表明当前的输入串中有语法错误,也应终止分析器的工作。
第三步 重复上述第二步的工作,直到在分析的某一步,栈顶出现“接受状态”或“出错状态”为止。对于前者,分析栈的最终格局应为:
其中,Z为文法的开始符号,Sα则为使ACTION[Sα,#]=“接受”的唯一状态(即接受状态)。 对任何不同的LR(1)分析表都适用。
5.LR(0)项目集族和分析表的构造
活前缀:
文法G的活前缀是他的规范句型的前缀,该前缀不超过句柄的右端。
活前缀特点:
该前缀加上被分析串中未被分析的终结符,就可以构成一个规范句型
活前缀与句柄间的关系:
(1)活前缀中已含有句柄的全部符号(句柄的符号即为其最右符号)。
(2)活前缀中含句柄的一部分符号(句柄开头的 若干符号与活前缀最右的若干个符号一致)。
(3)活前缀中全然不包含句柄的任何符号 。
LR(0)项目:在每个产生式的右部适当位置添加一个圆点构成项目。
构成识别一个文法活前缀的DFA项目集(状态)的全体称为这个文法的LR(0)项目集规范族。
I的闭包CLOSURE(I):
(1) I的任何项目都属于CLOSURE(I);
(2) 若A→α·Bβ属于CLOSURE(I),那么,对任何关于B的产生式B→γ的项目B→·γ也属于CLOSURE(I);
(3) 重复执行上述两步骤直至CLOSURE(I) 不再增大为止
例如:设I={S'→·E}
则CLOSURE(I)={S'→·E ,E→·aA, E→·bB}
定义转换函数如下:
GOTO(I,X)=CLOSURE(J)其中:
I为包含某一项目集的状态,
X为一文法符号,
J={任何形如A→αX•β的项目|A→αX•β属于I}。
LR(0)分析表的ACTION和GOTO表的构造步骤
a)若项目A→α•aβ属于Ik,且转换函数GO(Ik,a)=Ij,当a为终结符时 ,则置ACTION[k,a]为Sj。
b)若项目A→α•属于Ik, 则对a为任何终结符或#′,置ACTION[k,a]=rj, j为产生式在文法G′中的编号。LR(0)项目集规范族不存在移进-归约,或归约-归约冲突,称为LR(0)文法。
c)若GO(Ik,A)=Ij,则置GOTO[k,A]=j,其中A为非终结符,j为某一状态号。
d)若项目S′→S•属于Ik,则置ACTION[k,#]= acc。
e)其它填上“报错标志”。
四.知识应用:
五.总结
所谓自下而上分析法就是从输入串开始,逐步进行归约,直到归约到文法的开始符号;或者说从语法树的末端开始,步步向上归约,直到根结。但是感觉这张明显理解起来很吃力,而且知识点好多不懂,像LR的分析过程。。。。。。只能课下在多再看看。