LR(0)分析器的构造算法如下:
对一个文法构造了它的LR(0)分析表后就可以在LR分析器的总控程序(驱动程序)控制下对输入串进行分析,即根据输入串的当前符号和分析栈的栈顶状态查找分析表应采取的动作,对状态栈和符号栈进行相应的操作即移进、归约、接受或报错。具体说明如下:
(1)若ACTION[S,a]=Sj,a为终结符,则把a移入符号栈,j移入状态栈;
(2)若ACTION[S,a]=rj,a为终结符或#号,则用第j个产生式归约,并将两个栈的指针减去k,其中k为第j个产生式右部的符号串长度,这时当面临符号为第j个产生式左部的非终结符,不妨设为A,归约后栈顶状态设为n,则再进行GOTO[n,A];
(3)若ACTION[S,a]=acc,a应为“#”号,则为接受,表示分析成功;
(4)若GOTO[S,A]=j,A为非终结符,表明前一动作是用关于A的产生式归约的,当前面临非终结符A应移入符号栈,j移入状态栈。对于终结符GOTO[S,a]已和ACTION[S,a]重合。(此算法摘自《编译原理》(第2版)张素琴等著,清华大学出版社)
下面就以一个例子来说明LR(0)分析器的构造过程:
已知文法G[S]为:
(1)SàaAcBe
(2)Aàb
(3)AàAb
(4)Bàd
其LR(0)分析表如下:
|
|
| ACTION |
|
|
|
| GOTO |
|
| a | c | e | b | d | # | S | A | B |
0 | S2 |
|
|
|
|
| 1 |
|
|
1 |
|
|
|
|
| acc |
|
|
|
2 |
|
|
| S4 |
|
|
| 3 |
|
3 |
| S5 |
| S6 |
|
|
|
|
|
4 | r2 | r2 | r2 | r2 | r2 | r2 |
|
|
|
5 |
|
|
|
| S8 |
|
|
| 7 |
6 | r3 | r3 | r3 | r3 | r3 | r3 |
|
|
|
7 |
|
| S9 |
|
|
|
|
|
|
8 | r4 | r4 | r4 | r4 | r4 | r4 |
|
|
|
9 | r1 | r1 | r1 | r1 | r1 | r1 |
|
|
|
根据文法G[S]的LR(0)分析表构造LR(0)分析器:
分析器构造程序如下:
/*根据基于LR(0)分析的行动表和状态转换表构造LR(0)分析器*/
#include<stdio.h>
typedef int Action[10][6];//定义二维行动表Action
typedef int Goto[10] [3];//定义二维状态转换表Goto
typedef int Integer[40];//定义一维整型数组Integer
typedef char String[40];//定义一维字符型数组String
void char2Int(String string,Integer integer);//根据编码表将输入字符串string转换为整型串
int findInArray(Integer integer,int findNValue);//查找数组integer中值第一个不等于findNValue的下标
void Push(Integer stack,int topValue);//将topValue压入stack栈顶
void print(Integer statusStack,Integer charStack);//打印栈stack中的非-1内容
void LR_0_AnalyseDevice(String string,Action actionTable,Goto gotoTable);//创建LR(0)分析器,参数中,string为输入字符串,
//actionTable为行动表,gotoTable为状态转换表
int main(){
String string;
Action actionTable = {12,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,10,
-1,-1,-1,14,-1,-1,
-1,15,-1,16,-1,-1,
2,2,2,2,2,2,
-1,-1,-1,-1,18,-1,
3,3,3,3,3,3,
-1,-1,19,-1,-1,-1,
4,4,4,4,4,4,
1,1,1,1,1,1};//根据编码表初始化行动表actionTable,编码表为:-1->空动作,1->r1,2->r2,3->r3,4->r4,10->acc,
//12->S2,14->S4,15->S5,16->S6,18->S8,19->S9,行动表行下标为即为状态,列下标为终结符编码,其编码表为:
//a->0,c->1,e->2,b->3,d->4,#->5
Goto gotoTable = {1,-1,-1,
-1,-1,-1,
-1,3,-1,
-1,-1,-1,
-1,-1,-1,
-1,-1,7,
-1,-1,-1,
-1,-1,-1,
-1,-1,-1,
-1,-1,-1};//初始化状态转换表gotoTable,状态转换表行下标为状态,列下标为非终结符编码,其编码表为:
//S->0,A->1,B->2
printf("******************************************\n");
printf("Please input string...\nString = ");
scanf("%s",string);
printf("\n------------------------------------------\n");
printf("Status Stack Char Stack\n");
printf("+ + + + + + + + + + + + + + + + + + + + + \n");
LR_0_AnalyseDevice(string,actionTable,gotoTable);
printf("******************************************\n");
return 0;
}
void char2Int(String string,Integer integer){
//根据编码表将输入字符串string转换为整型串,编码表为:a->0,c->1,e->2,b->3,d->4,S->5,A->6,B->7,#->8
for(int index = 0;index < 40;index++){
integer[index] = -1;
}
int index = 0;
for(index;string[index] != '\0';index++){//原码到编码的转换
switch (string[index]){
case 'a':integer[index] = 0;break;
case 'c':integer[index] = 1;break;
case 'e':integer[index] = 2;break;
case 'b':integer[index] = 3;break;
case 'd':integer[index] = 4;break;
case 'S':integer[index] = 5;break;
case 'A':integer[index] = 6;break;
case 'B':integer[index] = 7;break;
default:printf("The char you have inputed is invalid!");integer[index] = -1;//输入字符串中出现额外字符
}
}
integer[index] = 8;
}
int findInArray(Integer integer,int findNValue){
//查找数组integer中值第一个不等于findNValue的下标
int findindex = 0;
for(findindex;integer[findindex] == findNValue && findindex < 40;findindex++){
}
if(findindex < 40)
return findindex;
else{//在数组integer中没有找到指定要求的值
printf("Invalid operation!");
return -1;
}
}
void Push(Integer stack,int topValue){
//将topValue压入stack栈顶
int index = 0;
for(index;index < 40;index++){
if(stack[index] != -1){
stack[index-1] = topValue;
break;
}
}
if(index > 40)
printf("Stack index out of boundary!");
}
void print(Integer statusStack,Integer charStack){
//打印状态栈statusStack和字符栈charStack中的内容
int count = 0;
for(int index = 39;index >= 0;index--){//打印状态栈中的信息
if(statusStack[index] != -1){
printf("%d",statusStack[index]);
count++;
}
}
if(count < 25){//确定打印文本中状态和字符的间距,用于美化输出文本
for(int i = 0;i < 25-count;i++){
printf(" ");
}
}
for(int index = 39;index >= 0;index--){//打印字符栈中的信息
if(charStack[index] != -1){
switch (charStack[index]){//字符编码到原码转换
case 0:printf("a");break;
case 1:printf("c");break;
case 2:printf("e");break;
case 3:printf("b");break;
case 4:printf("d");break;
case 5:printf("S");break;
case 6:printf("A");break;
case 7:printf("B");break;
case 8:printf("#");break;
}
}
}
printf("\n");
}
void LR_0_AnalyseDevice(String string,Action actionTable,Goto gotoTable){
//创建LR(0)分析器,参数中,string为输入字符串,actionTable为行动表,gotoTable为状态转换表
int expressions[4][2] = {5,5,1,6,2,6,1,7};//各产生式右部符号串长度
Integer statusStack;//创建状态栈
Integer charStack;//创建符号栈
Integer integer;
char2Int(string,integer);// 将输入字符串转换为整型
for(int index = 0;index < 40;index++){
statusStack[index] = -1;
charStack[index] = -1;
}
statusStack[39] = 0;
charStack[39] = 8;
int index = 0;
int a,A,S,firststatus,firstinput,Sj,inputindex = 0;
print(statusStack,charStack);
while(findInArray(charStack,-1) != 5){//LR(0)分析开始
firststatus = findInArray(statusStack,-1);
S = statusStack[firststatus];//取状态栈栈顶元素
a = integer[inputindex++];//取输入字符串待取字符
if(a == 8)
a = 5;
if(actionTable[S][a] == 10){//分析成功
printf("\n Congratulation!\n Acceptable!\n");
return;
}else if(actionTable[S][a] > 10){//进入其他状态
Push(charStack,a);
Push(statusStack,actionTable[S][a]-10);
print(statusStack,charStack);
}else if(actionTable[S][a] < 10 && actionTable[S][a] > -1){//进入归约程序
int i = firststatus;
for(i;i < firststatus+expressions[actionTable[S][a]-1][0];i++){
statusStack[i] = -1;
charStack[i] = -1;
}
charStack[i-1] = expressions[actionTable[S][a]-1][1];//字符进栈
statusStack[i-1] = gotoTable[statusStack[i]][charStack[i-1]-5];//状态进栈
print(statusStack,charStack);
inputindex--;
}else if(actionTable[S][a] == -1){//出错处理
print(statusStack,charStack);
printf(". . .\n Analysis stoped by accident!\n Sorry,refused!\n");
return ;
}
if(inputindex == 40)//边界括号防越界处理
inputindex = 39;
}
}