概述: LR分析法是一种自下而上进行规范归约的语法分析法,L指从左到右扫描输入符号串,R是指构造最右推导的逆过程。对大多数无二义性上下文无关文法描述的语言都可用它进行有效的分析。主要分析器有LR(0),SLR(1),LR(1),LALR(1): LR(0):在分析的每一步,只需根据当前栈顶状态而不必向前查看输入符号就能确定应采取的分析动作。所能分析的LR(0)文法要求文法的每一个LR(0)项目集中都不含冲突项目。 示例文法:
SLR(1):通过采用对含有冲突的项目集向前查看一个输入符号的办法来解决冲突的方法。 示例文法:
一、LR分析器由三个部分组成: (1)总控程序,也可以称为驱动程序。对所有的LR分析器总控程序都是相同的。 (2)分析表或分析函数,不同的文法分析表将不同,同一个文法采用的LR分析器不同时,分析表将不同,分析表又可以分为动作表(ACTION)和状态转换(GOTO)表两个部分,它们都可用二维数组表示。 (3)分析栈,包括文法符号栈和相应的状态栈,它们均是先进后出栈。分析器的动作就是由栈顶状态和当前输入符号所决定。
二、分析算法及思路: ①、数据结构: 二维数组action[][]存放ACTION表中的元素,二维数组goto[][]存放GOTO表中元素。字符数组vt[]存放终结符,字符数组vn[]存放非终结符。字符数组LR[]存放产生式。数组a[]实现状态栈,数组b[]实现符号栈。 ②、算法: 初始化,初始状态S0在分析栈栈顶,输入串W#的第一个符号读入a中。 while( ACTION[S,a] != acc) { if( ACTION[S,a] == Si) {状态i和输入符号a进栈;将下一个输入符号读入a中;} else if (ACTION[S,a] == rj) { 用第j条规则A –> a 归约;将|a|个状态和|a|个输入符号退栈;当前栈顶状态为S’,将A和GOTO[S’,A] = S’’进栈; Else if(ACTION[S,a]==ERROR) error(); } 三、程序源代码(SLR(1)) 对应文法:
分析表:
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#include<stdio.h> #include<string.h>
char *action[12][6]={"S5#",NULL,NULL,"S4#",NULL,NULL, /*ACTION表*/ NULL,"S6#",NULL,NULL,NULL,"acc", NULL,"r2#","S7#", NULL,"r2#","r2#", NULL,"r4#","r4#", NULL,"r4#","r4#", "S5#",NULL,NULL, "S4#",NULL,NULL, NULL,"r6#","r6#", NULL,"r6#","r6#", "S5#",NULL,NULL, "S4#",NULL,NULL, "S5#",NULL,NULL, "S4#",NULL,NULL, NULL,"S6#",NULL, NULL,"S11#",NULL, NULL,"r1#","S7#", NULL,"r1#","r1#", NULL,"r3#","r3#", NULL,"r3#","r3#", NULL,"r5#","r5#", NULL,"r5#","r5#"}; int goto1[12][3]={1,2,3, /*QOTO表*/ 0,0,0, 0,0,0, 0,0,0, 8,2,3, 0,0,0, 0,9,3, 0,0,10, 0,0,0, 0,0,0, 0,0,0, 0,0,0}; char vt[6]={'i','+','*','(',')','#'}; /*存放终结符*/ char vn[3]={'E','T','F'}; /*存放非终结符*/ char *LR[7]={"M->E#","E->E+T#","E->T#","T->T*F#","T->F#","F->(E)#","F->i#"};/*存放产生式*/
int a[20];//数组a实现状态栈 char b[20],c[20],c1;//数组b实现符号栈,数组c存放输入的字符串 int top1,top2,top3,top,m,n;
void main() { int g,h,i,j,k,l,p,y,z,count; char x,copy[20],copy1[20]; top1=0;top2=0;top3=0;top=0; a[0]=0;y=a[0];b[0]='#'; count=0;z=0;
//输入要识别的字符串 printf("请输入表达式/n"); do{ scanf("%c",&c1); c[top3]=c1; //字符数组c[10]存放输入的字符串 top3=top3+1;//最后top3=5 }while(c1!='#');
//输出分析结果 printf("步骤/t状态栈/t/t符号栈/t/t输入串/t/tACTION/tGOTO/n"); do{ y=z;m=0;n=0; /*y,z指向状态栈栈顶*/ g=top;j=0;k=0; x=c[top]; //将输入符号赋给x count++; printf("%d/t",count);//输出步骤序号
while(m<=top1) { /*输出状态栈*/ printf("%d",a[m]); m=m+1; }
printf("/t/t"); while(n<=top2) { /*输出符号栈*/ printf("%c",b[n]); n=n+1; }
printf("/t/t"); while(g<=top3) { /*输出输入串*/ printf("%c",c[g]); g=g+1; }
printf("/t/t"); while(x!=vt[j]&&j<=5) //获取当前x对应j的值 j++;
if(j==5&&x!=vt[j])//如果x不是终结符则报错 { printf("error/n"); return; }
if(action[y][j]==NULL){//???? printf("error/n"); return; } else strcpy(copy,action[y][j]);//
//////////////////////////////////////////////////////// if(copy[0]=='S') { /*处理移进*/ z=copy[1]-'0';//因为状态从0开始 top1=top1+1; top2=top2+1; a[top1]=z;//数组a实现状态栈 b[top2]=x;//数组b实现符号栈 top=top+1;//输入符号串数组c的顶 i=0; while(copy[i]!='#')//例 "S3#" 输出ACTION { printf("%c",copy[i]); i++; } printf("/n"); }
//////////////////////////////////////////////////////// if(copy[0]=='r') { /*处理归约*/ i=0; while(copy[i]!='#')//例 "S3#" 输出ACTION { printf("%c",copy[i]); i++; } h=copy[1]-'0';//因为状态从0开始
strcpy(copy1,LR[h]); while(copy1[0]!=vn[k]) //获取当前k值 k++; l=strlen(LR[h])-4;/// top1=top1-l+1; top2=top2-l+1; y=a[top1-1]; p=goto1[y][k]; a[top1]=p; b[top2]=copy1[0]; z=p; printf("/t"); printf("%d/n",p); }
}while(action[y][j]!="acc"); printf("acc/n"); } |
转载自:http://blog.csdn.net/zhouhuozhi/article/details/4144336