文章目录
- 一、实验要求
- 二、实验设计
- 三、实验结果
- 四、附完整代码
补录与分享本科实验,以示纪念。
一、实验要求
在词法分析、语法分析和语义分析程序的基础上,将C−−源代码翻译为中间代码。
要求将中间代码输出成线性结构(三地址代码),使用虚拟机小程序(附录B)来测试中间代码的运行结果。
由于在后面的实验中还会用到本次实验已经写好的代码,因此保持一个良好的代码风格、系统地设计代码结构和各模块之间的接口对于整个实验来讲相当重要!
- 基本要求
- 对于正确的测试样例,输出可以在虚拟机上运行的中间代码文件。
- 在程序可以生成正确的中间代码(“正确”是指该中间代码在虚拟机小程序上运行结果正确)的前提下,效率也是最终评分的关键因素。
- 附加要求
- 修改前面对C−−源代码的假设2和3,使源代码中:
a) 可以出现结构体类型的变量(但不会有结构体变量之间直接赋值)。
b) 结构体类型的变量可以作为函数的参数(但函数不会返回结构体类型的值)。 - 修改前面对C−−源代码的假设2和3,使源代码中:
c) 一维数组类型的变量可以作为函数参数(但函数不会返回一维数组类型的值)。
d) 可以出现高维数组类型的变量(但高维数组类型的变量不会作为函数的参数或返回类值)。
本实验只实现了abc,没有实现d。
二、实验设计
1、translate
该函数使用switch-case寻找需要处理的节点进行处理,否则继续寻找下层结点:
void translate(Node *h) {
if (h == NULL) return;
switch (h->type) {
case Specifier:
return;
case FunDec: {
translateFunDec(h);
break;
}
case Dec: {
translateDec(h);
break;
}
case Stmt: {
translateStmt(h);
break;
}
default: {
for (int i = 0; i < h->childNum; i++)
translate(h->child[i]);
break;
}
}
}
语义分析需要对每个匹配的产生式进行分析,因此需要写专门的函数进行操作。每个函数的操作均不一样,但也拥有相同的操作:
bool checkNode(Node *node, Types type) {
if (node == NULL) {
addLogNullNode(type);
return false;
}
else if (node->type != type) {
addLogTypeDismatch(type);
return false;
}
addLogStartDealing(type);
return true;
}
bool hasBrothers(Node *node, int n, ...) {
va_list vaList;
va_start(vaList, n);
Types next;
for (int i = 0; i < n; ++i) {
next = va_arg(vaList, Types);
if (node == NULL || next != node->type) return false;
node = node->brother;
}
return node == NULL;
}
2、translateExp
我们注意到,一个exp的处理需要分两种情况:刚定义和已定义。即未被处理和已被处理过。于是我们添加了一个参数option:option = 0表示exp未被用过,option = 1表示exp已被用过。
这样做的另一个好处是,可以实现exp值的向上传递。
因此,translateExp函数对每一个匹配的产生式都进行了两种处理:option = 0和option = 1。
void translateExp(Node *h, char *place, int option) {
if (h->child[0]->type == _LP) {
return translateExp(h->child[1], place, option);
} else if (h->childNum == 3 && h->child[1]->type == _ASSIGNOP) {
char temp[MAX_LENGTH];
translateExp(h->child[0], temp, 0);
translateExp(h->child[2], temp, 1);
if (place != NULL) {
if (option == 0) {
strcpy(place, temp);
} else {
addIrCode(3, place, ":=", temp);
}
}
} else if (h->childNum == 3 && h->child[1]->type == _LP) {
if (place == NULL) {
if (strcmp(h->child[0]->name, "read") == 0)
return;
char temp[MAX_LENGTH];
newTemp(temp);
addIrCode(4, temp, ":=", "CALL", h->child[0]->name);
} else {
if (option == 0)
newTemp(place);
if (strcmp(h->child[0]->name, "read") == 0)
addIrCode(2, "READ", place);
else
addIrCode(4, place, ":=", "CALL", h->child[0]->name);
}
} else if (h->childNum == 4 && h->child[1]->type == _LP) {
if (place == NULL) {
if (strcmp(h->child[0]->name, "write") == 0) {
char temp[MAX_LENGTH];
translateExp(h->child[2]->child[0], temp, 0);
addIrCode(2, "WRITE", temp);
} else {
FunDefUnit *f = getFunction(h->child[0]->name);
translateArgs(h->child[2], f->parameterList, 0);
char temp[MAX_LENGTH];
newTemp(temp);
addIrCode(4, temp, ":=", "CALL", h->child[0]->name);
}
} else {
if (strcmp(h->child[0]->name, "write") == 0) {
char temp[MAX_LENGTH];
translateExp(h->child[2]->child[0], temp, 0);
addIrCode(2, "WRITE", temp);
if (option == 0) {
place[0] = '#';
place[1] = '0';
place[2] = '\0';
} else {
addIrCode(3, place, ":=", "#0");
}
} else {
FunDefUnit *f = getFunction(h->child[0]->name);
translateArgs(h->child[2], f->parameterList, 0);
if (option == 0)
newTemp(place);
addIrCode(4, place, ":=", "CALL", h->child[0]->name);
}
}
}
if (place == NULL)return;
if (h->child[0]->type == _INT) {
if (option == 0) {
sprintf(place, "#%d", h->child[0]->intValue);
} else {
char temp[MAX_LENGTH];
sprintf(temp, "#%d", h->child[0]->intValue);
addIrCode(3, place, ":=", temp);
}
} else if (h->child[0]->type == _ID && h->childNum == 1) {
if (option == 0) {
strcpy(place, h->child[0]->name);
} else {
addIrCode(3, place, ":=", h->child[0]->name);
}
} else if (h->childNum == 3 &&
(h->child[1]->type == _PLUS || h->child[1]->type == _MINUS || h->child[1]->type == _STAR ||
h->child[1]->type == _DIV)) {
char temp1[MAX_LENGTH], temp2[MAX_LENGTH];
translateExp(h->child[0], temp1, 0);
if ((temp1[0] == '#' && temp1[1] == '0') && (h->child[1]->type == _STAR || h->child[1]->type == _DIV)) {
if (option == 0) {
place[0] = '#';
place[1] = '0';
place[2] = '\0';
} else {
addIrCode(3, place, ":=", "#0");
}
}
translateExp(h->child[2], temp2, 0);
if ((temp2[0] == '#' && temp2[1] == '0') && (h->child[1]->type == _STAR || h->child[1]->type == _DIV)) {
if (option == 0) {
place[0] = '#';
place[1] = '0';
place[2] = '\0';
} else {
addIrCode(3, place, ":=", "#0");
}
} else if (temp1[0] == '#' && temp2[0] == '#') {
int i1 = strtol(&temp1[1], NULL, 10);
int i2 = strtol(&temp2[1], NULL, 10);
if (h->child[1]->type == _PLUS) {
if (option == 0) {
sprintf(place, "#%d", i1 + i2);
} else {
char temp[MAX_LENGTH];
sprintf(temp, "#%d", i1 + i2);
addIrCode(3, place, ":=", temp);
}
} else if (h->child[1]->type == _MINUS) {
if (option == 0) {
sprintf(place, "#%d", i1 - i2);
} else {
char temp[MAX_LENGTH];
sprintf(temp, "#%d", i1 - i2);
addIrCode(3, place, ":=", temp);
}
} else if (h->child[1]->type == _STAR) {
if (option == 0) {
sprintf(place, "#%d", i1 * i2);
} else {
char temp[MAX_LENGTH];
sprintf(temp, "#%d", i1 * i2);
addIrCode(3, place, ":=", temp);
}
} else {
if (option == 0) {
sprintf(place, "#%d", i1 / i2);
} else {
char temp[MAX_LENGTH];
sprintf(temp, "#%d", i1 / i2);
addIrCode(3, place, ":=", temp);
}
}
} else if (temp2[0] == '#' && temp2[1] == '0') {
if (option == 0)
strcpy(place, temp1);
else
addIrCode(3, place, ":=", temp1);
} else if (temp1[0] == '#' && temp1[1] == '0' && h->child[1]->type == _PLUS) {
if (option == 0)
strcpy(place, temp2);
else
addIrCode(3, place, ":=", temp2);
} else {
char op[2];
op[1] = '\0';
if (h->child[1]->type == _PLUS) op[0] = '+';
else if (h->child[1]->type == _MINUS) op[0] = '-';
else if (h->child[1]->type == _STAR) op[0] = '*';
else op[0] = '/';
if (option == 0) {
newTemp(place);
}
addIrCode(5, place, ":=", temp1, op, temp2);
}
} else if (h->child[0]->type == _MINUS) {
char temp[MAX_LENGTH];
translateExp(h->child[1], temp, 0);
if (temp[0] == '#') {
int i = strtol(&temp[1], NULL, 10);
if (option == 0) {
sprintf(place, "#%d", -i);
} else {
char temp1[MAX_LENGTH];
sprintf(temp1, "#%d", -i);
addIrCode(3, place, ":=", temp1);
}
} else {
if (option == 0) {
newTemp(place);
}
addIrCode(5, place, ":=", "#0", "-", temp);
}
} else if (h->child[0]->type == _NOT || h->child[1]->type == _RELOP || h->child[1]->type == _AND ||
h->child[1]->type == _OR) {
char label1[MAX_LENGTH], label2[MAX_LENGTH];
newLabel(label1);
newLabel(label2);
if (option == 0)
newTemp(place);
addIrCode(3, place, ":=", "#0");
translateCond(h, label1, label2);
addIrCode(3, "LABEL", label1, ":");
addIrCode(3, place, ":=", "#1");
addIrCode(3, "LABEL", label2, ":");
} else if (h->childNum == 4 && h->child[1]->type == _LB) {
char temp1[MAX_LENGTH], temp2[MAX_LENGTH];
getLocation(h->child[0], temp1);
translateExp(h->child[2], temp2, 0);
if (temp2[0] == '#' && temp2[1] == '0') {
char temp[MAX_LENGTH];
if (temp1[0] == '&')
strcpy(temp, &temp1[1]);
else
sprintf(temp, "*%s", temp1);
if (option == 0) {
strcpy(place, temp);
} else {
addIrCode(3, place, ":=", temp);
}
} else if (temp2[0] == '#') {
int i = strtol(&temp2[1], NULL, 10);
char temp[MAX_LENGTH], tempi[MAX_LENGTH];
sprintf(tempi, "#%d", i * currentSize);
newTemp(temp);
addIrCode(5, temp, ":=", temp1, "+", tempi);
char result[MAX_LENGTH];
sprintf(result, "*%s", temp);
if (option == 0)
strcpy(place, result);
else
addIrCode(3, place, ":=", result);
} else {
char temp[MAX_LENGTH], tempi[MAX_LENGTH], result[MAX_LENGTH], num[MAX_LENGTH];
sprintf(num, "#%d", currentSize);
newTemp(temp);
newTemp(tempi);
addIrCode(5, tempi, ":=", temp2, "*", num);
addIrCode(5, temp, ":=", temp1, "+", tempi);
sprintf(result, "*%s", temp);
if (option == 0)
strcpy(place, result);
else
addIrCode(3, place, ":=", result);
}
} else if (h->childNum == 3 && h->child[1]->type == _DOT) {
char left[MAX_LENGTH], temp[MAX_LENGTH], result[MAX_LENGTH];
getLocation(h->child[0], left);
int offseti = structGetOffset(currentStruct, h->child[2]->name);
char offset[MAX_LENGTH];
sprintf(offset, "#%d", offseti);
newTemp(temp);
addIrCode(5, temp, ":=", left, "+", offset);
sprintf(result, "*%s", temp);
if (option == 0)
strcpy(place, result);
else
addIrCode(3, place, ":=", result);
}
}
3、translateStmt
和translate函数类似,匹配每一个产生式做出相应的操作,其中可以用到translateExp处理exp结点:
void translateStmt(Node *h) {
switch (h->child[0]->type) {
case Exp: {
translateExp(h->child[0], NULL, 0);
break;
}
case CompSt: {
translate(h->child[0]);
break;
}
case _RETURN: {
char temp[MAX_LENGTH];
translateExp(h->child[1], temp, 0);
addIrCode(2, "RETURN", temp);
break;
}
case _IF: {
char label1[MAX_LENGTH], label2[MAX_LENGTH], label3[MAX_LENGTH];
newLabel(label1);
newLabel(label2);
if (h->childNum == 7) {
newLabel(label3);
}
translateCond(h->child[2], label1, label2);
addIrCode(3, "LABEL", label1, ":");
translate(h->child[4]);
if (h->childNum == 7)
addIrCode(2, "GOTO", label3);
addIrCode(3, "LABEL", label2, ":");
if (h->childNum == 7) {
translate(h->child[6]);
addIrCode(3, "LABEL", label3, ":");
}
break;
}
case _WHILE: {
char label1[MAX_LENGTH], label2[MAX_LENGTH], label3[MAX_LENGTH];
newLabel(label1);
newLabel(label2);
newLabel(label3);
addIrCode(3, "LABEL", label1, ":");
translateCond(h->child[2], label2, label3);
addIrCode(3, "LABEL", label2, ":");
translate(h->child[4]);
addIrCode(2, "GOTO", label1);
addIrCode(3, "LABEL", label3, ":");
break;
}
}
}
4、translateArgs
(1)如果Args→Exp COMMA Args,则继续处理Args,即函数的第一个if语句。
(2)分情况考虑,如果exp不为数组或结构,则翻译exp,即函数的第二个if语句。
(3)否则,exp为数组或结构。首先使用getlocation函数获取其地址,然后将其加入irCode。
void translateArgs(Node *h, VarDefUnit **args, int count) {
if (h->childNum == 3)
translateArgs(h->child[2], args, count + 1);
if (args[count]->varType != _ARR_STRUCT_) {
char temp[MAX_LENGTH];
translateExp(h->child[0], temp, 0);
addIrCode(2, "ARG", temp);
}else {
char temp[MAX_LENGTH];
getLocation(h->child[0], temp);
addIrCode(2, "ARG", temp);
}
}
三、实验结果
- t1.cmm
int main()
{
int n;
n = read();
if (n > 0) write(1);
else if (n < 0) write (-1);
else write(0);
return 0;
}
执行中间代码生成:
中间代码:
FUNCTION main :
READ n
IF n > #0 GOTO label0
GOTO label1
LABEL label0 :
WRITE #1
GOTO label2
LABEL label1 :
IF n < #0 GOTO label3
GOTO label4
LABEL label3 :
WRITE #-1
GOTO label5
LABEL label4 :
WRITE #0
LABEL label5 :
LABEL label2 :
RETURN #0
中间代码执行结果(输入 2):
- t2.cmm
int fact(int n)
{
if (n == 1)
return n;
else
return (n * fact(n - 1));
}
int main()
{
int m, result;
m = read();
if (m > 1)
result = fact(m);
else
result = 1;
write(result);
return 0;
}
执行中间代码生成:
中间代码:
FUNCTION fact :
PARAM n
IF n == #1 GOTO label0
GOTO label1
LABEL label0 :
RETURN n
GOTO label2
LABEL label1 :
_t0 := n - #1
ARG _t0
_t1 := CALL fact
_t2 := n * _t1
RETURN _t2
LABEL label2 :
FUNCTION main :
READ m
IF m > #1 GOTO label3
GOTO label4
LABEL label3 :
ARG m
result := CALL fact
GOTO label5
LABEL label4 :
result := #1
LABEL label5 :
WRITE result
RETURN #0
中间代码执行结果(输入 5):
- t3.cmm
struct Operands
{
int o1;
int o2;
};
int add(struct Operands temp)
{
return (temp.o1 + temp.o2);
}
int main()
{
int n;
struct Operands op;
op.o1 = 1;
op.o2 = 2;
n = add(op);
write(n);
return 0;
}
执行中间代码生成:
中间代码:
FUNCTION add :
PARAM temp
_t0 := temp + #0
_t1 := temp + #4
_t2 := *_t0 + *_t1
RETURN _t2
FUNCTION main :
DEC op 8
_t3 := &op + #0
*_t3 := #1
_t4 := &op + #4
*_t4 := #2
ARG &op
n := CALL add
WRITE n
RETURN #0
中间代码执行结果:
- t4.cmm
int add(int temp[2])
{
return (temp[0] + temp[1]);
}
int main()
{
int op[2];
int r[1][2];
int i = 0, j = 0;
while (i < 2) {
while (j < 2) {
op[j] = i + j;
j = j + 1;
}
r[0][i] = add(op);
write(r[0][i]);
i = i + 1;
j = 0;
}
return 0;
}
执行中间代码生成:
中间代码:
FUNCTION add :
PARAM temp
_t0 := temp + #4
_t1 := *temp + *_t0
RETURN _t1
FUNCTION main :
DEC op 8
DEC r 8
i := #0
j := #0
LABEL label0 :
IF i < #2 GOTO label1
GOTO label2
LABEL label1 :
LABEL label3 :
IF j < #2 GOTO label4
GOTO label5
LABEL label4 :
_t3 := j * #4
_t2 := &op + _t3
_t8 := i + j
*_t2 := _t8
j := j + #1
GOTO label3
LABEL label5 :
_t5 := i * #8
_t4 := &r + _t5
ARG &op
_t9 := CALL add
*_t4 := _t9
_t7 := i * #8
_t6 := &r + _t7
WRITE *_t6
i := i + #1
j := #0
GOTO label0
LABEL label2 :
RETURN #0
中间代码执行结果:
四、附完整代码
github 链接:https://github.com/zheliku/byyl---Intermediate-Code-Generation。