预测分析法是一种确定的自顶向下的分析方法,一个文法能否用预测分析法进行分析,关键看其是否为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
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 ;
}