算符优先分析法

1、主要思想:

对文法按一定规则,求Vt(终结符)之间的关系,再按照这种关系来确定句柄。(通俗来讲就是不要管非终结符)

2、步骤:

  • 拓广文法:S'-->#S#
  • 构造算符优先关系表
  • 判断是否为算符优先文法(OPG文法)
  • 根据优先关系表分析句子

3、优先函数:

为了节约存储空间,用“优先函数”代替“优先关系表”

4、算符文法的定义:

算符文法上下文无关文法G中没有形如A-->...BC...的产生式,则称OG文法。(就是说产生式右部不存在相邻的两个非终结符

性质1:任何句型都不包含两个相邻的非终结符

性质2:如Ab/bA(终结符和非终结符相邻)出现在算符文法的句型eq?%5Calpha中,则eq?%5Calpha任何包含b的短语比包含有A。(但含A的未必含b)

5、算符优先关系的定义:

(1)a=b: 含有形如A-->...ab...a-->...aBb的产生式

(2)a<b: 含有形如A-->...aB...的产生式,B至少一次推导出b...或Cb...

(3)a>b: 含有形如A-->...Bb...的产生式,B至少一次推导出...a或...aC(以终结符结尾或终结符带非终结符结尾)

5473198139474edf91b2c4f98baff6c2.png

6、算符优先关系表的构造

定义法  构造算符优先关系表:

(1)定义:FirstVTLastVT

        FirstVT(B) = {b|B有限次推导出以b...终结符b开/以Cb...开头}

        LastVT(B) = {a|B有限次推导出...a以(以终结符a结尾)...aC(或带一个非终结符)}

(2)求优先关系

        a=b                A-->...ab.../A--->...aBb...

        a<FirstVT(B)        A-->...aB...

        LastVT(B)>c        A-->...Bc...

(3)构造优先关系表

        步骤

  1. 计算每个Vn的FirstVt集和LastVt集
  2. 求优先关系:
  • 求=关系
  • 求<关系:找...aB...  a<FirstVT(B)
  • 求>关系:找...Bc...  LastVT(B)>c

     3.构造优先关系表


例1: 

 有文法G[E]:

E-->E+T

E-->T

T-->T*F

T-->F

F-->P^F

F-->P

P-->(E)

P-->i


步骤一:拓广文法:

S'-->#E#

E-->E+T

E-->T

T-->T*F

T-->F

F-->P^F

F-->P

P-->(E)

P-->i


步骤二:求FirstVT和LastVT:(从叶子节点找比较方便

FirstVTLastVT
E'#
E(  i  ^  *  +)  i  ^  *  +
T(  i  ^  *)  i  ^  *
F(  i  ^)  i  ^
P(  i)  i

步骤三: 求优先关系:

=关系:#=#、(=)

<关系:找...aB...  a<FirstVT(B):

        #E:#<(   #<i  #<^  #<*  #<+

        +T:+<(  +<i  +<^  +<*

        *F:*<(  *<i  *<^

        ^F:^<(  ^<i  ^<^

        (E:(<(  (<i  (<^  (<*  (<+

>关系:找...Bc...  LastVT(B)>c:

        E#:)>#  i>#  ^>#  *>#  +>#

        E+:)>+  i>+  ^>+  *>+  +>+

        T*: )>*   i>*  ^>*  +>*

        P^: )>^  i>^

        E): )>)  i>)  ^>)  *>)  +>)


构造算符优先关系表:

+*^()i#
+><<<><>
*>><<><>
^>><<><>
(<<<<=<
)>>>>>
i>>>>>
#<<<<<=

7、算符优先文法的定义

1. 设有一个不含eq?%5Cvarepsilon产生式的算符文法G,如果对于任意两个终结符a和b之间至多只有=,<,>三种关系的一种成立,则称G是一个算符优先文法(OPG)

特点:

  • 不含产生式
  • 任何产生式右部不包含两个相邻的非终结符
  • 任何两个终结符之间优先关系唯一

2. 算符优先文法是无二义性的。


例2:

有文法:

E'-->#E#

E-->E+T|T

T-->T*F|F

F-->F^P|P

P-->(E)|i

+*^()i#
+><<<><>
*>><<><>
^>><<><>
(<<<<=<
)>>>>>
i>>>>>
#<<<<<=

分析句子  #i+i#

 步骤优先关系当前符号待输入串动作
1#<i+i#移进
2#i>+i#归约i<--P
3#S(终结符忽略用S代替,下同)<+i#移进
4#S+<i#移进
5#S+i>#归约i<--P
6#S+S>#归约S+S<--E
7#S=#接受

归约时:往前比较关系,直到遇到小于,小于右边为句柄头,开始为句柄尾


8、算符优先分析

规约过程中,只考虑终结符之间的优先关系来确定句柄,而与非终结符无关。这样去掉了单个非终结符的归约,不是规范归约。

9、最左素短语

  1. 素短语:设有文法G[S],其句型的素短语是一个短语,它至少包含一个终结符,且除自身外不在包含其他素短语。
  2. 最左素短语:句型最左边的素短语。例子:

30b2c507944f45158cc41390441208b4.png

素短语:T*F    i

最左素短语:T*F   (树中靠最左边)

10、算符优先分析的局限性

简单优先分析:是规范归约,关键是寻找句柄

算符优先分析:不是规范归约,关键是寻找最左素短语。(会出现“错误的句子得到正确的归约”,一般语言的文法难满足算符优先分析的条件)

所以,算符优先文法分析只适用于表达式的语法分析

11、优先函数

  • 优点:优先函数比优先矩阵节省空间
  • 缺点:当发生错误的时候不能准确指出错误位置
  • 优先函数的构造方法:

                1、由定义直接构造

               2、用关系图构造优先函数


例子:

优先关系表
+*i
+><<
*>><
i>>

 优先关系图:横为g,列为f(由大指向小,=则双向箭头)

优先关系表:可经过的节点数(自身算一个节点)

835df70e2b414ffc8935e5e9255a82ef.png5b8881b8dd444e3d819e42190d2c7d7d.png

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
算符优先分析法 C++ 编译原理 运行环境:Visual Studio 2005 #include "SStack.h" #include <iostream> #include <string> using namespace std; class Functor { private : char ** table; string ** production; string prog;//待分析字符串 int p;//字符指针 int num;//终结符个数 int num1;//产生式个数 SStack <char> stack; public: Functor(int m,int n,char ** T,string **prod,string pr) { num=m; num1=n; table=T; production=prod; prog=pr; p=0; stack.push('$'); } void traversal() { while(p<(prog.length())) { stack.display(); cout<<prog.substr(p)<<" "; char ch; if(Getnum(stack.gettop())) { ch=stack.gettop(); } else { ch=stack.getsecond(); } switch(compare(ch,prog[p])) { case 1: case 2:stack.push(prog[p]);p++;cout<<"移入"<<endl;break; case 3:reduct();cout<<"归约"<<endl;break; } } cout<<"分析成功!"<<endl; } int Getnum(char ch) { for(int i=1;i<num;i++) { if(ch==table[i][0]) { return i; } } return 0; } int compare(char col,char row) { int c=Getnum(col); int r=Getnum(row); switch( table[c][r]) { case '>': return 3;break; case '<': return 2;break; case '=': return 1;break; default:cout<<endl<<"输入串有误,程序将终止!"<<endl;system("pause");exit(0);break; } } void reduct() { //待定 string token=""; int temp; string str=""; if(!Getnum(stack.gettop())) { token+=stack.gettop(); stack.pop(); } char ch=stack.gettop(); str+=ch; temp=Haven(str); if(temp!=-1) { token+=production[temp][0]; } else { token+=ch; } stack.pop(); bool Nover=true; while(Nover) { if(Getnum(stack.gettop())) { if(compare(stack.gettop(),ch)==2) { Nover=false; } else { ch=stack.gettop(); str=""; str+=ch; temp=Haven(str); if(temp!=-1) { token+=production[temp][0]; } else { token+=ch; } stack.pop(); } } else { token+=stack.gettop(); stack.pop(); } } string token2=""; //cout<<token<<" "; for(int i=token.length()-1;i>=0;i--) { token2+=token[i]; } //cout<<token2<<endl; if(Haven(token2)!= -1) { stack.push(production[Haven(token2)][0][0]); } else { cout<<"输入串有误!分析终止!"<<endl; system("pause"); exit(0); } } int Haven(string temp) { for(int i=0;i<num1;i++) { int j=1; while(production[i][j]!="") { if(temp==production[i][j]) { return i; } j++; } } return -1; } public: ~Functor(void) { } };
算符优先分析文法是一种工具,在编译的过程中,隶属于语法分析环节,却又与中间代码的生成息息相关,编译可以分为五个阶段:词法分析、语法分析、语义分析(中间代码的生成)、代码优化、目标代码生成。语法分析是指:在词法分析基础上,将单词符号串转化为语法单位(语法范畴)(短语、子句、句子、程序段、程序),并确定整个输入串是否构成语法上正确的程序。也就是说语法分析是检验输入串的语法是否正确,注意这里的语法正确,只是简单地符合自己定义的规范,而不能检测出运行时错误,比如"X/0",空指针错误,对象未初始化等错误。在这一个实验中,我将通过算符优先分析文法这一个工具,在语法分析的时候,顺便进行语义分析,也就是识别出语法单位,同时简要的将识别出的中间代码进行计算(目标代码的生成+运行),得到相应的结果,来检验自己设计的正确性。可以说题目虽然叫做算符优先分析文法,其实却是一个贯穿了“词法分析+语法分析+语义分析+中间代码优化+目标代码生成+运行”全过程的一个极具概括性的程序。如果能将这个程序得心应手的完成出来,我相信诸位对编译原理的掌握也算是炉火纯青了。时隔将近两年再来整理自己以前写过的实验报告,还是挺有感慨的,对一件东西感兴趣,原来影响还会如此深远,还记得自己当时连续六个小时全神贯注写出的实验报告,现在看看竟然写了五六十页,核心内容也有三四十页,不觉的感慨当年充满热情的时代慢慢的竟走出许久
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小李学不完

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值