算符优先文法
- 格式:doc
- 大小:68.00 KB
- 文档页数:18
一、实验目的与任务算术表达式和赋值语句的文法可以是(你可以根据需要适当改变):S→i=EE→E+E|E-E|E*E|E/E|(E)|i根据算符优先分析法,将赋值语句进行语法分析,翻译成等价的一组基本操作,每一基本操作用四元式表示。
二、实验涉及的相关知识点算符的优先顺序。
三、实验内容与过程如参考C语言的运算符。
输入如下表达式(以分号为结束):(1)a = 10;(2)b = a + 20;注:此例可以进行优化后输出(不作要求):(+,b,a,20)(3)c=(1+2)/3+4-(5+6/7);四、实验结果及分析(1)输出:(=, a,10,-)(2)输出:(=,r1,20,-)(+,r2,a,r1)(=,b,r2,-)(3)输出:(+,r1,1,2) (/,r2,r1,3) (/,r3,6,7) (+,r4,5,r3,) (+,r5,r2,4) (-,r6,r5,r4) (=,c,r6,-)五、实验有关附件(如程序、附图、参考资料,等)......h == '#') o][Peek(n0).No];if(r == '<') h == 'E'&& Peek(1).ch == '#' && Token[ipToken].ch == '#')return TRUE;elsereturn FALSE;}h){k = TRUE; h == 'E'){n ++;}return n;}词结束(遇到“#”号),无法移进,需要规约,返回:1词没有结束,需判断是否可以移进栈单词<=单词:移进后返回:2栈单词>单词:不能移进,需要规约,返回:1单词没有优先关系:出错,返回:-1int MoveIn(){SToken s,t; h = '#';Token[TokenNumber].No = O_NUL;return TRUE; h = '+';Token[TokenNumber].No = O_PLUS;GetChar();break;case '-':Token[TokenNumber].ch = '-';Token[TokenNumber].No = O_MINUS;GetChar();break;case '*':Token[TokenNumber].ch = '*';Token[TokenNumber].No = O_TIMES;GetChar();break;case '/':Token[TokenNumber].ch = '/';Token[TokenNumber].No = O_SLASH;GetChar();break;case '(':Token[TokenNumber].ch = '(';Token[TokenNumber].No = O_L_PAREN;GetChar();break;case ')':Token[TokenNumber].ch = ')';Token[TokenNumber].No = O_R_PAREN;GetChar();break;default:if(ch >= '0' && ch <= '9') h = 'i';Token[TokenNumber].No = O_IDENT;}else{return ! MakeErr("表达式中含有非法字符。
一、实验目的1. 理解算符优先分析法的原理和过程。
2. 掌握算符优先分析法的实现方法。
3. 通过实验加深对自底向上语法分析方法的理解。
二、实验内容1. 算符优先分析法原理介绍算符优先分析法是一种自底向上的语法分析方法,它通过比较相邻算符的优先次序来识别句型中的句柄,进而执行归约。
该方法的核心是确立文法的终结符之间的优先关系。
2. 实验步骤(1)判断文法是否为OG文法:OG文法要求所有产生式右部至少有一个终结符。
(2)判断文法是否为OPG文法:计算FIRSTVT集、LASTVT集,并构建算符优先矩阵。
(3)对句子进行分析:根据分析表判断句子是否为文法的句子。
(4)实现程序:从文件和键盘读取输入,将结果输出到指定文件和屏幕,并具有一致性。
3. 实验数据(1)文法:g[e]:e->e+t|t(2)测试句子:12+t, t+12, 12+13t, 12+t13三、实验过程1. 判断文法是否为OG文法根据给定的文法,我们可以看到所有产生式右部至少有一个终结符,因此该文法为OG文法。
2. 判断文法是否为OPG文法,并构建算符优先矩阵(1)计算FIRSTVT集FIRSTVT(e) = {t}FIRSTVT(t) = {t}(2)计算LASTVT集LASTVT(e) = {t}LASTVT(t) = {t}(3)构建算符优先矩阵| + - ( ) t e $+ > - - - > > -- > - - - > > -> > > > > > >( > > > > > > >) - - - - - - -t - - - - - - -e - - - - - - -$ - - - - - - -3. 对句子进行分析(1)分析句子“12+t”根据分析表,我们可以得到以下分析过程:12+t -> 12+t -> 12+t -> t -> t(2)分析句子“t+12”根据分析表,我们可以得到以下分析过程:t+12 -> t+12 -> t+12 -> t+12 -> t+12 -> t -> t (3)分析句子“12+13t”根据分析表,我们可以得到以下分析过程:12+13t -> 12+13t -> 12+13t -> 12+13t -> 12+13t -> t -> t(4)分析句子“12+t13”根据分析表,我们可以得到以下分析过程:12+t13 -> 12+t13 -> 12+t13 -> 12+t13 -> 12+t13 -> t13 -> t13 -> t13 -> t -> t四、实验结果1. 测试句子“12+t”分析结果:正确2. 测试句子“t+12”分析结果:正确3. 测试句子“12+13t”分析结果:正确4. 测试句子“12+t13”分析结果:正确五、实验总结通过本次实验,我们深入了解了算符优先分析法的原理和实现方法。
算符优先文法分析1.问题描述基于算符优先分析法的语法分析程序要求:(1)输入已知文法,生成文法矩阵,判断该文法是否是算符优先文法。
(2)用程序自动生成该文法的算符优先关系矩阵。
(3)对人工输入的句型或句子,分析该句型或句子是否合法,能否用已知文法推出。
(4)具有通用性。
所开发的程序可适用于不同的文法和任意输入串,且能判断该文法是否为算符优先文法。
(5)有运行实例。
对于输入的文法和符号串,所编制的语法分析程序应能正确判断此串是否为文法的句子,并要求输出分析过程。
2.算符优先分析法2.1算符优先文法定义:设有不含空串的一文法G,如果G中没有形如G>……BC……的产生式,其中B和C为非终结符,且对任意两个终结符a,b之间之多只有<,>,=,三种关系的一种成立,则称G是一个算符优先文法。
非终结符的FIRSTVT集合和LASTVT集合FIRSTVT(B)={b|B→b…或B→Cb…}LASTVT(B)={b|B→…a或B→…aC}2.2算符优先矩阵算符优先关系矩阵,判断输入是否满足已知文法的依据。
根据非终结符的FIRSTVT集合和LASTVT集合产生。
1.“=”关系若A→…ab…或A→…aBb…,则a=b;2.“〈⋅”关系若A→…aB…,对每一个b属于FIRSTVT(B),有a〈⋅b;3.“⋅〉”关系若A→…Bb…,对每一个a属于LASTVT(B),有a⋅〉 b。
2.3如何规约在分析过程中,利用分析栈存放已识别的那部分句型,而句型的其余部分由剩余输入串组成,通过比较栈顶符号和下一个输入符号之间的关系,可以判别栈顶符号是否为句柄尾符号。
如果是句柄尾,则沿栈顶向下,在栈内寻找句柄头(利用关系)。
由关系和关系之间包括的符号串就是句柄,然后把它们弹出栈,并代之以归约后的非终结符。
这样就完成了一次归约过程。
2.4算符优先分析方法的局限性由于算符优先分析法去掉了单非终结符之间的归约,尽管在分析过程中,当决定是否为句柄时采取一些检查措施,但仍难完全避免把错误的句子得到正确的归约。
《编译原理》课程实验报告实验名称:算符优先文法姓名学号:地点:教师院系:计算机与通信工程学院专业:计算机科学与技术09-2一.实验目的设计、编制并调试一个算符优先法分析程序,加深对算符优先法分析原理的理解。
二.实验内容算术表达式的文法:(1).E → E +T | E -T | T(2).T → T * F | T / F | F(3).F → i |(E)转化后的文法:(1).E → E +T(2).E → E -T(3).E → T(4).T → T * F(5).T →T / F(6).T →F(7).F → i(8).F →(E)根据表达式的文法,首先计算每个非终结符的FIRSTVT和LASTVT:执行算法逐条扫描文法规则,从而构造出文法的算符优先关系表如图所示用算符优先分析法法对该文法进行分析,在每次归约成功后则输出四元式。
四元式形式如下:(op,arg1,arg2,result)其中op是运算符,arg1,arg2分别是第一和第二个运算对象,当op是一目运算时,常常将运算对象定义为arg1.例如,表达式-C和赋值语句X=a的四元式可分别表示为(i)(@,C,-,T)(j)(=,a,-,X)三.源代码:#include<stdio.h>#include<string.h>#include<stdlib.h>#define MAXSIZE 64#define N -10typedef char datatype;typedef struct{datatype data[MAXSIZE];int top;}seqstack;seqstack OPR;seqstack OPT;char *p;int matrix[7][7]={{N,-1,-1,-1,-1,N,1},{N,1,-1,-1,-1,1,1},{N,1,1,-1,-1,1,1},{1,1,1,N,N,1,1},{N,-1,-1,-1,-1,0,N},{N,1,1,N,N,1,1},{-1,N,N,-1,N,N,0}}; int row,line;int count=1;int compare(char m,char n){switch(m){case '=':row=0;break;case '+':row=1;break;case '*':row=2;break;case 'i':row=3;break;case '(':row=4;break;case ')':row=5;break;case '$':row=6;break;default: return -100;break;}switch(n){case '=':line=0;break;case '+':line=1;break;case '*':line=2;break;case 'i':line=3;break;case '(':line=4;break;case ')':line=5;break;case '$':line=6;break;default: return -100;break;}return matrix[row][line];}void OPRsetnull(){OPR.top=-1;}bool OPRempty(){if(OPR.top>=0)return false;elsereturn true;}void OPRpush(char x){if(OPR.top==MAXSIZE-1)printf("上溢!");else {OPR.top++;OPR.data[OPR.top]=x;}}datatype OPRpop(){if(OPRempty()){printf("下溢!");return NULL;}else{OPR.top--;return(OPR.data[OPR.top+1]);}}datatype OPRtop(){if(OPRempty()){return NULL;}elsereturn(OPR.data[OPR.top]); }void OPTsetnull(){OPT.top=-1;}bool OPTempty(){if(OPT.top>=0)return false;elsereturn true;}void OPTpush(char x){if(OPT.top==MAXSIZE-1)printf("上溢!");else{OPT.top++;OPT.data[OPT.top]=x;}}datatype OPTpop(){if(OPTempty()){printf("下溢!");return NULL;}else{OPT.top--;return(OPT.data[OPT.top+1]);}}datatype OPTtop(){if(OPTempty()){return NULL;}else return(OPT.data[OPT.top]);}void output(char opt,char op1,char op2,int num){if(op1=='i'&&op2=='i') printf("(%c,%c,%c,t%d)\n",opt,op1,op2,num);if(op1!='i'&&op2=='i') printf("(%c,t%d,%c,t%d)\n",opt,op1,op2,num);if(op2!='i'&&op1=='i') printf("(%c,%c,t%d,t%d)\n",opt,op1,op2,num);if(op1!='i'&&op2!='i') printf("(%c,t%d,t%d,t%d)\n",opt,op1,op2,num); }void scan(){char opt;char op1,op2;if(*p=='$') OPTpush(*p);p++;while(*p!='$'){if(*p=='i') OPRpush(*p);else {opt=OPTtop();P: switch(compare(opt,*p)){case -1: OPTpush(*p); break;case N: break;case 0: OPTpop(); break;case 1: op1=OPRpop();op2=OPRpop();output(opt,op1,op2,count);OPRpush(count);count++;opt=OPTpop();opt=OPTtop();goto P; break;}}p++;}while(!OPTempty()&&!OPRempty()&&(OPTtop()!='$')){ op1=OPRpop();op2=OPRpop();opt=OPTpop();if(opt!='='){output(opt,op1,op2,count);OPRpush(char(count));count++;}if(opt=='=') printf("(%c,t%d, ,i)\n",opt,count-1);}}void main(){int d;OPRsetnull();OPTsetnull();char ch[]="$i=i*(i*(i+i))*i$";printf("分析语句:");printf("%s\n",ch);p=ch;scan();}四.实验步骤调试程序的结果:。
算符优先算法1. 算符优先算法简介算符优先算法(Operator Precedence Parsing)是一种用于解析和计算表达式的方法。
它通过定义运算符之间的优先级和结合性来确定表达式的计算顺序,从而实现对表达式的准确解析和计算。
在算符优先算法中,每个运算符都被赋予一个优先级,表示其与其他运算符之间的优先关系。
根据这些优先级规则,可以将一个表达式转化为一个操作符和操作数构成的序列,并按照一定的顺序进行计算。
2. 算符优先文法在使用算符优先算法进行解析时,需要定义一个文法来描述运算符之间的关系。
这个文法称为算符优先文法。
一个典型的算符优先文法由以下三部分组成:1.终结符:表示可以出现在表达式中的基本元素,例如数字、变量名等。
2.非终结符:表示可以出现在表达式中但不能作为最终结果输出的元素,例如运算符。
3.产生式:描述了如何将非终结符转化为终结符或其他非终结符。
通过定义合适的产生式规则,可以建立起非终结符之间的优先关系。
这些优先关系决定了表达式中运算符的计算顺序。
3. 算符优先表算符优先表(Operator Precedence Table)是算符优先算法的核心数据结构之一。
它用于存储运算符之间的优先级和结合性信息。
一个典型的算符优先表由以下几部分组成:1.终结符集合:包含所有可能出现在表达式中的终结符。
2.非终结符集合:包含所有可能出现在表达式中的非终结符。
3.优先关系矩阵:用于存储运算符之间的优先关系。
矩阵中每个元素表示两个运算符之间的关系,例如“<”表示左运算符优先级低于右运算符,“>”表示左运算符优先级高于右运算符。
“=”表示两个运算符具有相同的优先级。
通过使用算符优先表,可以根据当前输入字符和栈顶字符来确定下一步应该进行的操作,例如移进、规约等。
4. 算法流程下面是一个简化版的算法流程:1.初始化输入串、操作数栈和操作符栈。
2.从输入串中读取一个字符作为当前输入字符。
3.如果当前输入字符为终结符,则进行移进操作,将其压入操作数栈,并读取下一个输入字符。
简单优先和算符优先分析方法简单优先分析(Simple Precedence Parsing)和算符优先分析(Operator Precedence Parsing)是两种常用的自底向上的语法分析方法。
它们是基于符号优先级的理念,通过比较符号之间的优先级关系,来进行语法分析。
1.简单优先分析简单优先分析是一种自底向上的语法分析方法,它利用一个优先级表来确定符号之间的优先关系。
简单优先分析的算法如下:(1)将输入串和符号栈初始化为空。
(2)从输入串中读入第一个输入符号a。
(3)将a与栈顶的符号进行比较:a.如果a的优先级大于栈顶符号的优先级,将a推入符号栈,并读入下一个输入符号。
b.如果a的优先级小于栈顶符号的优先级,将栈中的符号做规约操作,直到栈顶的符号优先级不小于a。
然后,将a推入符号栈。
c.如果a和栈顶符号优先级相等,栈顶的符号出栈,并将a推入符号栈。
(4)重复步骤(3)直到输入串为空。
(5)如果符号栈中只有一个符号且为文法的开始符号,则分析成功。
简单优先分析的优先级表一般由语法规则和符号之间的优先关系组成。
我们可以通过构造优先级关系表来实现简单优先分析。
2.算符优先分析算符优先分析是一种自底向上的语法分析方法,它也是基于符号优先级的理念,但是相对于简单优先分析,算符优先分析更加灵活,并且允许处理左递归的文法。
算符优先分析的算法如下:(1)将输入串和符号栈初始化为空。
(2)从输入串中读入第一个输入符号a。
(3)将a与栈顶的符号进行比较:a.如果a的优先级大于栈顶符号的优先级,将a推入符号栈,并读入下一个输入符号。
b.如果a的优先级小于栈顶符号的优先级,将栈中的符号做规约操作,直到栈顶的符号优先级不小于a。
然后,将a推入符号栈。
c.如果a和栈顶符号优先级相等,根据符号栈中符号的类型执行相应的操作(如归约、移进等)。
(4)重复步骤(3)直到输入串为空。
(5)如果符号栈中只有一个符号且为文法的开始符号,则分析成功。
算符优先文法课程设计一、课程目标知识目标:1. 学生能理解算符优先文法的基本概念,掌握算符优先级的原则。
2. 学生能运用算符优先文法对算术表达式进行正确的解析和计算。
3. 学生了解算符优先文法在计算机科学中的应用和重要性。
技能目标:1. 学生能够运用算符优先文法设计简单的计算器程序,实现对算术表达式的计算。
2. 学生能够通过分析算术表达式,准确地判断算符的优先级,并进行相应的计算。
3. 学生能够运用所学知识解决实际问题,提高编程和逻辑思维能力。
情感态度价值观目标:1. 学生培养对计算机科学和程序设计的兴趣,激发探索精神。
2. 学生在学习过程中,培养合作、交流和问题解决的积极态度。
3. 学生通过算符优先文法的学习,认识到数学与计算机科学的紧密联系,增强学科交叉融合的意识。
课程性质分析:本课程为计算机科学相关学科,通过讲解算符优先文法,使学生掌握计算机处理算术表达式的基本原理。
学生特点分析:学生处于具备一定数学基础和逻辑思维能力的年级,对新鲜事物充满好奇,但可能对编程和算法尚感陌生。
教学要求:1. 教师应注重理论与实践相结合,让学生在实际操作中掌握算符优先文法。
2. 教师应引导学生主动思考,提高学生分析问题和解决问题的能力。
3. 教师关注学生的情感态度,鼓励学生积极参与课堂讨论,培养合作精神。
二、教学内容1. 算符优先文法基本概念:算符、优先级、结合性。
2. 算符优先级的判定方法:算术表达式中算符的优先级判断。
3. 算符优先文法的应用:设计简单计算器程序,实现算术表达式的计算。
4. 算符优先文法的算法实现:递归下降分析法、算符栈方法。
5. 实例分析:分析常见算术表达式的算符优先文法应用,总结规律。
6. 编程实践:编写计算器程序,实现对算术表达式的解析和计算。
教学内容安排和进度:第一课时:算符优先文法基本概念,结合教材第一章第一节。
第二课时:算符优先级的判定方法,结合教材第一章第二节。
第三课时:算符优先文法的应用,结合教材第二章第一节。
算符优先⽂法的构造算符优先⽂法的构造算符优先⽂法属于⾃底向上的⽂法分析,需要不断的进⾏移进-规约操作,让⼀个输⼊的句⼦通过不断的移进-规约,最终变成⽂法的开始符号。
在移进-规约的过程中我们需要知道先对什么进⾏规约,得有个先后关系,故需要构造⽂法的算符优先表,来帮助规约分析时的规约对象。
构造FirstVT集和LastVT集FirstVT和LastVT分别代表某个⾮终结符所产⽣的句型中第⼀个和最后⼀个终结符的集合。
具体产⽣规则如下:Firstvt找Firstvt的三条规则:如果要找A的Firstvt,A的候选式中出现:A->a.......,即以终结符开头,该终结符⼊FirstvtA->B.......,即以⾮终结符开头,该⾮终结符的Firstvt⼊A的FirstvtA->Ba.....,即先以⾮终结符开头,紧跟终结符,则终结符⼊FirstvtLastvt找Lastvt的三条规则:如果要找A的Lastvt,A的候选式中出现:A->.......a,即以终结符结尾,该终结符⼊LastvtA->.......B,即以⾮终结符结尾,该⾮终结符的Lastvt⼊A的LastvtA->.....aB,即先以⾮终结符结尾,前⾯是终结符,则终结符⼊Firstvt构造算符优先表算符优先关系表即确定各个终结符的优先关系,以便之后寻找最左素短语。
算符优先表分以下⼏种情况:E->...aBc...和E->...ac...,在产⽣式中存在类似关系的终结符优先级相等,即a和c的优先级相等。
E->Ab,在产⽣式中存在⼀个⾮终结符在前⼀个终结符在后的情况,则A的LastVT集合中的终结符优先级都⾼于终结符b的优先级E->aB,在产⽣式中存在⼀个终结符在前和⼀个⾮终结符在后的情况,则B的FirstVT集合中的终结符优先级都⾼于终结符a的优先级其实⼤⽩话说起来就遵循⼀种就⾏:就是产⽣式中哪些终结符⼀起能规约成左部⾮终结符,则两者优先级相等,⽽终结符和⾮终结符在同⼀个产⽣式中,⾮终结符的终结符集合需要先规约成⾮终结符,所以那些⾮终结符的终结符的优先级要⾼于与⾮终结符在同⼀产⽣式中的终结符寻找待规约串寻找规约串即寻找最左素短语。
编译原理实验代码:对于任意给定的文法,判断其是否是算符优先文法。
代码如下:#include<iostream>#include<stdlib.h>#include <fstream>#define row 50#define col 50#define SIZE 50using namespace std;//两个重要结构体的定义//FIRSTVT表或LASTVT表中一个表项(A,a)结构体的初始化typedef struct{char nonterm; //非终结符char term; //终结符}StackElement;//存放(A,a)的栈的初始化typedef struct{StackElement *top;StackElement *bottom;int stacksize;}stack;//初始化(A,a)栈void InitStack(stack &S){S.bottom = new StackElement[SIZE];if(!S.bottom)cout<<"存储空间分配失败!"<<endl;S.top = S.bottom;S.stacksize = SIZE;}//判断(A,a)栈是否为空bool ifEmpty(stack S){if(S.top==S.bottom) return true; //如果栈为空,则返回true else return false; //否则不为空,返回false}//插入栈顶(A,a)元素void Insert(stack &S,StackElement e){if(S.top-S.bottom>=S.stacksize)cout<<"栈已满,无法插入!"<<endl;else{S.top->nonterm=e.nonterm;S.top->term=e.term;S.top++;}}//弹出栈顶(A,a)元素StackElement Pop(stack &S){StackElement e;e.nonterm = '\0';e.term = '\0';if(S.top==S.bottom){cout<<"栈为空,无法进行删除操作!"<<endl;return e;}else{S.top--;e.nonterm=S.top->nonterm;e.term=S.top->term;return e;}}//终结符与非终结符的判断函数(布尔类型)bool TerminalJud(char c){if(c>='A'&&c<='Z') return false; //非终结符返回false //else if(c>='a'&&c<='z') return false;else return true; //终结符返回true}//判断非终结符在first表中是否已存在bool ItemJud(char first[][col],int frist_len,char C){for(int i=0;i<frist_len;i++){if(first[i][0]==C)return true; //如果first表中已存在此非终结符,则返回true }return false;}//读文件函数int readfile(char sen[][col]){char addr[50];cout<<"请输入要读文件的地址(\\用\\\\表示):"<<endl;cin>>addr;ifstream fin;fin.open(addr,ios::in);if(!fin){cout<<"Cannot open file!\n"<<endl;}int i,mm,l,z,k,j;char D[100][100];for(i=0;!fin.eof();i++){fin>>D[i];cout<<D[i]<<endl;}k=0;//cout<<i<<" iiii"<<endl;//cout<<k<<endl;//for(j=0;j<i;j++)//cout<<D[j]<<"ggg"<<endl;for(z=0;z<i;z++){mm=0;l=0;for(j=0;j<=strlen(D[z]);j++){if(D[z][j]=='|'){sen[k][l]='\0';mm=1;k++;sen[k][0]=D[z][0];sen[k][1]='-';sen[k][2]='>';l=3;j++;}if(mm==0){sen[k][l]=D[z][j];l++ ;}if(mm==1){sen[k][l]=D[z][j];l++ ;}}k++;}//cout<<k<<" kkkkkk"<<endl;//for(i=0;i<k;i++)//cout<<sen[i]<<endl;return k;}//FIRSTVT表和LASTVT表中表项(非终结符)的初始化void ItemInit(char sen[][col],char first[][col],char last[][col],int sen_len,int &frist_len){int i;frist_len=1;first[0][0]=sen[0][0];last[0][0]=sen[0][0];for(i=1;i<sen_len;i++){if(TerminalJud(sen[i][0])==false &&ItemJud(first,frist_len,sen[i][0])==false) //k是当前first和last表的长度{first[frist_len][0]=sen[i][0];last[frist_len][0]=sen[i][0];frist_len++;}}}void FirstVt(char sen[][col],char first[][col],int sen_len,int frist_len) // frist_len 是first 表的行数sen_len是产生式的个数{StackElement DFS,record[SIZE];//StackElement char nonterm; //非终结符char term; //终结符stack Operator; //创建存放(A,a)的栈StackElement*top; StackElement *bottom; int stacksize;InitStack(Operator);int i,j,r=0;for(i=0;i<sen_len;i++) //第一次扫描,将能直接得出的first(A,a)放进栈中{for(j=3;sen[i][j]!='\0';j++){if(TerminalJud(sen[i][j])==true) //遇到的第一个终结符压入{int exist=0;DFS.nonterm=sen[i][0];DFS.term=sen[i][j];for(int i1=0;i<r;i++){if(record[i1].nonterm==sen[i][0]&&record[i1].term==sen[i][j]){exist=1;break;}record[r].nonterm=sen[i][0];record[r].term=sen[i][j];if(exist==0){Insert(Operator,DFS);//A-aB A-aC (A,a)压栈两次?record[r].nonterm=sen[i][0];record[r].term=sen[i][j];r++;}break;}}}int location[col]; //辅助数组,用来记录first表中放入终结符的位置for(i=0;i<frist_len;i++)location[i]=1;while(!ifEmpty(Operator)){int exist=0; //标志位,记录即将入栈的元素是否已经存在StackElement IDElement,DElement;DElement=Pop(Operator); //弹出栈顶元素for(i=0;i<frist_len;i++){if(first[i][0]==DElement.nonterm){int n=location[i];first[i][n]=DElement.term; //将终结符填入相应的first表中location[i]++;break;}}for(j=0;j<sen_len;j++){if(sen[j][3]==DElement.nonterm) //找出能推出当前非终结符的产生式的左部{IDElement.nonterm=sen[j][0];IDElement.term=DElement.term;//判断将要放进栈里的元素曾经是否出现过,若没有,才压入栈for(int r0=0;r0<r;r0++) //r记录record数组中的元素个数{if(record[r0].nonterm==IDElement.nonterm &&record[r0].term==IDElement.term)exist=1;break;}}if(exist==0){Insert(Operator,IDElement);record[r].nonterm=IDElement.nonterm;record[r].term=IDElement.term;r++;}}}}}void LastVt(char sen[][col],char last[][col],int sen_len,int frist_len) //firstvt 表与lastvt表行数一样first_len表示last 表的行数{int i,j,i1,j1;char c,record[row][col]={'\0'};for(i=0;i<sen_len;i++){for(j=0;sen[i][j]!='\0';j++){record[i][j]=sen[i][j];}j=j-1;for(i1=3,j1=j;i1<j1;i1++,j1--) //做翻转,就可以用求first的方法求last{c=record[i][i1];record[i][i1]=record[i][j1];record[i][j1]=c;}}//forFirstVt(record,last,sen_len,frist_len);}//判断非终结符在term表中是否已存在bool TermTableJud(char term[col],int term_len,char C)for(int i=0;i<term_len;i++){if(term[i]==C)return true; //如果first表中已存在此非终结符,则返回1}return false;}//构造算符优先关系表bool OpPriotable(char sen[][col],char first[][col],char last[][col],char opTable[][col],int sen_len,int first_len,int &opTable_len){int i,j,term_len=0;int i2,i3,opr,opc;char c1,c2,c3;char term[SIZE]={'\0'};for(i=0;i<sen_len;i++) //一维数组term记录关系表中存在的所有终结符{for(j=3;sen[i][j]!='\0';j++){if(TerminalJud(sen[i][j])==true)if(TermTableJud(term,term_len,sen[i][j])==false) //term_len记录term表的长度{term[term_len]=sen[i][j];term_len++;}}} //得到终结符表for(i=0;i<term_len+1;i++) //给优先关系表赋初值,都等于空for(j=0;j<term_len+1;j++)opTable[i][j]=' ';for(i=1;i<term_len+1;i++) //设置优先关系表的表头{opTable[i][0]=term[i-1];opTable[0][i]=term[i-1];}opTable[i][0]='$';opTable[0][i]='$';for(i=0;i<sen_len;i++) //找等于关系{for(j=4;sen[i][j]!='\0';j++)if(TerminalJud(sen[i][j-1])==true&&TerminalJud(sen[i][j])==true){c1=sen[i][j-1];c2=sen[i][j];for(opr=1;opr<term_len+1;opr++) //在opTable表中找到该存入的行标opr{if(opTable[opr][0]==c1)break;}for(opc=1;opc<term_len+1;opc++) //在opTable表中找到该存入的列标j2{if(opTable[0][opc]==c2)break;}if(opTable[opr][opc]!=' '){if(opTable[opr][opc]!='='){cout<<"不是算符优先文法!"<<endl;return false;}}else{opTable[opr][opc]='=';}}}for(j=5;sen[i][j]!='\0';j++){if(TerminalJud(sen[i][j-2])==true&&TerminalJud(sen[i][j-1])==false&&Ter minalJud(sen[i][j])==true){c1=sen[i][j-2];c2=sen[i][j];for(opr=1;opr<term_len+1;opr++) //在opTable表中找到该存入的行标opr{if(opTable[opr][0]==c1)break;}for(opc=1;opc<term_len+1;opc++) //在opTable表中找到该存入的列标opc{if(opTable[0][opc]==c2)break;}if(opTable[opr][opc]!=' ') //表示存在多种关系不满足条件{if(opTable[opr][opc]!='='){cout<<"不是算符优先文法!"<<endl;return false;}}else{opTable[opr][opc]='=';}}//if}//for(j)}//for(i)for(i=0;i<sen_len;i++) //找小于关系{for(j=3;sen[i][j]!='\0';j++){if(TerminalJud(sen[i][j])==true&&TerminalJud(sen[i][j+1])==false){c1=sen[i][j]; //c1记录终结符c2=sen[i][j+1]; //c2记录非终结符for(opr=1;opr<term_len+1;opr++) //在opTable表中找到该存入的行标opr{if(opTable[opr][0]==c1)break;}for(opc=0;opc<first_len;opc++) //找出非终结符在first表中的列标opc {if(first[opc][0]==c2)break;for(i2=1;first[opc][i2]!='\0';i2++){c3=first[opc][i2];for(i3=1;i3<term_len+1;i3++)if(opTable[0][i3]==c3){if(opTable[opr][i3]!=' '){if(opTable[opr][i3]!='<'){cout<<"不是算符优先文法!"<<endl;return false;}}else{opTable[opr][i3]='<';}break;}}}}}for(i=0;i<sen_len;i++) //找大于关系{for(j=3;sen[i][j]!='\0';j++){if(TerminalJud(sen[i][j])==false&&sen[i][j+1]!='\0'&&TerminalJud(sen[i][j +1])==true){c1=sen[i][j]; //c1记录非终结符c2=sen[i][j+1]; //c2记录终结符for(opr=1;opr<term_len+1;opr++) //在opTable表中找到该存入的列标j1{if(opTable[0][opr]==c2)break;for(opc=0;opc<first_len;opc++) //找出非终结符在last表中的行标j2 {if(last[opc][0]==c1)break;}for(i2=1;last[opc][i2]!='\0';i2++){c3=last[opc][i2];for(i3=1;i3<term_len+1;i3++)if(opTable[i3][0]==c3){if(opTable[i3][opr]!=' '){if(opTable[i3][opr]!='>'){cout<<"不是算符优先文法!"<<endl;return false;}}else{opTable[i3][opr]='>';}break;}}}}}opTable_len=term_len+1;return true;}//判断两算符优先关系并给出类型供构造分析表int RelationshipJud(char c1,char c2,char opTable[][col],int opTable_len) {int i,j;for(i=1;i<opTable_len;i++){if(opTable[i][0]==c1)break;}for(j=1;j<opTable_len;j++){if(opTable[0][j]==c2)break;}if(opTable[i][j]=='<')return 1;else if(opTable[i][j]=='=')return 2;else if(opTable[i][j]=='>')return 3;else return 4;}//判断输入串是不是优先文法bool PrioGramJud(char sen[][col],int sen_len){int i,j;for(i=0;i<sen_len;i++){for(j=4;sen[i][j]!='\0';j++)//gfhgfhggggggggggggggggggggggggggggggggg ggggggggggggggggggg{if(TerminalJud(sen[i][j-1])==false&&TerminalJud(sen[i][j])==false){cout<<"输入的不是算符文法!"<<endl;return false;}}}return true;}//开始分析输入串void InputAnalyse(char opTable[][col],char string[col],intopTable_len) //opTable_len是opTable表的长度{char a,Q,S[SIZE]={'\0'}; //S是分析栈char cho1,cho2;int i,j,relation;int k=0;S[k]='#';cho2='y';cout<<"\t\t\t\t分析过程如下:"<<endl;cout<<"-----------------------------------------------------------------------------"<<endl;//cout<<" 栈\t当前字符\t优先关系\t移进或规约"<<endl;//cout<<"分析过程如下:"<<endl;cout.width(10);cout<<"栈";cout.width(15);cout<<"当前字符";cout.width(20);cout<<"剩余符号串";cout.width(15);cout<<"优先关系";cout.width(15);cout<<"移进或规约"<<endl;char* p;p=string;p++;for(i=0;string[i]!='\0'&&cho2=='y';i++,p++){a=string[i]; //读入当前字符cho1='n'; //可否接受while(cho1=='n'){if(TerminalJud(S[k])==true) j=k; //规约使栈内有非终结符else j=k-1;relation=RelationshipJud(S[j],a,opTable,opTable_len);if(relation==3) //S[j]>a{//cout<<" "<<S<<"\t"<<" "<<a<<"\t\t >\t\t";cout.setf(ios::left);cout.width(10);cout<<S;cout.unsetf(ios::left);cout.width(15);cout<<a;cout.width(20);cout<<p;cout.width(15);cout<<">";do{Q=S[j];if(TerminalJud(S[j-1])==true) j=j-1;else j=j-2;}while(RelationshipJud(S[j],Q,opTable,opTable_len)!=1);//cout<<" "<<S[j]<<"归约"<<endl;cout.width(11);cout<<S[j];cout.width(4);cout<<"归约"<<endl;k=j+1;S[k]='N';for(int l=k+1;l<SIZE;l++){S[l]='\0';}}else if(relation==1) //S[j]<a{cho1='y';//cout<<" "<<S<<"\t"<<" "<<a<<"\t\t <\t\t 移进"<<endl;cout.setf(ios::left);cout.width(10);cout<<S;cout.unsetf(ios::left);cout.width(15);cout<<a;cout.width(20);cout<<p;cout.width(15);cout<<"<";cout.width(15);cout<<"移进"<<endl;k=k+1;S[k]=a;}else if(relation==2) //S[j]=a{cho1='y';//cout<<" "<<S<<"\t"<<" "<<a<<"\t\t =\t\t";cout.setf(ios::left);cout.width(10);cout<<S;cout.unsetf(ios::left);cout.width(15);cout<<a;cout.width(20);cout<<p;cout.width(15);cout<<"=";cout.width(15);if(RelationshipJud(S[j],'#',opTable,opTable_len)==2) {cout<<" 接受"<<endl;break;}else{cout<<" 移进"<<endl;k=k+1;S[k]=a;}}else{cho1='y';//cout<<" "<<S<<"\t"<<a<<"\t\t出错"<<endl;cout<<S<<" "<<a<<" 出错"<<endl;cout<<"对不起!字符串有错!"<<endl;cho2='n';break;}}//while}//for}//int main(){char choice='y';while(choice=='y'){system("cls");charsen[row][col]={'\0'},first[row][col]={'\0'},last[row][col]={'\0'},opTable[row ][col]={'\0'};char string[col];int i,k,p,q;p=readfile(sen);if(PrioGramJud(sen,p)==true){ItemInit(sen,first,last,p,q); //j记录FIRSTVT和LASTVT表的长度FirstVt(sen,first,p,q);cout<<"\t\t各非终结符FIRSTVT集"<<endl;cout<<"------------------------------------------------"<<endl;for(i=0;i<p;i++){for(int h=0;h<col;h++)cout<<first[i][h]<<" ";cout<<endl;}// cout<<endl;LastVt(sen,last,p,q);cout<<"\t\t各非终结符LASTVT集"<<endl;cout<<"-------------------------------------------------"<<endl;for(i=0;i<p;i++){for(int h=0;h<col;h++)cout<<last[i][h]<<" ";cout<<endl;}// cout<<endl;int flag=0 ,j;if(OpPriotable(sen,first,last,opTable,p,q,k)==true) //k记录opTable表的长度{for(i=1;i<=k;i++){flag=0;for(j=0;j<p;j++){for(int h=0;h<col;h++){if(last[j][h]==opTable[i][0]){opTable[i][k]='>';flag=1;break;}}if(flag=1) break;}}for(i=1;i<=k;i++){flag=0;for(j=0;j<p;j++){for(int h=0;h<=col;h++){if(first[j][h]==opTable[0][i]){opTable[k][i]='<';flag=1;break;}}if(flag=1) break;}}opTable[k][k]='=';cout<<"\t\t优先关系表:"<<endl;cout<<"----------------------------------------------"<<endl;for(i=0;i<=k;i++){for(int h=0;h<=k;h++)cout<<opTable[i][h]<<" ";cout<<endl;}// cout<<endl;cout<<"请输入要分析的串,以$结束:"<<endl;cin>>string;InputAnalyse(opTable,string,k); //k是opTable表的长度}}cout<<"是否继续?y/n"<<endl;cin>>choice;}system("pause");}。