算符优先文法实验_第1页
算符优先文法实验_第2页
算符优先文法实验_第3页
算符优先文法实验_第4页
算符优先文法实验_第5页
已阅读5页,还剩101页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、 编译原理实验二 姓 名:朱彦荣学 号:20132184 专 业:软件工程2 实验题目:算符优先分析文法 完成语言:C/C+ 上级系统:VC+6.0 日 期:2015/11/24 算符优先分析文法设计一 任务:实验目的:1.了解掌握算符优先分析的基本方法、内容;2.学会科学思考并解决问题,提高程序设计能力。实验内容与要求: 用算符优先分析方法设计一个分析解释程序,对输入的赋值语句、输出语句、清除语句进行词法分析、语法分析、表达式求值并存储于指定变量中;若存在错误,提示错误相关信息。文法表示:Sv=E|E?|clearEE+T|E-T|TTT*F|T/F|FF (E)|v|c 单词种别码设计:

2、= 1 ? 2 + 3 - 4 * 5 / 6 ( 7 ) 8 v 9 c 10 clear 11 # 12 N 13可归约串语义解释: 变量归约;常量归约;运算归约;括号归约; 赋值语句;输出语句;清除语句。演示示例: a=5 b=a+10 b? b+a*a? a=a+b 二 分析: 首先,这是一个很好的题目,从知识的理解、将形式化的东西转化成具体的过程、编程能力、编程技巧、调试改错能力等多个方面考察了我们的学习情况。 算符优先文法是一种自下而上的文法分析方法,这种方法的用处十分广泛,虽然有的文法不能用算符优先分析文法,如类似PQ.(P,Q为非终结符)这样形式的产生式,但是对于大部分文法这种

3、分析方法还是十分有用的。 其次,对于本程序中的文法,实质上是算数表达式的计算。用这种文法就是再好不过了,作为从算符文法抽象出来的算符优先文法当然继承了算符文法的特性。下面就切入正题了,我将详细介绍一下我对于这个文法的思考出发点和分层分析的方法。 模块一:构建firstVT()和lastVT()这两个集合。基于“优先”这两个字,有效的回避了左递归(自上而下文法分析)和二义性的问题。关键是如何体现“优先”这两个字。这就需要firstVT()和lastVT()集合了。firstVT(E)=a|Eàa.|EàQa.|firstVT(Q),从这个定义可以看到,firstVT()主要找

4、到是本产生式中的第一个非终结符和若第一个是非终结符则包含该非终结符的firstVT()集,因为firstVT有可能要求Q的firstVT()集,因此有可能要用递归才能求尽所有的firstVT()集。同理,lastVT(E)=a|Eà.a|Eà.aQ,可见这两个关系好像反对称的影像。说了这么多,还是没有说到这两个集合要干什么用。让我们想象一个句型aQ.在这个句型中我们知道只有等Q的短语规约为Q了,才有可能将aQ.再次向上规约,因此a的优先级要小于Q产生式的firstVT(Q)集,因为我们可以断定a必定是比Q中第一个出现的终结符优先级低的,也就是说优先级a<优先级firs

5、tVT(Q),至于第二个,第三个终结符。我们不敢判定。于是才要费尽心思地构造firstVT()这样的一个集合。同理,对于lastVT(),让我们想一下这种情况.Qa.,对于这个句型我们知道只有当Q的短语归约成了Q,我们才敢将.Qa向上归约。这样的话就是说Q的产生式中最后出现的一个终结符的优先级必定是比a的优先级高的,也就是优先级lastVT(Q)>优先级a,同样的对于倒数第二个,倒数第三个终结符。我们不敢判定。说了这么多我想应该能够理解这两个集合存在的必要性和决定性了。因为是程序,我就说一下程序如何实现这两个集合的求解。 首先是一些数据结构和意义: char FIRSTVT2020; 存

6、储firstVT()集,第二维代表第几个产生式,第一维代表集合中的第几个元素 char LASTVT2020; 存储lastVT()集,第二维代表第几个产生式,第一维代表集合中的第几个元素 char INPUT2020; 按照一定的形式存储文法中的所有产生式。然后是几个函数:1. void setFIRSTVT(char X,int T);这个函数的目的是将求出的终结符X,存放到第T条产生式的左部对应的firstVT集合中。2. void getFIRSTVT(char X,int S)S标记产生式的位置,X为将要计算的产生式的左部。这个函数就比较复杂了,它将完成求出一个产生式左部的first

7、VT的终结符的重要任务,可以说是主控程序了。它的算法是逐个遍历产生式,对每个产生式求出该产生式的直接a,并且若有EàQa还要递归的求出Q的firstVT()将其并入firstVT(E)的集合中。3. 同理void setLASTVT(char X,int T)4. void getLASTVT(char X,int S)和上面类似。5. void DisplayFirstVT_LasVT() 这个函数也是主程序开始时要进入的位置。它主要提示用户输入文法(产生式组),然后调用上面的函数计算并显示两种集合。下面是void getFIRSTVT(char X,int S)的函数。/找出FI

8、RSTVT集元素void getFIRSTVT(char X,int S) int i,j=0,k;/j当前数组指针 int T=0;/X position int L=0;/X offspring length char C20; for(i=0;i<20;i+) if(INPUTi0=X)/找到将要处理的产生式 T=i; /标记产生式的位置 break; /按照规则从产生式的右部第一个字符开始处理,直至遇上'/n'/每一次都判断指针j指向的字符若满足p->w中w的规定则放进C/若遇上|或'n'则求这段右部对应的firstVT() for(i=4;

9、i<20;i+) if(INPUTTi='|'|INPUTTi='n')/刚开始走不到这里 L=j;/j指针所指位置为C中字符串的长度 j=0;/交给L后就清零,以供下一次使用 for(k=0;k<L;k+) /要是数组C中的终结符,如小写字母'a''z',加减乘除,乘方,#/则归入fisrstVT集中 /若是Aab.则a成为F()一部分,b被忽略,A也不用求first集?需要求!除非A=X /若是QRa.,则不是算符优先文法,故不可能 /若是a.则只是填进a if(Ck>=97&&Ck<=

10、122)|Ck='+'|Ck='*'|Ck='-'|Ck='/'|Ck='!'|Ck='('|Ck=')'|Ck='#'|Ck='?'|Ck='=') /只能用一次,因是算符优先文法,故前两个中必会至少存在一个终结符 setFIRSTVT(Ck,S);/存入FIRSTVT中,S标记产生式的位置 break;/跳出循环保证存入的是最左边的终结符 if(C0>=65&&C0<=90&&C0!=X)

11、 /若C0中为AZ,并且C0不是X(否则将无限循环),则递归的进行填充 int flag=0,count; for(count=0;count<20;count+) if(INPUTcount0=C0)/找到将要处理的产生式 flag=1;/若存在,则填充 if(flag=1)/递归,所用极妙,画龙点睛 getFIRSTVT(C0,S);/S为子集中的元素填入父集中指明了方向 else if(INPUTTi!='|'&&INPUTTi!='0')/该行没结束,过滤'0' Cj=INPUTTi;/j从0开始 j+;/移进 if

12、(INPUTTi='n')/该行结束break; 比如说对于这个文法分析出的集合如下: 模块二:构建优先符号表。为了体现“优先”的关系,只是构建出了上面的两种集合是不够的,由上面分析我们知道了这两个集合的用处。说白了就是为了构造出算符优先分析表。因为关系无非四类1.等于,2.大于,3.小于,4没有关系。注意这里的“没有关系”也是一种关系。而由第一个阶段产生的两个集合就可以找到所有的大于和小于关系,那就只剩下了等于关系,如果等于关系找到了,剩余的没有填写的关系就是没有关系。等于关系是这样的:如果存在这样的句型.ab.或.aQb.则关系(a=b)。这样的结果也是显而易见的,因为a和

13、b注定要共同归约,没有谁先谁后,因此是等于关系。好了现在所有关系都搞请了,就可以建表了。还是首先解释一下新定义的一个数据结构:char PriorityTable2020;优先关系表,其中存放着终结符以及终结符对应的关系。然后是一些函数:1. int IsVT(char ch) 判断ch是否为终结符,若是则返回1,否则返回0 2.int SearchTbl(char ch) 搜索终结符ch在符号表中的行列数,用来定位将要填写的位置。 3.int FL_map(char ch) 这个映射既是查找产生式左部的位置,若存在则返回该产生式的条数,即是第几个产生式,失败则返回-1这个出错标记。 4.vo

14、idcreatePriorityTable() 这个是建表的主控程序,用来填写所有关系与表中。遍历所有的产生式,填写所有的关系。这里主要解释一下程序是如何找到横纵坐标并且将关系填写进去的。对于简单的情况只要拿一个终结符来使用SearchTbl(终结符)就可以找到横(纵)坐标了,但是因为对于大小关系我们往往要填的是“终结符<firstVT()”或“lastVT()>终结符”这样的情况,因此势必要从集合中取出终结符,并用该终结符来映射坐标,即是用到了类似这样的转换:temp_column=FIRSTVTFL_map(C2)count_1; tbl_column=SearchTbl(te

15、mp_column);/将上述结果再次转换或者temp_row=LASTVTFL_map(C1)reg;tbl_row=SearchTbl(temp_row);/map这样的映射。知道了这些程序不难读懂。5. void DisplayPriorityTable()这个函数就是显示优先关系表的内容的。下面是 voidcreatePriorityTable() 函数的实现过程:voidcreatePriorityTable()/创建并填写优先级表/对每个产生式遍历,求出四种关系1.=,2.<,3.>,4.没有关系 char temp13='+','-',

16、'*','/','(',')','v','c','=','?','#','0' int j,L,i; int tbl_row,tbl_column;/表的元素坐标 char C20; for(int r=1;r<12;r+) PriorityTable0r=tempr-1;/初始化行头,第0行PriorityTabler0=tempr-1;/初始化第0列 /扫描产生式的右部,如果发现终结符且该终结符周围有其他字符 /若该其他字符为

17、终结符,则这两者关系为相等 /若该其他字符为非终结符,则根据非终结符的firstVT,LastVt填表 for(int p=0;p<4;p+) j=0; for(i=4;i<20;i+) /注意,此处因为时间有限考虑不是很全面,只是对老师给定的文法进行了周密的部署 /在别的文法上可能需要少许加工,不是问题 if(INPUTpi='|'|INPUTpi='n') /刚开始走不到这里 L=j;/j指针所指位置为C中字符串的长度 j=0;/交给L后就清零,以供下一次使用 if(L>1)/大于一则处理,否则不关心 /对于清零指令l自动忽略 if(IsV

18、T(C0)&&IsVT(C1)|(L=3)&&IsVT(C0)&&IsVT(C2)&&(FL_map(C1)!=-1) /若为终结符因至少有两个,若出现两个终结符则C0'='C1|C2,注意这是此文法的情况 /则需要填表,查表找到C0的行数,C1,C2的列数进行填表 tbl_row=SearchTbl(C0);/记录行数 if(IsVT(C1) /列数,若是终结符 v= tbl_column=SearchTbl(C1); if(IsVT(C2)&&(L=3) /列数 (E) tbl_column=S

19、earchTbl(C2); PriorityTabletbl_rowtbl_column='='/填表 if(L=3)&&IsVT(C0)&&IsVT(C1)&&(FL_map(C2)!=-1) /v=E,这种情况 int count_1=0; char temp_column; tbl_row=SearchTbl(C1);/ =<firstVT(E) while(FIRSTVTFL_map(C2)count_1!='0') /填写小于关系 temp_column=FIRSTVTFL_map(C2)count

20、_1;/映射,仔细体会 tbl_column=SearchTbl(temp_column);/将上述结果再次转换 PriorityTabletbl_rowtbl_column='<'/填写关系 count_1+;/准备填写下一个 count_1=0;/清零 if(L=3)&&IsVT(C0)&&IsVT(C2)&&(FL_map(C1)!=-1) /弥补(E),针对本文法/首先填写<关系 char temp_row,temp_column; int reg=0; tbl_row=SearchTbl(C0); while

21、(FIRSTVTFL_map(C1)reg!='0') /填写小于关系 '('<firstVT(E) temp_column=FIRSTVTFL_map(C1)reg; tbl_column=SearchTbl(temp_column);/皆是映射 PriorityTabletbl_rowtbl_column='<' reg+; reg=0;/清零 tbl_column=SearchTbl(C2); while(LASTVTFL_map(C1)reg!='0') /填写大于关系 lastVT(E)>')&

22、#39; temp_row=LASTVTFL_map(C1)reg; tbl_row=SearchTbl(temp_row);/map PriorityTabletbl_rowtbl_column='>' reg+; reg=0;/reset else if(FL_map(C0)!=-1)&&IsVT(C1) /C0肯定为非终结符lastVT(C0)>C1 /填写大于关系 char temp_row,temp_column; int count=0; tbl_column=SearchTbl(C1); while(LASTVTFL_map(C0)co

23、unt!='0') /填写大于关系 temp_row=LASTVTFL_map(C0)count; tbl_row=SearchTbl(temp_row);/同上 PriorityTabletbl_rowtbl_column='>' count+; count=0; if(L=3) /在这种情况下C2必为非终结符,求C2的firstVT(),填写小于关系 /E+T,E-T,T*F,T/F等情况 tbl_row=SearchTbl(C1); while(FIRSTVTFL_map(C2)count!='0') /填写小于关系 temp_col

24、umn=FIRSTVTFL_map(C2)count; tbl_column=SearchTbl(temp_column);/map PriorityTabletbl_rowtbl_column='<' count+; count=0; /end if else if(INPUTpi!='|'&&INPUTpi!='0')/该行没结束,过滤'0' Cj=INPUTpi;/j从0开始 j+;/移进 if(INPUTpi='n') /该行结束break; /补上#的关系for(int m1=1;m

25、1<11;m1+)PriorityTableSearchTbl('#')m1='<'/这个容易理解,补行for(int m2=1;m2<11;m2+)PriorityTablem2SearchTbl('#')='>'/补列PriorityTableSearchTbl('#')SearchTbl('#')='='比如说对于这个文法分析出来的优先关系表如下: 模块三:构建词法分析的程序做好了上面两步运算已经累得不行了,下面还要继续进行分析,那就是词法分析程序,多亏

26、这个程序在实验一已经完成过,这里就拿出那里的代码进行必要的改进和删除,保留适合本文法要求的部分即可。其实想来无非是用到了识别标识符、识别常数、识别+、-、*、/、?、#、(、)、保留字clear等符号的算法罢了。还是比较好写的。但考虑到后面的运算,也就是最精彩的部分a=3;b=a+3;这样的句子,我们不得不在进行词法分析的时候将这些标识符登记到标识符表中,将句子打碎成二元组存放到符号表中。注意这里的符号表没有什么其他意义,就是存放将句子解释成的有序序列罢了。综上所述,词法分析这一过程就是识别字符串,若正确则填表,若错误,则报错。两个任务:填表、报错。由此也可以看到表格处理和错误处理在整个编译过

27、程中无处不在。这里新增了一些数据结构和全局变量:typedef struct char IDentifier30;/标识符长度 int value;/定义标识符代表的数值IDentifierTable;typedef struct int syn;/种别码 int value;/数值或者标识符入口指针SymbolTbl;IDentifierTable idTbl30;/定义全局标识符表SymbolTbl symbol100;/定义符号表,记录输入的程序片段下面是这一模块的具体的函数:1. void InsertID(char name,int entry,int value)功能是将标识符的名

28、字和数值插入到以entry为标识符入口地址的标识符表中。2. int ScanEntry(char name) 查找标识符表中是否有空闲位置,若有则返回入口地址,若无则报错。3.void Insert_Into_SymbolTbl(int syn,int value,int &pointer)将句子打散成的所有的二元组(名字和数值)插入到以pointer为符号表入口地址的符号表中。4. bool IsExist(char id) 查找表中是否已经存在该标识符5.int Search_Free_Entity( )这个函数即是在标识符表中申请一个可用的存储空间,若有则返回入口地址,否则报错

29、,申请失败。6. bool IsLetter(char letter)判断是否为字母7. bool IsDigit(char digit) 判断是否为数字8.void Scanner(char sentence,char name,int &syn,int &scan_point,int &value)扫描子程序,识别正规式。对句子进行扫描,抛出一个个单词。scan_point为扫描的总指针,name和value用来记录返回值;sentence即是要分析的句子;syn为种别码。这个程序是词法分析的核心,在上一实验中已详细介绍过,再次不必赘述。9. bool Check_

30、Is_Right(char sentence)检查句子是不是#。#的形式,因为程序的需要,输入的句子规定必须是这样的形式。10. void LexicalAnalysisCtl()词法分析的主控程序,也就是老师上课一再讲的那个主控程序。这个程序控制着Scanner(char sentence,char name,int &syn,int &scan_point,int &value)产生不同的正规式,并且负责着登记数据和错误处理。11. void Clear_Symbol_Tbl()这个函数负责着清除符号表中的句子,以便接下来的句子输入。12. void Clear_I

31、Dentifier_Tbl() 这个函数的功能是清楚标识符表的所有内容。一般会在“清除语句”中使用。下面是Scanner的程序:void Scanner(char sentence,char name,int &syn,int &scan_point,int &value)char token30,ch;int p_token=0;/token的指针int digit_value=0;/记录常数的大小for(int n=0;n<30;n+) tokenn='0'/对字符数组清零ch=sentencescan_point; /读入一个字符if(ch=

32、'#'&&scan_point=0)/该字符的种别码已经在主程序中登记了scan_point+;/刚开始的第一个字符一定为#ch=sentencescan_point;/指针下移,扫描下一字符 if(IsLetter(ch) /ch是否为字母while(IsLetter(ch)|IsDigit(ch) /ch是否为字母或数字 tokenp_token+=ch; scan_point+; ch=sentencescan_point; /读入一个字符tokenp_token='0'syn=9;/代表找到了标识符if(strcmp(token,&quo

33、t;clear")=0)/代表找到了保留字“clear”syn=11;strcpy(name,token);/带回标识符else if(IsDigit(ch) /ch是否为数字 digit_value=0; while(IsDigit(ch) /此处假设只是整数 digit_value=digit_value*10+ch-'0' scan_point+; ch=sentencescan_point; /读入一个字符 value=digit_value;/带回整数值 syn=10; else switch(ch) case'=':syn=1; break

34、;case'?':syn=2; break;case'+':syn=3; break;case'-':syn=4; break;case'*':syn=5; break;case'/':syn=6; break; case'(':syn=7; break;case')':syn=8; break;case'#':syn=12; break;default:printf("输入句子有误!n");exit(0);break; scan_point+;/

35、保持指针始终指向待判断的字符ch=sentencescan_point; /读入一个字符 下面是主控程序:void LexicalAnalysisCtl()/主控程序char sentence100="0"int syn=-1; char name30=""int value;int scan_point=0;/从开始处扫描int id_pointer;/定义标识符表入口指针int sym_pointer=0,entry;do printf("请输入句子,以#开始并且以#结束n"); scanf("%s",sent

36、ence);while(!Check_Is_Right(sentence);Insert_Into_SymbolTbl(12,-1,sym_pointer);printf("(%d , )n",12); while(syn!=12)/直到扫描到第二个#为止 Scanner(sentence,name,syn,scan_point,value); switch(syn) /若是单词 case 9:printf("(%d , %s)n",syn,name); /登记到表中 if(!IsExist(name) /不存在则插入 /查找可插入位置 id_point

37、er=Search_Free_Entity(); InsertID(name,id_pointer,-1);/-1代表还没被赋值 /搜索该标识符的入口地址放入value中 entry=ScanEntry(name); Insert_Into_SymbolTbl(syn,entry,sym_pointer); break; case 10:/常数 Insert_Into_SymbolTbl(syn,value,sym_pointer); printf("(%d , %d)n",syn,value); break; default:printf("(%d , )n&q

38、uot;,syn); Insert_Into_SymbolTbl(syn,-1,sym_pointer);/-1代表该处不需要值 printf("-词法分析正确!-n");/打印出符号表和标识符表 printf("标识符的入口地址 标识符 标识符的值(-1代表没被赋值)n"); for(int m1=0;m1<30;m1+)/标识符表 if(!(strcmp(idTblm1.IDentifier,"")=0) printf("t%d %s %dn",m1,idTblm1.IDentifier,idTblm1.

39、value); printf("符号表的入口地址 种别码 具体的值(或标识符入口)n"); for(int m2=0;m2<sym_pointer;m2+)/符号表printf("t%d %d %dn",m2,symbolm2.syn ,symbolm2.value);printf("-n");比如说对于#temp=2+(3*(2+4)#这个句子的词法分析结果为: 模块四:核心功能模块-算符优先分析 前面做了那么多铺垫就是为了算符优先分析做准备。到了这一步,真的很不容易,因此我们更要对今天的编译器的处理能力感到惊叹,的确不是一个

40、人可以完成的,就算一个人可以完成那所用的时间也真的不值。但是对于我们来说,学习一些编译原理上的一些处理问题的办法和角度,对我们未来的工作和生活绝对是大有裨益的。好了,就说一说这个费了我两天才完成的核心程序吧。其实,核心程序并没有那么难以理解!只要我们举几个简单的例子,模拟一下计算机在处理这个句子的过程,便不难写出程序。 首先分析我们现在有什么? 1.现在的情况是已经分析出了句子的单词,并且变成了单词块,存放在SymbolTbl symbol100中,单词的形式是(种别码,常数值)(种别码,标识符入口地址)、(种别码,用-1表示无意义)这是三大类。 2.并且分析出了标识符存放在了IDentifi

41、erTable idTbl30中。标识符的形式是(标识符名字,标识符的值),用-1表示暂未被赋值(这里就凑合一点,时间比较紧,待改进)。 3.分析出了算符优先分析的优先关系表存放在char PriorityTable2020中。 4.已经编码出了种别码表,放在char SymbolTbl_Define15中,这个是老师要求的次序,便于一致。但又需要一次转换,以后再说。 好了,我们已经有了这么多数据和方法(函数function),是不是马上就可以进行下去了呢?!还不行,因为我们迫切需要一个后进先出的存储结构来保存我们的数据,来完成我们的移进,归约。那就是栈。我们需要构造一个这样的栈:它的每个元素

42、的数据结构都是符号表中元素的数据结构,即为(种别码,-),-处即为上面分析的三种情况。栈的能力主要有:template <typename T>1. T gettop() 获得栈顶元素2.int getTopPointer() 得到栈顶指针的数值3.T traverseStack(int pointer) 定义遍历整个栈的能力4. void push(T num) 将元素压栈的能力5.T pop() 将元素弹出栈的能力6. Stack()top=-1; 初始化的能力7. void Clear_Stack() 清空堆栈的能力数据对象:Stack<SymbolTbl> Re

43、ource_Symbol;/定义堆栈还有几个分析将使用的函数:char SearchSyn(int syn) 根据种别码返回相应字符,因为我们是在对种别码进行大小比较,需要先将该种别码映射成具体的终结符。然后再将该终结符映射成优先关系表中的横纵坐标。int Search_Priority_Setxy(char ch)搜索一个字符在优先符表中的位置,这就是我说的“将该终结符映射成优先关系表中的横纵坐标。”的映射方法。void Print_Context(int Stack_Top,int Sym_Pointer)打印出当前堆栈和符号表的上下文void MainProc_Analysis()主分析

44、函数,整个算法的核心。 好了,有了这些东西,我们的分析总算可以一马平川了。 1.首先将符号表的第一个元素#,对应的(种别码,-1)压栈,即 SymbolTbl temp_sym; temp_sym.syn=12; temp_sym.value=-1;/-1代表这个地方不需要 Reource_Symbol.push(temp_sym);/将#压栈 2.对于堆栈定义两个指针,一个指针pStackTop始终指向栈顶,在栈被修改(push,pop)之后都要修改。另一个堆栈指针是pScanStack,负责对整个堆栈的扫描,不断地查找可归约串的结束位置。 对于符号表,定义Sym_scan_pointer指

45、针,从一开始,对符号表进行扫描。 3.因为现在不仅是语法分析,还包含了语义分析,我们要定义好语义子程序,比如说“清除语句”,#clear#,我们遇到这个东西时,就要1.清空符号表和标识符表;2.清除屏幕(我自己理解的,清除应该就是这些吧。) 因此,我们在进行其他分析之前,先把这个清除语句搞定。if(sym_length>=3&&(symbol1.syn=11) /清除语句,清除屏幕并且清空标号表中的值 Clear_IDentifier_Tbl(); Clear_Symbol_Tbl(); system("cls"); goto end; 4.扫除了这些

46、障碍,我们总算可以进行真正的分析了。 首先栈扫描指针和栈顶指针同时指向栈顶开始分析:下面进行永真循环:*查看栈扫描指针pScanStack所指的元素和符号表指针所指元素的关系。4.1若为小于: 则将符号表指针所指元素压栈,修改栈的两个指针都指向栈顶。符号表指针下移。4.2若为等于: 此时要分两种情况:1.若是栈扫描指针pScanStack所指的元素和符号表指针所指元素都是#,则查看栈中是否只有两个元素且栈顶元素是否为N,若为真,则说明归约成功,输出栈顶的值,然后结束分析。否则,则报错。 2.若不是上面的情况,则按照小于关系处理。4.3若为大于: 这个时候,就是激动人心的时候了,因为要进行归约了

47、。 首先对齐pStackTop,pScanStack这两个指针,虽然这个时候肯定是对齐的(自己想),然后进入小循环 while(Prior_Relation='>'),小循环的内容是: *判断现在栈扫描指针所指元素的种别码,该种别码所对应元素即是大于符号表中指针所指的元素。4.3.1若该元素为标识符:语义分析:判断标识符是否已定义;弹出栈顶元素,将N(13,标识符的值)压入栈中,这里取了一次巧,即是让N来承载归约的结果,更加方便。重新修改栈顶指针,栈扫描指针,将栈扫描指针指向从栈顶数第一个终结符的位置,即下移。pScanStack=Reource_Symbol.getTo

48、pPointer()-1;重新定位行列指针(列不变),修改关系。row_prior=Search_Priority_Setxy(SearchSyn(Reource_Symbol.traverseStack(pScanStack).syn); Prior_Relation=PriorityTablerow_priorcolumn_prior; 4.3.2若该元素为常量,则分析的过程和标识符极其相似,唯一不同的是,N(13,值)中的值,一个是从标识符表中查到的,另一个是直接就有的。4.3.3若该元素为=,这时根据文法的要求,出现等号就应该满足“v=N”这种情况。首先判断是否满足,若不满足则报错,若

49、满足,则将这三个元素归约为一个元素N(13,旧N.value),并且要反填符号表,将该变量的值赋为旧N.value。这一步语义分析十分重要,直接关系着以后引用这个变量时是否能够找到它的值。idTblReource_Symbol.traverseStack(pScanStack-1).value.value=Reource_Symbol.gettop().value;/此时栈顶必为E然后就是修改栈的两个指针,重新定位行列(列不变),修改关系。4.3.4若该元素为+、-、*、/,则这四个的处理方式一样。首先判断栈顶是否满足N op N,op=+|-|*|/,若满足则归约,否则认为是错误的,进行报错处理。规约之后,同样的将N op N归约为N,并且将 “新N.value=(N1.value op N1.value)” -语义分析然后就是修改栈的两个指针,重新定位行列(列不变),修改关系。4.3.5若该元素为),这个时候栈顶一定为(N),若不是,则句子出错,进行错误处理,又因为(是大于任何终结符的,因此(N)就构成了“鱼眼睛”,“< = >”,所以需

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论