Y当且仅当Y为G的终结符,G中含有形如P…QR…的产生式,其中Q,R为非终结符,且Q …X,YFirst(R)
D)对任何X,若文法开始符号SX…,则##。
3.1.2简单优先法的基本思想
根据优先关系的定义,将简单优先文法中各文法符号之间的这种关系用一个矩阵表示,称作简单优先矩阵。PDA读入一个单词后,比较栈顶符号和该单词的优先级,若栈顶符号优先级低于该单词,继续读入;若栈顶符号优先级高于或等于读入符号,则找句柄进行归约,找不到句柄就继续读入。直到最后栈内只剩下开始符号,输入串读到“#”为止。此时识别正确。可分点描述如下:
1、对句型中相邻的文法符号规定优先关系,以寻找句型中的句柄;
2、规定句柄内各相邻符号之间具有相同的优先级;
3、规定句柄两端符号优先级要比位于句柄之外而又和句柄相邻的符号的优先级高,以先归约句柄;
4、对于文法中所有符号,只要它们可能在某个句型中相邻,就要为它们规定相应的优先关系,若某两个符号永远不可能相邻,则它们之间就无关系.
3.1.3简单优先矩阵
用于表示文法符号之间的简单优先关系的矩阵。
3.1.4简单优先法的优缺点
优点:技术简单
缺点:适用范围小,分析表尺寸太大。
3.2中间代码形式描述
四元式是一种比较普遍采用的中间代码形式。四元式的四个组成成分是:算符op,第一和第二运算对象ARG1和ARG2及运算结果RESULT。运算对象和运算结果有时指用户自己定义的变量,有时指编译程序引进的临时变量。
例如:输入字符串 do c=a+1 while a>b 则输出四元式
(1) (+,a,1,c)
(2) (>,a,b,t0)
(3) (=,t0,true,1)
(4) (-,-,-,-)
4简要的分析与概要设计
整个工程分为5个文件:
Main.c ----- 程序的入口点,输入待分析的字符串后先进行词法分析,然后调用两个函数进行语法分析及产生中间代码。
Global.h ----- 定义了一些全局变量及宏
Parse.h ----- 语法分析器的主要算法
Prece.h ----- 定义和实现了一些关于优先级的操作
Stack.h ----- 定义和实现了一个栈及其操作
5详细的算法描述
5.1 Main的主要算法
void InputString()//输入字符串
{
int len = 0;
printf("表达式文法为: ");
printf(GRAMMAR);
printf("\n Please input any string to parse:\n");
scanf("%s", Buff);//输入字符串
len = strlen(Buff);//取字符串长度
Buff[len] = #;
Buff[len+1] = 0;
}
void main()//主程序
{
printf(" DO-WHILE循环语句的翻译\n ");
printf("循环语句的格式为:DO WHILE \n ");
printf("翻译的语句:do c=a+1 while a>b\n ");
cifa();//调用词法分析程序,对输入字符串进行词法分析
InputString();//再次输入待分析字符串以便进行语法分析
Parse();//调用语法分析,对输入字符串进行语法分析
getch();
}
void cifa()//词法分析
{
char str;
printf(" ********** 词法分析器 **********\n");
if ((fp=fopen("lj.txt","r"))==NULL)//如果文件无法打开
printf("源程序无法打开!\n");
else
{ str =fgetc(fp);
while (str!=EOF)
{ if (isalpha(str)!=0)//判断是否为字符
str=letterprocess(str);//调用字符处理
else
{ if (isdigit(str)!=0)判断是否为数字
str=numberprocess(str);//调用数字处理
else//其它
str=otherprocess(str); //调用其它处理
}
};
printf("词法分析结束!\n");
}
}
5.2 Global的主要算法
typedef enum{ false=0, true } bool;
#define GRAMMAR "G(s): S->do B while E,B->c:=a+1,E=a>b"//定义文法
#define BUFFSIZE 100
#define STACKSIZE 100
5.3 Parse的主要算法
void error()//规约不成功
{ printf("The input string doesnt match the grammar!");}
void succeed()//规约成功
{ printf("Succeed! The input match the grammar.");}
char Reduce(const char* c) //将终极符或非终极符规约为非终极符
{
if (*c == d) { return S; }
else if (*c == c )
{ return B; }
else if (*c == a)
{ return E; }
}
bool Parse()//简单优先语法分析
{
char c; //保存栈顶元素
char t; //保存最有可能弹出的终极符
int ip = 0; //指向输入缓冲区的指针
InitStack(); //初始化栈
while (true)
{ TopValue(&c);
if (c==S && Buff[ip]==#)//如果栈顶为S或#,规约成功
{ succeed();
return true; }
else
{ switch (GetPrecedence(&c, &Buff[ip]))
{//如果优先符是小于或等于则压栈,否则进栈
case LT:
case EQ:
{ Push(&Buff[ip++]);//压栈
PrintStack();
break; }
case GT:
{ Pop(&c);//出栈
do
{ t = c;
Pop(&c); }
while (GetPrecedence(&c, &t) != LT);
Push(&c);
t = Reduce(&t);
Push(&t);
PrintStack();
break; }
default:
{ error();
return false;
}
}
}
}
}
5.4 Prece的主要算法
//定义优先关系
Prece PreTable[18][18] =
{ /** S d o B w h i l e E a = + 1 > b c # **/
/* S */ { NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, GT },
/* d */ { NO, NO, EQ, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, GT },
/* o */ { NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, LT, GT },
/* B */{ NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, GT },
/* w */{ NO, NO, NO, NO, NO, EQ, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, GT },
/* h */ { NO, NO, NO, NO, NO, NO, EQ, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, GT },
/* i */ { NO, NO, NO, NO, NO, NO, NO, EQ, NO, NO, NO, NO, NO, NO, NO, NO, NO, GT },
/* l */ { NO, NO, NO, NO, NO, NO, NO, NO, EQ, NO, NO, NO, NO, NO, NO, NO, NO, GT },
/* e */ { NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, LT, NO, NO, NO, NO, NO, NO, GT },
/* E */ {NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, GT },
/* a */ { NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, EQ, NO, NO, EQ, NO, GT },
/* = */ { NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, EQ, NO, NO, NO, NO, NO, NO, GT },
/* + */ { NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, EQ, NO, NO, NO, GT },
/* 1 */ { NO, NO, NO, NO, NO, GT, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, GT },
/* > */{ NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, EQ, NO, GT },
/* b */ { NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, GT },
/* c */ { NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, EQ, NO, NO, NO, NO, NO, GT },
/* # */ { LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, EQ },
};
int CharToIndex(const char* c)//定义矩阵
{
switch (*c)
{
case S: return 0;
case d: return 1;
case o: return 2;
case B: return 3;
case w: return 4;
case h: return 5;
case i: return 6;
case l: return 7;
case e: return 8;
case E: return 9;
case a: return 10;
case =: return 11;
case +: return 12;
case 1: return 13;
case >: return 14;
case b: return 15;
case c: return 16;
case #: return 17;
default: return -1;
}
}
Prece GetPrecedence(const char* c1, const char* c2) //取优先关系
{
int i, j;
i = CharToIndex(c1);//栈顶元素
j = CharToIndex(c2);//输入符号流第一个元素
if (i!=-1 && j!=-1)
{ return PreTable[i][j]; }
else
{ return ND;//否则没有优先关系 }
}
5.5 Stack的主要算法
void InitStack()//初始化符号栈
{ char c = #;
StackTop = 0;
Push(&c);
}
bool Push(const char* c)//压栈
{
if (StackTop < STACKSIZE)
{ TheStack[StackTop++] = *c;
return true; }
else
{ return false; }
}
bool Pop(char* c)//出栈
{
if (StackTop >= 0)
{ *c = TheStack[--StackTop];
return true; }
else
{ return false; }
}
bool TopValue(char* c)//取栈顶元素值
{
if (StackTop > 0)/* not null */
{ *c = TheStack[StackTop-1];
return true; }
else
{ return false; }
}
void PrintStack()//打印栈的元素
{ int i;
for (i=0; i