编译原理 回填拉链实现短路运算 代码

编译原理 回填拉链实现短路运算 代码,第1张

编译原理 回填拉链实现短路运算 代码 背景

本学期有编译原理课程设计,我定义的语言是一个类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 && z!=5,我们也要跳到真出口。
如果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)

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5690571.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存