背景
本学期有编译原理课程设计,我定义的语言是一个类C语言。过程中遇到了布尔表达式优化处理的难题。这部分上课讲的是回填拉链法,但网上的资料也是很少。
遂自己琢磨实现,最终可以实现自定义语言的中间代码生成,使用递归下降法。
文法定义
<布尔表达式> ::= <布尔项>{|| <布尔项>}
<布尔项> ::= <布尔因子>{&& <布尔因子>}
<布尔因子> ::= <表达式>[<关系><表达式>]
<关系> ::= ==|!=|<|<=|>|>=
<表达式> ::= <项>{<加法运算符><项>}
<项> ::= <因子>{<乘法运算符><因子>}
<因子> ::= <标识符>|<常数>|'('<表达式>')‘
<WHILE语句> ::= while<布尔表达式>do<语句>
<IF语句> ::= if<布尔表达式>then<语句>[else<语句>]
规定布尔表达式存在与、或两种运算,与的优先级高于或,未设计非运算与括号。但因为包含了所有的关系运算符,仍然能够实现所有的逻辑关系。
回填拉链
回填拉链,一个是回填,一个是拉链。举例如下:
while (x < y) do
{
x = x + 1;
}
y = y + 1;
生成的中间代码如下:
7: (j<,x,y,9)
8: (jp,_,_,12)
9: (+,x,1,t5)
10: (=,t5,_,x)
11: (jp,_,_,7)
12: (+,y,1,t6)
13: (=,t6,_,y)
回填:执行完判断x < y指令之后,下一条语句的位置是不确定的,需要回填。
拉链:把需要回填while的真出口与假出口的中间代码都保存起来。
对于本例,while的真出口是x = x + 1指令,假出口是y = y + 1指令。
拉那些链
while (x < y || x > z && z != 5 || (x + 2)) do
{
x = x + 1;
}
y = y + 1;
对于存在与、或优先级的布尔表达式文法,需要拉三条链——while真链、while假链、布尔表达式假链。
如果x <y 我们要跳到while的真出口,如果x >y && z!=5,我们也要跳到真出口。
如果y>=x不成立,我们要跳到while的假出口。
如果x<= y,我们要跳到处理y>=x的部分,这条链我们叫做布尔表达式的假出口。
这就是我们要拉的三条链。
怎么拉链
规定每个布尔因子发射两条四元式中间代码,成真如何处理,成假如何处理。
维护程序计数器PC,使每个四元式,单独对应一个程序编号。
对于每一条链,维护一个vector,存储要填入回填地址的四元式对应的PC。
对于每条语句具体属于那条链,我们要看它后面的符号是什么。
也就是说,要通过向后看一个符号来决定他是属于哪条链。
怎么回填
回填地址是下一步要执行的程序的编号。借助拉的三条链,当确定要执行的指令后,每条链填写对应的回填地址即可。
代码
以处理while语句为例,if处理方法一样。throw表示错误处理,不用理会。
v1,v2,v3分别是while真链,while假链,布尔表达式假链。
void Semantic::whileSent()
{
vector<int> v1, v2;
if (sym == WHILE)
{
pos++;
if (sym == ZUOXIAO)
{
int temp_PC = progCount;
pos++;
boolExp(v1, v2);
if (sym == YOUXIAO)
{
pos++;
if (sym == DO)
{
for (auto it : v1)
qvec[it].dest = to_string(progCount);
pos++;
sentence();
emit("jp", "_", "_", to_string(temp_PC));
for (auto it : v2)
qvec[it].dest = to_string(progCount);
}
else
throw(15);
}
else
throw(15);
}
else
throw(15);
}
else
throw(15);//while error
}
void Semantic::boolExp(vector<int>& v1, vector<int>& v2)//<boolTerm>{OR <boolTerm>}
{
vector<int> v3;
boolTerm(v1, v2, v3);
for (auto it : v3)
qvec[it].dest = to_string(progCount);
while (sym == OR)
{
pos++;
v3.clear();
boolTerm(v1, v2, v3);
for (auto it : v3)
qvec[it].dest = to_string(progCount);
}
if (sym == YOUXIAO)//follow(boolExp),如果遇到了follow,不算错
{
return;
}
else
{
cout << __LINE__ << endl;
throw(10);
}
}
void Semantic::boolTerm(vector<int>& v1, vector<int>& v2, vector<int>& v3)//<boolFactor> {AND <boolFactor>}
{
boolFactor(v1, v2, v3);
while (sym == AND)
{
pos++;
boolFactor(v1, v2, v3);
}
if (sym == YOUXIAO || sym == OR)//follow(boolTerm),如果遇到了follow,不算错
{
return;
}
else
{
cout << __LINE__ << endl;
throw(10);
}
}
void Semantic::boolFactor(vector<int>& v1, vector<int>& v2, vector<int>& v3)
{
int d1, d2;
string n1, n2;
try
{
expression(n1, d1);//situation2:<expression>[<guanxi> <expression>]
string op;
switch (sym)
{
case DAYU:
op = "j>";
goto L;
case XIAOYU:
op = "j<";
goto L;
case DADENG:
op = "j>=";
goto L;
case XIAODENG:
op = "j<=";
goto L;
case DENGDENG:
op = "j=";
goto L;
case BUDENG:
op = "j!=";
L:
pos++;
expression(n2, d2);
if (sym == AND)
{
emit(op, n1, n2, to_string(progCount + 2));//真
v3.push_back(progCount);
emit("jp", "_", "_");//假
}
else if (sym == OR)
{
v1.push_back(progCount);
emit(op, n1, n2);
emit("jp", "_", "_", to_string(progCount + 1));
}
else if (sym == YOUXIAO)
{
v1.push_back(progCount);
emit(op, n1, n2);
v2.push_back(progCount);
emit("jp", "_", "_");
}
else
{
cout << __LINE__ << endl;
throw(10);
}
break;
case AND:
op = "jnz";
emit(op, n1, "_", to_string(progCount + 2));//真
v3.push_back(progCount);
emit("jp", "_", "_");//假
break;
case OR:
op = "jnz";
v1.push_back(progCount);
emit(op, n1, "_");
emit("jp", "_", "_", to_string(progCount + 1));
break;
case YOUXIAO:
op = "jnz";
v1.push_back(progCount);
emit(op, n1, "_");
v2.push_back(progCount);
emit("jp", "_", "_");
break;
default:
throw(10);
}
}
catch (int x)
{
throw(10);
}
}
测试样例
while (x < y || x > z && z != 5 || (x + 2)) do
{
x = x + 1;
}
y = y + 1;
输出如下:
7: (j<,x,y,16)
8: (jp,_,_,9)
9: (j>,x,z,11)
10: (jp,_,_,13)
11: (j!=,z,5,16)
12: (jp,_,_,13)
13: (+,x,2,t5)
14: (jnz,t5,_,16)
15: (jp,_,_,19)
16: (+,x,1,t6)
17: (=,t6,_,x)
18: (jp,_,_,7)
19: (+,y,1,t7)
20: (=,t7,_,y)