Bootstrap

语义分析及中间代码生成

实验四 语义分析及中间代码生成
1.实验目的
(1)通过上机实习,加深对语法制导翻译原理的理解,掌握将语法分析 所识别的语法范畴变换为某种中间代码的语义翻译方法。
(2)掌握目前普遍采用的语义分析方法──语法制导翻译技术。
(3)给出 PL/0 文法规范,要求在语法分析程序中添加语义处理,对于语法正确的表达式,输出其中间代码;对于语法正确的算术表达式,输出其计算值。
2.实验内容
(1)已给 PL/0 语言文法,在实验二或实验三的表达式语法分析程序里,添加语义处理部分,输出表达式的中间代码,用四元式序列表示。
(2) PL/0 算术表达式的语义计算:
PL/0 算术表达式,例如:2+35 作为输入。
输出: 17
PL/0 表达式的中间代码表示
PL/0 表达式,例如: a
(b+c)。
输出: (+,b,c,t1) (,a,t1,t2)
3.设计思想
(1)语义规则: 属性计算的过程即是语义处理的过程对于文法的每一个产生式配备一组属性的计算规则,则称为语义规则。
终结符只有综合属性,它由词法分析器提供。
非终结符既可以有综合属性也可以有继承属性,文法开始符号的所有继承属性作为属性计算前的初始值。
产生式右边符号的继承属性和产生式左边符号的综合属性都必须提供一个计算规则。
产生式左边符号的继承属性和产生式右边符号的综合属性由其它产生式的属性规则计算。
(2)基于递归下降翻译器的设计
递归下降分析法的原理是利用函数之间的递归调用来模拟语法树自上而下的构建过程。从根节点出发,自顶向下为输入串中寻找一个最左匹配序列,建立一棵语法树。对于每个非终结符的继承属性当作形式参数,函数的返回值当作非终结符的继承属性;对于终结符要初始化所有的继承属性。再进行分析过程中,非终结符根据当前的输入符号决定使用哪个产生式候选。
(3) 加入递归下降翻译器子程序伪码
表达式递归下降子程序为:
function表达式:string;
string s1, s2, s3, result;
BEGIN
IF SYM=’+’ OR SYM=’-’ THEN
ADVANCE;
ELSE IF SYM =FIRST(项)
ELSE ERROR;
BEGIN s1:=项;
END;
WHILE SYM=’+’ OR SYM=’-’ THEN
BEGIN
ADVANCE;
S2:=项;
result := newtemp();
emit(SYM,s1,s2,result);
s1:= result;
END;
Return result;
END;
项递归下降子程序为:
function 项:string;
string s1, s2, s3, result;
BEGIN
IF SYM =FIRST(因子) THEN
BEGIN
s1:=因子;
END;
ELSE ERROR;
WHILE SYM =’
’OR SYM=’/’ THEN
IF SYM =FIRST(因子) THEN
BEGIN
ADVANCE;
S2:=因子;
result := newtemp();
emit(SYM,s1,s2,result);
s1:= result;
END;
Return result;
END;
ELSE ERROR;
因子递归下降子程序为:
function 因子:string;
string s;
BEGIN
IF SYM =’(’ THEN
ADVANCE;
s:=表达式;
ADVANCE;
IF SYM=’)’ THEN
ADVANCE;
Return s;
ELSE ERROR;
ELSE IF SYM =FIRST(因子) THEN
ADVANCE;
ELSE ERROR;
END;

4.程序流程图

5.实验结果

6.实验总结
(1)编写代码之前需要写出递归下降翻译器的伪代码,重点就是要找到对于每个非终结符的属性哪些是继承属性,哪些是综合属性。然后将继承属性作为参数,综合属性作为返回值,进行计算。利用实验二所写的递归下降分析器的伪代码做出改写,加入参数返回值以及一些初始化。
(2)编写代码的时候,需要用到实验一和实验二的代码,写实验一代码的时候没考虑到后面会用到,直接将结果输出并没有保存中间结果,以至于自己在编码的时候需要先将实验一的结果存放在一个自定义的结构体中,里面包含词法分析的两个因素:值和类型。而分析器分析的时候,直接调取这个结构体的内容,四元式的结果也会放在一个特殊的结构体,里面记录了四元式的四个值,方便输出。如果是数字运算式,可以模拟计算器对于这四个值进行计算,并且需要数组和判定运算符函数来判断是数字还是辅助变量,根据对应符号进行运算。
(3)通过这次实验,从词法分析到语法分析到语义分析的知识点有了大致的回顾,并且重点回顾了每个阶段输入什么,输出什么,这些信息怎么存储,用什么算法来计算。还需要进一步优化自己的代码,比如在这次的实验代码过程中,需要改进的是将词法分析和语法分析合并,降低时间复杂度,提高执行效率。
(4)通过这四次的实验过程,让我对于编译原理这门课有了比较清晰的认识,可能理论课当时听懂了,过一会可能就会遗忘。但实验课不一样,花费了很久时间然后又是动手敲代码,又是写实验报告梳理思路更加深了对于这门课的理解。通过学习编译原理,感觉用到了数据结构,算法等思维理解,又需要对于许多概念的理解记忆。这也是这门课的难点所在。通过这次学习,懂得更要注重对于基础科目的掌握,不断加强和拓展自己的计算机思维。
7.附录(实验代码)
#include <bits/stdc++.h> //万能头文件
using namespace std;
struct sv
{
string s; //词法分析的类型
string v; //词法分析变量的值
};
struct sc
{
string fuhao; //符号
string a; //第一个操作数
string b; //第二个操作数
string result; //结果
};
string input; //输入全局
int cnt; //全局变量
int k=0; //sv输入
int lala=0;
sv result[200];//存放结果
sc shuchu[200];//存放输出的四元组
int xxx=0;//sc 的下标
int ans=0;//遍历的时候的下标
bool error=true;//出错标志
int isletter=0;
int t[1001];
string biaodashi();
string xiang();
string yinzi();
string newtemp() ///产生新变量名t1,t2等
{
char pq;
char mm[18];
pq=(char
)malloc(18);
lala++;
//itoa(lala,mm,10);
snprintf(mm,sizeof(mm),"%d",lala);
strcpy(pq+1,mm);
pq[0]=‘t’;
string s;
s=pq;
return s;
}
bool judge (string input, string s) ///判断是否和目标串匹配
{
int i=0;
if (input.length()!=s.length()) return false;
else
{
for(i=0;i<s.length();i++)
{
if(input[i]!=s[i]) return false; ///遍历
}
return true;
}
}
bool judge1 (string input, string s) ///判断是否和目标串匹配
{
if(input[0]==s[0]) return true;
// if (input.length()!=s.length()) return false;
else return false;

}
void feifuhao(string p) ///判断非符号的程序,包含判断关键字,标识符,常数
{
if(judge (p,“begin”)) ///判断是否跟目标串相同,相同的话输出结果
{
result[k].s=“beginsym”;
result[k].v=p;
k++;
}
else if(judge (p,“call”)) ///判断是否跟目标串相同,相同的话输出结果
{
result[k].s=“callsym”;
result[k].v=p;
k++;
}
else if(judge (p,“const”)) ///判断是否跟目标串相同,相同的话输出结果
{
result[k].s=“constsym”;
result[k].v=p;
k++;
}
else if(judge (p,“do”)) ///判断是否跟目标串相同,相同的话输出结果
{
result[k].s=“dosym”;
result[k].v=p;
k++;
}
else if(judge (p,“end”)) ///判断是否跟目标串相同,相同的话输出结果
{
result[k].s=“endsym”;
result[k].v=p;
k++;
}
else if(judge (p,“if”)) ///判断是否跟目标串相同,相同的话输出结果
{
result[k].s=“ifsym”;
result[k].v=p;
k++;
}
else if(judge (p,“odd”)) ///判断是否跟目标串相同,相同的话输出结果
{
result[k].s=“oddsym”;
result[k].v=p;
k++;
}
else if(judge (p,“procedure”)) ///判断是否跟目标串相同,相同的话输出结果
{
result[k].s=“proceduresym”;
result[k].v=p;
k++;
}
else if(judge (p,“read”)) ///判断是否跟目标串相同,相同的话输出结果
{
result[k].s=“readsym”;
result[k].v=p;
k++;
}
else if(judge (p,“var”)) ///判断是否跟目标串相同,相同的话输出结果
{
result[k].s=“varsym”;
result[k].v=p;
k++;
}
else if(judge (p,“then”)) ///判断是否跟目标串相同,相同的话输出结果
{
result[k].s=“thensym”;
result[k].v=p;
k++;
}
else if(judge (p,“write”)) ///判断是否跟目标串相同,相同的话输出结果
{
result[k].s=“writesym”;
result[k].v=p;
k++;
}
else if(judge (p,“while”)) ///判断是否跟目标串相同,相同的话输出结果
{
result[k].s=“whilesym”;
result[k].v=p;
k++;
}
else
{
int flag=0;
for(int i=0;i<p.length();i++)
{
if(!isdigit(p[i])) //判断是否是标识符
{
flag=1;
result[k].s=“ident”;
result[k].v=p;
k++;
break;
}
}
if(!flag) //判断是否是数字
{
result[k].s=“number”;
result[k].v=p;
k++;
}
}
}
int change(string aa,int cnt) ///防止多个运算符组成,返回正确下标
{
int x=0;
char f[15]={’+’,’-’,’’,’/’,’=’,’<’,’>’,’:’,’(’,’)’,’,’,’;’,’.’};
for(int i=0;i<13;i++)
{
if(aa[cnt]f[i])
{
x=i;
}
}
if(x
5)
{
if(aa[cnt+1]’>’) //如果运算符是两个符号组成,cnt+1
{
cnt=cnt+1;
return cnt;
}
else if(aa[cnt+1]
’=’) //判断两个运算符相连
{
cnt=cnt+1;
return cnt;
}
}
if(x==7) //判断:=
{
cnt=cnt+1;
return cnt;
}
return cnt;
}
void fuhao (string aa,int cnt) ///对运算符和界符的输出
{
int x=0;
char f[15]={’+’,’-’,’
’,’/’,’=’,’<’,’>’,’:’,’(’,’)’,’,’,’;’,’.’};
for(int i=0;i<13;i++)
{
if(aa[cnt]f[i])
{
x=i;
}
}
if(x
0)
{
result[k].s=“plus”;
result[k].v=f[x];
k++;
}
if(x1)
{
result[k].s=“minus”;
result[k].v=f[x];
k++;
}
if(x
2)
{
result[k].s=“times”;
result[k].v=f[x];
k++;
}
if(x3)
{
result[k].s=“slash”;
result[k].v=f[x];
k++;
}
if(x
4)
{
result[k].s=“eql”;
result[k].v=f[x];
k++;
}
if(x5)
{
if(aa[cnt+1]
’>’)
{
cnt=cnt+1;
result[k].s=“neq”;
result[k].v="<>";
k++;
}
else if(aa[cnt+1]’=’)
{
result[k].s=“leq”;
result[k].v="<=";
k++;
}
else
{
result[k].s=“lss”;
result[k].v="<";
k++;
}
}
if(x
6)
{
if(aa[cnt+1]’=’)
{
result[k].s=“geq”;
result[k].v=">=";
k++;// cout<<"(geq,>=)"<<endl;
}
else
{
result[k].s=“gtr”;
result[k].v=">";
k++;
}
}
if(x
7)
{
result[k].s=“becomes”;
result[k].v=":=";
k++; // cout<<"(becomes,:=)"<<endl;
}
if(x8)
{
result[k].s=“lparen”;
result[k].v="(";
k++;
}
if(x
9)
{
result[k].s=“rparen”;
result[k].v=")";
k++;
}
if(x10)
{
result[k].s=“comma”;
result[k].v=",";
k++;
}
if(x
11)
{
result[k].s=“semicolon”;
result[k].v=";";
k++;
}
if(x==12)
{
result[k].s=“period”;
result[k].v=".";
k++;
}
}
void cifa() ///词法分析
{
string aa;
while(cin>>aa)
{
cnt=0;
const char d = " ±/=<>:(),;.";
char p;
///运用空格和运算符和界符分割字符串并且遍历
char buf[1001] ;
strcpy(buf , aa.c_str()); //字符串转成数组
p = strtok(buf,d); //p是一个char

while§
{
if(aa[cnt]==p[0]) //当前无符号
{
feifuhao§;
cnt=cnt+strlen§;
}
else ///当前是符号
{
while(aa[cnt]!=p[0])
{
fuhao(aa,cnt);
cnt=change(aa,cnt);
cnt=cnt+1;
}
feifuhao§;
cnt=cnt+strlen§;
}
// printf("%s\n",p);
p=strtok(NULL,d); //下移一位,进行遍历
}
for(int i=cnt;i<aa.length();i++)
{
//cout<<aa[i];
fuhao(aa,i); //防止最后有多个符号
}
}
}
void hasletter() ///判断是那种类型的计算
{
for(int i=0;i<k;i++)
{
if(judge(result[i].s,“ident”))
{
isletter=1;
break;
}
}
}
string biaodashi() ///表达式的递归下降分析函数
{
string ss;
string s1,s2,s3;
if(ans>k) return NULL;
if(judge(result[ans].v,"+") || judge(result[ans].v,"-")) ///加减符号
{
ans++;
if(ans>k)
{
cout<<1<<endl;
error=false;///错误判定
}
s1=xiang();
}
else if( judge(result[ans].v,"(") ||judge(result[ans].s,“ident”) ||judge(result[ans].s,“number”))
{
s1=xiang();//项目判定,前面条件是first集合
}
else
{
cout<<2<<endl;
error=false;///错误判定
}//
while(judge(result[ans].v,"+") || judge(result[ans].v,"-"))
{
int anstemp=ans;
ans++;
if(ans>k)
{
cout<<3<<endl;
error=false;///错误判定
}
s2=xiang(); //项目循环
shuchu[xxx].fuhao=result[anstemp].v;
shuchu[xxx].a=s1;
shuchu[xxx].b=s2;
shuchu[xxx].result=newtemp();
ss=shuchu[xxx].result;
s1=ss;
xxx++;
}
return ss;
}
string xiang() ///项的递归下降分析函数
{
string ss;
string s1,s2,s3;
if(ans>k) return NULL;
s1=yinzi(); //因子判断
while(judge(result[ans].v,"") || judge(result[ans].v,"/"))
{
int anstemp=ans;
ans++;
if(ans>k)
{
cout<<4<<endl;
error=false;///错误判定
}
s2=yinzi();
shuchu[xxx].a=s1;
shuchu[xxx].fuhao=result[anstemp].v;
shuchu[xxx].b=s2;
shuchu[xxx].result=newtemp();
ss=shuchu[xxx].result;
s1=ss;
xxx++;
}
return s1;
}
string yinzi() ///因子的递归下降分析函数
{
string ss;
if(ans>=k) return NULL;
if(judge(result[ans].s,“ident”) ||judge(result[ans].s,“number”)) //开头字母或数字
{
ss=result[ans].v;
ans++;
if(ans>k)
{
cout<<5<<endl;
error=false;///错误判定
}
}
else if(judge(result[ans].v,"(")) //左括号
{
ans++;
ss= biaodashi(); //表达式
if(judge(result[ans].v,")")) //右括号
{
ans++;
if(ans>k)
{
cout<<6<<endl;
error=false;///错误判定
}
}
}
else
{
cout<<7<<endl;
error=false;///错误判定
}
return ss;
}
string delet(string s) ///删除第一个字母
{
char c[101];
for(int i=0;i<s.length()-1;i++)
{
c[i]=s[i+1];
}
return c;
}
void jisuan(int i)
{
char
end;
if(judge(shuchu[i].fuhao,"*")) //如果是乘法
{
if(!judge1(shuchu[i].a,“t”)) //判断第一个符号是字母还是数字
{
if(!judge1(shuchu[i].b,“t”))
{
//强制类型转换
t[i+1]=static_cast(strtol(shuchu[i].a.c_str(),&end,10))*static_cast(strtol(shuchu[i].b.c_str(),&end,10));
}
}
}
else
{
if(!judge1(shuchu[i].b,“t”))
{
string cc;
cc=delet(shuchu[i].a);
//强制类型转换
int zz=static_cast(strtol(cc.c_str(),&end,10));
t[i+1]=t[zz]*static_cast(strtol(shuchu[i].b.c_str(),&end,10));
}
else
{
string d;
d=delet(shuchu[i].a);
int yy=static_cast(strtol(d.c_str(),&end,10));
string cc;
cc=delet(shuchu[i].b);
int zz=static_cast(strtol(cc.c_str(),&end,10));
t[i+1]=t[yy]*t[zz];
}
if(judge(shuchu[i].fuhao,"+"))
{
if(!judge1(shuchu[i].a,“t”))
{
if(!judge1(shuchu[i].b,“t”))
{
t[i+1]=static_cast(strtol(shuchu[i].a.c_str(),&end,10))+static_cast(strtol(shuchu[i].b.c_str(),&end,10));
}
else
{
string cc;
cc=delet(shuchu[i].b);
int yy=static_cast(strtol(shuchu[i].a.c_str(),&end,10));
int zz=static_cast(strtol(cc.c_str(),&end,10));
t[i+1]=yy+t[zz];
}
}
else
{
if(!judge1(shuchu[i].b,“t”))
{
string cc;
cc=delet(shuchu[i].a);
int zz=static_cast(strtol(cc.c_str(),&end,10));
t[i+1]=t[zz]+static_cast(strtol(shuchu[i].b.c_str(),&end,10));
}
else
{
string d;
d=delet(shuchu[i].a);
int yy=static_cast(strtol(d.c_str(),&end,10));
string cc;
cc=delet(shuchu[i].b);
int zz=static_cast(strtol(cc.c_str(),&end,10));
t[i+1]=t[yy]+t[zz];
}
}
}
}

}
int main()
{
cifa(); //词法分析函数
hasletter();//判断类型
biaodashi();//语法分析和语义分析
if(isletter==1)//进行输出
{
for(int i=0;i<xxx;i++)
{
cout<<"("<<shuchu[i].fuhao<<","<<shuchu[i].a<<","<<shuchu[i].b<<","<<shuchu[i].result<<")"<<endl;
}
}
else //进行输出,计算结果
{
for(int i=0;i<xxx;i++)
{
jisuan(i);
}
cout<<t[xxx]<<endl;
}
return 0;
}

;