编译原理实验指导书Word格式.docx
《编译原理实验指导书Word格式.docx》由会员分享,可在线阅读,更多相关《编译原理实验指导书Word格式.docx(46页珍藏版)》请在冰豆网上搜索。
每调用此函数一次,从当前待编译文件中识别出一单词,并给出其类型和值。
关于PL/0的说明参见<
<
编译原理>
>
第二章(清华大学吕映芝编)。
2、生成一工程文件,调用1中生成的函数Getsym(),对一指定的文件进行词法分析,要求分析出单词的类型和值,对于词法错误之处,要给出错误所在位置。
并将分析结果存入一文件Mydata.dat中。
3、实验前请仔细阅读实验预习提示,提示中程序仅供参考。
4、本实验建议上机时间4-6学时。
(3)实验预习提示
1、词法分析器的功能和输出格式
词法分析器的功能是输入源程序,输出单词符号。
词法分析器的单词符号常常表示成以下的二元式(单词种别码,单词符号的属性值)。
本实验中,采用的是一符一种别码的方式。
2、单词的EBNF(扩展巴科斯范式)表示
下面是对PL/0进行词法分析所用到的部份EBNF。
标识符>
:
=<
字母>
{<
|<
数字>
下划线>
}
无符号整数>
加法运算符>
=+
减法运算符>
=-
.
大于关系运算符>
=>
大于等于关系运算符>
=
3、“超前搜索”方法
词法分析时,常常会用到超前搜索方法。
如当前待分析字符串为“a>
+”,当前字符为’>
’,此时,分析器到底是将其分析为大于关系运算符还是大于等于关系运算符呢?
显然,只有知道下一个字符是什么才能下结论。
于是分析器读入下一个字符’+’,这时可知应将’>
’解释为大于运算符。
但此时,超前读了一个字符’+’,所以要回退一个字符,词法分析器才能正常运行。
在分析标识符,无符号整数等时也有类似情况。
4、工程文件结构
由于在以后的实验中,还会用到本次实验的结果。
为提高代码的复用性,必须采用模块化设计的方法。
本例中,用到了自编的四个文件,即Basedata.h,Symbol.h,Symbol.c,Testsym.c。
其中,两个.h头文件中存放的是一些宏定义和自定义数据类型,Symbol.h中还存放有词法分析器要用到的一些自定义函数的声明。
在Symbol.c中存放的是对这些函数的定义部份。
Testsym.c中存放的是主函数部份,在此处调用词法分析器对待分析PL/0文件进行分析。
现建一工程文件,名为test.prj,将文件Basedata.h,Symbol.h,Symbol.c,Testsym.c加入工程文件中,编译链接后生成可执行文件Test.exe,运行之即可对指定的源文件进行词法分析。
5、参考源程序
[1]Basedata.h
#ifndef_BASETYPE_H
#define_BASETYPE_H
#defineFALSE0
#defineTRUE1
#defineSPACE0x20
#defineBACKSPACE0x08
#defineENTER0x0d
#defineESC0x1b
#defineTABLE0x09
#defineENDFILE-1
#endif
[2]Symbol.h
#ifndef_SYMBOL_H
#define_SYMBOL_H
#include<
stdio.h>
stdlib.h>
#defineWORDLEN13//保留字个数
#defineMAXIDLEN50//标识符最长长度
#defineSYMBOLNUM32//种别码个数
typedefenumSYMBOL
{NOL,IDENT,NUMBER,PLUS,MINUS,TIMES,SLASH,
ODDSYM,EQL,NEQ,LSS,LEQ,GTR,GEQ,LPAREN,
RPAREN,COMMA,SEMICOLON,PERIOD,BECOMES,
BEGINSYM,ENDSYM,IFSYM,THENSYM,WHILESYM,
WRITESYM,READSYM,DOSYM,CALLSYM,CONSTSYM,
VARSYM,PROCSYM}SYMBOL;
//定义种别码
voidGetchar(void);
//取下一个字符
voidGetbc(void);
//如当前字符为白字符,则读字符至不为白字符时停止
voidConcat(void);
//将当前字符加入token字
voidRetract(void);
//回退一字符
intReserve(void);
//判断token字中单词是否是保留字
intGetsym(void);
//从当前文件中识别出一单词,并给出其类型和值
voidErrorsym(void);
//打印错误信息
[3]Symbol.c
#include"
basedata.h"
symbol.h"
conio.h>
string.h>
ctype.h>
char*WORD[WORDLEN]={"
BEGIN"
"
CALL"
CONST"
DO"
"
END"
IF"
ODD"
PROCEDURE"
READ"
THEN"
VAR"
WHILE"
WRITE"
};
//保留字字符串表,用于将保留字种别码转为字符串输出
SYMBOLWSYM[WORDLEN]={BEGINSYM,CALLSYM,CONSTSYM,
DOSYM,ENDSYM,IFSYM,ODDSYM,
PROCSYM,READSYM,THENSYM,
VARSYM,WHILESYM,WRITESYM};
//保留字种别码表
char*SNAME[SYMBOLNUM]=
{"
NOL"
IDENT"
NUMBER"
PLUS"
MINUS"
TIMES"
"
SLASH"
ODDSYM"
EQL"
NEQ"
LSS"
LEQ"
GTR"
GEQ"
LPAREN"
RPAREN"
COMMA"
SEMICOLON"
PERIOD"
BECOMES"
BEGINSYM"
ENDSYM"
IFSYM"
THENSYM"
WHILESYM"
WRITESYM"
READSYM"
DOSYM"
CALLSYM"
CONSTSYM"
VARSYM"
PROCSYM"
};
//单词字符串表,用于将保留字种别码转为字符串输出
SYMBOLsym;
//最近已识的单词种别码
chartoken[MAXIDLEN+1];
//最近已识别的单词
intnum;
//最近已识别的数字值
charch;
//最近已识别的字符
intcol=1,row=1;
//当前行和列值
FILE*fd;
//指向待编译文件
externFILE*fout;
//指向存放结果文件
voidGetchar(void)
{
ch=fgetc(fd);
if(ch!
=EOF&
&
ch!
='
\n'
)
col++;
return;
voidGetbc(void)
while(ch==SPACE||ch==TABLE||ch=='
{
if(ch=='
){row++;
col=1;
Getchar();
}//为空字符则一直读至不为空字符
voidRetract(void)
fseek(fd,-1l,SEEK_CUR);
col--;
voidConcat(void)
chartemp[2];
temp[0]=ch;
temp[1]='
\0'
;
strcat(token,temp);
intReserve(void)
inti,j;
chartemp[60];
j=strlen(token);
for(i=0;
i<
j;
i++)
temp[i]=toupper(token[i]);
//将当前token字以大写形式存入temp中
}
temp[i]='
WORDLEN;
if(!
strcmp(WORD[i],temp))
break;
}//判断当前token是否是保留字
if(i>
=WORDLEN)i=-1;
returni;
voidErrorsym(void)
fprintf(fout,
Thereiserror@row:
%5d,@col:
%5d"
row,col);
intGetsym(void)
intk;
intflag=TRUE;
Getbc();
//滤掉白字符
strcpy(token,"
"
);
if(isalpha(ch))
//以字母开头则是标识符
num=0;
Concat();
while(isalnum(ch))
{
Concat();
Getchar();
}
Retract();
//由于超前搜索了,所以回退一个字符
k=Reserve();
//判断此标识符是否是保留字
if(k!
=-1)
sym=WSYM[k];
//将保留字种别码存入sym中
else
sym=IDENT;
//将一般标识符种别码存入sym中
}//endelsek!
=-1;
}//endofifisalpha
elseif(isdigit(ch))
//以数字开头则为无符号整数
while(isdigit(ch))
flag=FALSE;
while(isalnum(ch))
}//endofflag=FALSE
//回退
if(flag)//若是无符号整数,则将整数值存于num中
{sym=NUMBER;
num=atoi(token);
}//endofifisdigit
switch(ch)
case'
+'
Concat();
sym=PLUS;
break;
-'
sym=MINUS;
*'
sym=TIMES;
/'
sym=SLASH;
('
sym=LPAREN;
)'
sym=RPAREN;
sym=EQL;
#'
sym=NEQ;
/*
ODDSYM,EQL,NEQ,LSS,LEQ,GTR,GEQ,LPAREN,
RPAREN,COMMA,SEMICOLON,PERIOD,BECOMES,
*/
'
sym=COMMA;
.'
sym=PERIOD;
'
sym=SEMICOLON;
Concat();
Getchar();
if(ch!
)//若后不跟'
则回退
{sym=GTR;
Retract();
else
{Concat();
sym=GEQ;
break;
{sym=LSS;
sym=LEQ;
{flag=FALSE;
sym=BECOMES;
default:
flag=FALSE;
}//endofswitchelsechar
}//endofelsechar
returnflag;
[4]Testsym.c
externchar*WORD[WORDLEN];
externintWSYM[WORDLEN];
externchar*SNAME[SYMBOLNUM];
externSYMBOLsym;
//lastreadedwordtype;
externchartoken[MAXIDLEN+1];
//lastreadedword
externintnum;
//lastreadednum;
externcharch;
//lastreadedchar;
externintcol,row;
externFILE*fd;
FILE*fout;
voidInit(void);
voidQuit(void);
voidmain()
intflag;
Init();
fprintf(fout,"
\nTOKENSYMNUM"
do{
flag=Getsym();
if(flag)
\n%10s%10s%d"
token,SNAME[sym],num);
elseif(ch!
=EOF)
\n%10s"
token);
Errorsym();
}while(ch!
=EOF);
//反复调用Getsym()识别单词,将输出结果存入fout中
Quit();
//======================================
voidInit(void)
chartemp[30];
printf("
\nPleaseinputyourfilename:
gets(temp);
if((fd=fopen(temp,"
rt"
))
==NULL)
fprintf(stderr,"
Cannotopeninputfile%s.\n"
temp);
getch();
return;
}//将fd指针指向待分析源文件
if((fout=fopen("
mydata.dat"
"
wt"
Cannotopeninputfile.\n"
}//将fout指向文件mydata.dat
voidQuit(void)
fclose(fd);
fclose(fout);
实验二 熟悉FLEX使用方法
(1)实验目的
1、掌握FLEX基本使用方法
2、掌握如何将通过FLEX生成的C语言模块加入到自已的程序中
(2)实验要求
1、编制FLEX源程序,分别统计文本文件a.txt中出现的标识符和整数个数,并显示之。
标识符定义为字母开头,后跟若干个字母,数字或下划线。
整数可以带+或-号,也可不带,且不以0开头。
非单词和非整数则忽略不记,将之滤掉不显示。
2、编制一FLEX源程序,分别求出文件hh.c中字母,数字,回车符的个数。
3、思考:
若main函数不在FLEX中实现,应该如何实现?
4、本次实验建议学时2学时。
参见附录一。
在看懂的基础上将之调试通过。
实验三 用FLEX自动生成PL/0词法分析器
熟练掌握FLEX,并通过其生成一个词法分析器
1、通过FLEX生成一词法分析器函数intGetsym(),其功能同实验一中词法分析器函数类似。
2、生成一工程文件,调用1中生成的函数Getsym(),对一指定的文件进行词法分析,要求分析出单词的类型和值。
3、本实验建议学时4学时。
1、FLEX可自动生成函数intyylex(),则intGetsym()可通过调用yylex()实现。
2、由于FLEX生成的C程序模块lex.yy.c过于复杂,基本不可读,所以不要直接修改它,可将它看成一个“黑箱”,即不需要清楚知道其内部结构,只需要知道其接口即可。
可通过修改FLEX源程序间接修改之。
关于lex.yy.c中常用变量和函数,在附录中有详细说明。
3、编制一FLEX源程序,不妨取名为sym.l,通过FLEX生成lex.yy.c,并将之加入到工程文件中。
生成一工程文件,不妨取名为test.prj,将文件Symbol.c,lex.yy.c,testsym.c加入之。
源程序参考如下:
同实验一中Basedata.h
#defineWORDLEN13/*保留字个数*/
#defineMAXIDLEN50/*标识符最长长度*/
#defineSYMBOLNUM32/*种别码个数*/
{NOL,IDENT,NUMBER,PLUS,MINUS,TIMES,SLASH,
BEGINSYM,ENDSYM,IFSYM,THENSYM,WHILESYM,
WRITESYM,READSYM,DOSYM,CALLSYM,CONSTSYM,
VARSYM,PROCSYM}SYMBOL;
/*定义种别码*/
/*判断token字中单词是否是保留字*/
/*从当前文件中识别出一单词,并给出其类型和值*/
voidMyError(void);
/*打印错误信息*/
[3]symbol.c
Basedata.h"
Symbol.h"
char*WORD[WOR