编译原理实验报告实验一编写词法分析程序Word文件下载.docx
《编译原理实验报告实验一编写词法分析程序Word文件下载.docx》由会员分享,可在线阅读,更多相关《编译原理实验报告实验一编写词法分析程序Word文件下载.docx(14页珍藏版)》请在冰豆网上搜索。
1、掌握从源程序文件中读取有效字符的方法和产生源程序的内部表示文件的方法。
2、掌握词法分析的实现方法。
3、上机调试编出的词法分析程序。
二、实验过程
以编写PASCAL子集的词法分析程序为例
1.理论部分
(1)主程序设计考虑
主程序的说明部分为各种表格和变量安排空间。
数组k为关键字表,每个数组元素存放一个关键字。
采用定长的方式,较短的关键字
后面补空格。
P数组存放分界符。
为了简单起见,分界符、算术运算符和关系运算符都放在p表中
(编程时,还应建立算术运算符表和关系运算符表,并且各有类号),合并成一类。
id和ci数组分别存放标识符和常数。
instring数组为输入源程序的单词缓存。
outtoken记录为输出内部表示缓存。
还有一些为造表填表设置的变量。
主程序开始后,先以人工方式输入关键字,造k表;
再输入分界符等造p表。
主程序的工作部分设计成便于调试的循环结构。
每个循环处理一个单词;
接收键盘上
送来的一个单词;
调用词法分析过程;
输出每个单词的内部码。
⑵词法分析过程考虑
将词法分析程序设计成独立一遍扫描源程序的结构。
其流程图见图1-1。
图1-1
该过程取名为lexical,它根据输入单词的第一个字符(有时还需读第二个字符),判断单词类,产生类号:
以字符k表示关键字;
i表示标识符;
c表示常数;
p表示分界符;
s表示运算符(编程时类号分别为1,2,3,4,5)。
对于标识符和常数,需分别与标识符表和常数表中已登记的元素相比较,如表中已有
该元素,则记录其在表中的位置,如未出现过,将标识符按顺序填入数组id中,将常数
变为二进制形式存入数组中ci中,并记录其在表中的位置。
lexical过程中嵌有两个小过程:
一个名为getchar,其功能为从instring中按顺序取出一个字符,并将其指针pint加1;
另一个名为error,当出现错误时,调用这个过程,
输出错误编号。
2.实践部分
所有识别出的单词都用两个字节的等长表示,称为内部码。
第一个字节为t,第二个字节为i。
t为单词的种类。
关键字的t=1;
分界符的t=2;
算术运算符的t=3;
关系运算符的t=4;
无符号数的t=5;
标识符的t=6。
i为该单词在各自表中的指针或内部码值。
表1-1为关键字表;
表1-2为分界符表;
表1-3为算术运算符的i值;
表1-4为关系运算符的i值。
关键字表
指针l
关键字
BEGIN
1
DO
2
ELSE
3
EN
4
IF
5
THEN
6
VAR
7
WHILE
表1-1
分界符表
分界符
,
;
。
:
=
(
)
"
表1-2
算术运算符
10H
+
11H
-
20H
*
21H
/
表1-3
关系运算符
00H
<
01H
02H
03H
>
04H
05H
表1-4
常数表和标识符表是在编译过程中建立起来的。
其i值是根据它们在源程序中出现的顺序确定的。
另外可以根据Pascal语言子集中出现其它单词情况进行自行修改以上表格。
最后编写程序进行词法分析,判断目标在哪个表中并进行显示。
三、实验结果
1.测试数据
数据共分为3组,分别如下:
第一组数据
vari,j,k:
integer;
begin
i:
=5;
j:
=6;
k:
=i+j;
write("
k="
k);
End.
第二组数据
vari,sum:
sum:
=0;
fori:
=1to10do
begin
=sum+i;
end;
writeln("
sum="
sum);
第三组数据
varweight,price:
real;
pleaseinputweight:
"
);
readln(weight);
ifweight<
10
then
price=5;
else
price=5+(weight-10)*0.4;
price="
price);
这三组数据都是通过文件“test.txt”读入到程序中,通过程序一一读取文件中的数据进行分析,程序分析时要注意所属的类型。
2.测试结果
以上三组数据测试结果通过控制台显示,显示时要根据表进行分类,不同的表有不同的标号,具体显示如图1-1,1-2,1-3,和1-4所示:
图1-2
图1-3
图1-4
图1-4(接图1-5)
四、讨论与分析
实验结果的每一条数据可分为两个部分。
第一个部分是识别出的单词部分,第二个部分(小括号内的部分)则显示了单词在表中的位置,括号内第一个数字表示是第几张表,第二个数字代表单词在表的位置。
实验结果与预期结果一致。
该实验证明了通过其他语言来编译一种语言的词法分析器是可行的。
实验结果说明了词法分析是作为相对独立的阶段来完成的。
在词法分析过程中,编译程序是通过操作系统从外部介质中读取源程序文件中的各个字符的。
同时,为正确地识别单词,有时还需进行超前搜索和回退字符等操作。
因此,为了提高读盘效率和便于扫描器进行工作,通常可采用缓冲输入的方案,即在内存中设置一个适当大小的输入缓冲区,让操作系统直接将磁盘上的源程序字符串分批送入此缓冲区中,供扫描器进行处理。
五、附录:
关键代码部分如下:
boolisKey(stringstr,int&
syn)/*判断是否为关键字,若是传回相应关键码的种别名*/
{
inti;
for(i=0;
i<
7;
i++)
if(str==key[i])
syn=i+1;
returntrue;
}
returnfalse;
boolisLetter(charc)//判断是否为字母,若是返回true,不是返回false
if((c>
='
A'
&
&
c<
Z'
)||(c>
a'
z'
))
else
boolisDigit(charc)//判断是否为数字,若是返回true,不是返回false
if(c>
0'
9'
voidanalyse(FILE*fileP)//分析函数对具体情形进行分析
intn;
charc;
stringstr="
;
intcount=0;
//标识变量
intcount1=0;
while((c=fgetc(fileP))!
=EOF)
if(c=='
'
||c=='
\n'
\t'
continue;
elseif(isDigit(c))//如果是数字
while(isDigit(c))//数字后还是数字
str+=c;
//数值连接
c=fgetc(fileP);
fseek(fileP,-1,SEEK_CUR);
for(inta=0;
a<
50;
a++){//数字没出现在数组中,在数组中加入
if(arr1[a]==str){
break;
}elseif(arr1[a]=="
){
arr1[count1]=str;
count1++;
break;
}
}
for(intb=0;
b<
b++){//数字的分析
if(arr1[b]==str){
cout<
str<
(5,"
<
b<
)"
endl;
str="
elseif(isLetter(c))//字母开头的
while(isDigit(c)||isLetter(c))//字母后还是字母
if(isKey(str,n))//如果是关键码
cout<
("
1<
"
n<
//关键码分析
else{
for(inti=0;
i<
i++){//标识符没出现在数组中,在数组中加入
if(arr[i]==str){
break;
}elseif(arr[i]=="
arr[count]=str;
count++;
}
}
for(intj=0;
j<
j++){//标识符分析
if(arr[j]==str)
cout<
(6,"
j<
}
else//操作符等字符,为表2,3,4中的
switch(c)
...
//列举出现在表2,3,4中的字符进行分析,此处略
intmain()//主函数
FILE*fileP;
fileP=fopen("
test.txt"
r"
//读文件
------词法分析如下------"
analyse(fileP);
//调用函数analyse
return0;
六、实验者自评
总的来说,实验过程还算顺利,遇到的一系列问题都得到比较好的解决,当然分析器还有很大的改进空间,这里只是简单的依照给定的图实现了PASCAL子集的词法分析。
虽说如此,但是最后能够完成还是感觉是不太容易的。
通过此次实验,让我了解到如何设计、编制并调试词法分析程序,加深对词法分析原理的理解;
熟悉了构造词法分析程序的手工方式的相关原理,根据识别语言单词的状态转换图,使用某种高级语言(例如C语言)直接编写此法分析程序。