Code Generate
Tiny+代码生成
目录
Tiny+代码生成... 1
一. 说明... 2
二. CGEN.C说明... 2
1. 对于string的处理... 2
2. 对于bool表达式的处理... 2
3. 对于op表达式的处理... 3
4. 对于while语句的处理... 4
5. 对于read语句的处理... 4
6. 对于write语句的处理... 5
三. 运行结果... 6
四. 实验中遇到的问题... 7
五. 实验感想... 7
六. 附录(详细运行结果)... 7
一. 说明
代码生成部分主要在CODE.C,CODE.H,CGEN.C,CGEN.H中实现。其中对CODE.C未作修改。
二. CGEN.C说明
1. 对于string的处理
由于要确定内存分配空间,所以规定string的最大长度是MAXSTRING,即32。
把string里面的char一个一个的存放到内存的gp空间里,然后把首字母的内存地址放到ac寄存器上,即返回string首字母的内存地址。
关键代码:
case StringK :
if (TraceCode) emitComment("-> String") ;
/* gen code to store a string */
for(i=0; i<MAXSTRING; i++){
char ch = tree->attr.name[i];
if(ch == '\0')
break;
emitRM("LDC",ac,(int)ch,0,"load a char");
emitRM("ST",ac,location+i,gp,"String: store a char");
}
emitRM("LDC",ac,location,0,"load the string address");
location += MAXSTRING-1;
if (TraceCode) emitComment("<- String") ;
break; /* StringK */
2. 对于bool表达式的处理
主要模仿opK表达式:
- Ø AND操作符:
先判断左边表达式是否为0,若是则直接跳到false case,否则跳到true case;
再判断右边表达式是否为1,若是则跳到true case,否则跳到false case。
关键代码:
case AND:
emitComment(“->op: And”);
emitRM(“JEQ”,ac1,1,pc,”br if false”) ;
emitRM(“JGT”,ac,2,pc,”br if true”) ;
emitRM(“LDC”,ac,0,ac,”false case”) ;
emitRM(“LDA”,pc,1,pc,”unconditional jmp”) ;
emitRM(“LDC”,ac,1,ac,”true case”) ;
emitComment(“<-op:And”);
break;
- Ø OR操作符:
先判断左边表达式是否为1,若是则跳到true case,否则跳到false case;
再判断右边表达式是否为1,若是则跳到true case,否则跳到false case。
关键代码:
case OR:
emitComment(“->op: OR”);
emitRM(“JGT”,ac1,3,pc,”br if true”) ;
emitRM(“JGT”,ac,2,pc,”br if true”) ;
emitRM(“LDC”,ac,0,ac,”false case”) ;
emitRM(“LDA”,pc,1,pc,”unconditional jmp”) ;
emitRM(“LDC”,ac,1,ac,”true case”) ;
emitComment(“<-op:OR”);
break;
3. 对于op表达式的处理
添加了>,>=,<=三个比较符
关键代码:
case MT :
emitRO(“SUB”,ac,ac1,ac,”op >”) ;
emitRM(“JGT”,ac,2,pc,”br if true”) ;
emitRM(“LDC”,ac,0,ac,”false case”) ;
emitRM(“LDA”,pc,1,pc,”unconditional jmp”) ;
emitRM(“LDC”,ac,1,ac,”true case”) ;
break;
case LOE :
emitRO(“SUB”,ac,ac1,ac,”op >”) ;
emitRM(“JLE”,ac,2,pc,”br if true”) ;
emitRM(“LDC”,ac,0,ac,”false case”) ;
emitRM(“LDA”,pc,1,pc,”unconditional jmp”) ;
emitRM(“LDC”,ac,1,ac,”true case”) ;
break;
case MOE :
emitRO(“SUB”,ac,ac1,ac,”op >”) ;
emitRM(“JGE”,ac,2,pc,”br if true”) ;
emitRM(“LDC”,ac,0,ac,”false case”) ;
emitRM(“LDA”,pc,1,pc,”unconditional jmp”) ;
emitRM(“LDC”,ac,1,ac,”true case”) ;
break;
4. 对于while语句的处理
while语句的代码生成:
p1是child[0],即while的判断条件;p2是child[1],即while的执行语句。
关键代码:
case WhileK:
if (TraceCode) emitComment(“-> while”) ;
p1 = tree->child[0] ;
p2 = tree->child[1] ;
savedLoc1 = emitSkip(0);
emitComment(“while: jump after body comes back here”);
/* generate code for test */
cGen(p1);
savedLoc2 = emitSkip(1) ;
emitComment(“while: jump to end belongs here”);
/* recurse on body part */
cGen(p2);
/*go back to the test without any condition*/
emitRM_Abs(“LDA”,pc,savedLoc1,”jmp to the while test”) ;
/*if while test is false jump to the end*/
currentLoc = emitSkip(0) ;
emitBackup(savedLoc2) ;
emitRM_Abs(“JEQ”,ac,currentLoc,”while: jmp to the end”);
emitRestore() ;
if (TraceCode) emitComment(“<- while”) ;
break; /* while */
5. 对于read语句的处理
输入赋值前添加了变量类型的判断,如果类型不是String的话就按照原来的代码执行;如果类型是String的话,则把该string的char字符一个个放到内存gp空间里,并把首字母的内存地址赋值给该变量。
关键代码:
case ReadK:
if (TraceCode) emitComment("-> read") ;
loc = st_lookup(tree->attr.name);
/*if the id is a string, then read and store the chars in the string one by one*/
if(type_lookup(tree->attr.name) == String){
for(i=0; i<MAXSTRING; i++){
emitRO("IN",ac,0,0,"read a char");
emitRM("ST",ac,location+i,gp,"read: store value");
}
emitRM("LDC",ac,location,0,"load the string address");
location += MAXSTRING-1;
}
emitRM("ST",ac,loc,gp,"read: store value");
if (TraceCode) emitComment("<- read") ;
break;
6. 对于write语句的处理
输出前添加了变量类型的判断,如果类型不是String的话就按照原来的代码执行;如果类型是String的话,则变量储存的内存地址,把该string的char字符一个个从内存gp空间里取出来并打印。
关键代码:
case WriteK:
if (TraceCode) emitComment("-> write") ;
/* generate code for expression to write */
p1 = tree->child[0] ;
cGen(p1);
if(p1->type == String){
for(i=0; i<MAXSTRING; i++){
/*
*Here has a problem, ac stores the address of a string,
*but i don't know how to find the value in gp memory according to this address.
*It seems that tm doesn't provide this service.
*The offset here i written is ac+i, but actually is the value of ac plus i. :(
*/
emitRM("LD",ac1,(ac)+i,gp,"write: load value”);
emitRO(“OUT”,ac1,0,0,”write ac”);
}
}
else
emitRO(“OUT”,ac,0,0,”write ac”);
if (TraceCode) emitComment(“<- write”) ;
break;
三. 运行结果
测试代码:
string str;
int x, fact;
str:= 'sample program' ;
read x;
if x>0 and x<100 then {don't compute if x<=0}
fact:=1;
while x>0 do
fact:=fact*x;
x:=x-1
end;
write fact
end
输出结果:(文字版放在附录)
四. 实验中遇到的问题
修改write语句关于string输出的时候,遇到了问题。相关代码如下:
if(p1->type == String){
for(i=0; i<MAXSTRING; i++){
/*
*Here has a problem, ac stores the address of a string,
*but i don't know how to find the value in gp memory according to this address.
*It seems that tm doesn't provide this service.
*The offset here i written is ac+i, but actually is the value of ac plus i. :(
*/
emitRM("LD",ac1,(ac)+i,gp,"write: load value”);
emitRO(“OUT”,ac1,0,0,”write ac”);
}
}
TM代码貌似没有提供把寄存器ac的值作为内存地址,去取这个地址对应的东西。所以此处的实现是有问题的。由于是TM代码的缺陷,暂时想不到解决的方案。还有一个问题是,TM能否输出字符的问题。我看原来tiny生成代码,好像只能输出数字,未知如何控制输出是字符。
五. 实验感想
老实说,这个代码生成我写了一个通宵。其实我觉得代码生成比语义分析要难,难是难在关于string的处理。我请教了部分生成TM代码的同学,因为他们说很简单,仔细问了一下,发现他们都直接把string当成integer去处理。我觉得这个是很有问题的!
个人觉得寄存器只能存string的地址,而不是整个string。string和数字是不能等同的!这是一个值还是一个指针(也就是地址)的差别!我绝不允许自己这样子蒙混过关的!(聊过以后,那些同学也承认了自己的偷工减料,但懒得去改。)
于是我把string的字符一个个存放到内存里,赋值给变量的话是直接赋值其地址,也就是说String变量里存的不是string本身,而是存放这个string的内存地址。虽然这次写的时间比预想中要多,但至少我认真对待了,而且对内存管理、指针等概念有了更深刻的认识。
——黄聪
六. 附录(详细运行结果)
测试代码:
string str;
int x, fact;
str:= 'sample program' ;
read x;
if x>0 and x<100 then {don't compute if x<=0}
fact:=1;
while x>0 do
fact:=fact*x;
x:=x-1
end;
write fact
end
运行结果:
* TINY Compilation to TM Code
* File: test.tm
* Standard prelude:
0: LD 6,0(0) load maxaddress from location 0
1: ST 0,0(0) clear location 0
* End of standard prelude.
* -> assign
* -> String
2: LDC 0,115(0) load a char
3: ST 0,3(5) String: store a char
4: LDC 0,97(0) load a char
5: ST 0,4(5) String: store a char
6: LDC 0,109(0) load a char
7: ST 0,5(5) String: store a char
8: LDC 0,112(0) load a char
9: ST 0,6(5) String: store a char
10: LDC 0,108(0) load a char
11: ST 0,7(5) String: store a char
12: LDC 0,101(0) load a char
13: ST 0,8(5) String: store a char
14: LDC 0,32(0) load a char
15: ST 0,9(5) String: store a char
16: LDC 0,112(0) load a char
17: ST 0,10(5) String: store a char
18: LDC 0,114(0) load a char
19: ST 0,11(5) String: store a char
20: LDC 0,111(0) load a char
21: ST 0,12(5) String: store a char
22: LDC 0,103(0) load a char
23: ST 0,13(5) String: store a char
24: LDC 0,114(0) load a char
25: ST 0,14(5) String: store a char
26: LDC 0,97(0) load a char
27: ST 0,15(5) String: store a char
28: LDC 0,109(0) load a char
29: ST 0,16(5) String: store a char
30: LDC 0,3(0) load the string address
* <- String
31: ST 0,0(5) assign: store value
* <- assign
* -> read
32: ST 0,1(5) read: store value
* <- read
* -> if
* -> Bool
* -> Op
* -> Id
33: LD 0,1(5) load id value
* <- Id
34: ST 0,0(6) op: push left
* -> Const
35: LDC 0,0(0) load const
* <- Const
36: LD 1,0(6) op: load left
37: SUB 0,1,0 op >
38: JGT 0,2(7) br if true
39: LDC 0,0(0) false case
40: LDA 7,1(7) unconditional jmp
41: LDC 0,1(0) true case
* <- Op
42: ST 0,0(6) op: push left
* -> Op
* -> Id
43: LD 0,1(5) load id value
* <- Id
44: ST 0,-1(6) op: push left
* -> Const
45: LDC 0,100(0) load const
* <- Const
46: LD 1,-1(6) op: load left
47: SUB 0,1,0 op <
48: JLT 0,2(7) br if true
49: LDC 0,0(0) false case
50: LDA 7,1(7) unconditional jmp
51: LDC 0,1(0) true case
* <- Op
52: LD 1,0(6) op: load left
* ->op: And
53: JEQ 1,1(7) br if false
54: JGT 0,2(7) br if true
55: LDC 0,0(0) false case
56: LDA 7,1(7) unconditional jmp
57: LDC 0,1(0) true case
* <-op:And
* <- Bool
* if: jump to else belongs here
* -> assign
* -> Const
59: LDC 0,1(0) load const
* <- Const
60: ST 0,2(5) assign: store value
* <- assign
* -> while
* while: jump after body comes back here
* -> Op
* -> Id
61: LD 0,1(5) load id value
* <- Id
62: ST 0,0(6) op: push left
* -> Const
63: LDC 0,0(0) load const
* <- Const
64: LD 1,0(6) op: load left
65: SUB 0,1,0 op >
66: JGT 0,2(7) br if true
67: LDC 0,0(0) false case
68: LDA 7,1(7) unconditional jmp
69: LDC 0,1(0) true case
* <- Op
* while: jump to end belongs here
* -> assign
* -> Op
* -> Id
71: LD 0,2(5) load id value
* <- Id
72: ST 0,0(6) op: push left
* -> Id
73: LD 0,1(5) load id value
* <- Id
74: LD 1,0(6) op: load left
75: MUL 0,1,0 op *
* <- Op
76: ST 0,2(5) assign: store value
* <- assign
* -> assign
* -> Op
* -> Id
77: LD 0,1(5) load id value
* <- Id
78: ST 0,0(6) op: push left
* -> Const
79: LDC 0,1(0) load const
* <- Const
80: LD 1,0(6) op: load left
81: SUB 0,1,0 op -
* <- Op
82: ST 0,1(5) assign: store value
* <- assign
83: LDA 7,-23(7) jmp to the while test
70: JEQ 0,13(7) while: jmp to the end
* <- while
* -> write
* -> Id
84: LD 0,2(5) load id value
* <- Id
85: OUT 0,0,0 write ac
* <- write
* if: jump to end belongs here
58: JEQ 0,28(7) if: jmp to else
86: LDA 7,0(7) jmp to end
* <- if
* End of execution.
87: HALT 0,0,0
代码和文档下载请按 https://files.cnblogs.com/sandywong/TINY%e5%8a%a0.rar