编译原理实验二
《编译原理(实验部分)》实验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");};}。
编译原理课程实验报告
五、实验体会
指导教师评语:
日期:
编译原理课程实验报告实验2语法分析院系姓名任课教师实验地点实验课表现学号出勤表现得分操作结果得分指导教师实验时间实验报告得分实验总分一实验目的要求需分析本次实验的基本目的并综述你是如何实现这些目的的二实验内容要求对如下工作进行展开描述1给出如下语言成分的文法描述函数定义或过程定义变量说明赋值表达式循环分支2语法分析程序的总体结构及物理实现3语法分析表及其数据结构和查找算法4语法分析表的生成算法5错误处理错误的位置及类型等三实验结果要求将实验获得的结果进行描述基本内容包括1针对一测试程序输出其语法分析结果2输出针对此测试程序对应的语法错误报告注其中的测试样例需先用已编写的词法分析程序进行处理
变量说明
赋值
表达式
循环
分支
(2)语法分析程序的总体结构及物理实现
(3)语法分析表及其数据结构和查找算法
(4)语法分析表的生成算法
(5)错误处理
错误的位置及类型等
三、实验结果
要求:将实验获得的结果进行描述,基本内容包括:
(1)针对一测试程序输出其语法分析结果;
(2)输出针对此测试程序对应的语法错误报告;
编译原理课程实验报告
实验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("该句子是该文法的合法句子。
编译原理实验二:压缩文法的等价变换
实验二:压缩文法的等价变换一:要求输入:任意的上下文无关文法输出:等价的压缩了的文法要求:除了可查看压缩了的文法,还可查看删除了哪些规则二:实验目的了解文法的简化三:实验原理删除文法中的有害规则和多余规则有害规则:若文法中有如U::=U的规则,则这就是有害规则,它会引起二义性,而无任何用处。
多余规则:(1)某条规则U::=u的左部非终结符U(U不是识别符号),不在任何其他规则右部出现,即所有的推导始终不会用到此规则。
【不可到达】(2)在推导句子的过程中,一旦使用了该规则,将推不出任何终结符号串。
即该规则中含有推不出任何终结符号串的非终结符。
【不可终止】四:数据结构与算法struct Chomsky{string left;string right;};void apart(Chomsky *p,int i) //分开产生式左右部void VNVT(Chomsky *p)//求VN和VTint zero(Chomsky *p)//0型文法int one(Chomsky *p)//1型文法int two(Chomsky *p)//2型文法void shanchu(Chomsky *p)//删除多余规则与有害规则五:出错分析1:变量重复定义导致了一些小错误2:程序太长{}缺少也导致了错误3:后面删除规则的程序出错了,没有调试成功。
六:实验结果与分析不是上下文无关文法的:2型文法的压缩:七:源代码#include<iostream>#include<string>using namespace std;#define max 50int NONE=1;int RELEFT=1;string strings,noend,end;//非终结符与终结符存储int n;//产生式总数int flag;struct Chomsky{string left;string right;};void apart(Chomsky *p,int i) //分开产生式左右部{int j;for(j=0;j<strings.length();j++)if(strings[j]=='-'){p[i].left=strings.substr(0,j);p[i].right=strings.substr(j+1,strings.length()-j);}}void VNVT(Chomsky *p)//求VN和VT{int i,j;for(i=0;i<n;i++){for(j=0;j<(int)p[i].left.length();j++){if((p[i].left[j]>='A'&&p[i].left[j]<='Z'))//非终结符判断{if(noend.find(p[i].left[j])>100)noend+=p[i].left[j];}else{if(end.find(p[i].left[j])>100)end+=p[i].left[j];}}{if(!(p[i].right[j]>='A'&&p[i].right[j]<='Z'))//终结符判断{if(end.find(p[i].right[j])>100)end+=p[i].right[j];}else{if(noend.find(p[i].right[j])>100)noend+=p[i].right[j];}}}}int zero(Chomsky *p)//0型文法{int flag(0),count(0);int i,j;for(i=0;i<n;i++){{if(p[i].left[j]>='A'&&p[i].left[j]<='Z') //有否非终结符flag++;}if(flag>0){flag=0;count++;}elsebreak; //左部没有非终结符,结束}if(count==n)return 1; //属于0型文法else{cout<<endl<<"所输产生式不属于任何文法。
编译原理实验报告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
学生学号实验课成绩武汉理工大学学生实验报告书实验课程名称编译原理开课学院计算机科学与技术学院指导老师姓名饶文碧学生姓名学生专业班级—学年第学期实验课程名称:编译原理实验项目名称单词的词法分析实验成绩实验者专业班级组别同组者实验日期第一部分:实验分析与设计(可加页)一、实验内容描述(问题域描述)完成对某一种常用高级语言(如Pascal、C语言、PL/0语言)的各类单词进行词法分析,即对源程序从左到右进行扫描,对组成源程序的字符串拼接成为单词;并把其转换成属性字输出。
实验要求:(1)选择常用高级程序设计语言(如 Pascal、C语言、PL/0语言)的源程序作为词法分析对象。
(2)根据教学要求和学生具体情况,从上列语言之一中选取它的一个适当大小的子集,可以选取一类典型单词,也可以尽可能使各种类型的单词都能兼顾到。
其基本要求是:对源程序从左到右进行扫描,对组成源程序的字符串拼接成为单词,并把其转换成属性字输出。
二、实验基本原理与设计(包括实验方案设计,实验手段的确定,试验步骤等,用硬件逻辑或者算法描述)#include<string.h>#include<stdio.h>#include<stdlib.h>#include<ctype.h>char *table[7]={" ","main","int","if","then","else","return"},TOKEN[20],ch;//定义关键字int lookup(char *TOKEN){ //关键字匹配函数int m,i;for(i=1;i<6;i++){if((m=strcmp(TOKEN,table[i]))==0)return(i);}return(0);}void out(int c,char *TOKEN){ //输出函数printf("(%d,%s)\n",c,TOKEN);}void scanner(FILE *fp){ //扫描函数char TOKEN[20]={'\0'};char ch;int i,c;ch=fgetc(fp); //获取字符指针fp并自动指向下一个字符 if(isalpha(ch)){ //判断该字符是否是字母TOKEN[0]=ch;ch=fgetc(fp);i=1;while(isalnum(ch)){ //判断该字符是否是字母或数字TOKEN[i]=ch;i++;ch=fgetc(fp);}TOKEN[i]='\0';fseek(fp,-1,1); //回退一个字符c=lookup(TOKEN);if(c==0)out(6,TOKEN); //输出标识符else out(c,TOKEN); //输出关键字}elseif(isdigit(ch)){ //判断是否是数字TOKEN[0]=ch;ch=fgetc(fp);i=1;while(isdigit(ch)){TOKEN[i]=ch;i++;ch=fgetc(fp);}TOKEN[i]='\0';fseek(fp,-1,1);out(7,TOKEN);}else{TOKEN[0]=ch;switch(ch){case'{':out(17,TOKEN);break;case'}':out(18,TOKEN);break;case',':out(14,TOKEN);break;case';':out(15,TOKEN);break;case'<':ch=fgetc(fp);TOKEN[1]=ch;if(ch=='='){out(9,TOKEN);}else if(ch=='>'){out(11,TOKEN);}else {fseek(fp,-1,1);out(8,TOKEN);}break;case'=':out(10,TOKEN);break;case'>':ch=fgetc(fp);TOKEN[1]=ch;if(ch=='=') out(13,TOKEN); else {fseek(fp,-1,1);out(12,TOKEN);}break;default:printf("error!\n");break;}}}void main(){ FILE *fp;if((fp=fopen("D:\\ZHT.txt","r"))==NULL){//读取文件内容,并返回文件指针,该指针指向文件的第一个字符 fprintf(stderr,"error opening.\n");exit(1);}do{ch=fgetc(fp);if(ch=='#') //文件以#结尾作为扫描结束条件break;if(ch==' ') //如果是空格,自动跳到下个字符scanner(fp);else{fseek(fp,-1,1); //如果不是空格,则回退一个字符并扫描 scanner(fp);}}while(ch!='#');return(0);}三、主要仪器设备及耗材VC6.0第二部分:实验调试与结果分析(可加页)一、调试过程(包括调试方法描述、实验数据记录,实验现象记录,实验过程发现的问题等)在扫描源程序字符串时一旦识别出关键字、分隔符、标识符、无符号常数中之一即以单词形式各类单词均采用相同的结构,即二元式编码形式输出。
编译原理实验二:消除文法的左递归.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就显现出其左递归性了,这就是间接左递归文法。
编译原理实验二word版本
编译原理二-------词法分析器一.问题描述词法分析程序的功能:输入源程序,输出单词符号,如图所示:单词符号处理过程:在扫描源程序字符串时,一旦识别出关键字、分隔符、标识符、无符号常数中之一,即以单词形式(各类单词均采用相同的结构,即二元式编码形式)输出。
每次调用词法分析程序,它均能自动继续扫描下去,形成下一个单词,直至整个源程序全部扫描完毕,并形成相应的单词串形式的源程序。
二.需求分析1.对给定的程序通过词法分析器能够识别一个个单词符号,并以二元式(单词类型,单词符号)显示;2.可以将要分析的程序保存到文件中进行读取;3.删除无用的空白字符、回车符、及其它非实质性符号。
三.程序设计本程序规定:(1)关键字"begin","end","if","then","else","while","write","read", "do", "call","const","char","until","procedure","repeat"(2)运算符:"+","-","*","/","="(3)界符:"{","}","[","]",";",",",".","(",")",":"(4)其他标记如字符串,表示以字母开头的标识符。
编译原理实验二
编译原理二-------词法分析器一.问题描述词法分析程序的功能:输入源程序,输出单词符号,如图所示:单词符号处理过程:在扫描源程序字符串时,一旦识别出关键字、分隔符、标识符、无符号常数中之一,即以单词形式(各类单词均采用相同的结构,即二元式编码形式)输出。
每次调用词法分析程序,它均能自动继续扫描下去,形成下一个单词,直至整个源程序全部扫描完毕,并形成相应的单词串形式的源程序。
二.需求分析1.对给定的程序通过词法分析器能够识别一个个单词符号,并以二元式(单词类型,单词符号)显示;2.可以将要分析的程序保存到文件中进行读取;3.删除无用的空白字符、回车符、及其它非实质性符号。
三.程序设计本程序规定:(1)关键字"begin","end","if","then","else","while","write","read","do", "call","const","char","until","procedure","repeat"(2)运算符:"+","-","*","/","="(3)界符:"{","}","[","]",";",",",".","(",")",":"(4)其他标记如字符串,表示以字母开头的标识符。
编译原理实验二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)该函数的功能是生成一个三地址语句送到四元式表中。
编译原理-语法分析实验二
华北水利水电学院编译原理实验报告2010~2011学年第二学期 xxxx 级计算机专业班级: xxxxx 学号: xxxxx 姓名: xxx一、实验目的通过设计、编制、调试一个典型的语法分析程序,实现对词法分析程序所提供的单词序列进行语法检查和结构分析,进一步掌握常用的语法分析方法。
二、实验要求⑴选择最有代表性的语法分析方法,如LL(1)分析法、算符优先法或LR分析法⑵选择对各种常见程序语言都用的语法结构,如赋值语句(尤指表达式)作为分析对象,并且与所选语法分析方法要比较贴切。
⑶实习时间为6小时。
三、实验内容选题1:使用预测分析法(LL(1)分析法)实现语法分析:(1)根据给定文法,先求出first集合、follow集合和select集合,构造预测分析表(要求预测分析表输出到屏幕或者输出到文件);(2)根据算法和预测分析表分析给定表达式是否是该文法识别的正确的算术表达式(要求输出归约过程)(3)给定表达式文法为:G(E): S→TEE→+TE | εT→FKK→*FK |εF→(S)|i(4)分析的句子为:(i+i)*i和i+i)*i四、程序源代码#include "stdafx.h"#include "SyntaxAnalysis.h"#include "SyntaxAnalysisDlg.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_ char THIS_FILE[] = __FILE__; #endif/////////////////////////////////////////// // CAboutDlg dialog used for App Aboutclass CAboutDlg : public CDialog{public:CAboutDlg();// Dialog Data//{{AFX_DATA(CAboutDlg)enum { IDD = IDD_ABOUTBOX };//}}AFX_DATA// ClassWizard generated virtual function overrides//{{AFX_VIRTUAL(CAboutDlg)protected:virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support//}}AFX_VIRTUAL// Implementationprotected://{{AFX_MSG(CAboutDlg)//}}AFX_MSGDECLARE_MESSAGE_MAP()};CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD){//{{AFX_DATA_INIT(CAboutDlg)//}}AFX_DATA_INIT}voidCAboutDlg::DoDataExchange(CDataExchange* pDX){CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CAboutDlg)//}}AFX_DATA_MAP}BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)//{{AFX_MSG_MAP(CAboutDlg)// No message handlers//}}AFX_MSG_MAPEND_MESSAGE_MAP()// CSyntaxAnalysisDlg dialogCSyntaxAnalysisDlg::CSyntaxAnalysisDlg(CWnd * pParent /*=NULL*/): CDialog(CSyntaxAnalysisDlg::IDD, pParent){//{{AFX_DATA_INIT(CSyntaxAnalysisDl g)m_strCode = _T("");m_strResult = _T("");//}}AFX_DATA_INIT// Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);}voidCSyntaxAnalysisDlg::DoDataExchange(CDataExc hange* pDX){CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CSyntaxAnalysisDlg)DDX_Control(pDX, IDC_LIST1, m_ListCtrl);DDX_Text(pDX, IDC_EDIT_Code, m_strCode);DDX_Text(pDX, IDC_EDIT_Result, m_strResult);//}}AFX_DATA_MAP}BEGIN_MESSAGE_MAP(CSyntaxAnalysisDlg, CDialog)//{{AFX_MSG_MAP(CSyntaxAnalysisDlg)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(IDC_BTN_Analysis, OnBTNAnalysis)//}}AFX_MSG_MAPEND_MESSAGE_MAP()// CSyntaxAnalysisDlg message handlersBOOL CSyntaxAnalysisDlg::OnInitDialog(){CDialog::OnInitDialog();ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);ASSERT(IDM_ABOUTBOX < 0xF000);CMenu* pSysMenu = GetSystemMenu(FALSE);if (pSysMenu != NULL){CString strAboutMenu;strAboutMenu.LoadString(IDS_ABOUTBO X);if (!strAboutMenu.IsEmpty()){pSysMenu->AppendMenu(MF_SEPARATOR);pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);}}SetIcon(m_hIcon, TRUE);// Set big iconSetIcon(m_hIcon, FALSE);// Set small icon// TODO: Add extra initialization here//初始化给定文法m_VN[0]="S";m_VN[1]="E";m_VN[2]="T";m_VN[3]="K";m_VN[4]="F";m_VT[0]="i";m_VT[1]="+";m_VT[2]="*";m_VT[3]="(";m_VT[4]=")";m_Gl[0]=0;m_Gr[0]="TE";m_Gl[1]=1;m_Gr[1]="+TE";m_Gl[2]=1;m_Gr[2]="ε";m_Gl[3]=2;m_Gr[3]="FK";m_Gl[4]=3;m_Gr[4]="*FK";m_Gl[5]=3;m_Gr[5]="ε";m_Gl[6]=4;m_Gr[6]="(S)";m_Gl[7]=4;m_Gr[7]="i";Cal_Symbol();Cal_First();Cal_Follow();DrawMList();return TRUE; // return TRUE unless you set the focus to a control}void CSyntaxAnalysisDlg::OnSysCommand(UINT nID, LPARAM lParam){if ((nID & 0xFFF0) == IDM_ABOUTBOX){CAboutDlg dlgAbout;dlgAbout.DoModal();}else{CDialog::OnSysCommand(nID, lParam);}} void CSyntaxAnalysisDlg::OnPaint(){if (IsIconic()){CPaintDC dc(this);SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);// Center icon in client rectangleint cxIcon = GetSystemMetrics(SM_CXICON);int cyIcon = GetSystemMetrics(SM_CYICON);CRect rect;GetClientRect(&rect);int x = (rect.Width() - cxIcon + 1) / 2;int y = (rect.Height() - cyIcon + 1) / 2;// Draw the icondc.DrawIcon(x, y, m_hIcon);}else{CDialog::OnPaint();}}CSyntaxAnalysisDlg::OnQueryDragIcon(){return (HCURSOR) m_hIcon;}void CSyntaxAnalysisDlg::Cal_Symbol() //求出能推出ε的非终结符{int i,j,k,nEnd;CString Gr[8];for (i=0;i<5;i++)m_nFlags[i]=0; //置初值,0表示否for (i=0;i<8;i++){Gr[i]=m_Gr[i];if (Gr[i]=="ε"){m_nFlags[m_Gl[i]]=1;//1表示是,即能推出ε}}do{nEnd=0;for (i=0;i<5;i++) //检查每一个非终结符{if (m_nFlags[i]==1) //如果该非终结符能推出ε,就将所有表达式右部删去该终结符{for(j=0;j<8;j++) //查找每一个表达式{if (Gr[j].IsEmpty()||Gr[j]=="ε") continue;for (k=0;k<Gr[j].GetLength();k++) //查找表达式右部的每一个字符{if (Gr[j].GetAt(k)==m_VN[i]) //找到该终结符{Gr[j]=Gr[j].Left(k)+Gr[j].Right(Gr[ j].GetLength()-k-1); //删去该终结符nEnd=1;break;}}if (Gr[j].IsEmpty()) m_nFlags[m_Gl[j]]=1; //如果右部为空,就在表中填是}}}} while(nEnd);}void CSyntaxAnalysisDlg::Cal_First() //求各非终结符的First集合{int i,j,k,nEnd,n;CString strFirst;for (i=0;i<5;i++){for (j=0;j<6;j++)m_First[i][j]=0;}for (i=0;i<8;i++){if (m_Gr[i].Left(2)=="ε"){m_First[m_Gl[i]][5]=1;continue;}strFirst=m_Gr[i].GetAt(0);for (j=0;j<5;j++){if(strFirst==m_VT[j]) //如果右部第一个字符是终结符{m_First[m_Gl[i]][j]=1;break;}}}do{nEnd=0;for (i=0;i<8;i++){n=0;strFirst=m_Gr[i].GetAt(0);do{for(j=0;j<5;j++){if (strFirst==m_VN[j]) //如果右部第一个字符是非终结符{for (k=0;k<6;k++){if(m_First[m_Gl[i]][k]!=m_First[j][k]){m_First[m_Gl[i]][k]=m_First[j][k];nEnd=1;}}if(m_First[j][5]==1&&n<m_Gr[i].GetLength()-1) //前一字符能推出ε,则下一字符的first集也包含于first(x)strFirst=m_Gr[i].GetAt(++n);elsestrFirst="";break;}}if (j==5) break;}while(!strFirst.IsEmpty());}} while(nEnd);}void CSyntaxAnalysisDlg::Cal_Follow() //求各非终结符的Follow集合{}void CSyntaxAnalysisDlg::DrawMList() //构造预测分析表{int i,j;for (i=0;i<5;i++){for (j=0;j<6;j++){m_M[i][j]="";}}m_M[0][0]="TE";m_M[0][3]="TE";m_M[1][1]="+TE";m_M[1][4]="ε";m_M[1][5]="ε";m_M[2][0]="FK";m_M[2][3]="FK";m_M[3][1]="ε";m_M[3][2]="*FK";m_M[3][4]="ε";m_M[3][5]="ε";m_M[4][0]="i";m_M[4][3]="(S)";m_ListCtrl.SetExtendedStyle(LVS_EX_ GRIDLINES);m_ListCtrl.InsertColumn(0,"",LVCFMT _CENTER,50);m_ListCtrl.InsertColumn(1,"i",LVCFM T_CENTER,50);m_ListCtrl.InsertColumn(2,"+",LVCFM T_CENTER,50);m_ListCtrl.InsertColumn(3,"*",LVCFM T_CENTER,50);m_ListCtrl.InsertColumn(4,"(",LVCFM T_CENTER,50);m_ListCtrl.InsertColumn(5,")",LVCFM T_CENTER,50);m_ListCtrl.InsertColumn(6,"#",LVCFM T_CENTER,50);for (i=0;i<5;i++){m_ListCtrl.InsertItem(i,m_VN[i]);for (j=0;j<6;j++){if(!m_M[i][j].IsEmpty())m_ListCtrl.SetItemText(i,j+1,"→"+m_M[i][j]);}}}void CSyntaxAnalysisDlg::OnBTNAnalysis() {UpdateData(true);if (m_strCode.IsEmpty()){MessageBox("请输入要分析的句子!","提醒");return;}if (Analysis())m_strResult+="归约过程如下:\r\n\r\n"+m_sPro.Right(m_sPro.GetLength( )-3);UpdateData(false);}//主要的程序算法BOOL CSyntaxAnalysisDlg::Analysis(){CString stack[100];int pStack;//定义一个顺序栈stack[0]="#";stack[1]="S";pStack=1;//初始化栈int n=0;CString sStack,sCode,str,strCode,strPro;int i,j;strCode=m_strCode+"#"; //输入串m_sPro="<= S";strPro="S";while (1){if (n==m_strCode.GetLength()&&pStack==0) //分析成功{m_strResult="符合给定文法.";return true;}sStack=stack[pStack];//栈顶字符sCode=strCode.GetAt(n);//剩余输入串的首字符if (sStack==sCode) //匹配{pStack--;n++;continue;}for (i=0;i<5;i++){if (sStack==m_VN[i])break;}if (i==5){m_strResult="不符合给定文法!";return false;}for (j=0;j<5;j++){if (sCode==m_VT[j])break;}if (j==5&&sCode!="#") {m_strResult="不可识别的字符: "+sCode; return false;}str=m_M[i][j]; if (str.IsEmpty()) {m_strResult="不符合给定文法!"; return false;}if (str=="ε") { strPro=strPro.Left(n)+strPro.Right(strPro.GetLength()-n-1);m_sPro="<="+strPro+"\r\n"+m_sPro;pStack--; continue;}strPro=strPro.Left(n)+str+strPro.Right(strPro.GetLength()-n-1);m_sPro="<="+strPro+"\r\n"+m_sPro; pStack--;for(j=0;j<str.GetLength();j++) {pStack++;stack[pStack]=str.GetAt(str.GetLength()-j-1); }}五、运行结果分析句子(i+i)*i正确并写出归约此次实验我继续使用VC++6.0平台编译程序,见面力求简洁,以满足实验功能为主。
编译原理实验二: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就显现出其左递归性了,这就是间接左递归文法。
编译原理实验报告二
内蒙古工业大学信息工程学院实验报告课程名称:编译原理试验名称:语法制导把体现式翻译成逆波兰式试验类型:验证性□ 综合性□ 设计性□试验室名称:班级:学号姓名:组别:同组人:成绩:试验日期:预习汇报成绩:指导教师审核(签名):年月日预习汇报一、试验目旳通过上机实习加深对语法指导翻译原理旳理解,掌握运算符优先权旳算法,将语法分析所识别旳体现式变换成中间代码旳翻译措施。
二、试验题目语法制导把体现式翻译成逆波兰式三、规定及提醒1、从左到右扫描中缀体现式,经语法分析找出中缀体现式出现旳错误并给出错误旳详细位置和类型。
2、设一种运算符栈寄存临时不能出现旳运算符,逆波兰区寄存逆波兰体现式。
3、测试所编程序,给出对旳和错误旳成果。
4、工具:C语言或其他高级语言5、试验时间:4课时试验汇报成绩:指导教师审核(签名):年月日试验汇报试验二语法制导把体现式翻译成逆波兰式一、试验名称语法制导把体现式翻译成逆波兰式二、试验目旳通过上机实习加深对语法指导翻译原理旳理解,深入掌握语法制导翻译旳概念,掌握运算符优先权旳算法,将语法分析所识别旳体现式变换成中间代码旳翻译措施。
三、体现式生成逆波兰式旳算法1、初始化△送到运算符栈。
2、扫描左括号“(”,把△送到运算符栈。
3、扫描到变量,把它送到逆波兰区。
4、扫描到运算符(1)栈内运算符比较a.栈内运算符>=栈外运算符,把栈内运算符送到逆波兰区。
b.栈内运算符<栈外运算符,把栈外运算符入栈。
( 2 ) 栈内是△把运算符入栈。
5、扫描右括号“)”。
( 1 )栈内是运算符,把栈内运算符送到逆波兰区。
( 2 )栈内是△则△退栈,读入下一种字符。
6、扫描到#(结束符)( 1 )栈内是运算符,把栈内运算符送到逆波兰区。
( 2 )栈内是△结束,否则继续分析。
四、程序清单#include<stdio.h>#include<string.h>int main(){char str[100];char exp[100];char stack[100];char ch;int flag=1;unsigned int zs;while(true){int i=0,j=0,t=0,top=0;printf("---语法制导把体现式翻译成逆波兰式---\n");printf("请输入体现式:");scanf("%s",str);zs=strlen(str);str[zs]='#';ch=str[i];while(ch!='#'){if((ch>='a'&&ch<'z')||(ch>='0'&&ch<='9')){exp[t]=ch;t++;}else if(ch=='('||ch=='^'){top++;stack[top]=ch;}else if(ch==')'){while(stack[top]!='('){exp[t]=stack[top];top--;t++;}top--;}else if(ch=='+'||ch=='-'){while(top!=0&&stack[top]!='('){exp[t]=stack[top];top--;t++;}top++;stack[top]=ch;}else if(ch=='*'||ch=='/'){while(stack[top]=='*'||stack[top]=='/'){ exp[t]=stack[top];top--;t++;}top++;stack[top]=ch;}else{printf("第%d个字母开始出错!\n",i+1);flag=0;break;}i++;ch=str[i];}if(flag!=0){while(top!=0){exp[t]=stack[top];t++;top--;}printf("逆波兰式输出:");for(j=0;j<t;j++)printf("%c",exp[j]);printf("\n");}}return 0;}五、体现式生成逆波兰式算法旳流程图Y六、测试程序出现旳问题及处理措施1. 完毕这个试验,在老师给定试验汇报旳基础上,没有做太多旳弯路,做起来还算顺利,不过由于自己旳编程能力不好,还是碰到了诸多旳困难,有挑战才有动力进步,在同学旳协助下我都一一克服了。
编译原理实验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正规式的定义与应用的文章,希望对你有所帮助。
编译原理实验二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);}。
计科1505-河南工业大学--编译原理实验二
河南工业大学实验报告课程名称编译原理 _ 实验项目实验二 LL(1)分析法院系信息科学与工程学院专业班级计科F1505班姓名李杰学号 201516010118指导老师阎娟日期 2018.5.2批改日期成绩一.实验目的1.掌握LL(1)分析法的基本原理2.掌握LL(1)分析表的构造方法3.掌握LL(1)驱动程序的构造方法二.实验内容及要求根据某一文法编制调试LL(1)分析程序,以便对任意输入的符号串进行分析。
本次实验的目的主要是加深对预测分析LL(1)分析法的理解。
例:对下列文法,用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输出的格式如下:(1)LL(1(2)输入一以#结束的符号串((3)输出过程如下:步骤分析栈剩余输入串所用产生式1 E i+i*i# E->TG(或者为合法符号串)备注:(1)在“所用产生式”一列中如果对应有推导则写出所用产生式;如果为匹配终结符则写明匹配的终结符;如分析异常出错则写为“分析出错”;若成功结束则写为“分析成功”。
(3)上述描述的输出过程只是其中一部分的。
注意:1.表达式中允许使用运算符(+-*/)、分割符(括号)、字符i,结束符#;2.如果遇到错误的表达式,应输出错误提示信息(该信息越详细越好);3.对学有余力的同学,测试用的表达式事先放在文本文件中,一行存放一个表达式,同时以分号分割。
同时将预期的输出结果写在另一个文本文件中,以便和输出进行对照;4.可采用的其它的文法。
三.实验过程○1总体思路分析及流程图给定一个正规文法G,在LL(1)预测分析中,必须先求出First集和Follow集,然后求出Select集,通过Select集判断是否是LL1文法,如果是的话,构造预测分析表。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
编译原理二-------词法分析器一.问题描述词法分析程序的功能:输入源程序,输出单词符号,如图所示:单词符号处理过程:在扫描源程序字符串时,一旦识别出关键字、分隔符、标识符、无符号常数中之一,即以单词形式(各类单词均采用相同的结构,即二元式编码形式)输出。
每次调用词法分析程序,它均能自动继续扫描下去,形成下一个单词,直至整个源程序全部扫描完毕,并形成相应的单词串形式的源程序。
二.需求分析1.对给定的程序通过词法分析器能够识别一个个单词符号,并以二元式(单词类型,单词符号)显示;2.可以将要分析的程序保存到文件中进行读取;3.删除无用的空白字符、回车符、及其它非实质性符号。
三.程序设计本程序规定:(1)关键字"begin","end","if","then","else","while","write","read", "do", "call","const","char","until","procedure","repeat"(2)运算符:"+","-","*","/","="(3)界符:"{","}","[","]",";",",",".","(",")",":"(4)其他标记如字符串,表示以字母开头的标识符。
(5)空格、回车、换行符跳过。
对于一段可能的输入代码,其结果在屏幕上显示如下:( 1 , 无符号整数)( begin , 关键字 )( if , 关键字 )( +, 运算符 )( ; , 界符 )( a , 普通标识符 )关键字或标识符的判断:读入一串字符,将ASCII码在字母范围的字符存入数组中,将该数组与设置好的关键字比较,如果相等则输出是关键字,否则继续读入直至下一字符既非数字也非字母,输出为标识符;数字的判断:若跟在字母后面则一起输出为标识符,否则输出为数字;界符、运算符的判断:直接判断其ASCII码运行过程为:1.预处理:把源文件一个字符一个字符的读入词法分析程序设置的输入字符结构体数组中(输入缓冲区),读入过程要删除多余的空格;2.源程序字符数组中获得单词, 编码为二元式.:二元式采用结构体数组存储, 把单词类型和词元记录下来。
为了方便和适用起见,首先建立一个文本,进而在文本中进行pascal语言输入。
输入完毕之后,就可以进行从文本中取字符,进而把它放在一个数组中。
之后再数组中进行取字符,之前要定义一个数组,定义一个指针指向数组,为first。
之后就用一个循环依次从数组中取字符,假如是字符就放在buf中,first++;一次进行下去,期间要时刻与关键字指针数组进行比较如果相等就立马输出,并显示是关键字此时将buf置为初值,first重新指向首地址。
四.流程图Y五.调试分析刚开始的时候,我的程序没有采用文件形式,结果只能输入一行代码分析一行,很不实用,后来我想到可以将分析结果保存到数组中,并将结果和结果之间用空格分隔开,这样在输出时就可以连续输出了,我将这一思想运用到了文件系统中,经过改进,现在的程序可以分析保存在文件中的比较长的代码了。
六.用户手册现将要处理的代码段保存于文件中,在本程序中,我保存的位置是D:\ hello.txt,文件内容如下图所示:点击运行程序需要先输入待分析代码的文件位置,在本程序中是D:\hello.txt,输入后程序自动分析并输出结果。
七.运行结果点击运行程序,其分析结果如下:八.程序代码:#include <iostream>#include<string>using namespace std;#define MAX 22char ch =' ';stringkey[15]={"begin","end","if","then","else","while","write","read", "do", "call","const","char","until","procedure","repeat"};int Iskey(string c){//关键字判断int i;for(i=0;i<MAX;i++) {if(key[i].compare(c)==0) return 1;}return 0;}int IsLetter(char c) {//判断是否为字母if(((c<='z')&&(c>='a'))||((c<='Z')&&(c>='A'))) return 1;else return 0;}int IsDigit(char c){//判断是否为数字if(c>='0'&&c<='9') return 1;else return 0;}void fenxi(FILE *fpin){string arr="";while((ch=fgetc(fpin))!=EOF) {arr="";if(ch==' '||ch=='\t'||ch=='\n'){}else if(IsLetter(ch)){while(IsLetter(ch)||IsDigit(ch)) {if((c h<='Z')&&(ch>='A')) ch=ch+32;arr=arr+ch;ch=fgetc(fpin);}fseek(fpin,-1L,SEEK_CUR);if (Iskey(arr)){cout<<arr<<"\t$关键字"<<endl;}else cout<<arr<<"\t$普通标识符"<<endl;}else if(IsDigit(ch)){while(IsDigit(ch)||ch=='.'&&IsDig it(fgetc(fpin))){arr=arr+ch;ch=fgetc(fpin);}fseek(fpin,-1L,SEEK_CUR);cout<<arr<<"\t$无符号实数"<<endl;}else switch(ch){case'+':case'-' :case'*' :case'=' :case'/' :cout<<ch<<"\t$运算符"<<endl;break;case'(' :case')' :case'[' :case']' :case';' :case'.' :case',' :case'{' :case'}' :cout<<ch<<"\t$界符"<<endl;break;case':' :{ch=fgetc(fpin);if(ch=='=')cout<<":="<<"\t$运算符"<<endl;else{cout<<"="<<"\t$运算符"<<endl;;fseek(f pin,-1L,SEEK_CUR);}}break;case'>' :{ch=fgetc(fpin);if(ch=='=')cout<<">="<<"\t$运算符"<<endl;if(ch=='>')cout<<"> >"<<"\t$输入控制符"<<endl;else{cout<<">"<<"\t$运算符"<<endl;fseek(fpin, -1L,SEEK_CUR);}}break;case'<' :{ch=fgetc(fpin);if(ch=='=')cout<<"< ="<<"\t$运算符"<<endl;elseif(ch=='<')cout<<"<<"<<"\t$输出控制符"<<endl;else if(ch=='>') cout<<"<>"<<"\t$运算符"<<endl;else{cout<<"<"<<"\t $运算符"<<endl;fseek(fpin,-1 L,SEEK_CUR);}}break;default : cout<<ch<<"\t$无法识别字符"<<endl;}}}void main(){char in_fn[30];FILE * fpin;cout<<"请输入源文件名(包括路径和后缀名):";for(;;){cin>>in_fn;if((fpin=fopen(in_fn,"r"))!=NULL) break;else cout<<"文件路径错误!请输入源文件名(包括路径和后缀名):";}cout<<"\n********************分析如下*********************"<<endl;fenxi(fpin);fclose(fpin);}九.实验总结分析通过这次实验,我对词法分析器有了一定的了解,进一步的巩固了这部分的知识。