一、实验内容
以LR(1)为代表的LR(K)分析方法是严格的从左向右扫描,和自底向上的语法分析方法,具体包括LR(0),LR(1),SLR(1),LALR(1)四类。不同于自上而下的LL(1)分析法,LR(K)分析过程基本有三大步:写出自动机(即 LR(0)或 LR(1)项集族,后面都称作自动机) -> 构造文法分析表-> 进行文法分析过程。第一步中的自动机有两种: LR(0)自动机和 LR(1)自动机。LR(0) 和 SLR文法分析用的是 LR(0)自动机,LR(1)和 LALR文法分析用的是 LR(1)自动机。而LR(1)自动机构造方法和LR(0)自动机的构造方法相同,只是多增加了向前搜索符号。
- 已知本次实验考虑文法如下:
(1)E->E+T
(2)E->E—T
(3)E->T
(4)T->T*F
(5)T->T/F
(6)T->F
(7)F->(E)
(8)F->i
- 首先拓广文法,加入(0)S->E
- 然后需要构造 LR(1)自动机,就是加入了一个圆点,圆点后的符号是即将处理的符号,如果圆点后是非终结符时,则要写出该终结符为产生式左部的所有产生式。反复以上过程,直到不再扩大。给它们编号并写出读入下一个符号(即圆点后的符号)会跳转到哪。LR(1)分析中的特色之一是考虑“展望符”,即当前状态可能遇到的下一个输入符号。这个符号将影响分析器的动作决策,特别是对于归约动作至关重要。确定的项目集、LR(1)自动机及LR(1)分析表分别如下图所示。
其中:为优化分析表的构建,使用LALR(1)实现对LR(1)文法的合理简化,既保留了强大的语法分析能力,又显著减少了状态数量和解析表的复杂性。具体来说,LALR(1)通过合并产生相同核心(即项集的第一分量)但搜索符不同的项集,减少了状态数量。
状态 | ACTION | GOTO | |||||||||
+ | - | * | / | ( | ) | i | # | E | T | F | |
0 | S4 | S5 | 1 | 2 | 3 | ||||||
1 | S6 | S7 | acc | ||||||||
2 | R3 | R3 | S8 | S9 | R3 | R3 | |||||
3 | R6 | R6 | R6 | R6 | R6 | R6 | |||||
4 | S4 | S5 | 10 | 2 | 3 | ||||||
5 | R8 | R8 | R8 | R8 | R8 | R8 | |||||
6 | S4 | S5 | 11 | 3 | |||||||
7 | S4 | S5 | 12 | 3 | |||||||
8 | S4 | S5 | 13 | ||||||||
9 | S4 | S5 | 14 | ||||||||
10 | S6 | S7 | S15 | ||||||||
11 | R1 | R1 | S8 | S9 | R1 | R1 | |||||
12 | R2 | R2 | S8 | S9 | R2 | R2 | |||||
13 | R4 | R4 | R4 | R4 | R4 | R4 | |||||
14 | R5 | R5 | R5 | R5 | R5 | R5 | |||||
15 | R7 | R7 | R7 | R7 | R7 | R7 |
二、实验步骤
首先,LR(1)语法分析器是一种自下而上的语法分析方法,它使用一个项目集族来表示输入串的上下文信息。在LR(1)语法分析过程中,我们使用一个状态栈来存储当前的状态,一个符号栈来存储输入串中的符号,以及一个动作表来确定下一步的操作。我们已经定义了action表、goto1表、非终结符集合vt、终结符集合vn和产生式集合LR。这些数据结构用于支持LR(1)语法分析过程,且与上述的LR(1)分析表相对应。相关的代码如下:
#include<stdio.h>
#include<string.h>
char *action[16][8]={NULL,NULL,NULL,NULL,"S4#",NULL,"S5#",NULL, /*ACTION表*/
"S6#","S7#",NULL,NULL,NULL,NULL,NULL,"acc",
"R3#","R3#","S8#","S9#",NULL,"R3#",NULL,"R3#",
"R6#","R6#","R6#","R6#",NULL,"R6#",NULL,"R6#",
NULL,NULL,NULL,NULL,"S4#",NULL,"S5#",NULL,
"R8#","R8#","R8#","R8#",NULL,"R8#",NULL,"R8#",
NULL,NULL,NULL,NULL,"S4#",NULL,"S5#",NULL,
NULL,NULL,NULL,NULL,"S4#",NULL,"S5#",NULL,
NULL,NULL,NULL,NULL,"S4#",NULL,"S5#",NULL,
NULL,NULL,NULL,NULL,"S4#",NULL,"S5#",NULL,
"S6#","S7#",NULL,NULL,NULL,"S15#",NULL,NULL,
"R1#","R1#","S8#","S9#",NULL,"R1#",NULL,"R1#",
"R2#","R2#","S8#","S9#",NULL,"R2#",NULL,"R2#",
"R4#","R4#","R4#","R4#","R4#","R4#","R4#","R4#",
"R5#","R5#","R5#","R5#","R5#","R5#","R5#","R5#",
"R7#","R7#","R7#","R7#","R7#","R7#","R7#","R7#",
};
int goto1[16][3]={1,2,3, /*QOTO表*/
0,0,0,
0,0,0,
0,0,0,
10,2,3,
0,0,0,
0,11,3,
0,12,3,
0,0,13,
0,0,14,
0,0,0,
0,0,0,
0,0,0,
0,0,0,
0,0,0,
0,0,0};
char vt[8]={'+','-','*','/','(',')','i','#'}; /*存放非终结符*/
char vn[3]={'E','T','F'}; /*存放终结符*/
char *LR[9]={"S->E#","E->E+T#","E->E-T#","E->T#","T->T*F#","T->T/F#","T->F#","F->(E)#","F->i#"};/*存放产生式*/
int a[16];
char b[16],c[16],c1;
int top1,top2,top3,top,m,n;
int main(){
int g,h,i,j,k,l,p,y,z,count;
char x,copy[16],copy1[16];
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;
top3=top3+1;
}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];
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<=7) j++;
if(j==7&&x!=vt[j]){
printf("error\n");
return 0;
}
if(action[y][j]==NULL){
printf("error\n");
return 0;
}
else
strcpy(copy,action[y][j]);
if(copy[0]=='S'){ /*处理移进*/
i=1;
z=0;
while(copy[i]!='#'){
z=z*10+copy[i]-'0';
i++;
}
top1=top1+1;
top2=top2+1;
a[top1]=z;
b[top2]=x;
top=top+1;
i=0;
while(copy[i]!='#'){
printf("%c",copy[i]);
i++;
}
printf("\n");
}
if(copy[0]=='R'){ /*处理归约*/
i=0;
while(copy[i]!='#'){
printf("%c",copy[i]);
i++;
}
h=copy[1]-'0';
strcpy(copy1,LR[h]);
while(copy1[0]!=vn[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");
}