本学期有编译原理课程设计,我定义的语言是一个类C语言。过程中遇到了布尔表达式优化处理的难题。这部分上课讲的是回填拉链法,但网上的资料也是很少。
遂自己琢磨实现,最终可以实现自定义语言的中间代码生成,使用递归下降法。
<布尔表达式> ::= <布尔项>{|| <布尔项>} <布尔项> ::= <布尔因子>{&& <布尔因子>} <布尔因子> ::= <表达式>[<关系><表达式>] <关系> ::= ==|!=|<|<=|>|>= <表达式> ::= <项>{<加法运算符><项>} <项> ::= <因子>{<乘法运算符><因子>} <因子> ::= <标识符>|<常数>|'('<表达式>')‘::= while<布尔表达式>do<语句> ::= 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>=x不成立,我们要跳到while的假出口。
如果x<= y,我们要跳到处理y>=x的部分,这条链我们叫做布尔表达式的假出口。
这就是我们要拉的三条链。
规定每个布尔因子发射两条四元式中间代码,成真如何处理,成假如何处理。
维护程序计数器PC,使每个四元式,单独对应一个程序编号。
对于每一条链,维护一个vector,存储要填入回填地址的四元式对应的PC。
对于每条语句具体属于那条链,我们要看它后面的符号是什么。
也就是说,要通过向后看一个符号来决定他是属于哪条链。
回填地址是下一步要执行的程序的编号。借助拉的三条链,当确定要执行的指令后,每条链填写对应的回填地址即可。
代码以处理while语句为例,if处理方法一样。throw表示错误处理,不用理会。
v1,v2,v3分别是while真链,while假链,布尔表达式假链。
void Semantic::whileSent() { vector测试样例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 & v1, vector & v2)// {OR } { vector 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 & v1, vector & v2, vector & v3)// {AND } { 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 & v1, vector & v2, vector & v3) { int d1, d2; string n1, n2; try { expression(n1, d1);//situation2: [ ] 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)
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)