编译原理实验2

合集下载

《编译原理(实验部分)》实验2_PL0词法分析

《编译原理(实验部分)》实验2_PL0词法分析

《编译原理》(实验部分)实验2_PL0 词法分析一、实验目的加深和巩固对于词法分析的了解和掌握;初步认识PL/0 语言的基础和简单的程序编写;通过本实验能够初步的了解和掌握程序词法分析的整个过程;提高自己上机和编程过程中处理具体问题的能力。

二、实验设备1、P C兼容机一台;操作系统为WindowsWindowsX P2、Visual C++ 6.0 或以上版本,Windows 2000 或以上版本,汇编工具 (在Software 子目录下)。

三、实验原理PL/O语言的编译程序,是用高级语言PASCAL语言书写的。

整个编译过程是由一些嵌套及并列的过程或函数完成。

词法分析程序是独立的过程GETSY完成,供语法分析读单词时使用。

四、实验步骤阅读所给出的词法分析程序( pl0_lexical.c ),搞懂程序中每一个变量的含义,以及每一个过程的作用,并在该过程中进行中文注释;阅读完程序后,画出各过程的流程图;给出的程序包含两处输入错误,利用所给的pl/0 源程序(test.pl0) 对程序进行调试,使其能正确对所给文件进行分析并能够解释运行;在阅读懂所给出的词法分析程序后,将你对词法分析的理解写在实验报告上。

实验代码#include<stdio.h>main(){ printf ("my name is 08061118 yuchaofeng ");}主程序:#include <stdio.h>#include <ctype.h>#include <alloc.h>#include <stdlib.h>#include <string.h>#define NULL 0FILE *fp;char cbuffer;char *key[8]={"DO","BEGIN","ELSE","END","IF","THEN","VAR","WHILE"}; char *border[6]={",",";",":=",".","(",")"};char *arithmetic[4]={"+","-","*","/"};char *relation[6]={"<","<=","=",">",">=","<>"};char *consts[20];char *label[20];int constnum=0,labelnum=0;int search(char searchchar[],int wordtype){int i=0;switch (wordtype) {case 1:for (i=0;i<=7;i++){if (strcmp(key[i],searchchar)==0)return(i+1);};case 2:{for (i=0;i<=5;i++){if (strcmp(border[i],searchchar)==0)return(i+1);};return(0);}case 3:{for (i=0;i<=3;i++){ if (strcmp(arithmetic[i],searchchar)==0){};};return(0);};case 4:{for (i=0;i<=5;i++){ if (strcmp(relation[i],searchchar)==0){return(i+1);};};return(0);};case 5:{for (i=0;i<=constnum;i++){ if (strcmp(consts[i],searchchar)==0){return(i+1);};}consts[i-1]=(char *)malloc(sizeof(searchchar));strcpy(consts[i-1],searchchar);constnum++;return(i);};case 6:{for (i=0;i<=labelnum;i++){ if (strcmp(label[i],searchchar)==0){ return(i+1);};}label[i-1]=(char *)malloc(sizeof(searchchar)); strcpy(label[i-1],searchchar);return(i);};}}char alphaprocess(char buffer){int atype;int i=-1;char alphatp[20];while ((isalpha(buffer))||(isdigit(buffer))){ alphatp[++i]=buffer; buffer=fgetc(fp);}; alphatp[i+1]='\0';if (atype=search(alphatp,1)) printf("%s (1,%d)\n",alphatp,atype-1); else { atype=search(alphatp,6);printf("%s (6,%d)\n",alphatp,atype-1); };return(buffer);char digitprocess(char buffer){int i=-1;char digittp[20];int dtype;while ((isdigit(buffer))){ digittp[++i]=buffer;buffer=fgetc(fp);}digittp[i+1]='\0';dtype=search(digittp,5);printf("%s (5,%d)\n",digittp,dtype-1); return(buffer);}char otherprocess(char buffer){int i=-1;char othertp[20];int otype,otypetp;othertp[0]=buffer;othertp[1]='\0';if (otype=search(othertp,3)){printf("%s (3,%d)\n",othertp,otype-1);buffer=fgetc(fp);goto out;};if (otype=search(othertp,4)){buffer=fgetc(fp);othertp[1]=buffer;othertp[2]='\0';if (otypetp=search(othertp,4)){printf("%s (4,%d)\n",othertp,otypetp-1); goto out;}elseothertp[1]='\0';printf("%s (4,%d)\n",othertp,otype-1);goto out;};if (buffer==':'){ buffer=fgetc(fp);if (buffer=='=')printf(":= (2,2)\n");buffer=fgetc(fp);goto out;}else{if (otype=search(othertp,2)){ printf("%s (2,%d)\n",othertp,otype-1); buffer=fgetc(fp); goto out;}};if ((buffer!='\n')&&(buffer!=' '))printf("%c error,not a word\n",buffer); buffer=fgetc(fp);out: return(buffer);} void main(){ int i;for (i=0;i<=20;i++){label[i]=NULL; consts[i]=NULL;};if ((fp=fopen("skh.c","r"))==NULL) printf("error");else{ cbuffer = fgetc(fp);while (cbuffer!=EOF){if (isalpha(cbuffer)) cbuffer=alphaprocess(cbuffer);else if (isdigit(cbuffer))cbuffer=digitprocess(cbuffer); else cbuffer=otherprocess(cbuffer); };printf("over\n");};}。

编译原理实验二LL文法分析

编译原理实验二LL文法分析

实验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<stdio.h>#include<stdlib.h>#include<string.h>#define MAX 20using namespace std;char A[MAX];char B[MAX];char v1[MAX] = { 'i','+','-','*','/','(',')','#'}; char v2[MAX] = {'E','G','T','S','F'};int j = 0, b = 0, top = 0;int l; //l是字符串长度class type{public:char origin;char array[7];int length;};type e, t, g,g0, g1, s, s0,s1, f, f1;type C[10][10];void print(){int a;for ( a = 0; a <= top + 1; a++)cout<<A[a];cout << "\t\t";}void print1(){int j;for (j = 0; j<b; j++)cout << " ";for (j = b; j <= l; j++)cout << B[j];cout << "\t\t\t";}int main(){int m, n, k = 0;int flag = 0,finish = 0;char ch, x;type cha;e.origin = 'E';strcpy(e.array, "TG");e.length = 2;t.origin = 'T';strcpy(t.array, "FS");t.length = 2;g.origin = 'G';strcpy(g.array, "+TG");g.length = 3;g0.origin = 'G';strcpy(g0.array, "-TG");g0.length = 3;g1.origin = 'G';g1.array[0] = '^';g1.length = 1;s.origin = 'S';strcpy(s.array, "*FS");s.length = 3;s0.origin = 'S';strcpy(s0.array, "/FS");s0.length = 3;s1.origin = 'S';s1.array[0] = '^';s1.length = 1;f.origin = 'F';strcpy(f.array, "(E)");f.length = 3;f1.origin = 'F';f1.array[0] = 'i';f1.length = 1;for (m = 0; m <= 4;m++)for (n = 0; n <= 7; n++)C[m][n].origin = 'N';/*C[0][0] = e; C[0][3] = e; C[1][2] = g0;C[1][1] = g; C[1][4] = g1; C[1][5] = g1;C[2][0] = t; C[2][3] = t;C[3][1] = s1; C[3][2] = s;C[3][4] = C[3][5] = s1;C[4][0] = f1; C[4][3] = f;*/C[0][0] = e; C[0][5] = e;C[1][1] = g; C[1][2] = g0;C[1][6] = g1; C[1][7] = g1;C[2][0] = t; C[2][5] = t;C[3][1] = s1; C[3][2] = s1;C[3][3] = s;C[3][4] = s0; C[3][6] = s1; C[3][7] = s1;C[4][0] = f1; C[4][5] = f;cout << "input,please~:";do{cin >> ch;if ((ch!='i') &&(ch!='+') &&(ch!='-') &&(ch!='*') &&(ch!='/') &&(ch!='(') &&(ch!=')') &&(ch!='#')){cout << "Error!\n";exit(1);}B[j] = ch;j++;} while (ch != '#');l = j; //l是字符串长度/* for(j=0;j<l;j++)cout<<B[j]<<endl;*/ch = B[0]; //当前分析字符A[top] = '#';A[++top] = 'E';/*'#','E'进栈*/cout << "步骤\t\t分析栈\t\t剩余字符\t\t所用字符\n"; do{x = A[top--];cout << k++;cout << "\t\t";for (j = 0; j<=7 ; j++)if (x == v1[j]){flag = 1;break;}if (flag==1){if (x == '#'){finish = 1;cout << "acc!\n";getchar();getchar();exit(1);}if (x == ch){print();print1();cout <<ch << "匹配\n";ch = B[++b];flag = 0;}else{cout<<"x:"<<x<<endl;cout<<"ch:"<<ch<<endl;print();print1();cout <<ch<< "出错\n" ;exit(1);}}else //非终结符{for (j = 0; j <= 4; j++)if (x == v2[j]){m = j;//行号break;}for (j = 0; j <= 7; j++)if (ch == v1[j]){n = j; //列号break;}cha = C[m][n];if (cha.origin != 'N'){print();print1();cout << cha.origin << "->";for (j = 0; j<cha.length; j++)cout << cha.array[j];cout << "\n";for (j = (cha.length - 1); j >= 0; j--)A[++top] = cha.array[j];if (A[top] == '^')/*为空则不进栈*/top--;}else{print();print1();cout<<"x:"<<x<<endl;cout<<"ch:"<<ch<<endl;cout<<"sign1"<<endl;cout << "Error!" << x;exit(1);}}} while (finish == 0);}。

编译原理_实验报告实验二__语法分析(算符优先) 2

编译原理_实验报告实验二__语法分析(算符优先) 2

华北水利水电学院编译原理实验报告一、实验题目:语法分析(算符优先分析程序)(1)选择最有代表性的语法分析方法算符优先法;(2)选择对各种常见程序语言都用的语法结构,如赋值语句(尤指表达式)作为分析对象,并且与所选语法分析方法要比较贴切。

二、实验内容(1)根据给定文法,先求出FirstVt和LastVt集合,构造算符优先关系表(要求算符优先关系表输出到屏幕或者输出到文件);(2)根据算法和优先关系表分析给定表达式是否是该文法识别的正确的算术表达式(要求输出归约过程)(3)给定表达式文法为:G(E’): E’→#E#E→E+T | TT→T*F |FF→(E)|i(4) 分析的句子为:(i+i)*i和i+i)*i三、程序源代#include<stdlib.h>#include<stdio.h>#include<string.h>#include<iostream.h>#define SIZE 128char priority[6][6]; //算符优先关系表数组char input[SIZE]; //存放输入的要进行分析的句子char remain[SIZE]; //存放剩余串char AnalyseStack[SIZE]; //分析栈void analyse();int testchar(char x); //判断字符X在算符优先关系表中的位置void remainString(); //移进时处理剩余字符串,即去掉剩余字符串第一个字符int k;void init()//构造算符优先关系表,并将其存入数组中{priority[0][2]='<';priority[0][3]='<';priority[0][4]='>';priority[0][5]='>';priority[1][0]='>';priority[1][1]='>';priority[1][2]='<';priority[1][3]='<';priority[1][4]='>';priority[1][5]='>';priority[2][0]='>';priority[2][1]='>';priority[2][2]='$';//无优先关系的用$表示priority[2][3]='$';priority[2][4]='>';priority[2][5]='>';priority[3][0]='<';priority[3][1]='<';priority[3][2]='<';priority[3][3]='<';priority[3][4]='=';priority[3][5]='$';priority[4][0]='>';priority[4][1]='>';priority[4][2]='$';priority[4][3]='$';priority[4][4]='>';priority[4][5]='>';priority[5][0]='<';priority[5][3]='<';priority[5][4]='$';priority[5][5]='=';}void analyse()//对所输入的句子进行算符优先分析过程的函数{FILE *fp;fp=fopen("li","a");int i,j,f,z,z1,n,n1,z2,n2;int count=0;//操作的步骤数char a; //用于存放正在分析的字符char p,Q,p1,p2;f=strlen(input); //测出数组的长度for(i=0;i<=f;i++){a=input[i];if(i==0)remainString();if(AnalyseStack[k]=='+'||AnalyseStack[k]=='*'||AnalyseStack[k]=='i'||Analy seStack[k]=='('||AnalyseStack[k]==')'||AnalyseStack[k]=='#')j=k;elsej=k-1;z=testchar(AnalyseStack[j]);//从优先关系表中查出s[j]和a的优先关系if(a=='+'||a=='*'||a=='i'||a=='('||a==')'||a=='#')n=testchar(a);else //如果句子含有不是终结符集合里的其它字符,不合法{printf("错误!该句子不是该文法的合法句子!\n");break;}if(p=='$'){printf("错误!该句子不是该文法的合法句子!\n");return;}if(p=='>'){ for( ; ; ){Q=AnalyseStack[j];if(AnalyseStack[j-1]=='+'||AnalyseStack[j-1]=='*'||AnalyseStack[j-1]=='i'||AnalyseStack[j-1]=='('||AnalyseStack[j-1]==')'||AnalyseStack[j-1]=='#')j=j-1;elsej=j-2;z1=testchar(AnalyseStack[j]);n1=testchar(Q);p1=priority[z1][n1];if(p1=='<') //把AnalyseStack[j+1]~AnalyseStack[k]归约为N{count++;printf("(%d) %s\t%10c\t%5c%17s\t 归约\n",count,AnalyseStack,p,a,remain);fprintf(fp,"(%d) %s\t%17s\t %s\n",count,AnalyseStack,remain,"归约");k=j+1;i--;AnalyseStack[k]='N';int r,r1;r=strlen(AnalyseStack);for(r1=k+1;r1<r;r1++)AnalyseStack[r1]='\0';break;}else}}else{if(p=='<') //表示移进{count++;printf("(%d) %s\t%10c\t%5c%17s\t 移进\n",count,AnalyseStack,p,a,remain);fprintf(fp,"(%d) %s\t%17s\t %s\n",count,AnalyseStack,remain,"移进");k=k+1;AnalyseStack[k]=a;remainString();}else{if(p=='='){z2=testchar(AnalyseStack[j]);n2=testchar('#');p2=priority[z2][n2];if(p2=='='){count++;printf("(%d) %s\t%10c\t%5c%17s\t 接受\n",count,AnalyseStack,p,a,remain);fprintf(fp,"(%d) %s\t%17s\t %s\n",count,AnalyseStack,remain,"接受");printf("该句子是该文法的合法句子。

编译原理实验报告LL(2)分析法

编译原理实验报告LL(2)分析法

课程编译原理实验名称实验二 LL(1)分析法实验目的1.掌握LL(1)分析法的基本原理;2.掌握LL(1)分析表的构造方法;3.掌握LL(1)驱动程序的构造方法。

一.实验内容及要求根据某一文法编制调试LL(1)分析程序,以便对任意输入的符号串进行分析。

本次实验的目的主要是加深对预测分析LL(1)分析法的理解。

对下列文法,用LL(1)分析法对任意输入的符号串进行分析:(1)E->TG(2)G->+TG(3)G->ε(4)T->FS(5)S->*FS(6)S->ε(7)F->(E)(8)F->i程序输入一以#结束的符号串(包括+*()i#),如:i+i*i#。

输出过程如下:步骤分析栈剩余输入串所用产生式1 E i+i*i# E->TG... ... ... ...二.实验过程及结果代码如下:#include<iostream>#include "edge.h"using namespace std;edge::edge(){cin>>left>>right;rlen=right.length();if(NODE.find(left)>NODE.length())NODE+=left;}string edge::getlf(){return left;}string edge::getrg(){return right;}string edge::getfirst(){return first;}string edge::getfollow(){return follow;}string edge::getselect(){return select;}string edge::getro(){string str;str+=right[0];return str;}int edge::getrlen(){return right.length();}void edge::newfirst(string w){int i;for(i=0;i<w.length();i++)if(first.find(w[i])>first.length())first+=w[i];}void edge::newfollow(string w){int i;for(i=0;i<w.length();i++)if(follow.find(w[i])>follow.length()&&w[i]!='@')follow+=w[i];}void edge::newselect(string w){int i;for(i=0;i<w.length();i++)if(select.find(w[i])>select.length()&&w[i]!='@')select+=w[i];}void edge::delfirst(){int i=first.find('@');first.erase(i,1);}int SUM;string NODE,ENODE;//计算firstvoid first(edge ni,edge *n,int x){int i,j;for(j=0;j<SUM;j++){if(ni.getlf()==n[j].getlf()){if(NODE.find(n[j].getro())<NODE.length()){for(i=0;i<SUM;i++)if(n[i].getlf()==n[j].getro())first(n[i],n,x);}elsen[x].newfirst(n[j].getro());}}}//计算followvoid follow(edge ni,edge *n,int x){int i,j,k,s;string str;for(i=0;i<ni.getrlen();i++){s=NODE.find(ni.getrg()[i]);if(s<NODE.length()&&s>-1) //是非终结符if(i<ni.getrlen()-1) //不在最右for(j=0;j<SUM;j++)if(n[j].getlf().find(ni.getrg()[i])==0){if(NODE.find(ni.getrg()[i+1])<NODE.length()){for(k=0;k<SUM;k++)if(n[k].getlf().find(ni.getrg()[i+1])==0){n[j].newfollow(n[k].getfirst());if(n[k].getfirst().find("@")<n[k].getfirst().length())n[j].newfollow(ni.getfollow());}}else{str.erase();str+=ni.getrg()[i+1];n[j].newfollow(str);}}}}//计算selectvoid select(edge &ni,edge *n){int i,j;if(ENODE.find(ni.getro())<ENODE.length()){ni.newselect(ni.getro());if(ni.getro()=="@")ni.newselect(ni.getfollow());}elsefor(i=0;i<ni.getrlen();i++){for(j=0;j<SUM;j++)if(ni.getrg()[i]==n[j].getlf()[0]){ni.newselect(n[j].getfirst());if(n[j].getfirst().find('@')>n[j].getfirst().length())return;}}}//输出集合void out(string p){int i;if(p.length()==0)return;cout<<"{";for(i=0;i<p.length()-1;i++){cout<<p[i]<<",";}cout<<p[i]<<"}";}//连续输出符号void outfu(int a,string c){int i;for(i=0;i<a;i++)cout<<c;}//输出预测分析表void outgraph(edge *n,string (*yc)[50]){int i,j,k;bool flag;for(i=0;i<ENODE.length();i++){if(ENODE[i]!='@'){outfu(10," ");cout<<ENODE[i];}}outfu(10," ");cout<<"#"<<endl;int x;for(i=0;i<NODE.length();i++){outfu(4," ");cout<<NODE[i];outfu(5," ");for(k=0;k<ENODE.length();k++){flag=1;for(j=0;j<SUM;j++){if(NODE[i]==n[j].getlf()[0]){x=n[j].getselect().find(ENODE[k]);if(x<n[j].getselect().length()&&x>-1){cout<<"->"<<n[j].getrg();yc[i][k]=n[j].getrg();outfu(9-n[j].getrlen()," ");flag=0;}x=n[j].getselect().find('#');if(k==ENODE.length()-1&&x<n[j].getselect().length()&&x>-1){cout<<"->"<<n[j].getrg();yc[i][j]=n[j].getrg();}}}if(flag&&ENODE[k]!='@')outfu(11," ");}cout<<endl;}}//分析符号串int pipei(string &chuan,string &fenxi,string (*yc)[50],int &b){char ch,a;int x,i,j,k;b++;cout<<endl<<" "<<b;if(b>9)outfu(8," ");elseoutfu(9," ");cout<<fenxi;outfu(26-chuan.length()-fenxi.length()," "); cout<<chuan;outfu(10," ");a=chuan[0];ch=fenxi[fenxi.length()-1];x=ENODE.find(ch);if(x<ENODE.length()&&x>-1){if(ch==a){fenxi.erase(fenxi.length()-1,1);chuan.erase(0,1);cout<<"'"<<a<<"'匹配";if(pipei(chuan,fenxi,yc,b))return 1;elsereturn 0;}elsereturn 0;}else{if(ch=='#'){if(ch==a){cout<<"分析成功"<<endl;return 1;}elsereturn 0;}elseif(ch=='@'){fenxi.erase(fenxi.length()-1,1);if(pipei(chuan,fenxi,yc,b))return 1;elsereturn 0;}else{i=NODE.find(ch);if(a=='#'){x=ENODE.find('@');if(x<ENODE.length()&&x>-1)j=ENODE.length()-1;elsej=ENODE.length();}elsej=ENODE.find(a);if(yc[i][j].length()){cout<<NODE[i]<<"->"<<yc[i][j];fenxi.erase(fenxi.length()-1,1);for(k=yc[i][j].length()-1;k>-1;k--)if(yc[i][j][k]!='@')fenxi+=yc[i][j][k];if(pipei(chuan,fenxi,yc,b))return 1;elsereturn 0;}elsereturn 0;}}}void main(){edge *n;string str,(*yc)[50];int i,j,k;bool flag=0;cout<<"请输入上下文无关文法的总规则数:"<<endl;cin>>SUM;cout<<"请输入具体规则(格式:左部右部,@为空):"<<endl;n=new edge[SUM];for(i=0;i<SUM;i++)for(j=0;j<n[i].getrlen();j++){str=n[i].getrg();if(NODE.find(str[j])>NODE.length()&&ENODE.find(str[j])>ENODE.length()) ENODE+=str[j];}//计算first集合for(i=0;i<SUM;i++){first(n[i],n,i);}//outfu(10,"~*~");cout<<endl;for(i=0;i<SUM;i++)if(n[i].getfirst().find("@")<n[i].getfirst().length()){if(NODE.find(n[i].getro())<NODE.length()){for(k=1;k<n[i].getrlen();k++){if(NODE.find(n[i].getrg()[k])<NODE.length()){for(j=0;j<SUM;j++){if(n[i].getrg()[k]==n[j].getlf()[0]){n[i].newfirst(n[j].getfirst());break;}}if(n[j].getfirst().find("@")>n[j].getfirst().length()){n[i].delfirst();break;}}}}}//计算follow集合for(k=0;k<SUM;k++){for(i=0;i<SUM;i++){if(n[i].getlf()==n[0].getlf())n[i].newfollow("#");follow(n[i],n,i);}for(i=0;i<SUM;i++){for(j=0;j<SUM;j++)if(n[j].getrg().find(n[i].getlf())==n[j].getrlen()-1)n[i].newfollow(n[j].getfollow());}}//计算select集合for(i=0;i<SUM;i++){select(n[i],n);}for(i=0;i<NODE.length();i++){str.erase();for(j=0;j<SUM;j++)if(n[j].getlf()[0]==NODE[i]){if(!str.length())str=n[j].getselect();else{for(k=0;k<n[j].getselect().length();k++)if(str.find(n[j].getselect()[k])<str.length()){flag=1;break;}}}}//输出cout<<endl<<"非终结符";outfu(SUM," ");outfu(SUM," ");cout<<"Follow"<<endl;outfu(5+SUM,"-*-");cout<<endl;for(i=0;i<NODE.length();i++){for(j=0;j<SUM;j++)if(NODE[i]==n[j].getlf()[0]){outfu(3," ");cout<<NODE[i];outfu(SUM+4," ");out(n[j].getfirst());outfu(SUM+4-2*n[j].getfirst().length()," ");out(n[j].getfollow());cout<<endl;break;}}outfu(5+SUM,"-*-");cout<<endl<<"判定结论:";if(flag){cout<<"该文法不是LL(1)文法!"<<endl;return;}else{cout<<"该文法是LL(1)文法!"<<endl;}//输出预测分析表cout<<endl<<"预测分析表如下:"<<endl;yc=new string[NODE.length()][50];outgraph(n,yc);string chuan,fenxi,fchuan;cout<<endl<<"请输入符号串:";cin>>chuan;fchuan=chuan;fenxi="#";fenxi+=NODE[0];i=0;cout<<endl<<"预测分析过程如下:"<<endl;outfu(7," ");cout<<"分析栈";outfu(10," ");cout<<"剩余输入串";outfu(8," ");cout<<"推导所用产生式或匹配";if(pipei(chuan,fenxi,yc,i))cout<<endl<<"输入串"<<fchuan<<"是该文法的句子!"<<endl;elsecout<<endl<<"输入串"<<fchuan<<"不是该文法的句子!"<<endl;}截屏如下:三.实验中的问题及心得这次实验让我更加熟悉了LL(1)的工作流程以及LL(1)分析表的构造方法。

昆明理工编译原理实验报告2

昆明理工编译原理实验报告2

昆明理工大学信息工程与自动化学院学生实验报告( 2014 — 2015 学年 第1学期 )课程名称:编译原理 开课实验室:信自楼445 时间:2014年12月15日 一、实验目的及要求目的:编制一个语法分析程序,实现对词法分析程序所提供的单词序列进行语法检查和结构分析。

要求:在实验一词法分析的基础上,采用递归子程序法或其他适合的语法分析方法,实现其语法分析程序。

要求编译后能检查出语法错误。

已知待分析的C 语言子集的语法,用EBNF 表示如下: <程序>→main()<语句块> <语句块> →‘{’<语句串>‘}’ <语句串> → <语句> {; <语句> };<语句> → <赋值语句> |<条件语句>|<循环语句> <赋值语句>→ID=<表达式><条件语句>→if ‘(‘条件’)’<语句块> <循环语句>→while ’(‘<条件>’)‘<语句块> <条件> → <表达式><关系运算符> <表达式> <表达式> →<项>{+<项>|-<项>}年级、专业、班学号姓名成绩实验项目名称 实验二 语法分析器指导教师李亚教师评语该同学是否了解实验原理: A.了解□ B.基本了解□ C.不了解□ 该同学的实验能力: A.强 □ B.中等 □ C.差 □ 该同学的实验是否达到要求: A.达到□B.基本达到□C.未达到□ 实验报告是否规范: A.规范□ B.基本规范□ C.不规范□是否有运行结果与分析: A.详细□ B.一般 □ C.没有 □ 是否有总结与体会: A.详细□B.一般 □C.没有 □教师签名: 年 月 日<项> → <因子> {* <因子> |/ <因子>}<因子> →ID|NUM| ‘(’<表达式>‘)’<关系运算符> →<|<=|>|>=|==|!=二、实验原理及基本技术路线图(方框原理图或程序流程图)开始调用打开对话框输入文法优化输入的文法并判断文法合法性获取文法的终结符和非终结符对文法求SELECT集并判断合法性构造文法分析法输入并分析句子结束三、所用仪器、材料(设备名称、型号、规格等或使用软件)1台PC及visual c++ 6.0软件四、实验方法、步骤(或:程序代码或操作过程)#include <iostream>#include <string>using namespace std;char prog[80],token[8];char ch;int syn,p,m,n,sum,k=0;char *key[6]={"main","int","char","if","else","while"};void scaner();void lrparser();void yucu();void statement();void expression();void term();void factor();void main(){p=0;cout<<"语法分析"<<endl;cout<<"请输入字符串,以@结尾:"<<endl;do {ch = getchar(); prog[p++]=ch;}while(ch!='@');p=0;scaner();lrparser();}void scaner(){sum=m=0;for(n=0;n<8;n++) token[n]=NULL;ch=prog[p++];while(ch==' ') ch=prog[p++];if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')){while((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')||(ch>='0'&&ch<='9')){token[m++]=ch; ch=prog[p++];}token[m++]='\0';p--;syn=10;for(n=0;n<6;n++)if(strcmp(token,key[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=20;}elseswitch(ch){case '<': m=0;token[m++]=ch;ch=prog[p++];if(ch=='<') {syn=33; token[m++]=ch;}else if(ch=='=') {syn=35; token[m++]=ch;}break;case '>': m=0;token[m++]=ch;ch=prog[p++];if(ch=='=') {syn=34; token[m++]=ch;}else {syn=32; p--;}break;case '=':token[m++]=ch;ch=prog[p++];if(ch=='='){ syn=36;token[m++]=ch;}else{ syn=21;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=22; token[0]=ch; break;case '-': syn=23; token[0]=ch; break;case '*': syn=24; token[0]=ch; break;case '/': syn=25; token[0]=ch; break;case ';': syn=31; token[0]=ch; break;case '(': syn=26; token[0]=ch; break;case ')': syn=27; token[0]=ch; break;case '@': syn=0; token[0]=ch; break;default : syn=-1;}}void lrparser(){if(syn==1){scaner();yucu();if(syn=6){scaner();if(syn==0 && (k==0))cout<<"\nsuccess\n"<<endl;}else{if(k!=1)cout<<"\nwhile error\n"<<endl;k=1;}}else{cout<<"\nmain error\n"<<endl;k=1;}return;}void yucu(){statement();while(syn==31){scaner();statement();}return;}void statement(){if(syn==10){scaner();if(syn==18){scaner();expression();}else{cout<<"\nscentence error\n"<<endl;k=1;}}return;}void expression(){term();while(syn==22||syn==23){scaner();term();}return;}void term(){factor();while(syn==24||syn==25){scaner();factor();}return;}void factor(){if(syn==10||syn==20)scaner();else if(syn==26){scaner();expression();if(syn==27)scaner();else{cout<<"( error"<<endl;k=1;}}else{cout<<"expression error"<<endl;k=1;}return;}五、实验过程原始记录( 测试数据、图表、计算等)六、实验结果、分析和结论(程序运行结果、改进、收获)本实验在词法分析的基础上,对提取出的标识符进行语法判断。

编译原理实验全集

编译原理实验全集

目录实验1词法分析 (2)1.1. 目的 (2)1.2. 内容 (2)1.3. 知识 (2)1.4. 步骤 (2)1.5. 问题及解答 (4)1.6. 实验报告要求 (4)实验2自顶向下的语法分析 (5)2.1. 目的 (5)2.2. 知识 (5)2.3. 内容 (6)2.4. 步骤 (10)2.5. 问题及解答 (10)2.6. 提高 (10)2.7. 实验报告要求 (10)实验3自底向上的语法分析 (12)3.1. 目的 (12)3.2. 内容 (12)3.3. 步骤 (14)3.4. 问题 (14)3.5. 实验报告要求 (14)实验4语义分析 (15)4.1. 目的 (15)4.2. 知识 (15)4.3. 内容 (17)4.4. 步骤 (18)4.5. 实验报告要求 (18)实验5 中间代码生成实验6 代码优化与代码生成编译原理实验指导相关说明实验1、2要求独立完成。

实验3、实验4的实现代码(VC++工程)均已调试成功,打包在目录中(lab3,lab4)。

希望认真学习的同学多看看。

由于时间关系,许多地方还没来得及做好,本手册的内容可能比较繁琐。

欢迎大家提出问题和意见。

时间比较紧的同学也请关注每个实验末尾的实验报告要求。

期末实验占10分。

实验1词法分析1.1. 目的构造词法分析器,熟悉编译程序词法分析过程。

掌握 LEX 自动生成工具的使用。

1.2. 内容从本实验开始,用C语言实现一个编译系统。

词法分析是其第一步。

采用Lex工具自动生成大大简化了其中的内容。

因此本实验的重心并不在如何操作,而是在于怎样编写Lex 源程序。

而要编写Lex源程序,首先要定义源语言,即该编译系统所实现的语言。

这里作为例子,我们以C++为基础,采用其部分单词,因此不妨将我们定义的这种语言称之为Mini C++。

1.3. 知识Lex是一个词法分析器的自动构造工具。

相关资料较多。

1.4. 步骤1、在编写LEX源程序前,首先要定义一种高级语言。

编译原理实验 (词法语法分析 附源代码

编译原理实验 (词法语法分析 附源代码

编译原理实验报告******************************************************************************* ******************************************************************************* PL0语言功能简单、结构清晰、可读性强,而又具备了一般高级程序设计语言的必须部分,因而PL0语言的编译程序能充分体现一个高级语言编译程序实现的基本方法和技术。

PL/0语言文法的EBNF表示如下:<程序>::=<分程序>.<分程序> ::=[<常量说明>][<变量说明>][<过程说明>]<语句><常量说明> ::=CONST<常量定义>{,<常量定义>};<常量定义> ::=<标识符>=<无符号整数><无符号整数> ::= <数字>{<数字>}<变量说明> ::=V AR <标识符>{, <标识符>};<标识符> ::=<字母>{<字母>|<数字>}<过程说明> ::=<过程首部><分程序>{; <过程说明> };<过程首部> ::=PROCEDURE <标识符>;<语句> ::=<赋值语句>|<条件语句>|<当循环语句>|<过程调用语句>|<复合语句>|<读语句><写语句>|<空><赋值语句> ::=<标识符>:=<表达式><复合语句> ::=BEGIN <语句> {;<语句> }END<条件语句> ::= <表达式> <关系运算符> <表达式> |ODD<表达式><表达式> ::= [+|-]<项>{<加法运算符> <项>}<项> ::= <因子>{<乘法运算符> <因子>}<因子> ::= <标识符>|<无符号整数>| ‘(’<表达式>‘)’<加法运算符> ::= +|-<乘法运算符> ::= *|/<关系运算符> ::= =|#|<|<=|>|>=<条件语句> ::= IF <条件> THEN <语句><过程调用语句> ::= CALL 标识符<当循环语句> ::= WHILE <条件> DO <语句><读语句> ::= READ‘(’<标识符>{,<标识符>}‘)’<写语句> ::= WRITE‘(’<表达式>{,<表达式>}‘)’<字母> ::= a|b|…|X|Y|Z<数字> ::= 0|1|…|8|9【预处理】对于一个pl0文法首先应该进行一定的预处理,提取左公因式,消除左递归(直接或间接),接着就可以根据所得的文法进行编写代码。

编译原理实验二:消除文法的左递归.doc

编译原理实验二:消除文法的左递归.doc

编译原理实验报告实验名称消除文法的左递归实验时间2013年11月12日院系计算机科学与电子技术系班级11计算机软件学号JV114001 JV114095 JP114065 姓名唐茹韩强强徐思维1.试验目的:输入:任意的上下文无关文法。

输出:消除了左递归的等价文法。

2.实验原理:1.直接左递归的消除消除产生式中的直接左递归是比较容易的。

例如假设非终结符P 的规则为:P →P α / β其中,β是不以P 开头的符号串。

那么,我们可以把P 的规则改写为如下的非直接左递归形式: P →βP ’P ’→αP ’ / ε这两条规则和原来的规则是等价的,即两种形式从P 推出的符号串是相同的。

设有简单表达式文法G[E]: E →E+T/ T T →T*F/ F F →(E )/ I经消除直接左递归后得到如下文法: E →TE ’E ’ →+TE ’/ ε T →FT ’T ’ →*FT ’/ εF →(E )/ I考虑更一般的情况,假定关于非终结符P 的规则为P →P α1 / P α2 /…/ P αn / β1 / β2 /…/βm其中,αi (I =1,2,…,n )都不为ε,而每个βj (j =1,2,…,m )都不以P 开头,将上述规则改写为如下形式即可消除P 的直接左递归:P →β1 P ’ / β2 P ’ /…/βm P ’P ’ →α1P ’ / α2 P ’ /…/ αn P ’ /ε 2.间接左递归的消除直接左递归见诸于表面,利用以上的方法可以很容易将其消除,即把直接左递归改写成直接右递归。

然而文法表面上不存在左递归并不意味着该文法就不存在左递归了。

有些文法虽然表面上不存在左递归,但却隐藏着左递归。

例如,设有文法G[S]:S →Qc/ c Q →Rb/ b R →Sa/ a虽不具有左递归,但S 、Q 、R 都是左递归的,因为经过若干次推导有 S ⇒Qc ⇒Rbc ⇒SabcQ ⇒Rb ⇒Sab ⇒Qcab R ⇒Sa ⇒Qca ⇒Rbca就显现出其左递归性了,这就是间接左递归文法。

编译原理实验2正规式的定义与应用

编译原理实验2正规式的定义与应用

编译原理实验2正规式的定义与应用一、正规式的定义1.1 正规式的概念正规式是描述正规语言的基本表达式,它是由字母表中字母、连接符号、或运算符和闭包运算符组成的字符串。

1.2 正规式的形式化定义设Σ是一个字母表,Σ的任意成员都是一个正规式。

如果r和s是正规式,则r+s、r·s和r*也是正规式,其中+表示或运算,·表示连接运算,*表示闭包运算。

1.3 正规式的应用正规式广泛应用于字符串匹配、模式识别、文本搜索等领域,是编译原理中的重要概念。

二、正规式的深入探讨2.1 正规式的特性正规式具有闭合性、结合性和分配性等基本特性,这使得正规式在描述和处理字符串时非常灵活和强大。

2.2 正规式的最简形式对于同一个正规语言,可以有多个不同的正规式来描述它,但是可以通过化简等操作得到最简形式的正规式。

2.3 正规式的等价性在编译原理中,我们常常需要判断两个正规式是否等价,即它们描述的是否是同一个正规语言,这是编译原理中的一个重要问题。

三、正规式的应用案例分析3.1 正规式的在文本搜索中的应用通过正规式,我们可以方便地描述要搜索的目标字符串的模式,从而实现高效的文本搜索。

3.2 正规式的在词法分析中的应用在编译器的词法分析阶段,正规式用来描述词法单元的模式,如标识符、常数等,对于编译原理学习而言,这是正规式的重要应用之一。

3.3 正规式的在模式识别中的应用正规式也被广泛应用于模式识别领域,可以描述图像、音频等多种形式的模式。

四、总结与展望4.1 对正规式的回顾正规式是编译原理中的基本概念,具有重要的理论意义和实际应用价值,通过深入理解正规式的定义和应用,可以更好地应用于实际问题解决中。

4.2 个人观点正规式作为编译原理中的重要内容,不仅能够帮助我们理解编译器的工作原理,还可以在实际工程项目中发挥重要作用,我对正规式的深度理解有助于我将来在相关领域有更好的应用和发挥。

以上是我的对编译原理实验2正规式的定义与应用的文章,希望对你有所帮助。

编译原理Lab2

编译原理Lab2

编译原理实验报告实验名称:语法分析器设计与实现实验日期: 2016.1.13学生姓名:学生学号:一、实验目的加深对语法分析器的工作过程的理解;加强对语法分析方法的掌握;能够采用一种编程语言实现简单的语法分析程序;能够使用自己编写的分析程序对简单的程序段进行语法分析。

通过本实验,应达到以下目标:1.掌握从源程序文件中读取有效字符的方法和产生源程序的内部表示文件的方法。

2.掌握语法分析的实现方法。

3.上机调试编出的语法分析程序。

二、实验内容编写语法分析程序,利用实验一词法分析的结果,逐个读入经过词法分析生成的Token 序列。

根据定义好的句型,构造LR(1)分析表,根据该表对输入串进行规约,并输出规约序列。

语法分析是编译过程中的一个阶段,在词法分析后进行。

也可以和词法分析结合在一起进行,由语法分析程序调用词法分析程序来获得当前单词供语法分析使用。

输入:Token序列输出:规约序列三、实验方案1.程序的功能:从destination.txt文件读入Token序列,在syntax.txt文件中写入规约序列,格式为X->Y。

2.实现方案:采用LR(1)文法实现:a)定义上下文无关文法(CFG)b)根据CFG构造分层有限自动机c) 根据分层有限自动机构造LR(1)分析表c) 使用LR(1)分析表设计程序四、实验假设定义上下文无关文法如下:S’->SS->if S else SS->if SS->S;SS->EE->(E)E->E+TE->E-TE->TT->T*FT->T/FT->FF->idF->num五、相关的有限自动机根据上下文无关文法构造分层有限自动机(略)六、构造LR(1)分析表根据有限自动机构造LR(1)分析表如下:对于表中的冲突项:r2/S30冲突: 因为if的优先级高于;,所以应该将if S.;S左边的if S归约为S,故应保留r2。

编译原理实验二zy

编译原理实验二zy

实验二语法分析及语义处理实验专业:13计算机一班学号:20130610040109 姓名:赵宇一、【实验目的】加深对语法分析器工作过程的理解;能够采用一种编程语言实现简单的语义分析程序;能够使用自己编写的分析程序对简单的程序段进行语义分析,生成中间代码。

二、【实验内容】1.掌握递归子程序(或过程)的设计方法。

2.掌握用递归子程序法设计语法分析的方法,从而加深对其他方法的理解。

3.掌握目标程序的运行方法,掌握各源程序语句的目标结构。

4.掌握以语法为主导的翻译方法。

5.用递归下降分析法编制语义分析程序。

三、【实验要求】1. 对语法规则有明确的定义;2. 编写的分析程序能够对输入算数表达式进行正确的语义分析;3. 对于遇到的语法、语义错误,能够做出简单的错误处理,给出简单的错误提示,保证语义分析过程;4. 实验报告要求用文法的形式对语义详细说明,说明语义分析程序的工作过程,说明相应翻译动作的实现。

四、【实验步骤】1. 定义语法规则;2. 设置语义过程,插入语义动作;3. 对遇到的语法、语义错误做出错误处理。

五、【算法思想】1、算术表达式的定义算术表达式的文法:〈无符号整数〉∷=〈数字〉 { 〈数字〉 }〈标识符〉∷=〈字母〉 {〈字母〉|〈数字〉 }〈表达式〉∷=〈项〉 {〈加法运算符〉〈项〉 }〈项〉∷=〈因子〉 {〈乘法运算符〉〈因子〉 }〈因子〉∷=〈标志符〉|〈无符号整数〉〈加法运算符〉∷=+|-〈乘法运算符〉∷=*|/〈字母〉∷= a | b | … | z〈数字〉∷= 0 | 1 | … | 92、构造出相应的文法E->TE~E~->+TE~E~->-TE~E~->&T->FT~T~->*FT~T~->\FT~T~->&F->(E)F->nF->zn 表示数字 z 表示字符3、设置语义过程。

(1)emit(char *result,char *ag1,char *op,char *ag2)该函数的功能是生成一个三地址语句送到四元式表中。

编译原理标准实验报告

编译原理标准实验报告

编译原理实验报告江苏科技大学电子信息学院2005年8月19日目录实验一:词法分析设计 (2)实验二:LL(1)预测分析 (10)实验三:逆波兰表达式的产生及计算 (26)实验四:SLR(1)语法分析设计 (48)实验五:应用DAG进行局部优化 (52)实验一词法分析设计一.实验目的通过本实验的编程实践,使学生了解词法分析的任务,掌握词法分析程序设计的原理和构造方法,使学生对编译的基本概念、原理和方法有完整的和清楚的理解,并能正确地、熟练地运用。

二.实验内容用VC++/VB/JAV A语言实现对C语言子集的源程序进行词法分析。

通过输入源程序从左到右对字符串进行扫描和分解,依次输出各个单词的内部编码及单词符号自身值;若遇到错误则显示“Error”,然后跳过错误部分继续显示;同时进行标识符登记符号表的管理。

三.实验步骤1.基于实验的内容,构造程序所需的模块2.根据已建构的模块,写出各个模块的相应程序代码3.在主函数中调用模块来完成所要得到的效果四.参考答案1.源程序'#################################################################### #########################################'####'## 存在问题:如何能较好的判断符号的优先级??##'####'#################################################################### #########################################'******************************************************************** ********************************************' 定义变量'******************************************************************** ********************************************Dim str_stack(1 To 20) As String, str_input As String, str_output As String, current As StringDim stack_p As Double, str_feihouzhui As String'******************************************************************** ********************************************' 函数定义'******************************************************************** ********************************************Private Sub chansheng()Dim i As Double, j As Double, int_length As Long, stack_top As String,temp_stack_p As DoubleDim str_temp As String, int_length2 As Long, success As Boolean, str_temp_stack(1 To 20) As StringDim msg As Doublesuccess = TrueFor i = 1 To 20str_stack(i) = ""Nextstr_input = "": str_output = "": current = ""i = 1: j = 1: stack_p = 1temp_stack_p = 0 '用于存放优先级较高的运算符的临时堆栈的指针str_input = InputBox("请输入待转换的非后缀式:", "输入非后缀式", "(a+b*c)*d", 3000, 5000) & "#"str_feihouzhui = str_inputint_length = Len(str_input)int_length2 = int_lengthgrid.Rows = 100 '初始化表格控件grid.Cols = 4grid.TextMatrix(0, 0) = "当前符号"grid.TextMatrix(0, 1) = "输入区"grid.TextMatrix(0, 2) = "符号栈"grid.TextMatrix(0, 3) = "输出区"grid.ColWidth(0) = 2100 '设置列宽grid.ColWidth(1) = 2100grid.ColWidth(2) = 2075grid.ColWidth(3) = 3100Do While (success)current = Mid(str_input, 1, 1)l0: stack_top = str_stack(stack_p)str_temp = ""Select Case currentCase "0" To "9", "a" To "z"str_output = str_output & currentint_length2 = int_length2 - 1Case "*", "/"Select Case stack_topCase ""str_stack(stack_p) = currentint_length2 = int_length2 - 1Case "*", "/", "+", "-", "("stack_p = stack_p + 1str_stack(stack_p) = currentint_length2 = int_length2 - 1End SelectCase "+", "-"Select Case stack_topCase ""str_stack(stack_p) = currentFor j = temp_stack_p To 1 Step -1If str_temp_stack(temp_stack_p) <> "" Thenstack_p = stack_p + 1str_stack(stack_p) = str_temp_stack(j)temp_stack_p = temp_stack_p - 1End IfNextint_length2 = int_length2 - 1Case "*", "/"str_output = str_output & str_stack(stack_p) '若优先级低于栈顶运算符,则弹出栈顶运算符并输出If stack_p > 1 Thenstack_p = stack_p - 1Elsestr_stack(stack_p) = ""End IfGoTo l0Case "+", "-", "("stack_p = stack_p + 1str_stack(stack_p) = currentint_length2 = int_length2 - 1For j = temp_stack_p To 1 Step -1If str_temp_stack(temp_stack_p) <> "" Thenstack_p = stack_p + 1str_stack(stack_p) = str_temp_stack(j)temp_stack_p = temp_stack_p - 1End IfNextEnd SelectCase "("Select Case stack_topCase ""str_stack(stack_p) = currentint_length2 = int_length2 - 1Case "*", "/", "+", "-", "("stack_p = stack_p + 1str_stack(stack_p) = currentint_length2 = int_length2 - 1End SelectCase ")"Select Case stack_topCase ""msg = MsgBox("错误,没有匹配的“(”。

编译原理实验二:LL(1)语法分析器

编译原理实验二:LL(1)语法分析器

编译原理实验⼆:LL(1)语法分析器⼀、实验要求 1. 提取左公因⼦或消除左递归(实现了消除左递归) 2. 递归求First集和Follow集 其它的只要按照课本上的步骤顺序写下来就好(但是代码量超多...),下⾯我贴出实验的⼀些关键代码和算法思想。

⼆、基于预测分析表法的语法分析 2.1 代码结构 2.1.1 Grammar类 功能:主要⽤来处理输⼊的⽂法,包括将⽂法中的终结符和⾮终结符分别存储,检测直接左递归和左公因⼦,消除直接左递归,获得所有⾮终结符的First集,Follow集以及产⽣式的Select集。

#ifndef GRAMMAR_H#define GRAMMAR_H#include <string>#include <cstring>#include <iostream>#include <vector>#include <set>#include <iomanip>#include <algorithm>using namespace std;const int maxn = 110;//产⽣式结构体struct EXP{char left; //左部string right; //右部};class Grammar{public:Grammar(); //构造函数bool isNotTer(char x); //判断是否是终结符int getTer(char x); //获取终结符下标int getNonTer(char x); //获取⾮终结符下标void getFirst(char x); //获取某个⾮终结符的First集void getFollow(char x); //获取某个⾮终结符的Follow集void getSelect(char x); //获取产⽣式的Select集void input(); //输⼊⽂法void scanExp(); //扫描输⼊的产⽣式,检测是否有左递归和左公因⼦void remove(); //消除左递归void solve(); //处理⽂法,获得所有First集,Follow集以及Select集void display(); //打印First集,Follow集,Select集void debug(); //⽤于debug的函数~Grammar(); //析构函数protected:int cnt; //产⽣式数⽬EXP exp[maxn]; //产⽣式集合set<char> First[maxn]; //First集set<char> Follow[maxn]; //Follow集set<char> Select[maxn]; //select集vector<char> ter_copy; //去掉$的终结符vector<char> ter; //终结符vector<char> not_ter; //⾮终结符};#endif 2.1.2 AnalyzTable类 功能:得到预测分析表,判断输⼊的⽂法是否是LL(1)⽂法,⽤预测分析表法判断输⼊的符号串是否符合刚才输⼊的⽂法,并打印出分析过程。

编译原理——语法分析程序设计实验报告

编译原理——语法分析程序设计实验报告

实验二语法分析程序设计[实验目的]:1.了解语法分析的主要任务。

2.熟悉编译程序的编制。

[实验内容]:根据某文法,构造一基本递归下降语法分析程序。

给出分析过程中所用的产生式序列。

[实验要求]:1.选择一个文法,进行实验,可选的文法包括以下三个:P190 4.8P190 4.9P190 4.102.设计语法分析程序的输出形式(输出应为语法树或推导),一个可以参考的例子,可见图1。

3.编写递归下降语法分析程序(参考P148-149 Topdown parsing byrecursive-descent),实现基本的递归下降分析器,能够分析任给的符号串是否为该文法所定义的合法句子。

实验报告中要说明分析使用的方法。

4.根据所作业题选项e所给出的input,生成并输出分析过程中所用的产生式序列(show the actions of parser):1 产生式12 产生式2……5.自已设计一个不合法的句子,作为输出进行分析,给出结果。

[实验过程]本次实验选择的文法为P190 4.8lexp->atom|listatom->number|identifierlist->(lexp-seq)lexp-seq->lexp lexp-seq1.写出实现的算法,并画流程图。

本次实验采用递归下降算法,算法流程图如下图1-1:图1-1 算法流程图2.根据你选择的文法,分析左递归或左因子是否会影响本算法的结果。

会影响本算法的结果。

递归下降分析法要求的文法是LL(1)文法,需要消除左递归和左因子的影响。

如果存在左因子,对相同的字符跳转到不同的函数,无法实现递归。

3.列举实验设计过程中出现的问题及解决的方法(至少3条,选择实验中最困扰的问题)。

1).会多次输出accept/error结果解决方案:所有的递归函数返回类型为int,若accept返回1,error返回0,在main主函数中统一判断输出语句。

编译原理实验二:消除文法的左递归说课讲解

编译原理实验二:消除文法的左递归说课讲解

编译原理实验报告实验名称消除文法的左递归实验时间2013年11月12日院系计算机科学与电子技术系班级11计算机软件学号JV114001 JV114095 JP114065 姓名唐茹韩强强徐思维1.试验目的:输入:任意的上下文无关文法。

输出:消除了左递归的等价文法。

2.实验原理:1.直接左递归的消除消除产生式中的直接左递归是比较容易的。

例如假设非终结符P 的规则为:P →P α / β其中,β是不以P 开头的符号串。

那么,我们可以把P 的规则改写为如下的非直接左递归形式: P →βP ’P ’→αP ’ / ε这两条规则和原来的规则是等价的,即两种形式从P 推出的符号串是相同的。

设有简单表达式文法G[E]: E →E+T/ T T →T*F/ F F →(E )/ I经消除直接左递归后得到如下文法: E →TE ’E ’ →+TE ’/ ε T →FT ’T ’ →*FT ’/ εF →(E )/ I考虑更一般的情况,假定关于非终结符P 的规则为P →P α1 / P α2 /…/ P αn / β1 / β2 /…/βm其中,αi (I =1,2,…,n )都不为ε,而每个βj (j =1,2,…,m )都不以P 开头,将上述规则改写为如下形式即可消除P 的直接左递归:P →β1 P ’ / β2 P ’ /…/βm P ’P ’ →α1P ’ / α2 P ’ /…/ αn P ’ /ε 2.间接左递归的消除直接左递归见诸于表面,利用以上的方法可以很容易将其消除,即把直接左递归改写成直接右递归。

然而文法表面上不存在左递归并不意味着该文法就不存在左递归了。

有些文法虽然表面上不存在左递归,但却隐藏着左递归。

例如,设有文法G[S]:S →Qc/ c Q →Rb/ b R →Sa/ a虽不具有左递归,但S 、Q 、R 都是左递归的,因为经过若干次推导有 S ⇒Qc ⇒Rbc ⇒SabcQ ⇒Rb ⇒Sab ⇒Qcab R ⇒Sa ⇒Qca ⇒Rbca就显现出其左递归性了,这就是间接左递归文法。

编译原理实验二

编译原理实验二

实验二语法分析一、实验目的:设计MiniC的上下文无关文法,利用JavaCC生成调试递归下降分析程序,以便对任意输入的符号串进行分析。

本次实验的目的主要是加深对递归下降分析法的理解。

二、语法分析器:按照MiniC语言的语法规则检查词法分析输出的记号流是否符合这些规则,并根据这些规则所体现出的语言中的各种语法结构的层次性。

把规则写入到JavaCC的.jjt文件中,可以生成树状的层次结构。

三、JavaCC:在JavaCC的文法规范文件中,不仅可以描述语言的语法规范,而且可以描述词法规范,本次实习中,利用JavaCC以MiniC语言构造一个不含语义分析的编译器前端,包括词法分析、语法分析,并要考虑语法分析中的错误恢复问题。

通过使用JavaCC, 可以体会LL(k)文法的编写特点,掌握编写JavaCC文法规范文件的方法。

内容:利用JavaCC生成一个MiniC的语法分析器;要求:1.用流的形式读入要分析的C语言程序,或者通过命令行输入源程序。

2.具有错误检查的能力,如果有能力可以输出错误所在的行号,并简单提示3.如果输入的源程序符合MiniC的语法规范,输出该程序的层次结构的语法树本次实习仅完成以下语法范畴的语法分析:1. 写出一个源程序中仅包含if…else, else语句的语法分析。

要求能分析其自身嵌套. 其他语句可简化处理2. 写出一个源程序中仅包含for语句的语法分析。

要求能分析其自身嵌套,其他语句可简化处理3. 写出一个源程序中仅包含while语句的语法分析。

要求能分析其自身嵌套。

其他语句可简化处理4. 写出一个源程序中包含上面的12或者13或者23或者123语句的语法分析。

要求能分析除其自身嵌套外,还包括相互嵌套。

其他语句可简化处理具体实施步骤如下:1.把MiniC转换为文法如下<程序〉→ main()〈语句块〉〈语句块〉→{〈语句串〉}〈语句串〉→〈语句〉;〈语句串〉|〈语句〉;〈语句〉→〈赋值语句〉|〈条件语句〉|〈循环语句〉〈赋值语句〉→ ID =〈表达式〉;〈条件语句〉→ if〈条件〉〈语句块〉〈循环语句〉→ while〈条件〉〈语句块〉〈条件〉→(〈表达式〉〈关系符〉〈表达式〉)〈表达式〉→〈表达式〉〈运算符〉〈表达式〉|(〈表达式〉)|ID|NUM〈运算符〉→+|-|*|/〈关系符〉→<|<=|>|>=|=|!>2.在eclipse环境下完成JavaCC的插件安装后,写一个JavaCC文法规范文件(扩展名为jj)3.完成的功能包括词法分析,语法分析(输出语法树),能够读文件,也能够把输出的结果保存文件中,可以把树的层次结果输出到文件中。

编译原理实验报告

编译原理实验报告
实验四: 设计一个表示01符号串集合的自动机,其中符号串至少包含1个0且长度必须大于等于2。并通过该自动机判断任意输入的符号串是否合法符号串。
实验五: 设计一个算法,求出任一上下文无关文法中所有导空符号,并输出。
实验六: 检查某段C源程序中,标识符的使用是否正确,即是否先声明后使用,或重复声明。假设数据类型只有int,float,double,char。
break;
}
if(temp[n*13+n2]=='k'&&zt[m]==0) //那些不能推出 空,但是因为要加入 其他非终结符的first集 而可能含有 空
n2++;
else if(n3>=n1) //for循环结束是因为n3而不是break ,即无相同字符
while(temp[n*13+n2]!='\0') //把z[n]对应的first加入temp[m*13+n1]这个first中,每个字符依次加在最后
{
for(n3=0;n3<n1;n3++) //循环判定是否有相同的字符
{
if(temp[m*13+n3]==temp[n*13+n2])
}
n++;
}
break; //break位于if(gs[n]==z2[m]),对于gs[n]已找到z2[m]完成任务跳出for循环
}
}
n2=m; //存放该for循环中m的值
n++;
}
//进一步处理集除去非终结符
m=0;n=0;n1=0;n2=0;
else n2++;
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

第二章语法分析器构造我们采用一种最为常用的语法分析器─LR分析器。

LR分析器的构造主要是指上下文无关文法的自下而上分析程序的自动构造。

从实践角度出发,我们采用手工方法来设计LR 分析器。

LR系指“自左向右扫描和自下而上进行归约”。

大多数用上下文无关文法描述的程序语言都可用LR分析器予以识别。

LR分析法在自左至右扫描输入串时就能发现其中的任何错误,并能准确地指出出错地点。

一个LR分析器包括两部分,一个总控(驱动)程序和一张分析表。

注意,所有LR分析器的总控程序都是一样的,只是分析表各有不同。

因此,产生器的主要任务就是产生分析表。

2.1 LR分析器基本知识我们知道,规范归约(最左归约,即最右推导的逆过程)的关键问题是寻找句柄。

LR 方法的基本思想是:在规范归约过程中,一方面记住已移进和归约出的整个符号串,即记住“历史”;另一方面根据所用的产生式推测未来的可能碰到的输入符号,即对未来进行“展望”。

当一串貌似句柄的符号串呈现于分析栈的顶端时,我们希望能够根据所记载的“历史”和“展望”以及“现实”的输入符号等三方面的材料,来确定栈顶的符号是否构成相对某一产生式的句柄。

一个LR分析器实质上是一个带先进后出存贮器(栈)的确定有限状态自动机。

我们将把“历史”和“展望”材料综合地抽象成某些“状态”。

分析栈(先进后出存贮器)用来存放状态。

栈里的每个状态概括了从分析开始直到某一归约阶段的全部“历史”和“展望”资料。

任何时候,栈顶的状态都代表了整个的历史和已推测出的展望。

LR分析器的每一步工作都是由栈顶状态和现行输入符号所唯一决定的。

为了有助于明确归约手续,我们把已归约出的文法符号串也同时放在栈里。

于是,栈的结构可看成图2-1所示的结构。

TOP图2-1 分析栈示意栈的每一项内容包括状态s和文法符号X两部分。

(s O,#)为分析开始前预先放入栈里的初始状态和句子括号。

栈顶状态为s m,符号串X1X2…X m是至今已移进归约出的文法符号串。

LR分析器的核心部分是一张分析表。

这张分析表包括两部分:一是“动作”(ACTION)表,另一是“状态转换”(GOTO)表。

它们都是二维数组。

ACTION[s,a]规定了当状态s面临输入符号a时应采取什么动作。

GOTO[s,X]规定了状态s面对文法符号X(终结符或非终结符)时下一状态是什么。

显然,GOTO[s,X]定义了一个以文法符号为字母表的DFA(确定有限自动机)。

每一项ACTION[s,a]所规定的动作不外是下述四种可能之一:(1)移进:把(s,a)的下一状态s′=ACTION[s,a]和输入符号a推进栈(对终结符a,GOTO[s,a]的值已放入ACTION[s,a]中),下一输入符号变成现行输入符号。

(2)归约:指用某一产生式A→β进行归约。

假若β的长度为γ,归约的动作是去掉栈顶的γ个项,使状态s m-γ变成栈顶状态,然后把(s m-γ,A)的下一状态s′=GOTO[s m-γ,A] 和文法符号A推进栈。

归约动作不改变现行输入符号。

执行归约的动作意味着呈现于栈顶的符号串X m-γ+1…X m是一个相对于A的句柄。

(3)接受:宣布分析成功,停止分析器的工作。

(4)报错:报告发现源程序含有错误,调用出错处理程序。

LR分析器的总控程序本身的工作是非常简单的,它的任何一步只需按栈顶状态s和现行输入符号a执行ACTION[s,a]所规定的动作。

不管什么分析表,总控程序都是一样地工作。

我们主要关心的问题是如何从文法构造LR分析表。

对于一个文法,如果能够构造一张分析表,使得它的每个入口均是唯一确定的,则我们将把这个文法称为LR文法。

对于一个LR文法,当分析器对输入串进行自左至右扫描时,一旦句柄呈现于栈顶,就能及时对它实行归约。

一个LR分析器有时需要“展望”和实际检查未来的K个输入符号才能决定应采取什么样的“移进-归约”决策。

一般而言,一个文法如果能用一个每步顶多向前检查K个输入符号的LR分析器进行分析,则这个文法就称为LR(k)文法。

对于一个文法,如果它的任何“移进-归约”分析器都存在如下的情形:尽管栈的内容和下一个输入符号都已了解,但无法确定是“移进”还是“归约”;或者,无法从几种可能的归约中确定其一;那么这个文法就是非LR(1)的。

注意,LR文法肯定是无二义的,一个二义文法决不会是LR的。

但是,LR分析技术可修改为适用于分析一定的二义文法。

2.2 LR(0)分析表的构造我们希望仅由一种只概括“历史”资料而不包含推测性“展望”材料的简单状态就能识别呈现在栈顶的某些句柄,而LR(0)项目集就是这样一种简单状态。

在讨论LR分析法时,需要定义一个重要概念,这就是文法的规范句型的“活前缀”。

字的前缀是指该字的任意首部,例如字abc的前缀有ε、a、ab或abc。

所谓活前缀是指规范句型的一个前缀,这种前缀不含句柄之后的任何符号。

在LR分析工作过程中的任何时候,栈里的文法符号(自栈底而上)X1X2…X m应该构成活前缀,把输入串的剩余部分配上之后即应成为规范句型(如果整个输入串确实构成一个句子)。

因此,只要输入串的已扫描部分保持可归约成一个活前缀,那么就意味着所扫描过的部分没有错误。

对于一个文法G,我们首先要构造一个NFA(非确定有限自动机),它能识别G的所有活前缀。

这个NFA的每个状态就是一个“项目”。

而文法G每一个产生式的右部添加一个圆点称为G的一个LR(0)项目(简称项目)。

例如产生式A→XYZ对应有四个项目: A→·X Y ZA→ X·Y ZA→ X Y·ZA→ X Y Z·但是产生式A→ε只对应一个项目A→·。

一个项目指明了在分析过程的某时刻我们看到产生式多大一部分。

我们可以使用这些项目状态构造一个NFA,用来识别一个文法的所有活前缀。

使用子集方法把识别活前缀的NFA确定化,使之成为一个以项目集合为状态的DFA (确定有限自动机),这个DFA就是建立LR分析算法的基础。

构成识别一个文法活前缀的DFA的项目集(状态)的全体称为这个文法的LR(0)项目集规范族。

这个规范族提供了建立一类LR(0)和SLR(简单LR)分析器的基础。

注意,凡园点在最右端的项目,如A →α·,称为一个“归约项目”;对文法的开始符号S′的归约项目,如S′→α·称为“接受”项目。

形如A→α·aβ的项目,其中a为终结符,称为“移进”项目;形如A→α·Bβ的项目,其中B为非终结符,称为“待约”项目。

2.2.1 LR(0)项目集规范族的构造我们采用ε_CLOSURE(闭包)的方法来构造一个文法G的LR(0)项目集规范族。

首先,为了使“接受”状态易于识别,总是将文法G进行拓广。

假定文法G是一个以S为开始符号的文法,我们构造一个G′,它包含了整个G并引进了一个不出现在G中的非终结符S′,同时加进了一个新产生式S′→S,而这个S′是G′的开始符号,我们称G ′是G的拓广文法。

由于会有一个仅含项目S′→S·的状态,这就是唯一的“接受”态。

假定I是文法G′的任一项目集,定义和构造I的闭包CLOSURE(I)的方法是:(1)I的任何项目都属于CLOSURE(I);(2)若A→α·Bβ属于CLOSURE(I),那么对任何关于B的产生式B→γ,项目B→·γ也属于CLOSURE(I)(设A→α·Bβ的状态为i,则i到所有含B→·γ的状态都有一条ε弧);(3)重复执行上述两步骤直至CLOSURE(I)不再增大为止。

在构造CLOSURE(I)时,请注意一个重要的事实,那就是对任何非终结符B,若某个圆点在左边的项目B→·γ进入到CLOSURE(I),则B的所有其它圆点在左边的项目B→·β也将进入同一个CLOSURE集。

函数GO是一个状态转换函数。

GO(I,X)的第一个变元I是一个项目集,第二个变元X 是一个文法符号。

函数值GO(I,X)定义为:GO(I,X)=CLOSURE(J)其中,如果A→α·Xβ属于I,则J={任何形如A→αX·β的项目}。

也即,如果由I项目集发出的字符为X的有向弧,则到达的状态即为CLOSURE(J)。

直观上说,若I是对某个活前缀γ有效的项目集(状态),那么GO(I,X)便是对γX有效的项目集(状态)。

通过函数CLOSURE和GO很容易构造一个文法G的拓广文法G′的LR(0)项目集规范族。

也就是说,如果我们已经求出了I的闭包CLOSURE(I),则用状态转换函数GO可以求出由项目集I到另一项目集状态必须满足的字符(即转换图有向弧上的字符)。

然后,再求出有向弧到达的状态所含的项目集(即用GO(I,X)=CLOSURE(J)求出J,然后再对J求其闭包CLOSURE(J),也就是有向边弧到达状态所含的项目集)。

以此类推,最终构造出拓广文法G′的LR(0)项目集规范族。

2.2.2 LR(0)分析表的构造假若一个文法G的拓广文法G′的活前缀识别自动机中的每个状态(项目集)不存在下述情况:即含移进项目又含归约项目或者含有多个归约项目,则称G是一个LR(0)文法。

换言之,LR(0)文法规范族的每个项目集不包含任何冲突项目。

对于LR(0)文法,我们可直接从它的项目集规范族C和活前缀自动机的状态转换函数GO构造出LR分析表。

下面是构造LR(0)分析表的算法。

假定C={I0,I1,…,I n}。

由于我们已经习惯用数字表示状态,因此令每个项目集I k 的下标K作为分析器的状态。

特别是令那个包含项目S′→·S(表示整个句子还未输入)的集合I k的下标K为分析器的初态。

分析表的ACTION子表和GOTO子表可按如下方法构造:(1)若项目A→α·aβ属于I k且GO(I k,a)=I j,a为终结符,则置ACTION[k,a]为“将(j,a)移进栈”,简记为“s j”。

(2)若项目A→α·属于I k,则对任何终结符a(或结束符#),置ACTION[k,a]为“用产生式A→α进行归约”,简记为“r j”(注意:j是产生式的编号而不是项目集的状态号,即A→α是文法G′的第j个产生式)。

(3)若项目S′→S·属于I k(S·表示整个句子已输入并归约结束),则置ACTION[k,#]为“接受”,简记为“acc”。

(4)若GO(I k,A)=I j,A为非终结符,则置GOTO[K,A]=j。

(5)分析表中凡不能用规则(1)~(4)填入的空白格均置上“报错标志”。

由于假定LR(O)文法规范族的每个项目集不含冲突项目,因此,按上述方法构造的分析表的每个入口都是唯一的(即不含多重定义)。

我们称如此构造的分析表是一张LR(0)表,使用LR(0)表的分析器叫做一个LR(0)分析器。

相关文档
最新文档