北邮 编译原理 语义分析实验报告
北邮 编译原理 语义分析实验报告
编译原理第六章语义分析目录1. 实验题目和要求 (2)2. 实验分析和思考 (3)3. 翻译方案 (4)4. LR实现自底向上分析(摘自语法分析实验) (5)4.1.构造识别所有活前缀的DFA (5)5.1. 扩充分析栈 ................................................................................................................ 7 5.2. 改造分析程序 ............................................................................................................ 7 5.3. 编程实现 .................................................................................................................... 76.运行结果截图: (13)1. 实验题目和要求题目:语义分析程序的设计与实现。
实验内容:编写语义分析程序,实现对算术表达式的类型检查和求值。
要求所分析算术表达式由如下的文法产生。
numE idF F F T F T T T T E T E E |)(||/|*||→→-+→ 实验要求:用自底向上的语法制导翻译技术实现对表达式的分析和翻译。
(1) 写出满足要求的语法制导定义或翻译方案。
(2) 编写分析程序,实现对表达式的类型进行检查和求值,并输出: ① 分析过程中所有产生式。
② 识别出的表达式的类型。
③ 识别出的表达式的值。
(3) 实验方法:可以选用以下两种方法之一。
① 自己编写分析程序。
② 利用YACC 自动生成工具。
2.实验分析和思考由于要求进行类型检查和求值,所以可以定义两个综合属性,一个记录值一个记录类型,存放在结构中,一并传入传出。
编译原理实验报告
编译原理实验报告一、实验目的本次编译原理实验的主要目的是通过实践加深对编译原理中词法分析、语法分析、语义分析和代码生成等关键环节的理解,并提高实际动手能力和问题解决能力。
二、实验环境本次实验使用的编程语言为 C/C++,开发工具为 Visual Studio 2019,操作系统为 Windows 10。
三、实验内容(一)词法分析器的设计与实现词法分析是编译过程的第一个阶段,其任务是从输入的源程序中识别出一个个具有独立意义的单词符号。
在本次实验中,我们使用有限自动机的理论来设计词法分析器。
首先,我们定义了单词的种类,包括关键字、标识符、常量、运算符和分隔符等。
然后,根据这些定义,构建了相应的状态转换图,并将其转换为程序代码。
在实现过程中,我们使用了字符扫描和状态转移的方法,逐步读取输入的字符,判断其所属的单词类型,并将其输出。
(二)语法分析器的设计与实现语法分析是编译过程的核心环节之一,其任务是在词法分析的基础上,根据给定的语法规则,判断输入的单词序列是否构成一个合法的句子。
在本次实验中,我们采用了自顶向下的递归下降分析法来实现语法分析器。
首先,我们根据给定的语法规则,编写了相应的递归函数。
每个函数对应一种语法结构,通过对输入单词的判断和递归调用,来确定语法的正确性。
在实现过程中,我们遇到了一些语法歧义的问题,通过仔细分析语法规则和调整函数的实现逻辑,最终解决了这些问题。
(三)语义分析与中间代码生成语义分析的任务是对语法分析所产生的语法树进行语义检查,并生成中间代码。
在本次实验中,我们使用了四元式作为中间代码的表示形式。
在语义分析过程中,我们检查了变量的定义和使用是否合法,类型是否匹配等问题。
同时,根据语法树的结构,生成相应的四元式中间代码。
(四)代码优化代码优化的目的是提高生成代码的质量和效率。
在本次实验中,我们实现了一些基本的代码优化算法,如常量折叠、公共子表达式消除等。
通过对中间代码进行分析和转换,减少了代码的冗余和计算量,提高了代码的执行效率。
北邮-语义分析
编译原理程序设计3语义分析By坏学长一、 实验题目和要求题目:语义分析程序的设计与实现。
实验内容:编写语义分析程序,实现对算术表达式的类型检查和求值。
要求所分析算术表达式由如下的文法产生。
numE idF F F T F T T T T E T E E |)(||/|*||→→-+→ 实验要求:用自底向上的语法制导翻译技术实现对表达式的分析和翻译。
(1) 写出满足要求的语法制导定义或翻译方案。
(2) 编写分析程序,实现对表达式的类型进行检查和求值,并输出: ① 分析过程中所有产生式。
② 识别出的表达式的类型。
③ 识别出的表达式的值。
(3) 实验方法:可以选用以下两种方法之一。
① 自己编写分析程序。
② 利用YACC 自动生成工具。
二、 实验分析1. 自底向上的LR 分析 ◆ 该文法的拓广文法E' -> EE -> E + T E -> E - T E -> T T -> T *F T -> T / F T -> F F -> id F ->( E ) F ->num◆ FIRST 和FOLLOW 集◆该文法的LR(0)项目集规范族:●CLOUSURE I0E' -> .EE -> .E+TE -> .E-TE -> .TT -> .T*FT -> .T/FT -> .FF -> .idF -> .(E) F -> .num●CLOUSURE I1E' -> E. E -> E.+TE -> E.-T●CLOUSURE I2E -> T. T -> T.*FT -> T./F●CLOUSURE I3T -> F.●CLOUSURE I4F -> id.●CLOUSURE I5F -> num.●CLOUSURE I6F -> (.E) E -> .E+TE -> .E-TE -> .TT -> .T*FT -> .T/FT -> .FF -> .idF -> .(E) F -> .num●CLOUSURE I7E -> E+.TT -> .T*FT -> .T/FT -> .FF -> .idF -> .(E) F -> .num●CLOUSURE I8E -> E-.TT -> .T*FT -> .T/FT -> .FF -> .idF -> .(E) F -> .num●CLOUSURE I9T -> T*.FF -> .idF -> .(E) F -> .num●CLOUSURE I10T -> T/.FF -> .idF -> .(E) F -> .num●CLOUSURE I11F -> (E.) E -> E.+TE -> E.-T●CLOUSURE I12E -> E+T. T -> T.*FT -> T./F●CLOUSURE I13E -> E-T. T -> T.*FT -> T./F●CLOUSURE I14T -> T*F.●CLOUSURE I15T -> T/F.●CLOUSURE I16F -> (E).构造SLR(1)分析表2.S属性定义的制导翻译自底向上的制导翻译需要在LR分析的基础上进行扩展,进行综合属性的记录和计算,完成类型检查和结果计算.◆扩充分析栈目的:用于保存综合属性实现:栈由state和value类的容器类实现,state元素是指向LR(1)分析表中状态的指针(或索引),val中就存放分析树中对应的属性值。
北邮大三上-编译原理-语法分析实验报告
.编译原理第四章语法分析班级:09211311学号:姓名:schnee目录1. 实验题目和要求 (2)2. 递归调用预测分析实现自顶向下分析(方法1) (2)1. 消除左递归 (2)2. 画状态转移图 (3)3. 编程实现递归调用自顶向下分析 (3)3. LR实现自底向上分析(方法三) (11)1. 构造识别所有活前缀的DFA (6)2. 构造LR分析表 (7)3. 编程实现算法4.3,实现自底向上LR分析 (8)4. 运行结果截图 (11)1. 实验题目和要求题目:语法分析程序的设计与实现。
实验内容:编写语法分析程序,实现对算术表达式的语法分析。
要求所分析算术表达式由如下的文法产生。
numE idF F F T F T T T T E T E E |)(||/|*||→→-+→ 实验要求:在对输入表达式进行分析的过程中,输出所采用的产生式。
方法1:编写递归调用程序实现自顶向下的分析。
方法2:编写LL(1)语法分析程序,要求如下。
(1) 编程实现算法4.2,为给定文法自动构造预测分析表。
(2) 编程实现算法4.1,构造LL(1)预测分析程序。
方法3:编写语法分析程序实现自底向上的分析,要求如下。
(1) 构造识别所有活前缀的DFA 。
(2) 构造LR 分析表。
(3) 编程实现算法4.3,构造LR 分析程序。
方法4:利用YACC 自动生成语法分析程序,调用LEX 自动生成的词法分析程序。
2. 递归调用预测分析实现 自顶向下分析(方法1)(1) 消除文法左递归。
文法改写为:numE idF FT FT T FT T TE TE E TE E |)(||/|*||''''''''→→→-+→→εε(2) 画出状态图得εE ': E :T ': T :F:化简得ε6(3) 预测分析程序的实现① 说明定义函数error()为错误处理子程序。
北邮编译原理LR语法分析程序实验报告
LR语法分析程序实验报告说明:该程序使用实现对算术表达式自底向上的语法分析,并且在对输入表达式进行分析的过程中,输出分析动作,移进或者用哪个产生式进行规约,该程序使用的是LR语法分析程序,手动构造了识别所有活前缀的DFA,为给定文法构造LR分析表,并通过预测分析表对输入的表达式进行分析,并将栈顶状态和预测分析过程详细输出,如果匹配成功则接受,如果匹配不成功则返回错误信息。
特别的是,该程序参照书上129页的有关LR分析的错误处理与恢复表对一些可能出现的错误进行报错和局部恢复,在action表中设置相应的错误处理过程入口,调用相应的过程进行错误处理和恢复,使语法分析能继续进行。
给定文法的产生式为:E->E+T | TT->T*F | FF-> id | (E)源代码:#include<iostream>#include<stack>using namespace std;stack<char> symbol;stack<int> state;char sen[50];char sym[12][6]={//符号表{'s','e','e','s','e','e'},{'e','s','e','e','e','a'},{'r','r','s','r','r','r'},{'r','r','r','r','r','r'},{'s','e','e','s','e','e'},{'r','r','r','r','r','r'},{'s','e','e','s','e','e'},{'s','e','e','s','e','e'},{'e','s','e','e','s','e'},{'r','r','s','r','r','r'},{'r','r','r','r','r','r'},{'r','r','r','r','r','r'}};char snum[12][6]={//数字表{5,1,1,4,2,1},{3,6,5,3,2,0},{2,2,7,2,2,2},{4,4,4,4,4,4},{5,1,1,4,2,1},{6,6,6,6,6,6},{5,1,1,4,2,1},{5,1,1,4,2,1},{3,6,5,3,11,4},{1,1,7,1,1,1},{3,3,3,3,3,3},{5,5,5,5,5,5}};int go2[12][3]={//goto表{1,2,3},{0,0,0},{0,0,0},{0,0,0},{8,2,3},{0,0,0},{0,9,3},{0,0,10},{0,0,0},{0,0,0},{0,0,0},{0,0,0}};void action(int i,char *&a,char &how,int &num,char &A,int &b)//action函数[i,a] {int j;switch(*a){case 'i':j=0;break;case '+':j=1;break;case '*':j=2;break;case '(':j=3;break;case ')':j=4;break;case '#':j=5;break;default:j=-1;break;}printf("%c\t\t",*a);if(j!=-1){how=sym[i][j];num=snum[i][j];if(how=='r'){switch(num){case 1:A='E',b=3;cout<<"reduce by E->E+T"<<endl;break;case 2:A='E',b=1;cout<<"reduce by E->T"<<endl;break;case 3:A='T',b=3;cout<<"reduce by T->T*F"<<endl;break;case 4:A='T',b=1;cout<<"reduce by T->F"<<endl;break;case 5:A='F',b=3;cout<<"reduce by F->(E)"<<endl;break;case 6:A='F',b=1;cout<<"reduce by F->id"<<endl;break;default:break;}}}}int go(int t,char A)//goto[t,A]{switch(A){case 'E':return go2[t][0];break;case 'T':return go2[t][1];break;case 'F':return go2[t][2];break;}}void error(int i,int j,char *&a)//error处理函数{switch(j){case 1://期望输入id或左括号,但是碰到+,*,或$,就假设已经输入id了,转到状态5 cout<<"error:缺少运算对象id"<<endl;symbol.push('i');//必须有这个,如果假设输入id的话,符号栈里必须有....printf("i\t\t");state.push(5);printf("5\t\t");break;case 2://从输入中删除右括号a++;cout<<"error:不配对的右括号"<<endl;break;case 3://期望碰到+,但是输入id或左括号,假设已经输入算符+,转到状态6 cout<<"error:缺少运算符"<<endl;symbol.push('+');printf("+\t\t");state.push(6);printf("6\t\t");break;case 4://缺少右括号,假设已经输入右括号,转到状态11cout<<"error:缺少右括号"<<endl;symbol.push(')');printf(")\t\t");state.push(11);printf("11\t\t");break;case 5:a++;cout<<"error:*号无效,应该输入+号!"<<endl;case 6:a++;}}int main(){int s;char *a;char how;int num;int b;char A;cout<<"请输入表达式(以i表示标识符,以#结束):"<<endl;while(1){cin>>sen;a=sen;state.push(0);//先输入0状态printf("\t\t-------分析过程-------\n");printf("符号栈栈顶\t状态栈栈顶\t当前读入符号\t分析动作\n");printf(" \t\t0\t\t");while(*a!='\0'){b=0;num=0;how='\0';A='\0';s=state.top();action(s,a,how,num,A,b);if(how=='s')//移进{cout<<"Shift"<<endl;symbol.push(*a);printf("%c\t\t",*a);state.push(num);printf("%d\t\t",num);a++;}else if(how=='r')//规约{for(int i=0;i<b;i++){if(!state.empty())state.pop();if(!symbol.empty())symbol.pop();}int t=state.top();symbol.push(A);printf("%c\t\t",A);state.push(go(t,A));printf("%d\t\t",go(t,A));}else if(how=='a')//接受break;else{error(s,num,a);//错误处理}}cout<<"accept"<<endl;}return 0;}输入的表达式正确则不报错并接受:输入错误的表达式i*(i+i*i#报错并进行恢复:输入错误的表达式i+*i#报错并恢复:输入错误表达式i*ii+i)#进行报错并恢复:。
编译原理实验报告
编译原理实验报告一、实验目的编译原理是计算机科学中的重要学科,它涉及到将高级编程语言转换为计算机能够理解和执行的机器语言。
本次实验的目的是通过实际操作和编程实践,深入理解编译原理中的词法分析、语法分析、语义分析以及中间代码生成等关键环节,提高我们对编译过程的认识和编程能力。
二、实验环境本次实验使用的编程语言为C++,开发环境为Visual Studio 2019。
此外,还使用了一些相关的编译工具和调试工具,如 GDB 等。
三、实验内容(一)词法分析器的实现词法分析是编译过程的第一步,其任务是将输入的源程序分解为一个个单词符号。
在本次实验中,我们使用有限自动机的理论来设计和实现词法分析器。
首先,定义了各种单词符号的类别,如标识符、关键字、常量、运算符等。
然后,根据这些类别设计了相应的状态转换图,并将其转换为代码实现。
在实现过程中,使用了正则表达式来匹配输入字符串中的单词符号。
对于标识符和常量等需要进一步处理的单词符号,使用了相应的规则进行解析和转换。
(二)语法分析器的实现语法分析是编译过程的核心环节之一,其任务是根据给定的语法规则,分析输入的单词符号序列是否符合语法结构。
在本次实验中,我们使用了递归下降的语法分析方法。
首先,根据实验要求定义了语法规则,并将其转换为相应的递归函数。
在递归函数中,通过对输入单词符号的判断和处理,逐步分析语法结构。
为了处理语法错误,在分析过程中添加了错误检测和处理机制。
当遇到不符合语法规则的输入时,能够输出相应的错误信息,并尝试进行恢复。
(三)语义分析及中间代码生成语义分析的目的是对语法分析得到的语法树进行语义检查和语义处理,生成中间代码。
在本次实验中,我们使用了三地址码作为中间代码的表示形式。
在语义分析过程中,对变量的定义和使用、表达式的计算、控制流语句等进行了语义检查和处理。
对于符合语义规则的语法结构,生成相应的三地址码指令。
四、实验步骤(一)词法分析器的实现步骤1、定义单词符号的类别和对应的正则表达式。
编译原理语义分析实验报告
实验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#输出结果八、收获(体会)与建议通过此次实验, 让我了解到如何设计、编制并调试语义分析程序, 加深了对语法制导翻译原理的理解, 掌握了将语法分析所识别的语法成分变换为中间代码的语义翻译方法。
编译原理语义分析实验报告 免费
编译原理综合训练语义分析实验报告指导老师:班级:学生:zeadom学号:学生:学号:2011/6/29目录语言文法的形式化描述 (3)语义规则 (3)运行环境介绍 (5)关键算法的流程图及文字解释 (5)1、本编译器的总框架 (5)2、在语义分析中的主要函数介绍 (5)3、产生布尔表达式 (7)4、While-do语句的语义分析 (8)5、词法、语法和语义分析的衔接 (8)测试报告 (8)附录 (12)语言文法的形式化描述(BNF范式)程序开始P->program i;SDn SC;定义语句SDn->SDSDn|nullSD->var int iSDTSDT -> null|,iSDT复合语句SC->begin Sn endSn->S;Sn||null单个语句S->SD|SA|SIF|SW|SC赋值语句SA->i:=E算术表达式E->cET|iET|(E)ETET->AE|CE|DE|null;C->+|-|*|/;布尔表达式B->EAEBT|NOT B|(B)BTBT->DB|nullA->>|<|=|>=|<=|<>D->AND|ORif语句SIF->if B then S SELSESELSE->null|else S2while语句SW->while B do S语义规则(属性文法)运行环境介绍运行环境是DEVC++Dev-C++是一个C&C++开发工具,它是一款自由软件,遵守GPL协议。
它集合了GCC、MinGW32等众多自由软件,并且可以取得最新版本的各种工具支持,而这一切工作都是来自全球的狂热者所做的工作,并且你拥有对这一切工具自由使用的权利,包括取得源代码等,前提是你也必须遵守GNU协议。
Dev-C++每一天都在进步着,因为它是一个自由软件。
编译原理_ 语义分析_实验报告
编译原理实验三语义分析实验报告◆学院:数学与计算机科学技术学院◆专业:计算机科学与技术◆班级:级计算机班◆小组组员:姓名:学号:姓名:学号:姓名:学号:姓名:学号:实验题目一、实验目的要求学生用与实验2相同的语言,编制语义分析程序。
二、实验准备微机CPU主频1.3G以上,128M内存,安装好C语言,PASCAL语言,或C++。
三、实验时间13学时四、实验内容要求学生用与实验2相同的语言,编制语义分析程序。
定义该语言的语义成分,将语义分析程序编制成子程序,在实验2分析出各语法单位后,分析其含义,并将可执行语句或表达式翻译为四元式输出,并将错误信息输出。
实验报告必须包括设计的思路,以及测试报告(输入测试例子,输出结果)。
五、上交文档1.实验报告(书面);2.程序文件(通过网络提交)。
<program> ::= <block> .<block> ::= <const-decl> <var-decl> <proc-decl> <statement><const-decl> ::= const <const-assignment-list> ; | ε<const-assignment-list> ::= <ident> = <number>| <const-assignment-list> , <ident> = <number><var-decl> ::= var <ident-list> ; |ε<ident-list> ::= <ident> | <ident-list> , <ident><proc-decl> ::= <proc-decl> procedure <ident> ; <block> ; |ε<statement> ::= <ident> := <expression>| call <ident>| begin <statement-list> end| if <condition> then <statement>| while <condition> do <statement>|ε<statement-list> ::= <statement> | <statement-list> ; <statement><condition> ::= odd <expression> | <expression> <relation> <expression><relation> ::= = | <> | < | > | <= | >=<expression> ::= <term> | <adding-operator> <term>| <expression> <adding-operator> <term><adding-operator> ::= + | -<term> ::= <factor> | <term> <multiplying-operator> <factor><multiplying-operator> ::= * | /<factor> ::= <ident> | <number> | ( <expression> )注意:(1) "ε" 表示空串。
编译原理实验报告语义分析
编译原理实验报告语义分析实验名称:语义分析实验目的: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. 识别并解析变量声明和赋值语句;2. 检查变量的重复声明和赋值类型的一致性;3. 计算并输出表达式的值。
二、实验环境和工具为了完成本次实验,我们需要准备以下环境和工具:1. 操作系统:Windows、Linux或MacOS;2. 编程语言:C++、Java或Python;3. 开发工具:编译器和调试器。
三、实验原理语义分析是编译过程中的重要环节,它主要负责对代码进行语义检查和语义解释。
在编译器中,语义分析器通常通过构建抽象语法树(AST)来实现。
AST是一种树状的数据结构,用于表示代码的语法结构和语义信息。
在语义分析的过程中,我们需要进行变量声明和赋值语句的解析和检查。
首先,我们需要识别代码中的变量声明和赋值语句,并将其转换成AST。
在解析过程中,我们需要检查变量的重复声明和赋值类型的一致性。
如果发现错误,我们需要报告相应的错误信息,并终止编译过程。
接下来,我们需要对表达式进行求值。
表达式是编程语言中的核心概念,它由操作数和运算符组成。
在求值过程中,我们需要考虑运算符的优先级和结合性。
为了实现这一功能,我们可以使用递归下降法或者使用运算符优先级算法。
四、实验过程1. 识别变量声明和赋值语句我们首先需要编写词法分析器,将代码中的字符序列转换成标记序列。
在词法分析的过程中,我们需要识别变量声明和赋值语句的关键字和标识符,并将其转换成相应的标记。
2. 构建抽象语法树在词法分析的基础上,我们可以构建抽象语法树。
北邮编译原理词法分析报告器实验
词法分析程序设计一.问题描述1.可以识别出用C语言编写的源程序中的每个单词符号,并以记号的形式输出每个单词符号。
2.可以并识别读取源程序中的注释。
3.可以统计源程序中的语句行数、单词个数和字符数,其中标点和空格不计为单词,并输出统计结果。
4.检察源程序中存在的错误,并可以报告错误所在行列的位置。
5.发现原程序中存在的错误,进行适当修复,使词法分析可以继续进行,通过一次词法分析处理,可以检查并报告源程序中存在的所有错误。
二.算法思想编写一个词法分析程序,它从左到右逐个字符的对源程序进行扫描,产生一个个的单词形成记号流文件输出。
其中,具体子问题有:(1)源程序文件读入缓冲区中(注意要删除空格和无用符号)(2)确定读入的为关键字还是运算符还是变量名,对于普通标识符和常量,分别建立标识符表和常量表当遇到一个标识符或常量时,查找标识符表或常量表,若存在,则返回位置,否则进入符号表或常量表中并返回表的入口地址。
(3)对于各类运算符、标点符号、以及注释符号等,准确识别出来并打印输出结果(4)对于源文件中出现的数字常量,不但能按要求加入常量表中,还进行了字符型到float型数值的转换,便于后续程序操作处理。
(4)尽量精简整合各种情况,使算法复杂度降低,精简易读。
三、实验程序设计说明1.主要函数说明void readChar();//读字符过程,每调用一次,从输入缓冲区读一个字符,并把它放入变量C 中,且向前扫描指针pointer指向下一个字符void ignoreSpace();//每次调用时,检查C中的字符是否为空字符,若是,则反复调用该过程,直到C进入一个非空字符为止void link();//把C中的字符与token中的字符串连接起来bool alphabet();//布尔函数,判断C中的字符是否为字母,若是则返回true,否则返回false bool digit();//布尔函数,判断C中的字符是否为数字,若是则返回true,否则返回false int searchForKeywords();//查关键字表,若此函数的返回值为0,则表示token中的字符串是标识符,否则为关键字int searchForToken();//查符号表,若此函数的返回值为0,则表示token中的字符串是新出现的,否则为已出现过的标识符int searchForNum(); //查常数表,若此函数的返回值为0,则表示token中的数字是新出现的,否则为已出现的常数void insertTokenList();//将标识符插入符号表void insertNumList();//将数字插入常数表void fillBuffer(int a);//填充buff的半区函数2.程序源代码#include<stdio.h>#include<stdlib.h>#include<string.h>#include<math.h>int pointer=0;//int i=0,j=0,c=0,appear,d=0,num_location;//int row_num=0,letter_num=0,word_num=0;int z=1;char C=' ';//char token[30];//char buff[4095];//char token_list[200][30];//char number[200][10];//char next_charac,charac,file_name[20];charkeywords[32][10]={"auto","break","case","char","const","continue","default","do"," double","else","enum","extern","float","for","goto","if","int","long","register"," return","short","signed","sizeo","fstatic","struct","switch","typedef","union","un signed","void","volatile","while"};double num;FILE *file_pointer;void fillBuffer(int a)//{//i=0;while((!feof(file_pointer))&& i<2048){//buff[a+i]=charac;if(charac!=' '){//if(charac=='\n'){row_num++;//}else{letter_num++;}}charac=fgetc(file_pointer);i++;}if(feof(file_pointer)){buff[a+i]='\0';}};void readChar()//{C=buff[pointer];if(pointer==1023){//fillBuffer(1024);//pointer++;//}else if(pointer==2047){//fillBuffer(0);//pointer==0;//}else{pointer++;}};void ignoreSpace()//{if(C==' '||C=='\n'||C=='\t'){ C=buff[pointer];if(pointer==1023){//fillBuffer(1024);// pointer++;//}else if(pointer==2047){// fillBuffer(0);//pointer=0;//}else{pointer++;}ignoreSpace();}};void link()//{token[j++]=C;};bool alphabet()//{if((C>=97 && C<=122)||(C>=65 && C<=90)){ return true;}else{return false;}};bool digit()//{if(C>=48 && C<=57){return true;}else{return false;}};int searchForKeywords()//{for(int x=0;x<32;x++){if(strcmp(token,keywords[x])==0){return 0;//}}return 1;};int searchForToken()//{int i=0;while(i<=c-1){if(strcmp(token,token_list[i])==0){ appear=i;return 0;}//i++;}word_num++;return 1;};int searchForNum()//{int i=0;while(i<=d-1){if(strcmp(token,number[i])==0){num_location=i;return 0;}//i++;}word_num++;return 1;};void insertTokenList()//{strcpy(token_list[c++],token);};void insertNumList()//{strcpy(number[d++],token);};main(){printf("输入源文件的路径:\n");scanf("%s",file_name);file_pointer=fopen(file_name,"r");if(file_pointer==NULL) printf("无法查找到文件,发生错误!\n");//charac=fgetc(file_pointer);fillBuffer(0);//while(C!='\0'){readChar();//ignoreSpace();//switch(C){//case 65:case 66:case 67:case 68:case 69:case 70:case 71:case 72: case 73:case 74:case 75:case 76:case 77:case 78:case 79:case 80:case 81:case 82:case 83:case 84:case 85:case 86:case 87:case 88:case 89:case 90:case 97: case98:case99:case100:case101:case102:case103:case104:case105:case106: case 107:case 108:case 109:case 110:case 111:case 112:case 113:case 114:case 115:case 116:case 117:case 118:case 119:case 120:case 121:case 122:case '_'://ǰזΪזĸʽזϟwhile(alphabet()||digit()||C=='_'){//link();//readChar();//}//token[j]='\0';//j=0;//pointer--;//if(searchForKeywords()==1){//if(searchForToken()==1){//insertTokenList();//printf("< ID, %d >\n",c-1);}else{printf("< ID, %d >\n",appear);}//}else{printf("< %s, ז >\n",token);//}break;case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57: num=(C-48);link();readChar();while(digit()){link();num=num*10+(C-48);//readChar();}if(C=='.'){link();readChar();while(digit()){link();num=num+(C-48)*pow(0.1,z++);// readChar();}}token[j]='\0';//j=0;//pointer--;if(searchForNum()==1){//insertNumList();//printf("< %f, %d >\n",num,d-1);}else{printf("< %f, %d >\n",num,num_location);}//break;case '+':readChar();if(C=='='){printf("< +=, 赋值运算符 >\n");}else if(C=='+'){printf("< ++, 自加>\n");}else{pointer--;printf("< +, 加号 >\n");}break;case '-':readChar();if(C=='-'){printf("< --, 自减>");}else if(C=='='){printf("< -= , 赋值运算符>\n");}else{pointer--;printf("< -, 减号 >\n");}break;case '*':printf("< *, 乘号 >\n");break;case '/':readChar();if(C=='*'){readChar();next_charac=buff[pointer];while(C!='*' && next_charac!='/'){readChar();next_charac=buff[pointer];}readChar();printf("< /*, 多行注释 >\n");}else if(C=='/'){readChar();while(C!='\n'){readChar();}printf("< //, 单行注释 >\n");}else{pointer--;printf("< /, 除号 >\n");}break;case '%':printf("< %, 取模 >\n");break;case '(':printf("< (, 左小括号 >\n");break;case ')':printf("< ), 右小括号 >\n");break;case '[':printf("< [, 左中括号 >\n");break;case ']':printf("< ], 右中括号 >\n");break;case '{':printf("< {, -左大括号 >\n");break;case '}':printf("< }, 右大括号 >\n");break;case ':':printf("< :, 冒号 >\n");break;case ';':printf("< ;, 分号 >\n");break;case ',':printf("< , 逗号 >\n");break;case '.':printf("< ., 句号 >\n");break;case '?':printf("< ?, 问号 >\n");break;case '"':printf("< "", 引号 >\n");break;case '#':printf("< #, 井号 >\n");break;case '>':readChar();if(C=='='){printf("< >=, 大于等于 >\n");}pointer--;printf("< >, 大于 >\n");}break;case '<':readChar();if(C=='='){printf("< <=, 小于等于 >\n");}else{pointer--;printf("< <, 小于 >\n");}break;case '=':readChar();if(C=='='){printf("< ==, 判等 >\n");}else{pointer--;printf("< =, 赋值等 >\n");}break;case '&':readChar();if(C=='&'){printf("< &&, 且 >\n");}else{pointer--;printf("< &, 取地址符 >\n");}break;case '|':readChar();if(C=='|'){printf("< ||, 或 >\n");}else{pointer--;printf("< |, 运算符 >\n");}case '!':readChar();if(C=='='){printf("< !=, 不等 >\n");}else{pointer--;printf("< !, 非 >\n");}break;}}printf("该源文件的行数为:%d,单词数为%d,字符数为%d.\n",row_num,word_num,letter_num);system("pause");return 0;}3.程序的执行结果测试程序为:运行结果为:四、有待改进的地方。
编译原理语义分析报告
《编译原理》实验报告专业班级_软工1502 姓名_赵翘楚_ 学号_20151107062_1.题目要求:1.1实验目的通过上机实习,加深对语法制导翻译原理的理解,掌握将语法分析所识别的语法成分变换为中间代码的语义翻译方法。
1.2实验原理采用递归下降语法制导翻译法,对算术表达式、赋值语句进行语义分析并生成四元式序列。
2.算法分析2.1主程序示意图置初值调用scaner调用lrparser输出四元组结束图12.2设置语义过程emit(char *result,char *arg1,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.3函数lrparser在原来语法分析的基础上插入相应的语义动作:将输入串翻译成四元式序列。
在实验中我们只对表达式、赋值语句进行翻译。
3、实验步骤#include "stdio.h"#include "string.h"#include "stdlib.h"char prog[100],token[8],ch;char*rwtab[6]={"begin","if","then","while","do"," end"};int syn,p,m,n,sum,q;int kk;struct { char result1[8];char ag11[8];char op1[8];char ag21[8];} quad[20];char *factor();char *expression();int yucu();char *term();int statement();int lrparser();char *newtemp();scaner();emit(char *result,char *ag1,char *op,char *ag2);void main(){ int j; q=p=kk=0;printf("\nplease input a string (end with '#'): ");do{ scanf("%c",&ch);prog[p++]=ch;}while(ch!='#');p=0;scaner();lrparser();if(q>19)printf(" to long sentense!\n"); elsefor(j=0;j<q;j++)printf("%s=%s%s%s\n\n", quad[j].result1,quad[j].ag11,quad[j].op1,quad[j].ag21);//getch();}int lrparser(){ int schain=0;kk=0;if (syn==1){ scaner(); //读下一个单词符号schain=yucu(); //调用语句串分析函数进行分析if(syn==6){ scaner(); //读下一个单词符号if((syn==0)&&(kk==0))printf("Success!\n"); //输出(“success”)}else { if(kk!=1)printf("short of 'end' !\n"); //输出 ‘缺end ’ 错误kk=1; // getch(); exit(0); } } else { printf("short of 'begin' !\n"); //输出’begin ’错误kk=1; // getch(); exit(0); } return (schain); } int yucu() { int schain=0; schain=statement(); //调用语句分析函数进行分析 while(syn==26) { scaner(); //读下一个单词符号 schain=statement(); //调用语句分析函数进行分析 } return (schain); } int statement() { char tt[8],eplace[8]; int schain=0; if (syn==10) { strcpy(tt,token); scaner(); if(syn==18) { scaner(); //读下一个单词符号strcpy(eplace,expression()); emit(tt,eplace,"",""); schain=0; } else { printf("short of sign ':=' !\n"); //输出’缺少赋值号’的错误kk=1; // getch(); exit(0); } return (schain); } } char *expression() { 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 分析产生表达式计算的第一项eplace while((syn==13)||(syn==14)) { if (syn==13)strcpy(tt,"+"); //操作符 tt= ‘+’或者‘—’ else strcpy(tt,"-"); scaner(); //读下一个单词符号 strcpy(ep2,term()); //调用term 分析产生表达式计算的第二项ep2 strcpy(tp,newtemp()); //调用newtemp 产生临时变量tp 存储计算结果 emit(tp,eplace,tt,ep2); //生成四元式送入四元式表 strcpy(eplace,tp); } return (eplace); } char *term() //仿照函数expression 编写 { 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==15)||(syn==16)) { if (syn==15)strcpy(tt,"*"); else strcpy(tt,"/"); scaner(); //读下一个单词符号 strcpy(ep2,factor());strcpy(tp,newtemp()); emit(tp,eplace,tt,ep2); strcpy(eplace,tp); } return (eplace);}char *factor(){ char *fplace;fplace=(char *)malloc(12);strcpy(fplace,"");if(syn==10){ strcpy(fplace,token);scaner(); //读下一个单词符号}else if(syn==11){ itoa(sum,fplace,10);scaner(); //读下一个单词符号}else if(syn==27){ scaner(); //读下一个单词符号fplace=expression(); //调用expression分析返回表达式的值if(syn==28) scaner(); //读下一个单词符号else { printf("error on ')' !\n");kk=1;// getch();exit(0);}}else { printf("error on '(' !\n");kk=1;// getch();exit(0);}return (fplace);}char *newtemp(){ char *p;char m[8];p=(char *)malloc(8);kk++;itoa(kk,m,10);strcpy(p+1,m);p[0]='t';return(p);}scaner(){ sum=0;for(m=0;m<8;m++)token[m++]=NULL;m=0;ch=prog[p++];while(ch==' ')ch=prog[p++];if(((ch<='z')&&(ch>='a'))||((ch<='Z')&&(ch>= 'A'))){ while(((ch<='z')&&(ch>='a'))||((ch<='Z')&& (ch>='A'))||((ch>='0')&&(ch<='9'))){token[m++]=ch;ch=prog[p++];}p--;syn=10;token[m++]='\0';for(n=0;n<6;n++)if(strcmp(token,rwtab[n])==0){ syn=n+1;break;}}else if((ch>='0')&&(ch<='9')){ while((ch>='0')&&(ch<='9')){ sum=sum*10+ch-'0';ch=prog[p++];}p--;syn=11;}else switch(ch){ case '<':m=0;ch=prog[p++];if(ch=='>'){ syn=21;}else if(ch=='='){ syn=22;}else{ syn=20;p--;}break;case '>':m=0;ch=prog[p++];if(ch=='='){ syn=24;}else{ syn=23;p--;}break;case ':':m=0;ch=prog[p++];if(ch=='='){ syn=18;}else{ syn=17;p--;}break;case '+': syn=13; break; case '-': syn=14; break;case '*': syn=15;break;case '/': syn=16;break;case '(': syn=27;break;case ')': syn=28;break;case '=': syn=25;break;case ';': syn=26;break;case '#': syn=0;break;default: syn=-1;break;}}emit(char *result,char *ag1,char *op,char *ag2){strcpy(quad[q].result1,result);strcpy(quad[q].ag11,ag1);strcpy(quad[q].op1,op);strcpy(quad[q].ag21,ag2);q++;}4、实验结果实验的输入和输出:输入是语法分析提供的正确的单词串,输出为三地址指令形式的四元式序列。
北邮编译原理词法分析报告程序报告材料
程序设计一词法分析程序一.实验题目和要求题目:词法分析程序的设计与实现。
实验内容:设计并实现C语言的词法分析程序,要求如下。
(1)、可以识别出用C语言编写的源程序中的每个单词符号,并以记号的形式输出每个单词符号。
(2)、可以识别并读取源程序中的注释。
(3)、可以统计源程序汇总的语句行数、单词个数和字符个数,其中标点和空格不计算为单词,并输出统计结果(4)、检查源程序中存在的错误,并可以报告错误所在的行列位置。
(5)、发现源程序中存在的错误后,进行适当的恢复,使词法分析可以继续进行,通过一次词法分析处理,可以检查并报告源程序中存在的所有错误。
实验要求:方法1:采用C/C++作为实现语言,手工编写词法分析程序。
方法2:通过编写LEX源程序,利用LEX软件工具自动生成词法分析程序。
二.程序设计思路采用C++来编写此程序。
根据书上的函数、变量提示写出各种函数、整体框架。
大部分变量名称与书上相同。
画出符号间转换自动机模型,之后根据自动机写函数、错误判断。
缓冲区用数组完成,标记位置的指针用int型来表示。
用lnum存储语句行数,wordnum存储单词个数,charnum存储字符个数。
标点和空格不计算为单词。
错误所在的行列位置存储在error.txt文件当中。
三.程序运行结果举例Code.txt:#include<stdio.h>main(){int num,n=0,m,l,t;printf("please input an integer:");scanf("%d",&num); //dsfsdffor(l=0;num!=0;l++){m=num%10; //sdfafdafor(t=0;t!=l;t++)m=m*2; //dafdafn=nm;num=num/10; /*dafdas2323*/}printf("//the result is %d //",n);return 0 ;}窗口运行结果:============================================================= *词法分析系统*=============================================================请输入需要分析的文件名称:code.txt------------------------------------------------------------- 处理完毕。
编译原理语义实验报告
编译原理语义实验报告编译原理语义实验报告引言:编译原理是计算机科学中的重要课程之一,它研究的是如何将高级程序语言转化为机器语言,使得计算机能够理解并执行程序。
语义分析是编译过程中的重要环节,它负责对程序的语义进行分析和处理。
本实验报告将介绍我们在编译原理课程中进行的语义实验,并分享我们的实验结果和心得体会。
实验目的:本次实验的主要目的是掌握语义分析的基本原理和方法,了解如何构建语法树以及如何进行类型检查和语义规则的验证。
通过实验,我们将能够更好地理解编译器是如何对程序进行处理和优化的。
实验环境和工具:为了完成本次实验,我们使用了一些常见的编程语言和工具。
其中,我们选择了C语言作为实验的目标语言,并使用了Flex和Bison作为词法分析器和语法分析器的生成工具。
此外,我们还使用了一些辅助工具和库,如LLVM和GCC 等。
实验过程:在实验过程中,我们首先需要设计和实现一个简单的编程语言,包括其语法和语义规则。
然后,我们使用Flex和Bison来生成词法分析器和语法分析器,并通过这些工具将源代码转换为语法树。
接下来,我们对语法树进行类型检查和语义规则的验证,以确保程序的正确性和合法性。
最后,我们将生成的中间代码转化为目标代码,并进行优化和生成可执行文件。
实验结果:通过实验,我们成功地设计和实现了一个简单的编程语言,并使用Flex和Bison生成了相应的词法分析器和语法分析器。
我们还实现了类型检查和语义规则的验证,确保了程序的正确性和合法性。
最终,我们成功地将生成的中间代码转化为目标代码,并生成了可执行文件。
实验心得:通过本次实验,我们深入理解了编译原理中的语义分析过程。
我们学会了如何构建语法树,并对其进行类型检查和语义规则的验证。
我们还学会了使用一些常见的编程语言和工具,如C语言、Flex、Bison等。
通过实验,我们不仅提高了自己的编程能力,还加深了对编译原理的理解和认识。
结论:编译原理是计算机科学中的重要课程,语义分析是编译过程中的关键环节。
北邮编译原理实验 LR语法分析 实验报告
LR语法分析实验报告班级:2010211308 姓名:杨娜学号:10211369一.题目:LR语法分析程序的设计与实现二.设计目的:(1)了解语法分析器的生成工具和编译器的设计。
(2)了解自上而下语法分析器的构造过程。
(3). 理解和掌握LR语法分析方法的基本原理;根据给出的LR)文法,掌握LR分析表的构造及分析过程的实现。
(4)掌握预测分析程序如何使用分析表和栈联合控制实现LR分析。
三.实验内容:编写语法分析程序,实现对算术表达式的语法分析,要求所分析算数表达式由如下的文法产生:E->E+T|E-T|TT->T/F|T*F|FF->i|n|(E)四.实验要求:编写LR语法分析程序,要求如下:(1)构造识别所有活动的DFA(2)构造LR分析表(3)编程实现算法4.3,构造LR分析程序五.算法流程分析程序可分为如下几步:六.算法设计1.数据结构s :文法开始符号line :产生式的个数G[i][0] :产生式的标号Vt[] :终结符Vn[] :非终结符id :项目集编号Prjt *next :指示下一个项目集Prjt[]:存储项目的编号,prjt[0]项目编号的个数Pointafter[] :圆点后的字符,pointafter[0]为字符个数Prjset*actorgo[]:存储出度Pointbefore:圆点前面的字符Form:动态数组下标,同时作为符号的编号Vn[] :非终结符序列Vt[]:终结符序列2.LR分析器由三个部分组成(1)总控程序,也可以称为驱动程序。
对所有的LR分析器总控程序都是相同的。
(2)分析表或分析函数,不同的文法分析表将不同,同一个文法采用的LR分析器不同时,分析表将不同,分析表又可以分为动作表(ACTION)和状态转换(GOTO)表两个部分,它们都可用二维数组表示。
(3)分析栈,包括文法符号栈和相应的状态栈,它们均是先进后出栈。
分析器的动作就是由栈顶状态和当前输入符号所决定。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
编译原理第六章语义分析目录1. 实验题目和要求 (2)2. 实验分析和思考 (3)3. 翻译方案 (4)4. LR实现自底向上分析(摘自语法分析实验) (5)4.1.构造识别所有活前缀的DFA (5)5.1. 扩充分析栈 ................................................................................................................ 7 5.2. 改造分析程序 ............................................................................................................ 7 5.3. 编程实现 .................................................................................................................... 76.运行结果截图: (13)1. 实验题目和要求题目:语义分析程序的设计与实现。
实验内容:编写语义分析程序,实现对算术表达式的类型检查和求值。
要求所分析算术表达式由如下的文法产生。
numE idF F F T F T T T T E T E E |)(||/|*||→→-+→ 实验要求:用自底向上的语法制导翻译技术实现对表达式的分析和翻译。
(1) 写出满足要求的语法制导定义或翻译方案。
(2) 编写分析程序,实现对表达式的类型进行检查和求值,并输出: ① 分析过程中所有产生式。
② 识别出的表达式的类型。
③ 识别出的表达式的值。
(3) 实验方法:可以选用以下两种方法之一。
① 自己编写分析程序。
② 利用YACC 自动生成工具。
2.实验分析和思考由于要求进行类型检查和求值,所以可以定义两个综合属性,一个记录值一个记录类型,存放在结构中,一并传入传出。
输出的产生式可以作为虚拟综合属性,在产生式的最后打印出来。
id认为是定义的变量名,假设是26个小写字母,它们的值存于一个数组里。
将类型检查和求值归于一次扫描,当检查类型出错时则停止,否则继续。
哈希实现输入的映射,模拟词法分析的记号流。
输入格式为每个num和id对应两个输入字符,其他运算符仍对应一个字符。
比如第4个num,输入为num4。
由于只具有综合属性,故可以用S属性的自底向上翻译实现,利用LR分析程序来实现,只需扩充分析站和改造分析程序。
PS:这次实验我只是简单模拟了最简单的显式严格匹配,即没有实现隐式类型转换。
3. 翻译方案}..),"int(",..{}..),)"(int(",..){(}..),"int(",..{}..),"int(",..{};_.;..)..({)}"/int(",./..{/};_.;..)..({)}"*int(",.*..{*}..),"int(",..{};_.;..)..({)}"int(",...{};_.;..)..({)}"int(",...{111111111111type num type F num F pr val num val F num F type E type F E F pr val E val F E F type id type F id F pr val id val F id F type F type T F T pr val F val T F T error type type T elsetype F type T type F type T if F T T pr val F val T val T F T T error type type T elsetype F type T type F type T if F T T pr val F val T val T F T T type T type E T E pr val T val E T E error type type E elsetype T type E type T type E if T E E pr val T val E val E T E E error type type E elsetype T type E type T type E if T E E pr val T val E val E T E E =→=→=→=→=→=→=→=→====→=→====→=→=→=→====-→-=-→====+→+=+→4. LR 实现 自底向上分析(摘自语法分析实验)4.1. 构造识别所有活前缀的DFA构造扩展文法 E E →'numE idF F F T F T T T T E T E E |)(||/|*||→→-+→ FIRST 和FOLLOW 集如下ETFFIRST id, (, num id, (, num id, (, num FOLLOW$, ), +, -$, ), +, -, *, /$, ), +, -, *, /构造识别所有活前缀的DFA 如下4.2. 构造LR 分析表T E E +→ (1) F T T *→ (4) id F → (7)T E E -→ (2) F T T /→ (5) )(E F → (8) T E → (3) F T → (6) num F → (9)5.S属性定义的自底向上实现5.1.扩充分析栈多定义一个结构栈数组,结构里有两个变量,一个为val, 一个为type。
实现时,val其实是定义了两个变量,一个表示int时的值,一个表示real时的值,因为无法公用一个类型的变量。
定义type只有三种,一种为int, 一种为real, 一种为type_error。
val由外部提供。
可通过数组搜索。
5.2.改造分析程序在归约时完成类型检查和求值。
之所以与归约联系,是因为每一次归约决定着所用的是哪一个产生式。
acc时打印最终求值结果和表达式类型。
5.3.编程实现#include <cmath>#include <stack>#include <vector>#include <string>#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>#include <algorithm>using namespace std;const int S =1;//移进const int R =2;//归约const int ACC =3;//分析成功const int Vt_num =9;//终结符和$数const int Vn_num =3;//非终结符数const int State_num =17;//状态数const int formula_num =10;//扩展文法产生式数目const int Max_input =1024;//输入记号流长度const int max_stack =2500;//栈的最大高度int token[Max_input];//记号流int len;//记号流长度int pointer;//定义指向输入串的指针stack<int> st;//定义栈struct action{int rs; //初始化表项的动作为0即出错,R归约S移进ACC成功int no;}act[State_num][Vt_num];//action表表项int gto[State_num][Vn_num];//goto表表项struct attri{int type;//int-1, real-2, type_error-0int i_val;double r_val;}val[max_stack];int v_top;void initial_table(){//初始化分析表memset(act,0,sizeof(act));memset(gto,-1,sizeof(gto));//动作表actionact[0][4]={S,4}; act[0][5]={S,6}; act[0][6]={S,5};act[1][0]={S,7}; act[1][1]={S,8}; act[1][8].rs = ACC;act[5][4]={S,4}; act[5][5]={S,6}; act[5][6]={S,5};act[7][4]={S,4}; act[7][5]={S,6}; act[7][6]={S,5};act[8][4]={S,4}; act[8][5]={S,6}; act[8][6]={S,5};act[9][4]={S,4}; act[9][5]={S,6}; act[9][6]={S,5};act[10][4]={S,4}; act[10][5]={S,6}; act[10][6]={S,5};act[11][0]={S,7}; act[11][1]={S,8}; act[11][7]={S,16};act[3][0]= act[3][1]= act[3][2]= act[3][3]= act[3][7]= act[3][8]={R,6};act[4][0]= act[4][1]= act[4][2]= act[4][3]= act[4][7]= act[4][8]={R,7};act[6][0]= act[6][1]= act[6][2]= act[6][3]= act[6][7]= act[6][8]={R,9};act[14][0]= act[14][1]= act[14][2]= act[14][3]= act[14][7]= act[14][8]={R,4};act[15][0]= act[15][1]= act[15][2]= act[15][3]= act[15][7]= act[15][8]={R,5};act[16][0]= act[16][1]= act[16][2]= act[16][3]= act[16][7]= act[16][8]={R,8};act[2][2]={S,9}; act[2][3]={S,10};act[2][0]= act[2][1]= act[2][7]= act[2][8] ={R,3};act[12][2]={S,9};act[12][3]={S,10};act[12][0]=act[12][1]=act[12][7]=act[12][8]= {R,1};act[13][2]={S,9};act[13][3]={S,10};act[13][0]=act[13][1]=act[13][7]=act[13][8]= {R,2};gto[11][2]=16;gto[7][1]=12; gto[7][2]=3;gto[8][1]=13; gto[8][2]=3;gto[5][0]=11; gto[5][1]=2; gto[5][2]=3;gto[0][0]=1; gto[0][1]=2; gto[0][2]=3;//产生式存入fm数组//记录产生式对应的左部的非终结符f_vn//记录产生式右部的长度flenfm[1]="E -> E+T \n"; f_vn[1]=0; flen[1]=3;fm[2]="E -> E-T \n"; f_vn[2]=0; flen[2]=3;fm[3]="E -> T \n"; f_vn[3]=0; flen[3]=1;fm[4]="T -> T*F \n"; f_vn[4]=1; flen[4]=3;fm[5]="T -> T/F \n"; f_vn[5]=1; flen[5]=3;fm[6]="T -> F \n"; f_vn[6]=1; flen[6]=1;fm[7]="F -> id \n"; f_vn[7]=2; flen[7]=1;fm[8]="F -> (E) \n"; f_vn[8]=2; flen[8]=3;fm[9]="F -> num \n"; f_vn[9]=2; flen[9]=1;}/*初始化num和id表项的值*/void initial_entry(){//id: A-M为int,N-Z为real//num:a-m为int,n-z为real//值为A/a:0, N/n:0.00}void lexi_input(){//调用词法分析程序//+ - * / id num ( ) $分别对应从0到8的整数//A-Z为id(4), a-z为num(5)//'a'-97, 'A'-65//处理输入字符串将记号流存到token[]数组里//并将记号流长度赋给len//eg: (a+b)*c/(L-E)//token={6, 97, 0, 98, 7, 2, 99, 3, 6, 76, 1, 69, 7};//len=13;//eg:O-N+n//token={79, 1, 78, 0, 110};//len=5;//eg:O-M+mvoid error(){puts("E R R O R ");//错误处理程序}int main(){initial_table();initial_entry();lexi_input();token[len]=Vt_num-1;len++;while(!st.empty())st.pop();//清空栈st.push(0);//0状态入栈pointer=0;//指针指向输入记号流的第一个记号v_top=1;//属性值指针int cur_state, cur_token;int i, j;do{cur_state = st.top();//栈顶状态cur_token = token[pointer];//当前指针指向的输入符号if(cur_token>='a'&& cur_token<='z') cur_token=5;else if(cur_token>='A'&& cur_token<='Z') cur_token=4;if(act[cur_state][cur_token].rs == S){/*移进,只需让val也同步移进*/st.push(cur_token);st.push(act[cur_state][cur_token].no);if(cur_token==5){if(token[pointer]<'n')val[v_top].type=1,val[v_top].i_val=token[pointer]-'a';else val[v_top].type=2, val[v_top].r_val=token[pointer]-'a'+0.0;}else if(cur_token==4){if(token[pointer]<'N')val[v_top].type=1,val[v_top].i_val=token[pointer]-'A';else val[v_top].type=2, val[v_top].r_val=token[pointer]-'A'+0.0;pointer++;printf("s%d\n",act[cur_state][cur_token].no);}else if(act[cur_state][cur_token].rs == R){/*归约,检查类型并计算属性值*/j=act[cur_state][cur_token].no;i=2*flen[j];while(i-->0){st.pop();}printf("r%d ", act[cur_state][cur_token].no); cout<<fm[j];cur_state=st.top();st.push(f_vn[j]+ Vt_num);st.push(gto[cur_state][f_vn[j]]);if(j==1)//E->E+T{if(val[v_top-2].type==val[v_top-6].type){if(val[v_top-6].type==1)val[v_top-6].i_val+=val[v_top-2].i_val;elseval[v_top-6].r_val+=val[v_top-2].r_val; v_top-=4;}else{printf("TYPE_ERROR \n");break;}}else if(j==2)//E->E-T{if(val[v_top-2].type==val[v_top-6].type){if(val[v_top-6].type==1)val[v_top-6].i_val-=val[v_top-2].i_val;elseval[v_top-6].r_val-=val[v_top-2].r_val; v_top-=4;}else{printf("TYPE_ERROR \n");break;}}else if(j==4)//T->T*F{if(val[v_top-2].type==val[v_top-6].type){if(val[v_top-6].type==1)val[v_top-6].i_val*=val[v_top-2].i_val;elseval[v_top-6].r_val*=val[v_top-2].r_val;v_top-=4;}else{printf("TYPE_ERROR \n");break;}}else if(j==5)//T->T/F{if(val[v_top-2].type==val[v_top-6].type){if(val[v_top-6].type==1)val[v_top-6].i_val/=val[v_top-2].i_val;elseval[v_top-6].r_val/=val[v_top-2].r_val;v_top-=4;}else{printf("TYPE_ERROR \n");break;}}else if(j==8)//F->(E){val[v_top-6]=val[v_top-4];v_top-=4;}}else if(act[cur_state][cur_token].rs == ACC){/*表达式类型检查无误,输出类型及值*/puts("S U C C E S S ");printf("The expression type is ");if(val[v_top-2].type==1)printf("integer");else printf("real");printf(", the value is ");if(val[v_top-2].type==1)printf("%d\n\n", val[v_top-2].i_val);else printf("%lf\n\n", val[v_top-2].r_val);break;}else{error();break;}}while(1);return0;}6.运行结果截图:①输入符号串为O-N+n即token={79, 1, 78, 0, 110};len=5;②输入符号串为(a+b)*c/(L-E)即token={6, 97, 0, 98, 7, 2, 99, 3, 6, 76, 1, 69, 7};len=13;③输入符号串O-M+m即token={79, 1, 77, 0, 109};len=5;。