试验一手工编写简单词法分析程序.docx
《试验一手工编写简单词法分析程序.docx》由会员分享,可在线阅读,更多相关《试验一手工编写简单词法分析程序.docx(16页珍藏版)》请在冰豆网上搜索。
试验一手工编写简单词法分析程序
编译原理
实验报告
日期:
班级:
题目组员:
1实验目的及要求
1.通过设计、编写、调试一个具体的词法分析程序,加深对词法分析原理的理解。
2.掌握在对程序设计语言源程序进行扫描的过程中,将其分解为各类单词的词法分析方法。
2实验平台
Windows+VC+Win32Console
3实验步骤
1.查询资料,了解词法分析器的工作过程与原理。
2.分析题目,整理出基本设计思路。
3.实践编码,将设计思想转换用c语言编码实现,编译运行。
4.测试功能,多次设置包含不同字符,关键字的待解析文件,仔细察看运行结果,检测该分
析器的分析结果是否正确。
通过最终的测试发现问题,逐渐完善代码中设置的分析对象与关键字表,拓宽分析范围提高分析能力。
4实验内容
4.1实现下述功能,并将分析结果保存在文件中•(既可以参考范例程序,也可
以独立完成)
程序输入/输出示例:
输入一段C语言程序,识别出各个具有独立意义的单词,即基本保留字、
标识符、常数、运算符、界符。
(遇到错误时可显示“Error”,然后跳
过错误部分继续显示)
输入源程序示例:
main()
{
inta,b=10;
intc;
c=a+b*20;
}
保留字表2
输出固定表格如下
单词类别表
单词类型
单词种别
标识符
1
保留字
2
常量
3
运算符
4
分界符
5
运算符表4
算符
地址指针
+
1
一
2
*
3
/
4
=
5
…
…
保留字
地址指针
int
1
float
2
main分界符表35
printf
界符
4
地址指针
丿匕」11.J1—1V1
d
j
2
(
3
)
4
{
5
…
…
输出动态表格如下
标识符表1
常量表3
标识符
地址指针
a
1
b
2
c
3
常量
地址指针
10
1
20
2
符号表
单词名称
类别
地址指针
int
2
1
c
1
3
J
5
2
c
1
3
=
4
5
a
1
1
单词名称
类别
地址指针
+
4
1
int
2
1
b
1
2
c
1
3
*
4
3
J
5
2
20
3
2
c
1
3
J
5
2
=
4
5
a
1
1
+
4
1
b
1
2
*
4
3
20
3
2
J
5
2
}
5
6
4.2程序:
#include
#include
#include
#include
//定义关键字
char*Key[10]={"main","void","int","char","printf',"scanf',"else","if","return"};
charWord[20],ch;//存储识别出的单词流intIsAlpha(charc){//判断是否为字母
if(((c<='z')&&(c>='a'))||((c<='Z')&&(c>='A')))return1;
elsereturn0;
}
//判断是否为数字
intIsNum(charc){if(c>='0'&&c<='9')return1;elsereturn0;
}
intIsKey(char*Word){//识别关键字函数intm,i;
for(i=0;i<9;i++){
if((m=strcmp(Word,Key[i]))==0)
{
if(i==0)
return2;
elsereturn1;
}
return0;
}
voidscanner(FILE*fp){
//扫描函数
charWord[20]={'\0'};
charch;
inti,c;
ch=fgetc(fp);
//获取字符,指针fp并自动指向下一个字符
if(IsAlpha(ch)){
//判断该字符是否是字母
Word[0]=ch;
ch=fgetc(fp);
i=1;
while(IsNum(ch)||IsAlpha(ch)){//判断该字符是否是字母或数字
Word[i]=ch;
i++;
ch=fgetc(fp);
}
Word[i]='\0';
//'\0'代表字符结束(空格)
fseek(fp,-1,1);
//回退一个字符
c=IsKey(Word);
//判断是否是关键字
if(c==0)printf("\t\t
111\n\t\t—K%s\t\t11\t|1\t\t
|\n",Word);〃不是关键字
elseif(c==2)
printf("\t\t|11\n\t\tdI%s\t\t|2\t|3\t\t|
\n",Word);
else
printf("\t\t|11\t\td|%s\t\t|3\t|1\t\t|
\n",Word);//输出关键字
}
else
//开始判断的字符不是字母
while(IsNum(ch)){
Word[i]=ch;
i++;
ch=fgetc(fp);
\n",Word);
else
7\t\t
9\t\t
3\t\t
5\t\t
Word[i]='\0';
fseek(fp,-1,1);
printf("\t\t
//回退
H%s\t\t|3\t|1\t\t
//开始判断的字符不是字母也不是数字
Word[0]=ch;
switch(ch){
case'[':
printf("\t\t
\n",Word);break;
case']':
printf("\t\t
\n",Word);break;
case'(':
printf("\t\t
\n",Word);break;
case'{':
printf("\t\t
\n",Word);break;
An\t\tH%s\t\t|5\t
An\t\tH%s\t\t|5\t
An\t\tH%s\t\t|5\t
\\H%s\t\t|5\t
case'}':
printf("\t\t
5\t|
6\t\t|\n".Word);break;
case'+':
ch=fgetc(fp);
Word[1]=ch;
if(ch=='='){
printf("\t\t|11———|%s\t\t|
4\t|6\t\t|\n",Word);〃运算符"+="
else{
fseek(fp,-1,1);
printf("\t\t|11—\td|%s\t\t|
4\t1\t\t\n",Word);//判断结果为"+"
}
break;
case'-':
ch=fgetc(fp);
Word[1]=ch;
if(ch=='='){
printf("\t\t
4\t|6\t\t|\n",Word);}
elseif(ch=='-'){
AMt\HI%s\t\t|
printf("\t\t(
4\t16\t\t|\n",Word);//判断结果为"--"
}
else{
fseek(fp,-1,1);
printf("\t\t|11\nM\td|%s\t\t|
4\t2\t\t\n",Word);//判断结果为"-"
}
break;
\t\「I%s\t\t|4\t
case'*':
printf("\t\t
3\t\t\n",Word);break;
case'!
':
case'=':
ch=fgetc(fp);
if(ch=='='){
printf("\t\t|111\n\t\t
|%s\t\t|4\t|6\t\t|\n".Word);
}
else{
fseek(fp,-1,1);
printf("\t\t|11\nM\td|%s\t\t|
4\t5\t\t\n",Word);
}
break;
case'<':
ch=fgetc(fp);
Word[1]=ch;
if(ch=='='){
printf("\t\t|111\n\t\t
%s\t\t4\t6\t\t\n",Word);//判断结果为运算符"<="
}
elseif(ch=='<'){
}
fseek(fp,-1,1);
4\t16\t\t|\n",Word);//判断结果为"<"
}
break;
case'>':
ch=fgetc(fp);
Word[1]=ch;
if(ch=='=')printf("\t\t|11
\n\t\t|%s\t\t|4\t|6\t\t|\n",Word);
else{
fseek(fp,-1,1);
printf("\t\t|111\n\t\t
%s\t\t4\t6\t\t\n",Word);
}
break;
case'%':
ch=fgetc(fp);
Word[1]=ch;
if(ch=='='){printf("\t\t|11
\n\t\t%s\t\t4\t6\t\t\n",Word);}
AnM\t―|无法识别字
并返回文件指针,该指
fseek(fp,-1,1);
取余运算符\tI\t\n",Word);
}
break;
default:
printf("\t\t|1一
符!
\t\t\t\t|\n");break;
}
}
}
main()
{
charin_fn[30];//文件路径
FILE*fp;
printf("\n请输入源文件名(包括路径和后缀名):
");
while(true){
gets(in_fn);
//scanf("%s",in_fn);
if((fp=fopen(in_fn,"r"))!
=NULL)break;//读取文件内容,
针指向文件的第一个字符
elseprintf("文件路径错误!
请重新输入:
");
printf("\t\t|
1\nt\^
TI标识符
\t1
\t\n",Word);
printf("\t\t|
1\nt\^
T丨保留子
\t2
\t\n",Word);
printf("\t\t|
1\nt\^
T常量
\t3
\t\n",Word);
printf("\t\t|
1\nt\^
T运算符
\t4
\t\n",Word);
printf("\t\t|
1\nt\^
T分界符
\t5
\t\n",Word);
printf("\t\t11rd);
printf("\t\ti
1\nt\^
|保留字
\t地址指针\t\n",Word);
printf("\t\t|
1\nt\^
Tint
\t
1
\t
\n",Word);
printf("\t\t|
1\nt\^
Tfloat
\t
2
\t
\n",Word);
printf("\t\t|
1\nt\^
Tmain
\
3
\t\n",Word)
printf("\t\t|
1\nt\^
Tprintf
\t
4
\t
\n",Word);
printf("\t\t1
1rd);
****************************
****************************
printf("\t\ti
1\n\t\b-
1算符
\t|地址指针\t
\n",Word);
r\rin+f/"\4-\4-
XnXMJ.
1I+
\t|1
\t
\n",Word);
print”\t\t|
n\n\t\t
TI+
r\rin+f/"\4-\4-
XnXMJ.
i|
\t|2
\t
\n",Word);
print”\t\t|
n\n\t\t
T|—
printf("\t\t|
1\n\t\\
T*
\t|3
\t
\n",Word);
printf("\t\t|
1\—HI/
\t4
\t
\n",Word);
r\rin+f/"\4-\4-
\n\+\+—
\t5
\t
\n",Word);
printT(\t\tr
n\n\t\tnI=
printf("\t\t|
1\—HI其他
\t6
\t
\n",Word);
printf("\t\t1
1rd);
printf("\n****************************
分界符表******************************\n");
printf("\t\ti11\n\t\t―b单词名称\tI类别\tI地址指针\t
\n",Word);
do{
else{
fseek(fp,-1,1);//回退一个字节开始识别单词流scanner(fp);
}
}while(ch!
='#');
printf("\t\t111);
return(0);
}
5实验结果
5.1解析源文件:
main()
{
inta,b=10;
intc;
c=a+b*20;
}
5.2解析结果:
I'D:
Vxiaobin\Debjg\1l.exe'1=1亘_
6实验总结分析
在本次实验,使我们再次浏览了有关c语言的一些基本知识,特别是对文件,字符串
进行基本操作的方法。
C语言中没有string类型,因此本实验中的对字符串提取与识别均借助#include及字符型数组来实现。
让我们练习对字符串函数应用的同时也提高了自己的逻辑思维能力。
在本次实验中,我纠正了一个一直以来的概念错误:
main不是关键字,它定义为程序的入口,是主函数!
在本实验中,虽然我把main初始化在关键字表(字符指针类型数组)*Key[10]中,当与该数组中字符串进行比较时,若与main匹配成功,则返回2,若为其他关键字则返回1,以此来把main从关键字中区别出来。
在本实验中的关键字表只初始化了几个常用的关键字,还可继续扩充(只需扩大数组,向其中补充要添加的关键字)。
如果要对本程序中未识别的c语言中的一些其他的字符进行扩充(目前处理为不可识别字符),可在程序代码中继续添加case选项,分别对相应要识别的特殊字符加以描述。
程序中,我们利用特殊符号构造表格,使画面美观,易于观察。