安徽大学编译原理试验斯
安徽工业大学编译原理实验报告
编译原理实验报告姓名:叶玉虎班级:计122班指导老师:王森玉实验日期:2015/5/11实验内容:1.求出每个非终结符的FIRST集合2.求出每个产生式右部的FIRST集合3.求出每个非终结符的Follow集合实验环境:Visual Studio2010实验目的:让同学们掌握FIRST集合和FOLLOW集合的求法实验代码:#include<stdio.h>#include<string.h>#define MAX 50char css[MAX][MAX];//保存所有的产生式int count=0;int cnt=0;struct L{//保存所有的终结符char ch;int flag;//1:能推出ε,0:不能,初值:-1int num;char first[MAX];int s;//first的长度char follow[MAX];int l;//follow的长度}l[MAX];//对输入的格式进行控制,并校验输入是否符合格式int handle(char a[]){int len,i=0,j,k;len=strlen(a);while(a[i]!=10){if(a[i]=='$')return 2;if((' '==a[i])||(9==a[i])){i++;continue;}if((a[i]>='A')&&(a[i]<='Z')){if((a[i+1]!='-')||(a[i+2]!='>')){printf("产生式格式错误\n");return -1;}else{j=i;k=0;while((a[j]!=' ')&&(a[j]!=9)&&(a[j]!='$')&&(a[j]!=10)){if(a[j]=='|'){css[count][k]='\0';count++;if((a[j+1]=='')||(a[j]==9)||(a[j]=='$')||(a[j]==10)){printf("产生式格式错误\n");return 0;}css[count][0]=a[i];css[count][1]=a[i+1];css[count][2]=a[i+2];k=3;j++;continue;}css[count][k]=a[j];k++;j++;}css[count][k]='\0';i=j;count++;}}else{printf("产生式格式错误\n");return -1;}}return 0;}//从键盘获得输入int input(){char a[MAX*MAX];int v;printf("输入产生式,产生式之间以空格回车或Tab键分隔,并以$键结束.\n");printf("用@表示虚拟符号ε,终结符用大写字母表示,其他字符表示非终结符\n");while(1){fgets(a,MAX*MAX,stdin);v=handle(a);if(v==-1)return -1;if(v==2)return 0;}}//求出能推出ε的非终结符void seekEmpty(){int i,j,k,t;int flag=0,flag2=0;int len,c;char a[MAX][MAX],ch;for(i=0;i<count;i++){strcpy(a[i],css[i]);}//求出含有的非终结符的个数,并把各终结符保存起来for(i=0;i<count;i++){for(j=0;j<cnt;j++){if(l[j].ch==a[i][0]){l[j].num++;flag=1;break;}elseflag=0;}if((!cnt)||(!flag)){l[cnt].ch=a[i][0];l[cnt].flag=-1;l[cnt].num=1;l[cnt].s=0;l[cnt].l=0;cnt++;flag=1;continue;}}c=count;while(c){for(i=0;i<c;i++){//如果该终结符推出ε,从a[]中删除所有带有该终结符的产生式if(a[i][3]=='@'){ch=a[i][0];for(j=0;j<c;j++){if(ch==a[j][0]){if(j!=c-1){for(k=j;k<c-1;k++)strcpy(a[k],a[k+1]);c--;j--;}else{c--;j--;}}}for(j=0;j<cnt;j++){if(ch==l[j].ch){l[j].flag=1;break;}}i--;continue;}len=strlen(a[i]);for(j=3;j<len;j++){//当该产生式右边含有非终结符时从a[]中删除该条记录if((a[i][j]<'A')||(a[i][j]>'Z')){flag2=1;break;}}if(flag2){for(k=0;k<cnt;k++){if(a[i][0]==l[k].ch){l[k].num--;if(l[k].num==0)l[k].flag=0;break;}}if(i!=c-1)for(k=i;k<c-1;k++){strcpy(a[k],a[k+1]);}c--;i--;flag2=0;continue;}//如果产生式右边为非终结符看看该终结符能不能推出εfor(j=3;j<len;j++){if((a[i][j]>='A')&&(a[i][j]<='Z')){for(k=0;k<cnt;k++){if(a[i][j]==l[k].ch){if(l[k].flag==0){flag2=1;break;}else if(l[k].flag==1){for(t=j;t<len-1;t++)a[i][t]=a[i][t+1];a[i][len-1]='\0';j--;len--;break;}break;}}if(flag2)break;}}if(a[i][3]=='\0'){ch=a[i][0];for(j=0;j<c;j++){if(ch==a[j][0]){if(j!=c-1){for(k=j;k<c-1;k++)strcpy(a[k],a[k+1]);c--;j--;}else{c--;j--;}}}i--;for(k=0;k<cnt;k++){if(ch==l[k].ch){l[k].flag=1;break;}}}if(flag2){for(k=0;k<cnt;k++){if(a[i][0]==l[k].ch){l[k].num--;if(l[k].num==0)l[k].flag=0;}}if(i!=c-1)for(k=i;k<c-1;k++){strcpy(a[k],a[k+1]);}c--;i--;flag2=0;continue;}}}}//求每个非终结符的First集合void seekFirstVn(){int i,j,k,t,t1,t2,c,item;int len,s,flag=0,flag2=0,fchange;char a[MAX][MAX],ch[MAX];for(i=0;i<count;i++){strcpy(a[i],css[i]);}c=count;while(1){fchange=0;for(i=0;i<c;i++){//右部为ε,将ε并入到左部的First中if(a[i][3]=='@'){/*for(j=0;j<cnt;j++){if(l[j].ch==a[i][0]){for(k=0;k<l[j].s;k++)if(l[j].first[k]==a[i][3]){flag=1;break;}if(!flag){l[j].first[l[j].s]=a[i][3];l[j].s++;l[j].first[l[j].s]='\0';fchange=1;break;}flag=0;}}*///从当前列表a[]中删除if(i!=c-1)for(j=i;j<c-1;j++)strcpy(a[j],a[j+1]);c--;i--;continue;}len=strlen(a[i]);//产生式右边符号为终结符时,将该终结符并入到左部的First集合中for(j=3;j<len;j++){if((a[i][j]<'A')||(a[i][j]>'Z')){for(k=0;k<cnt;k++){if(a[i][0]==l[k].ch){for(t=0;t<l[k].s;t++){if(a[i][j]==l[k].first[t]){flag=1;break;}}if(!flag){l[k].first[l[k].s]=a[i][j];l[k].s++;l[k].first[l[k].s]='\0';fchange=1;}flag=0;break;}}//从a[][]中删除该条产生式if(i!=c-1)for(k=i;k<c-1;k++)strcpy(a[k],a[k+1]);c--;i--;break;}//产生式右边符号为非终结符时else if((a[i][j]>='A')&&(a[i][j]<='Z')){/*将该非终结符的FIRST集合除去ε并入到当前非终结符的FIRST集合中*/for(k=0;k<cnt;k++){if(a[i][j]==l[k].ch){for(t=0;t<cnt;t++){if(a[i][0]==l[t].ch){for(t1=0;t1<l[k].s;t1++){for(t2=0;t2<l[t].s;t2++){if(l[k].first[t1]==l[t].first[t2]){break;}}if((t2==l[t].s)&&(l[k].first[t1])!='@'){fchange=1;l[t].first[l[t].s]=l[k].first[t1];l[t].s++;l[t].first[l[t].s]='\0';}}break;}}break;}}if(l[k].flag)continue;elsebreak;}}}if(!fchange){for(i=0;i<cnt;i++){if(l[i].flag){l[i].first[l[i].s]='@';l[i].s++;l[i].first[l[i].s]='\0';}printf("FIRST(%c): %s\n",l[i].ch,l[i].first);}printf("\n");break;}}}//求产生式右部的First集合void seekFirstRight(){struct Right{char a[MAX];char first[MAX];int s;}r[MAX];int i,j,k,t;int cnt=0,len,len1,flag=0;for(i=0;i<count;i++){for(j=0;j<cnt;j++){if(!strcmp(css[i]+3,r[j].a)){flag=1;break;}}if(flag){flag=0;continue;}strcpy(r[j].a,css[i]+3);r[j].s=0;cnt++;}for(i=0;i<cnt;i++){len=strlen(r[i].a);for(j=0;j<len;j++){//遇到终结符if(r[i].a[j]=='@'){r[i].first[r[i].s]='@';r[i].s++;r[i].first[r[i].s]='\0';break;}else if((r[i].a[j]<'A')||(r[i].a[j]>'Z')){r[i].first[r[i].s]=r[i].a[j];r[i].s++;r[i].first[r[i].s]='\0';break;}else{for(k=0;k<cnt;k++){if(r[i].a[j]==l[k].ch){len1=strlen(l[k].first);for(t=0;t<len1;t++){if(l[k].first[t]!='@'){r[i].first[r[i].s]=l[k].first[t];r[i].s++;r[i].first[r[i].s]='\0';}}break;}}if(l[k].flag){if(j==len-1){r[i].first[r[i].s]='@';r[i].s++;r[i].first[r[i].s]='\0';}continue;}elsebreak;}}}for(i=0;i<cnt;i++){printf("FIRST(%s): %s\n",r[i].a,r[i].first);}printf("\n");}//求每个非终极符的Follow集合void seekFollow(){int i,j,k,t,t1,t2,t3,c=0;int flag=0,len;int fchange;//判断一次循环是否有改动的地方char a[MAX][MAX],ch[MAX];for(i=0;i<count;i++){len=strlen(css[i]);for(j=3;j<len;j++){if((css[i][j]>='A')&&(css[i][j]<='Z')){break;}}if(j!=len){strcpy(a[c],css[i]);c++;}}l[0].follow[l[0].l]='#';l[0].l++;l[0].follow[l[0].l]='\0';while(1){fchange=0;for(i=0;i<c;i++){len=strlen(a[i]);for(j=3;j<len;j++){if((a[i][j]>='A')&&(a[i][j]<='Z')){//判断该非终结符的前一位是否为非终结符,是的话,//将其First集合去ε后并到其前一位非终结符的Follow集合中if((a[i][j-1]>='A')&&(a[i][j-1]<='Z')){for(k=0;k<cnt;k++){if(a[i][j-1]==l[k].ch){for(t=0;t<cnt;t++){if(a[i][j]==l[t].ch){for(t1=0;t1<l[t].s;t1++){if(l[t].first[t1]=='@')continue;for(t2=0;t2<l[k].l;t2++)if(l[t].first[t1]==l[k].follow[t2])break;if(t2==l[k].l){fchange=1;l[k].follow[l[k].l]=l[t].first[t1];l[k].l++;l[k].follow[l[k].l]='\0';}}break;}}break;}}}//如果该非终结符是最后一位,//将该产生式左部非终结符的Follow集合//加入到当前非终结符的Follow集合中.//然后从当前终结符开始向右判断是否为非终结符,是的话,进行相应处理//循环直到当前非终结符推不出ε或当前为终结符时退出if(j==len-1){t3=j;strcpy(ch,a[i]);while(!flag){if((ch[t3]>='A')&&(ch[t3]<='Z')){for(k=0;k<cnt;k++){if(ch[0]==l[k].ch){for(t=0;t<cnt;t++){if(ch[t3]==l[t].ch){for(t1=0;t1<l[k].l;t1++){for(t2=0;t2<l[t].l;t2++)if(l[k].follow[t1]==l[t].follow[t2])break;if(t2!=l[t].l)continue;else{fchange=1;l[t].follow[l[t].l]=l[k].follow[t1];l[t].l++;l[t].follow[l[t].l]='\0';}}if(l[t].flag)ch[t3--]='\0';else{flag=1;t3--;}break;}}break;}}}elsebreak;}flag=0;}}//如果当前位为终结符,判断其前一位是否为非终结符//是的话,将该终结符并到该非终结符的Follow集合中else{if((a[i][j-1]>='A')&&(a[i][j-1]<='Z')){for(k=0;k<cnt;k++){if(a[i][j-1]==l[k].ch){for(t=0;t<l[k].l;t++)if(a[i][j]==l[k].follow[t])break;if(t==l[k].l){fchange=1;l[k].follow[l[k].l]=a[i][j];l[k].l++;l[k].follow[l[k].l]='\0';}}}}}}}if(!fchange){for(i=0;i<cnt;i++)printf("FOLLOW(%c): %s\n",l[i].ch,l[i].follow);break;}}}int main(){int i;if(input()==-1)return -1;seekEmpty();seekFirstVn();seekFirstRight();seekFollow();return 0;}实验演示:因为不知道怎么用电脑输出’ε’符号,我在代码里用’@’来表示‘ε’.以‘$’来结束输入测试数据1:S->MH|aH->LSo|@K->dML|@L->eHfM->K|bLM测试数据2:S->aHH->aMd|dM->Ab|@A->aM|e实验感想:经过这几次的实验,不仅让我们更加深刻的知道了first集合和follow集合的计算步骤和方法,还很好的培养了我们动手能力。
安徽大学编译原理B-补考
安徽大学2012 -2013学年第一学期《编译原理》(B卷)年级院系专业姓名学号座位号(闭卷时间120分钟)一.简答(20分)Array 1.说明编译方式与解释方式的区别2.什么叫文法?乔姆斯基将文法分为哪四类?3.简述DFA M 与NFA M的异同点4.解释语法分析中自底向上分析的一般过程5.解释名字和标志符的异同点文法G[S]:S S(S)S| ,请判断G[S]是否是二义文法,说明理由三、(15分)有语言L={w|w ∈ (0,1)+,并且 w 中至少有两个 1 ,又在任何两个1之间有偶数个 0 },试构造接受该语言的确定有限状态自动机(10分)现有文法GE → E+T | E-T | TT → T*F | T/F | F F → (E) | i其中E 是文法的开始符号,求出句型(F +i )-T*(E-T)的短语,简单短语,句柄和素短语 五、(10分)考虑文法 G[S]:S → (T) | a+S | a T → T,S | S消除文法的左递归及提取公共左因子。
请给对文法G[S]进行改写成LL(1)文法,并给出改写后文法的预测分析表,要求计算出改写后文法各非终极符的FIRST和FOLLOW集合。
S → S*aA | aA| *aAA→ +aA | +a七、(10分)(1)if a<b OR c<d AND e>f then S1 else S2(2) while (A>B) do if (C<D) then X = Y+Z(3)令A是一个10×20的数组,写出赋值语句A[ I+2, J+1 ] =M+N的四元式序列八、(20分)已知文法G为:(0)S′→ S(1)S → aAd(2)S → bAc(3)S → aec(4)S → bed(5) A → e试构造它的LR(1)项目集、可归前缀图和LR(1)分析表。
编译原理 实验
编译原理实验编译原理实验。
编译原理是计算机科学中的一个重要领域,它研究的是编译器的设计和实现原理。
编译器是将高级语言代码转换成机器语言代码的程序,它在软件开发过程中起着至关重要的作用。
而编译原理实验则是帮助学生深入理解编译原理的重要手段之一,通过实际操作来加深对编译原理知识的理解和掌握。
在编译原理实验中,我们需要掌握以下几个关键点:1. 词法分析,词法分析是编译过程中的第一步,它负责将源代码分割成一个个的单词(Token)。
在词法分析实验中,我们需要实现一个词法分析器,能够正确地识别出源代码中的各种单词,并进行分类和标记。
2. 语法分析,语法分析是编译过程中的第二步,它负责将词法分析得到的单词序列转换成抽象语法树。
在语法分析实验中,我们需要实现一个语法分析器,能够根据给定的文法规则,将单词序列转换成抽象语法树,并进行语法检查。
3. 语义分析,语义分析是编译过程中的第三步,它负责对抽象语法树进行语义检查和翻译。
在语义分析实验中,我们需要实现一个语义分析器,能够对抽象语法树进行类型检查、作用域分析等,并生成中间代码。
4. 代码生成,代码生成是编译过程中的最后一步,它负责将中间代码转换成目标机器代码。
在代码生成实验中,我们需要实现一个代码生成器,能够将中间代码转换成目标机器代码,并进行优化。
通过以上实验,我们可以深入理解编译原理的各个环节,并掌握编译器的设计和实现原理。
同时,实验过程中还能培养我们的动手能力和解决问题的能力,为今后的软件开发打下坚实的基础。
总之,编译原理实验是非常重要的,它能够帮助我们深入理解编译原理知识,提高我们的动手能力和解决问题的能力。
希望大家能够认真对待编译原理实验,从中获得更多的收获和成长。
安徽大学编译原理第一章
主讲:XX
1
重要性
计算机专业的专业基础必修课之一 软件技术基础 计算机专业的学生必修的一门主干课
2
作用
编译原理介绍了如何将高级程序设计语言 变换成计算机硬件所能识别的机器语言, 以便计算机进行处理。
它的理论基础坚实,其形式化系统不仅应 用于编译技术,还大量应用于人工智能、 多媒体技术及数据库等领域。
17
在计算机上如何执行一个高级语言程序?
把高级语言程序翻译成机器语言程序 运行所得的机器语言程序求得计算结果
高级语 言程序
编译程序
低级语 言程序
18
源程序、翻译程序、目标程序 三者关系:
源程序
SOURCE PROGRAM
翻译程序
TRANSLATER
目标程序
OBJECT PROGRAM
即源程序是翻译程序的输入,目标程序是翻译程序的输出
<1>保留字 (如:void,int,float)
<2>标识符 (如:a, b, c, d, x, y,
jisuan) <3>常数 (如:50) <4>运算符 (如:*,+,= ) <5>界限符 (如{ };,( ) ) )
Void jisuan( ) {int y,c,d;
float x,a,b; x=a+b*50; y=c+)d*(x+b; }
编译原理实验报告
编译原理实验报告班级姓名:学号:自我评定:实验一词法分析程序实现一、实验目的与要求通过编写和调试一个词法分析程序,掌握在对程序设计语言的源程序进行扫描的过程中,将字符形式的源程序流转化为一个由各类单词符号组成的流的词法分析方法。
二、实验内容根据教学要求并结合学生自己的兴趣和具体情况,从具有代表性的高级程序设计语言的各类典型单词中,选取一个适当大小的子集。
例如,可以完成无符号常数这一类典型单词的识别后,再完成一个尽可能兼顾到各种常数、关键字、标识符和各种运算符的扫描器的设计和实现。
输入:由符合或不符合所规定的单词类别结构的各类单词组成的源程序。
输出:把单词的字符形式的表示翻译成编译器的内部表示,即确定单词串的输出形式。
例如,所输出的每一单词均按形如(CLASS,VALUE)的二元式编码。
对于变量和常数,CLASS字段为相应的类别码;VALUE字段则是该标识符、常数的具体值或在其符号表中登记项的序号(要求在变量名表登记项中存放该标识符的字符串;常数表登记项中则存放该常数的二进制形式)。
对于关键字和运算符,采用一词一类的编码形式;由于采用一词一类的编码方式,所以仅需在二元式的CLASS字段上放置相应的单词的类别码,VALUE字段则为“空”。
另外,为便于查看由词法分析程序所输出的单词串,要求在CLASS字段上放置单词类别的助记符。
三、实现方法与环境词法分析是编译程序的第一个处理阶段,可以通过两种途径来构造词法分析程序。
其一是根据对语言中各类单词的某种描述或定义(如BNF),用手工的方式(例如可用C语言)构造词法分析程序。
一般地,可以根据文法或状态转换图构造相应的状态矩阵,该状态矩阵同控制程序便组成了编译器的词法分析程序;也可以根据文法或状态转换图直接编写词法分析程序。
构造词法分析程序的另外一种途径是所谓的词法分析程序的自动生成,即首先用正规式对语言中的各类单词符号进行词型描述,并分别指出在识别单词时,词法分析程序所应进行的语义处理工作,然后由一个所谓词法分析程序的构造程序对上述信息进行加工。
编译原理实验报告
编译原理实验报告一、实验目的编译原理是计算机科学中的重要学科,它涉及到将高级编程语言转换为计算机能够理解和执行的机器语言。
本次实验的目的是通过实际操作和编程实践,深入理解编译原理中的词法分析、语法分析、语义分析以及中间代码生成等关键环节,提高我们对编译过程的认识和编程能力。
二、实验环境本次实验使用的编程语言为C++,开发环境为Visual Studio 2019。
此外,还使用了一些相关的编译工具和调试工具,如 GDB 等。
三、实验内容(一)词法分析器的实现词法分析是编译过程的第一步,其任务是将输入的源程序分解为一个个单词符号。
在本次实验中,我们使用有限自动机的理论来设计和实现词法分析器。
首先,定义了各种单词符号的类别,如标识符、关键字、常量、运算符等。
然后,根据这些类别设计了相应的状态转换图,并将其转换为代码实现。
在实现过程中,使用了正则表达式来匹配输入字符串中的单词符号。
对于标识符和常量等需要进一步处理的单词符号,使用了相应的规则进行解析和转换。
(二)语法分析器的实现语法分析是编译过程的核心环节之一,其任务是根据给定的语法规则,分析输入的单词符号序列是否符合语法结构。
在本次实验中,我们使用了递归下降的语法分析方法。
首先,根据实验要求定义了语法规则,并将其转换为相应的递归函数。
在递归函数中,通过对输入单词符号的判断和处理,逐步分析语法结构。
为了处理语法错误,在分析过程中添加了错误检测和处理机制。
当遇到不符合语法规则的输入时,能够输出相应的错误信息,并尝试进行恢复。
(三)语义分析及中间代码生成语义分析的目的是对语法分析得到的语法树进行语义检查和语义处理,生成中间代码。
在本次实验中,我们使用了三地址码作为中间代码的表示形式。
在语义分析过程中,对变量的定义和使用、表达式的计算、控制流语句等进行了语义检查和处理。
对于符合语义规则的语法结构,生成相应的三地址码指令。
四、实验步骤(一)词法分析器的实现步骤1、定义单词符号的类别和对应的正则表达式。
国开电大 编译原理 实验4:语法分析实验报告
国开电大编译原理实验4:语法分析实
验报告
1. 实验目的
本实验的目的是研究和掌握语法分析的原理和实现方法。
2. 实验内容
本次实验主要包括以下内容:
- 设计并实现自顶向下的LL(1)语法分析器;
- 通过语法分析器对给定的输入串进行分析,并输出相应的分析过程;
- 编写测试用例,验证语法分析器的正确性。
3. 实验步骤
3.1 设计LL(1)文法
首先,根据实验要求和给定的语法规则,设计LL(1)文法。
3.2 构建预测分析表
根据所设计的LL(1)文法,构建预测分析表。
3.3 实现LL(1)语法分析器
根据预测分析表,实现自顶向下的LL(1)语法分析器。
3.4 对输入串进行分析
编写程序,通过LL(1)语法分析器对给定的输入串进行分析,并输出相应的分析过程和结果。
3.5 验证语法分析器的正确性
设计多组测试用例,包括正确的语法串和错误的语法串,验证语法分析器的正确性和容错性。
4. 实验结果
经过实验,我们成功设计并实现了自顶向下的LL(1)语法分析器,并对给定的输入串进行了分析。
实验结果表明该语法分析器具有较好的准确性和容错性。
5. 实验总结
通过本次实验,我们对语法分析的原理和实现方法有了更深入的了解。
同时,我们也学会了如何设计并实现自顶向下的LL(1)语
法分析器,并验证了其正确性和容错性。
这对于进一步研究编译原理和深入理解编程语言的语法结构具有重要意义。
6. 参考资料
- 《编译原理与技术》
- 课程实验文档及代码。
安徽大学编译原理试验斯
不确定的有穷自动机的化简2015年11月25日星期三班级:软件工程学号: E21314003 姓名:李世1. 目的与要求通过设计、编写和调试,将不确定的有穷自动机转换为与之等价的确定的有穷自动机的程序,使学生了解子集法。
掌握转换过程中的相关概念和方法。
DFA的表现形式可以是表格或图形。
2. 理论基础有穷自动机(也称有限自动机)作为一种识别装置,它能准确地识别正规集,即识别正规式所表示的集合. 应用有穷自动机这个理论,为词法分析程序的自动构造寻找有效的方法和工具。
有穷自动机分为两类,即,确定的有穷自动机(Deterministic Finite Automata)和不确定的有穷自动机(Nondeterministic Finite Automata) 。
(1) 不确定的有穷自动机的定义:一个不确定的有穷自动机(NFA)M 是一个五元组:NFA M={K,Σ,f,S,Z},其中:K为状态的有穷非空集;Σ 为有穷输入字母表;f为K× Σ* 到K的子集(2K)的一种映射, 2K表示K的幂集(f不是一个单值函数);S⊆K是初始状态集;Z ⊆K为终止状态集.例子:NFA M=({S,P,Z},{0,1},f,{S,P},{Z}),其中:f(S,0)={P}//函数的结果为集合f(S,1)={S,Z}f(P,1)={Z}f(Z,0)={P}f(Z,1)={P}状态图表示为:矩阵表示为:(2) 确定的有穷自动机的定义:一个确定的有穷自动机(DFA)M是一个五元组:M=(K,Σ,f,S,Z)其中:K是一个有穷集,它的每个元素称为一个状态;Σ是一个有穷字母表,它的每个元素称为一个输入符号,所以也称Σ为输入符号表;f是转换函数,是在K×Σ→K上的映射,即,如f(ki,a)=kj,(ki ∈K,kj∈K)就意味着,当前状态为ki,输入符为a时,将转换为下一个状态kj,我们把kj称作ki的一个后继状态;S∈K是唯一的一个初态;Z⊂ K是一个终态集,终态也称可接受状态或结束状态。
编译原理实验报告文档
《编译原理》实验报告
专业班级:计101班
学号:109074002
姓名:卞恩会
指导老师:王森玉
实验内容:
1.求出每个非终结符的FIRST集合
2.求出每个产生式右部的FIRST集合
3.求出每个非终结符的Follow集合实验环境:
Visual Studio2010
实验目的:
掌握FIRST集合和FOLLOW集合的求法
测试数据1:
S->aH
H->aMd|d
M->Ab|@
A->aM|e
输出结果:
测试数据2:S->AB
S->bC
A->@
A->b
B->@
B->aD
C->AD
C->b
D->aS
D->c
测试数据3:E->TX
X->+TX|@ T->FY
Y->*FY|@ F->i|(E)
输出结果:
感受:通过上机调试代码让我对书上的单纯的理论的知识有了一个更深的理解同时让我明白了对待一个问题我们应该全面的去理解它,这样才能学到的更多。
程序清单:。
编译原理实验报告1
03091337 李璐 03091339 宗婷婷一、上机题目:实现一个简单语言(CPL)的编译器(解释器)二、功能要求:接收以CPL编写的程序,对其进行词法分析、语法分析、语法制导翻译等,然后能够正确的执行程序。
三、试验目的1.加深编译原理基础知识的理解:词法分析、语法分析、语法制导翻译等2.加深相关基础知识的理解:数据结构、操作系统等3.提高编程能力4.锻炼独立思考和解决问题的能力四、题目说明1.数据类型:整型变量(常量),布尔变量(常量)取值范围{…, -2, -1, 0, 1, 2, …}, {true, false}2、运算表达式:简单的代数运算,布尔运算3、程序语句:赋值表达式,顺序语句,if-else语句,while语句五、环境配置1.安装Parser Generator、Visual C++;2.分别配置Parser Generator、Visual C++;3.使用Parser Generator创建一个工程编写l文件mylexer.l;编译mylexer.l,生成mylexer.h与mylexer.c;4.使用VC++创建Win32 Console Application工程并配置该项目;加入mylexer.h与mylexer.c,编译工程;执行标识符数字识别器;注意:每次修改l文件后,需要重新编译l文件,再重新编译VC工程六、设计思路及过程设计流程:词法分析LEX的此法分析部分主要利用有限状态机进行单词的识别,在分析该部分之前,首先应该对YACC的预定义文法进行解释。
在YACC中用%union扩充了yystype的内容,使其可以处理char型,int型,node型,其中Node即为定义的树形结点,其定义如下:typedef enum { TYPE_CONTENT, TYPE_INDEX, TYPE_OP } NodeEnum;/* 操作符 */typedef struct {int name; /* 操作符名称 */int num; /* 操作元个数 */struct NodeTag * node[1]; /* 操作元地址可扩展 */} OpNode;typedef struct NodeTag {NodeEnum type; /* 树结点类型 *//* Union 必须是最后一个成员 */union {int content; /* 内容 */int index; /* 索引 */OpNode op; /* 操作符对象 */};} Node;extern int Var[26];结点可以是三种类型(CONTENT,INDEX,OP)。
编译原理课程的教学实践
助 学生 掌握 基础 理 论 和技 术的 同时提 高学 生 实 际动 手能 力 ,培 养他 们 开发 软件 的 工程 意识 和 团队 协作 精
神。 关键字 : 译原 理 ; 学效果 ; 编 教 工程 意 识 。
中图分 类 号 : 6 24 G4 .
文献 标识 码 : A
文 章编 号 :6 2 4 7 2 1)4 0 3 - 2 17 — 4 X(0 00 - 1 3 0
我 校 立足 于 应用 型 本科 院 校 , 养 的 是 应 用型 培 实 用性 人 才 , 此 我们 在课 程 教 学 过 程 中 要注 重 学 因
释 技 术 ,懂 得 编 译 器 在 后 台 的 编 译 方 式 和 编 译 过
程 。 生 们 在 编 程 时 才 能 有 正 确 的思 维 方 式 , 能 学 才
和技 术 具 有十 分普 遍 的 意 义 , 每一 个 计 算机 科 学 在
技 术工 作 者 的职 业生 涯 中 , 些原 理 和 技 术都 被 反 这
编 译原 理 课 程 中理 论 知识 特 别 多 ,难度 大 , 如 正 则式 、 有穷 状态 机 、 e 网 、 法 分析 等 , 生们 更 Pr t 语 学
个 硬件 系 统都 离 不 开编 译 程序 的作 用 , 同时 一个 编 译 程 序 的 好 坏 直 接 影 响 着 计 算 机 软 硬 件 资 源 的利
项 目开发模式角度 出发 , 探讨如何 有效提 高教学效果 。
2 编 译原 理 的教 学 内容选 取
用 , 且带 给 用 户不 同 的使 用 效 果 。编 译 器 的原 理 并
( 山学 院 信 息 _ 程 学院 , 徽 黄 山 2 5 2 ) 黄 T - 安 4 0 1
合肥工业大学编译原理实验报告(完整代码版)
计算机与信息学院之欧侯瑞魂创作创作时间:二零二一年六月三十日编译原理实验陈说专业班级信息平安13-1班学生姓名及学号马骏 2013211869课程教学班号任课教师李宏芒实验指导教师李宏芒实验地址实验楼机房2015 ~2016 学年第二学期实验1 词法分析设计一、实验目的通过本实验的编程实践, 使学生了解词法分析的任务, 掌握词法分析法式设计的原理和构造方法, 使学生对编译的基本概念、原理和方法有完整的和清楚的理解, 并能正确地、熟练地运用二、实验要求1、编程时注意编程风格:空行的使用、注释的使用、缩进的使用等.2、将标识符填写的相应符号表须提供给编译法式的以后各阶段使用.3、根据测试数据进行测试.测试实例应包括以下三个部份:全部合法的输入.各种组合的非法输入.由记号组成的句子.4、词法分析法式设计要求输出形式:例:输入VC++语言的实例法式:If i=0 then n++;a﹤= 3b %);输出形式为:单词二元序列类型位置(行, 列)(单词种别, 单词属性)for (1,for ) 关键字(1, 1)i ( 6,i ) 标识符(1, 2)= ( 4, = ) 关系运算符(1, 3) 120 ( 5, 0 ) 常数(1, 4)then ( 1, then) 关键字(1, 5)n (6,n ) 标识符(1, 6)++ Error Error (1, 7);( 2, ; ) 分界符(1, 8)a (6,a ) 标识符(2, 1)﹤= (4,<= ) 关系运算符(2, 2)3b Error Error (2, 4)% Error Error (2, 4)) ( 2, ) ) 分界符(2, 5);( 2, ; ) 分界符(2, 6)三、实验内容用 VC++/VB/JAVA 语言实现对 C 语言子集的源法式进行词法分析.通过输入源法式从左到右对字符串进行扫描和分解, 依次输出各个单词的内部编码及单词符号自身值;若遇到毛病则显示“Error”, 然后跳过毛病部份继续显示;同时进行标识符挂号符号表的管理.以下是实现词法分析设计的主要工作:(1)从源法式文件中读入字符.(2)统计行数和列数用于毛病单词的定位.(3)删除空格类字符, 包括回车、制表符空格.(4)按拼写单词, 并用(内码, 属性)二元式暗示.(属性值——token的机内暗示)(5)如果发现毛病则陈说犯错 7(6)根据需要是否填写标识符表供以后各阶段使用.四、实验步伐1、根据流程图编写出各个模块的源法式代码上机调试.2、编制好源法式后, 设计若干用例对系统进行全面的上机测试, 并通过所设计的词法分析法式;直至能够获得完全满意的结果.3、书写实验陈说;实验陈说正文的内容:功能描述:该法式具有什么功能?法式结构描述:函数调用格式、参数含义、返回值描述、函数功能;函数之间的调用关系图.详细的算法描述(法式总体执行流程图) .给出软件的测试方法和测试结果.实验总结(设计的特点、缺乏、收获与体会).五、实验截图输入If i=0 then n++;a<= 3b %);六、核心代码#include<iostream>#include<string>#include<fstream>#include <sstream>using namespace std;const char* salaryfile="salaryfile.txt";const int max=40;stringid[max]={"do","end","for","if","printf","scanf","then"," while"};//关键字表string s[max]={",",";","(",")","[","]","+","-","*","/","<","<=","=",">",">=","<>"};//分界符表算数运算符表关系运算符表string k[max];// 标识符string ci[max];// 常数int fjfpoint=5;//分界符表尾int mathpoint=9;//算数运算符表尾int cipointer=0;//常数表尾int idpointer=0;//关键字表尾int kpointer=0;//标识符表尾int fjf;//0 不是分界符 1是int rowy=1;//识别输入行位置int rowx=1;//识别输入列位置int outkey=0;//打印控制 0为数字后有字母其他可以void searcht(int i,string m)//根据已识另外首字母识别字符串{//cout<<"enter searcht!!"<<endl;int x;if(i==0)//首字符是字母识别关键字{//cout<<" a word!!"<<endl;for(x=0;x<max;x++){if(id[x]==m){cout<<"(1,"<<id[x]<<")"<<" 关键字("<<rowy<<","<<rowx<<")"<<endl;break;}}if(x==max)//不是关键字再识别标识符{for(x=0;x<max;x++){if(k[x]==m){cout<<"(6,"<<m<<") "<<"标识符("<<rowy<<","<<rowx<<")"<<endl;break;}}if(x==max)//标识符表没有时拔出标识符{cout<<"(6,"<<m<<") "<<"标识符("<<rowy<<","<<rowx<<")"<<endl;k[kpointer]=m;kpointer++;}}}if(i==1)//识别常数{//cout<<" a number!!"<<endl;for(x=0;x<max;x++){if(ci[x]==m){cout<<"(5,"<<x<<")"<<endl;break;}}if(x==max){cout<<"(5,"<<m<<") 常数("<<rowy<<","<<rowx<<")"<<endl;ci[cipointer]=m;cipointer++;}}if(i==2)//识别分界符算数运算符关系运算符{//cout<<" a signal!!"<<endl;for(x=0;x<max;x++){if(s[x]==m)break;}//x--;if(x<6){fjf=1;}if(x>5&&x<10){if(outkey==1){cout<<"(3,"<<s[x]<<") 算数运算符("<<rowy<<","<<rowx<<")"<<endl;outkey=0;}fjf=0;}if(x>9&&x<max-1){if(outkey==1){cout<<"(4,"<<s[x]<<") 关系运算符("<<rowy<<","<<rowx<<")"<<endl;outkey=0;}fjf=0;}if(x==max){if(outkey==1){cout<<"Error Error ("<<rowy<<","<<rowx<<")"<<endl; outkey=0;}fjf=0;}}};void wordlook(char t,string sn)//识别首字符, 分类识别字符串{if(t>=48&&t<=57)searcht(1,sn);else{if((t>64&&t<91)||(t>96&&t<123))searcht(0,sn);else searcht(2,sn);}};void split(string s)//分割字符串{//cout<<s<<endl;string now[max];string sn;int nowpointer=0;int i=0;int x;int sign=2;//非法数字标识表记标帜int diannumber=0;//数中点的个数for(x=0;x<s.length();x++){if((s[x]>64&&s[x]<91)||(s[x]>96&&s[x]<123)||(s[x]>=48&&s [x]<=57)||(x>0&&s[x]==46&&sign==1))//判断数字后跟字母还是字母后有数字{if(i==0){if(s[x]>=48&&s[x]<=57)sign=1;else sign=2;}else{if(sign==1){if(s[x]>=48&&s[x]<=57||s[x]==46){if(s[x]==46){if(diannumber==0)diannumber++;else sign=0;}}else sign=0;}}i++;if(x==(s.length()-1)){sn=s.substr(x-i+1,i);if(i>0){// cout<<sn<<" i="<<i<<endl;cout<<sn<<" ";if(sign==0)//数字后有字母的情况cout<<" Error Error ("<<rowy<<","<<rowx<<")"<<endl;else //字母开头的字符串{// cout<<" true"<<endl;wordlook(sn[0],sn);rowx++;}}}}else{if(x>0&&(s[x-1]>64&&s[x-1]<91)||(s[x-1]>96&&s[x-1]<123)||(s[x-1]>=48&&s[x-1]<=57))//遇到分界符运算符如果前面是数字或字母{sn=s.substr(x-i,i);if(i>0){// cout<<sn<<" i="<<i<<endl;cout<<sn<<" ";if(sign==0)cout<<" Error Error ("<<rowy<<","<<rowx<<")"<<endl;else{// cout<<" true"<<endl;wordlook(sn[0],sn);rowx++;}}i=0;}string ll=s.substr(x,1);//判断是运算符还是分界符wordlook(s[x],ll);if(fjf==0)//是运算符{i++;if((s[x+1]>64&&s[x+1]<91)||(s[x+1]>96&&s[x+1]<123)||(s[x +1]>=48&&s[x+1]<=57))//如果后面是数字或字母{sn=s.substr(x-i+1,i);// cout<<sn<<"运算符 i="<<i<<endl;cout<<sn<<" ";outkey=1;wordlook(sn[0],sn);rowx++;i=0;}}if(fjf==1){if((s[x-1]>64&&s[x-1]<91)||(s[x-1]>96&&s[x-1]<123)||(s[x-1]>=48&&s[x-1]<=57))//如果前面是数字或字母 {}else if(i>0){sn=s.substr(x-i,i);// cout<<sn<<"运算符 i="<<i<<endl;cout<<sn<<" ";outkey=1;wordlook(sn[0],sn);rowx++;i=0;}cout<<s[x]<<" (2,"<<s[x]<<") 分界符("<<rowy<<","<<rowx<<")"<<endl;rowx++;/* if(ll==";"){rowy++;rowx=1;}*/}}};int main(){int x;string instring;//读入一行string sn;/*getline(cin,sn);// string带空格输入cout<<sn<<endl;char t=sn[0];if(t>=48&&t<=57)searcht(1,sn);else{if((t>64&&t<91)||(t>96&&t<123))searcht(0,sn);else searcht(2,sn);}*/ifstream inputfile;//in file stream inputfile.open(salaryfile);//inputfile>>noskipws;if(!inputfile){cout<<"no file"<<endl;}string pp;while(!inputfile.eof()){getline(inputfile,pp); istringstream istr(pp);string ppword;while(istr>>ppword)//依照空格分割字符串{split(ppword);}int begin = 0;//去失落字符串的所有空格begin = pp.find(" ",begin); //查找空格在str中第一次呈现的位置while(begin != -1) //暗示字符串中存在空格{pp.WordStr(begin, 1, ""); // 用空串替换str中从begin开始的1个字符begin = pp.find(" ",begin); //查找空格在替换后的str中第一次呈现的位置}*///cout<<"good "<<pp<<endl;//rowx++;rowy++;//换行rowx=1;}return 0;}七、实验总结通过本次试验使我不单对词法分析器有了更深的了解, 而且提高了编程能力, 希望在以后的学习中可以解决词法分析更多的问题.实验2 LL(1)分析法一、实验目的通过完成预测分析法的语法分析法式, 了解预测分析法和递归子法式法的区别和联系.使学生了解语法分析的功能, 掌握语法分析法式设计的原理和构造方法, 训练学生掌握开发应用法式的基本方法.有利于提高学生的专业素质, 为培养适应社会多方面需要的能力.二、实验要求1、编程时注意编程风格:空行的使用、注释的使用、缩进的使用等.2、如果遇到毛病的表达式, 应输犯毛病提示信息.3、对下列文法, 用 LL(1)分析法对任意输入的符号串进行分析:(1)E->TG(2)G->+TG|—TG(3)G->ε(4)T->FS(5)S->*FS|/FS(6)S->ε(7)F->(E)(8)F->i三、实验内容根据某一文法编制调试 LL ( 1 )分析法式, 以便对任意输入的符号串进行分析.构造预测分析表, 并利用分析表和一个栈来实现对上述法式设计语言的分析法式.分析法的功能是利用 LL(1)控制法式根据显示栈栈顶内容、向前看符号以及 LL(1)分析表, 对输入符号串自上而下的分析过程.四、实验步伐1、根据流程图编写出各个模块的源法式代码上机调试.2、编制好源法式后, 设计若干用例对系统进行全面的上机测试, 并通过所设计的 LL(1)分析法式;直至能够获得完全满意的结果.3、书写实验陈说;实验陈说正文的内容:写出 LL(1)分析法的思想及写出符合 LL(1)分析法的文法.法式结构描述:函数调用格式、参数含义、返回值描述、函数功能;函数之间的调用关系图.详细的算法描述(法式执行流程图) .给出软件的测试方法和测试结果.实验总结(设计的特点、缺乏、收获与体会).五、实验截图六、核心代码#include<iostream>#include<string>using namespace std;string pp;//输出字符串string hh="\r\n";//换行const int max=50;int endfu[max];//终止符序号表int endfupointer=8;char endfureal[max]={'+','-','*','/','(','i',')','#'};int unendfu[max];int unendfupointer=5;char unendfureal[max]={'E','G','T','S','F'};string makemath[max]={"E->TG","G->+TG","G->-TG","G->$","T->FS","S->*FS","S->/FS","S->$","F->(E)","F->i"};//0 E->TG,1 G->+TG,2 G->-TG,3 G->$,4 T->FS,5 S->*FS,6 S->/FS,7 S->$,8 F->(E),9 F->i//$代表空串string behavior[max]={"初始化","POP"};int smarttable[max][max];//分析表int checkendfu(char fu)//查终结符序号{int x;for(x=0;x<endfupointer;x++){if(endfureal[x]==fu){break;}}if(x<endfupointer)return x;else return -1;};int checkunendfu(char fu)//查非终结符序号{int x;for(x=0;x<unendfupointer;x++){if(unendfureal[x]==fu)break;}if(x<unendfupointer)return x;else return-1;};string checkmakemath(int x)//查发生式表{return makemath[x];};int checksmarttable(int x,int y)//查分析表{return smarttable[x][y];};class smartbox{public:smartbox(){box[0]='#';box[1]='E';boxpointer=1;}void push(char fu){boxpointer++;box[boxpointer]=fu;}char pop(){char a=box[boxpointer];if(a!='#'){//cout<<"pop: "<<boxpointer<<" "<<a<<endl; //stringstream oss;/*pp=pp+"pop: ";char buffer[max];sprintf(buffer,"%d",boxpointer);string s=buffer;pp=pp+" ";pp=pp+s;pp=pp+hh;*/boxpointer--;return a;}}void check(){if(checkendfu(box[boxpointer])!=-1){char a;//cout<<box[boxpointer]<<checkendfu(box[boxpointer])<<" ";//char buffer[max];//sprintf(buffer//pp=pp+box[boxpointer];//pp=pp+checkendfu(box[boxpointer]);//pp=pp+" ";a=pop();//cout<<"out "<<a<<endl;。
编译原理实验报告
编译原理实验报告合工大编译原理实验报告,后面附代码,孩纸,只能参考不能抄袭哦,好好学习天天向上,编译原理实验报告合肥工业大学计算机科学与技术完成日期:20XX年.6.3实验一词法分析设计一、实验功能:合工大编译原理实验报告,后面附代码,孩纸,只能参考不能抄袭哦,好好学习天天向上,对输入的txt文件内的内容进行词法分析:由文件流输入test.txt中的内容,对文件中的各类字符进行词法分析打印出分析后的结果;二、程序结构描述:(源代码见附录)1、利用Key[]进行构造并存储关键字表;利用optr[]进行构造并存储运算符表;利用separator[]进行构造并存储分界符表;2、bool IsKey(string ss) {}判断是否是关键字函数若是关键字返回true,否则返回false;bool IsLetter(char c) {}判断当前字符是否字母,若是返回true,否则返回false;bool IsDigit(char c) {}判断当前字符是否是数字,若是返回true,否则返回false;bool IsOptr(string ss) {}判断当前字符是否是运算符,若是返回true,否则返回false;bool IsSeparator(string ss) {}判断当前字符是否是分界符,若是返回true,否则返回false;void analyse(ifstream in) {}分析函数构造;关系运算符通过switch来进行判断;三、实验结果合工大编译原理实验报告,后面附代码,孩纸,只能参考不能抄袭哦,好好学习天天向上,实验总结:词法分析的程序是自己亲手做的,在实现各个函数时花了不少功夫,1、要考虑到什么时候该退一字符,否则将会导致字符漏读甚至造成字符重复读取。
2、在实现行数和列数打印时要考虑到row++和line++应该放在什么位置上才可以,如当读取一个\n时line要增加一,而row需要归0处理,在读取某一字符串或字符后row需要加一;3、对于关系运算符用switch结构进行选择判断即可解决一个字符和两个字符的运算符之间的差异;4、将自己学过的知识应用到实践中是件不怎么容易的事情,只有亲身尝试将知识转化成程序才能避免眼高手低,对于知识的理解也必将更加深刻。
编译原理中实验报告
实验名称:编译原理实验实验时间:2023年X月X日实验地点:实验室实验指导老师:XXX一、实验目的1. 理解编译原理的基本概念和流程。
2. 掌握词法分析和语法分析的基本方法。
3. 学习编译器生成中间代码和目标代码的过程。
4. 培养编程能力和问题解决能力。
二、实验内容本次实验主要包括以下内容:1. 词法分析:编写一个简单的词法分析器,将源代码输入转换为抽象语法树(AST)。
2. 语法分析:实现一个简单的递归下降解析器,对词法分析器输出的AST进行语法分析。
3. 中间代码生成:根据AST生成三地址代码(Three-Address Code)。
4. 代码优化:对生成的三地址代码进行优化。
5. 目标代码生成:将优化后的三地址代码转换为机器代码。
三、实验步骤1. 设计词法分析器首先,我们需要设计一个能够识别源代码中各种单词的词法分析器。
在本实验中,我们定义了以下几种单词:- 关键字:如if、else、while、int、float等。
- 标识符:由字母、数字和下划线组成,不能以数字开头。
- 常量:包括整型常量和浮点型常量。
- 运算符:如+、-、、/、==、<=等。
- 分隔符:如(、)、;、,等。
根据以上定义,我们可以编写一个词法分析器,它将输入的源代码字符串逐个字符地读取,并根据定义的规则识别出相应的单词。
2. 语法分析词法分析器生成的AST是一个树形结构,其中每个节点代表源代码中的一个单词或符号。
为了进一步分析AST的结构,我们需要实现一个递归下降解析器,它能够根据语法规则对AST进行解析。
在本实验中,我们以一个简单的算术表达式为例,实现了一个递归下降解析器。
解析器从AST的根节点开始,按照语法规则递归地解析每个子节点,直到整个表达式被解析完毕。
3. 中间代码生成在完成语法分析后,我们需要将AST转换为中间代码。
在本实验中,我们选择了三地址代码作为中间代码的形式。
三地址代码是一种表示赋值、条件判断和循环等操作的方式,它使用三个操作数和两个操作符来表示一个操作。
编译原理实验报告要求
编译原理实验报告学 院:专业班级:学生学号:学生姓名: 年 月 日 实验一:词法分析程序的设计与实现一实验目的基本掌握计算机语言的词法分析程序的开发方法。
二 实验内容编制一个能够分析整数、标识符、主要运算符和主要关键字的词法分析程序。
三.实验要求根据教材第四章内容设计词法分析程序。
四. 实验环境PC微机DOS操作系统或 Windows 操作系统Turbo C 程序集成环境或 Visual C++ 程序集成环境五. 实验步骤1. 根据状态图,设计词法分析算法或者根据GETSYM设计。
2. 采用C语言,设计函数getsym( ),实现该算法3. 编制测试程序(主函数main)。
4. 调试程序:输入一组单词,检查输出结果。
六. 基本测试数据输入数据例:正确结果:七. 实验报告要求实验报告应需要说明以下几个部分:1.词法分析程序设计思路2.词法分析程序的数据结构与算法3.关键程序说明、技术要点4.存在的问题及改进办法实验二:递归子程序实现语法分析一实验目的基本掌握计算机语言的语法分析程序的自顶向下分析方法。
二 实验内容编制一个能够分析表达式文法的递归分析程序。
三.实验要求采用递归子程序法,改写文法,构造语法分析程序表达式文法为:E → E + T | TT →T * F | FF →( E ) | i四. 实验环境PC微机DOS操作系统或 Windows 操作系统Turbo C 程序集成环境或 Visual C++ 程序集成环境五. 实验步骤1.考虑给定的文法,消除左递归,提取左因子。
2.编制递归子程序的算法3.连接实验一的词法分析函数getsym( ),进行测试4.编制测试程序(main函数)5.调试程序:输入一个语句,检查输出的结果六. 基本测试数据输入数据例:正确结果:七. 实验报告要求实验报告应需要说明以下几个部分:1.语法分析程序设计思路2.程序的数据结构与算法3.关键程序说明、技术要点4.存在的问题及改进办法实验三:算符优先分析实现 一实验目的基本掌握计算机语言的语法分析程序的自底向上分析方法。
2021年安徽师范大学《编译原理实践》课程教学大纲
2021年安徽师范大学《编译原理实践》课程教学大纲《编译原理实践》课程教学大纲课程编号:07114180适用于专业:计算机科学与技术系则计算机应用专业(软件本科)学时数:34(理论学时数:10实验或讨论学时数:48)学分数:2执笔者:周有顺撰写日期:2021年2月继续执行时间:2021年以后入学的年级一、课程的性质和目的编程原理课堂教学设计就是计算机科学与技术专业学生的专业必修课。
系统软件是计算机系统的重要组成部分。
本课程是在学习系统软件的组成、设计原理和实现方法的基础之上,设计并上机实现部分系统软件----编译程序。
目的在于完成相关课程从理论到实践的推进,使学生真正掌握计算机信息处理的实质,提高其专业素质及驾驭各种系统软件和应用软件的能力。
二、课程教学内容编译程序设计与实现的目的:介绍编译程序的共同组成及各部分的基本任务;掌控编译程序各部分的设计原理和同时实现方法;体会理论内容与具体内容课堂教学之间的关系。
第一章课堂教学内容要点(1)编程过程概述:(4学时)词法分析、语法分析、语义分析及中间代码生成、目标代码生成等各部分的具体实现算法;符号表管理、错误信息处理的具体实现方法;上述各部分之间的数据及信息的传递与交流。
(2)编译程序同时实现途径(6学时)编译程序的书写语言与t型图;编译程序的自展技术;编译程序的构造工具。
第二章课堂教学内容概述(上机部分)(24学时)(1)实验型语言源文法(略)。
(2)编译程序的设计目标①设计该语言的词法分析程序和语法分析及语义分析程序,词法分析程序和语法分析程序分别做为一遍撰写,并分解成二元式和中间代码四元式形式。
②在语法分析中,对各语句和布尔表达式的分析采用递归下降分析,对算数表达式的分析采用算符优先分析。
③程序中应当包含符号表管理和直观的失效处置。
词法分析失效处置包含非法字符和非法单词;语法分析失效处置包含直观的语法错误,即为程序结构不合乎语法规则的错误。
④将中间代码四元式生成8086/8088汇编语言的目标代码形式。
安徽大学-人工智能-消解原理
学号姓名实验日期2015/12/20实验报告【实验名称】子句消解实验【实验目的】在参数比较多的情况下,通过编程实现对含有参数的句子进行消解,寻找最一般的合一者σ,并理解、掌握子句消解的原理和规则,了解消解推理的某些常用规则,理解合一者的概念,能熟练的对任意两个子句进行消解。
【实验设备】设备:CPU:i5内存:4G的PC一台。
开发环境:Spyder语言:实验采用python语言实现。
【实验原理】两任意原子公式Sentence1和Sentence12具有相同的谓词符号,但却有着不同的变量。
已知两子句Sentence1∨P和~Sentence12∨Q,如果Sentence1和Sentence2具有最一般合一σ,那么通过消解可以从这两个父辈子句推导出一个新子句P∨Q。
且需要对其中的变量或常量进行替换,替换的一般规则是,用函数替代变量,比如(g(x)->y),用常量替代变量,比如(b->y),其中b为常量,y为变量。
这里我们事先约定好常量是哪些字母并存到列表中,变量是哪些字母并存在另一个列表中。
也可以设置26个字母的前半部分是常量后半部分是变量。
【实验步骤】1、获得输入的两个子句。
2、调用split分割函数,以“v”将子句分割成两个字符串数组并保存到各自的列表中去。
3、在其中的一个列表中找到带有“~”的文字,在另一个列表中分别取文字进行对比,采用字符串分割,查看谓词符号是否相同,如果相同的话,则从各自的列表中删除该元素,完成消解。
反之从新选取列表中的元素在进行对比,直至循环结束。
4、将3中的合一者存储在合一者列表中。
5、如果两个列表中的元素非空,则用“v”对列表中的所有元素进行字符串拼接,最后查询在合一者列表对拼接后的字符串进行替换,替换规则见实验原理。
【实验代码】# -*- coding: utf-8 -*-replaceList=[]resultList=[]def resolution(s1,s2,List1,List2,replaceList):if ',' in s1:index=s1.find('(')headstr1=s1[1:index]#print headstr1if s2.startswith(headstr1):sub1=s1[index+1:len(s1)-1]sub2=s2[index:len(s2)-1]sublist1=sub1.split(',')sublist2=sub2.split(',')#print sublist1#print sublist2for i in range(0,len(sublist1)):if sublist1[i]!=sublist2[i]:if len(sublist1[i])>len(sublist2[i]):replaceList.append(sublist1[i]+"/"+sublist2[i])else:replaceList.append(sublist2[i]+"/"+sublist1[i])List1.remove(s1)List2.remove(s2)else:index=s1.find('(')headstr1=s1[1:index]if s2.startswith(headstr1):sub1=s1[index+1:len(s1)-1]sub2=s2[index:len(s2)-1]if sub1!=sub2:if len(sub1)>len(sub2):replaceList.append(sub1+"/"+sub2)else:replaceList.append(sub2+"/"+sub1)List1.remove(s1)List2.remove(s2)def result(List1,List2,replaceList):s=""#print len(List1)if len(List1)!=0:for i in range(0,len(List1)-1):s+=List1[i]+"v"s+=List1[len(List1)-1]if len(List2)!=0:s+="v"if len(List2)!=0:for i in range(0,len(List2)-1):s+=List2[i]+"v"s+=List2[len(List2)-1]#print sif s=="":return "NIL"else:for r in replaceList:s.replace(r.split('/')[1],r.split('/')[0]) return s#主函数部分str1 = "~P(f(f(a)))vR(z,g(r))"str2 = "Q(x)v~R(f(a),x)"strList1=str1.split('v')strList2=str2.split('v')for s1 in strList1:for s2 in strList2:if'~' in s1:#print s1," ",s2resolution(s1,s2,strList1,strList2,replaceList) elif '~'in s2:resolution(s2,s1,strList2,strList1,replaceList) print"σ=".decode("utf-8").encode("gbk"),print replaceListprint result(strList1,strList2,replaceList)【实验结果】(1)B(x)和~B(x)vC(x)(2)P(x)vQ(x)和~Q(f(y))(3)P(x,f(y))vQ(x)vR(f(a),y)和~P(f(f(a)),z)vR(z,w)(4) ~P(f(f(a)))和P(x)。
实验2+消除文法左递归
int kk=sx.find(sw[h].at(0));
string temp="";
if(ss[kk].find('|')!=-1)
{
bool appflag=false;
for(jj=3;jj<ss[kk].length();jj++)
{
if(ss[kk].at(3)==sa.at(j))
{
sr="";
sr='|';
sr+=se;
ss[j]+=sr;
}
}
}
if(flag1)
{
ss[l]+='|';
ss[l]+='*';
l++;
}
}
sx+=sa.at(j);
}
}
void show()
{
int i=0;
while(i<l)
{
cout<<ss[i]<<endl;
ss[i]="";
i++;
}
{
string temp="";
temp+=c;
int i=0;
for(int j=0;j<l;j++)
{
for(i=0;i<l;i++)
if(temp.find(ss[i].at(0))!=-1)
temp+=ss[i];
}
for(i=0;i<l;i++)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
不确定的有穷自动机的化简2015年11月25日星期三班级:软件工程学号: E21314003 姓名:李世1. 目的与要求通过设计、编写和调试,将不确定的有穷自动机转换为与之等价的确定的有穷自动机的程序,使学生了解子集法。
掌握转换过程中的相关概念和方法。
DFA的表现形式可以是表格或图形。
2. 理论基础有穷自动机(也称有限自动机)作为一种识别装置,它能准确地识别正规集,即识别正规式所表示的集合. 应用有穷自动机这个理论,为词法分析程序的自动构造寻找有效的方法和工具。
有穷自动机分为两类,即,确定的有穷自动机(Deterministic Finite Automata)和不确定的有穷自动机(Nondeterministic Finite Automata) 。
(1) 不确定的有穷自动机的定义:一个不确定的有穷自动机(NFA)M是一个五元组:NFA M={K,Σ,f,S,Z},其中:K为状态的有穷非空集;Σ 为有穷输入字母表;f为K× Σ* 到K的子集(2K)的一种映射, 2K表示K的幂集(f不是一个单值函数);S⊆K是初始状态集;Z ⊆K为终止状态集.例子:NFA M=({S,P,Z},{0,1},f,{S,P},{Z}),其中:f(S,0)={P}//函数的结果为集合f(S,1)={S,Z}f(P,1)={Z}f(Z,0)={P}f(Z,1)={P}状态图表示为:矩阵表示为:(2) 确定的有穷自动机的定义:一个确定的有穷自动机(DFA)M 是一个五元组:M=(K,Σ,f,S,Z)其中:K是一个有穷集,它的每个元素称为一个状态;Σ是一个有穷字母表,它的每个元素称为一个输入符号,所以也称Σ为输入符号表;f是转换函数,是在K×Σ→K上的映射,即,如f(ki,a)=kj,(ki ∈K,kj∈K)就意味着,当前状态为ki,输入符为a时,将转换为下一个状态kj,我们把kj称作ki的一个后继状态;S∈K是唯一的一个初态;Z⊂ K是一个终态集,终态也称可接受状态或结束状态。
例子:DFA M=({S,U,V,Q},{a,b},f,S,{Q}),其中f定义为:f(S,a)=U f(V,a)=Uf(S,b)=V f(V,b)=Qf(U,a)=Q f(Q,a)=Qf(U,b)=V f(Q,b)=Q状态图表示为:矩阵表示为:(3) 确定有限自动机和不确定有限自动机DFA是NFA的特例。
对每个NFA N一定存在一个DFA M,使得L(M)=L(N)。
对每个NFA N存在着与之等价的DFA M。
有一种算法,将NFA转换成接受同样语言的DFA.这种算法称为子集法.子集法的基本思想:让DFA的每一个状态对应NFA的一组状态,也就是让DFA使用它的状态去记录在NFA读入一个输入符号后可能达到的所有状态。
注意:与某一NFA等价的DFA不唯一.a) 定义对状态集合I的几个有关运算:状态集合I的ε-闭包:表示为ε-closure(I),定义为一状态集,是状态集I中的任何状态S经任意条ε弧而能到达的状态的集合。
状态集合I中的任何状态S都属于ε-closure(I)。
状态集合I的a弧转换:表示为move(I, a)定义为状态集合J,其中J是所有那些可从I中的某一状态经过一条a弧而到达的状态的全体。
三、调试测试四、程序源代码#include<iostream> #include<string>#define MAXS 100using namespace std;string NODE;string CHANGE;int N;struct edge{string first;string change;string last;};struct chan{string ltab;string jihe[MAXS];};void kong(int a){int i;for(i=0;i<a;i++)cout<<' ';}//排序void paixu(string &a){int i,j;char b;for(j=0;j<a.length();j++)for(i=0;i<a.length();i++)if(NODE.find(a[i])>NODE.find(a[i+1])) {b=a[i];a[i]=a[i+1];a[i+1]=b;}}void eclouse(char c,string &he,edge b[]) {int k;for(k=0;k<N;k++){if(c==b[k].first[0])if(b[k].change=="*"){if(he.find(b[k].last)>he.length())he+=b[k].last;eclouse(b[k].last[0],he,b);}}}void move(chan &he,int m,edge b[]){int i,j,k,l;k=he.ltab.length();l=he.jihe[m].length();for(i=0;i<k;i++)for(j=0;j<N;j++)if((CHANGE[m]==b[j].change[0])&&(he.ltab[i]==b[j].first[0]))if(he.jihe[m].find(b[j].last[0])>he.jihe[m].length())he.jihe[m]+=b[j].last[0];for(i=0;i<l;i++)for(j=0;j<N;j++)if((CHANGE[m]==b[j].change[0])&&(he.jihe[m][i]==b[j].first[0]))if(he.jihe[m].find(b[j].last[0])>he.jihe[m].length())he.jihe[m]+=b[j].last[0];}//输出void outputfa(int len,int h,chan *t){int i,j,m;cout<<" I ";for(i=0;i<len;i++)cout<<'I'<<CHANGE[i]<<" ";cout<<endl<<"-------------------------"<<endl;for(i=0;i<h;i++){cout<<' '<<t[i].ltab;m=t[i].ltab.length();for(j=0;j<len;j++){kong(8-m);m=t[i].jihe[j].length();cout<<t[i].jihe[j];}cout<<endl;}}void main(){edge *b=new edge[MAXS];int i,j,k,m,n,h,x,y,len;bool flag;string jh[MAXS],endnode,ednode,sta;cout<<"********************************************"<<endl;cout<<"* 页式地址重定位模拟 *"<<endl;cout<<"* 作者:李世 E21314003 *"<<endl;cout<<"* 13级软件工程 *"<<endl;cout<<"********************************************"<<endl;cout<<"请输入NFA各边信息(起点条件[空为*] 终点),以#结束:"<<endl;for(i=0;i<MAXS;i++){cin>>b[i].first;if(b[i].first=="#") break;cin>>b[i].change>>b[i].last;} N=i; /*for(j=0;j<N;j++) cout<<b[j].first<<b[j].change<<b[j].last<<endl;*/ for(i=0;i<N;i++){if(NODE.find(b[i].first)>NODE.length())NODE+=b[i].first;if(NODE.find(b[i].last)>NODE.length())NODE+=b[i].last;if((CHANGE.find(b[i].change)>CHANGE.length())&&(b[i].change!="*")) CHANGE+=b[i].change;}len=CHANGE.length();cout<<"结点中属于终态的是:"<<endl;cin>>endnode;for(i=0;i<endnode.length();i++)if(NODE.find(endnode[i])>NODE.length()){cout<<"所输终态不在集合中,错误!"<<endl;return;} //cout<<"endnode="<<endnode<<endl;chan *t=new chan[MAXS];t[0].ltab=b[0].first;h=1;eclouse(b[0].first[0],t[0].ltab,b); //求e-clouse//cout<<t[0].ltab<<endl;for(i=0;i<h;i++){for(j=0;j<t[i].ltab.length();j++)for(m=0;m<len;m++)eclouse(t[i].ltab[j],t[i].jihe[m],b); //求e-clousefor(k=0;k<len;k++){ //cout<<t[i].jihe[k]<<"->";move(t[i],k,b); //求move(I,a)//cout<<t[i].jihe[k]<<endl;for(j=0;j<t[i].jihe[k].length();j++)eclouse(t[i].jihe[k][j],t[i].jihe[k],b); //求e-clouse }for(j=0;j<len;j++){paixu(t[i].jihe[j]); //对集合排序以便比较for(k=0;k<h;k++){flag=operator==(t[k].ltab,t[i].jihe[j]);if(flag)break;}if(!flag&&t[i].jihe[j].length())t[h++].ltab=t[i].jihe[j];}}cout<<endl<<"状态转换矩阵如下:"<<endl;outputfa(len,h,t); //输出状态转换矩阵//状态重新命名string *d=new string[h];NODE.erase();cout<<endl<<"重命名:"<<endl;for(i=0;i<h;i++){sta=t[i].ltab;t[i].ltab.erase();t[i].ltab='A'+i;NODE+=t[i].ltab;cout<<'{'<<sta<<"}="<<t[i].ltab<<endl;for(j=0;j<endnode.length();j++)if(sta.find(endnode[j])<sta.length())d[1]=ednode+=t[i].ltab;for(k=0;k<h;k++)for(m=0;m<len;m++)if(sta==t[k].jihe[m])t[k].jihe[m]=t[i].ltab;}for(i=0;i<NODE.length();i++)if(ednode.find(NODE[i])>ednode.length())d[0]+=NODE[i];endnode=ednode;cout<<endl<<"DFA如下:"<<endl;outputfa(len,h,t); //输出DFAcout<<"其中终态为:"<<endnode<<endl; //DFA最小化m=2;sta.erase();flag=0;for(i=0;i<m;i++){//cout<<"d["<<i<<"]="<<d[i]<<endl;for(k=0;k<len;k++){//cout<<"I"<<CHANGE[k]<<endl;y=m;for(j=0;j<d[i].length();j++){for(n=0;n<y;n++){if(d[n].find(t[NODE.find(d[i][j])].jihe[k])<d[n].length()||t[NODE.find(d[i][j])].ji he[k].length()==0){if(t[NODE.find(d[i][j])].jihe[k].length()==0)x=m;elsex=n;if(!sta.length()){sta+=x+48;}elseif(sta[0]!=x+48){d[m]+=d[i][j];flag=1;d[i].erase(j,1); //cout<<d[i]<<endl;j--;}break; //跳出n}}//n}//jif(flag){m++;flag=0;} //cout<<"sta="<<sta<<endl;sta.erase();}//k}//icout<<endl<<"集合划分:";for(i=0;i<m;i++)cout<<"{"<<d[i]<<"} ";cout<<endl; //状态重新命名chan *md=new chan[m];NODE.erase();cout<<endl<<"重命名:"<<endl;for(i=0;i<m;i++){md[i].ltab='A'+i;NODE+=md[i].ltab;cout<<"{"<<d[i]<<"}="<<md[i].ltab<<endl;}for(i=0;i<m;i++)for(k=0;k<len;k++)for(j=0;j<h;j++){if(d[i][0]==t[j].ltab[0]){for(n=0;n<m;n++){if(!t[j].jihe[k].length())break;elseif(d[n].find(t[j].jihe[k])<d[n].length()){md[i].jihe[k]=md[n].ltab;break;}}break;}}ednode.erase();for(i=0;i<m;i++)for(j=0;j<endnode.length();j++)if(d[i].find(endnode[j])<d[i].length()&&ednode.find(md[i].ltab))ednode+=md[i].ltab;endnode=ednode;cout<<endl<<"最小化DFA如下:"<<endl;outputfa(len,m,md);cout<<"其中终态为:"<<endnode<<endl;}。