河北工业大学编译原理.docx
《河北工业大学编译原理.docx》由会员分享,可在线阅读,更多相关《河北工业大学编译原理.docx(33页珍藏版)》请在冰豆网上搜索。
![河北工业大学编译原理.docx](https://file1.bdocx.com/fileroot1/2023-1/6/73be5be3-271e-4795-9067-1c68e04cb1fd/73be5be3-271e-4795-9067-1c68e04cb1fd1.gif)
河北工业大学编译原理
编译原理实验报告
实验一词法分析程序实现
一、实验目的与要求
通过编写和调试一个词法分析程序,掌握在对程序设计语言的源程序进行扫描的过程中,将字符形式的源程序流转化为一个由各类单词符号组成的流的词法分析方法。
二、实验设计
语言中具有的单词包括五个关键字begin、end、if、then、else;标识符;整型常数;六种关系运算符;一个赋值符和四个算术运算符。
参考实现方法简述如下。
单词的分类:
构造上述语言中的各类单词符号及其分类码表。
表I语言中的各类单词符号及其分类码表
单词符号
类别编码
类别码的助记符
单词值
begin
1
BEGIN
end
2
END
if
3
IF
then
4
THEN
else
5
ELSE
标识符
6
ID
字母打头的字母数字串
整常数
7
INT
数字串
<
8
LT
<=
9
LE
=
10
EQ
<>
11
NE
>
12
GT
>=
13
GE
:
=
14
IS
+
15
PL
-
16
MI
*
17
MU
/
18
DI
识别表I所列语言中的部分单词的DFA及相关的语义过程
将表I单词集中的整常数改为无符号常数,无符号常数的单词分类码助记符:
UCON
描述无符号数的正规文法和状态转换图:
无符号数的右线性文法G1[<无符号数>]如下:
〈无符号数〉→d〈余留无符号数〉
〈无符号数〉→·〈小数部分〉
〈无符号数〉→d
〈余留无符号数〉→d〈余留无符号数〉
〈余留无符号数〉→·〈十进小数〉
〈余留无符号数〉→E〈指数部分〉
〈余留无符号数〉→d
〈余留无符号数〉→·
〈十进小数〉→E〈指数部分〉
〈十进小数〉→d〈十进小数〉
〈十进小数〉→d
〈小数部分〉→d〈十进小数〉
〈小数部分〉→d
〈指数部分〉→d〈余留整指数〉
〈指数部分〉→+〈整指数〉
〈指数部分〉→-〈整指数〉
〈指数部分〉→d
〈整指数〉→d〈余留整指数〉
〈整指数〉→d
〈余留整指数〉→d〈余留整指数〉
〈余留整指数〉→d
图所示为上述文法的状态转换图,其中编号0、1、2、…、6分别代表非终结符号<无符号数>、<余留无符号数>、<十进小数>、<小数部分>、<指数部分>、<整指数>及<余留整指数>。
文法G1[<无符号数>]的状态转换图
包含语义处理过程的识别无符号数的状态矩阵
3、源程序
#include
#include
#include
#include
#include
#defineBEGIN1
#defineEND2
#defineIF3
#defineTHEN4
#defineELSE5
#defineID6
#defineINT7
#defineLT8
#defineLE9
#defineEQ10
#defineNE11
#defineGT12
#defineGE13
#definePL14
#defineMI15
#defineMU16
#defineDI17
#defineIS18
#defineTOKEN_SIZE64
#defineTAB_SIZE5
charTOKEN[TOKEN_SIZE];
externintlookup(char*);
externvoidout(int,char*);
externvoidreport_error();
intGetChar(void);
intEXCUTE(int,int);
intLEX(void);
#defineLETTER0
#defineDIGIT1
#definePOINT2
#defineOTHER3
#definePOWER4
#definePLUS5
#defineMINUS6
#defineClassNo100
#defineClassOther200
#defineEndState-1
intw,n,p,e,d;
intClass;
intICON;
floatFCON;
staticintCurrentState;
charch;
//信息表保存5个关键字
typedefstruct
{
intad;
charid[6];
}info_ele;
info_eleTab[TAB_SIZE]={{1,"begin"},{2,"end"},{3,"if"},{4,"then"},{5,"else"}};
voidscanner_example(FILE*fp)//扫描器函数
{
inti,c;
ch=fgetc(fp);
if(isalpha(ch))//是否为字母
{
TOKEN[0]=ch;
i=1;
ch=fgetc(fp);
while(isalnum(ch))//是否为字母或数字
{
TOKEN[i]=ch;
i++;
ch=fgetc(fp);
}
fseek(fp,-1,1);
TOKEN[i]='\0';
c=lookup(TOKEN);//调用输出函数out()
if(c==0)
out(ID,TOKEN);
else
out(c,TOKEN);
}
elseif(isdigit(ch))//判断是否为整数
{
TOKEN[0]=ch;
i=1;
ch=fgetc(fp);
while(isdigit(ch)||ch=='.'||ch=='e'||ch=='-')
{
TOKEN[i]=ch;
i++;
ch=fgetc(fp);
}
fseek(fp,-1,1);
TOKEN[i]='\0';
out(INT,TOKEN);
LEX();
}
else//判断运算符
if(ch==''||ch=='\n');//遇见空格、回车继续
else
switch(ch)
{
case'=':
out(EQ,"=");
break;
case':
':
ch=fgetc(fp);
if(ch=='=')
out(IS,":
=");break;
case'>':
ch=fgetc(fp);
if(ch=='=')out(GE,">=");
else
{
fseek(fp,-1,1);
out(GT,">");
}
break;
case'<':
ch=fgetc(fp);
if(ch=='=')
out(LE,"<=");
elseif(ch=='>')
out(NE,"<>");
else{
fseek(fp,-1,1);
out(LT,"<");
}
break;
//case':
=':
out(IS,":
=");break;
case'+':
out(PL,"+");break;
case'-':
out(MI,"-");break;
case'*':
out(MU,"*");break;
case'/':
out(DI,"/");break;
default:
report_error();
break;
}
}
intlookup(charp[])//查找是否为关键字
{
inti=0;
for(i;i{
if(!
strcmp(Tab[i].id,p))
return(Tab[i].ad);
}
return0;
}
voidout(inta,char*p)///输出结果
{
switch(a)
{
caseBEGIN:
printf("(BEGIN,%s)\n",p);break;
caseEND:
printf("(END,%s)\n",p);break;
caseIF:
printf("(IF,%s)\n",p);break;
caseTHEN:
printf("(THEN,%s)\n",p);break;
caseELSE:
printf("(ELSE,%s)\n",p);break;
caseID:
printf("(ID,%s)\n",p);break;
caseINT:
printf("(UCON,%s)\n",p);break;
caseLT:
printf("(LT,%s)\n",p);break;
caseLE:
printf("(LE,%s)\n",p);break;
caseEQ:
printf("(EQ,%s)\n",p);break;
caseNE:
printf("(NE,%s)\n",p);break;
caseGT:
printf("(GT,%s)\n",p);break;
caseGE:
printf("(GE,%s)\n",p);break;
casePL:
printf("(PL,%s)\n",p);break;
caseMI:
printf("(MI,%s)\n",p);break;
caseMU:
printf("(MU,%s)\n",p);break;
caseDI:
printf("(DI,%s)\n",p);break;
caseIS:
printf("(IS,%s)\n",p);break;
default:
break;
}
}
voidreport_error()
{
printf("\n有错误!
\n");
exit(0);
}
////////////////////////////////////////////////
///识别无符号数////
intHandleOtherWord(void)
{
returnClassOther;}
intHandleError(void)
{printf("Error!
\n");return0;}
intGetChar(inti)
{
intc;
c=(int)TOKEN[i];
//scanf("d%",c);
if(isdigit(c)){d=c-'0';returnDIGIT;}
if(c=='.')returnPOINT;
if(c=='e'||c=='E')returnPOWER;
if(c=='+')returnPLUS;
if(c=='-')returnMINUS;
returnOTHER;
}
intEXCUTE(intstate,intsymbol)
{
//floatpow(int,int);
switch(state)
{
case0:
switch(symbol)
{
caseDIGIT:
n=0;p=0;e=1;w=d;CurrentState=1;Class=ClassNo;break;
casePOINT:
w=0;n=0;p=0;e=1;CurrentState=3;Class=ClassNo;break;
default:
HandleOtherWord();ClassOther;
CurrentState=EndState;
}
break;
case1:
switch(symbol)
{
caseDIGIT:
w=w*10+d;break;
casePOINT:
CurrentState=2;break;
casePOWER:
CurrentState=4;break;
default:
ICON=w;CurrentState=EndState;
printf("%d\n",ICON);
}
break;
case2:
switch(symbol)
{
caseDIGIT:
n++;w=w*10+d;break;
casePOWER:
CurrentState=4;break;
default:
FCON=w*pow(10,e*p-n);CurrentState=EndState;
printf("%f\n",FCON);
}
break;
case3:
switch(symbol)
{
caseDIGIT:
n++;w=w*10+d;CurrentState=2;break;
default:
HandleError();CurrentState=EndState;
}
break;
case4:
switch(symbol)
{
caseDIGIT:
p=p*10+d;CurrentState=6;break;
caseMINUS:
e=-1;CurrentState=5;break;
casePLUS:
CurrentState=5;break;
default:
HandleError();CurrentState=EndState;
}
break;
case5:
switch(symbol)
{
caseDIGIT:
p=p*10+d;CurrentState=6;break;
default:
HandleError();CurrentState=EndState;
}
break;
case6:
switch(symbol)
{
caseDIGIT:
p=p*10+d;break;
default:
FCON=w*pow(10,e*p-n);CurrentState=EndState;
printf("%f\n",FCON);
}
break;
}
returnCurrentState;
}
intLEX(void)
{
intch,a=0;
CurrentState=0;
while(CurrentState!
=EndState)
{
ch=GetChar(a);
EXCUTE(CurrentState,ch);
a++;
}
returnClass;
}
voidmain()
{
externcharch;
FILE*fp;
if((fp=fopen("data.txt","r"))==NULL)//打开文件data.txt
{
printf("\nfileopenerror!
\n");
exit(0);
}
do
{
scanner_example(fp);//调用扫描程序
}while(ch!
=EOF);
}
结果:
实验二语法分析程序实现
一、实验目的与要求
通过设计、编制、调试一个典型的语法分析程序(任选有代表性的语法分析方法,如算符优先法、递归下降法、LL
(1)、SLR
(1)、LR
(1)等,作为编制语法分析程序的依据),对扫描器所提供的单词序列进行语法检查和结构分析,实现并进一步掌握常用的语法分析方法。
2、实验设计
文法:
[<算术表达式>]
<算术表达式>→<项>|<算术表达式>+<项>|<算术表达式>-<项>
<项>→<因式>|<项>*<因式>|<项>/<因式>
<因式>→<运算对象>|(<算术表达式>)
若将非终结符号<算术表达式>、<项>、<因式>和<运算对象>分别用E、T、F和i代表,则文法可写成:
E→T|E+T|E-TT→F|T*F|T/FF→i|(E)
设计思路:
用C语言编制算符优先分析法的语法分析程序。
其中使用了分析栈stack,用来在分析过程中存放当前句型的某一前缀,一旦句型的最左素短语在栈顶形成,便立即进行归约。
用两个数组stack[MAXSTACK],a[]实现分析栈和余留符号栈。
然后,构造该文法的算符优先关系矩阵。
在此可以根据算术表达式中各算符的优先级和结合性,直接手工构造算符优先关系表。
算符优先关系表
+
-
*
/
(
)
i
#
+
>
>
<
<
<
<
<
>
-
>
>
<
<
<
<
<
>
*
>
>
>
>
<
<
<
>
/
>
>
>
>
<
<
<
>
(
<
<
<
<
<
=
<
)
>
>
>
>
>
>
i
>
>
>
>
>
>
>
#
<
<
<
<
<
<
=
>
3、源程序
#include
#defineRIGHT1
#defineERROR0
#defineMAXINPUT300
#defineMAXSTACK100
charstack[MAXSTACK],a[]={'i','+','i','*','i','#'};/*a[]isinputline余留符号栈*/
intIsHigherThan(int,int);/*算符优先比较,前者是否高于后者*/
intIsLowerThan(int,int);/*//算符优先比较,前者是否低于后者*/
intIsEqualTo(int,int);/*//算符优先比较,前者是否等于后者*/
intReduce(intbegin,intend,intlen);/*归约函数*/
charvt[3]={'E','F','T'};///*determineifstacksymbolisinVt*/
/////算符优先表///
inttable[8][8]={
{1,1,-1,-1,-1,1,-1,1},
{1,1,-1,-1,-1,1,-1,1},
{1,1,1,1,-1,1,-1,1},
{1,1,1,1,-1,1,-1,1},
{-1,-1,-1,-1,-1,0,-1,''},
{1,1,1,1,1,1,'',''},
{1,1,1,1,1,1,'',1},
{-1,-1,-1,-1,-1,-1,0,1}
};
intCharToIndex(intch)//算符转换表
{
intt;
switch(ch)
{
case'+':
t=0;break;
case'-':
t=1;break;
case'*':
t=2;break;
case'/':
t=3;break;
case'(':
t=4;break;
case')':
t=5;break;
case'i':
t=6;break;
case'#':
t=7;break;
default:
t=8;break;
}
returnt;
}
intIsVt(intch)//判断是否为终结符
{
inti=0;
while(ch!
=vt[i])//查看是否为t[]数组中元素
{
i++;
if(i>3)
return1;
}
return0;
}
intIsHigherThan(inti,intj)//算符优先比较,前者是否高于后者
{
i=CharToIndex(i);
j=CharToIndex(j);
if(i==8||j==8)
{
return0;
}
elseif(table[i][j]==1)
return1;
elsereturn0;
}
intIsLowerThan(inti,intj)//算符优先比较,前者是否低于后者
{
i=CharToIndex(i);
j=CharToIndex(j);
if(i==8||j==8)
{
return0;
}
elseif(table[i][j]==-1)
return1;
elsereturn0;
}
intIsEqualTo(inti,intj)//算符优先比较,前者是否等于后者
{
i=CharToIndex(i);
j=CharToIndex(j);
if(i==8||j==8)
{
return0;
}
elseif(table[i][j]==0)
return1;
elsereturn0;
}
intReduce(intbegin,intend,intlen)//归约函数
{
inti;
chartemp[50];
charNewVn='\0';
for(i=begin;i<=end;i++)
{
temp[i-begin]=stack[i];
}
temp[len]='\0';
printf("规约项:
%s\t",temp);
if(len==3)
{
switch(temp[1])
{
case'*':
case'/':
NewVn='T';break;
case'+':
case'-':
NewVn='E';break;
case'E':
NewVn='F';break;
default:
break;
}
}
elseif(len==1)
{
switch(temp[0])
{
case'i':
NewVn='F';break;
case'F':
NewVn='T';break;
case'T':
NewVn='E';break;
default:
break;
}
}
printf("-->%c\n",NewVn);
returnNewVn;
}
intmain()
{
inti,k,r,NewVn;/*NewVnholdsleftsideofaproduction*/
i=0;k=0;/*i,kisindexofa[]andstack[]separately*/
stack[0]='#';
do
{
intj;
r=a[i++];
if(IsVt(stack[k]))j=k;elsej=k-1;
whil