编译原理实验报告Word文档格式.docx
《编译原理实验报告Word文档格式.docx》由会员分享,可在线阅读,更多相关《编译原理实验报告Word文档格式.docx(50页珍藏版)》请在冰豆网上搜索。
2、语法分析程序设计与实现
选择对各种常见高级程序设计语言都较为通用的语法结构——算术表达式的一个简化子集——作为分析对象,根据如下描述其语法结构的BNF定义G2[<
算术表达式>
],任选一种学过的语法分析方法,针对运算对象为无符号常数和变量的四则运算,设计并实现一个语法分析程序。
G2[<
]:
<
→<
项>
|<
+<
-<
因式>
*<
/<
运算对象>
|(<
)
若将语法范畴<
、<
和<
分别用E、T、F和i代表,则G2可写成:
G2[E]:
E→T|E+T|E-TT→F|T*F|T/FF→i|(E)
由实验一输出的单词串,例如:
UCON,PL,UCON,MU,ID·
·
若输入源程序中的符号串是给定文法的句子,则输出“RIGHT”,并且给出每一步分析过程;
若不是句子,即输入串有错误,则输出“ERROR”,并且显示分析至此所得的中间结果,如分析栈、符号栈中的信息等,以及必要的出错说明信息。
对文法G2[<
]中的产生式添加语义处理子程序,完成运算对象是简单变量(标识符)和无符号数的四则运算的计值处理,将输入的四则运算转换为四元式形式的中间代码。
包含测试用例(由标识符、无符号数和+、−、*、/、(、)构成的算术表达式)的源程序文件。
将源程序转换为中间代码形式表示,并将中间代码序列输出到文件中。
若源程序中有错误,应指出错误信息
二、设计思路
1)单词分类
为了编程的实现。
我们假定要编译的语言中,全部关键字都是保留字,程序员不得将它们作为源程序中的标识符;
作了这些限制以后,就可以把关键字和标识符的识别统一进行处理。
即每当开始识别一个单词时,若扫视到的第一个字符为字母,则把后续输入的字母或数字字符依次进行拼接,直至扫视到非字母、数字字符为止,以期获得一个尽可能长的字母数字字符串,然后以此字符串查所谓保留字表(此保留字表要事先造好),若查到此字符串,则取出相应的类别码;
反之,则表明该字符串应为一标识符。
表1语言中的各类单词符号及其分类码表
单词符号
类别编码
类别码的助记符
单词值
begin
1
BEGIN
end
2
END
if
3
IF
then
4
THEN
else
5
ELSE
标识符
6
ID
字母打头的字母数字串
无符号常数
7
UCON
机内二进制表示
8
LT
=
9
LE
10
EQ
>
11
NE
12
GT
13
GE
:
14
IS
+
15
PL
-
16
MI
*
17
MU
/
18
DI
2)词法分析器的设计
函数GETCHAR:
每调用一次,就把扫描指示器当前所指示的源程序字符送入字符变量ch,然后把扫描指示器前推一个字符位置。
字符数组TOKEN:
用来依次存放一个单词词文中的各个字符。
函数CAT:
每调用一次,就把当前ch中的字符拼接于TOKEN中所存字符串的右边。
函数LOOKUP:
每调用一次,就以TOKEN中的字符串查保留字表,若查到,就将相应关键字的类别码赋给整型变量c;
否则将c置为零。
函数RETRACT:
每调用一次,就把扫描指示器回退一个字符位置(即退回多读的那个字符)。
函数OUT:
一般仅在进入终态时调用此函数,调用的形式为OUT(c,VAL)。
图1识别表I所列语言中的部分单词的DFA及相关的语义过程
3)词法分析程序的实现
编写的扫描器:
charTOKEN[20],TOKEND[20],TOKENDO[20];
intlookup(char*);
voidout(int,char*);
voidreport_error(void);
//externvoidLEX(void);
intsiagn=0;
//标志位
FILE*fp1;
char*KeyWordTable[MAX_KEY_NUMBER]={"
begin"
"
end"
"
if"
then"
else"
KEY_WORD_END};
/*查保留字表,判断是否为关键字*/
intlookup(char*token)
{
intn=0;
while(strcmp(KeyWordTable[n],KEY_WORD_END))/*strcmp比较两串是否相同,若相同返回0*/
{
if(!
strcmp(KeyWordTable[n],token))/*比较token所指向的关键字和保留字表中哪个关键字相符*/
{
returnn+1;
/*根据单词分类码表I,设置正确的关键字类别码,并返回此类别码的值*/
break;
}
n++;
}
return0;
}
voidscanner_example(FILE*fp)
charch;
inti,c,isd,cpoint;
doubleo;
ch=fgetc(fp);
//fgetc函数在文件中读取一个字符
if(isalpha(ch))/*itmustbeaidentifer!
它必须是一个标识符判断字符ch是否为英文字母,若为小写字母,返回2,若为大写字母,返回1。
若不是字母,返回0*/
TOKEN[0]=ch;
ch=fgetc(fp);
i=1;
while(isalnum(ch)||ch=='
.'
)//isalnum函数判断ch是否为空当ch为数字0-9或字母a-z及A-Z时,返回非零值,否则返回零
if(ch=='
){
cpoint=-1;
//标志字符串中有小数点
}
TOKEN[i]=ch;
i++;
ch=fgetc(fp);
TOKEN[i]='
\0'
;
if(ch=='
'
||ch=='
='
){
fseek(fp,-2,1);
siagn=1;
elsefseek(fp,-1,1);
//fseek(fp,-1,1);
/*retractfseek函数每调用一次,就把扫描指示器回退一个字符位置(即退回多读的那个字符)*/
i=0;
if(TOKEN[i]=='
o'
||TOKEN[i]=='
O'
{ i++;
if(TOKEN[i]=='
x'
X'
{
i++;
while(TOKEN[i]!
{
if(!
isdigit(TOKEN[i])||TOKEN[i]!
a'
||TOKEN[i]!
b'
c'
d'
e'
f'
||TOKEN[i]!
A'
B'
C'
D'
E'
F'
{
isd=-1;
}
isd=16;
//标志字符串十六进制
i++;
}
elseif(TOKEN[i]=='
0'
1'
2'
3'
4'
5'
6'
7'
)
isd=8;
//标志字符串八进制
if(TOKEN[i]!
isd=8;
}
if(isd==8){
strncpy(TOKEND,TOKEN+1,strlen(TOKEN)-1);
//拷贝函数
//printf("
%o"
atof(TOKEND));
o=octal(TOKEND);
%g"
o);
sprintf(TOKENDO,"
octal(TOKEND));
out(OCTAL,TOKENDO);
elseif(isd==16){
strn