LL(1)语法分析程序的设计思路还是很清晰的,按照教材上的算法公式去实现即可。
找出了以前在学校的时候写的一个实现,在VC6上编译的。当时写的比较稚嫩,程序也并不完美,有机会再完善下。
使用例子
输入产生式的个数:5
请输入各产生式:
说明:若有空产生式A->ε,则ε不必打出来;直接输入A->
第1个产生式:E->iF
第2个产生式:F->+E
第3个产生式:F->
第4个产生式:i->1
第5个产生式:i->2
请输入语句:
1+2+1
分析过程如下所示:
------------------------------------------------------------
分析栈 │ Rest │ 产生式|匹配
------------------------------------------------------------
#E | 1+2+1# | E->iF
#Fi | 1+2+1# | i->1
#F1 | 1+2+1# | 1 匹配
#F | +2+1# | F->+E
#E+ | +2+1# | + 匹配
#E | 2+1# | E->iF
#Fi | 2+1# | i->2
#F2 | 2+1# | 2 匹配
#F | +1# | F->+E
#E+ | +1# | + 匹配
#E | 1# | E->iF
#Fi | 1# | i->1
#F1 | 1# | 1 匹配
#F | # | F->ε
# | # | 分析成功
------------------------------------------------------------
#include <string.h>
#include <iostream.h>
#include <malloc.h>
const int STACK_INIT_SIZE = 30; //存储空间初始分配量
const int STACKINCREMENT = 10; //存储空间分配增量
const int VTNUM = 10;
const int VNNUM = 10;
const int prNUM = 15;
const int pLength = 9;
const int MAXNUM = 25;
int pnum;
int vnum;
char VT[VTNUM]; // 终结符
char VN[VNNUM]; // 非终结符
char pr[prNUM][pLength]; // 产生式
bool VEmpty[VNNUM];
char VFirst[VNNUM][VTNUM + 1];
char VFollow[VNNUM][VTNUM + 1];
char VSelect[MAXNUM][VTNUM + 3];
typedef char SElemType, ElemType;
typedef struct {
SElemType * base;
SElemType * top;
int stacksize;
}SqStack;
bool InitStack (SqStack &S);
SElemType GetTop (SqStack S);
bool Push (SqStack &S, SElemType e);
bool Pop (SqStack &S);
bool InitStack (SqStack &S) // 构建一个空栈 S
{
S.base = (SElemType *)malloc(STACK_INIT_SIZE * sizeof(ElemType));
if(!S.base) return false; //exit (OVERFLOW); // 存储分配失败
S.top = S.base;
S.stacksize = STACK_INIT_SIZE;
return true;
}
SElemType GetTop (SqStack S)
{ // 若不为空,用e返回栈顶元素
if(S.top == S.base) // if(S.top = S.base) 错错错
{
return false;
}
SElemType e = *(S.top - 1);
return e;
}
bool Push (SqStack &S, SElemType e) // 入栈
{ //插入元素 e 为新的栈顶元素
if(S.top - S.base >= S.stacksize)
{
S.base = (ElemType * )realloc(S.base,
(S.stacksize + STACKINCREMENT) * sizeof(ElemType));
if(!S.base) return false;//exit(OVERFLOW);
S.top = S.base + S.stacksize;
S.stacksize += STACKINCREMENT;
}
*S.top ++ = e;
return true;
}
bool Pop (SqStack &S) // 出栈
{ // 删除 S 栈顶元素
if(S.top == S.base) return false;
--S.top;
return true;
}
int StackEmpty(SqStack S)
{
if(S.top == 0) return 1;
else return 0;
}
void PrintStack(SqStack S)
{
SElemType * p;
p = S.top - 1;
while (1 > 0)
{
cout<<*p;
if (p == S.base)
{
return;
}
p--; ///
}
}
void RePrintStack(SqStack S)
{
SElemType *p;
p = S.base;
while (p != S.top)
{
cout<<*p;
p++;
}
}
int IsVN(char ch)
{
for (int i = 0; i < VNNUM, VN[i] != '\0'; i++)
{
if (ch == VN[i])
{
return i;
}
}
return -1;
}
int IsVT(char ch)
{
for (int i = 0; i < VTNUM, VT[i] != '\0'; i++)
{
if (ch == VT[i])
{
return i;
}
}
return -1;
}
void GetVN(char a) // 从一条产生式中提取出 非终结符
{
for (int i = 0; i < VNNUM; i++)
{
if (a == VN[i] || VN[i] == '\0')
{
break;
}
// VN[i] = a;
}
VN[i] = a;
}
void GetVT(char *p) // 从一条产生式中提取出 终结符
{
for (int j = 3; j <= pLength, p[j] != '\0'; j++)
{
char a = p[j];
if (IsVN(a) >= 0)
{
continue; /
}
for (int i = 0; i < VTNUM; i++)
{
if (a == VT[i] || VT[i] == '\0')
{
break;
}
}
if (a != 'ε') // ε不是终结符
{
VT[i] = a;
}
}
}
void MayEmpty()
{
int code, num, cc = 0;
for (int i = 0; i < VNNUM; i++)
{
VEmpty[i] = false;
}
for (int j = 1; j <= pnum; j++) // 初扫描
{
if (pr[j][3] == 'ε' || pr[j][3] == '\0')
{
code = IsVN(pr[j][0]);
VEmpty[code] = true;
}
// VEmpty[code] = true;
}
while (1 < 5) // 检查次数 有待进一步 确认
{
for (int i = 1; i <= pnum; i++)
{
code = IsVN(pr[i][0]);
if (VEmpty[code])
{
continue; //
}
for (int j = 3; j < pLength, pr[i][j] != '\0'; j++)
{
code = IsVN(pr[i][j]);
if (code < 0)
{
break;
}
if (!VEmpty[code])
{
break;
}
}
if (pr[i][j] == '\0')
{
code = IsVN(pr[i][0]);
VEmpty[code] = true;
}
}
num = 0;
for ( i = 0; i < VNNUM; i++)
{
if (VEmpty[i] == true)
{
num++;
}
}
if (num == cc)
{
return;
}
cc = num;
}
}
void Addch(char *p, char *from) // 求并集
{ // *p在增长,应该为一个数组
int i = strlen(p);
int j = strlen(from);
int k = i;
for (int a = 0; a < j; a++)
{
for (int b = 0; b < i; b++)
{
if (from[a] == p[b])
{
break;
}
}
if (b == i)
{
p[k++] = from[a];
}
}
}
void Addchar(char *to, char a)
{
int i = strlen(to);
for (int j = 0; j < i; j++)
{
if (to[j] == a)
{
break;
}
}
if (j == i)
{
to[i] = a;
}
}
void First(char ch) // 求非终结符ch 的First集
{
int a, b, code;
char c;
code = IsVN(ch);
for (int i = 1; i <= pnum; i++)
{
if (pr[i][0] != ch )
{
continue;
}
int L = strlen( pr[i] );
for (int k = 3; k < L; k++)
{
c = pr[i][k];
a = IsVT( pr[i][k] );
b = IsVN( pr[i][k] );
if ( b >= 0 ) // A->Bc A->BCD
{
Addch(VFirst[code], VFirst[b] );
if ( !VEmpty[b] ) // 如果不能推出空
{
break;
}
}
else // A->c
{
Addchar( VFirst[code], c );
break;
}
}
}
}
void Follow(char vn) // A->aBc
{
int a, b, c;
c = IsVN(vn);
for (int i = 1; i <= pnum; i++)
{
a = IsVN(pr[i][0] );
int L = strlen( pr[i] );
for (int j = 3; j < L; j++)
{
if ( pr[i][j] == vn )
{
for (int k = j + 1; k < L; k++)
{
// a = IsVT(pr[i][k] );
b = IsVN(pr[i][k] );
if (b < 0)
{
Addchar(VFollow[c], pr[i][k] );
break;
}
else
{
Addch(VFollow[c], VFirst[b] );
if (!VEmpty[b] )
{
break;
}
}
}
if (k == L)
{
Addch(VFollow[c], VFollow[a] );
}
}
}
}
}
void Select(int c) // 求第c条产生式的Select集
{
int a, b = IsVN(pr[c][0]);
int L = strlen(pr[c] );
for (int i = 3; i < L; i++)
{
a = IsVN(pr[c][i] );
if (a < 0)
{
Addchar(VSelect[c], pr[c][i] );
// i--; //
break;
}
else
{
Addch(VSelect[c], VFirst[a] );
if (!VEmpty[a])
{
break;
}
}
}
if (i == L) // 用来判断 for 循环时有无中断,如果for()顺利执行,则有 i == L
{
Addch(VSelect[c], VFollow[b] );
}
}
void GetSelect()
{
for (int i = 1; i <= pnum; i++)
{
Select(i);
}
}
void GetFirst()
{
int a = 0, num = 0;
while (1 > 0)
{
for (int i = 0; i < vnum; i++)
{
First(VN[i] );
}
num = 0;
for (int c = 0; c < VNNUM; c++)
{
for (int d = 0; d < VNNUM + 1; d++)
{
if (VFirst[c][d] == '\0' )
{
continue;
}
num++;
}
}
if (a == num)
{
return;
}
a = num;
}
}
void GetFollow()
{
int a = 0, num = 1;
while (1 > 0)
{
for (int i = 0; i < vnum; i++)
{
Follow(VN[i] );
}
num = 0; /
for (int c = 0; c < VNNUM; c++)
{
for (int d = 0; d < VNNUM + 1; d++)
{
if (VFirst[c][d] == '\0' )
{
continue;
}
num++;
}
}
if (a == num)
{
return;
}
a = num;
}
}
void Inite()
{
cout<<"输入产生式的个数:";
cin>>pnum;
cin.get();
cout<<"请输入各产生式:\n";
cout<<"\n说明:若有空产生式A->ε,则ε不必打出来;直接输入A->\n\n";
int i = 1;
while ( i <= pnum )
{
cout<<"\n第"<<i<<"个产生式:";
int k = 0;
char a = cin.get();
while (a != '\n')
{
if (a != ' ')
{
pr[i][k++] = a;
}
a = cin.get();
}
pr[i][k++] = '\0';
GetVN( pr[i][0] );
i++;
}
// 提取出终结符
for (int j = 1; j <= pnum; j++)
{
GetVT( &pr[j][0] );
VSelect[j][0] = pr[j][0];
}
for (j = 0; j < VNNUM; j++)
{
if (VN[j] == '\0' )
{
break;
}
}
vnum = j;
VFollow[0][0] = '#';
}
void Predict()
{
SqStack see, sin;
InitStack(see);
InitStack(sin);
char c = VN[0];
Push(see, '#');
Push(see, c);
cout<<"\n请输入语句: \n ";
// cin.get();
char a;
char ch[29];
int k = 0;
while ((a = cin.get()) != '\n')
{
ch[k++] = a;
}
ch[k++] = '#';
ch[k] = '\0';
for (int i = k - 1; i >= 0; i--)
{
Push(sin, ch[i]);
}
char seetop, sintop;
int code;
cout<<"分析过程如下所示:\n\n";
cout<<"------------------------------------------------------------\n";
cout<<"分析栈 │ Rest │ 产生式|匹配\n";
cout<<"------------------------------------------------------------\n";
while (!( (GetTop(see) == '#') && (GetTop(sin) == '#') ))
{
seetop = GetTop(see);
sintop = GetTop(sin);
code = IsVN(seetop);
RePrintStack(see); ///
cout<<" | ";
PrintStack(sin);
cout<<" | ";
if (code >= 0) // top是非终结符
{
for (i = 1; i <= pnum; i++) /
{
if ( VSelect[i][0] != seetop )
{
continue;
}
else
{
int L = strlen( VSelect[i] );
for (int j = 1; j < L; j++)
{
if ( VSelect[i][j] == sintop )
{
break;
}
}
// break;
if ( VSelect[i][j] == sintop )
{
break; // 避免用goto
}
}
}
if (i == pnum + 1)
{
cout<<"错误";
return;
}
Pop(see);
int Le = strlen( pr[i] );
for (int k = Le - 1; k >= 3; k--)
{
if ( pr[i][k] != '\0' || pr[i][k] != 'ε' )
{
Push(see, pr[i][k] );
}
}
cout<<pr[i];
if ( pr[i][3] == '\0' )
{
cout<<"ε";
}
cout<<"\n";
}//if (code >= 0) // top是非终结符
else
{
if ( seetop != sintop )
{
cout<<"error";
return;
}
else
{
cout<<sintop<<" 匹配"<<endl;
Pop(see);
Pop(sin);
}
}
}// while (!( (GetTop(see) == '#') && (GetTop(sin) == '#') ))
cout<<"# | # | 分析成功\n";
cout<<"------------------------------------------------------------\n";
}
int main()
{
Inite();
MayEmpty();
GetFirst();
GetFollow();
GetSelect();
while (1 > 0)
{
char c;
Predict();
cout<<"\n继续/停止(Y/N) ";
cin>>c;
cin.get();
if (c == 'N' || c == 'n')
{
return 0;
}
}
return 0;
}