编译原理课设.docx
《编译原理课设.docx》由会员分享,可在线阅读,更多相关《编译原理课设.docx(35页珍藏版)》请在冰豆网上搜索。
编译原理课设
编译技术课程设计
班级
学号
姓名
指导老师
2015年6月
一、目的
<<编译技术>>是理论与实践并重的课程,而其课程设计要综合运用一、二年级所学的多门课程的内容,用来完成一个小型编译程序。
从而巩固和加强对词法分析、语法分析、语义分析、代码生成和报错处理等理论的认识和理解;培养学生对完整系统的独立分析和设计的能力,进一步培养学生的独立编程能力。
二、题目
题目1表达式的小型编译器
三、要求
1.词法分析
产生语言的单词序列
2.语法分析
能识别由加+乘*括号()操作数(变量或常数)所组成的算术表达式,其文法如下:
E→E+T|T
T→T*F|F
F→(E)|i
使用的分析方法可以是:
递归下降分析法或LR分析法。
3.代码生成
产生上述算术表达式的中间代码
4.错误处理
给出错误信息
输入:
算术表达式
输出:
符号表,常数表。
归下降分析法:
递归调用过程/LR分析法:
语义栈和符号栈
四元式序列
四、实验环境
1.开发环境:
VisualStudio2013
2.程序语言:
C++
五、系统实现
1.词法分析
(1)单词符号表
(2)状态转换图
(3)数据结构
(4)函数说明
voidgetonechar()/*从输入的算数表达式中读取一个字符*/
voidconcatenation()/*将token中的字符串与character中的字符并作为token中新的字符串*/
boolletter()/*判断character中的字符是否为字母的布尔函数,是则返回true,否侧返回false*/
booldigit()/*判断character中的字符是否为数字的布尔函数,是则返回true,否侧返回false*/
voidretract()/*扫描指针回退一个字符,同时将character置为空白*/
intreserve()/*将token中的字符查找保留字数组,若是保留字就返回它的种别编码,否则返回0*/
voidbuildlist1()/*将标识符登录到符号表中(value2[])*/
voidbuildlist2()/*将常数登录到常数表中(value1[])*/
voidresolve()/*词法分析的主要函数,每次识别一个单词,将种别编码放入cf[]中,填入对应的value1[]和value[]*/
voidcffx()/*词法分析,读入输入的算数表达式,循环执行resolve(),直到所有单词识别完毕*/
2.语法分析
(1)分析方法说明
本程序采用LR分析法,存在4种动作:
①移进:
使(s,a)的下一个状态s’=ACTION[s,a]和输入符号a进栈,下一输入符号变成现行输入符号.
②规约:
指用某一产生式A→β进行规约,假若β的长度为γ,则规约动作是去掉栈顶的γ个栈,即是状态Sm-γ变成栈顶状态,然后使(Sm-γ,A)的下一状态s’=GOTO[Sm-γ,A]和文法符号A进栈.规约的动作不改变现行输入符号,执行规约的动作意味着呈现于栈顶的符号串Xm-γ+1…Xm是一个相对于A的句柄.
③接受:
宣布分析成功,停止分析器工作.
④报错:
报告发现源程序含有错误,调用错误处理程序.
(2)文法
(3)数据结构
#include/*引入c++标准库*/
stackstatus;/*状态栈*/
stacksign;/*符号栈*/
(4)函数说明
VoidinitYffx()/*语法分析初始化,状态栈放0,符号栈放#,语义栈放_*/
VoidshowLR()/*遍历状态栈,符号栈,语义栈,并显示出来*/
VoidyffxSolve()/*查action二维数组,进行移进,规约处理*/
Voidyyfx()/*循环执行yffxSolve(),直到分析成功或出现错误*/
VoidshowBlm()/*显示变量名表*/
VoidshowCsb()/*显示常数表*/
3.中间代码
(1)属性文法
①移进时:
如果输入的是终结符,语义栈就移进”_”,如果是非终结符,则语义栈移进对应的常数或变量名.
②规约时:
如果规约对应的文法是(4)E→i时语义栈不变,
对应其他文法时,先pop出栈顶3个元素,
再如果是(3)E→(E)文法时,语义栈push刚才出栈的第二个元素,
如果是
(1)E→E+E文法时,判断刚才出栈的第一个和第三个元素是否是常数,是则push两个常数的和,否则push临时变量Tn;
如果是
(1)E→E*E文法时,判断刚才出栈的第一个和第三个元素是否是常数,是则push两个常数的积,否则push临时变量Tn;
(2)数据结构
#include/*引入c++标准库*/
stackyuyi;/*语义栈*/
stringv1,v2,v3,v4;/*分别表示四元式的参数1,参数2,参数3,参数4*/
(3)函数说明
语义栈和四元式的产生是在语法分析一起的,在yffxSolve().
voidyffxSolve()
{
stacktempYuyiPush;
showLR();
inti=-1;
if(cf[m]==6||cf[m]==7){
i=0;
}
if(cf[m]==8){
i=1;
}
if(cf[m]==10){
i=2;
}
if(cf[m]==14){
i=3;
}
if(cf[m]==15){
i=4;
}
if(cf[m]==16){
i=5;
}
if(i==-1){
cout<<"输入了错误的种别编码"<m++;
return;
}
if(action[status.top()][i]>0)
{
if(action[status.top()][i]>100)
{
if(action[status.top()][i]==1000)
{
cout<<"acc"<system("pause");
exit(0);
}
/*规约*/
//cout<<"gy"<ints=action[status.top()][i]-100;
for(intj=0;j{
if(s!
=4)
{
tempYuyiPush.push(yuyi.top());
yuyi.pop();
}
status.pop();
sign.pop();
}
status.push(action[status.top()][6]);
sign.push('E');
if(s==4)
{
}
else{
v2=tempYuyiPush.top();
tempYuyiPush.pop();
stringv2plus5=tempYuyiPush.top();
tempYuyiPush.pop();
v3=tempYuyiPush.top();
tempYuyiPush.pop();
if(isdigit(v2)&&isdigit(v3))
{
if(s==1)
{
v4=intToStr(strToInt(v2)+strToInt(v3));
}
if(s==2)
{
v4=intToStr(strToInt(v2)*strToInt(v3));
}
yuyi.push(v4);
}
else{
if(v2=="_"&&isdigit(v2plus5)&&v2=="_")
{
v4=v2plus5;
yuyi.push(v4);
}
else{
stringtempNum=intToStr(yuyiNum);
stringtempS="T"+tempNum;
yuyiNum++;
yuyi.push(tempS);
v4=tempS;
}
}
if(s==1)
{
v1="+";
}
if(s==2)
{
v1="*";
}
}
}
else
{
/*移近*/
//cout<<"yj"<status.push(action[status.top()][i]);
sign.push(inputSign[i]);
if(cf[m]==6||cf[m]==7)
{
if(cf[m]==6)
{
yuyi.push(value2[m]);
}
else{
stringtempVal=intToStr(value1[m]);
yuyi.push(tempVal);
}
}
else{
yuyi.push("_");
}
m++;
}
}
else
{
interr=action[status.top()][i];
cout<<"第"<system("pause");
exit(0);
}
lrNum++;
}
(4)流程图
4.错误处理
(1)数据结构
stringshowErr[12]=
{
{"FOUNDERROR:
+前缺少变量或常量"},/*0,e1*/
{"FOUNDERROR:
*前缺少变量或常量"},/*1,e2*/
{"FOUNDERROR:
)前缺少对应("},/*2,e3*/
{"FOUNDERROR:
连续的变量或常量,缺少+/*"},/*3,e4*/
{"FOUNDERROR:
(前缺少+/*"},/*4,e5*/
{"FOUNDERROR:
(后缺少常量或变量"},/*5,e6*/
{"FOUNDERROR:
()内无表达式"},/*6,e7*/
{"FOUNDERROR:
+后缺少变量或常量"},/*7,e8*/
{"FOUNDERROR:
*后缺少变量或常量"},/*8,e9*/
{"FOUNDERROR:
算数表达式为空"},/*9,e10*/
{"FOUNDERROR:
缺少对应)"},/*10,e11*/
{"FOUNDERROR:
语法分析错误"}/*11,e12*/
};
(2)函数说明
yffxSolve()中,查action数组时,遇到e时输出错误位置和错误信息,跳过此单词,继续进行语法分析.
六、程序运行结果
1.连乘
2.连加
3.加乘混合
4.带括号
5.常数
6.错误的算术表达式
1)缺少操作符
2)缺少操作数
3)不完整的()
七、总结
通过课程设计更加深入地理解了LR分析法对算数表达式处理的过程,熟悉了编译的四个阶段:
词法分析,语法分析,语义分析和中间代码,以及错误处理.在运用c++编写程序时,也熟悉了c++标准库中stack的使用.
程序是一段一段写下来的,整个程序没有整体的规划,定义的变量又多又乱,造成许多变量需要不断的修改,而且不利于程序的理解.在对栈处理的时候,发现标准库定义的stack的函数太少,只有pop,push,empty,top,size,没有遍历,需要自己写.
程序需要不断修改才能完成.检查时发现:
显示错误处理时没有给出错误位置;当出现多个错误时,只能显示第一个错误.
完整代码:
#include
#include
#include
#include
#include
usingnamespacestd;
stringstr;/*源程序*/
charcharacter;/*源程序当前字符*/
intp=-1;/*源程序游标*/
stringtoken="";
stringblz[5]={"while","if","else","switch","case"};
intc;/*标示符种类编码*/
//intlength;/*输入源程序的长度*/
intstatue=0;/*判断词法分析完成*/
intcf[50];/*词法分析后的种类编码数组*/
intvalue1[50];/*cf对应常数*/
stringvalue2[50];/*cf对应变量名*/
intq=0;/*cf创建的游标*/
intm=0;/*cf语法分析的游标*/
stringblmb[50];/*变量名表*/
inta=0;/*变量名表的游标*/
stringcsb[50];/*常数表*/
intb=0;/*常数表的游标*/
staticintaction[10][7]=
{{3,-12,-11,2,-10,-3,1},
{-9,4,5,-8,-10,1000,-1},
{3,-7,-7,2,-6,-2,6},
{-9,104,104,-8,104,104,-1},
{3,-5,-5,2,-10,-5,7},
{3,-4,-4,2,-10,-4,8},
{-9,4,5,-9,9,-2,-1},
{-9,101,5,-9,101,101,-1},
{-9,102,102,-9,102,102,-1},
{-9,103,103,-9,103,103,-1}};
stackstatus;
stacksign;
stackyuyi;
intlrNum=0;/*分析表步骤号*/
charinputSign[7]={'i','+','*','(',')','#','E'};/*进栈符号*/
intgyLen[4]={3,3,3,1};
intyuyiNum=1;/*语义临时变量序号*/
stringv1,v2,v3,v4;
stringshowErr[12]=
{
"发现错误:
+前缺少变量或常量",/*0,e12*/
"发现错误:
*前缺少变量或常量",/*1,e11*/
"发现错误:
)前缺少对应(",/*2,e10*/
"发现错误:
连续的变量或常量,缺少+/*",/*3,e9*/
"发现错误:
(前缺少+/*",/*4,e8*/
"发现错误:
(后缺少常量或变量",/*5,e7*/
"发现错误:
()内无表达式",/*6,e6*/
"发现错误:
+后缺少变量或常量",/*7,e5*/
"发现错误:
*后缺少变量或常量",/*8,e4*/
"发现错误:
算数表达式为空",/*9,e3*/
"发现错误:
缺少对应)",/*10,e2*/
"发现错误:
语法分析错误"/*11,e1*/
};
voidgetonechar()
{
/*if(p>=length)
{
system("pause");
exit(0);
}*/
p++;
while(str[p]==''&&str[p+1]=='')
{
p++;
}
character=(char)str[p];
}
voidconcatenation()
{
token+=character;
}
boolletter()
{
if((character>='a'&&character<='z')||(character>='A'&&character<='Z'))
{
returntrue;
}
else
returnfalse;
}
booldigit()
{
if((character>='0'&&character<='9'))
{
returntrue;
}
else
returnfalse;
}
intreserve()
{
for(inti=0;i<5;i++)
{
if(token==blz[i])
{
returni+1;
}
}
return0;
}
voidretract()
{
p--;
}
/*变量名表*/
voidbuildlist1(stringtoken)
{
inti;
for(i=0;i{
if(token==blmb[i])
{
break;
}
}
if(i==a)
{
blmb[a]=token;
a++;
}
value2[q]=token;
}
/*常数表*/
voidbuildlist2(stringtoken)
{
inti;
for(i=0;i
{
if(token==csb[i])
{
break;
}
}
if(i==b)
{
csb[b]=token;
b++;
}
stringstreamss;
ss<intnum;
ss>>num;
value1[q]=num;
}
voidresolve()
{
token="";
getonechar();
switch(character)
{
case'a':
case'b':
case'c':
case'd':
case'e':
case'f':
case'g':
case'h':
case'i':
case'j':
case'k':
case'l':
case'm':
case'n':
case'o':
case'p':
case'q':
case'r':
case's':
case't':
case'u':
case'v':
case'w':
case'x':
case'y':
case'z':
while(letter()||digit())
{
concatenation();
getonechar();
}
retract();
c=reserve();
if(c==0)
{
buildlist1(token);
cout<<"(6,"<cf[q]=6;
q++;
}
else
{
cout<<"("<cf[q]=c;
q++;
}
break;
case'0':
case'1':
case'2':
case'3':
case'4':
case'5':
case'6':
case'7':
case'8':
case'9':
while(digit())
{
concatenation();
getonechar();
}
retract();
buildlist2(token);
cf[q]=7;
q++;
cout<<"(7,"<break;
case'+':
cf[q]=8;
q++;
cout<<"(8,+)"<break;
case'-':
cf[q]=9;
q++;
cout<<"(9,-)"<break;
case'(':
cf[q]=14;
q++;
cout<<"(14,()"<break;
case')':
cf[q]=15;
q++;
cout<<"(15,))"<break;
case'*':
cf[q]=10;
q++;
cout<<"(10,*)"<break;
case'<':
getonechar();
if(character=='=')
{
cf[q]=11;
q++;
cout<<"(11,LE)"<}
else
{
retract();
cf[q]=11;
q++;
cout<<"(11,LT)"<}
break;
case'=':
getonechar();
if(character==