LL(0)語法分析演算法(完整版) ----(編譯原理試驗)
阿新 • • 發佈:2018-11-13
語法分析程式設計
【實驗目的】
1.熟悉判斷LL(1)文法的方法及對某一輸入串的分析過程。
2.學會構造表示式文法的預測分析表。
【實驗內容】
編寫一個語法分析程式,對於給定的輸入串,能夠判斷識別該串是否為給定文法的句型。
【實驗要求】
1. 輸入一個LL(1)文法,構造相應的LL(1)預測分析表。
2. 從鍵盤讀入輸入串,由演算法判斷該輸入串是否為該文法的句子,若正確,就通過,若錯誤就報錯。
【參考說明】
語法分析主要是將從詞法分析那裡得來的記號構成一棵語法樹。例:
SHMA#adbe#
S->aH
H->aMd
H->d
M->Ab
M->
A->aM
A->e
【實驗程式碼】
//LL1.h
#ifndef LL1_H_INCLUDED #define LL1_H_INCLUDED #include "stdio.h" #include "stdlib.h" #define MaxRuleNum 8 #define MaxVnNum 5 #define MaxVtNum 5 #define MaxStackDepth 20 #define MaxPLength 20 #define MaxStLength 50 struct pRNode /*產生式右部結構*/ { int rCursor; /*右部序號*/ struct pRNode *next; }; struct pNode /*產生式結點結構*/ { int lCursor; /*左部符號序號*/ int rLength; /*右部長度*/ /*注當rLength = 1 時,rCursor = -1為空產生式*/ struct pRNode *rHead; /*右部結點頭指標*/ }; char Vn[MaxVnNum + 1]; /*非終結符集*/ int vnNum; char Vt[MaxVtNum + 1]; /*終結符集*/ int vtNum; struct pNode P[MaxRuleNum]; /*產生式*/ int PNum; /*產生式實際個數*/ char buffer[MaxPLength + 1]; char ch; /*符號或string ch;*/ char st[MaxStLength]; /*要分析的符號串*/ struct collectNode /*集合元素結點結構*/ { int nVt; /*在終結符集中的下標*/ struct collectNode *next; }; struct collectNode* first[MaxVnNum + 1]; /*first集*/ struct collectNode* follow[MaxVnNum + 1]; /*follow集*/ int analyseTable[MaxVnNum + 1][MaxVtNum + 1 + 1]; /*預測分析表存放為產生式的編號,+1用於存放結束符,多+1用於存放#(-1)*/ int analyseStack[MaxStackDepth + 1]; /*分析棧*/ int topAnalyse; /*分析棧頂*/ /*int reverseStack[MaxStackDepth + 1]; /*顛倒順序棧*/ /*int topReverse; /*倒敘棧頂*/ void Init();/*初始化*/ int IndexCh(char ch); /*返回Vn在Vn表中的位置+100、Vt在Vt表中的位置,-1表示未找到*/ void InputVt(); /*輸入終結符*/ void InputVn();/*輸入非終結符*/ void ShowChArray(char* collect, int num);/*輸出Vn或Vt的內容*/ void InputP();/*產生式輸入*/ bool CheckP(char * st);/*判斷產生式正確性*/ void First(int U);/*計算first集,U->xx...*/ void AddFirst(int U, int nCh); /*加入first集*/ bool HaveEmpty(int nVn); /*判斷first集中是否有空(-1)*/ void Follow(int V);/*計算follow集*/ void AddFollow(int V, int nCh, int kind);/*加入follow集, kind = 0表加入follow集,kind = 1加入first集*/ void ShowCollect(struct collectNode **collect);/*輸出first或follow集*/ void FirstFollow();/*計算first和follow*/ void CreateAT();/*構造預測分析表*/ void ShowAT();/*輸出分析表*/ void Identify(char *st);/*主控程式,為操作方便*/ /*分析過程顯示操作為本行變換所用,與教程的顯示方式不同*/ void InitStack();/*初始化棧及符號串*/ void ShowStack();/*顯示符號棧中內容*/ void Pop();/*棧頂出棧*/ void Push(int r);/*使用產生式入棧操作*/ #endif // HEAD_H_INCLUDED
//main.cpp
#include "LL1.h"
int main(void)
{
char todo,ch;
Init();
InputVn();
InputVt();
InputP();
getchar();
FirstFollow();
printf("所得first集為:");
ShowCollect(first);
printf("所得follow集為:");
ShowCollect(follow);
CreateAT();
ShowAT();
todo = 'y';
while('y' == todo)
{
printf("\n是否繼續進行句型分析?(y / n):");
todo = getchar();
while('y' != todo && 'n' != todo)
{
printf("\n(y / n)? ");
todo = getchar();
}
if('y' == todo)
{
int i;
InitStack();
printf("請輸入符號串(以#結束) : ");
ch = getchar();
i = 0;
while('#' != ch && i < MaxStLength)
{
if(' ' != ch && '\n' != ch)
{
st[i++] = ch;
}
ch = getchar();
}
if('#' == ch && i < MaxStLength)
{
st[i] = ch;
Identify(st);
}
else
printf("輸入出錯!\n");
}
}
getchar();
}
void Init()
{
int i,j;
vnNum = 0;
vtNum = 0;
PNum = 0;
for(i = 0; i <= MaxVnNum; i++)
Vn[i] = '\0';
for(i = 0; i <= MaxVtNum; i++)
Vt[i] = '\0';
for(i = 0; i < MaxRuleNum; i++)
{
P[i].lCursor = NULL;
P[i].rHead = NULL;
P[i].rLength = 0;
}
PNum = 0;
for(i = 0; i <= MaxPLength; i++)
buffer[i] = '\0';
for(i = 0; i < MaxVnNum; i++)
{
first[i] = NULL;
follow[i] = NULL;
}
for(i = 0; i <= MaxVnNum; i++)
{
for(j = 0; j <= MaxVnNum + 1; j++)
analyseTable[i][j] = -1;
}
}
/*返回Vn在Vn表中的位置+100、Vt在Vt表中的位置,-1表示未找到*/
int IndexCh(char ch)
{
int n;
n = 0; /*is Vn?*/
while(ch != Vn[n] && '\0' != Vn[n])
n++;
if('\0' != Vn[n])
return 100 + n;
n = 0; /*is Vt?*/
while(ch != Vt[n] && '\0' != Vt[n])
n++;
if('\0' != Vt[n])
return n;
return -1;
}
/*輸出Vn或Vt的內容*/
void ShowChArray(char* collect)
{
int k = 0;
while('\0' != collect[k])
{
printf(" %c ", collect[k++]);
}
printf("\n");
}
/*輸入非終結符*/
void InputVn()
{
int inErr = 1;
int n,k;
char ch;
while(inErr)
{
printf("\n請輸入所有的非終結符,注意:");
printf("請將開始符放在第一位,並以#號結束:\n");
ch = ' ';
n = 0;
/*初始化陣列*/
while(n < MaxVnNum)
{
Vn[n++] = '\0';
}
n = 0;
while(('#' != ch) && (n < MaxVnNum))
{
if(' ' != ch && '\n' != ch && -1 == IndexCh(ch))
{
Vn[n++] = ch;
vnNum++;
}
ch = getchar();
}
Vn[n] = '#'; /*以“#”標誌結束用於判斷長度是否合法*/
k = n; /*k用於記錄n以便改Vn[n]='\0'*/
if('#' != ch)
{
if( '#' != (ch = getchar()))
{
while('#' != (ch = getchar()))
;
printf("\n符號數目超過限制!\n");
inErr = 1;
continue;
}
}
/*正確性確認,正確則,執行下下面,否則重新輸入*/
Vn[k] = '\0';
ShowChArray(Vn);
ch = ' ';
while('y' != ch && 'n' != ch)
{
if('\n' != ch)
{
printf("輸入正確確認?(y/n):");
}
scanf("%c", &ch);
}
if('n' == ch)
{
printf("錄入錯誤重新輸入!\n");
inErr = 1;
}
else
{
inErr = 0;
}
}
}
/*輸入終結符*/
void InputVt()
{
int inErr = 1;
int n,k;
char ch;
while(inErr)
{
printf("\n請輸入所有的終結符,注意:");
printf("以#號結束:\n");
ch = ' ';
n = 0;
/*初始化陣列*/
while(n < MaxVtNum)
{
Vt[n++] = '\0';
}
n = 0;
while(('#' != ch) && (n < MaxVtNum))
{
if(' '!= ch && '\n' != ch && -1 == IndexCh(ch))
{
Vt[n++] = ch;
vtNum++;
}
ch = getchar();
}
Vt[n] = '#'; /*以“#”標誌結束*/
k = n; /*k用於記錄n以便改Vt[n]='\0'*/
if('#' != ch)
{
if( '#' != (ch = getchar()))
{
while('#' != (ch = getchar()))
printf("\n符號數目超過限制!\n");
inErr = 1;
continue;
}
}
/*正確性確認,正確則,執行下下面,否則重新輸入*/
Vt[k] = '\0';
ShowChArray(Vt);
ch =' ';
while('y' != ch && 'n' != ch)
{
if('\n' != ch)
{
printf("輸入正確確認?(y/n):");
}
scanf("%c", &ch);
}
if('n' == ch)
{
printf("錄入錯誤重新輸入!\n");
inErr = 1;
}
else
{
inErr = 0;
}
}
}
/*產生式輸入*/
void InputP()
{
char ch;
int i = 0, n,num;
printf("請輸入文法產生式的個數:");
scanf("%d", &num);
PNum = num;
getchar(); /*消除回車符*/
printf("\n請輸入文法的%d個產生式,並以回車分隔每個產生式:", num);
printf("\n");
while(i < num)
{
printf("第%d個:", i);
/*初始化*/
for(n =0; n < MaxPLength; n++)
buffer[n] = '\0';
/*輸入產生式串*/
ch = ' ';
n = 0;
while('\n' != (ch = getchar()) && n < MaxPLength)
{
if(' ' != ch)
buffer[n++] = ch;
}
buffer[n] = '\0';
/* printf("%s", buffer);*/
if(CheckP(buffer))
{
/*填寫入產生式結構體*/
pRNode *pt, *qt;
P[i].lCursor = IndexCh(buffer[0]);
pt = (pRNode*)malloc(sizeof(pRNode));
pt->rCursor = IndexCh(buffer[3]);
pt->next = NULL;
P[i].rHead = pt;
n = 4;
while('\0' != buffer[n])
{
qt = (pRNode*)malloc(sizeof(pRNode));
qt->rCursor = IndexCh(buffer[n]);
qt->next = NULL;
pt->next = qt;
pt = qt;
n++;
}
P[i].rLength = n - 3;
i++;
/*除錯時使用*/
}
else
printf("輸入符號含非法在成分,請重新輸入!\n");
}
}
/*判斷產生式正確性*/
bool CheckP(char * st)
{
int n;
if(100 > IndexCh(st[0]))
return false;
if('-' != st[1])
return false;
if('>' != st[2])
return false;
for(n = 3; '\0' != st[n]; n ++)
{
if(-1 == IndexCh(st[n]))
return false;
}
return true;
}
/*====================first & follow======================*/
/*計算first集,U->xx...*/
void First(int U)
{
int i,j;
for(i = 0; i < PNum; i++)
{
if(P[i].lCursor == U)
{
struct pRNode* pt;
pt = P[i].rHead;
j = 0;
while(j < P[i].rLength)
{
if(100 > pt->rCursor)
{
/*注:此處因程式設計出錯,使空產生式時
rlength同樣是1,故此處同樣可處理空產生式*/
AddFirst(U, pt->rCursor);
break;
}
else
{
if(NULL == first[pt->rCursor - 100])
{
First(pt->rCursor);
}
AddFirst(U, pt->rCursor);
if(!HaveEmpty(pt->rCursor))
{
break;
}
else
{
pt = pt->next;
}
}
j++;
}
if(j >= P[i].rLength) /*當產生式右部都能推出空時*/
AddFirst(U, -1);
}
}
}
/*加入first集*/
void AddFirst(int U, int nCh) /*當數值小於100時nCh為Vt*/
/*當處理非終結符時,AddFirst不新增空項(-1)*/
{
struct collectNode *pt, *qt;
int ch; /*用於處理Vn*/
pt = NULL;
qt = NULL;
if(nCh < 100)
{
pt = first[U - 100];
while(NULL != pt)
{
if(pt->nVt == nCh)
break;
else
{
qt = pt;
pt = pt->next;
}
}
if(NULL == pt)
{
pt = (struct collectNode *)malloc(sizeof(struct collectNode));
pt->nVt = nCh;
pt->next = NULL;
if(NULL == first[U - 100])
{
first[U - 100] = pt;
}
else
{
qt->next = pt; /*qt指向first集的最後一個元素*/
}
pt = pt->next;
}
}
else
{
pt = first[nCh - 100];
while(NULL != pt)
{
ch = pt->nVt;
if(-1 != ch)
{
AddFirst(U, ch);
}
pt = pt->next;
}
}
}
/*判斷first集中是否有空(-1)*/
bool HaveEmpty(int nVn)
{
if(nVn < 100) /*為終結符時(含-1),在follow集中用到*/
return false;
struct collectNode *pt;
pt = first[nVn - 100];
while(NULL != pt)
{
if(-1 == pt->nVt)
return true;
pt = pt->next;
}
return false;
}
/*計算follow集,例:U->xVy,U->xV.(注:初始符必含#——"-1")*/
void Follow(int V)
{
int i;
struct pRNode *pt ;
if(100 == V) /*當為初始符時*/
AddFollow(V, -1, 0 );
for(i = 0; i < PNum; i++)
{
pt = P[i].rHead;
while(NULL != pt && pt->rCursor != V) /*注此不能處理:U->xVyVz的情況*/
pt = pt->next;
if(NULL != pt)
{
pt = pt->next; /*V右側的符號*/
if(NULL == pt) /*當V後為空時V->xV,將左符的follow集併入V的follow集中*/
{
if(NULL == follow[P[i].lCursor - 100] && P[i].lCursor != V)
{
Follow(P[i].lCursor);
}
AddFollow(V, P[i].lCursor, 0);
}
else /*不為空時V->xVy,(注意:y->),呼叫AddFollow加入Vt或y的first集*/
{
while(NULL != pt && HaveEmpty(pt->rCursor))
{
AddFollow(V, pt->rCursor, 1); /*y的字首中有空時,加如first集*/
pt = pt->next;
}
if(NULL == pt) /*當後面的字元可以推出空時*/
{
if(NULL == follow[P[i].lCursor - 100] && P[i].lCursor != V)
{
Follow(P[i].lCursor);
}
AddFollow(V, P[i].lCursor, 0);
}
else /*發現不為空的字元時*/
{
AddFollow(V, pt->rCursor, 1);
}
}
}
}
}
/*當數值小於100時nCh為Vt*/
/*#用-1表示,kind用於區分是併入符號的first集,還是follow集
kind = 0表加入follow集,kind = 1加入first集*/
void AddFollow(int V, int nCh, int kind)
{
struct collectNode *pt, *qt;
int ch; /*用於處理Vn*/
pt = NULL;
qt = NULL;
if(nCh < 100) /*為終結符時*/
{
pt = follow[V - 100];
while(NULL != pt)
{
if(pt->nVt == nCh)
break;
else
{
qt = pt;
pt = pt->next;
}
}
if(NULL == pt)
{
pt = (struct collectNode *)malloc(sizeof(struct collectNode));
pt->nVt = nCh;
pt->next = NULL;
if(NULL == follow[V - 100])
{
follow[V - 100] = pt;
}
else
{
qt->next = pt; /*qt指向follow集的最後一個元素*/
}
pt = pt->next;
}
}
else /*為非終結符時,要區分是加first還是follow*/
{
if(0 == kind)
{
pt = follow[nCh - 100];
while(NULL != pt)
{
ch = pt->nVt;
AddFollow(V, ch, 0);
pt = pt->next;
}
}
else
{
pt = first[nCh - 100];
while(NULL != pt)
{
ch = pt->nVt;
if(-1 != ch)
{
AddFollow(V, ch, 1);
}
pt = pt->next;
}
}
}
}
/*輸出first或follow集*/
void ShowCollect(struct collectNode **collect)
{
int i;
struct collectNode *pt;
i = 0;
while(NULL != collect[i])
{
pt = collect[i];
printf("\n%c:\t", Vn[i]);
while(NULL != pt)
{
if(-1 != pt->nVt)
{
printf(" %c", Vt[pt->nVt]);
}
else
printf(" #");
pt = pt->next;
}
i++;
}
printf("\n");
}
/*計算first和follow*/
void FirstFollow()
{
int i;
i = 0;
while('\0' != Vn[i])
{
if(NULL == first[i])
First(100 + i);
i++;
}
i = 0;
while('\0' != Vn[i])
{
if(NULL == follow[i])
Follow(100 + i);
i++;
}
}
/*=================構造預測分析表,例:U::xyz=============*/
void CreateAT()
{
int i;
struct pRNode *pt;
struct collectNode *ct;
for(i = 0; i < PNum; i++)
{
pt = P[i].rHead;
while(NULL != pt && HaveEmpty(pt->rCursor))
{
/*處理非終結符,當為終結符時,定含空為假跳出*/
ct = first[pt->rCursor - 100];
while(NULL != ct)
{
if(-1 != ct->nVt)
analyseTable[P[i].lCursor - 100][ct->nVt] = i;
ct = ct->next;
}
pt = pt->next;
}
if(NULL == pt)
{
/*NULL == pt,說明xyz->,用到follow中的符號*/
ct = follow[P[i].lCursor - 100];
while(NULL != ct)
{
if(-1 != ct->nVt)
analyseTable[P[i].lCursor - 100][ct->nVt] = i;
else /*當含有#號時*/
analyseTable[P[i].lCursor - 100][vtNum] = i;
ct = ct->next;
}
}
else
{
if(100 <= pt->rCursor) /*不含空的非終結符*/
{
ct = first[pt->rCursor - 100];
while(NULL != ct)
{
analyseTable[P[i].lCursor - 100][ct->nVt] = i;
ct = ct->next;
}
}
else /*終結符或者空*/
{
if(-1 == pt->rCursor) /*-1為空產生式時*/
{
ct = follow[P[i].lCursor - 100];
while(NULL != ct)
{
if(-1 != ct->nVt)
analyseTable[P[i].lCursor - 100][ct->nVt] = i;
else /*當含有#號時*/
analyseTable[P[i].lCursor - 100][vtNum] = i;
ct = ct->next;
}
}
else /*為終結符*/
{
analyseTable[P[i].lCursor - 100][pt->rCursor] = i;
}
}
}
}
}
/*輸出分析表*/
void ShowAT()
{
int i,j;
printf("構造預測分析表如下:\n");
printf("\t|\t");
for(i = 0; i < vtNum; i++)
{
printf("%c\t", Vt[i]);
}
printf("#\t\n");
printf("- - -\t|- - -\t");
for(i = 0; i <= vtNum; i++)
printf("- - -\t");
printf("\n");
for(i = 0; i < vnNum; i++)
{
printf("%c\t|\t", Vn[i]);
for(j = 0; j <= vtNum; j++)
{
if(-1 != analyseTable[i][j])
printf("R(%d)\t", analyseTable[i][j]);
else
printf("error\t");
}
printf("\n");
}
}
/*=================主控程式=====================*/
void Identify(char *st)
{
int current,step,r; /*r表使用的產生式的序號*/
printf("\n%s的分析過程:\n", st);
printf("步驟\t分析符號棧\t當前指示字元\t使用產生式序號\n");
step = 0;
current = 0; /*符號串指示器*/
printf("%d\t",step);
ShowStack();
printf("\t\t%c\t\t- -\n", st[current]);
while('#' != st[current])
{
if(100 > analyseStack[topAnalyse]) /*當為終結符時*/
{
if(analyseStack[topAnalyse] == IndexCh(st[current]))
{
/*匹配出棧,指示器後移*/
Pop();
current++;
step++;
printf("%d\t", step);
ShowStack();
printf("\t\t%c\t\t出棧、後移\n", st[current]);
}
else
{
printf("%c-%c不匹配!", analyseStack[topAnalyse], st[current]);
printf("此串不是此文法的句子!\n");
return;
}
}
else /*當為非終結符時*/
{
r = analyseTable[analyseStack[topAnalyse] - 100][IndexCh(st[current])];
if(-1 != r)
{
Push(r); /*產生式右部代替左部,指示器不移動*/
step++;
printf("%d\t", step);
ShowStack();
printf("\t\t%c\t\t%d\n", st[current], r);
}
else
{
printf("無可用產生式,此串不是此文法的句子!\n");
return;
}
}
}
if('#' == st[current])
{
if(0 == topAnalyse && '#' == st[current])
{
step++;
printf("%d\t", step);
ShowStack();
printf("\t\t%c\t\t分析成功!\n", st[current]);
printf("%s是給定文法的句子!\n", st);
}
else
{ while(topAnalyse > 0)
{ if(100 > analyseStack[topAnalyse]) /*當為終結符時*/
{ printf("無可用產生式,此串不是此文法的句子!\n");
return;
}
else
{ r = analyseTable[analyseStack[topAnalyse] - 100][vtNum];
if(-1 != r)
{ Push(r); /*產生式右部代替左部,指示器不移動*/
step++;
printf("%d\t", step);
ShowStack();
if(0 == topAnalyse && '#' == st[current])
{ printf("\t\t%c\t\t分析成功!\n", st[current]);
printf("%s是給定文法的句子!\n", st);
}
else
printf("\t\t%c\t\t%d\n", st[current], r); }
else
{ printf("無可用產生式,此串不是此文法的句子!\n");
return; }
}
}
}
}
}
/*初始化棧及符號串*/
void InitStack()
{ int i;
/*分析棧的初始化*/
for(i = 0; i < MaxStLength; i++)
st[i] = '\0';
analyseStack[0] = -1; /*#(-1)入棧*/
analyseStack[1] = 100; /*初始符入棧*/
topAnalyse = 1;
}
/*顯示符號棧中內容*/
void ShowStack()
{ int i;
for(i = 0; i <= topAnalyse; i++)
{ if(100 <= analyseStack[i])
printf("%c", Vn[analyseStack[i] - 100]);
else
{ if(-1 != analyseStack[i])
printf("%c", Vt[analyseStack[i]]);
else
printf("#");
}
}
}
/*棧頂出棧*/
void Pop()
{ topAnalyse--;
}
/*使用產生式入棧操作*/
void Push(int r)
{ int i;
struct pRNode *pt;
Pop();
pt = P[r].rHead;
if(-1 == pt->rCursor) /*為空產生式時*/
return;
topAnalyse += P[r].rLength;
for(i = 0; i < P[r].rLength; i++)
{ /*不為空產生式時*/
analyseStack[topAnalyse - i] = pt->rCursor;/*逆序入棧*/
pt = pt->next;
}/*迴圈未完時pt為空,則說明rLength記錄等出錯*/
}