编译原理课程设计C++语法分析器.docx
《编译原理课程设计C++语法分析器.docx》由会员分享,可在线阅读,更多相关《编译原理课程设计C++语法分析器.docx(19页珍藏版)》请在冰豆网上搜索。
![编译原理课程设计C++语法分析器.docx](https://file1.bdocx.com/fileroot1/2023-1/22/b359ec9b-e641-43a9-99b3-68d79c734fef/b359ec9b-e641-43a9-99b3-68d79c734fef1.gif)
编译原理课程设计C++语法分析器
福建农林大学计算机与信息学院
计算机类
课程设计报告
课程名称:
编译原理
课程设计题目:
语法分析器
姓名:
系:
计算机
专业:
计算机科学与技术
年级:
2009级
学号:
指导教师:
职称:
2010~2011学年第一学期
福建农林大学计算机与信息学院计算机类
课程设计结果评定
评语:
成绩:
指导教师签字:
任务下达日期:
评定日期:
目录
1正则表达式1
1.1正则表达式1
1.2确定化(化简)后的状态转换图1
1.3分析程序代码1
1.4程序运行截图4
1.5小结4
2LL
(1)分析5
2.1LL
(1)文法5
2.2LL
(1)预测分析表5
2.3分析程序代码5
2.4程序运行截图7
2.5小结7
3算符优先分析8
3.1算符优先文法8
3.2算符优先关系表8
3.3分析程序代码8
3.4程序运行截图10
3.5小结11
4LR分析12
4.1LR文法12
4.2LR分析表12
4.3分析程序代码12
4.4程序运行截图14
4.5小结14
参考文献:
14
1正则表达式
1.1正则表达式
(a|b)*(aa|bb)(a|b)*(注:
该正规式为示例,可更改)
1.2确定化(化简)后的状态转换图
1.3分析程序代码
#include
#include
using namespace std;
const int Max=20;
typedef struct ArcNode{
int adjvex;//该弧所指向的顶点的位置
char info; //权
struct ArcNode *nextarc;//指向下一条弧的指针
}ArcNode;
typedef struct VNode{
char data; //顶点信息
ArcNode *firstarc; //指向第一条依附该顶点的弧的指针
}VNode;
class Nfa
{
public:
Nfa(); //构造函数,初始化nfa
int FindAdj(char c); //返回c状态的在邻接表中的序号
void AlpAdd(char c); //向字母表集合中添加表中没有的新元素c
void InitVisit(); //初始化Visited集合
void e_closure(int index); //求单一状态c的e-闭包
void e_closure(int a[]); //重载的状态集合的e-闭包
void move(int I,char a); //单一状态I的a弧转换
void move(int I[],char a); //重载的状态集合的a弧转换
void Nfa:
:
Visit_I(int *Temp); //Visited转换为集合
void Insert(int I[],int a); //向状态集合中添加新元素
int TAdd(int I[]); //状态矩阵T中加入新状态集合
void Resault(int i);
void Nfa_Dfa();
private:
int K; //状态数
int T[Max][Max]; //状态子集矩阵
VNode AdjList[Max]; //nfa,邻接表的数据结构存储
VNode Dfa[Max]; //dfa
bool Visited[Max]; //存e-闭包结果
char Alp[Max]; //字母表,0号单元用于存放个数
};
Nfa:
:
Nfa()
{
K=Alp[0]=0;
char c;
string line;
ArcNode *p;
while(cin>>c&&c!
='#')
{
AdjList[K].data=c;
AdjList[K].firstarc=new ArcNode;
AdjList[K].firstarc->nextarc=NULL;
K++;
}
getline(cin,line);
while(getline(cin,line)&&line!
="#")
{
int index=FindAdj(line[0]);
if(index!
=-1)
{
p=AdjList[index].firstarc;
while(p->nextarc)
p=p->nextarc;
p->nextarc=new ArcNode;
p->nextarc->nextarc=NULL;
p->nextarc->adjvex=FindAdj(line[4]);
p->nextarc->info=line[2];
AlpAdd(p->nextarc->info);
}
}
cout<<"------------------------------"< cout<<"Initialization completely."< cout<<"K={";
for(int i=0;i cout< cout< cout<<"∑={";
for(int i=1;i<(int)Alp[0];i++)
cout< cout< for(int i=0;i {
p=AdjList[i].firstarc;
p=p->nextarc;
while(p)
{
cout<<"f("<info<<")="<adjvex<<" ";
p=p->nextarc;
}
if(inextarc)
#include
intexch[4][2]={1,2,3,2,1,3,3,3};
voidjudge(char*s)
{
intcur=0,i=0;
while(s[i])
{
if(s[i]-'a'>1||s[i]<'a')
break;
cur=exch[cur][s[i++]-'a'];
}
if(s[i]==0&&cur==3)
printf("%s√Right!
\n\n",s);
elseprintf("%s×Wrong!
\n\n",s);
}
intmain()
{
charstr[100];
while
(1)
{
printf("有限自动机,判断是否符合(a|b)*(aa|bb)(a|b)*\n");
printf("请输入字符串:
");
gets(str);
judge(str);
}
}
1.4程序运行截图
1.5小结
平时的学习需要通过实践来检验,通过这次实验我能发现自身存在的一些问题,并且加以改正,同时通过实验加强了自己的动手能力,并且增强了对于正则表达式的理解,并不只在于应试方面。
2LL
(1)分析
2.1LL
(1)文法
E→TE'(注:
该文法为示例,可更改)
E'→+TE'|ε
T→FT'
T'→*FT'|ε
F→(E)|i
2.2LL
(1)预测分析表
i
+
*
(
)
#
E
E→TE'
E→TE'
E'
E'→+TE'
E'→ε
E'→ε
T
T→FT'
T→FT'
T'
T'→ε
T'→*FT'
T'→ε
T'→ε
F
F→i
F→(E)
2.3分析程序代码
输入文法:
E→TE'(注:
该文法为示例,可更改)
E'→+TE'|ε
T→FT'
T'→*FT'|ε
F→(E)|i
代码:
#include
#include
chardata[5][6][10]={"12","","","12","","",
"","12+","","","-","-",
"34","","","34","","",
"","-","34*","","-","-",
"i","","",")0(","","",
};//第一维0-4分别代表EE'TT'F,第二维0-5代表i+*()#-代表ε
intexch(charch)
{
switch(ch)
{
case'i':
return0;
case'+':
return1;
case'*':
return2;
case'(':
return3;
case')':
return4;
case0:
return5;//字符串结束标志代表'#'.
default:
return-1;
}
}
voidjudge(char*s)
{
inttot=0,i=0,cur,k=exch(s[0]);
charsta[100];;
sta[++tot]='0';
while(tot>0)
{
cur=sta[tot]-'0';
if(s[i]=='')//去空格
++tot,k=exch(s[++i]);
elseif(cur+'0'==s[i])//推导出相同字符,出栈
k=exch(s[++i]);
elseif(k<0||data[cur][k][0]==0)//踩空,或者出现非法字符
break;
elseif(data[cur][k][0]!
='-')//不是ε,进栈继续推导
{
strcpy(sta+tot,data[cur][k]);
tot+=strlen(data[cur][k]);
}
--tot;
}
if(tot==0)
printf("%s√Right!
\n\n",s);
elseprintf("%s×Wrong!
\n\n",s);
}
intmain()
{
charstr[100];
printf("判断符号串是否符合文法:
\n\n\tE→TE'\n\t");
printf("E'→+TE'|ε\n\tT→FT'\n\tT'→*FT'|ε\n\tF→(E)|i\n\n");
while(printf("输入符号串:
")&&gets(str)&&str[0])
judge(str);
return0;
}
2.4程序运行截图
2.5小结
实践实践验证里的唯一标准,这次课程设计主要巩固了我对LL
(1)文法的深刻认识,掌握程序实现文法判断、链表的使用等多种问题的基本方法,进一步提高了综合运用所学知识的能力。
3算符优先分析
3.1算符优先文法
E→T|E+T|E-T(注:
该文法为示例,可更改)
T→F|T*F|T/F
F→(E)|i
3.2算符优先关系表
+
-
*
/
(
)
i
#
+
>
>
<
<
<
>
<
>
-
>
>
<
<
<
>
<
>
*
>
>
>
>
<
>
<
>
/
>
>
>
>
<
>
<
>
(
<
<
<
<
<
=
<
)
>
>
>
>
>
>
i
>
>
>
>
>
>
#
<
<
<
<
<
<
=
3.3分析程序代码
#include
#include
charcom[8][8]={'>','>','<','<','<','>','<','>',
'>','>','<','<','<','>','<','>',
'>','>','>','>','<','>','<','>',
'>','>','>','>','<','>','<','>',
'<','<','<','<','<','=','<','',
'>','>','>','>','-','>','-','>',
'>','>','>','>','-','>','-','>',
'<','<','<','<','<','-','<','=',
};//0-7分别代表 +-*/()i#
intexch(charch)
{
switch(ch)
{
case'+':
return0;
case'-':
return1;
case'*':
return2;
case'/':
return3;
case'(':
return4;
case')':
return5;
case'i':
return6;
case0:
return7;//字符串结束标志代表‘#’
default:
return-1;
}
}
charexpre[6][5]={"N+N","N-N","N*N","N/N","(=N)","i"};//为了挽回因忽略语法变量而产生的错误,在规约时检验终结符是否带了应有的操作对象。
intconfirm(char*sta,intt)//检验终结符是否带了应有的变量。
{
inti,n=t;
while(n>0&&sta[n]!
='<')
n--;
if(n>0)
for(i=0;i<6;i++)
if(memcmp(expre[i],sta+n+1,sizeof(char)*(t-n))==0)
{
sta[n]='N';//说明是有应有的操作对象,所以进行规约。
returnn;
}
return0;
}
voidjudge(char*s)
{
charsta[100];
inttot=0,cur,m,k,i=0;
sta[++tot]=0;
while(tot>0)
{
m=tot;
do{
cur=exch(sta[m--]);
}while(cur<0);//要忽略变量,直接对终结符进行比较优先级。
while(s[i]=='')//跳过空格
i++;
k=exch(s[i]);
if(cur==k&&cur==7)
tot=0;//规约成功,结束标记。
elseif(k<0||com[cur][k]=='-')//踩空或者输入非法符
tot=-1;
elseif(com[cur][k]!
='>')//遇到‘>',准备规约
{
if(sta[tot]=='N')//这里一个小问题就是变量N是要在'<'左边还是右边呢,这要取决于终结符是什么,左右两边有几个变量,不过针对本程序方法,只需全部放在右边。
{
sta[tot]=com[cur][k];
sta[++tot]='N';
}
else
sta[++tot]=com[cur][k];
sta[++tot]=s[i++];
}
elseif((tot=confirm(sta,tot))==0)//检验终结符是否带了应有的变量。
没有,就规约失败
tot=-1;
}
if(tot==0)
printf("%s√Right!
\n\n",s);
elseprintf("%s×Wrong!
\n\n",s);
}
intmain()
{
charstr[100];
printf("判断符号串是否符合文法:
\n\n\tE→T|E+T|E-T\n\tT→F|T*F|T/F\n\tF→(E)|i\n\n");
while(printf("输入符号串:
")&&gets(str)&&str[0])
judge(str);
return0;
}
3.4程序运行截图
3.5小结
通过这次课程设计,我发现之前没发现的问题。
算符优先分析方法有一定的局限性由于算符优先分析法去掉了单非终结符之间的归约,尽管在分析过程中,当决定是否为句柄时采取一些检查措施,但仍难完全避免把错误的句子得到正确的归约。
4LR分析
4.1LR文法
(0)S'→S(注:
该文法为示例,可更改)
(1)S→BB
(2)B→aB
(3)B→b
4.2LR分析表
ACTION
GOTO
a
b
#
S
B
0
S3
S4
1
2
1
acc
2
S3
S4
5
3
S3
S4
6
4
r3
r3
r3
5
r1
r1
r1
6
r2
r2
r2
4.3分析程序代码
#include
#include
intaction[7][5]={
3,4,0,1,2,
0,0,-4,0,0,
3,4,0,0,5,
3,4,0,0,6,
-3,-3,-3,0,0,
-1,-1,-1,0,0,
-2,-2,-2,0,0
};//负数代表此时可规约,即r,第二维0-5分别代表ab#SB,-4表示acc
intcnt[]={0,'S'*10+2,'B'*10+2,'B'*10+1};//表示ri的产生式的左边变量和右边长度
intexch(charch)
{
switch(ch)
{
case'a':
return0;
case'b':
return1;
case'#':
case'\0':
return2;//字符串结束标志代表‘#'.
case'S':
return3;
case'B':
return4;
default:
return-1;
}
}
voidjudge(char*s)
{
intint_stack[100],ti=0,tc=0,i=1,cur,k=exch(s[0]);
charchar_stack[100];
int_stack[++ti]=0;
while(ti>0)
{
cur=int_stack[ti];
if(k<0||action[cur][k]==0)//踩空,或者出现非法字符
ti=-1;
elseif(action[cur][k]>0)//入栈,等待规约
{
int_stack[++ti]=action[cur][k];//数字栈
char_stack[++tc]=s[i];//字符栈
k=exch(s[i++]);
}
elseif(action[cur][k]==-4)//规约完成,说明是符合要求
ti=0;
else//可以规约
{
--i;//说明输入的字符s[i-1]还没有用,此时它不进栈,故i--,以便下次取到的是要s[i-1];
ti-=cnt[-action[cur][k]]%10;//取ri的长度,出栈这么多个的字符
tc-=cnt[-action[cur][k]]%10;
char_stack[++tc]=cnt[-action[cur][k]]/10;//取产生式的左边变量,进行规约。
k=exch(char_stack[tc]);
}
}
if(ti==0)
printf("%s√Right!
\n\n",s);
elseprintf("%s×Wrong!
\n\n",s);
}
intmain()
{
charstr[100];
printf("判断符号串是否符合如下文法:
\n\n\tS→BB\n\tB→aB\n\tB→b\n\n");
while(printf("输入符号串:
")&&gets(str)&&str[0])
judge(str);
return0;
}
4