编译原理实验—LR(1)分析法

一、实验内容

以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. 已知本次实验考虑文法如下:

(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

  1. 首先拓广文法,加入(0)S->E
  2. 然后需要构造 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");
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值