编译原理第二次上机实验报告软工李U172xx.docx
《编译原理第二次上机实验报告软工李U172xx.docx》由会员分享,可在线阅读,更多相关《编译原理第二次上机实验报告软工李U172xx.docx(26页珍藏版)》请在冰豆网上搜索。
编译原理第二次上机实验报告软工李U172xx
编译原理第二次上机实验报告
姓名:
李x
班级:
软工140x班
学号:
U2014172xx
实验二 设计实现简单语言的语法分析器
1、实验目的
通过该实验,熟练应用编译原理关于语法分析的基本理论和方法;学会用C/C++高级程序设计语言设计一个语法分析器;加深对编译原理理论的分析理解,提高实际操作和解决具体问题的能力。
2、实验条件
计算机上安装C/C++编译处理软件。
3、实验内容及要求
对下述单词表与语法定义的语言设计编制一个语法分析器。
单词符号及种别表、语法及语法分析器功能、基本要求如下:
(1)单词符号及种别表
单词符号
种别编码
单词值
main
1
int
2
float
3
double
4
char
5
if
6
else
7
do
8
while
9
l(l|d)*
10
内部字符串
(+|-|ε)dd*(.dd*|ε)(e(+|-|ε)dd*|ε)
20
二进制数值表示
=
21
+
22
-
23
*
24
/
25
(
26
)
27
{
28
}
29
30
;
31
>
32
>=
33
<
34
<=
35
==
36
!
=
37
#
0
(2)语法结构定义
<表达式>:
:
=<项>{+<项>|-<项>}
<项>:
:
=<因子>{*<因子>|/<因子>}
<因子>:
:
=ID|num|(<表达式>)
num:
:
=(+|-|ε)数字数字*(.数字数字*|ε)(e(+|-|ε)数字数字*|ε)
ID:
:
=字母(字母|数字)*
字母:
:
=a|b|c…|z|A|B|C…|Z
数字:
:
=0|1|2…|9
(3)语法分析器功能及基本要求
处理用户提交的符合上述文法的源代码序列,进行语法分析,并给出语法是否正确的结论。
(1)总体设计思想
利用自上而下的分析方法;本实验所采用的是LL
(1)分析法即预测分析法;每次通过词法分析模块读入一个完整的单词,在语法分析中判断正确性,最终将结果输出。
(2)详细算法设计
语法分析
<表达式>:
:
=<项>{+<项>|-<项>}
<项>:
:
=<因子>{*<因子>|/<因子>}
<因子>:
:
=ID|num|(<表达式>)
num:
:
=(+|-|ε)数字数字*(.数字数字*|ε)(e(+|-|ε)数字数字*|ε)
ID:
:
=字母(字母|数字)*
字母:
:
=a|b|c…|z|A|B|C…|Z
数字:
:
=0|1|2…|9
用字母替代后写成如下:
E→T{+T|-T}
T→F{*F|/F}
F→i|n|(E)
将该扩充文法还原
EE+T|E-T|T
TT*F|T/F|F
F(E)|i|n
消除非终结符E、T的直接左递归后,文法变为
ETE’
E’+TE’|-TE’|ε
TFT’
T’*FT’|/FT’|ε
F(E)|i|n
此文法是LL
(1)文法
求出该文法的预测分析表
i
n
+
-
*
/
(
)
$
E
ETE’
ETE’
ETE’
E’(e)
E’+TE’
E’TE’
E’ε
E’ε
T
TFT’
TFT’
TF’
T’(t)
T’ε
T’ε
T’*FT’
T’/FT’
T’ε
T’ε
F
Fi
Fn
F(E)
根据预测分析表、分析栈和一个总控程序来判断一个语句是否正确;
(3)流程框图
(4)函数相关说明
charinput[300];//存放输入的字符串
chartoken[20];//存放符合C语言词法规则的单词
charch;//单个字符
charprevious;//ch的前一个字符
charlatter;//ch的后一个字符
charch1,ch2;//当处理注释的时候使用
inttypenum;//表示单词的种别码
intp,m,n,cx;
doubledecimal;//记录小数
doublesum;//存放数字
intindex;//存放指数
intisNum;//是否是数字
intisDecimal;//记录是否为小数
intisExp;//记录是否为指数
intisNegative;//是否带负号(对于指数)
intisNegative1;//是否为负数
charX,a;
charstack[200];
voidscanner();
char*rwtab[11]={"main","int","float","double","char","if","else","while","do","end"};
//记录预测分析表,0表示没有产生式,其他数字表示产生式的序号
intList[5][9]={
{1,2,0,0,0,0,3,0,0},
{0,0,4,5,0,0,0,6,7},
{8,9,0,0,0,0,10,0,0},
{0,0,11,12,13,14,0,15,16},
{17,18,0,0,0,0,19,0,0}
};
charreturnResult()函数返回n、i、e、+、-、*、/、(、);
voidscanner()扫描函数判断种别码
boolisVT(charx)判断是否为终结符
boolcheckList(intx,inty)查询是否在分析表中
intgetX()、intgetY()获取要查询数组M[X,a]元素的下标
voidmakeTop()把栈顶放入X中
voidpush(intxy)将y1y2...yn逆序放入S栈中
intmain()主函数
(5)输入与输出(包括出错处理)
输入以$结束回车即可运行程序
输出success!
或者unsuccess!
或者error!
unsuccess!
出错分为两种情况
1.词法错误:
error!
unsuccess!
2.词法正确但语法错误:
unsuccess!
(6)程序运行结果(屏幕截图)
(7)词法分析器使用说明
打开编译器VS或者VC++;文件新建项目;
将代码复制粘贴,编译运行,按照提示输入即可使用;
(8)心得与体会
加强了自己对于LL
(1)分析法的理解与记忆;第二次试验难度要大于第一次;主要难在求预测分析表;开始由于预测分析表求错误导致程序运行一直出错也不知道到底bug出在哪里,后来才发现自己预测分析表求错了;对于词法分析实验一已经给出,预测分析总控制程序算法书本上已经给出;所以最大的难点就是求预测分析表;这需要足够的耐心和细心才能保证FIRSE集和FOLLOW集不多一个,也不漏掉其中一个;后期需要加强练习;
(9)源程序清单
//语法编译器01.cpp:
定义控制台应用程序的入口点。
//
#include"stdafx.h"
#include
#include
#include
charinput[300];//存放输入的字符串
chartoken[20];//存放符合C语言词法规则的单词
charch;//单个字符
charprevious;//ch的前一个字符
charlatter;//ch的后一个字符
charch1,ch2;//当处理注释的时候使用
inttypenum;//表示单词的种别码
intp,m,n,cx;
doubledecimal;//记录小数
doublesum;//存放数字
intindex;//存放指数
intisNum;//是否是数字
intisDecimal;//记录是否为小数
intisExp;//记录是否为指数
intisNegative;//是否带负号(对于指数)
intisNegative1;//是否为负数
charX,a;
charstack[200];
voidscanner();
char*rwtab[11]={"main","int","float","double","char","if","else","while","do","end"};
//记录预测分析表,0表示没有产生式,其他数字表示产生式的序号
intList[5][9]={
{1,2,0,0,0,0,3,0,0},
{0,0,4,5,0,0,0,6,7},
{8,9,0,0,0,0,10,0,0},
{0,0,11,12,13,14,0,15,16},
{17,18,0,0,0,0,19,0,0}
};
charreturnResult()
{
scanner();
switch(typenum)
{
case20:
return'n';//表示返回一个数字number
case10:
return'i';//表示返回id
case22:
return'+';
case23:
return'-';
case24:
return'*';
case25:
return'/';
case26:
return'(';
case27:
return')';
case0:
return'$';
default:
return'e';//表示error!
}
}
voidscanner()
{
cx=0;//用来记录小数点后面的位数
m=0;
sum=0;
decimal=0;
index=0;
isDecimal=0;
isNegative=0;
isNegative1=0;
isExp=0;
for(n=0;n<8;n++)
token[n]='\0';
ch=input[p++];
//处理回车换行空格
while((ch=='')||(ch==9)||(ch==10))
{
ch=input[p++];
}
//处理注释
if(ch=='/')
{
ch1=input[p];
if(ch1=='*')
{
do
{
ch=input[p++];
ch2=input[p];
}while((ch!
='*')||(ch2!
='/'));
p=p+1;
ch=input[p++];
}
}
if(((ch>='a')&&(ch<='z'))||((ch>='A')&&(ch<='Z')))//如果当前ch为字母
{
while(((ch>='a')&&(ch<='z'))||((ch>='A')&&(ch<='Z'))||((ch>='0')&&(ch<='9')))
{
token[m++]=ch;
ch=input[p++];
}
token[m++]='\0';
typenum=10;//10表示l(l|d)*
p=p-1;//回退一步
for(n=0;n<10;n++)
if(strcmp(rwtab[n],token)==0)
{
typenum=n+1;
break;
}
}
elseif((ch>='0')&&(ch<='9'))
{
isNum:
while((ch>='0')&&(ch<='9'))
{
sum=sum*10+(ch-'0');
ch=input[p++];
}
if(ch=='.')
{
isDecimal=1;
ch=input[p++];
while(ch>='0'&&ch<='9')
{
cx=cx+1;
decimal=decimal*10+(ch-'0');
ch=input[p++];
}
if(ch=='')
{
typenum=-1;
return;
}
for(inta=0;adecimal=decimal*0.1;
sum=sum+decimal;
}
if((ch=='e')||(ch=='E'))
{
isExp=1;
ch=input[p++];
if(ch=='-')
{
isNegative=1;//表示指数为负数
ch=input[p++];
}
if(ch=='+')
{
isNegative=0;//表示指数为正
ch=input[p++];
}
if(ch=='')
{
typenum=-1;
return;
}
while((ch>='0')&&(ch<='9'))
{
index=index*10+(ch-'0');
ch=input[p++];
}
if(isNegative==1)//如果指数为负数
{
for(intk=0;ksum=sum*0.1;
}
else
{
for(intk=0;ksum=sum*10;
}
}
if(isNegative1==1)
sum=sum*(-1);
p--;//回退一步
typenum=20;//表示为数字
}
//运算符、界运算符
else{
switch(ch)
{
case'=':
typenum=21;
token[m++]=ch;
break;
case'+':
previous=input[p-2];
latter=input[p];
//当+号前面为空或者(或者=并且后面为数字时,+表示正负号;
if(((previous=='')||(previous=='(')||(previous=='='))&&((latter>='0')&&(latter<='9')))
{
isNegative1=0;//表示此+号为正负号
ch=input[p++];
gotoisNum;
}
//当+号前面为+、-、*、/号且后面为数字时,-号表示正负号;
elseif(((previous=='+')||(previous=='-')||(previous=='*')||(previous=='/'))&&((latter>='0')&&(latter<='9')))
{
isNegative1=0;
ch=input[p++];
gotoisNum;
}
//如果+号后面是+、-号,则表示为加减号
elseif((latter=='+')||(latter=='-'))
{
typenum=22;
token[m++]=ch;
break;
}
//如果+号后面是字母;
elseif(((latter>='a')&&(latter<='z'))||((latter>='A')&&(latter<='Z')))
{
typenum=22;
token[m++]=ch;
break;
}
elseif((((previous>='a')&&(previous<='z'))||((previous>='A')&&(previous<='Z'))||((previous>='0')&&(previous<='9')))&&((latter>=0)||(latter<='9')))
{
typenum=22;
token[m++]=ch;
break;
}
else
{
typenum=-1;
break;
}
case'-':
previous=input[p-2];
latter=input[p];
//当-号前面为空或者(或者=并且后面为数字时,-表示正负号;
if(((previous=='')||(previous=='(')||(previous=='='))&&((latter>='0')&&(latter<='9')))
{
isNegative1=1;//表示此+号为正负号
ch=input[p++];
gotoisNum;
}
//当-号前面为+、-、*、/号且后面为数字时,-号表示正负号;
elseif(((previous=='+')||(previous=='-')||(previous=='*')||(previous=='/'))&&((latter>='0')&&(latter<='9')))
{
isNegative1=1;
ch=input[p++];
gotoisNum;
}
//如果-号后面是+、-号,则表示为加减号
elseif((latter=='+')||(latter=='-'))
{
typenum=23;
token[m++]=ch;
break;
}
//如果-号后面是字母;
elseif(((latter>='a')&&(latter<='z'))||((latter>='A')&&(latter<='Z')))
{
typenum=23;
token[m++]=ch;
break;
}
//如果前面为字母或者数字且后面为数字,则表示-号
elseif((((previous>='a')&&(previous<='z'))||((previous>='A')&&(previous<='Z'))||((previous>='0')&&(previous<='9')))&&((latter>=0)||(latter<='9')))
{
typenum=23;
token[m++]=ch;
break;
}
else
{
typenum=-1;
break;
}
case'*':
typenum=24;
token[m++]=ch;
break;
case'/':
typenum=25;
token[m++]=ch;
break;
case'>':
token[m++]=ch;
ch=input[p++];
if(ch=='=')
{
typenum=33;
token[m++]=ch;
}
else
{
typenum=32;
p--;
}
break;
case'<':
token[m++]=ch;
ch=input[p++];
if(ch=='=')
{
typenum=35;
token[m++]=ch;
}
else
{
typenum=34;
p--;
}
break;
case'(':
typenum=26;
token[m++]=ch;
break;
case')':
typenum=27;
token[m++]=ch;
break;
case'{':
typenum=28;
token[m++]=ch;
break;
case'}':
typenum=29;
token[m++]=ch;
break;
case':
':
typenum=30;
token[m++]=ch;
break;
case';':
typen