#编译原理实验评测报告Word文件下载.docx
《#编译原理实验评测报告Word文件下载.docx》由会员分享,可在线阅读,更多相关《#编译原理实验评测报告Word文件下载.docx(29页珍藏版)》请在冰点文库上搜索。
![#编译原理实验评测报告Word文件下载.docx](https://file1.bingdoc.com/fileroot1/2023-5/1/8b1a9cd9-84c3-4437-b801-829cfd1b8a56/8b1a9cd9-84c3-4437-b801-829cfd1b8a561.gif)
|(<
|<
数字字符>
>
*(ε|_|.>
(<
*
十进制数:
(0|(1|2|3|4|5|6|7|8|9>
(0|1|2|3|4|5|6|7|8|9>
*>
(ε|.>
(0|1|2|3|4|5|6|7|8|9>
八进制数:
0(0|(1|2|3|4|5|6|7>
(0|1|2|3|4|5|6|7>
(ε|.>
(0|1|2|3|4|5|6|7>
十六进制数:
0x(0(|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f>
(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f>
(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f>
运算符和分隔符:
+-*/<
>
=(>
。
关键字:
ifthenelsewhiledo
二>
、改变后的正规文法
标识符>
->
<
temp>
temp2>
十进制整数>
temp3>
八进制整数>
0<
temp4>
十六进制整数>
0x<
temp5>
运算符和分隔符>
+|-|*|/|>
|<
|=|(|>
|;
关键字>
if|then|else|while|do
字母
a|b|c|d|e|f|g|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
0|1|2|3|4|5|6|7|8|9
(<
|ε
(ε|_|.>
将状态合起来,得:
(0>
1~9>
(1>
|0(4>
(12>
(17>
(1>
0~9>
|.(2>
(2>
(3>
(3>
(4>
.(2>
1~7>
(5>
|0(13>
|x(8>
|X(8>
(5>
0~7>
|.(6>
(6>
(7>
(7>
(8>
(9>
a~f>
|0(14>
(9>
|.(10>
(10>
(11>
(11>
a~z>
A~Z>
|.(15>
|_(15>
(13>
.(6>
(14>
.(10>
(15>
(16>
(16>
三>
、状态图:
0~90~9
1.23
0~9
1~9
.
0~70~7
567
004
1~7
0.
13
0~7
x|X
字母
81~f
0~f
9
.10
11
分隔符
12
.|_
014.
字母或数字
1516
17
四>
、数据结构:
char*arrBao[5]={"
if"
"
then"
else"
do"
while"
}。
//保留字表
typedefstruct{
chartype[TYPE_MAX]。
charvalue[VALUE_MAX]。
}CNode。
//词法分析的节点,保留分析出的token的种类和值
五>
、算法<
伪码):
boolMyScan(FILE*fp,CNode*&
node>
{
chartemp。
//当前读取的字符
chars[100]。
//保留字符串
intsi=0。
//对于控制s的下标
intstate=0。
//当前状态号
node=newCNode。
//返回的节点
while(1>
读取一个字符到temp。
if(temp=='
#'
{strcpy(node->
type,"
#"
。
strcpy(node->
value,"
_"
returnfalse。
//表示文件结束
}
switch<
state){
case0:
//状态0
if(temp为0>
state=4。
添加当前字符。
continue。
if(temp为1到9>
state=1。
if(temp为字母>
state=12。
添加当前字符。
if(temp为分隔符>
保存相应的分隔符到node。
returntrue。
if(temp为空格或回车或tab>
//忽略多个空格和回车
和制表符
else出错处理。
case1:
//状态1
if(temp为数字>
state=4。
if(temp为小数点>
state=2。
保存为INT10。
case2:
//状态2
state=3。
case3:
//状态3
if(temp为分隔符>
保存为REAL10。
case4:
//状态4
if(temp为小数点>
if(temp为1~7>
state=5。
if(temp为0>
state=13。
if(temp为x或X>
state=8。
case5:
//状态5
state=6。
if(temp为0~7>
保存为INT8。
case6:
//状态6
if(temp为0~7>
state=7。
case7:
//状态7
case8:
//状态8
if(temp为十六进制数>
state=9。
continue。
state=14。
case9:
//状态9
state=10。
保存为INT16。
case10:
//状态10
state=11。
case11:
//状态11
case12:
//状态12
if(temp为数字或者字母>
if(temp为_或者.>
state=15。
if(为保留字>
保存为保留字。
returntrue。
else保存为IDN。
case13:
//状态13
if(temp为.>
state=6。
else出错处理。
case14:
//状态14
state=10。
case15:
//状态15
state=16。
case16:
//状态16
}//switch
}//while
//主函数源程序
intmain(>
{FILE*fp。
fp=fopen("
code1.txt"
r"
CNode*node。
while(MyScan(fp,node>
{
if(node!
=NULL>
{//分析成功
printf("
%s\t%s\n"
node->
type,node->
value>
elseprintf("
\n"
fclose(fp>
getchar(>
return0。
六>
、测试
测试用例:
092+data>
0x3f00whilea+acc>
xxdox=x-1。
a=6.2+a*0X88.80。
ifa>
bthena=belsea=b-1+c。
#测试用例说明:
本测试用例测试了十进制数,八进制数,十六进制数,十进制0,八进制0,十进制小数,八进制小数,十六进制小数,各个关键字以及分隔符,对于空格,回车,制表符的测试,基本上全了。
因为词法分析器中不支持续编译
理由已在上面阐述),所以出错的例子无法在一个文件中给出,这里忽略。
分析的结果如下:
三)使用递归子程序法做三地址码生成器
写在前面:
递归子程序法的基本思路是:
给每一个变量都编写一个函数,产生式中如果存在变量则调用相应的程序。
主函数中调用最开始的程序。
这种方法的思路非常清晰,容易理解,易于控制。
我的理解是如果采用此种方法文法可以不是LL<
1)的,原因如下:
首先,文法必须是没有左递归的,否则系统栈会溢出。
但是最左公因子可以不用提取出来:
在一个程序中可以先统一做某些操作,然后根据不同的token决定接下来走哪一个分支。
而这些“统一的操作”就是最左公因子。
所以为了实现简便,也更容易理解,我没有提取最左公因子。
另外,这种方法中可以存在形如A->
B(+B>
*的产生式,因为在用子程序的时候这种产生式可以用循环控制<
循环条件为下一个token为+),将两者结合起来,如下的产生式E->
T1((+|->
T2>
*也是合法的,但用预约分析表决不允许这样的产生式出现,这也是递归子程序这种方法的灵活以及更贴近最原始的产生式的体现。
之后,在确定了程序应该进入那个分支后,需要在相应的分支之前加入语义规则。
以此来实现三地址码的生成。
、语义规则。
用递归子程序时,最左公因子可以不用提取,原因见上
S'
→S。
S.next=0。
.code=S.code||gen(S.next,”:
”>
S→ID=E
S.code=E.code||gen(IDN,”=”,E.place>
S→ifCthenS1
X
C->
isTrue=newlabel(>
X->
begin=S->
next。
C->
isFalse=X->
begin。
S1->
next=X->
next=S1->
S.code=C.code||gen(C.isTrue”:
||S1.code||tmpX.code
X→elseS
X.next=newlabel(>
S.next=X.next。
S.begin=X.begin。
X.iselse=true。
X.code=gen(“goto”,X.next>
||gen(X.begin,”:
||S.code
X→null
X.next=X.begin。
X.iselse=false。
X.code=””
S→whileCdo
S1
tmplabel=S.begin。
S.begin=newlabel(>
C.isTrue=
newlabel(>
S1.begin=tmpC->
isTrue。
C.isFalse=tmpS->
S1.next=tmpS->
S.code=gen(S.begin,”:
||C.code||gen(C.isTrue,”:
||S1.code||gen(‘goto’,S.begin>
C→E1>
E2
C.code=E1.code||E2.code||gen(“if”,E1.place,”>
”,E2.place>
||gen(“goto”
C.isTrue>
||gen(“goto”,C.isFalse>
C→E1<
C.code=E1.code||E2.code||gen(“if”,E1.place,”<
C→E1=E2
C.code=E1.code||E2.code||gen(“if”,E1.place,”=”,E2.place>
E→T1((+|->
IfE→TE.code=T.code。
E.place=T.place。
Else
E.place=newtemp(>
E.code=T1.code||T2.code||gen(E.place,”=”,T1.place,’+’or’-’,T2.place>
T1.code=E.code。
T1.place=E.place。
T→F1((*|/>
F2>
IfT→FT.code=F.code。
T.place=F.place。
T.place=newtemp(>
T.code=F1.code||F2.code||gen(T.place,”=”,F1.place,’*’or’/’,F2.place>
F1.code=T.code。
F1.place=T.place。
F→(E>
F.place=E.place。
F.code=E.code。
F→id
F.place=id.name。
F.code=’’。
F→int8
F.place=int8.value。
F→int10
F.place=int10.value。
F→int16
F.place=int16.value。
、三地址码生成的数据结构
typedefstruct{//S’
charcode[CODE_MAX]。
}str_S_。
typedefstruct{//S
intbegin,next。
}str_S。
typedefstruct{//X
booliselse。
}str_X。
typedefstruct{//C
intisFalse,isTrue。
}str_C。
typedefstruct{//E
charplace[VALUE_MAX]。
}str_E。
typedefstruct{//T
}str_T。
typedefstruct{//F
}str_F。
、语义分析的主要程序
boolMyFunction_S_(FILE*fp,str_S_*&
tmpS_>
{//S’CNode*node。
str_S*tmpS=newstr_S。
tmpS->
next=0。
Lnum=0。
if(MyFunction_S(fp,tmpS>
{//调用S
if(strcmp(Node->
"
==0>
{//匹配;
if(Lnum!
=0>
//需要有跳转
sprintf(tmpS_->
code,"
%s\nL%d:
tmpS->
code,tmpS->
next>
else//不需要跳转
%s\n"
code>
returnfalse。
boolMyFunction_S(FILE*fp,str_S*&
tmpS>
{//SCNode*node。
str_E*tmpE=newstr_E。
str_C*tmpC=newstr_C。
str_S*tmpS1=newstr_S。
str_X*tmpX=newstr_X。
if(getNext(fp>
{//读取一个字符
IDN"
{//如果为变量,走变量分支char*tmpName=Node->
value。
//记录变量名if(getNext(fp>
{//匹配变量
//产生式匹配
="
//检查下是否为=
//匹配=
if(MyFunction_E(fp,tmpE>
//递归执行程序E
//语义操作
sprintf(tmpS->
%s
=
tmpE->
code,tmpName,tmpE->
place>
returntrue。
then
elseif(strcmp(Node->
{//如果为if,走if分支
{//匹配iftmpC->
isTrue=newlabel(>
tmpX->
begin=tmpS->
//newlabel(>
tmpC->
isFalse=tmpX->
tmpS1->
next=tmpX->
tmpX->
next=tmpS1->
if(MyFunction_C(f