编译原理实验报告.docx
《编译原理实验报告.docx》由会员分享,可在线阅读,更多相关《编译原理实验报告.docx(46页珍藏版)》请在冰豆网上搜索。
编译原理实验报告
《编译原理》
实
验
报
告
学号:
1441901105
姓名:
谢卉
实验一词法分析设计
实验学时:
4
实验类型:
综合
实验要求:
必修
一、实验目的
通过本实验的编程实践,使学生了解词法分析的任务,掌握词法分析程序设计的原理和构造方法,使学生对编译的基本概念、原理和方法有完整的和清楚的理解,并能正确地、熟练地运用。
二、实验内容
用VC++/VB/JAVA语言实现对C语言子集的源程序进行词法分析。
通过输入源程序从左到右对字符串进行扫描和分解,依次输出各个单词的内部编码及单词符号自身值;若遇到错误则显示“Error”,然后跳过错误部分继续显示;同时进行标识符登记符号表的管理。
以下是实现词法分析设计的主要工作:
(1)从源程序文件中读入字符。
(2)统计行数和列数用于错误单词的定位。
(3)删除空格类字符,包括回车、制表符空格。
(4)按拼写单词,并用(内码,属性)二元式表示。
(属性值——token的机内表示)
(5)如果发现错误则报告出错
(6)根据需要是否填写标识符表供以后各阶段使用。
单词的基本分类:
◆关键字:
由程序语言定义的具有固定意义的标识符。
也称为保留字例如if、for、while、printf;单词种别码为1。
◆标识符:
用以表示各种名字,如变量名、数组名、函数名;
◆常数:
任何数值常数。
如125,1,0.5,3.1416;
◆运算符:
+、-、*、/;
◆关系运算符:
<、<=、=、>、>=、<>;
◆分界符:
;、,、(、)、[、];
三、词法分析实验设计思想及算法
1、主程序设计考虑:
◆程序的说明部分为各种表格和变量安排空间。
在具体实现时,将各类单词设计成结构和长度均相同的形式,较短的关键字后面补空。
k数组------关键字表,每个数组元素存放一个关键字(事先构造好关键字表)。
s数组------存放分界符表(可事先构造好分界符表)。
为了简单起见,分界符、算术运算符和关系运算符都放在s表中(编程时,应建立算术运算符表和关系运算符表,并且各有类号),合并成一类。
id和ci数组分别存放标识符和常数。
instring数组为输入源程序的单词缓存。
outtoken记录为输出内部表示缓存。
还有一些为造表填表设置的变量。
◆主程序开始后,先以人工方式输入关键字,造k表;再输入分界符等造p表。
◆主程序的工作部分设计成便于调试的循环结构。
每个循环处理一个单词;接收键盘上送来的一个单词;调用词法分析过程;输出每个单词的内部码。
例如,把每一单词设计成如下形式:
(type,pointer)
其中type指明单词的种类,例如:
Pointer指向本单词存放处的开始位置。
还有一些为造表填表设置的变量。
◆主程序开始后,先以人工方式输入关键字,造k表;再输入分界符等造p表。
◆主程序的工作部分设计成便于调试的循环结构。
每个循环处理一个单词;接收键盘上送来的一个单词;调用词法分析过程;输出每个单词的内部码。
例如,把每一单词设计成如下形式:
(type,pointer)
其中type指明单词的种类,例如:
Pointer指向本单词存放处的开始位置。
词法分析设计流程图
2、词法分析过程考虑
◆根据输入单词的第一个字符(有时还需读第二个字符),
判断单词类,产生类号:
以字符k表示关键字;id表示标识符;
ci表示常数;s表示分界符。
◆对于标识符和常数,需分别及标识符表和常数表中已登记的元素相比较,如表中已有该元素,则记录其在表中的位置,如未出现过,将标识符按顺序填入数组id中,将常数变为二进制形式存入数组中ci中,并记录其在表中的位置。
lexical过程中嵌有两个小过程:
一个名为getchar,其功能为从instring中按顺序取出一个字符,并将其指针pint加1;另一个名为error,当出现错误时,调用这个过程,输出错误编号。
◆要求:
所有识别出的单词都用两个字节的等长表示,称为内部码。
第一个字节为t,第二个字节为i。
t为单词的种类。
关键字的t=1;分界符的t=2;算术运算符的t=3;关系运算符的t=4;无符号数的t=5;标识符的t=6。
i为该单词在各自表中的指针或内部码值。
表1为关键字表;表2为分界符表;表3为算术运算符的i值;表4为关系运算符的i值。
取字符和统计字符行列位置子程序
四、实验要求
1、编程时注意编程风格:
空行的使用、注释的使用、缩进的使用等。
2、将标识符填写的相应符号表须提供给编译程序的以后各阶段使用。
3、根据测试数据进行测试。
测试实例应包括以下三个部分:
◆全部合法的输入。
◆各种组合的非法输入。
◆由记号组成的句子。
4、词法分析程序设计要求输出形式:
例:
输入VC++语言的实例程序:
Ifi=0thenn++;
a﹤=3b%);
输出形式为:
单词二元序列类型位置(行,列)
(单词种别,单词属性)
for(1,for)关键字(1,1)
i(6,i)标识符(1,2)
=(4,=)关系运算符(1,3)
0(5,0)常数(1,4)
then(1,then)关键字(1,5)
n(6,n)标识符(1,6)
++ErrorError(1,7)
;(2,;)分界符(1,8)
a(6,a)标识符(2,1)
﹤=(4,<=)关系运算符(2,2)
3bErrorError(2,4)
%ErrorError(2,4)
)(2,))分界符(2,5)
;(2,;)分界符(2,6)
五、实验步骤
1、根据流程图编写出各个模块的源程序代码上机调试。
2、编制好源程序后,设计若干用例对系统进行全面的上机测试,并通过所设计的词法分析程序;直至能够得到完全满意的结果。
3、书写实验报告;实验报告正文的内容:
◆功能描述:
该程序具有什么功能?
◆程序结构描述:
函数调用格式、参数含义、返回值描述、函数功能;函数之间的调用关系图。
◆详细的算法描述(程序总体执行流程图)。
◆给出软件的测试方法和测试结果。
◆实验总结(设计的特点、不足、收获及体会)。
六、实验代码
#include"stdafx.h"
#include
#include
#include
usingnamespacestd;
#defineMAX10000
structWordString
{
stringWord;//单词
intcategory;//类别
};
char*key[7]={"int","for","while","do","return","break","continue"};//关键字
WordStringwords[MAX];//创建一个单词符号串
stringtext;//读入的文本存入text中
stringword;//分割出的单词用word表示
intlength;//字符个数
intk;//总单词个数
char*fenhao[1]={";"};
introwx;
introwy;
voidscan()
{
inti,j;
k=0;
word="";
for(i=0;i<=length-1;i++)
{
if(word!
=""){
if(((word[0]>='A')&&(word[0]<='Z'))||((word[0]>='a')&&(word[0]<='z')))//首字符是字母
{
if(((text[i]>='A')&&(text[i]<='Z'))||((text[i]>='a')&&(text[i]<='z'))||((text[i]>=48)&&(text[i]<=57)))
{
word+=text[i];
}
else
{
words[k].Word=word;
for(j=0;j<7;j++)
{
if(words[k].Word==key[j])
{
words[k].category=1;//表示关键字
break;
}
elseif(j==6)
words[k].category=2;//表示标识符
}
k++;
word="";
i--;
}
}
elseif(word[0]==','||word[0]=='{'||word[0]=='}'||word[0]=='('||word[0]==')')//首字符是界限符
{
words[k].Word=word;
words[k].category=5;//表示界限符
k++;
word="";
i--;
}
elseif(word[0]==';')
{
words[k].Word=word;
words[k].category=7;//表示界限符
k++;
word="";
i--;
}
elseif(word[0]=='+'||word[0]=='-'||word[0]=='*'||word[0]=='/'||word[0]=='='||word[0]=='>'||word[0]=='<'||word[0]=='!
')//首字符是运算符
{
if(text[i]=='=')
{
word+=text[i];
words[k].Word=word;
words[k].category=4;//表示运算符
k++;
word="";
}
else
{
words[k].Word=word;
words[k].category=4;//表示运算符
k++;
word="";
i--;
}
}
elseif(word[0]>=48&&word[0]<=57)//首字符是数字
{
if(text[i]>=48&&text[i]<=57)
{
word+=text[i];
}
elseif((text[i]>='A'&&text[i]<='Z')||(text[i]>='a'&&text[i]<='z'))
{
word+=text[i];
words[k].category=6;//表示出错,标识符以数字开头
}
else
{
words[k].Word=word;
if(words[k].category!
=6)
words[k].category=3;//表示常数
k++;
word="";
i--;
}
}
}
else
{
if(text[i]!
=10&&text[i]!
=32&&text[i]!
=9)
{
word+=text[i];
}
}
}
}
intmain()
{
introwx=1,rowy=1;
FILE*fp;//文件指针
fp=fopen("F:
//text.txt","r");//打开文件
if(fp==NULL)
{
printf("文件打开错误\n");
exit(0);
}
inti=0;
while(!
feof(fp))//判断是否到文件结尾
{
text+=fgetc(fp);
i++;
}
length=i;//text最后一个字符是空字符
fclose(fp);//关闭文件
scan();
printf("\t—————————词法分析器—————————\n");
printf("\t单词\t\t类型\t\t二元序列\t坐标\n");
for(i=0;i{
if(words[i].category==1)
{
printf("\t%s\t\t关键字\t\t",words[i].Word.c_str());
printf("(%d,%s)\t",words[i].category,words[i].Word.c_str());
printf("(%d,%d)\n",rowx,rowy);
rowx+=1;
}
if(words[i].category==2)
{
printf("\t%s\t\t标识符\t\t",words[i].Word.c_str());
printf("(%d,%s)\t\t",words[i].category,words[i].Word.c_str());
printf("(%d,%d)\n",rowx,rowy);
rowx+=1;
}
if(words[i].category==3)
{
printf("\t%s\t\t常数\t\t",words[i].Word.c_str());
printf("(%d,%s)\t\t",words[i].category,words[i].Word.c_str());
printf("(%d,%d)\n",rowx,rowy);
rowx+=1;
}
if(words[i].category==4)
{
printf("\t%s\t\t运算符\t\t",words[i].Word.c_str());
printf("(%d,%s)\t\t",words[i].category,words[i].Word.c_str());
printf("(%d,%d)\n",rowx,rowy);
rowx+=1;
}
if(words[i].category==5)
{
printf("\t%s\t\t分界符\t\t",words[i].Word.c_str());
printf("(%d,%s)\t\t",words[i].category,words[i].Word.c_str());
printf("(%d,%d)\n",rowx,rowy);
rowx+=1;
}
if(words[i].category==7)
{
printf("\t%s\t\t分界符\t\t",words[i].Word.c_str());
printf("(%d,%s)\t\t",words[i].category,words[i].Word.c_str());
rowx=1;
rowy+=1;
printf("(%d,%d)\n",rowx,rowy);
}
if(words[i].category==6)
{
printf("\t%s\t\tEorror\t\t",words[i].Word.c_str());
printf("(%d,%d)\n",rowx,rowy);
rowx+=1;
}
}
/*switch(words[i].category)
{
case1:
printf("%s\t关键字\t",words[i].Word.c_str());
printf("(%d,%s)\t",words[i].category,words[i].Word.c_str());
printf("(%d,%d)\n",rowx,rowy);
rowx+=1;
break;
case2:
printf("%s\t标识符\t",words[i].Word.c_str());
printf("(%d,%s)\t",words[i].category,words[i].Word.c_str());
if(word==";")
{
rowy++;
rowx=1;
}
printf("(%d,%d)\n",rowx,rowy);
break;
}*/
getchar();
return0;
}
七、实验结果
实验二LL
(1)分析法
实验学时:
2
实验类型:
综合
实验要求:
必修
一、实验目的
通过完成预测分析法的语法分析程序,了解预测分析法和递归子程序法的区别和联系。
使学生了解语法分析的功能,掌握语法分析程序设计的原理和构造方法,训练学生掌握开发应用程序的基本方法。
有利于提高学生的专业素质,为培养适应社会多方面需要的能力。
二、实验内容
◆根据某一文法编制调试LL
(1)分析程序,以便对任意输入的符号串进行分析。
◆构造预测分析表,并利用分析表和一个栈来实现对上述程序设计语言的分析程序。
◆分析法的功能是利用LL
(1)控制程序根据显示栈栈顶内容、向前看符号以及LL
(1)分析表,对输入符号串自上而下的分析过程。
三、LL
(1)分析法实验设计思想及算法
◆模块结构:
(1)定义部分:
定义常量、变量、数据结构。
(2)初始化:
设立LL
(1)分析表、初始化变量空间(包括堆栈、结构体、数组、临时变量等);
(3)控制部分:
从键盘输入一个表达式符号串;
(4)利用LL
(1)分析算法进行表达式处理:
根据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
输出的格式如下:
五、实验步骤
1、根据流程图编写出各个模块的源程序代码上机调试。
2、编制好源程序后,设计若干用例对系统进行全面的上机测试,并通过所设计的LL
(1)分析程序;直至能够得到完全满意的结果。
3、书写实验报告;实验报告正文的内容:
◆写出LL
(1)分析法的思想及写出符合LL
(1)分析法的文法。
◆程序结构描述:
函数调用格式、参数含义、返回值描述、函数功能;函数之间的调用关系图。
◆详细的算法描述(程序执行流程图)。
◆给出软件的测试方法和测试结果。
◆实验总结(设计的特点、不足、收获及体会)。
六、实验代码
//ConsoleApplication1.cpp:
定义控制台应用程序的入口点。
//
#include"stdafx.h"
#include
#include
#include
#include
charA[20];/*分析栈*/
charB[20];/*剩余串*/
charv1[20]={'i','+','*','(',')','#'};/*终结符*/
charv2[20]={'E','G','T','S','F'};/*非终结符*/
intj=0,b=0,top=0,l;/*L为输入串长度*/
typedefstructtype/*产生式类型定义*/
{
charorigin;/*大写字符*/
chararray[5];/*产生式右边字符*/
intlength;/*字符个数*/
}type;
typee,t,g,g1,s,s1,f,f1;/*结构体变量*/
typeC[10][10];/*预测分析表*/
voidprint()/*输出分析栈*/
{
inta;/*指针*/
for(a=0;a<=top+1;a++)
printf("%c",A[a]);
printf("\t\t");
}/*print*/
voidprint1()/*输出剩余串*/
{
intj;
for(j=0;j
printf("");
for(j=b;j<=l;j++)
printf("%c",B[j]);
printf("\t\t\t");
}/*print1*/
voidmain()
{
intm,n,k=0,flag=0,finish=0;
charch,x;
typecha;/*用来接受C[m][n]*/
/*把文法产生式赋值结构体*/
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;
g1.origin='G';
g1.array[0]='^';
g1.length=1;
s.origin='S';
strcpy(s.array,"*FS");
s.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<=5;n++)
C[m][n].origin='N';/*全部赋为空*/
/*填充分析表*/
C[0][0]=e;C[0][3]=e;
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;
printf("提示:
本程序只能对由'i','+','*','(',')'构成的以'#'结束的字