BIT 2024 编译原理 Lab. 4 四代编译器实验说明和要求

实验四:四代编译器实验

一、实验要求

详细实验要求请参考文件《Lab4实验说明和要求.pdf》。

二、实验思路

1、与 lab3 的对比

如果你在 lab3 就已经像我一样单独写了个函数处理表达式,那么理论上,lab4 相比于 lab3,不过就是多了对 ifwhile 等语句的处理,而其他部分几乎不需要任何改变!

这样一来,lab4 就非常简单了。因此,本文是基于 lab3 的代码上进行修改,关于 lab3 的文章在这里:BIT 2024 编译原理 Lab. 3 三代编译器实验说明和要求-CSDN博客

2、函数的划分

现在,不能简单地通过 } 的出现位置来区分不同的函数块,这是因为函数内的 ifwhile 语句块通常也会出现 }.

如果你仍然希望实现预先对函数进行划分,一种可行的做法是:维护一个变量 left_brace_minus_right_brace,它等于 左大括号的数量-右大括号的数量,当且仅当 } 的位置满足left_brace_minus_right_brace = 0 时,表明这个 } 用于划分函数是有效的。

3、句子的识别

现在,句子不总是以 ; 作为结尾,因为 ifwhile 语句块通常以 } 结尾,这意味着仅使用 ; 分割两个句子是不完全正确的。为了解决这个问题,你需要添加一些其他的条件判断。

4、句子的处理

注意:这里仅提供我的方法,实际上你应该结合自己的理解和自己的代码进行修改!

对于 ifwhile ,你觉得一个句子应该在什么地方进行划分?

我这里的做法简单来说,是按照有效的 } 进行划分,我举一个例子。有如下代码:

if ( a>3 ) {
	if ( a<10 ) {
		println_int(a);
	}
	while ( a<b ) {
		println_int(b);
		a=a+1;
	}
}

那么,对于上面的例子,我认为

if (a>3) { if (a<10) { println_int(a); } while (a<b) { println_int(b); a=a+1; } }
         Δ																		Δ

是一个句子。在这个句子中,含有两个子句,它们分别是

if (a<10) { println_int(a); }
		  Δ					Δ
while (a<b) { println_int(b); a=a+1; }
			Δ					 	 Δ

对于前者,它又含有一个子句

println_int(a);

对于后者,它含有两个子句,分别是

println_int(b);
a=a+1;

这样的结构,令我想到了递归。显然,如同我在 lab3 中单独写一个函数处理表达式,现在,我要单独写一个函数处理句子

再次重申下表达式和句子的区别。表达式的本质是一个值,不管是一个数字、变量、调用函数、简单的运算还是复杂的运算,总之,它最后一定会被计算出一个值;句子是有明确语法含义的,比如说赋值语句、输出语句、if 语句等等。

唯一特殊的例子是调用返回值是 void 类型的函数,虽然它本身不返回任何值,但是它的处理跟返回值是 int 类型的函数完全相同,可以顺便当表达式处理了。当然啦,你也可以认为它是句子,反正你总得想办法处理它吧。

对于一个句子,直接调用该函数;如果句子内部又含有句子,则递归调用这个函数。

说实话,到这个时候,我也不敢说自己的做法是不是高明,所以请你自己认真思考一下,结合你自己手头上代码,你会用什么样的方法来处理 ifwhile 的语句块?

5、if 对应的汇编语句

if 语句处理十分简单,在不考虑 else 的情况下,它的代码结构一定是:

if ( 表达式 ) {
	一些句子
}

对应的汇编是:

if结构

如果考虑 else,代码结构如下:

if ( 表达式 ) {
	句子群a
}
else {
	句子群b
}

对应的汇编是:

else结构

6、while 对应的汇编语句

while 语句处理相比于 if 稍微复杂一些,我们先不考虑 continuebreak,它的代码结构一定是:

while ( 表达式 ) {
	一些句子
}

对应的汇编是:

while结构

while 的内部每多一个 continue,内部就多一个命令跳转到 while 开头,如下图所示:

continue结构

while 的内部每多一个 break,内部就多一个命令跳转出 while,如下图所示:

break结构

你最好先理解了再写代码,不然写起来会很费劲的。

三、实验注意

  1. 该部分主要阐述本人在做该实验时踩过的坑

  2. 提交方式:和 lab3 一样

  3. 局部变量

    这里指的是 ifwhile 内部定义的变量,例如:

    if (a==b) {
    	int c;
    	c = a+b;
    	println_int(c);
    }
    

    有时候,你可能需要注意对这种变量的处理。(但是我代码里没有考虑竟然也过了,好耶!)

  4. 用例 3:注意自定义函数的 if 内部的 return

  5. 用例 6:continuebreak 并不是只能出现在 while 内部,它也可能出现在 if 的内部(当然其实也算是在 while 的内部啦)

  6. 诸如 ifwhile 不带有 {} 的情形在 lab4 中不存在,即不存在下面这种样式:

    if (a>1) a=1;
    
  7. while 内部的直接 return 不需要考虑,形如:

    while ( 条件 ) {
    	一些语句
    	return;
    }
    

    间接存在的 return 仍然需要考虑,例如:

    while ( 条件1 ) {
    	一些语句
    	if ( 条件2 ) {
    		return;
    	}
    }
    

    你怎么知道我在明知道要考虑却不考虑的情况下直接交代码还不小心全对的?!!

  8. 最后,祝愿大家早日 AC

Lab1-Lab4分别完成了词法分析,语法分析;语义分析;中间代码生成和目标代码生成. Lab1实验报告 词法分析: 能够查出C--源代码中词法未定义的字符以及任何不符合词法单元定义的字符; 识别合法的八进制,如035、072; 识别合法的十六进制数,如0x23、0X4a; 识别合法的指数形式的浮点数,如1.2、.2、1.2e+4; 语法分析: 能够查出C--源代码中的语法错误; 没有词法和语错误的情况,则打印语法树 Lab2实验报告 语义分析: 可对输入的*.cmm文件进行语义分析,并检查如下类型的错误: 错误类型1:变量在使用时未定义。 错误类型2:函数在调用时未经定义。 错误类型3:变量出现重复定义,或变量与前面定义过的结构体名字重复。 错误类型4:函数出现重复定义。 错误类型5:赋值号两边的表达式类型不匹配。 错误类型6:赋值号左边出现一个只有右值的表达式。 错误类型7:操作数类型不匹配或操作数类型与操作符不匹配。 错误类型8:return语句的返回类型与函数定义的返回类型不匹配。 错误类型9:函数调用时实参与形参的数目或类型不匹配。 错误类型10:对非数组型变量使用“[…]”(数组访问)操作符。 错误类型11:对普通变量使用“(…)”或“()”(函数调用)操作符。 错误类型12:数组访问操作符“[…]”中出现非整数。 错误类型13:对非结构体型变量使用“.”操作符。 错误类型14:访问结构体中未定义过的域。 错误类型15:结构体中域名重复定义(同一结构体中),或在定义时对域进行初始化。 错误类型16:结构体的名字与前面定义过的结构体或变量的名字重复。 错误类型17:直接使用未定义过的结构体来定义变量。 Lab3实验报告 中间代码生成: 在词法分析、语法分析和语义分析的基础上,可对输入的*.cmm文件进行中间代码生成。但不支持结构体类型的变量,不支持高维数组的变量以及不支持一维数组作为函数参数出现。 Lab4实验报告 目标代码生成: 在词法分析、语法分析、语义分析和中间代码生成程序的基础上,将C--源代码翻译为MIPS32指令序列(可以包含伪指令),并在SPIM Simulator上运行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值