编译原理实验指导书 适用于医智12.docx
- 文档编号:29675970
- 上传时间:2023-07-26
- 格式:DOCX
- 页数:29
- 大小:131.14KB
编译原理实验指导书 适用于医智12.docx
《编译原理实验指导书 适用于医智12.docx》由会员分享,可在线阅读,更多相关《编译原理实验指导书 适用于医智12.docx(29页珍藏版)》请在冰豆网上搜索。
编译原理实验指导书适用于医智12
《编译原理》
实验指导书
目录
实验一:
消去C、C++程序中的注释1
实验二:
词法分析3
实验三:
语法分析程序LL
(1)18
实验四:
算术表达式的逆波兰表示与计算32
实验一:
消去C、C++程序中的注释
实验学时:
2
实验类型:
验证
实验要求:
必修
一、实验目的
掌握C语言文件的基本操作,消除源C语言程序中的注释,为以后的编译提供方便。
二、实验内容
注释对于高级语言程序设计可以提高程序的可阅读性,但是对于编译系统而言,注释是没有实际意义的,所以编译系统在预编译阶段首先就要去掉注释。
在VC中有两种注释,即单行注释,由//引入到行未,由/*…..*/所包围的注释。
要求去掉VC中这两种注释而不改变程序的其它部分。
三、实验原理或算法
算法原理:
逐字符读入源程序,并判断相邻2个字符是否为//或/*或*/,如果不是,则直接将读入的字符写入新文件中;如果是,则跳过注释部分。
四、程序清单
在VC6.0下程序清单:
//削除单行注释与多行注释即//与/*...*/
#include"stdio.h"
#include"stdlib.h"
main()
{
FILE*fp1,*fp2;
charch1,ch2,ch3,ch4,flag=0;
if((fp1=fopen("input.cpp","r"))==NULL)//input.cpp为任意带注释的C程序
{
printf("filecannotbeopened\n");
exit
(1);
}
if((fp2=fopen("output.cpp","w"))==NULL)//ouput.cpp为去掉注释后的程序
{
printf("filecannotbewrited\n");
exit
(1);
}
ch1=fgetc(fp1);
ch2=fgetc(fp1);
while(!
feof(fp1))
{
if(ch1=='/')
if(ch2=='*'||ch2=='/')
{if(ch2=='*')
{
ch3=fgetc(fp1);
ch4=fgetc(fp1);
while(!
(ch3=='*'&&ch4=='/')&&!
feof(fp1))
{
ch3=ch4;
ch4=fgetc(fp1);//readonlynotwrite
}
ch2=fgetc(fp1);
}
if(ch2=='/')
while((ch2=fgetc(fp1))!
=10);//readonly/notwrite
}
else
fputc(ch1,fp2);
else
fputc(ch1,fp2);
ch1=ch2;
ch2=fgetc(fp1);
}
fputc(ch1,fp2);
fclose(fp1);
fclose(fp2);
return1;
}
五、实验结果分析
比对源文件和产生的新文件,对照验证程序所产生的结果。
六、思考题
(1)将输入输出文件改成可由键盘输入的文件名。
(2)如果在字符串中出现连续的//或/*或*/则不应做处理,请修改上面的程序。
实验二:
词法分析
实验学时:
4
实验类型:
综合
实验要求:
必修
一、实验目的
通过设计编制调试一个具体的词法分析程序,加深对词法分析原理的理解。
并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。
二、实验内容
编制一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。
并依次输出各个单词的内部编码及单词符号自身值。
(遇到错误时可显示“Error”,然后跳过错误部分继续显示)。
三、实验原理或算法
1、词法分析器的功能和输出格式
词法分析器的功能是输入源程序,输出单词符号。
词法分析器的单词符号常常表示成以下的二元式(单词种别码,单词符号的属性值)。
本实验中,采用的是一类符号一种别码的方式。
2、单词的BNF表示
<标识符>-><字母><字母数字串>
<字母数字串>-><字母><字母数字串>|<数字><字母数字串>|<下划线><字母数字串>|ε
<无符号整数>-><数字><数字串>
<数字串>-><数字><数字串>|ε
<加法运算符>->+
<减法运算符>->-
<大于关系运算符>->>
<大于等于关系运算符>->>=
3、“超前搜索”方法
词法分析时,常常会用到超前搜索方法。
如当前待分析字符串为“a>=”或“a>b”,当前字符为’>’,此时,分析器倒底是将其分析为大于关系运算符还是大于等于关系运算符呢?
显然,只有知道下一个字符是什么才能下结论。
于是分析器读入下一个字符’=’或’b’,这时可知应将’>’解释为大于或大于等于运算符。
但此时,超前读了一个字符’b’,所以要回退一个字符,词法分析器才能正常运行。
在分析标识符,无符号整数等时也有类似情况。
4、编程思路
这里以开始定义的C语言子集的源程序作为词法分析程序的输入数据。
在词法分析中,自文件头开始扫描源程序字符,一旦发现符合“单词”定义的源程序字符串时,将它翻译成固定长度的单词内部表示,并查填适当的信息表。
经过词法分析后,源程序字符串(源程序的外部表示)被翻译成具有等长信息的单词串(源程序的内部表示),并产生两个表格:
常数表和标识符表,它们分别包含了源程序中的所有常数和所有标识符。
5、单词种别码要求:
识别保留字:
if、int、for、while、do、return、break、continue;单词种别码为1。
分隔符包括:
、;、{、}、(、);单词种别码为2。
运算符包括:
+、-、*、/、=、;单词种别码为3。
关系运算符:
>、<、==、>=、<=、!
=;单词种别码为4。
标识符;单词种别码为5。
常数为无符号整形数;单词种别码为6。
四、程序清单
//词法分析程序
#include
#include
#include
#include
#defineNULL0
FILE*fp;
charcbuffer;
char*key[8]={"if","else","for","while","int","return","break","continue"};
char*border[6]={",",";","{","}","(",")"};
char*arithmetic[5]={"+","-","*","/","="};
char*relation[6]={"<","<=","==",">",">=","!
="};
char*consts[20];
char*label[20];
intconstnum=0,labelnum=0;
intsearch(charsearchchar[],intwordtype)
{
inti=0;
switch(wordtype)
{
case1:
for(i=0;i<=7;i++)
if(strcmp(key[i],searchchar)==0)return(i+1);
return0;
case2:
for(i=0;i<=5;i++)
if(strcmp(border[i],searchchar)==0)return(i+1);
return(0);
case3:
for(i=0;i<=4;i++)
if(strcmp(arithmetic[i],searchchar)==0)return(i+1);
return(0);
case4:
for(i=0;i<=5;i++)
if(strcmp(relation[i],searchchar)==0)return(i+1);
return(0);
case5:
for(i=0;i if(strcmp(consts[i],searchchar)==0)return(i+1); consts[i]=(char*)malloc(sizeof(searchchar)); strcpy(consts[i],searchchar); constnum++; return(i+1); case6: for(i=0;i if(strcmp(label[i],searchchar)==0)return(i+1); label[i]=(char*)malloc(sizeof(searchchar)); strcpy(label[i],searchchar); labelnum++; return(i+1); } } charalphaprocess(charbuffer)//字母开头串的处理(可能是保留字或标识符) { intatype; inti=-1; charalphatp[20]; while((isalpha(buffer))||(isdigit(buffer))) { alphatp[++i]=buffer; buffer=fgetc(fp); } alphatp[i+1]='\0'; //printf("%s,search=%d",alphatp,search(alphatp,1)); if(atype=search(alphatp,1)) printf("(%s,1,%d)\n",alphatp,atype); else { atype=search(alphatp,6); printf("(%s,6,%d)\n",alphatp,atype); } return(buffer); } chardigitprocess(charbuffer)//常量串 { inti=-1; chardigittp[20]; intdtype; while((isdigit(buffer))) { digittp[++i]=buffer; buffer=fgetc(fp); } digittp[i+1]='\0'; dtype=search(digittp,5); printf("(%s,5,%d)\n",digittp,dtype); return(buffer); } charotherprocess(charbuffer)//其它符号的处理 { inti=-1; charothertp[20]; intotype,otypetp; othertp[0]=buffer; othertp[1]='\0'; if(otype=search(othertp,3)) { printf("(%s,3,%d)\n",othertp,otype); buffer=fgetc(fp); gotoout; } 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); gotoout; } else { othertp[1]='\0'; printf("(%s,4,%d)\n",othertp,otype); gotoout; } } if(buffer==': ') { buffer=fgetc(fp); if(buffer=='=') printf(": =(2,2)\n"); buffer=fgetc(fp); gotoout; } else if(otype=search(othertp,2)) { printf("(%s,2,%d)\n",othertp,otype); buffer=fgetc(fp); gotoout; } if((buffer! ='\n')&&(buffer! ='')) printf("%cerror,notaword\n",buffer); buffer=fgetc(fp); out: return(buffer); } voidmain() { inti; for(i=0;i<=20;i++) { label[i]=NULL; consts[i]=NULL; }; if((fp=fopen("example.cpp","r"))==NULL) printf("OpenFileError! "); else { printf("输出格式为: (单词,类别,位置)\n"); cbuffer=fgetc(fp); while(cbuffer! =EOF) { if(isalpha(cbuffer)) cbuffer=alphaprocess(cbuffer); else if(isdigit(cbuffer)) cbuffer=digitprocess(cbuffer); elsecbuffer=otherprocess(cbuffer); } printf("AnysisEnd\n"); getchar(); } } 五、实验结果分析 如源程序为C语言。 输入如下一段: main() { inta,b; a=10; b=a+20; } 要求输出如下结果: 六、思考题 对于一个真正的系统应该怎样完善该程序? 实验三.词法分析程序LL (1) 实验学时: 4 实验类型: 设计 实验要求: 必修 一、实验目的 根据某一文法编制调试LL (1)分析程序,以便对任意输入的符号串进行分析。 本次实验的目的主要是加深对预测分析LL (1)分析法的理解。 二、实验内容 对文法: E->E+T|TT->T*F|FF->(E)|i所生成的句子进行LL (1)分析,构造其分析程序。 三、实验原理或算法 1、改造文法: 消除左递归、提取左因子 将文法改造为: E->TE’ E’->+TE|ε T->FT’ T’->*FT’|ε F->(E)|i 2、求出firstt和follow FIRST(α)的构造: 设α∈(VN∪VT)*,α=X1X2…Xn,FIRST(α): (1)若α=ε,则FIRST(α)={ε}; (2)若α≠ε,则FIRST(α)\{ε}⊂FIRST(X); (3)若X1X2…Xi-1⇒*ε,则: FIRST(Xi)\{ε}⊂FIRST(α); (4)若X1X2…Xn⇒*ε,则ε∈FIRST(α) 对于X∈(VN∪VT),FIRST(X)的构造: (1)若X∈VT,则FIRST(X)={X}; (2)若X∈VN,且有产生式X→a…,a∈VT,则: a∈FIRST(X),如果X→ε,那么ε∈FIRST(X); (3)若有产生式X→Y…,Y∈VN,则: FIRST(Y)\{ε}⊂FIRST(X); (4)如果有产生式X→Y1Y2…YK,其中Y1,Y2,Yi-1∈VN且Y1Y2…Yi-1⇒*ε,则FIRST(Yi)\{ε}⊂FIRST(X); (5)若Y1Y2…YK⇒*ε,则ε∈FIRST(X)。 FOLLOW(U)的构造: (1)#∈FOLLOW(S) (2)如果有产生式A→xUy,那么FIRST(y)\{ε}⇒FOLLOW(U)。 (3)如果有产生式A→xU或则A→xUy且y⇒*ε,那么FOLLOW(A)⇒FOLLOW(U) 3、LL (1)文法的判定: 对于文法G的每一个非终结符U的产生式: U→α1|α2|…|αn。 如果文法G是一个LL (1) 文法,则有SELECT(U→αi)∩SELECT(U→αj)=Ф(i≠j,i,j=1,2,…,n)。 4、SELECT集的构造: SELECT(U→α)=FIRST(α),当α不空 =FIRST(α)∪FOLLOW(U),当α为空 对于上面的方法可以得到: first(E)=first(E)=first(E)={(,i} first(E’)={+,ε} first(T’)={*,ε} follow(E)=follow(E’)={),#} follow(T)=follow(T’)={+,),#} follow(F)={*,+,),#} (3)构造预测分析表 5、LL (1)分析表构造算法: 对于每个产生式U→α,执行下一步骤: 1、对于每个终结符号: a∈FIRST(α),M[U,a]=‘U→α’. 2、如果e∈FIRST(α),对于每个终结符号: b∈FOLLOW(U),M[U,b]=‘U→α’。 3、将其它未定义的分析元素置为ERROR。 预测分析表 i + * ( ) # E E->TE’ E->TE’ E’ E’->+TE E’->ε E’->ε T T->FT’ T->FT’ T’ T’->ε T’->*FT’ T’->ε T’->ε F F->i F->(E) 6、自下而上分析技术: 从输入符号串出发,试图把它规约为识别符号。 自下而上分析技术是一种“移进-归约”法。 从输入符号串开始,从左到右进行扫描,将输入符号逐个移入一个栈中,边移入边分析,一旦栈顶符号串形成某个产生式的右部时,就用该产生式的左部非终结符代替,称为归约。 重复这一过程,直到归约到栈中只剩下文法的开始符号时,则分析成功,称为“移进-归约”方法。 四、程序清单 //文法: E->E+T|TT->T*F|FF->(E)|i //根据预测分析表M[A,a]对输入串进行自上而下的语法分析程序 //已知预测分析表M[A,a]和输入串 //判别输入串是否为文法的句子,并生成预测分析步骤 #include #include #include #include usingnamespacestd; charVn[]={'E','e','T','t','F'};//定义文法的非终结符,小写字母e表示E’ charVt[]={'i','+','*','(',')','#'};//定义文法的终结符 intLENVt=sizeof(Vt); voidshowstack(stack { inti,j; charch[100]; j=st.size(); for(i=0;i { ch[i]=st.top(); st.pop(); } for(i=j-1;i>=0;i--) { cout< st.push(ch[i]); } } intfind(charc,chararray[],intn)//查找函数,返回布尔值 { inti; intflag=0; for(i=0;i { if(c==array[i]) flag=1; } returnflag; } intlocation(charc,chararray[])//定位函数,指出字符所在位置,即将字母转换为数组下标值 { inti; for(i=0;c! =array[i];i++); returni; } voiderror() { cout<<"出错! "< } voidanalyse(charVn[],charVt[],stringM[5][6],stringstr) { inti,j,p,q,h,flag=1; chara,X; stack st.push('#'); st.push(Vn[0]);//#与识别符号入栈 j=0;//j指向输入串的指针 h=1; a=str[j]; cout<<"步骤"<<"分析栈"<<"剩余输入串"<<"所用产生式"< while(flag==1) { cout< h++; showstack(st);//显示分析栈中内容 cout<<""; for(i=j;i X=st.top();//取栈顶符号放入X if(find(X,Vt,LENVt)==1)//X是终结符 if(X==a)//分析栈的栈顶元素和剩余输入串的第一个元素相比较 if(X! ='#') { cout<<""< st.pop(); a=str[++j];//读入输入串的下一字符 } else {cout<<""<<"接受! "< else {error();break;} else { p=location(X,Vn);//实现下标的转换(非终结符转换为行下标) q=location(a,Vt);//实现下标的转换(终结符转换为列下标) stringS1("NULL"),S2("null"); if(M[p][q]==S1||M[p][q]==S2)//查找二维数组中的产生式 {error();break;}//对应项为空,则出错 else { stringstr0=M[p][q]; cout<<""< st.pop(); if(str0! ="$")//$代表“空”
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 编译原理实验指导书 适用于医智12 编译 原理 实验 指导书 适用于 12