LL(1)分析法的功能是利用LL(1)控制程序根据显示栈栈顶内容、向前看符号以及Ll(1)分析表,对输入符号串自上而下的分析过程。可通过消除左递归、提取左因子把非LL(1)文法改造成LL(1)文法。在LL( 1) 预测分析程序设计过程中,最重要的两个问题是预测分析表的构造和相关数据结构的设计。而预测分析表的构造首先必须计算文法每个非终结符的FIRST集和FOLLOW集。数据结构和算法实现具体实现如下:
1、数据结构:
数组A实现分析栈,数组B存储剩余分析串;一维数组V1存放文法终结符,一维数组V2存放文法非终结符。将产生式类型定义为结构体变量。
2、算法:
a、首先将‘ # ’压入堆栈中, 将开始符号S 也压入堆栈中,读取第一个输入符号到a.
循环执行b--d:
b、栈顶符号弹出放入X 中,如果X 为终结符号:当X = = a ! =‘ # ’时,表明成功匹配a 符号,然后读取下一个符号到a ,否则出错;当X = = a =‘ # ’时,分析结束,接受句子,跳出循环.
c、如果X ! = a ,进行出错处理.
d、如果X 为非终结符号, 则查分析表M :如果M[ X , a ]为空, 进行出错处理; 如果M [X , a ]=‘X1 X2 X3...Xn’, 则将右部Xn...X2 X1 反序压入堆栈中.
本程序分析的文法:
e// E -> TG R(O)
g// G -> +TG R(1)
g1// G -> ε R(2)
t// T -> FS R(3)
s// S -> *FS R(4)
s1// S -> ε R(5)
f// F -> (E) R(6)
f1// F -> i R(7)
g2// G -> -TG R(8)
s2// S -> /FS R(9)
分析句子:E->TG->FSG->iSG->i/FSG->i/iSG->i/iG->i/i-TG->i/i-FSG->i/i-iSG->i/i-iG->i/i-i
手工构造的预测分析表:
| i | + | * | ( | ) | - | / | # |
E | R(0) | Error | Error | R(0) | Error | Error | Error | Error |
G | Error | R(1) | Error | Error | R(2) | R(8) | Error | R(2) |
T | R(3) | Error | Error | R(3) | Error | Error | Error | Error |
S | Error | R(5) | R(4) | Error | R(5) | R(5) | R(9) | R(5) |
F | R(7) | Error | Error | R(6) | Error | Error | Error | Error |
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<dos.h> char A[20];/*分析栈*/ char B[20];/*剩余串*/ char v1[20]={'i','+','*','(',')','-','/','#'};/*终结符 */ char v2[20]={'E','G','T','S','F'};/*非终结符 */
int j=0,b=0,top=0,l;/*L为输入串长度 */
typedef struct type/*产生式类型定义 */ { char origin;/*大写字符 */ char array[5];/*产生式右边字符 */ int length;/*字符个数 */ }type;
type e,t,g,g1,g2,s,s1,s2,f,f1;/*结构体变量 */ type C[10][10];/*预测分析表 */
void print()/*输出分析栈 */ { int a;/*指针*/ for(a=0;a<=top+1;a++) printf("%c",A[a]); printf("/t/t"); }/*print*/
void print1()/*输出剩余串*/ { int j; for(j=0;j<b;j++)/*输出对齐符*/ printf(" "); for(j=b;j<=l;j++) printf("%c",B[j]); printf("/t/t/t"); }/*print1*/
void main() { int m,n,k=0,flag=0,finish=0; char ch,x; type cha;/*用来接受C[m][n]*/ /*把文法产生式赋值结构体*/ e.origin='E'; strcpy(e.array,"TG"); e.length=2;
t.origin='T'; strcpy(t.array,"FS"); t.length=2;
g.origin='G'; strcpy(g.array,"+TG"); g.length=3;
g1.origin='G'; g1.array[0]='^'; g1.length=1;
g2.origin='G'; strcpy(g2.array,"-TG"); g2.length=3;
s.origin='S'; strcpy(s.array,"*FS"); s.length=3;
s1.origin='S'; s1.array[0]='^'; s1.length=1;
s2.origin='S'; strcpy(s2.array,"/FS"); s2.length=3;
f.origin='F'; strcpy(f.array,"(E)"); f.length=3;
f1.origin='F'; f1.array[0]='i'; f1.length=1;
for(m=0;m<=4;m++)/*初始化分析表*/ for(n=0;n<=7;n++) C[m][n].origin='N';/*全部赋为空*/ /*填充分析表*/ C[0][0]=e;C[0][3]=e; C[1][1]=g;C[1][4]=g1;C[1][7]=g1;C[1][5]=g2; C[2][0]=t;C[2][3]=t; C[3][1]=s1;C[3][2]=s;C[3][4]=C[3][5]=C[3][7]=s1;C[3][6]=s2; C[4][0]=f1;C[4][3]=f; printf("提示:本程序只能对由'i','+','*','(',')'构成的以'#'结束的字符串进行分析,/n"); printf("请输入要分析的字符串:"); do/*读入分析串*/ { scanf("%c",&ch); if ((ch!='i') &&(ch!='+') &&(ch!='*')&&(ch!='(')&&(ch!=')')&&(ch!='#')&&(ch!='-')&&(ch!='/')) { printf("输入串中有非法字符/n"); exit(1); } B[j]=ch; j++; }while(ch!='#');
l=j;/*分析串长度*/ ch=B[0];/*当前分析字符*/ A[top]='#'; A[++top]='E';/*'#','E'进栈*/
printf("步骤/t/t分析栈 /t/t剩余字符 /t/t所用产生式 /n"); do { x=A[top--];/*x为当前栈顶字符*/ printf("%d",k++); printf("/t/t");
for(j=0;j<=7;j++)/*判断是否为终结符*/ if(x==v1[j]) { flag=1; break; } if(flag==1)/*如果是终结符*/ { if(x=='#') { finish=1;/*结束标记*/ printf("acc!/n");/*接受 */ getchar(); getchar(); exit(1); }/*if*/ if(x==ch) { print(); print1(); printf("%c匹配/n",ch); ch=B[++b];/*下一个输入字符*/ flag=0;/*恢复标记*/ }/*if*/ else/*出错处理*/ { print(); print1(); printf("%c出错/n",ch);/*输出出错终结符*/ exit(1); }/*else*/ }/*if*/ else/*非终结符处理*/ { for(j=0;j<=4;j++) if(x==v2[j]) { m=j;/*行号*/ break; } for(j=0;j<=7;j++) if(ch==v1[j]) { n=j;/*列号*/ break; } cha=C[m][n]; if(cha.origin!='N')/*判断是否为空*/ { print(); print1(); printf("%c->",cha.origin);/*输出产生式*/ for(j=0;j<cha.length;j++) printf("%c",cha.array[j]); printf("/n"); for(j=(cha.length-1);j >=0;j--)/*产生式逆序入栈*/ A[++top]=cha.array[j]; if(A[top]=='^')/*为空则不进栈*/ top--; }/*if*/ else/*出错处理*/ { print(); print1(); printf("%c出错/n",x);/*输出出错非终结符*/ exit(1); }/*else*/ }/*else*/ }while(finish==0); }/*main*/
|