电子科大编译原理实验报告得分70分文档格式.docx
《电子科大编译原理实验报告得分70分文档格式.docx》由会员分享,可在线阅读,更多相关《电子科大编译原理实验报告得分70分文档格式.docx(59页珍藏版)》请在冰豆网上搜索。
(二)词法分析的实现方法——利用状态转换
根据状态转化图,编写读到不同的内容时的状态转化函数,是设计词法分析器的核心。
(三)对“输入输出”文件的分析——文件相关操作
因为需要读写文件,并生成错误文件,涉及许多文件相关操作,通过相关函数函数实现功能:
5、实验器材(设备、元器件)
(一)操作系统:
Windows8Professional
(二)开发工具:
VisualStudio2015
(三)编程语言:
C
6、实验步骤:
(一)启动VisualStudio2015,新建一个项目LxicalAnalyzer
(二)编写LxicalAnalyzer.h文件,声明项目将要用到的自定义函数:
(三)编写LxicalAnalyzer.cpp文件,根据“状态转化图”、“单词符号与种别对照表”实现LxicalAnalyzer.h中声明的函数(详细代码附在实验报告最后);
(四)编写main.cpp文件,完成编码;
(五)根据给出的测试程序,编写输入文件test.pas
(六)运行写好的词法分析器程序,并结合输出文件test.err、test.dyd进行调试;
(七)完成实验。
7、实验数据及结果分析:
(一)输入文件test.pas
(二)执行词法分析器程序
(三)检查输出文件test.err
因为输入文件中测试程序没有错误,所以文件为空:
(四)检查输出文件test.dyd
检查可知,输出文件内容为符合实验要求的二元式:
(五)修改输入文件,在输入文件中添加错误
(六)再次执行词法分析器程序
(七)重新检查输出文件test.err
可见,本词法分析器成功实现检查多处词法错误:
8、实验结论、心得体会和改进建议:
(一)实验结论
通过编码与反复调试,成功完成了词法分析器的设计与实现,能够对给出文法的测试程序进行正确的词法分析,按要求输出二元式的*.dyd文件。
同时,也可以检测出所给源程序中的多处词法错误。
(二)心得体会
1.对于这种需要多次重复同一操作的实验,将相应的操作写成函数,可以方便编码,减少错误和代码行数。
2.第一次编码忽略了状态转化之后的回退工作,导致bug的出现,以后需要吸取经验教训。
3.尽量在第一次编写程序时,写出较多的提示信息和注释,便于发现bug后的调试。
(三)改进建议
上课使用的教材P134页“第六章词法分析”中的内容对本实验的完成有很大帮助,认真阅读后思路更加清晰。
*********为便于老师评阅报告,两次实验代码都添加底纹后放在在文档最后部分*********
实验二
递归下降分析器的设计与实现
根据给定的方法,编写相应的递归下降的语法分析程序,实现对词法分析后的单词序列的语法检查和程序结构的分析,生成相应的变量名表和过程名表,并将编译中语法检查出来的错误写入相应的文件。
语法错分类:
(1)缺少符号错;
(2)符号匹配错;
(3)符号无定义或重复定义。
通过设计递归下降分析器的设计与实现实验,使同学们掌握自上而下的递归分析法的语法分析原理和程序设计方法。
(一)语法分析的定义和功能
语法分析是根据语法规则,将单词符号构成各类语法单位,并进行语法检查。
在本实验中,对源程序经过词法分析后转换成的单词流按方法规则进行判断,对能构成正确句子的单词流,给出相应的语法树;
对不能构成正确句子的单词流判断其语法错误并做出相应处理。
(二)语法分析的方法
语法分析方法有自上而下和自下而上的分析方法。
(1)自上而下语法分析法:
或从开始符号出发,找最左推导;
或从根开始,构造推导树。
(2)自下而上语法分析法:
从输入串开始,归约,直至文法开始符。
本实验中,我们采用自上而下的递归下降分析法,在不含左递归的文法G中,如果对每一个非终结符的所有候选式的第一个终结符都是两两不相交的(即无公共左因子),则可能构造出一个不带回溯的自上而下的分析程序,这个分析程序由一组递归过程组成,每个过程对应文法的一个非终结符。
这样的分析程序称为递归下降分析程序。
(三)数据结构
1.*.dys同*.dyd
2.变量名表
·
变量名vname:
char(16)
所属过程vproc:
char(16)
分类vkind:
0..1(0—变量、1—形参)
变量类型vtype:
types
变量层次vlev:
int
变量在变量表中的位置vadr:
int(相对第一个变量而言)
3.过程名表
过程名pname:
过程类型ptype:
过程层次plev:
第一个变量在变量表中的位置fadr:
最后一个变量在变量表中的位置ladr:
4.四元式表
(oprd,op1,op2,result)
oprd——整数码
op1——第一操作数
op2——第二操作数
result——结果
op1、op2、result可用“值/地址”表示
5.目标代码——P码
(四)给定文法产生式
实验中给定文法如下:
<
程序>
→<
分程序>
→begin<
说明语句表>
;
执行语句表>
end
说明语句>
│<
;
变量说明>
函数说明>
→integer<
变量>
标识符>
字母>
│<
数字>
→a│b│c│d│e│f│g│h│i│j│k│l│m│n│o│p│q│r│s│t│u│v│w│x│y│z
→0│1│2│3│4│5│6│7│8│9
→integerfunction<
(<
参数>
);
函数体>
执行语句>
读语句>
写语句>
赋值语句>
条件语句>
→read(<
)
→write(<
:
=<
算术表达式>
-<
项>
*<
因子>
常数>
函数调用>
无符号整数>
→if<
条件表达式>
then<
else<
关系运算符>
→<
=│>
│>
=│=│<
>
(一)启动VisualStudio2015,新建一个项目GrammerAnalyzer;
(二)消除文法中的左递归;
(三)编写GrammerAnalyzer.h文件,定义将要用到的结构,并声明项目将要用到的自定义函数:
(四)编写GrammerAnalyzer.cpp文件,根据“文法产生式”实现LxicalAnalyzer.h中声明的函数和具体的递归下降分析法(详细代码附在实验报告最后);
(五)编写main.cpp文件,完成编码;
(五)将词法分析器的输出文件test.dyd作为实现的语法分析器的输入文件:
(六)运行写好的词法分析器程序,并结合输出文件test.dys、变量名表文件test.var、过程名表文件test.pro、错误文件等进行调试;
(一)输入文件test.dyd,内容为2元式子
(三)检查输出文件test.dys,与输入文件相同,正确:
(四)检查变量名表文件test.var,符合要求:
(五)检查过程名表文件test.pro,符合要求:
(六)检查过程名表文件test.err,基本符合要求:
(一)实验结论:
本实验程序较好地完成了递归下降分析器的设计与实现,能够对所给文法的程序进行语法分析,生成变量名表和过程名表,如果源程序有语法错误则给出出错类型及所在行数。
(二)心得体会:
1.标识符中不能包含关键字,以免出错;
2.要注意文法中公共左因子的消除;
3.思路要清晰,加一些提示信息,避免出现逻辑错误;
4.由于对Pascal语言语法细节不是特别熟悉,所以对错误的识别不一定准确,还有改正和提高的空间,期末考试过后有时间,可以做进一步的完善。
(三)改进建议:
可以改成对C语言等我们经常接触到的语言作为本次实验的源语言,实验做起来可能会更有趣。
************************以下为实验一源代码,共三个文件************************
(一)LexicalAnalyzer.h
#pragmaonce
#ifndefLEXICALANALYZER_H
#defineLEXICALANALYZER_H
chargetNextC();
//获取下一个字符
boollexAnalyzer();
//用于词法分析的函数
boolisLetter(charch);
//判断ch是否为字母
boolisDigit(charch);
//判断ch是否为数字
voidretract(char&
ch);
//回退字符
intreserve(char*token);
//返回保留字对应种别
intsymbol();
//返回标识符的对应种别
intconstant();
//返回常数的对应种别
voidoutput_token(constchar*token,intkindNum);
//按要求格式输出单词符号和种别
boolprintError(intlineNum,interrNum);
//按要求打印错误提醒
voidgetPath(char*in,char*out);
//获得路径
voidgetFilename(char*in,char*out);
//获得文件名
boolinit(intargc,char*argv[]);
//初始化函数
#endif//!
LEXICALANALYZER_H
(二)LexicalAnalyzer.cpp
#include"
LexicalAnalyzer.h"
#include<
string>
#defineMAX_COUNT1024
#defineILLEGAL_CHAR_ERROR1
#defineUNKNOWN_OPERATOR_ERROR2
FILE*file;
boollexAnalyzer(){//用于词法分析的函数
if(feof(file)){
returnfalse;
}
staticintlineNum=1;
charch;
chartoken[17]="
"
;
ch=getNextC();
switch(ch)
{
case'
\r'
\n'
//每行后加一EOLN24
output_token("
EOLN"
24);
lineNum++;
break;
caseEOF:
//结尾加EOF25
EOF"
25);
a'
b'
c'
d'
e'
f'
g'
h'
i'
j'
k'
l'
m'
n'
o'
p'
q'
r'
s'
t'
u'
v'
w'
x'
y'
z'
A'
B'
C'
D'
E'
F'
G'
H'
I'
J'
K'
L'
M'
N'
O'
P'
Q'
R'
S'
T'
U'
V'
W'
X'
Y'
Z'
while(isLetter(ch)||isDigit(ch))
chars[2]={ch};
strcat(token,s);
ch=getchar();
retract(ch);
intnum;
num=reserve(token);
if(num!
=0)
output_token(token,num);
else
intval;
val=symbol();
//标识符
output_token(token,val);
0'
1'
2'
3'
4'
5'
6'
7'
8'
9'
while(isDigit(ch))
val=constant();
='
="
12);
'
if(ch=='
13);
elseif(ch=='
14);
15);
16);
17);
-'
-"
18);
*'
*"
19);
20);
printError(lineNum,2);
//输出“未知运算符”错误
('
("
21);
)'
)"
22);
23);
default:
printError(lineNum,1);
//输出"
出现字母表以外的非法字符"
错误
returntrue;
}
boolisLetter(charch){//判断ch是否为字母
if((ch>
='
&
ch<
)||(ch>
&
ch<
))
boolisDigit(charch){//判断ch是否为数字
)&
(ch<
ch){//回退字符
ungetc(ch,stdin);
ch=NULL;
intreserve(char*token){//返回保留字对应种别
if(strcmp(token,"
begin"
)==0)
return1;
elseif(strcmp(token,"
end"
return2;
integer"
return3;
if"
return4;
then"
return5;
else"
return6;
function"
return7;
read"
return8;
write"
return9;
return0;
intsymbol(){//返回标识符对应种别
return10;
intconstant(){//返回保常数对应种别
return11;
voidoutput_token(constchar*token,intkindNum){//按要求输出二元式
printf("
%16s%2d\n"
token,kindNum);
boolprintError(intlineNum,interrNum){//按要求输出错误
char*errInfo;
switch(errNum)
caseILLEGAL_CHAR_ERROR:
errInfo="
caseUNKNOWN_OPERATOR_ERROR:
出现未知运算符(“:
”后无“=”)"
未知错误"
if(fprintf(stderr,"
***LINE:
%d%s\n"
lineNum,errInfo)>
chargetNextC(){//获取下一个字符
while(true)
||ch=='
\t'
'
){//
}
returnch;
voidgetPath(char*in,char*out)//获得路径
{
char*name;
name=strrchr(in,'
\\'
);
if(name!
=NULL)
strncpy(out,in,strlen(in)-strlen(name)+1);
strcpy(out,"
voidgetFilename(char*in,char*out)//获得文件名
{
char*fullName;
char*extension;
fullName=strrchr(in,'
extension=strrchr(in,'
.'
if(fullName!
strncpy(out,fullName+1,strlen(fullName)-1-strlen(extension));
strncpy(out,in,strlen(in)-strlen(extension));
boolinit(intargc,char*argv[])//初始化函数
if(0)