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;
}
输出结果示例如下: