F( ) /* 识别<因式>*/ {
if (SYM=’标识符’) /*在此设运算对象i为标识符,即简单变量*/ {
ADVANCE;
return Entry(i.词文); /*以标识符的词文为名字查、填符号表,可理解为返回标识符的值*/ } else
if ( SYM=’(’ ) {
ADVANCE; PLACE=E( ); if ( SYM=’)’ ) {
ADVANCE; return PLACE; }
else ERROR; /*例如:输出“缺少‘)’错误”*/ }
else ERROR; /*例如:输出“算术表达式应以‘标识符’或‘(’开头”*/
}
说明:
① 程序四中出现的主要语义变量和辅助函数的功能为:
E1_PLACE:文法符号E1的一个语义属性,用于描述变量在符号表中登记项的序号(>0时)或临时变量的编号(<0时),可理解为代表其值。
void GEN(char *Op, char *Arg1, char *Arg2, char *Result):用来生成一个四元式,将其送到四元式表中。参考代码如下:
void GEN(char *Op, char *Arg1, char *Arg2, char *Result) {
strcpy (pQuad[NXQ].op, Op); /*pQuad为全局变量,是用于存放四元式的数组*/ strcpy (pQuad[NXQ].arg1, Arg1); strcpy (pQuad[NXQ].arg2, Arg2); strcpy (pQuad[NXQ].result, Result);
NXQ++; /*全局变量NXQ用于指示所要产生的下一个四元式的编号*/ }
char *NewTemp(void):产生临时变量的函数,每调用一次都产生一个新的临时变量,并返回这个新的临时变量名,临时变量名产生的顺序依次为T1、T2、T3、……。例如:
char *NewTemp(void) /*产生一个临时变量*/ {
char *TempID=(char *)malloc(MAXLENGTH);
sprintf (TempID, “T%d”, NXTemp++); /*整型变量NXTemp指示临时变量的编号*/ return TempID; }
② 注意修改已在前面两个实验中完成的词法、语法分析器,以便在此基础上进行语义分析。如有必要,从总体设计的角度出发,重新定义整个系统所需要的一些数据结构、宏和全局变量等。例如:
/*定义与词法分析器的接口*/
union WORDCONTENT /*存放单词词文内容的联合*/
{
char Val1[MAXLENGTH]; /*对于标识符、关键字或由一个以上字符组成的复合单词结构的
词文(如:=、<=、<>等),采用字符串作为其值的内部表示*/
int Val2; /*对于数值常量采用其二进制值作为它们的内部表示*/ float Val3;
char Val4; /*记录由一个字符组成的单词的词文(如+、-、*、/ 等)*/ };
struct WORD /*单词的二元式形式表示*/ {
int Sym; /*单词的类别编码*/
union WORDCONTENT value; /*单词的值*/
}word; /*word存放由词法分析程序扫描得到的二元式形式的单词*/
/*定义语法(语义)分析器的接口*/
struct QUATERNION /*四元式表的结构*/ {
char op[MAXLENGTH]; /*操作符*/
char arg1[MAXLENGTH]; /*第一个操作数*/ char arg2[MAXLENGTH]; /*第二个操作数*/ char result[MAXLENGTH]; /*运算结果*/ }*pQuad; /*存放四元式的数组*/
这样用于处理表达式、项和因式的函数原型可分别写为char *E(void)、char *T(void)和char *F(void)。在此仅给出处理表达式的函数的参考代码:
char *E(void) {
char opp[2], *E1_place, *E2_place, *Temp_place; E1_place=T( );
while (word.Sym==PL || word.Sym==MI) /*单词为’+’或’?’*/ {
sprintf(opp, ”%c”, word.value.Val4);
scanner( ); /*调扫描器读下一个单词,并将其二元式形式的表示送入全局变量word中*/ E2_place=T( );
Temp_place=NewTemp( );
GEN(opp, E1_place, E2_place, Temp_place); E1_place=Temp_place; }
return E1_place; }