城市学院《编译原理》实验指导书.docx
《城市学院《编译原理》实验指导书.docx》由会员分享,可在线阅读,更多相关《城市学院《编译原理》实验指导书.docx(19页珍藏版)》请在冰点文库上搜索。
城市学院《编译原理》实验指导书
《编译原理》实验指导书
适用实验课时:
30
适用对象:
城市学院计算机系
实验目的和内容
编译原理实验的目的是使学生将编译理论运用到实际当中,实现一个简单语言集的词法分析程序、语法分析程序和简单语义处理程序,验证实际编译系统的实现方法,并加深对编译理论的认识。
基本实验分为三个部分,实验一识别无符号数的词法分析器设计实现、实验二无符号数的算术四则运算LR语法分析器设计实现,实验三是无符号数的算术四则运算语义处理程序实现,总的实验学时为30课时。
每部分基本实验还包括若干扩展实验,供编程能力较强的学生自愿进行。
要求每个学生独立完成三个基本实验的设计和编程实现,编程工具自选。
并形成完整的实验报告。
实验一词法分析程序实现
一、实验目的与要求
通过编写和调试一个词法分析程序,掌握在对程序设计语言的源程序进行扫描的过程中,将字符形式的源程序流转化为一个由各类单词符号组成的流的词法分析方法。
二、实验内容
选取无符号数的算术四则运算中的各类单词为识别对象,要求将其中的各个单词识别出来。
输入:
由无符号数和+,-,*,/,(,)构成的算术表达式,如1.5E+2-100。
输出:
对识别出的每一单词均单行输出其类别码(无符号数的值暂不要求计算)。
三、实现方法与环境
1、首先设计识别各类单词的状态转换图。
描述无符号常数的确定、最小化状态转换图如图1所示。
其中编号0,1,2,…,6代表非终结符号<无符号数>、<余留无符号数>、<十进小数>、<小数部分>、<指数部分>、<整指数>及<余留整指数>,1,2和6为终态,分别代表整数、小数和科学计数的识别结束状态。
图1文法G[<无符号数>]的状态转换图
其中编号0,1,2,…,6代表非终结符号<无符号数>、<余留无符号数>、<十进小数>、<小数部分>、<指数部分>、<整指数>及<余留整指数>,1,2和6为终态,分别代表整数、小数和科学计数的识别结束状态。
在一个程序设计语言中,一般都含有若干类单词符号,为此可首先为每类单词建立一张状态转换图,然后将这些状态转换图合并成一张统一的状态图,即得到了一个有限自动机,再进行必要的确定化和状态数最小化处理,最后据此构造词法分析程序。
四则运算算术符号的识别很简单,直接在状态图的0状态分别引出相应标记的矢线至一个新的终态即可。
根据自己的习惯,也可以将其转换为状态矩阵形式。
2、词法分析程序编写
根据描述语言中各类单词的文法状态转换图或状态矩阵,利用某种语言(C语言或JAVA语言)直接编写词法分析程序。
3、词法分析程序测试
用于测试扫描器的实例源文件中应有词法正确的,也应有错误的字符串,对于输入的测试用例的源程序文件,以对照的形式将扫描器的分析结果信息在输出文件中表示出来。
四、参考资料
实现无符号数识别的参考方法:
将设计的状态转换图直接转化为一张程序流程图,并在外层再增加一个以EOF为循环终止条件的while循环,即形成能连续识别各类单词的词法分析程序。
各类单词的编码建议如表1。
表1单词的内部编码
单词符号
类别码(CLASS)
单词值(VALUE)
无符号数
1
数字值
+
2
无值
-
3
无值
*
4
无值
/
5
无值
(
6
无值
)
7
无值
五、扩展实验
1、试对基础实验识别的单词种类进行扩充,构造识别以下单词的词法分析程序。
语言中具有的单词包括五个有代表性的关键字begin、end、if、then、else;标识符;整型常数;六种关系运算符;一个赋值符和四个算术运算符。
参考实现方法简述如下。
表2扩展单词分类码表
单词符号
类别编码
类别码的助记符
单词值
begin
1
BEGIN
end
2
END
if
3
IF
then
4
THEN
else
5
ELSE
标识符
6
ID
字母打头的字母数字串
整常数
7
INT
数字串
<
8
LT
<=
9
LE
=
10
EQ
<>
11
NE
>
12
GT
>=
13
GE
:
=
14
IS
+
15
PL
-
16
MI
*
17
MU
/
18
DI
处理过程:
在此为了使词法分析程序结构比较清晰,且尽量避免某些枝节问题的纠缠,假定要编译的语言中,全部关键字都是保留字,程序员不得将它们作为源程序中的标识符;在源程序的输入文本中,关键字、标识符、整常数之间,若未出现关系和算术运算符以及赋值符,则至少须用一个空白字符加以分隔。
作了这些限制以后,就可以把关键字和标识符的识别统一进行处理。
即每当开始识别一个单词时,若扫视到的第一个字符为字母,则把后续输入的字母或数字字符依次进行拼接,直至扫视到非字母、数字字符为止,以期获得一个尽可能长的字母数字字符串,然后以此字符串查所谓保留字表(此保留字表已事先造好),若查到此字符串,则取出相应的类别码;反之,则表明该字符串应为一标识符。
采用上述策略后,针对表2中部分单词可以构造一个如图2所示的有限自动机(以状态转换图表示)。
在图2中添加了当进行状态转移时,词法分析程序应执行的语义动作。
根据图2,可用C语言编写出符合以上几项要求的一个相应的扫描器程序,如程序一所示。
图2识别表I所列语言中的部分单词的DFA及相关函数
图2所出现的变量及函数的含义和功能说明如下:
函数GETCHAR:
每调用一次,就把扫描指示器当前所指示的源程序字符送入字符变量ch,然后把扫描指示器前推一个字符位置。
字符数组TOKEN:
用来依次存放一个单词词文中的各个字符。
函数CAT:
每调用一次,就把当前ch中的字符拼接于TOKEN中所存字符串的右边。
函数LOOKUP:
每调用一次,就以TOKEN中的字符串查保留字表,若查到,就将相应关键字的类别码赋给整型变量c;否则将c置为零。
函数RETRACT:
每调用一次,就把扫描指示器回退一个字符位置(即退回多读的那个字符)。
函数OUT:
一般仅在进入终态时调用此函数,调用的形式为OUT(c,VAL)。
其中,实参c为相应单词的类别码或其助记符;当所识别的单词为标识符和整数时,实参VAL为TOKEN(即词文分别为字母数字串和数字串),对于其余种类的单词,VAL均为空串。
函数OUT的功能是,在送出一个单词的内部表示之后,返回到调用该词法分析程序的那个程序。
参考程序:
#include
#include
#include
#defineID6
#defineINT7
#defineLT8
#defineLE9
#defineEQ10
#defineNE11
#defineGT12
#defineGE13
charTOKEN[20];
externintlookup(char*);
externvoidout(int,char*);
externreport_error(void);
voidscanner_example(FILE*fp)
{
charch;inti,c;
ch=fgetc(fp);
if(isalpha(ch))/*itmustbeaidentifer!
*/
{
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);/*retract*/
c=lookup(TOKEN);
if(c==0)out(ID,TOKEN);elseout(c,"");
}
else
if(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(INT,TOKEN);
}
else
switch(ch)
{
case′<′:
ch=fgetc(fp);
if(ch==′=′)out(LE,"");
elseif(ch==′>′)out(NE,"");
else
{
fseek(fp,-1,1);
out(LT,"");
}
break;
case′=′:
out(EQ,"");break;
case′>′:
ch=fgetc(fp);
if(ch==′=′)out(GE,"");
else
{
fseek(fp,-1,1);
out(GT,"");
}
break;
default:
report_error();break;
}
return;
}
提示:
扫描器所用的若干函数以及主程序有待于具体编写,并需事先建立好保留字表,以备查询。
例如:
/*建立保留字表*/
#defineMAX_KEY_NUMBER20/*关键字的数量*/
#defineKEY_WORD_END“waitingforyourexpanding”/*关键字结束标记*/
char*KeyWordTable[MAX_KEY_NUMBER]={“begin”,“end”,“if”,“then”,“else”,KEY_WORD_END};
/*查保留字表,判断是否为关键字*/
intlookup(char*token)
{
inti=0;
while(strcmp(KeyWordTable[n],KEY_WORD_END))/*strcmp比较两串是否相同,若相同返回0*/
{
if(!
strcmp(KeyWordTable[n],token))/*比较token所指向的关键字和保留字表中哪个关键字相符*/
{
returnn+1;/*设置正确的关键字类别码,并返回此类别码的值*/
break;
}
n++;
}
return0;/*单词不是关键字,而是标识符*/
}
另外,在扫描源程序字符串时,一旦识别出关键字、标识符、整常数以及运算符中之一,即以二元式形式(类别编码,值)输出单词到指定文件中。
每次调用词法分析程序,它均能自动继续扫描下去,形成下一个单词,直至整个源程序全部扫描完毕,并形成相应的单词串形式的源程序。
2、在词法分析过程中建立变量名表和常数表,以备以后的编译过程(如语法分析)查询;扩充关键字的数目、增加单词类别(如逻辑运算符等)、将常数分成字符串常量、整型常量和实型常量等;添加词法分析中单词出错的位置、错误类型检查,以及删除注释部分等。
3、可视化词法分析程序测试。
实验二语法分析程序实现
一、实验目的与要求
通过设计、编制、调试典型的SLR
(1)语法分析程序,实现对实验一所得词法分析程序所提供的单词序列进行语法检查和结构分析,进一步掌握常用的语法分析方法。
二、实验内容
选择对各种常见高级程序设计语言都较为通用的语法结构无符号数的算术四则运算作为分析对象,给出其文法描述(注意应与所采用的语法分析方法比较贴近),设计并实现一个完整的语法分析程序。
输入:
由实验一输出的单词类别串,如1,3,1。
输出:
对于所输入的源程序,如果输入符号串是给定文法定义的合法句子,则输出“RIGHT”,并且给出每一步归约的过程;如果不是句子,即输入串有错误,则输出“ERROR”,并且显示已经归约出的各个文法符号,以及必要的出错说明信息。
三、实现方法与环境
1、首先根据算术四则运算的语法定义,构造SLR
(1)分析表。
无符号数的算术四则运算的语法可表示为:
E->E+T|E-T|T
T->T*F|T/F|F
F->(E)|i
2、语法分析程序编写
设置输入缓冲区、状态栈、符号栈,并根据SLR
(1)分析表利用某种语言(C语言或JAVA语言)直接编写移进、归约、接受子程序,编写语法分析程序。
3、语法分析程序测试
用于测试的实例源文件中应有语法正确的,也应有语法错误的符号串,以对照的形式将分析结果信息在输出文件中表示出来。
四、扩展实验
1、对以下复合语句进行语法分析器的设计与实现。
G[<复合语句>]:
<复合语句>→begin<语句表>end
<语句表>→<语句>|<语句>;<语句表>
<语句>→<赋值语句>
<赋值语句>→<变量>:
=<算术表达式>
<算术表达式>→<项>|<算术表达式>+<项>|<算术表达式>-<项>
<项>→<因式>|<项>*<因式>|<项>/<因式>
<因式>→<变量>|<常数>|(<算术表达式>)
<变量>→<标识符>
<标识符>→<标识符><字母>|<标识符><数字>|<字母>
<常数>→<整数>|<浮点数>
<整数>→<数字>|<数字><整数>
<浮点数>→•<整数>|<整数>•<整数>
<字母>→A|B|C|…|X|Y|Z|a|b|c|…|x|y|z
<数字>→0|1|2|…|9
2、增强语法检查功能,对出错位置、错误类型给予提示。
3、可视化语法分析程序测试。
实验三语义分析程序实现
一、实验目的与要求
通过设计、编制、调试一个简单的语义处理分析程序,实现对实验一和实验二所得单词和语句的语义信息简单处里,进一步掌握语义处理的内容和简单方法。
二、实验内容
对实验一进行扩展,对识别的无符号数进行计值,并将输出形式改为(类别码,值)的二元式形式。
对实验二进行扩展,在语法分析的基础上,增加语义操作来实现语法制导翻译。
对于给定文法中的每一产生式,编写相应的语义子程序。
在语法分析过程中,每当用一产生式进行推导或归约时,语法分析程序除执行相应的语法分析动作之外,还要调用相应的语义子程序,计算并输出算术表达式的值。
将实验一与实验二的程序合并,以能对完整的输入源文件进行词法分析生成中间文件,然后进行语法制导翻译,输出最终翻译结果。
输入:
由无符号数和+,—,*,/,(,)构成的算术表达式。
输出:
如果输入单词串是合法的无符号数的算术四则运算,输出运算结果,并且给出每一步的分析过程;如果不是无符号数的算术四则运算,输出“非法四则运算表达式”。
三、基本实验题目
对实验一中每个无符号数识别状态插入计值处理,最终获得无符号数的取值。
对实验二进行扩展,在归约(分析表中的归约动作已经反应了运算优先级)处理子程序中加入计值处理,接受子程序中加入输出算数表达式值的处理。
四、参考资料
与无符号数状态转换图对应的包含语义处理过程(据此可计算求得无符号数的数字值)的状态矩阵和参考程序如下所示。
表3包含语义处理过程的识别无符号数的状态矩阵
根据加入语义过程说明的状态转换图直接编写词法分析程序,部分实现代码如下:
1#include
2#include
3#include
4#defineLETTER0
5#defineDIGIT1
6#definePOINT2
7#defineOTHER3
8#definePOWER4
9#definePLUS5
10#defineMINUS6
11#defineUCON7//Supposetheclassnumberofunsignedconstantis7
12#defineClassOther200
13#defineEndState-1
14intw,n,p,e,d;
15intClass;//Usedtoindicateclassoftheword
16intICON;
17floatFCON;
18staticintCurrentState;//Usedtopresentcurrentstate,theinitialvalue:
0
19
20intGetChar(void);
21intEXCUTE(int,int);
22intLEX(void);
23intHandleOtherWord(void)
24{returnClassOther;
25}
26intHandleError(void)
27{printf("Error!
\n");return0;}
28
29intGetChar(void)
30{
31intc;
32c=getchar();
33if(isdigit(c)){d=c-′0′;returnDIGIT;}
34if(c==′.′)returnPOINT;
35if(c==′E′||c==′e′)returnPOWER;
36if(c==′+′)returnPLUS;
37if(c==′-′)returnMINUS;
38returnOTHER;
39}
40intEXCUTE(intstate,intsymbol)
41{
42switch(state)
43{
44case0:
switch(symbol)
45{
46caseDIGIT:
n=0;p=0;e=1;w=d;CurrentState=1;Class=UCON;break;
47casePOINT:
w=0;n=0;p=0;e=1;CurrentState=3;Class=UCON;break;
48default:
HandleOtherWord();Class=ClassOther;
49CurrentState=EndState;
50}
51break;
52case1:
switch(symbol)
53{
54caseDIGIT:
w=w*10+d;break;//CurrentState=1
55casePOINT:
CurrentState=2;break;
56casePOWER:
CurrentState=4;break;
57default:
ICON=w;CurrentState=EndState;
58}
59break;
60case2:
switch(symbol)
61{
62caseDIGIT:
n++;w=w*10+d;break;
63casePOWER:
CurrentState=4;break;
64default:
FCON=w*pow(10,e*p-n);CurrentState=EndState;
65}
66break;
67case3:
switch(symbol)
68{
69caseDIGIT:
n++;w=w*10+d;CurrentState=2;break;
70default:
HandleError();CurrentState=EndState;
71}
72break;
73case4:
switch(symbol)
74{
75caseDIGIT:
p=p*10+d;CurrentState=6;break;
76caseMINUS:
e=-1;CurrentState=5;break;
77casePLUS:
CurrentState=5;break;
78default:
HandleError();CurrentState=EndState;
79}
80break;
81case5:
switch(symbol)
82{
83caseDIGIT:
p=p*10+d;CurrentState=6;break;
84default:
HandleError();CurrentState=EndState;
85}
86break;
87case6:
switch(symbol)
88{
89case:
DIGIT:
p=p*10+d;break;
90default:
FCON=w*pow(10,e*p-n);CurrentState=EndState;
91}
92break;
93}
94returnCurrentState;
95}
96intLEX(void)
97{
98intch;
99CurrentState=0;
100while(CurrentState!
=EndState)
101{
102ch=GetChar();
103EXCUTE(CurrentState,ch);
104}
105returnClass;
106}
五、扩展实验
1、对以下复合语句进行语法制导翻译程序的设计与实现。
G[<复合语句>]:
<复合语句>→begin<语句表>end
<语句表>→<语句>|<语句>;<语句表>
<语句>→<赋值语句>
<赋值语句>→<变量>:
=<算术表达式>
<算术表达式>→<项>|<算术表达式>+<项>|<算术表达式>-<项>
<项>→<因式>|<项>*<因式>|<项>/<因式>
<因式>→<变量>|<常数>|(<算术表达式>)
<变量>→<标识符>
<标识符>→<标识符><字母>|<标识符><数字>|<字母>
<常数>→<整数>|<浮点数>
<整数>→<数字>|<数字><整数>
<浮点数>→•<整数>|<整数>•<整数>
<字母>→A|B|C|…|X|Y|Z|a|b|c|…|x|y|z
<数字>→0|1|2|…|9
2、可视化语法制导翻译程序测试。
实验报告要求
要求每人针对每个实验上交一份实验报告,不接受不完整的实验报告,或者说明与程序或结果不符合的实验报告。
实验报告主要包括四方面内容:
1、实验设计
实验采用的文法,状态转换图或状态矩阵,程序流程设计和每部分的主要功能说明等。
2、程序代码
实验实现的源程序,要求符合代码行首缩进、单句代码换行、标识符命名合理,并包括必要的注释。
3、实验过程问题分析记录
记录实验过程中发生的编译错误并分析错误原因和解决的方法及结果,参考表3。
表3实验一中发生的编译错误记录表
编号
出错时间
出错代码
错误提示
出错原因分析
修改方法
修改结果
1
实验一第1课时
1#include
errorC2143:
syntaxerror:
missing';'before'constant'
“1”是示例程序