编译原理实验三-自下而上语法分析及语义分析.docx
编译原理 - 自下而上的语法分析
*
S A
且
A
则称是句型相对于非终结符A的短语。 特别是,如果有A,则称是句型
相对于规则A的直接短语 一个句型的最左直接短语称为该句型
的句柄
5.1.7 规范归约例一
▪ 例:文法G[E]:
E→E+T|T
T→T*F|F F→(E)|–F|id
考虑文法G[E]上的句子id1+id2*id3 ➢ 其最右推导和分析树如图5.1(a)、(b)所示
第五章 语法分析—自下而上分析
内容
▪ 自下而上分析基本问题 ▪ 算符优先分析
5.1 自下而上分析基本问题
▪ 自下而上分析基本问题
➢ 归约 ➢ 规范归约 ➢ 符号栈的使用 ➢ 语法树的表示
▪ 算符优先分析
5.1.1 自下而上分析
▪ 自下而上分析
abbcde aAbcde (A b)
➢ 从输入字符的角度而言 aAcde (A Ab)
➢ 最左归约
规范推导
▪ 由规范推导推出的句型称为规范句型。
▪ 规范归约的中心问题:确定句型的句柄。
5.1.2 规范归约简述
▪ 最右推导,推导的每一步结果都是一个右句 型。该推导即分析树 “剪句柄”的全过程。
S
S
S
S
S
a A B ea A B ea A B ea A B e
Ab c d
Ab c d
d
图5.1 id1+id2*id3的最右推导、分析树与短语 (a) 最右推导;(b) 分析树;(c) 短语
5.1.7.1 归约的分析树
▪ 分析树的叶子与短语、直接短语和句柄有下述关系 ➢ 短语 以非终结符为根的子树中所有从左到右排列的 叶子 ➢ 直接短语 只有父子关系的树中所有从左到右排列的叶子 树高为2 ➢ 句柄 最左边父子关系树中所有从左到右排列的叶子 句柄是唯一的
编译原理语义分析实验报告
实验3 语义分析实验报告一、实验目的二、通过上机实习, 加深对语法制导翻译原理的理解, 掌握将语法分析所识别的语法成分变换为中间代码的语义翻译方法。
三、实验要求四、采用递归下降语法制导翻译法, 对算术表达式、赋值语句进行语义分析并生成四元式序列。
五、算法思想1.设置语义过程。
(1)emit(char *result,char *ag1,char *op,char *ag2)该函数的功能是生成一个三地址语句送到四元式表中。
四元式表的结构如下:struct{ char result[8];char ag1[8];char op[8];char ag2[8];}quad[20];(2) char *newtemp()该函数回送一个新的临时变量名, 临时变量名产生的顺序为T1, T2, …char *newtemp(void){ char *p;char m[8];p=(char *)malloc(8);k++;itoa(k,m,10);strcpy(p+1,m);p[0]=’t’;return(p);}六、 2.函数lrparser 在原来语法分析的基础上插入相应的语义动作: 将输入串翻译成四元式序列。
在实验中我们只对表达式、赋值语句进行翻译。
源程序代码:#include<stdio.h>#include<string.h>#include<iostream.h>#include<stdlib.h>struct{char result[12];char ag1[12];char op[12];char ag2[12];}quad;char prog[80],token[12];char ch;int syn,p,m=0,n,sum=0,kk; //p是缓冲区prog的指针, m是token的指针char *rwtab[6]={"begin","if","then","while","do","end"};void scaner();char *factor(void);char *term(void);char *expression(void);int yucu();void emit(char *result,char *ag1,char *op,char *ag2);char *newtemp();int statement();int k=0;void emit(char *result,char *ag1,char *op,char *ag2){strcpy(quad.result,result);strcpy(quad.ag1,ag1);strcpy(quad.op,op);strcpy(quad.ag2,ag2);cout<<quad.result<<"="<<quad.ag1<<quad.op<<quad.ag2<<endl;}char *newtemp(){char *p;char m[12];p=(char *)malloc(12);k++;itoa(k,m,10);strcpy(p+1,m);p[0]='t';return (p);}void scaner(){for(n=0;n<8;n++) token[n]=NULL;ch=prog[p++];while(ch==' '){ch=prog[p];p++;}if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')){m=0;while((ch>='0'&&ch<='9')||(ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')){token[m++]=ch;ch=prog[p++];}token[m++]='\0';p--;syn=10;for(n=0;n<6;n++)if(strcmp(token,rwtab[n])==0){syn=n+1;break;}}else if((ch>='0'&&ch<='9')){{sum=0;while((ch>='0'&&ch<='9')){sum=sum*10+ch-'0';ch=prog[p++];}}p--;syn=11;if(sum>32767)syn=-1;}else switch(ch){case'<':m=0;token[m++]=ch;ch=prog[p++];if(ch=='>'){syn=21;token[m++]=ch;}else if(ch=='='){syn=22;token[m++]=ch;}else{syn=23;p--;}break;case'>':m=0;token[m++]=ch;ch=prog[p++];if(ch=='='){syn=24;token[m++]=ch;}else{syn=20;p--;}break;case':':m=0;token[m++]=ch;ch=prog[p++];if(ch=='='){syn=18;token[m++]=ch;}else{syn=17;p--;}break;case'*':syn=13;token[0]=ch;break; case'/':syn=14;token[0]=ch;break; case'+':syn=15;token[0]=ch;break; case'-':syn=16;token[0]=ch;break; case'=':syn=25;token[0]=ch;break; case';':syn=26;token[0]=ch;break; case'(':syn=27;token[0]=ch;break; case')':syn=28;token[0]=ch;break; case'#':syn=0;token[0]=ch;break; default: syn=-1;break;}}int lrparser(){//cout<<"调用lrparser"<<endl;int schain=0;kk=0;if(syn==1){scaner();schain=yucu();if(syn==6){scaner();if(syn==0 && (kk==0))cout<<"success!"<<endl;}else{if(kk!=1)cout<<"缺end!"<<endl;kk=1;}}else{cout<<"缺begin!"<<endl;kk=1;}return(schain);}int yucu(){// cout<<"调用yucu"<<endl;int schain=0;schain=statement();while(syn==26){scaner();schain=statement();}return(schain);}int statement(){//cout<<"调用statement"<<endl;char *eplace,*tt;eplace=(char *)malloc(12);tt=(char *)malloc(12);int schain=0;switch(syn){case 10:strcpy(tt,token);scaner();if(syn==18){scaner();strcpy(eplace,expression());emit(tt,eplace,"","");schain=0;}else{cout<<"缺少赋值符!"<<endl;kk=1;}return(schain);break;}return(schain);}char *expression(void){char *tp,*ep2,*eplace,*tt;tp=(char *)malloc(12);ep2=(char *)malloc(12);eplace=(char *)malloc(12);tt =(char *)malloc(12);strcpy(eplace,term ()); //调用term分析产生表达式计算的第一项eplacewhile((syn==15)||(syn==16)){if(syn==15)strcpy(tt,"+");else strcpy(tt,"-");scaner();strcpy(ep2,term()); //调用term分析产生表达式计算的第二项ep2strcpy(tp,newtemp()); //调用newtemp产生临时变量tp存储计算结果emit(tp,eplace,tt,ep2); //生成四元式送入四元式表strcpy(eplace,tp);}return(eplace);}char *term(void){// cout<<"调用term"<<endl;char *tp,*ep2,*eplace,*tt;tp=(char *)malloc(12);ep2=(char *)malloc(12);eplace=(char *)malloc(12);tt=(char *)malloc(12);strcpy(eplace,factor());while((syn==13)||(syn==14)){if(syn==13)strcpy(tt,"*");else strcpy(tt,"/");scaner();strcpy(ep2,factor()); //调用factor分析产生表达式计算的第二项ep2strcpy(tp,newtemp()); //调用newtemp产生临时变量tp存储计算结果emit(tp,eplace,tt,ep2); //生成四元式送入四元式表strcpy(eplace,tp);}return(eplace);}char *factor(void){char *fplace;fplace=(char *)malloc(12);strcpy(fplace,"");if(syn==10){strcpy(fplace,token); //将标识符token的值赋给fplacescaner();}else if(syn==11){itoa(sum,fplace,10);scaner();}else if(syn==27){scaner();fplace=expression(); //调用expression分析返回表达式的值if(syn==28)scaner();else{cout<<"缺)错误!"<<endl;kk=1;}}else{cout<<"缺(错误!"<<endl;kk=1;}return(fplace);}void main(){p=0;cout<<"**********语义分析程序**********"<<endl;cout<<"Please input string:"<<endl;do{cin.get(ch);prog[p++]=ch;}while(ch!='#');p=0;scaner();lrparser();}七、结果验证1、给定源程序begin a:=2+3*4; x:=(a+b)/c end#输出结果2、源程序begin a:=9; x:=2*3-1; b:=(a+x)/2 end#输出结果八、收获(体会)与建议通过此次实验, 让我了解到如何设计、编制并调试语义分析程序, 加深了对语法制导翻译原理的理解, 掌握了将语法分析所识别的语法成分变换为中间代码的语义翻译方法。
编译原理实验三-自下而上语法分析及语义分析.docx
上海电力学院编译原理课程实验报告实验名称:实验三自下而上语法分析及语义分析院系:计算机科学与技术学院专业年级:学生姓名:学号:指导老师:实验日期:实验三自上而下的语法分析一、实验目的:通过本实验掌握LR分析器的构造过程,并根据语法制导翻译,掌握属性文法的自下而上计算的过程。
二、实验学时:4学时。
三、实验内容根据给出的简单表达式的语法构成规则(见五),编制LR分析程序,要求能对用给定的语法规则书写的源程序进行语法分析和语义分析。
对于正确的表达式,给出表达式的值。
对于错误的表达式,给出出错位置。
四、实验方法采用LR分析法。
首先给出S-属性文法的定义(为简便起见,每个文法符号只设置一个综合属性,即该文法符号所代表的表达式的值。
属性文法的定义可参照书137页表6.1),并将其改造成用LR分析实现时的语义分析动作(可参照书145页表6.5)。
接下来给出LR分析表。
然后程序的具体实现:● LR分析表可用二维数组(或其他)实现。
●添加一个val栈作为语义分析实现的工具。
编写总控程序,实现语法分析和语义分析的过程。
注:对于整数的识别可以借助实验1。
五、文法定义简单的表达式文法如下:(1)E->E+T(2)E->E-T(3)E->T(4)T->T*F(5)T->T/F(6)T->F(7)F->(E)(8)F->i状态ACTION(动作)GOTO(转换)i + - * / ( ) # E T F0 S5 S4 1 2 31 S6 S12 acc2 R3 R3 S7 S13 R3 R33 R6 R6 R6 R6 R6 R64 S5 S4 8 2 35 R8 R8 R8 R8 R8 R86 S5 S4 9 37 S5 S4 108 S6 R12 S119 R1 R1 S7 S13 R1 R110 R4 R4 R4 R4 R4 R411 R7 R7 R7 R7 R7 R712 S5 S4 14 313 S5 S4 1514 R2 R2 S7 S13 R2 R215 R5 R5 R5 R5 R5 R5五、处理程序例和处理结果例示例1:20133191*(20133191+3191)+ 3191#六、源代码【cifa.h】//cifa.h#include<string>using namespace std;//单词结构定义struct WordType{int code;string pro;};//函数声明WordType get_w();void getch();void getBC();bool isLetter();bool isDigit();void retract();int Reserve(string str);string concat(string str);【Table.action.h】//table_action.hclass Table_action{int row_num,line_num;int lineName[8];string tableData[16][8];public:Table_action(){row_num=16;line_num=8;lineName[0]=30;lineName[1]=7;lineName[2]=13;lineName[3]=8;lineName[4]=14;lineName[5]=1;lineName[6]=2;lineName[7]=15;lineName[8]=0;for(int m=0;m<row_num;m++)for(int n=0;n<line_num;n++)tableData[m][n]="";tableData[0][0]="S5";tableData[0][5]="S4";tableData[1][1]="S6";tableData[1][2]="S12";tableData[1][7]="acc";tableData[2][1]="R3";tableData[2][2]="R3";tableData[2][3]="S7";tableData[2][4]="S13";tableData[2][6]="R3";tableData[2][7]="R3";tableData[3][1]="R6";tableData[3][3]="R6"; tableData[3][4]="R6"; tableData[3][6]="R6"; tableData[3][7]="R6"; tableData[4][0]="S5"; tableData[4][5]="S4"; tableData[5][1]="R8"; tableData[5][2]="R8"; tableData[5][3]="R8"; tableData[5][4]="R8"; tableData[5][6]="R8"; tableData[5][7]="R8"; tableData[6][0]="S5"; tableData[6][5]="S4"; tableData[7][0]="S5"; tableData[7][5]="S4"; tableData[8][1]="S6"; tableData[8][2]="S12"; tableData[8][6]="S11"; tableData[9][1]="R1"; tableData[9][2]="R1"; tableData[9][3]="S7"; tableData[9][4]="S13"; tableData[9][6]="R1"; tableData[9][7]="R1"; tableData[10][1]="R4"; tableData[10][2]="R4"; tableData[10][3]="R4"; tableData[10][4]="R4"; tableData[10][6]="R4"; tableData[10][7]="R4"; tableData[11][1]="R7"; tableData[11][2]="R7"; tableData[11][3]="R7"; tableData[11][4]="R7"; tableData[11][6]="R7"; tableData[11][7]="R7"; tableData[12][0]="S5"; tableData[12][5]="S4"; tableData[13][0]="S5"; tableData[13][5]="S4"; tableData[14][1]="R2"; tableData[14][2]="R2";tableData[14][4]="S13";tableData[14][6]="R2";tableData[14][7]="R2";tableData[15][1]="R5";tableData[15][2]="R5";tableData[15][3]="R5";tableData[15][4]="R5";tableData[15][5]="R5";tableData[15][6]="R5";tableData[15][7]="R5";}string getCell(int rowN,int lineN){int row=rowN;int line=getLineNumber(lineN);if(row>=0&&row<row_num&&line>=0&&line<=line_num) return tableData[row][line];elsereturn"";}int getLineNumber(int lineN){for(int i=0;i<line_num;i++)if(lineName[i]==lineN)return i;return -1;}};【Table_go.h】//table_go.hclass Table_go{int row_num,line_num;//行数、列数string lineName[3];int tableData[16][3];public:Table_go(){row_num=16;line_num=3;lineName[0]="E";lineName[1]="T";lineName[2]="F";for(int m=0;m<row_num;m++)for(int n=0;n<line_num;n++)tableData[m][n]=0;tableData[0][0]=1;tableData[0][1]=2;tableData[0][2]=3;tableData[4][0]=8;tableData[4][1]=2;tableData[4][2]=3;tableData[6][1]=9;tableData[6][2]=3;tableData[7][2]=10;tableData[12][1]=14;tableData[12][2]=3;tableData[13][2]=15;}int getCell(int rowN,string lineNa){int row=rowN;int line=getLineNumber(lineNa);if(row>=0&&row<row_num&&line<=line_num) return tableData[row][line];elsereturn -1;}int getLineNumber(string lineNa){for(int i=0;i<line_num;i++)if(lineName[i]==lineNa)return i;return -1;}};【Stack_num.h】class Stack_num{int i; //栈顶标记int *data; //栈结构public:Stack_num() //构造函数{data=new int[100];i=-1;}int push(int m) //进栈操作{i++;data[i]=m;return i;}int pop() //出栈操作{i--;return data[i+1];}int getTop() //返回栈顶{return data[i];}~Stack_num() //析构函数{delete []data;}int topNumber(){return i;}void outStack(){for(int m=0;m<=i;m++)cout<<data[m];}};【Stack_str.h】class Stack_str{int i; //栈顶标记string *data; //栈结构public:Stack_str() //构造函数{data=new string[50];i=-1;}int push(string m) //进栈操作{i++;data[i]=m;return i;}int pop() //出栈操作{data[i]="";i--;return i;}string getTop() //返回栈顶{return data[i];}~Stack_str() //析构函数{delete []data;}int topNumber(){return i;}void outStack(){for(int m=0;m<=i;m++)cout<<data[m];}};【cifa.cpp】//cifa.cpp#include<iostream>#include<string>#include"cifa.h"using namespace std;//关键字表和对应的编码string codestring[10]={"main","int","if","then","else","return","void","cout","endl"}; int codebook[10]={26,21,22,23,24,25,27,28,29};//全局变量char ch;int flag=0;/*//主函数int main(){WordType word;cout<<"请输入源程序序列:";word=get_w();while(word.pro!="#")//#为自己设置的结束标志{cout<<"("<<word.code<<","<<"“"<<word.pro<<"”"<<")"<<endl;word=get_w();};return 0;}*/WordType get_w(){string str="";int code;WordType wordtmp;getch();//读一个字符getBC();//去掉空白符if(isLetter()){ //以字母开头while(isLetter()||isDigit()){str=concat(str);getch();}retract();code=Reserve(str);if(code==-1){wordtmp.code=0;wordtmp.pro=str;}//不是关键字else{wordtmp.code=code;wordtmp.pro=str;}//是关键字}else if(isDigit()){ //以数字开头while(isDigit()){str=concat(str);getch();}retract();wordtmp.code=30;wordtmp.pro=str;}else if(ch=='(') {wordtmp.code=1;wordtmp.pro="(";}else if(ch==')') {wordtmp.code=2;wordtmp.pro=")";}else if(ch=='{') {wordtmp.code=3;wordtmp.pro="{";}else if(ch=='}') {wordtmp.code=4;wordtmp.pro="}";}else if(ch==';') {wordtmp.code=5;wordtmp.pro=";";}else if(ch=='=') {wordtmp.code=6;wordtmp.pro="=";}else if(ch=='+') {wordtmp.code=7;wordtmp.pro="+";}else if(ch=='*') {wordtmp.code=8;wordtmp.pro="*";}else if(ch=='>') {wordtmp.code=9;wordtmp.pro=">";}else if(ch=='<') {wordtmp.code=10;wordtmp.pro="<";}else if(ch==',') {wordtmp.code=11;wordtmp.pro=",";}else if(ch=='\'') {wordtmp.code=12;wordtmp.pro="\'";}else if(ch=='-') {wordtmp.code=13;wordtmp.pro="-";}else if(ch=='/') {wordtmp.code=14;wordtmp.pro="/";}else if(ch=='#') {wordtmp.code=15;wordtmp.pro="#";}else if(ch=='|') {wordtmp.code=16;wordtmp.pro="|";}else {wordtmp.code=100;wordtmp.pro=ch;} return wordtmp;}void getch(){if(flag==0) //没有回退的字符ch=getchar();else //有回退字符,用回退字符,并设置标志flag=0;}void getBC(){while(ch==' '||ch=='\t'||ch=='\n')ch=getchar();}bool isLetter(){if(ch>='a'&&ch<='z'||ch>='A'&&ch<='Z')return true;elsereturn false;}bool isDigit(){if(ch>='0'&&ch<='9')return true;elsereturn false;}string concat(string str){return str+ch;}void retract(){flag=1;}int Reserve(string str){int i;for(i=0;i<=8;i++){if(codestring[i]==str) //是某个关键字,返回对应的编码return codebook[i];}if(i==9) //不是关键字return -1;}【LR.cpp】#include<iostream>#include<string>#include<cstdlib>#include"cifa.h"#include"stack_num.h"#include"stack_str.h"#include"table_action.h"#include"table_go.h"using namespace std;void process(){int stepNum=1;int topStat;Stack_num statusSTK; //状态栈Stack_str symbolSTK; //符号栈Stack_num valueSTK; //值栈WordType word;Table_action actionTAB; //行为表Table_go goTAB; //转向表cout<<"请输入源程序,以#结束:";word=get_w();//总控程序初始化操作symbolSTK.push("#");statusSTK.push(0);valueSTK.push(0);cout<<"步骤\t状态栈\t符号栈\t值栈\t当前词\t动作\t转向"<<endl;//分析while(1){topStat=statusSTK.getTop(); //当前状态栈顶string act=actionTAB.getCell(topStat,word.code);//根据状态栈顶和当前单词查到的动作//输出cout<<stepNum++<<"\t";statusSTK.outStack(); cout<<"\t";symbolSTK.outStack(); cout<<"\t";valueSTK.outStack(); cout<<"\t";cout<<word.pro<<"\t";//行为为“acc”,且当前处理的单词为#,且状态栈里就两个状态//说明正常分析结束if(act=="acc"&&word.pro=="#"&&statusSTK.topNumber()==1){cout<<act<<endl;cout<<"分析成功!"<<endl;cout<<"结果为:"<<valueSTK.getTop()<<endl;return;}//读到act表里标记为错误的单元格else if(act==""){cout<<endl<<"不是文法的句子!"<<endl;cout<<"错误的位置为单词"<<word.pro<<"附近。
编译原理实验报告语义分析
编译原理实验报告语义分析实验名称:语义分析实验目的:1.掌握词法分析器生成的词法单元序列的构造;2.学会设计语法分析器,实现对程序的基本语法结构检查,并生成抽象语法树;3.学习语义规约的实现,实现对程序的语义分析和错误检查;4.熟悉语义分析向语法分析的接口。
实验原理:语义分析是编译过程的一个重要环节,它的主要任务是对生成的抽象语法树进行遍历,并验证程序的类型一致性、语义规则的正确性、错误的检查和恢复等。
语义分析的输入是由语法分析生成的抽象语法树,输出是继续优化的抽象语法树或中间代码,以供后续的中间代码生成等工作使用。
实验步骤:1.设计语法分析器,包括语法规则、优先级关系等;2.生成词法单元序列;3.构建语法分析器,进行语法分析,并生成抽象语法树;4.针对不同的语义规约,设计语义动作,实现对程序的语义分析和错误检查;5.完成语义分析器的构建和测试。
实验设备:1.计算机;2. 编程语言:C++/Java/Python等;3. 开发环境:Visual Studio/ Eclipse/PyCharm等。
实验结果:通过对语法分析生成的抽象语法树进行遍历,实现了对程序的语义分析和错误检查。
具体实现包括:1.类型检查:根据语义规约,对程序中的类型进行检查,包括变量的声明及使用、函数的调用、赋值语句的一致性等;2.作用域检查:检查变量的作用域和可见性等;3.错误检查:检测语义错误,如变量未声明、函数重复定义等;4.错误恢复:当检测到错误时,采取适当的错误恢复措施,如跳过错误的部分继续分析、提示错误信息等。
实验心得:本次实验主要学习了语义分析的原理和实现方法,深入了解了编译过程中各个环节的作用和关系。
通过实践操作,加深了对语法分析和语义分析的理解,提高了编程能力和解决问题的能力。
同时,实验过程中也遇到了一些挑战和困难,例如语义规约的设计和实现、错误检查和恢复等,但通过查阅资料和与同学讨论,最终解决了这些问题。
通过本次实验,我对编译原理和语义分析有了更深入的了解,并且对以后的学习和工作有了更好的准备。
编译原理实验报告-语义分析
编译原理课程实验报告实验3:语义分析图2-1本程序根据之前两个实验的结果进一步进行语义分析,主要是通过在第二个实验句法分析过程中添加语义分析功能完成的。
在代码编写之前,我将程序的功能模块分为界面及主控程序,实体类和工具类三大部分。
MyCompiler是整个程序运行的入口,是主控程序;ComplierFrame完成程序的界面,以及界面里事件的响应;Token是词法分析中词法单元的实体类;ErrorToken是错误的词法单元实体类;Symbol是句法分析中符号的实体类;Production是产生式的实体类;ErrorProduction是句法分析中产生错误的时候使用的产生式实体类;Id是标示符实体类,保存了语义分析后的标识符表;Node是语法分析树的节点类,帮助完成语法分析树的构造;LL类使用LL(1)分析法完成句法分析,同时完成语义分析;MyScanner完成了词法分析。
图2-2三、详细设计及实现得分要求:对如下工作进行展开描述(1)核心数据结构的设计本程序使用了两个新的实体类,分别是Id和Node。
Id是标识符,里面也包含了该标识符在本程序中存储的地址和长度等信息。
Id的属性如下:private String name; //名private String type;//基本类型private int offset;//起始地址private int length;//长度开始输入词法分析读入Token尝试匹配是否错误存储错误记录,处理栈顶与Token 序列是否为语义符号存储产生式,处理栈顶与Token 序列判断动作符号执行语义动作是否读到Token末尾打印结果结束分析结果以及错误报告:图4-1 标识符表:图4-2。
编译原理自上而下语法分析
1.课程设计目的:1.1 设计目的:通过编程实现语法分析(自上而下,自下而上)的可视化过程,加深对两法分析原理思想的理解。
[目的要求]通过设计编制调试一个具体的语法分析程序,加深对语法分析原理的理解。
并掌握在对程序设计语言源程序进行扫描过程中将其进行语法分析的方法。
[题目分析]递归下降分析方法是一种确定的自上而下分析方法。
它的基本思想是给文法的每一个非终结符均设计一个相应的子程序。
由于文法的产生式往往是递归的,因为这些子程序往往也是递归的。
1.2 开发环境:操作系统:Windows XP辅助工具:Visual Studio 2008编程语言:C#2. 课程设计要求(1)选定一文法,选定一种分析方法(自上而下、自下而上)(2)允许用户输入语句并对该语句进行相应的语法分析(3)要求显示语法树的建立过程以及跟踪分析表和分析栈的状态(4)要提供单步运行,让用户跟踪分析器工作的每一个步骤。
3. 总体设计3.1 设计框架:3.2 程序流程图:4. 设计功能描述:(1)该课程设计对语法分析指定了固定的文法,运行界面为:“开始”,会出现提示:。
(3)用户输入字符串,可以点击“”,软件根据该输入字符串做好初始化工作,再点击“”,开始分析,每一次点击“下一次”,就做分析的一个步骤,并且此时分析栈和输入栈做相应的出栈、入栈的的动作,同时在“分析栈”,“输入栈”,“输出栈”会显示出相应的状态。
(4)分析结果显示在中(5)如果在分析完后,还需要继续输入字符串分析的画,点击“”,可以再次作上述的操作。
(6)如果想退出程序,点击““,此时会弹出提示窗口:,点击“确定”,便退出程序。
分析实例:输入分析的字符串为i*(i+i)结果如下:5. 源程序代码:#region相关初始量(都是全局的)public string[] mystring = { "TC", "FALSE", "FALSE", "TC", "FALSE", "FALSE", "FALSE", "+TC", "FALSE", "FALSE", "ε", "ε", "FD", "FALSE", "FALSE", "FD", "FALSE", "FALSE", "FALSE", "ε", "*FD", "FALSE", "ε", "ε", "i", "FALSE", "FALSE", "(E)", "FALSE", "FALSE" };//分析表数组bool con = true;//控制显示的布尔量private Stack MyStack = new Stack(); //申请一个分析栈private Stack MyInputstack = new Stack();//申请一个输入栈public string[] Term = { "i", "+", "*", "(", ")", "&" }; //终结符数组public string[] unTerm = { "E", "C", "T", "D", "F" };//非终结符数组private int line, row; //定义行,列的全局变量string MyNowString;#endregion“开始”按钮实现的函数private void开始_Click(object sender, EventArgs e){if (Input_richTextBox1.Text == ""){MessageBox.Show("请输入要分析的字符串!");}else{this.MyOutput_listBox3.Items.Add("");MyStack.Push("&");MyStack.Push("E");MyStack_listBox1.Items.Add("&E");MyInput_listBox2.Items.Add(Input_richTextBox1.Text + "&");MyInputstack.Push("&");for (int i = Input_richTextBox1.Text.Length - 1; i >= 0; i--){MyInputstack.Push(Input_richTextBox1.Text[i]);}begin.Enabled = false;}}#region“下一步”按钮实现的函数private void下一步_Click(object sender, EventArgs e){int loc;string MyStackTop, MyStackInputTop;MyStackTop = MyStack.Peek().ToString();MyStackInputTop = MyInputstack.Peek().ToString();MyStackTopOne(MyStackTop);if (MyStackTopOne(MyStackTop)){MyStackTopTwo(MyStackTop, MyStackInputTop);}else if (MyStackTopThree(MyStackTop) &&MyInputStackTopOne(MyStackInputTop)){loc = line * 6 + row;MyNowString = mystring[loc];this.MyOutput_listBox3.Items.Add(MyStack.Peek().ToString() + "-->" + mystring[loc]);Analyse();}else{Rezult_richTextBox2.Text = "分析出错!";nextStep.Enabled = false;con = false;}if (con){ShowMyStack();ShowMyInpuStack();}}#endregion#region显示分析栈里的字符private void ShowMyStack(){string ch = "";int len = MyStack.Count;string display = "";for (int i = 0; i < len; i++){string t;t = MyStack.Pop().ToString();display = display + t;}for (int i = len - 1; i >= 0; i--){ch = ch + display[i];MyStack.Push(display[i]);this.MyStack_listBox1.Items.Add(ch);}#endregion#region显示输入栈里的字符private void ShowMyInpuStack(){int len = MyInputstack.Count;string display = "";for (int i = 0; i < len; i++){string t;t = MyInputstack.Pop().ToString();display = display + t;}for (int i = len - 1; i >= 0; i--){MyInputstack.Push(display[i]);}this.MyInput_listBox2.Items.Add(display);}#endregion#region判断状态栈栈顶元素是否为终结符public bool MyStackTopOne(string stack){bool symbol = false;for (int i = 0; i < Term.Length; i++){if (stack == Term[i]){symbol = true;break;}}return symbol;}#endregion#region状态栈栈顶元素是终结符的处理方法private void MyStackTopTwo(string stack, string input) {if (stack == input)if (stack == "&"){Rezult_richTextBox2.Text = "分析成功!"; nextStep.Enabled = false;con = false;}else{MyStack.Pop();MyInputstack.Pop();this.MyOutput_listBox3.Items.Add(""); }}}#endregion#region返回状态栈栈顶元素在非终结符数组里的下标public bool MyStackTopThree(string stack){bool symbol = false;for (int i = 0; i < unTerm.Length; i++){if (unTerm[i] == stack){line = i;symbol = true;break;}}return symbol;}#endregion#region返回输入栈栈顶元素在终结符数组里的下标private bool MyInputStackTopOne(string myinput){bool symbol = false;for (int i = 0; i < Term.Length; i++){if (Term[i] == myinput){row = i;symbol = true;break;}return symbol;}#endregion#region分析表字符入栈private void Analyse(){if (MyNowString == "FALSE"){Rezult_richTextBox2.Text = "分析出错!";nextStep.Enabled = false;con = false;}else if (MyNowString == "ε"){MyStack.Pop();}else{MyStack.Pop();for (int i = MyNowString.Length - 1; i >= 0; i--) {MyStack.Push(MyNowString[i]);}}}#endregion#region“退出”按钮实现的函数private void exit_button2_Click(object sender, EventArgs e) {DialogResult ret;ret = MessageBox.Show("确定要退出吗?","退出",MessageBoxButtons.OKCancel,MessageBoxIcon.Question,MessageBoxDefaultButton.Button2);if (ret == DialogResult.OK){this.Close();}}#endregion#region“重置”按钮实现的功能private void clear_Button_Click(object sender, EventArgs e){Input_richTextBox1.Clear();Rezult_richTextBox2.Clear();this.MyStack_listBox1.Items.Clear();this.MyInput_listBox2.Items.Clear();this.MyOutput_listBox3.Items.Clear();MyStack.Clear();MyInputstack.Clear();begin.Enabled = true;nextStep.Enabled = true;con = true;}#endregionprivate void button1_Click(object sender, EventArgs e){pictureBox1.Visible = true;}}6. 总结:通过本次课程设计,对于语法分析的原理与方法有了进一步的体会,在通过使用visual studio 2008的同时让我们对c#和语法分析有了更深的理解。
编译原理第三版 第五章 自下而上语法分析
a
b a
A a
b A A a a
c A a
d c A a
e B B c c A A a a
S
(2) 分析树: 用树表示“移进 - 归约 ”过程
A A B S
b
A
b
b
d
a
A
直接短语
T i F
句柄
T
T * F F ( E ) i
E + T T F
规范归约
设α是文法G的一个句子, 若序列αn, αn-1, …, α0,满足: (1)αn = α; (2) α0 = S; (3)对任 意i , 0< i ≤n , αi-1 是从αi 将句柄替换成 相应产生左部符号而得到的;则称该序列是一个 规范归约。
1、归约与分析树
(1)移进-归约法: 使用符号栈, 把输入符号逐一移 进栈, 栈顶出现某个产生式右部时归约为左部。
例 :给定文法 G: (1) S→aAcBe (2) A→b (3) A→Ab (4) B→d 输入串 abbcde是否为句子? 归约过程如下: 步骤: 1. 2. 进 进 动作: a b
例:文法G: G[E]: E→E+E|E*E |(E) |i (1) E→E+T│T (2) T→T*F│F (3) F→P↑F│P (4) P→(E)│i 算符优先关系为: 由(4): P→(E) ∴( =) 由(1) (2): E→E+T, T => T*F ∴+<* 由(2) (3): T→T*F, F => P↑F ∴ *<↑ 由(1): E→E+T, E => E+T ∴ +>+ 由(3): F→P↑F, F=> P↑F ∴ ↑ <↑ 由(4): P→(E), E => E+T ∴ ( < +, +>) ... ∴ G为算符优先文法(优先关系表如表5.1所示,P90) #看作终结符号
编译原理实验三-自下而上语法分析报告及语义分析报告.docx
上海电力学院编译原理课程实验报告实验名称:实验三自下而上语法分析及语义分析院系:计算机科学与技术学院专业年级:学生姓名:学号:指导老师:实验日期:实验三自上而下的语法分析一、实验目的:通过本实验掌握LR分析器的构造过程,并根据语法制导翻译,掌握属性文法的自下而上计算的过程。
二、实验学时:4学时。
三、实验内容根据给出的简单表达式的语法构成规则(见五),编制LR分析程序,要求能对用给定的语法规则书写的源程序进行语法分析和语义分析。
对于正确的表达式,给出表达式的值。
对于错误的表达式,给出出错位置。
四、实验方法采用LR分析法。
首先给出S-属性文法的定义(为简便起见,每个文法符号只设置一个综合属性,即该文法符号所代表的表达式的值。
属性文法的定义可参照书137页表6.1),并将其改造成用LR分析实现时的语义分析动作(可参照书145页表6.5)。
接下来给出LR分析表。
然后程序的具体实现:●LR分析表可用二维数组(或其他)实现。
●添加一个val栈作为语义分析实现的工具。
●编写总控程序,实现语法分析和语义分析的过程。
注:对于整数的识别可以借助实验1。
五、文法定义简单的表达式文法如下:(1)E->E+T(2)E->E-T(3)E->T(4)T->T*F(5)T->T/F(6)T->F(7)F->(E)(8)F->i五、处理程序例和处理结果例示例1:20133191*(20133191+3191)+ 3191#六、源代码【cifa.h】//cifa.h#include<string> using namespace std;//单词结构定义struct WordType{int code;string pro;};//函数声明WordType get_w();void getch();void getBC();bool isLetter();bool isDigit();void retract();int Reserve(string str); string concat(string str); 【Table.action.h】//table_action.hclass Table_action{int row_num,line_num;int lineName[8];string tableData[16][8]; public:Table_action(){row_num=16;line_num=8;lineName[0]=30;lineName[1]=7;lineName[2]=13;lineName[3]=8;lineName[4]=14;lineName[5]=1;lineName[6]=2;lineName[7]=15;lineName[8]=0;for(int m=0;m<row_num;m++) for(int n=0;n<line_num;n++) tableData[m][n]="";tableData[0][0]="S5";tableData[0][5]="S4";tableData[1][1]="S6";tableData[1][2]="S12";tableData[1][7]="acc";tableData[2][1]="R3";tableData[2][2]="R3";tableData[2][3]="S7";tableData[2][6]="R3"; tableData[2][7]="R3"; tableData[3][1]="R6"; tableData[3][2]="R6"; tableData[3][3]="R6"; tableData[3][4]="R6"; tableData[3][6]="R6"; tableData[3][7]="R6"; tableData[4][0]="S5"; tableData[4][5]="S4"; tableData[5][1]="R8"; tableData[5][2]="R8"; tableData[5][3]="R8"; tableData[5][4]="R8"; tableData[5][6]="R8"; tableData[5][7]="R8"; tableData[6][0]="S5"; tableData[6][5]="S4"; tableData[7][0]="S5"; tableData[7][5]="S4"; tableData[8][1]="S6";tableData[8][6]="S11"; tableData[9][1]="R1"; tableData[9][2]="R1"; tableData[9][3]="S7"; tableData[9][4]="S13"; tableData[9][6]="R1"; tableData[9][7]="R1"; tableData[10][1]="R4"; tableData[10][2]="R4"; tableData[10][3]="R4"; tableData[10][4]="R4"; tableData[10][6]="R4"; tableData[10][7]="R4"; tableData[11][1]="R7"; tableData[11][2]="R7"; tableData[11][3]="R7"; tableData[11][4]="R7"; tableData[11][6]="R7"; tableData[11][7]="R7"; tableData[12][0]="S5"; tableData[12][5]="S4";tableData[13][5]="S4";tableData[14][1]="R2";tableData[14][2]="R2";tableData[14][3]="S7";tableData[14][4]="S13";tableData[14][6]="R2";tableData[14][7]="R2";tableData[15][1]="R5";tableData[15][2]="R5";tableData[15][3]="R5";tableData[15][4]="R5";tableData[15][5]="R5";tableData[15][6]="R5";tableData[15][7]="R5";}string getCell(int rowN,int lineN){int row=rowN;int line=getLineNumber(lineN);if(row>=0&&row<row_num&&line>=0&&line<=line_num) return tableData[row][line];elsereturn"";}int getLineNumber(int lineN){for(int i=0;i<line_num;i++)if(lineName[i]==lineN)return i;return -1;}};【Table_go.h】//table_go.hclass Table_go{int row_num,line_num;//行数、列数string lineName[3];int tableData[16][3];public:Table_go(){row_num=16;line_num=3;lineName[0]="E";lineName[1]="T";lineName[2]="F";for(int m=0;m<row_num;m++) for(int n=0;n<line_num;n++)tableData[m][n]=0;tableData[0][0]=1;tableData[0][1]=2;tableData[0][2]=3;tableData[4][0]=8;tableData[4][1]=2;tableData[4][2]=3;tableData[6][1]=9;tableData[6][2]=3;tableData[7][2]=10;tableData[12][1]=14;tableData[12][2]=3;tableData[13][2]=15;}int getCell(int rowN,string lineNa){int row=rowN;int line=getLineNumber(lineNa);if(row>=0&&row<row_num&&line<=line_num) return tableData[row][line];elsereturn -1;}int getLineNumber(string lineNa){for(int i=0;i<line_num;i++)if(lineName[i]==lineNa)return i;return -1;}};【Stack_num.h】class Stack_num{int i; //栈顶标记int *data; //栈结构public:Stack_num() //构造函数{data=new int[100];i=-1;}int push(int m) //进栈操作{i++;data[i]=m;return i;}int pop() //出栈操作{i--;return data[i+1];}int getTop() //返回栈顶{return data[i];}~Stack_num() //析构函数{delete []data;}int topNumber(){return i;}void outStack(){for(int m=0;m<=i;m++)cout<<data[m];}};【Stack_str.h】class Stack_str{int i; //栈顶标记string *data; //栈结构public:Stack_str() //构造函数{data=new string[50];i=-1;}int push(string m) //进栈操作{i++;data[i]=m;return i;}int pop() //出栈操作{data[i]="";i--;return i;}string getTop() //返回栈顶{return data[i];}~Stack_str() //析构函数{delete []data;int topNumber(){return i;}void outStack(){for(int m=0;m<=i;m++)cout<<data[m];}};【cifa.cpp】//cifa.cpp#include<iostream>#include<string>#include"cifa.h"using namespace std;//关键字表和对应的编码stringcodestring[10]={"main","int","if","then","else","return","void","cout","endlint codebook[10]={26,21,22,23,24,25,27,28,29};//全局变量char ch;int flag=0;/*//主函数int main(){WordType word;cout<<"请输入源程序序列:";word=get_w();while(word.pro!="#")//#为自己设置的结束标志{cout<<"("<<word.code<<","<<"“"<<word.pro<<"”"<<")"<<endl;word=get_w();};return 0;}*/WordType get_w(){string str="";int code;WordType wordtmp;getch();//读一个字符getBC();//去掉空白符if(isLetter()){ //以字母开头while(isLetter()||isDigit()){str=concat(str);getch();}retract();code=Reserve(str);if(code==-1){wordtmp.code=0;wordtmp.pro=str;}//不是关键字else{wordtmp.code=code;wordtmp.pro=str;}//是关键字}else if(isDigit()){ //以数字开头while(isDigit()){str=concat(str);getch();}retract();wordtmp.code=30;wordtmp.pro=str;}else if(ch=='(') {wordtmp.code=1;wordtmp.pro="(";} else if(ch==')') {wordtmp.code=2;wordtmp.pro=")";} else if(ch=='{') {wordtmp.code=3;wordtmp.pro="{";} else if(ch=='}') {wordtmp.code=4;wordtmp.pro="}";} else if(ch==';') {wordtmp.code=5;wordtmp.pro=";";} else if(ch=='=') {wordtmp.code=6;wordtmp.pro="=";} else if(ch=='+') {wordtmp.code=7;wordtmp.pro="+";} else if(ch=='*') {wordtmp.code=8;wordtmp.pro="*";} else if(ch=='>') {wordtmp.code=9;wordtmp.pro=">";} else if(ch=='<') {wordtmp.code=10;wordtmp.pro="<";} else if(ch==',') {wordtmp.code=11;wordtmp.pro=",";} else if(ch=='\'') {wordtmp.code=12;wordtmp.pro="\'";} else if(ch=='-') {wordtmp.code=13;wordtmp.pro="-";} else if(ch=='/') {wordtmp.code=14;wordtmp.pro="/";} else if(ch=='#') {wordtmp.code=15;wordtmp.pro="#";} else if(ch=='|') {wordtmp.code=16;wordtmp.pro="|";}else {wordtmp.code=100;wordtmp.pro=ch;}return wordtmp;}void getch(){if(flag==0) //没有回退的字符ch=getchar();else //有回退字符,用回退字符,并设置标志flag=0;}void getBC(){while(ch==' '||ch=='\t'||ch=='\n')ch=getchar();}bool isLetter(){if(ch>='a'&&ch<='z'||ch>='A'&&ch<='Z')return true;elsereturn false;}bool isDigit(){if(ch>='0'&&ch<='9')return true;elsereturn false;}string concat(string str){return str+ch;}void retract(){flag=1;}int Reserve(string str){int i;for(i=0;i<=8;i++){if(codestring[i]==str) //是某个关键字,返回对应的编码return codebook[i];}if(i==9) //不是关键字return -1;}【LR.cpp】#include<iostream>#include<string>#include<cstdlib>#include"cifa.h"#include"stack_num.h"#include"stack_str.h"#include"table_action.h"#include"table_go.h"using namespace std;void process(){int stepNum=1;int topStat;Stack_num statusSTK; //状态栈Stack_str symbolSTK; //符号栈Stack_num valueSTK; //值栈WordType word;Table_action actionTAB; //行为表Table_go goTAB; //转向表cout<<"请输入源程序,以#结束:";word=get_w();//总控程序初始化操作symbolSTK.push("#");statusSTK.push(0);valueSTK.push(0);cout<<"步骤\t状态栈\t符号栈\t值栈\t当前词\t动作\t转向"<<endl;//分析while(1){topStat=statusSTK.getTop(); //当前状态栈顶string act=actionTAB.getCell(topStat,word.code);//根据状态栈顶和当前单词查到的动作//输出cout<<stepNum++<<"\t";statusSTK.outStack(); cout<<"\t";symbolSTK.outStack(); cout<<"\t";valueSTK.outStack(); cout<<"\t";cout<<word.pro<<"\t";//行为为“acc”,且当前处理的单词为#,且状态栈里就两个状态//说明正常分析结束if(act=="acc"&&word.pro=="#"&&statusSTK.topNumber()==1){cout<<act<<endl;cout<<"分析成功!"<<endl;cout<<"结果为:"<<valueSTK.getTop()<<endl;return;}//读到act表里标记为错误的单元格else if(act==""){cout<<endl<<"不是文法的句子!"<<endl;cout<<"错误的位置为单词"<<word.pro<<"附近。
实验三 自下而上语法分析及语义分析复习进程
实验三自下而上语法分析及语义分析实验三自下而上语法分析及语义分析一、实验目的:通过本实验掌握LR分析器的构造过程,并根据语法制导翻译,掌握属性文法的自下而上计算的过程。
二、实验学时:4学时。
三、实验内容根据给出的简单表达式的语法构成规则(见五),编制LR分析程序,要求能对用给定的语法规则书写的源程序进行语法分析和语义分析。
对于正确的表达式,给出表达式的值。
对于错误的表达式,给出出错位置。
四、实验方法采用LR分析法。
首先给出S-属性文法的定义(为简便起见,每个文法符号只设置一个综合属性,即该文法符号所代表的表达式的值。
属性文法的定义可参照书137页表6.1),并将其改造成用LR分析实现时的语义分析动作(可参照书145页表6.5)。
接下来给出LR分析表。
然后程序的具体实现:●LR分析表可用二维数组(或其他)实现。
●添加一个val栈作为语义分析实现的工具。
●编写总控程序,实现语法分析和语义分析的过程。
注:对于整数的识别可以借助实验1。
五、文法定义简单的表达式文法如下:E->E+T|E-T|TT->T*F|T/F|FF->(E)|i上式中, i 为整数。
六、处理程序例例1: 正确源程序例:23+(45+4)* 40分析结果应为:正确的表达式。
其值为:1983例2: 错误源程序例:5+(56+)-24分析结果应为:错误的表达式:出错位置为)附录:源程序#include <stdio.h>#include"string.h"#include <iostream>using namespace std;#define R 30#define C 20typedef struct elem{char e[4];}Elem; //ACTION表与GoTo表中的元素类型Elem LR[R][C]; //存放ACTION表与GoTo表中的内容typedef struct out{int order; //序号int state[10]; //状态栈char sign[30]; //符号栈char grasen[20]; //产生式char input[30]; //输入串char explen[50]; //解释说明}OutNode; //输出结果中每一行的类型OutNode out[20]; //存放输出结果char Sentence[20]; //存放文法的一个句子char GramSent[10][20]; //存放文法的一组产生式int row,colno; //row为状态个数数,colno 为ACTION表与GoTo表列总数int stateTop=0,signTop=0; //状态栈与符号栈的栈顶位置(值与栈中元素的个数相等)void input_GramSent(){int i,num;printf("请输入文法中产生式的个数\n");scanf("%d",&num);for(i=0;i<num;i++){printf("请输入文法的第%d个产生式\n",i);scanf("%s",GramSent+i-1);}printf("请输入文法的一个句子\n");scanf("%s",Sentence);printf("**********************************************************\n"); printf("* 文法的产生式如下: *\n");printf("**********************************************************\n"); for(i=0;i<num;i++)printf("%s\n",GramSent+i);printf("**********************************************************\n"); printf("* 文法的句子如下: *\n");printf("**********************************************************\n"); printf("%s\n",Sentence);}void input_LR(int row,int colno) //row为行总数,colno为列总数{int i,j;char mid[4];printf("**********************************************************\n"); printf("* 提示:每输入一个元素后就回车 *\n");printf("**********************************************************\n");printf("请输入LR分析表的终结符(包括#)与非终结符\n");for(j=0;j<colno;j++)scanf("%s",LR[0][j].e);for(i=0;i<row;i++){printf("请输入%d号状态所对应的各列的元素,空白的地方用s代替\n",i);for(j=0;j<colno;j++){scanf("%s",mid);if(strcmp(mid,"s")==0||strcmp(mid,"S")==0)strcpy(LR[i+1][j].e," ");elsestrcpy(LR[i+1][j].e,mid);}}}void output_LR(int row,int colno){int i,j;printf("**********************************************************\n"); printf("* LR分析表如下: *\n");printf("**********************************************************\n"); printf("\n");printf(" ");for(j=0;j<colno;j++)printf("%s ",LR[0][j].e);printf("\n");for(i=1;i<=row;i++){printf("%d ",i-1);for(j=0;j<colno;j++)printf("%s ",LR[i][j].e);printf("\n");}printf("\n");}int SignNum(char ch)//给定一个终结符或非终结符,返回其在ACTION表与GoTo表中的列位置{int i;char c[2]="0";c[0]=ch;for(i=0;i<colno;i++)if(strcmp(c,LR[0][i].e)==0)return i;return -1;}int CharChangeNum(char* ch)//给定一数字字符串,返回其所对应的数字{int result=0;while(*ch!='\0'){result=result*10+(*ch-'0');ch++;}return result;}int OutResult(int s,int c,int i)//输出结果的第i+1行处理函数,(s 为状态,c为列){char mid[4],gra[20];int s_num,r_num;int n,len,j;strcpy(mid,LR[s+1][c].e);if(strcmp(mid," ")==0){ printf("不能规约\n"); return -2; }if(strcmp(mid,"acc")==0||strcmp(mid,"ACC")==0){ printf("规约成功\n"); return -1; }out[i+1].order=i+2;if(mid[0]=='s'||mid[0]=='S'){s_num=CharChangeNum(mid+1);//s_num为S后的数字for(j=0;j<stateTop;j++)out[i+1].state[j]=out[i].state[j];out[i+1].state[stateTop]=s_num;out[i+1].state[++stateTop]=-1; //完成第i+1行的状态栈赋值strcpy(out[i+1].sign,out[i].sign);out[i+1].sign[signTop]=out[i].input[0];out[i+1].sign[++signTop]='\0'; //完成第i+1行的符号栈的赋值strcpy(out[i+1].grasen," "); //完成第i+1行的产生式的赋值strcpy(out[i+1].input,out[i].input+1); //完成第i+1行的输入符号串的赋值}else if(mid[0]=='r'||mid[0]=='R'){r_num=CharChangeNum(mid+1);//r_num为r后的数字strcpy(gra,*(GramSent+r_num-1));len=strlen(gra);for(j=0;j<len;j++)if(gra[j]=='-' && gra[j+1]=='>')break;n=strlen(gra+j+2);stateTop-=n; signTop-=n;for(j=0;j<stateTop;j++)out[i+1].state[j]=out[i].state[j];j=SignNum(gra[0]);out[i+1].state[stateTop]=CharChangeNum(LR[out[i+1].state[stateTop-1]+1][j].e);out[i+1].state[++stateTop]=-1; //完成第i+1行的状态栈赋值strcpy(out[i+1].sign,out[i].sign);out[i+1].sign[signTop]=gra[0];out[i+1].sign[++signTop]='\0'; //完成第i+1行的符号栈的赋值strcpy(out[i+1].grasen,gra); //完成第i+1行的产生式的赋值strcpy(out[i+1].input,out[i].input); //完成第i+1行的输入符号串的赋值}return 1;}void OutputResult(int r){int i,j;printf("**********************************************************\n"); printf("* 句子:%s 用LR分析表规约过程如下:*\n",Sentence);printf("**********************************************************\n"); for(i=0;i<=r;i++){j=0;printf("%2d ",out[i].order);while(out[i].state[j]!=-1)printf("%d",out[i].state[j++]);printf(" %s %s %s\n",out[i].sign,out[i].grasen,out[i].input); }}int OutControl()//输出结果的总控函数{int s_num,i=0;out[0].order=1; //序号赋值out[0].state[0]=0; stateTop=1;out[0].state[stateTop]=-1; //状态栈赋值,置栈顶位strcpy(out[0].sign,"#"); signTop=1; //符号栈赋值,置栈顶位strcpy(out[0].grasen," "); //产生式为空strcpy(out[0].input,Sentence); //以下两行为输入串赋值strcat(out[0].input,"#");strcpy(out[0].explen,"0和#进栈"); //解释说明//初使化输出结果的第一行while(1){s_num=SignNum(out[i].input[0]);//if(s_num!=-1)if(OutResult(out[i].state[stateTop-1],s_num,i)!=1)break;i++;}return i;}main(){int r;printf("**********************************************************\n"); printf("* 函数的输入: 文法的产生式,文法句型的一个句子,LR分析表 *\n");printf("* 函数的输出: LR分析器的工作过程与说明 *\n"); printf("**********************************************************\n");printf("请输入LR分析表中终结符与非终结符的总个数\n"); scanf("%d",&colno);printf("请输入LR分析表中状态的总个数\n");scanf("%d",&row);input_LR(row,colno);output_LR(row,colno);input_GramSent();r=OutControl(); //r为输出结果的行数OutputResult(r);}七、实验小结这个程序是从网上下载下来的,根据这个实验要求做了些更改,但是总是出现溢出错误,只能运行到LR分析表的部分(如截图),没有找到解决问题的办法。
编译原理-自上而下语法分析
递归下降分析程序构造 预测分析程序 LL(1)分析中的错误处理
4.3.1 不带回溯的自上而下分析算法
自上而下分析方法
不允许文法含有任何左递归 构造不带回溯的自上而下分析算法
消除文法的左递归性
找出克服回溯的充分必要条件
4.3.2 左递归的消除(一)
直接消除产生式中的左递归
4.1.1 语法分析器的功能
高级语言的语法结构
适合用上下文无关文法描述
语法分析器
任务:分析与判定程序的语法结构是否符合语法规则
工作本质:根据产生式识别输入串是否为一个句子
在编译器中的地位:核心部分
源程序
单词符号
词法分析器
取下一个单 词符号
语法分析器
语法分析树
编译器的 后继部分
那么,可以把这些规则改写成
A→A | 1 | 2 | … | m A→ 1 | 2 | … | n
经过反复提取左因子,就能够把每个非终结符(包括
新引进者)的所有候选首符集变成为两两不相交
4.3.3 消除回溯、提左因子(三)
例4.4:考察文法G:
S → iCtS | iCtSeS | a C→b
自上而下
从文法的开始符号出发,向下推导,推出句子
存在问题:带“回溯”
克服方法
不带回溯的递归子程序(递归下降)分析方法
自上而下分析的主旨
为输入串寻找一个最左推导 对任何输入串,试图用一切可能的办法,从文法开始
符号(根结点)出发,自上而下地为输入串建立一棵 语法树
4.2.2 回溯举例
4.3.3 回溯的消除(一)
为了消除回溯就必须保证
《编译原理》第6章自下而上语法分析
编译原理武汉大学计算机学院编译原理课程组自上而下语法分析·基本思想·存在的问题·解决方法·LL(1)方法·递归子程序法消除左递归FIRST集、FOLLOW集·LL(1)文法递归子程序的构造LL(1)分析表的构造6.1 自下而上语法分析1.自下而上语法分析的基本思想从输入的符号串开始,利用文法的产生式步步向上归约,试图归约到文法的识别符号。
如果从语法树的角度看,自下而上分析的过程是以输入符号串作为末端结点符号串,向着根结点的方向往上构造语法树,使识别符号正好是该语法树的根结点。
相应于高级语言的编译过程,自下而上语法分析就是从该高级语言文法的源程序或与其等价的单词串出发,试图归约得到该文法的开始符号——<程序>。
6.1 自下而上语法分析3.自下而上语法分析遇到的基本问题例如,对文法G[S]:S→aAcBeA→bA→AbB→d分析符号串abbcde。
1.短语、直接短语与句柄6.2 短语和句柄则称句型xuy 中的子串u 为句型xuy (相对于非终结符号U )的短语。
设有文法G[Z],w=xuy 是它的一个句型,如果有Z *⇒xUy +⇒且U u U ⇒u则称u为句型xuy的直接(简单)短语。
特别地,如果前述条件中U +⇒u为句型的最左直接(简单)短语称为句柄。
6.2 短语和句柄例:设有文法G[S]:S→ABA→Aa|bBB→a|Sb请给出句型baabaab的所有短语、直接短语和句柄。
6.2 短语和句柄2.短语、简单(直接)短语、句柄与语法树的关系语法树子树的末端结点符号串即是语法树所描述句型(相对于子树的根)的短语;简单子树(只有父子两代)的末端结点符号串即是直接短语。
最左简单子树的末端结点符号串即是句柄。
6.2 短语和句柄例:设有文法G[S]:S→ABA→Aa|bBB→a|Sb请给出句型baabaab的所有短语、直接短语和句柄。
第 6 章自学内容第 6 章作业P100 6.8求下列句型的所有短语、简单(直接)短语和句柄。
编译原理第4章 语法分析(自下而上分析)
二、算符优先文法和优先表的构造
1 算符优先文法(OPG文法)
两个非终结符相邻
(1)算符文法(OG文法):设有一文法G,若G中没有形如
S→…QR…产生式,(S,Q,R∈VN)则称文法G为算符文 法。 (2)定义优先关系:设文法G是一个OG文法,令a,b是任意两 个终结符号,P , G , R 是非终结符号,定义: . ① a = b 当且仅当文法G中含有形如P→…ab…或 P→…aQb…规则。 ② a <. b 当且仅当文法G中含有形如P→…aR…的 规则, 其中:R=>b…或R=>Qb…。 ③ a .> b 当且仅当文法G中含有形如P→…Rb…的 规则, 其中:R=>…a 或 R=>…aQ。
3
S S→aAcBe A→b | Ab a A c B e B→d 问abbcde是不是该文法的句子? A b d 步骤 符号栈 输入流 动作 0 # abbcde# b 1 #a bbcde# 移进 2 #ab bcde# 移进 3 #aA bcde# 归约,用A→b 4 #aAb cde# 移进 5 #aA cde# 归约,用A→Ab 6 #aAc de# 移进 7 #aAcd e# 移进 8 #aAcB e# 归约,用B→d 9 #aAcBe # 移进 10 #S # 归约,用S →aAcBe 4 11 #S # 成功 例:设文法G[S]:
10
优先关系的例子
文法:S→bAb
A→(B | a B→Aa) //S→bAb //A→(Aa)|a
语言:{bab, b(aa)b, b((aa)a)b, } 可以从语法树里面导出部分优先关系。
S b b<a A a b a>b
S
b
编译原理课件 语法分析自下而上分析
22
移进归约:系统框架
n 输入缓冲区:保存输入符号串,设符号串以# 为结束符,有一个指针,指向当前输入符号。
n 分析栈(符号栈):保存文法符号,记载分析的 历史 — 已经得到的部分结果;指示分析的 下一步动作 ---展望未来。
n 控制程序:控制分析的过程,输出分析结果。 分析中,栈顶未形成可归约串时则移进当前 输入符号到栈;当栈顶形成可归约串(是某个 非终结符的某个候选式)时则归约: 栈顶的可 归约串出栈, 该非终结符进栈。
A
B
⇒aAbcdeα3 ⇒abbcde α4
a b b cd e
20
• 练习:文法G(S): S → (L) | aS | a L → L , S | S (1)指出句子 (a,(a)) 的规范归约; (2)指出每次归约用的句柄。
解:(1)规范归约: (a,(a)) ,(S,(a)) ,(L,(a)) ,(L,(S)) ,(L,(L)) ,(L,S) ,(L) ,S
9
例5.2:文法G[S], 其4条产生式如下:
① S→aABe
② A→b
③ A→Abc
④ B→d
对句子abbcde的分析
最右推导 S⇒aABe⇒aAde⇒aAbcde⇒abbcde
最左归约 abbcd,eaAbcde ,aAde,aABe,S
S
S
A
A
B
⇒aABe ⇒aAde ⇒aAbcde
a b b cd e
T * i2 + i3
i2 + i3 #
读入* , *进栈
L, S
(2) n 短语: S、a、(a)、S,(a)、(S,(a))
编译原理-自下而上的语法分析
自上而下的语法分析
特点
从高层次的文法规则开始,通过不断展开和推导,直到生成目标字符串。
优点
易于理解和实现,可以生成详细的错误报告。
自下而上的语法分析
1
自底向上的语法分析方法概述
通过以输入的标记为起点,逐步推导文法规则,直到生成目标字符串。
2
LR语法分析
一种常用的自底向上的语法分析方法,通过构建一个LR分析表进行推导。
3
LALR语法分析
是LR语法分析的一种变体,通过合并相同状态来降低分析表的复杂度。
自下而上的语法分析的优点和局限性
优点
适用于大型文法,能够处理更广泛的语言结构。
局限性
分析过程复杂,容易产生冲突,需要较大的存储空 间。
自下而上的语法分析的实现
词法分分析器的生成
根据文法规则,构建分析表或语法分析器的数据结构。
语法制导翻译的实现
在语法分析过程中,将源代码转换为目标代码。
自下而上的语法分析的应用
1
编译器中的语法分析
语法分析是编译器中的重要组成部分,用于将源代码转换为中间代码或目标代码。
2
解析器生成器
自下而上的语法分析技术被广泛应用于解析器生成器中,用于自动生成语法分析 器。
结论
自下而上的语法分析是编译原理中重要的一环,虽然实现复杂,但却具有广 泛的应用价值。
编译原理-自下而上的语 法分析
编译原理是研究程序在计算机上的自动翻译过程,语法分析是其中的重要步 骤。自下而上的语法分析是一种常用的语法分析方法。
语法分析的定义和目的
1 定义
语法分析是编译器中的一个阶段,用于验证 和分析程序语法的正确性。
2 目的
语法分析的目的是将源代码转换为语法树, 为后续的编译过程提供基础。
《编译原理课程教案》第4章:自下而上语法分析
构造识别活前缀的DFA, 并根据DFA构造分析表
构造过程中需要消除直接 左递归和提取左因子等操 作
SLR(1)文法及其分析表的构造
SLR(1)文法是LR(0)文法 的简化版本,通过引入 FOLLOW集解决冲突问题
FOLLOW集表示在当前非 终结符之后可能出现的终 结符集合
ABCD
构造SLR(1)分析表时,需 要计算每个非终结符的 FOLLOW集
算符优先分析算法
01
02
03
算符优先分析算法是一 种自下而上的语法分析 方法,通过不断归约和
移进来构造语法树。
在分析过程中,需要维 护一个分析栈和一个输 入缓冲区,分别用于存 储已经分析过的部分和
待分析的部分。
根据优先关系表和分析 栈顶的元素,可以确定 下一步的操作是移进还
是归约。
算符优先分析法的局限性
《编译原理课程教案》第4章:自 下而上语法分析
contents
目录
• 引言 • 自下而上语法分析基本概念 • 算符优先分析法 • LR分析法 • 自下而上语法分析的优化技术 • 实验环节:自下而上语法分析器设计 • 章节小结与拓展思考
01 引言
编译原理课程概述
编译原理是计算机科学的一个重 要分支,研究将高级语言程序转 换为机器语言程序的原理和技术。
总结经验教训
总结实验过程中的经验教训,包括设计思路 的合理性、实现过程的难点和易错点等,为 今后的学习和工作提供参考。
07 章节小结与拓展思考
章节小结:关键知识点回顾
自下而上语法分析基本概念
从输入串开始,逐步进行归约,直到文法的 开始符号。
LR分析法
利用移进-归约思想,结合栈和状态转移表 进行语法分析。
编译原理 语法分析——自下而上分析
显然这是一个最右推导。
规范归约是关于是一个最右推导的逆过程
最左归约
规范推导
由规范推导推出的句型称为规范句型。
三峡大学计算机系602
S
a A c Be
A
bd
b S
S
a A c Be
Ab
d
S
aA
c Bea A
d
三峡大学计算机系602
c Be
5.1.3 符号栈的使用和分析树的表示
栈是语法分析的一种基本数据结构。’#’作 为栈底符号
e
dBB
b
cccc
bAAAAAAA
aaaaaaaaaS
三峡大学计算机系602
S
a A c Be
A
bd
b 分析树和语法树不一定一致。 自下而上分析过程:边输入单词符号,边 归约。 核心问题:识别可归约串
三峡大学计算机系602
5.1.2 规范归约
定义:令G是一个文法,S是文法的开始符 号,假定是文法G的一个句型,如果有
E
E* E- E E+E i
i
i
返回
E ( E)
E+ E
i
i
三峡大学计算机系602
句子i+i-i*(i+i)的归约过程是: (1) i+i-i*(i+i) (2) E+i-i*(i+i) (3) E+E-i*(i+i) (4) E-i*(i+i) (5) E-E*(i+i) (6) E-E*(E+i) (7) E-E*(E+E) (8) E-E*(E) (9) E-E*E (10) E-E (11) E
三峡大学计算机系602
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
上海电力学院编译原理课程实验报告实验名称:实验三自下而上语法分析及语义分析院系:计算机科学和技术学院专业年级:学生姓名:学号:指导老师:实验日期:实验三自上而下的语法分析一、实验目的:通过本实验掌握LR分析器的构造过程,并根据语法制导翻译,掌握属性文法的自下而上计算的过程。
二、实验学时:4学时。
三、实验内容根据给出的简单表达式的语法构成规则(见五),编制LR分析程序,要求能对用给定的语法规则书写的源程序进行语法分析和语义分析。
对于正确的表达式,给出表达式的值。
对于错误的表达式,给出出错位置。
四、实验方法采用LR分析法。
首先给出S-属性文法的定义(为简便起见,每个文法符号只设置一个综合属性,即该文法符号所代表的表达式的值。
属性文法的定义可参照书137页表6.1),并将其改造成用LR分析实现时的语义分析动作(可参照书145页表6.5)。
接下来给出LR分析表。
然后程序的具体实现:● LR分析表可用二维数组(或其他)实现。
●添加一个val栈作为语义分析实现的工具。
●编写总控程序,实现语法分析和语义分析的过程。
注:对于整数的识别可以借助实验1。
五、文法定义简单的表达式文法如下:(1)E->E+T(2)E->E-T(3)E->T(4)T->T*F(5)T->T/F(6)T->F(7)F->(E)(8)F->i状态ACTION(动作)GOTO(转换)i + - * / ( ) # E T F0 S5 S4 1 2 31 S6 S12 acc2 R3 R3 S7 S13 R3 R33 R6 R6 R6 R6 R6 R64 S5 S4 8 2 35 R8 R8 R8 R8 R8 R86 S5 S4 9 37 S5 S4 108 S6 R12 S119 R1 R1 S7 S13 R1 R110 R4 R4 R4 R4 R4 R411 R7 R7 R7 R7 R7 R712 S5 S4 14 313 S5 S4 1514 R2 R2 S7 S13 R2 R215 R5 R5 R5 R5 R5 R5五、处理程序例和处理结果例示例1:20133191*(20133191+3191)+ 3191#六、源代码【cifa.h】//cifa.h#include<string> using namespace std; //单词结构定义struct WordType{int code;string pro;};//函数声明WordType get_w(); void getch();void getBC();bool isLetter();bool isDigit();void retract();int Reserve(string str);string concat(string str);【Table.action.h】//table_action.hclass Table_action{int row_num,line_num;int lineName[8];string tableData[16][8];public:Table_action(){row_num=16;line_num=8;lineName[0]=30;lineName[1]=7;lineName[2]=13;lineName[3]=8;lineName[4]=14;lineName[5]=1;lineName[6]=2;lineName[7]=15;lineName[8]=0;for(int m=0;m<row_num;m++)for(int n=0;n<line_num;n++)tableData[m][n]="";tableData[0][0]="S5";tableData[0][5]="S4";tableData[1][1]="S6";tableData[1][2]="S12";tableData[1][7]="acc";tableData[2][1]="R3";tableData[2][2]="R3";tableData[2][3]="S7";tableData[2][4]="S13";tableData[2][6]="R3";tableData[2][7]="R3";tableData[3][1]="R6";tableData[3][2]="R6";tableData[3][3]="R6";tableData[3][4]="R6";tableData[3][6]="R6";tableData[4][0]="S5"; tableData[4][5]="S4"; tableData[5][1]="R8"; tableData[5][2]="R8"; tableData[5][3]="R8"; tableData[5][4]="R8"; tableData[5][6]="R8"; tableData[5][7]="R8"; tableData[6][0]="S5"; tableData[6][5]="S4"; tableData[7][0]="S5"; tableData[7][5]="S4"; tableData[8][1]="S6"; tableData[8][2]="S12"; tableData[8][6]="S11"; tableData[9][1]="R1"; tableData[9][2]="R1"; tableData[9][3]="S7"; tableData[9][4]="S13"; tableData[9][6]="R1"; tableData[9][7]="R1"; tableData[10][1]="R4"; tableData[10][2]="R4"; tableData[10][3]="R4"; tableData[10][4]="R4"; tableData[10][6]="R4"; tableData[10][7]="R4"; tableData[11][1]="R7"; tableData[11][2]="R7"; tableData[11][3]="R7"; tableData[11][4]="R7"; tableData[11][6]="R7"; tableData[11][7]="R7"; tableData[12][0]="S5"; tableData[12][5]="S4"; tableData[13][0]="S5"; tableData[13][5]="S4"; tableData[14][1]="R2"; tableData[14][2]="R2"; tableData[14][3]="S7"; tableData[14][4]="S13"; tableData[14][6]="R2"; tableData[14][7]="R2";tableData[15][2]="R5";tableData[15][3]="R5";tableData[15][4]="R5";tableData[15][5]="R5";tableData[15][6]="R5";tableData[15][7]="R5";}string getCell(int rowN,int lineN){int row=rowN;int line=getLineNumber(lineN);if(row>=0&&row<row_num&&line>=0&&line<=line_num) return tableData[row][line];elsereturn"";}int getLineNumber(int lineN){for(int i=0;i<line_num;i++)if(lineName[i]==lineN)return i;return -1;}};【Table_go.h】//table_go.hclass Table_go{int row_num,line_num;//行数、列数string lineName[3];int tableData[16][3];public:Table_go(){row_num=16;line_num=3;lineName[0]="E";lineName[1]="T";lineName[2]="F";for(int m=0;m<row_num;m++)for(int n=0;n<line_num;n++)tableData[m][n]=0;tableData[0][0]=1;tableData[0][1]=2;tableData[0][2]=3;tableData[4][0]=8;tableData[4][1]=2;tableData[4][2]=3;tableData[6][1]=9;tableData[6][2]=3;tableData[7][2]=10;tableData[12][1]=14;tableData[12][2]=3;tableData[13][2]=15;}int getCell(int rowN,string lineNa){int row=rowN;int line=getLineNumber(lineNa);if(row>=0&&row<row_num&&line<=line_num) return tableData[row][line];elsereturn -1;}int getLineNumber(string lineNa){for(int i=0;i<line_num;i++)if(lineName[i]==lineNa)return i;return -1;}};【Stack_num.h】class Stack_num{int i; //栈顶标记int *data; //栈结构public:Stack_num() //构造函数{data=new int[100];i=-1;}int push(int m) //进栈操作{i++;data[i]=m;return i;}int pop() //出栈操作{i--;return data[i+1];}int getTop() //返回栈顶{return data[i];}~Stack_num() //析构函数{delete []data;}int topNumber(){return i;}void outStack(){for(int m=0;m<=i;m++)cout<<data[m];}};【Stack_str.h】class Stack_str{int i; //栈顶标记string *data; //栈结构public:Stack_str() //构造函数{data=new string[50];i=-1;}int push(string m) //进栈操作{i++;data[i]=m;return i;}int pop() //出栈操作{data[i]="";i--;return i;}string getTop() //返回栈顶{return data[i];}~Stack_str() //析构函数{delete []data;}int topNumber(){return i;}void outStack(){for(int m=0;m<=i;m++)cout<<data[m];}};【cifa.cpp】//cifa.cpp#include<iostream>#include<string>#include"cifa.h"using namespace std;//关键字表和对应的编码string codestring[10]={"main","int","if","then","else","return","void","cout","endl"}; int codebook[10]={26,21,22,23,24,25,27,28,29};//全局变量char ch;int flag=0;/*//主函数int main(){WordType word;cout<<"请输入源程序序列:";word=get_w();while(word.pro!="#")//#为自己设置的结束标志{cout<<"("<<word.code<<","<<"“"<<word.pro<<"”"<<")"<<endl;word=get_w();};return 0;}*/WordType get_w(){string str="";int code;WordType wordtmp;getch();//读一个字符getBC();//去掉空白符if(isLetter()){ //以字母开头while(isLetter()||isDigit()){str=concat(str);getch();}retract();code=Reserve(str);if(code==-1){wordtmp.code=0;wordtmp.pro=str;}//不是关键字else{wordtmp.code=code;wordtmp.pro=str;}//是关键字}else if(isDigit()){ //以数字开头while(isDigit()){str=concat(str);getch();}retract();wordtmp.code=30;wordtmp.pro=str;}else if(ch=='(') {wordtmp.code=1;wordtmp.pro="(";} else if(ch==')') {wordtmp.code=2;wordtmp.pro=")";}else if(ch=='{') {wordtmp.code=3;wordtmp.pro="{";}else if(ch=='}') {wordtmp.code=4;wordtmp.pro="}";}else if(ch==';') {wordtmp.code=5;wordtmp.pro=";";}else if(ch=='=') {wordtmp.code=6;wordtmp.pro="=";}else if(ch=='+') {wordtmp.code=7;wordtmp.pro="+";}else if(ch=='*') {wordtmp.code=8;wordtmp.pro="*";}else if(ch=='>') {wordtmp.code=9;wordtmp.pro=">";}else if(ch=='<') {wordtmp.code=10;wordtmp.pro="<";}else if(ch==',') {wordtmp.code=11;wordtmp.pro=",";}else if(ch=='\'') {wordtmp.code=12;wordtmp.pro="\'";}else if(ch=='-') {wordtmp.code=13;wordtmp.pro="-";}else if(ch=='/') {wordtmp.code=14;wordtmp.pro="/";}else if(ch=='#') {wordtmp.code=15;wordtmp.pro="#";}else if(ch=='|') {wordtmp.code=16;wordtmp.pro="|";}else {wordtmp.code=100;wordtmp.pro=ch;}return wordtmp;}void getch(){if(flag==0) //没有回退的字符ch=getchar();else //有回退字符,用回退字符,并设置标志flag=0;}void getBC(){while(ch==' '||ch=='\t'||ch=='\n')ch=getchar();}bool isLetter(){if(ch>='a'&&ch<='z'||ch>='A'&&ch<='Z')return true;elsereturn false;}bool isDigit(){if(ch>='0'&&ch<='9')return true;elsereturn false;}string concat(string str){return str+ch;}void retract(){flag=1;}int Reserve(string str){int i;for(i=0;i<=8;i++){if(codestring[i]==str) //是某个关键字,返回对应的编码return codebook[i];}if(i==9) //不是关键字return -1;}【LR.cpp】#include<iostream>#include<string>#include<cstdlib>#include"cifa.h"#include"stack_num.h"#include"stack_str.h"#include"table_action.h"#include"table_go.h"using namespace std;void process(){int stepNum=1;int topStat;Stack_num statusSTK; //状态栈Stack_str symbolSTK; //符号栈Stack_num valueSTK; //值栈WordType word;Table_action actionTAB; //行为表Table_go goTAB; //转向表cout<<"请输入源程序,以#结束:";word=get_w();//总控程序初始化操作symbolSTK.push("#");statusSTK.push(0);valueSTK.push(0);cout<<"步骤\t状态栈\t符号栈\t值栈\t当前词\t动作\t转向"<<endl;//分析while(1){topStat=statusSTK.getTop(); //当前状态栈顶string act=actionTAB.getCell(topStat,word.code);//根据状态栈顶和当前单词查到的动作//输出cout<<stepNum++<<"\t";statusSTK.outStack(); cout<<"\t";symbolSTK.outStack(); cout<<"\t";valueSTK.outStack(); cout<<"\t";cout<<word.pro<<"\t";//行为为“acc”,且当前处理的单词为#,且状态栈里就两个状态//说明正常分析结束if(act=="acc"&&word.pro=="#"&&statusSTK.topNumber()==1){cout<<act<<endl;cout<<"分析成功!"<<endl;cout<<"结果为:"<<valueSTK.getTop()<<endl;return;}//读到act表里标记为错误的单元格else if(act==""){cout<<endl<<"不是文法的句子!"<<endl;cout<<"错误的位置为单词"<<word.pro<<"附近。