语法分析之LL(1)分析法

LL(K)分析方法是一种自顶向下的分析技术,这种分析方法是从左到右扫描源程序(输入串),同时从识别符号开始生成句子的最左推导,向前看K个符号,便能确定当前应选用怎样的规则。当K=1时,即是LL(1)分析法。

LL(1)分析法中很重要的一块内容是分析矩阵的构造,这个分析矩阵是进行语法分析的依据,每一步都要靠它来决定如何进行,分析矩阵的构造方法如下:

1.   对于A→ab(a∈Vt),则令LL(A,a)=R(b)/N

2.   对于A→Db(D∈Vn),且Select(A→Db)={b1,b2,…bn},则令LL(A,bi)=R(Db)/P(i=1,2,…n)

3.   对于A→є,且Select(A→є)={b1,b2,…bn},则令LL(A,bi)=R(є)/P(i=1,2,…n)

4.   a∈Vt,a不出现在规则右部的首部,则令LL(a,a)=R(є)/N

5.   #,则令LL(#,#)=acc

6.   其它情况出错,在分析矩阵中可用空白表示


看如下的示例:



其分析矩阵构造如下:



对于输入串i+i*i的分析过程如下:



在此,只用程序来实现在特定的分析矩阵的前提下,实现的语法分析,源程序如下:

#include "stdio.h"
#include "stdlib.h"
#include "string.h"

typedef struct E
{
	char *de;//存储产生式
	char *re;//要替换的表达式
	int flag;//是否要消去,为0是不消去,为1是消去
}E;

//栈结构
typedef struct Stack
{
	char *elem;
	int top;
	int size;
}Stack;

E T[7][6];//分析表

Stack as;//分析栈
char rs[30];//剩余字符串

char vn[7]={'E','G','T','S','F',')','#'};//非终结符
char vt[6]={'i','+','*','(',')','#'};//终结符

int p=0;//剩余字符串的指针

//根据终结符和非终结符找到两者在分析表中所对应的位置
E get(char a,char r)
{
	int i;
	int j;
	for(i=0;i<6;i++)
		if(a==vn[i])
			break;
	for(j=0;j<6;j++)
		if(r==vt[j])
			break;
	return T[i][j];
}

//初始化栈
void initStack(Stack *S)
{
	S->elem=(char *)malloc(30*sizeof(char));
	S->top=-1;
	S->size=30;
}

//入栈
void push(Stack *S,char x)
{
	if(S->top==S->size-1)  
	{
		printf("Stack Overflow!\n");
		return;
	}
    S->elem[++S->top]=x;
}  
   
//出栈
char pop(Stack *S)
{  
    char x;
    if(S->top==-1)
	{
		printf("Stack Empty!\n");
		return 0;
	}
    x=S->elem[S->top--];
    return x;
}

//取栈顶元素,但是不删除栈顶元素
char top(Stack *S)
{
    char x;
    if(S->top==-1)
	{
		printf("Stack Empty!\n");
		return 0;
	}
    x=S->elem[S->top];
    return x;
}

//打印栈中和剩余字符串中的数据
void print(Stack *S)
{
	int i;
	unsigned int j;

	for(i=0;i<=S->top;i++)
		printf("%c",S->elem[i]);
	printf("\t\t");
	
	for(i=0;i<p;i++)
		printf(" ");
	for(j=p;j<strlen(rs);j++)
		printf("%c",rs[j]);
	printf("\t");
}

void init()
{
	int i,j;

	for(i=0;i<7;i++)
		for(j=0;j<6;j++)
		{
			T[i][j].de="WA";
			T[i][j].re="WA";
			T[i][j].flag=0;
		}

	T[0][0].de="E->TG";
	T[0][0].re="TG";
	T[0][0].flag=0;

	T[0][3].de="E->TG";
	T[0][3].re="TG";
	T[0][3].flag=0;

	T[1][1].de="G->+TG";
	T[1][1].re="TG";
	T[1][1].flag=1;

	T[1][4].de="G->ε";
	T[1][4].re="";
	T[1][4].flag=0;

	T[1][5].de="G->ε";
	T[1][5].re="";
	T[1][5].flag=0;

	T[2][0].de="T->FS";
	T[2][0].re="FS";
	T[2][0].flag=0;

	T[2][3].de="T->FS";
	T[2][3].re="FS";
	T[2][3].flag=0;

	T[3][1].de="S->ε";
	T[3][1].re="";
	T[3][1].flag=0;

	T[3][2].de="S->*FS";
	T[3][2].re="FS";
	T[3][2].flag=1;

	T[3][4].de="S->ε";
	T[3][4].re="";
	T[3][4].flag=0;

	T[3][5].de="S->ε";
	T[3][5].re="";
	T[3][5].flag=0;

	T[4][0].de="F->i";
	T[4][0].re="";
	T[4][0].flag=1;

	T[4][3].de="F->(E)";
	T[4][3].re="E)";
	T[4][3].flag=1;

	T[5][4].de="";
	T[5][4].re="";
	T[5][4].flag=1;

	T[6][5].de="AC";
	T[6][5].re="AC";
	T[6][5].flag=0;
}

char ch;
int i=0;

int main()
{
	freopen("in.txt","r",stdin);
	init();
	initStack(&as);

	push(&as,'#');
	push(&as,'E');

	while(scanf("%c",&ch))
	{
		rs[i++]=ch;
		if(ch=='#')
			break;
	}

	i=0;//步骤数
	while(as.top!=-1)
	{
		char a;
		E elem;

		i++;
		printf("%d\t",i);//打印步骤
		print(&as);//打印分析栈和剩余串
		a=pop(&as);
		elem=get(a,rs[p]);
		
		printf("%s\n",elem.de);//打印产生式

		if(elem.de!="WA" && elem.de!="AC")
		{
			if(elem.re!="")
			{
				push(&as,elem.re[1]);
				push(&as,elem.re[0]);
			}

			if(elem.flag)
				p++;
		}
		else
			break;
	}

	return 0;
}

输出结果示例如下:




  • 3
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值