預測分析法是一種確定的自頂向下的分析方法,一個文法能否用預測分析法進行分析,關鍵看其是否爲LL(1)文法,一個預測分析器由三個部分組成:
#預測分析程序
#先進後出棧
#預測分析表
下面我們以一個具體的實例來看預測分析器的實現算法,其他文法可照推:
已知表達式文法:(只含*、+、)、(、i算術表達式的判斷文法)
E->E+T|T
T->T*F|F
F->i|(E)
設計預測分析程序。
由於文法中含有左遞歸,所以必須先消除左遞歸,消除後爲:
E->TE'
E'->+TE'|e
T->FT'
T'->*FT'|e
F->i|(E)
**說明:e代表空串**
進一步可得如下預測分析表:
|
i |
+ |
* |
( |
) |
# |
E |
TE’ |
|
|
TE’ |
|
|
E’ |
|
+TE’ |
|
|
e |
e |
T |
FT’ |
|
|
FT’ |
|
|
T’ |
|
e |
*FT’ |
|
e |
e |
F |
i |
|
|
(E) |
|
|
預測分析程序如下:
/*構造表達式文法的預測分析器
將表達式各字符編碼,再進行表達式文法的預測分析 */
#include<stdio.h>
typedef int Mat[5][6][3];//定義三維數組Mat,用於存儲編碼後的表達式文法的預測分析表
void ForecastAnalysisDevice(char *expressions,Mat forecasttable);//表達式文法的預測分析器
int main(){
Mat forecasttable = {2,1,9,9,9,9,9,9,9,2,1,9,9,9,9,9,9,9,
9,9,9,22,2,1,9,9,9,9,9,9,8,9,9,8,9,9,
4,3,9,9,9,9,9,9,9,4,3,9,9,9,9,9,9,9,
9,9,9,8,9,9,33,4,3,9,9,9,8,9,9,8,9,9,
11,9,9,9,9,9,9,9,9,44,0,55,9,9,9,9,9,9};
//編碼表:0=E,1=E',2=T,3=T',4=F,11=i,22=+,33=*,44=(,55=),66=#,8=空串,9=棧頂空
char expressions[100]; //表達式
printf("###################################\n");
printf("請輸入算術表達式...\nExpressions= ");
scanf("%s",expressions);
printf("-\n");
ForecastAnalysisDevice(expressions,forecasttable); //進行表達式文法的預測分析
printf("-----------------------------------\n");
printf("###################################\n");
return 0;
}
void ForecastAnalysisDevice(char *expressions,Mat forecasttable){
//表達式文法的預測分析器,expressions爲表達式,forecasttable爲表達式文法的預測分析表
char string[5] = {'i','+','*','(',')'}; //表達式字符集
int i = 0,j = 0,k,l;
int indexx,indexy,semp,sum;
int integer[100];
while(expressions[i] != '\0'){ //對表達式進行歸一化編碼轉換
switch (expressions[i]){
case 105:integer[j++] = 0;break;
case 43:integer[j++] = 1;break;
case 42:integer[j++] = 2;break;
case 40:integer[j++] = 3;break;
case 41:integer[j++] = 4;break;
case 35:integer[j++] = 5;break;
}
i++;
}
integer[i++] = 5;
sum = i;
j = 0;
int temp[12] = {9,9,9,9,9,9,9,9,9,9,9,0};//初始化預測分析棧
while(temp[11] != 9){
for(i = 0;i < 12;i++){ //找到棧頂
if(temp[i] != 9)
break;
}
if(temp[i] == 55){ //“)”匹配
printf("\")\"匹配\n");
temp[i] = 9;
i = i+1;
j = j+1;
}
indexx = temp[i]; //預測分析表x下標,即第一緯下標
indexy = integer[j]; //預測分析表y下標,即第二緯下標
if(forecasttable[indexx][indexy][0] != 11 && forecasttable[indexx][indexy][0] != 22 && forecasttable[indexx][indexy][0] != 33 && forecasttable[indexx][indexy][0] != 44 && forecasttable[indexx][indexy][0] != 55 && forecasttable[indexx][indexy][0] != 66 && forecasttable[indexx][indexy][0] != 9 && forecasttable[indexx][indexy][0] != 8){
//產生式推導仍爲非終結符
k = 2;
l = i;
while(k >= 0){
if(forecasttable[indexx][indexy][k] != 9){
if(forecasttable[indexx][indexy][k] > 9){ //大編碼變形,轉化爲預測分析表列下標
semp = forecasttable[indexx][indexy][k]/10;
semp *= 10+1;
temp[l] = forecasttable[indexx][indexy][k] - semp;
l--;
}else{
temp[l] = forecasttable[indexx][indexy][k];
l--;
}
}
k--;
}
}
else if(forecasttable[indexx][indexy][0] == 9){ //出錯處理
printf("...\n分析意外終止...\n輸入的串\"%s\"不可接受!\n",expressions);
return ;
}
else if(forecasttable[indexx][indexy][0] == 8) //產生式推導爲空
temp[i] = 9;
else{ //產生式推導出終結符
k = 2;
l = i;
while(k >= 0){
if(forecasttable[indexx][indexy][k] != 9){
temp[l] = forecasttable[indexx][indexy][k];
l--;
}
k--;
}
l++;
temp[l] -= (temp[l]/10)*10;
printf("\"%c\"匹配\n",string[temp[l]-1]); //打印匹配字符
temp[l] = 9;
if(j < sum-1) //避免表達式遍歷越界
j++;
}
}
printf("---------\n");
printf("Congratulation!\n輸入的串\"%s\"可接受!\n",expressions);//表達式滿足給定文法規則
return ;
}