LR(1)分析法
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
LR(1)分析法
实验三LR(1)分析法
⼀、实验⽬的
构造LR(1)分析程序,利⽤它进⾏语法分析,判断给出的符号串是否为该⽂法识别的句⼦,了解LR(K)分析⽅法是严格的从左向右扫描,和⾃底向上的语法分析⽅法。
⼆、实验内容
对下列⽂法,⽤LR(1)分析法对任意输⼊的符号串进⾏分析:
(1)E- E+T
(2)E- E—T
(3)T- T*F
(4)T- T/F
(5)F- (E)
(6)F- i
三、LR(1)分析法实验设计思想及算法
(1)总控程序,也可以称为驱动程序。
对所有的LR分析器总控程序都是相同的。
(2)分析表或分析函数,不同的⽂法分析表将不同,同⼀个⽂法采⽤的LR分析器不同时,分析表将不同,分析表⼜可以分为动作表(ACTION)和状态转换(GOTO)表两个部分,它们都可⽤⼆维数组表⽰。
(3)分析栈,包括⽂法符号栈和相应的状态栈,它们均是先进后出栈。
分析器的动作就是由栈顶状态和当前输⼊符号所决定。
LR分析器由三个部分组成:
◆其中:SP为栈指针,S[i]为状态栈,X[i]为⽂法符号栈。
状态转换表⽤
GOTO[i,X]=j表⽰,规定当栈顶状态为i,遇到当前⽂法符号为X时应转向状态j,X为终结符或⾮终结符。
◆ACTION[i,a]规定了栈顶状态为i时遇到输⼊符号a应执⾏。
动作有四种
可能:
(1)移进:
action[i,a]= Sj:状态j移⼊到状态栈,把a移⼊到⽂法符号栈,其中i,j表⽰状态号。
(2)归约:
action[i,a]=rk:当在栈顶形成句柄时,则归约为相应的⾮终结符A,即⽂法中有A- B的产⽣式,若B的长度为R(即|B|=R),则从状态栈和⽂法符号栈中⾃顶向下去掉R个符号,即栈指针SP减去R,并把A移⼊⽂法符号栈内,
j=GOTO[i,A]移进状态栈,其中i为修改指针后的栈顶状态。
(3)接受acc:
当归约到⽂法符号栈中只剩⽂法的开始符号S时,并且输⼊符号串已结束即当前输⼊符是'#',则为分析成功。
(4)报错:
当遇到状态栈顶为某⼀状态下出现不该遇到的⽂法符号时,则报错,说明输⼊端不是该⽂法能接受的符号串。
四、实验要求
1、编程时注意编程风格:空⾏的使⽤、注释的使⽤、缩进的使⽤等。
2、如果遇到错误的表达式,应输出错误提⽰信息。
3、程序输⼊/输出实例:
输⼊⼀以#结束的符号串(包括+—*/()i#):在此位置输⼊符号串
输出过程如下:
步骤状态栈符号栈剩余输⼊串动作1 0 # i+i*i# 移进
4、输⼊符号串为⾮法符号串(或者为合法符号串)
五、实验步骤
1、根据流程图编写出各个模块的源程序代码上机调试。
2、编制好源程序后,设计若⼲⽤例对系统进⾏全⾯的上机测试,并通过所设计的LR(1)语法分析程序;直⾄能够得到完全满意的结果。
3、书写实验报告;实验报告正⽂的内容:
◆描述LR(1)语法分析程序的设计思想。
◆程序结构描述:函数调⽤格式、参数含义、返回值描述、函数功能;函数
之间的调⽤关系图。
◆详细的算法描述(程序执⾏流程图)。
◆给出软件的测试⽅法和测试结果。
◆实验总结(设计的特点、不⾜、收获与体会)。
源程序:
#include
#include
#include
#include
#include
using namespace std;
int k=0;
struct Node1
{
int state;
char vt;
int s;
}map[100];//当状态栈中的状态遇到终结符或者⾮终结符时应如何归约或移进
//⽤M代表S',⽤R代表E',W代表T',e代表空
int ss[12]={0,1,2,3,4,5,6,7,8,9,10,11};
char S[12][4]={"S0","S1","S2","S3","S4","S5","S6","S7","S8","S9","S10","S11"};
char R[12][4]={"r0","r1","r2","r3","r4","r5","r6"};
char G[10][10]={"M->E","E->E+T","E->T","T->T*F","T->F","F->(E)","F->i"};//存储⽂法中的产⽣式
char VN[6]={'E','T','F'};//存储⾮终结符
char VT[6]={'+','*','(',')','i','#'};//存储终结符
char Right[10][8]={"E","E+T","T","T*F","F","(E)","i"};
stackstak1,stak2;//stak⽤于状态栈,stak1⽤于符号栈
int
ACTION[12][6]={200,200,4,200,5,200,6,200,200,200,200,0,102,7,200,102,200,102,104,104,200,
104,200,104,200,200,4,200,5,200,106,106,200,106,200,106,200,200,4,200,5,200,200,200,4,200,5, 200,6,200,200,11,200,200,101,7,200,101,200,101,103,103,200,103,200,103,105,105,200,105,200, 105}; int
GOTO[12][3]={1,2,3,200,200,200,200,200,200,200,200,200,8,2,3,200,200,200,200,9,3,200,200,1
0,200,200,200,200,200,200,200,200,200,200,200,200};
int Find(int state,char vt)
{
int i;
for(i=0;i
{
if(map[i].vt==state && map[i].vt==vt)
return map[i].s;
}
return 200;
}
int empty1(int q[],int n)
{
for(int i=0;i
{
if(q[i]!=-1)return 1;break;
}
return 0;
}
int point(int stak[],int n)
{
int temp=0;
{
if(stak[i]==-1)break;
}
temp=i-1;
return temp;
}
void pop1(int q[],int n){
int temp;
temp=point(q,n);
q[temp]=-1;
}
void push1(int q[],int n,int e){ int temp;
temp=point(q,n);
q[temp+1]=e;
}
int top1(int q[],int n)
{
int temp;
temp=point(q,n);
return q[temp];
}
int vn_t(char c){
for(int i=0;i<6;i++)
if(VT[i]==c)return i;
for( i=0;i<6;i++)
if(VN[i]==c)return i;
return 100;
}
char * Analyse(char * word) {
int stak[12];
int p,q;
int h;
int act;
char output[10];
int i=1,j,l=strlen(word),k=0,m;
for(int d=0;d<12;d++)
stak[d]=-1;
while(!stak1.empty())
stak1.pop();
while(empty1(stak,12))
pop1(stak,12);
push1(stak,12,100);
stak1.push('#');
push1(stak,12,0);
printf("_________________________________________________________________________ _______\n"); printf("\n 对符号串%s的分析过程\n",word);
printf("步骤状态栈元素符号栈顶元素剩余输⼊串ACTION GOTO\n");
p=top1(stak,12);
h=stak1.top();
while(p!=100)
{
printf("%3d ",i++);
p=top1(stak,12);
q=point(stak,12);
for(i=1;i<=q;i++)
printf("%d ",stak[i]);
printf(" ");
h=stak1.top();
printf("%8c ",h);
for(j=k,m=0;j
output[m++]=word[j];
output[m]='\0';
printf("%10s",output);
vt_n1=vn_t(word[k]);
if(vt_n1==100){
printf("error!");//return "error";
}
act=ACTION[p][vt_n1]; if(act==0){
printf(" 接受\n");
return "SUCCESS";
}
else if(act<100){
push1(stak,12,act); stak1.push(word[k]);
k++;
printf(" %s",S[act]);
}
else if(act<200) {
act=act-100;
int len=strlen(Right[act]); char fina=G[act][0];
int w=vn_t(fina);
printf(" %s",R[w]);
for(i=0;i
{
pop1(stak,12);
stak1.pop();
}
p=top1(stak,12);
m=GOTO[p][w];
if(m<100)
{
push1(stak,12,m); printf(" %s",S[m]);
}
else return"error";
stak1.push(fina);
}
else if(act==200){
printf(" 没有可⽤的产⽣式\n");
return "error";
}
printf("\n");
}
if(strcmp(output,"#")!=0)
return "ERROR";
}
int main(){
int m,o,e;
int i,j,k=0,h;
char c;
char source[100];
printf("_________________________________________________________________________ _______\n"); //分析表
for(i=0;i<12;i++)
{
for(j=0;j<6;j++)
{
map[k].state=i;
map[k].vt=VT[j];
map[k].s=ACTION[i][j];
k++;
}
for(h=0;h<3;h++)
{
map[k].state=i;
map[k].vt=VN[h];
map[k].s=GOTO[i][h];
k++;
}
}
printf("\nLR(1)⽂法的分析表如下:\n\n");
printf("");
for(i=0;i<6;i++)
printf("%8c",VT[i]);
for(i=0;i<3;i++)
printf("%8c",VN[i]);
printf("\n");
for(i=0;i<12;i++)
{
printf("-----------------------------------------------------------------------------\n"); if(i>=10)printf("%d",i);
else
printf(" %d",i);
for(j=0;j<6;j++)
{
for( m=0;m
{
if(ss[i]==map[m].state && VT[j]==map[m].vt)
{
o=map[m].s;
if(o==0)
printf(" acc");
else if(o<100)
printf("%7s",S[o]);
else if(o<200){
o=o-100;
printf("%7s",R[o]);
}
else if(o==200)printf(" ");
break;
}
}
}
for(j=0;j<3;j++)
{
for(m=0;m
if(ss[i]==map[m].state&&VN[j]==map[m].vt)
{
o=map[m].s;
if(o<100)
printf("%8s",S[o]);
else if(o==200)
printf(" ");
break;
}
}
}
printf("\n");
}
/*预测分析程序
Analyse函数*/
//输⼊源⽂件串
printf("请输⼊待分析的字符串:\n");
scanf("%c",&c);
e=0;
while(c!='\n')
{
source[e]=c;
e++;
scanf("%c",&c);
}
source[e++]='\0';
printf("\n分析结果:%s\n\n",Analyse(source));
while(1);
return 0;
}
六、实验感想
此次课程设计中受益良多,从⼀开始的不知道从何⼊⼿,再到决定⽤的编程语⾔、设计程序流程、调试,最后到程序运⾏成功。
较好的⽂法分析器是功能全⾯的能⾃动构造其项⽬集和转换函数并构造分析表,然后进⾏分析的程序,但是实现LR(1)⽂法的⾃动分析程序对我来说很困难,最后决定直接输出分析表,⽽让程序实现对输⼊符号串的分析,在编程过程中也遇到了很多困难,如对某些终结符的动作或是规约函数的实现,最后通过请教同学和上⽹查找参考资料,都得到了解决。