武汉理工大学《编译原理》课程设计说明书
11
武汉理工大学《编译原理》课程设计说明书
6 出错处理
由于输入的表达式有错误就要产生相应的出错处理函数
void err(int n) { if(n==1) cout<<\字符不匹配\ else if(n==2) cout<<\字符没有出现在产生式终结符集VT中\ else if(n==3) cout<<\没有找到合适的候选产生式来做进一步推导\ else cout<<\该句子是文法语言的句子!\}
7 语义分析及中间代码输出
根据上面给出的属性文法所规定的翻译方案,即可对输入的程序进行相应的语义分
析。对于中间代码部分,老师给的题目是以三地址的形式输出。对于三地址形式,在学习编译原理的时候接触的不是很多。我们接触的多的一般都是逆波兰式和四元式。仔细看书才发现,三地址和四元式是很相近的。比如说计算一个表达式a+b-c,四元式的形式是(+,a,b,t1),(-,t1,c,t2)。而三地址的形式为t1:=a+b,t2=t1-c。而对于跳转语句,无条件跳转如jump L1的四元式形式为(jump,-,-,L1);而其对应的三地址形式为goto L1。而对于条件跳转语句,则四元式为(jrop,a,b,L1),而三地址形式为if a rop b goto L1。
产生跳转的主要有三个地方,第一,就是if条件成立,则跳转到then后面的语局;第二,执行完then后面的语句后跳转到程序的出口;第三,就是if条件不成立则跳转到else后面的语句。在判断完if后面的条件后,保存这个布尔值,并产生跳转地址,这时,应该继续向前读取,如果碰到then这个关键字,则回填地址到then前面,否则报错。
关键是回填地址的那个函数一定要写准确。在有跳转的语句后面,一定要有跳转的地址,即要跳到什么地方。产生跳转的语句有在token这个结构体中有个地址域,用来保存转向的地址。而在产生运算结果的语句中,token这个结构体中有个result域,用来保存这个结果。 //打印词法分析结果
void print()
12
武汉理工大学《编译原理》课程设计说明书
{
cout<<\
if(count<10)cout<<'0'; cout< for(i=0;i<=sp;i++)cout< for(;queue[i]!='#';i++)cout< for(;i<=20;i++)cout<<\} //语义分析程序 void semantic() { if(VT[opr]=='=') { arr[d][1]=arr_i[opd]; arr[d][0]='='; arr[d][2]=id; arr[d][3]=' '; arr[d][4]=' '; id++; } else if(VT[opr]=='>') { arr[d][1]=arr_i[opd]; arr[d][0]='>'; arr[d][2]=id; arr[d][3]=' '; arr[d][4]=' '; id++; } else if(VT[opr]=='<') { arr[d][1]=arr_i[opd]; arr[d][0]='<'; arr[d][2]=id; arr[d][3]=' '; arr[d][4]=' '; id++; } else if(VT[opr]=='+') { //{\判断}; //{\判断}; //{\判断}; //{\判断}; 13 武汉理工大学《编译原理》课程设计说明书 arr[d][1]=arr_i[opd]; arr[d][0]='+'; arr[d][2]=id; arr[d][3]=' '; arr[d][4]=' '; id++; } else if(VT[opr]=='-') //{\判断}; { arr[d][1]=arr_i[opd]; arr[d][0]='-'; arr[d][2]=id; arr[d][3]=' '; arr[d][4]=' '; id++; } else if(VT[opr]=='*') //{\判断}; { arr[d][1]=arr_i[opd]; arr[d][0]='*'; arr[d][2]=id; arr[d][3]=' '; arr[d][4]=' '; id++; } else if(VT[opr]=='/') //{\判断}; { arr[d][1]=arr_i[opd]; arr[d][0]='/'; arr[d][2]=id; arr[d][3]=' '; arr[d][4]=' '; id++; } else if(opr==-2) //{其他字符判断}; { arr[d][1]=id-1; arr[d][0]=' '; arr[d][2]=arr_i[opd]; arr[d][3]=' '; arr[d][4]=' '; } else if(VT[opr]!='<'&&VT[opr]!='>'&&VT[opr]!='+'&&VT[opr]!='-'&&VT[opr]!='*'&&VT[opr]!='/')//{\结束符判断}; 14 武汉理工大学《编译原理》课程设计说明书 arr[d][1]=id-1; { d++; } } //输出三地址 cout<<\输出三地址:\ for(i=0;i 而三元式的输出则很简单。但也要根据它具体的语义来进行输出。如果是if语句,则要根据if后面的bool语句来实现跳转。如果为真,应该调到then后面的语句,如果为假,则跳转到else后面的语句,每个语句都有自己的标号,用label来标识。而对于每个计算结果的表达式,则首先用一个中间变量来存放结果,每次按照运算符的优先级算出一个结果,保存在中间变量中,最后将中间变量的结果赋给语句中的变量。 8 软件测试方法和结果 输入一组正确的词法和语法的if-else语句,和一组有词法错误和语法错误的if语句。 1. if {m>n} then i=i+3 else b=b/2 测试结果如下: 15