符号表与中间代码
符号表是记录编译过程中的源代码中的符号的数据结构, 符号表几乎在编译的每一个阶段都能用到, 符号表中可以保存很多信息, 如行数,类型,作用域等, 但是<<编译原理与实践>>中TINY的符号表很简单, 只是用来保存符号出现的函数, 在这里还要进行扩展, 使TINY语言带有作用域.
中间代码也是编译过程中的一个中间形式, 它是语法树的线性表示. 使用中间代码能够使代码生成程序更简单, 同时中间代码还有利于代码优化. <<编译原理与实践>>中使用三地址码来表示TINY的中间代码.
一 TINY的作用域
规定TINY语言的作用域除了全局作用域外, if和repeat语句产生局部作用域.
9)IF-STMT-> if EXP then STMT-SEQUENCE end
这里if语句产生两个作用域, 一个是EXP的作用域, 它是if语句的作用域包含在全局作用域中, 还有就是STMT-SEQUENCE 产生的作用域它包含在if语句作用域(也就是EXP)作用域中.
10)IF-STMT-> if EXP then STMT-SEQUENCT0 else STMT-SEQUENCE1 end
这里的STMT-SEQUENCE0和STMT-SEQUENCE1分属与两个不同的作用域, 但是它们都包含在if语句的作用域中.
11)REPEAT-STMT-> repeat STMT-SEQUENCE until EXP
repeat语句产生一个作用域, 它就是repeat语句本身的作用域, 包括STMT-SEQUENCE和EXP, 都包含在全局作用域中.
例如
read x;
read x;
read y;
read z;
repeat
read i;
if(j < x) then
j := j+i;
k := j
else
j := j–i;
k := j
end;
j := i*i
until j = 100
在这个代码中x, y, z具有全局作用域, i自在repeat语句的范围内有效, if语句中的j在if语句的作用域内定义的所以if语句的两个分句中使用的j是同一个既在j<x中定义的, 同时if语句中使用的i都是来自于repeat语句中定义的i.但是if语句两个分句中的k不是同一个, 它们是在各自的作用域中定义的. if语句执行过后if的作用域消失, 所以在if中定义的j和两个k都是消失了, 接下来的j是在repeat语句作用域内新定义的不同于if中的j, 但是until后面的j是同一个, 因为同在repeat作用域中.
二 符号表结构和作用域的表示
使用龙书中介绍的哈希表的形式来作为符号表的数据结构, 同时为每一个作用域建立一个符号表, 当前符号表指向包含它的作用域的符号表(参考龙书和<<编译原理与实践>>).
这样上面的程序的符号表表示如图:
如在else语句中引用i的过程就是在当前作用域范围内没有查找到i则转向它的上一级作用域范围一直到找到第一个i位置(就近原则), 如果没有找到i说明i是一个新的定义则将i插入到当前的作用域范围.
三 将符号表和语法树建立联系
符号表和语法树都是编译时十分重要的中间数据结构, 通过在语法书的节点上添加一个指向符号表的指针来建立两者的连接. 是编译程序通过语法树就可以访问当前节点的符号表.如图:
四 符号表的结构定义和对符号表的操作函数如下:
#define SYMTAB_BUCKET_NUMBER 101
#define HASH_KEY_SHIFT 2
/* symbol table node */
struct symattr
{
int line_no;
struct symattr* next_attr;
};
struct symnode
{
char* name;
struct symattr* attr;
struct symnode* next_node;
};
/* symbol table */
struct symtab
{
struct symnode* bucket[SYMTAB_BUCKET_NUMBER];
struct symtab* prev_effect_rang;
};
static int key(const char* symbol);
static struct symnode* new_node(const char* symbol, int line_no);
struct symtab* new_symtab(struct symtab* prev_effect_rang)
{
struct symtab* new_tab = (struct symtab*)malloc(sizeof(struct symtab));
if(new_tab == NULL)
{
fprintf(stderr, "Out of memory for malloc struct symtab/n");
exit(-1);
}
memset(new_tab, 0x00, sizeof(struct symtab));
new_tab->prev_effect_rang = prev_effect_rang;
return new_tab;
}
void insert_symtab(const char* symbol, struct symtab* table, int line_no)
{
int bucket_key = key(symbol);
struct symattr* attr = NULL;
struct symnode* node = NULL;
struct symtab* tab = table;
while(tab != NULL)
{
node = tab->bucket[bucket_key];
while(node != NULL)
{
if(strcmp(symbol, node->name) == 0)
goto target;
node = node->next_node;
}
tab = tab->prev_effect_rang;
}
target:
if(node == NULL)
{
if(table->bucket[bucket_key] == NULL)
table->bucket[bucket_key] = new_node(symbol, line_no);
else
{
node = table->bucket[bucket_key];
table->bucket[bucket_key] = new_node(symbol, line_no);
table->bucket[bucket_key]->next_node = node;
}
}
else
{
attr = node->attr;
if((node->attr = (struct symattr*)malloc(sizeof(struct symattr))) == NULL)
{
fprintf(stderr, "Out of memory for malloc struct symattr/n");
exit(-1);
}
node->attr->line_no = line_no;
node->attr->next_attr = attr;
}
}
static int key(const char* symbol)
{
int sym_len = strlen(symbol);
int count = 0;
/* int temp = 0; */
int i = 0;
for(i = 0; i < sym_len; i++)
{
/* temp = symbol[i]; */
/* temp = temp << (i+1)*HASH_KEY_SHIFT; */
/* count += temp; */
count += symbol[i] << (i+1)*HASH_KEY_SHIFT;
}
count %= SYMTAB_BUCKET_NUMBER;
return count;
}
static struct symnode* new_node(const char* symbol, int line_no)
{
struct symnode* node = NULL;
struct symattr* attr = NULL;
if((node = (struct symnode*)malloc(sizeof(struct symnode))) == NULL)
{
fprintf(stderr, "Out of memory for malloc struct symnode/n");
exit(-1);
}
if((attr = (struct symattr*)malloc(sizeof(struct symattr))) == NULL)
{
fprintf(stderr, "Out of memory for malloc struct symattr/n");
exit(-1);
}
if((node->name = (char*)malloc(strlen(symbol)+1)) == NULL)
{
fprintf(stderr, "Out of memory for malloc node->name/n");
exit(-1);
}
memset(node->name, '/0', strlen(symbol)+1);
strncpy(node->name, symbol, strlen(symbol));
attr->line_no = line_no;
attr->next_attr = NULL;
node->attr = attr;
node->next_node = NULL;
return node;
}
void print_symbol_table(TreeNode* tree)
{
struct symnode* node = NULL;
struct symattr* attr = NULL;
struct symtab* tab = NULL;
int i = 0;
while(tree != NULL)
{
tab = tree->symbol_tab;
printf("---------------------------------------/n");
printf("current effect range/n");
while(tab != NULL)
{
for(i = 0; i < SYMTAB_BUCKET_NUMBER; i++)
{
node = tab->bucket[i];
/* if(node == NULL) */
/* printf("[%d]:NULL/n", i); */
/* else */
if(node != NULL)
{
printf("[%d]: ", i);
while(node != NULL)
{
printf("name> %s .pos> ", node->name);
attr = node->attr;
while(attr != NULL)
{
printf("%d ", attr->line_no);
attr = attr->next_attr;
}
node = node->next_node;
}
printf("/n");
}
}
tab = tab->prev_effect_rang;
printf("/nprevious effect range/n");
}
print_symbol_table(tree->child[0]);
print_symbol_table(tree->child[1]);
print_symbol_table(tree->child[2]);
tree = tree->sibling;
}
}
static void build_symtab(TreeNode* tree, struct symtab* per_tab)
{
struct symtab* cur_tab = NULL;
struct symtab* exp_tab = NULL;
while(tree != NULL)
{
switch(tree->node_kind)
{
case KIND_STMT:
switch(tree->kind.stmt)
{
case KIND_IF:
tree->symbol_tab = per_tab;
/* for EXP */
if(tree->child[0] != NULL)
{
exp_tab = new_symtab(per_tab);
build_symtab(tree->child[0], exp_tab);
}
else
{
fprintf(stderr, "Bad TreeNode node!/n");
exit(-1);
}
/* for STMT-SEQUENCE0 */
if(tree->child[1] != NULL)
{
cur_tab = new_symtab(exp_tab);
build_symtab(tree->child[1], cur_tab);
}
else
{
fprintf(stderr, "Bad TreeNode node!/n");
exit(-1);
}
/* for STMT-SEQUENCE1 */
if(tree->child[2] != NULL)
{
cur_tab = new_symtab(exp_tab);
build_symtab(tree->child[2], cur_tab);
}
break;
case KIND_REPEAT:
tree->symbol_tab = per_tab;
/* for STMT-SEQUENCE */
if(tree->child[0] != NULL)
{
cur_tab = new_symtab(per_tab);
build_symtab(tree->child[0], cur_tab);
}
else
{
fprintf(stderr, "Bad TreeNode node!/n");
exit(-1);
}
/* for EXP */
if(tree->child[1] != NULL)
{
build_symtab(tree->child[1], cur_tab);
}
else
{
fprintf(stderr, "Bad TreeNode node!/n");
exit(-1);
}
break;
case KIND_ASSIGN:
tree->symbol_tab = per_tab;
insert_symtab(tree->attr.name, per_tab, tree->line_no);
if(tree->child[0] != NULL)
build_symtab(tree->child[0], per_tab);
else
{
fprintf(stderr, "Bad TreeNode node!/n");
exit(-1);
}
break;
case KIND_READ:
tree->symbol_tab = per_tab;
insert_symtab(tree->attr.name, per_tab, tree->line_no);
break;
case KIND_WRITE:
tree->symbol_tab = per_tab;
if(tree->child[0] != NULL)
build_symtab(tree->child[0], per_tab);
else
{
fprintf(stderr, "Bad TreeNode node!/n");
exit(-1);
}
break;
default:
fprintf(stderr, "Unknown TreeNode node!/n");
exit(-1);
break;
}
break;
case KIND_EXP:
switch(tree->kind.exp)
{
case KIND_OP:
tree->symbol_tab = per_tab;
if(tree->child[0] != NULL)
build_symtab(tree->child[0], per_tab);
else
{
fprintf(stderr, "Bad TreeNode node!/n");
exit(-1);
}
if(tree->child[1] != NULL)
build_symtab(tree->child[1], per_tab);
else
{
fprintf(stderr, "Bad TreeNode node!/n");
exit(-1);
}
break;
case KIND_CONST:
tree->symbol_tab = per_tab;
break;
case KIND_ID:
tree->symbol_tab = per_tab;
insert_symtab(tree->attr.name, per_tab, tree->line_no);
break;
default:
fprintf(stderr, "Unknown TreeNode node!/n");
exit(-1);
break;
}
break;
default:
fprintf(stderr, "Unknown TreeNode node!/n");
exit(-1);
break;
}
tree = tree->sibling;
}
}
五 三地址码及其实现形式
三地址码的形式如 x := y op z. 使用三地址码来翻译TINY程序使会产生很多临时变量.如TINY语句fact := fact + 1翻译成三地址码后:
t1 := fact + 1
fact = t1
这里t1就是翻译三地址代码产生的临时变量.
通常使用四元式的结构来实现三地址代码如(op, result, arg1, arg2). 对于前面的三地址码语句对应如下两条四元式:
(plus, t1, fact, 1)
(assign, fact, t1, _)
其中’_’表示四元式中该项空缺不需要使用, plus和assign表示操作符.
六 翻译成三地址码
TINY中有很多语句类型如赋值, 表达式, 循环等.
6.1 赋值语句的翻译
赋值语句是最容易的一个了, 以为三地址语句本身就是一条赋值语句.
如TINY语句:
x := y
三地址码:
x = y
四元式:
(assign, x, y, _)
6.2 表达式的翻译
如TINY语句:
x := a * (98 – b / 3)
三地址码:
t1 = b / 3
t2 = 98 – t1
t3 = a * t2
x = t3
四元式:
(div, t1, b, 3)
(minus, t2, 98, t1)
(mult, t3, a, t2)
(assign, x, t3, _)
6.3 read语句和write语句的翻译
将三地址码中加入自定义的readin和writeout操作符
如TINY语句:
read x;
write x+1
三地址码:
readin x
t1 = x + 1
writeout t1
四元式:
(readin, x, _, _)
(plus, t1, x, 1)
(writeout, t1, _, _)
6.4 if语句的翻译
if语句有两种形式
6.4.1 if EXP then STMT-SEQUENCE end
TINY语句:
if a + b < 0 then
write 0
end
三地址码:
t1 = a + b
t2 = t1 < 0
iff t2 end_label
writeout 0
label end_label
这里引入了新的操作符iff t2 end_label是当t2为false时跳转到end_label, 同时label end_label是指定标签.
四元式:
(plus, t1, a, b)
(lt, t2, t1, 0)
(iff, t2, end_label, _)
(writeout, 0, _, _)
(label, end_label, _, _)
6.4.2 if EXP then STMT-SEQUENCE end
TINY语句:
if a + b < 0 then
write 0
else
write 1
end
三地址码:
t1 = a + b
t2 = t1 < 0
iff t2 else_label
writeout 0
jump end_label
label else_label
writeout 1
label end_label
jump操作符是无条件跳转.
四元式:
(plus, t1, a, b)
(lt, t2, t1, 0)
(iff, t2, else_label, _)
(writeout, 0, _, _)
(jump, end_label, _, _)
(label, else_label, _, _)
(writeout, 1, _, _)
(label, end_label, _, _)
6.5 repeat语句的翻译
TINY语句:
repeat
write 1
unitl x < 0
三地址码:
label start_label
writeout 1
t1 = x < 0
ift t1 start_label
四元式:
(label, start_label, _, _)
(writeout, 1, _, _)
(lt, t1, x, 0)
(ift, t1, start_label, _)
七 生成中间代码的源代码:
其中获得唯一的临时变量时分为临时变量, 临时else变量, 临时end变量, 临时start变量.
临时变量如 temp@a&0007
临时else变量如 else@h&7803
临时end变量如 end@n&0246
临时start变量如 start@q&0037
typedef enum temp_op
{
plus, minus, mult, division, assign, readin, writeout, iff, ift, label, lt, eq, jump
}TEMP_OP;
typedef enum code_type
{
null, number, identifier
}CODE_TYPE;
typedef struct code_item
{
CODE_TYPE type;
int name_len;
union
{
int val;
char* name;
}item;
}CODE_ITEM;
typedef struct temp_code
{
TEMP_OP op;
CODE_ITEM result;
CODE_ITEM arg1;
CODE_ITEM arg2;
}TEMP_CODE;
static char temp_code_file[] = "tiny.temp_code";
static int fd_temp_code_file;
static TEMP_CODE output_code;
static int end_count = 0;
static char end_char_count = 'a';
static int else_count = 0;
static char else_char_count = 'a';
static int start_count = 0;
static char start_char_count = 'a';
static int temp_name_count = 0;
static char temp_name_char_count = 'a';
static char temp_string[101];
static void build_symtab(TreeNode* tree, struct symtab* per_tab);
static void build_temp_code(TreeNode* tree);
static void new_temp_name(void);
static void new_end_label(void);
static void new_else_label(void);
static void new_start_label(void);
static void write_output_code(void);
static void free_output_code(void);
static void fill_output_code_arg(TreeNode* tree, CODE_ITEM* arg);
static void print_temp_code(void);
void code_gain(TreeNode* tree)
{
struct symtab* global_table = new_symtab(NULL);
if((fd_temp_code_file = open(temp_code_file, O_WRONLY|O_CREAT|O_TRUNC,
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0)
{
fprintf(stderr, "Can't open temp code file/n");
exit(-1);
}
build_symtab(tree, global_table);
build_temp_code(tree);
close(fd_temp_code_file);
#ifdef TRACE_TEMP_CODE
print_temp_code();
#endif
}
static void new_start_label(void)
{
char temp[101] = {'/0'};
sprintf(temp, "%c&%04d", start_char_count, start_count);
temp_string[0] = '/0';
strcpy(temp_string,"start@");
strcat(temp_string, temp);
start_count++;
start_count %= 10000;
if(start_count == 0)
start_char_count++;
}
static void new_else_label(void)
{
char temp[101] = {'/0'};
sprintf(temp, "%c&%04d", else_char_count, else_count);
temp_string[0] = '/0';
strcpy(temp_string,"else@");
strcat(temp_string, temp);
else_count++;
else_count %= 10000;
if(else_count == 0)
else_char_count++;
}
static void new_end_label(void)
{
char temp[101] = {'/0'};
sprintf(temp, "%c&%04d", end_char_count, end_count);
temp_string[0] = '/0';
strcpy(temp_string,"end@");
strcat(temp_string, temp);
end_count++;
end_count %= 10000;
if(end_count == 0)
end_char_count++;
}
static void new_temp_name(void)
{
char temp[101] = {'/0'};
sprintf(temp, "%c&%04d", temp_name_char_count, temp_name_count);
temp_string[0] = '/0';
strcpy(temp_string,"temp@");
strcat(temp_string, temp);
temp_name_count++;
temp_name_count %= 10000;
if(temp_name_count == 0)
temp_name_char_count++;
}
static void build_symtab(TreeNode* tree, struct symtab* per_tab)
{
struct symtab* cur_tab = NULL;
struct symtab* exp_tab = NULL;
while(tree != NULL)
{
switch(tree->node_kind)
{
case KIND_STMT:
switch(tree->kind.stmt)
{
case KIND_IF:
tree->symbol_tab = per_tab;
/* for EXP */
if(tree->child[0] != NULL)
{
exp_tab = new_symtab(per_tab);
build_symtab(tree->child[0], exp_tab);
}
else
{
fprintf(stderr, "Bad TreeNode node!/n");
exit(-1);
}
/* for STMT-SEQUENCE0 */
if(tree->child[1] != NULL)
{
cur_tab = new_symtab(exp_tab);
build_symtab(tree->child[1], cur_tab);
}
else
{
fprintf(stderr, "Bad TreeNode node!/n");
exit(-1);
}
/* for STMT-SEQUENCE1 */
if(tree->child[2] != NULL)
{
cur_tab = new_symtab(exp_tab);
build_symtab(tree->child[2], cur_tab);
}
break;
case KIND_REPEAT:
tree->symbol_tab = per_tab;
/* for STMT-SEQUENCE */
if(tree->child[0] != NULL)
{
cur_tab = new_symtab(per_tab);
build_symtab(tree->child[0], cur_tab);
}
else
{
fprintf(stderr, "Bad TreeNode node!/n");
exit(-1);
}
/* for EXP */
if(tree->child[1] != NULL)
{
build_symtab(tree->child[1], cur_tab);
}
else
{
fprintf(stderr, "Bad TreeNode node!/n");
exit(-1);
}
break;
case KIND_ASSIGN:
tree->symbol_tab = per_tab;
insert_symtab(tree->attr.name, per_tab, tree->line_no);
if(tree->child[0] != NULL)
build_symtab(tree->child[0], per_tab);
else
{
fprintf(stderr, "Bad TreeNode node!/n");
exit(-1);
}
break;
case KIND_READ:
tree->symbol_tab = per_tab;
insert_symtab(tree->attr.name, per_tab, tree->line_no);
break;
case KIND_WRITE:
tree->symbol_tab = per_tab;
if(tree->child[0] != NULL)
build_symtab(tree->child[0], per_tab);
else
{
fprintf(stderr, "Bad TreeNode node!/n");
exit(-1);
}
break;
default:
fprintf(stderr, "Unknown TreeNode node!/n");
exit(-1);
break;
}
break;
case KIND_EXP:
switch(tree->kind.exp)
{
case KIND_OP:
tree->symbol_tab = per_tab;
if(tree->child[0] != NULL)
build_symtab(tree->child[0], per_tab);
else
{
fprintf(stderr, "Bad TreeNode node!/n");
exit(-1);
}
if(tree->child[1] != NULL)
build_symtab(tree->child[1], per_tab);
else
{
fprintf(stderr, "Bad TreeNode node!/n");
exit(-1);
}
break;
case KIND_CONST:
tree->symbol_tab = per_tab;
break;
case KIND_ID:
tree->symbol_tab = per_tab;
insert_symtab(tree->attr.name, per_tab, tree->line_no);
break;
default:
fprintf(stderr, "Unknown TreeNode node!/n");
exit(-1);
break;
}
break;
default:
fprintf(stderr, "Unknown TreeNode node!/n");
exit(-1);
break;
}
tree = tree->sibling;
}
}
static void build_temp_code(TreeNode* tree)
{
while(tree != NULL)
{
switch(tree->node_kind)
{
case KIND_STMT:
switch(tree->kind.stmt)
{
case KIND_IF:
if((tree->child[0] == NULL) ||
(tree->child[1] == NULL))
{
fprintf(stderr, "Bad TreeNode node!/n");
exit(-1);
}
if(tree->child[2] == NULL)
tree->else_label = NULL;
else
{
new_else_label();
tree->else_label = copy_string(temp_string);
}
new_end_label();
tree->end_label = copy_string(temp_string);
/* write EXP temp_code */
build_temp_code(tree->child[0]);
/* write iff code */
free_output_code();
output_code.op = iff;
fill_output_code_arg(tree->child[0], &output_code.result);
output_code.arg1.type = identifier;
if(tree->else_label == NULL)
{
output_code.arg1.name_len = strlen(tree->end_label);
output_code.arg1.item.name = copy_string(tree->end_label);
}
else
{
output_code.arg1.name_len = strlen(tree->else_label);
output_code.arg1.item.name = copy_string(tree->else_label);
}
write_output_code();
/* write STMT-SEQUENCE0 temp_code */
build_temp_code(tree->child[1]);
if(tree->else_label != NULL)
{
/* write jump end */
free_output_code();
output_code.op = jump;
output_code.result.type = identifier;
output_code.result.name_len = strlen(tree->end_label);
output_code.result.item.name = copy_string(tree->end_label);
output_code.arg1.type = null;
output_code.arg2.type = null;
write_output_code();
/* write label else */
free_output_code();
output_code.op = label;
output_code.result.type = identifier;
output_code.result.name_len = strlen(tree->else_label);
output_code.result.item.name = copy_string(tree->else_label);
output_code.arg1.type = null;
output_code.arg2.type = null;
write_output_code();
/* write STMT-SEQUENCE1 temp_code */
build_temp_code(tree->child[2]);
}
/* write label end */
free_output_code();
output_code.op = label;
output_code.result.type = identifier;
output_code.result.name_len = strlen(tree->end_label);
output_code.result.item.name = copy_string(tree->end_label);
output_code.arg1.type = null;
output_code.arg2.type = null;
write_output_code();
break;
case KIND_REPEAT:
if((tree->child[0] == NULL) ||
(tree->child[1] == NULL))
{
fprintf(stderr, "Bad TreeNode node!/n");
exit(-1);
}
free_output_code();
/* wrtie label start_label */
new_start_label();
tree->start_label = copy_string(temp_string);
output_code.op = label;
output_code.result.type = identifier;
output_code.result.name_len = strlen(tree->start_label);
output_code.result.item.name = copy_string(tree->start_label);
output_code.arg1.type = null;
output_code.arg2.type = null;
write_output_code();
/* write STMT-SEQUENCE temp_code */
build_temp_code(tree->child[0]);
/* write EXP temp_code */
build_temp_code(tree->child[1]);
/* write ift code */
free_output_code();
output_code.op = ift;
fill_output_code_arg(tree->child[1], &output_code.result);
output_code.arg1.type = identifier;
output_code.arg1.name_len = strlen(tree->start_label);
output_code.arg1.item.name = copy_string(tree->start_label);
output_code.arg2.type = null;
write_output_code();
break;
case KIND_ASSIGN:
if(tree->child[0] == NULL)
{
fprintf(stderr, "Bad TreeNode node!/n");
exit(-1);
}
free_output_code();
build_temp_code(tree->child[0]);
output_code.op = assign;
output_code.result.type = identifier;
output_code.result.name_len = strlen(tree->attr.name);
output_code.result.item.name = copy_string(tree->attr.name);
output_code.arg2.type = null;
fill_output_code_arg(tree->child[0], &output_code.arg1);
write_output_code();
break;
case KIND_READ:
free_output_code();
output_code.op = readin;
output_code.arg1.type = null;
output_code.arg2.type = null;
output_code.result.type = identifier;
output_code.result.name_len = strlen(tree->attr.name);
output_code.result.item.name = copy_string(tree->attr.name);
write_output_code();
break;
case KIND_WRITE:
if(tree->child[0] == NULL)
{
fprintf(stderr, "Bad TreeNode node!/n");
exit(-1);
}
build_temp_code(tree->child[0]);
free_output_code();
output_code.op = writeout;
output_code.arg1.type = null;
output_code.arg2.type = null;
fill_output_code_arg(tree->child[0], &output_code.result);
write_output_code();
break;
default:
fprintf(stderr, "Unknown TreeNode node!/n");
exit(-1);
break;
}
break;
case KIND_EXP:
switch(tree->kind.exp)
{
case KIND_OP:
if((tree->child[0] == NULL) || (tree->child[1] == NULL))
{
fprintf(stderr, "Bad TreeNode node!/n");
exit(-1);
}
build_temp_code(tree->child[0]);
build_temp_code(tree->child[1]);
free_output_code();
new_temp_name();
tree->temp_name = copy_string(temp_string);
output_code.result.type = identifier;
output_code.result.name_len = strlen(tree->temp_name);
output_code.result.item.name = copy_string(tree->temp_name);
fill_output_code_arg(tree->child[0], &output_code.arg1);
fill_output_code_arg(tree->child[1], &output_code.arg2);
switch(tree->attr.op)
{
case LT:
output_code.op = lt;
break;
case EQ:
output_code.op = eq;
break;
case PLUS:
output_code.op = plus;
break;
case MINUS:
output_code.op = minus;
break;
case MULT:
output_code.op = mult;
break;
case DIV:
output_code.op = division;
break;
default:
fprintf(stderr, "Unknown TreeNode node!/n");
exit(-1);
break;
}
write_output_code();
break;
case KIND_CONST:
break;
case KIND_ID:
tree->temp_name = copy_string(tree->attr.name);
break;
default:
fprintf(stderr, "Unknown TreeNode node!/n");
exit(-1);
break;
}
break;
default:
fprintf(stderr, "Unknown TreeNode node!/n");
exit(-1);
break;
}
tree = tree->sibling;
}
}
static void fill_output_code_arg(TreeNode* tree, CODE_ITEM* arg)
{
if((tree->node_kind == KIND_EXP) &&
(tree->kind.exp == KIND_CONST)) /* for const */
{
arg->type = number;
arg->name_len = 0;
arg->item.val = tree->attr.val;
}
else if((tree->node_kind == KIND_EXP) &&
(tree->kind.exp == KIND_ID)) /* for identifer */
{
arg->type = identifier;
arg->name_len = strlen(tree->attr.name);
arg->item.name = copy_string(tree->attr.name);
}
else /* for other node */
{
arg->type = identifier;
arg->name_len = strlen(tree->temp_name);
arg->item.name = copy_string(tree->temp_name);
}
}
static void write_output_code(void)
{
/* write op */
write(fd_temp_code_file, &output_code.op, sizeof(TEMP_OP));
/* write result */
write(fd_temp_code_file, &output_code.result.type, sizeof(CODE_TYPE));
if(output_code.result.type == number)
write(fd_temp_code_file, &output_code.result.item.val, sizeof(int));
else if(output_code.result.type == identifier)
{
write(fd_temp_code_file, &output_code.result.name_len, sizeof(int));
write(fd_temp_code_file, output_code.result.item.name,
output_code.result.name_len);
}
/* write arg1 */
write(fd_temp_code_file, &output_code.arg1.type, sizeof(CODE_TYPE));
if(output_code.arg1.type == number)
write(fd_temp_code_file, &output_code.arg1.item.val, sizeof(int));
else if(output_code.arg1.type == identifier)
{
write(fd_temp_code_file, &output_code.arg1.name_len, sizeof(int));
write(fd_temp_code_file, output_code.arg1.item.name,
output_code.arg1.name_len);
}
/* write arg2 */
write(fd_temp_code_file, &output_code.arg2.type, sizeof(CODE_TYPE));
if(output_code.arg2.type == number)
write(fd_temp_code_file, &output_code.arg2.item.val, sizeof(int));
else if(output_code.arg2.type == identifier)
{
write(fd_temp_code_file, &output_code.arg2.name_len, sizeof(int));
write(fd_temp_code_file, output_code.arg2.item.name,
output_code.arg2.name_len);
}
}
static void free_output_code(void)
{
/* free op */
output_code.op = plus;
/* free result */
if(output_code.result.type == identifier)
{
free(output_code.result.item.name);
output_code.result.item.name = NULL;
}
else
{
output_code.result.item.val = 0;
}
output_code.result.type = null;
output_code.result.name_len = 0;
/* free arg1 */
if(output_code.arg1.type == identifier)
{
free(output_code.arg1.item.name);
output_code.arg1.item.name = NULL;
}
else
{
output_code.arg1.item.val = 0;
}
output_code.arg1.type = null;
output_code.arg1.name_len = 0;
/* free arg2 */
if(output_code.arg2.type == identifier)
{
free(output_code.arg2.item.name);
output_code.arg2.item.name = NULL;
}
else
{
output_code.arg2.item.val = 0;
}
output_code.arg2.type = null;
output_code.arg2.name_len = 0;
}
static void print_temp_code(void)
{
ssize_t read_size = 0;
free_output_code();
if((fd_temp_code_file = open(temp_code_file, O_RDONLY)) < 0)
{
fprintf(stderr, "Can't open the temp code file!/n");
exit(-1);
}
for(;;)
{
/* read op */
if((read_size = read(fd_temp_code_file, &output_code.op, sizeof(TEMP_OP)))
<= 0)
goto end_while;
switch(output_code.op)
{
case plus:
printf(" plus ");
break;
case minus:
printf(" minus ");
break;
case mult:
printf(" mult ");
break;
case division:
printf(" division ");
break;
case lt:
printf(" lt ");
break;
case eq:
printf(" eq ");
break;
case writeout:
printf(" writeout ");
break;
case readin:
printf(" readin ");
break;
case assign:
printf(" assign ");
break;
case iff:
printf(" iff ");
break;
case ift:
printf(" ift ");
break;
case label:
printf("label ");
break;
case jump:
printf(" jump ");
break;
default:
printf("Bad temp code instration!/n");
exit(-1);
break;
}
/* read result */
if((read_size = read(fd_temp_code_file,
&output_code.result.type, sizeof(CODE_TYPE))) <= 0)
goto end_while;
switch(output_code.result.type)
{
case null:
break;
case number:
if((read_size = read(fd_temp_code_file,
&output_code.result.item.val, sizeof(int))) <= 0)
goto end_while;
printf("%d ", output_code.result.item.val);
break;
case identifier:
if((read_size = read(fd_temp_code_file,
&output_code.result.name_len, sizeof(int))) <= 0)
goto end_while;
memset(temp_string, '/0', sizeof(char)*101);
if((read_size = read(fd_temp_code_file,
temp_string, output_code.result.name_len)) <= 0)
goto end_while;
printf("%s ", temp_string);
break;
default:
printf("Bad temp code instration!/n");
exit(-1);
break;
}
/* read arg1 */
if((read_size = read(fd_temp_code_file,
&output_code.arg1.type, sizeof(CODE_TYPE))) <= 0)
goto end_while;
switch(output_code.arg1.type)
{
case null:
break;
case number:
if((read_size = read(fd_temp_code_file,
&output_code.arg1.item.val, sizeof(int))) <= 0)
goto end_while;
printf("%d ", output_code.arg1.item.val);
break;
case identifier:
if((read_size = read(fd_temp_code_file,
&output_code.arg1.name_len, sizeof(int))) <= 0)
goto end_while;
memset(temp_string, '/0', sizeof(char)*101);
if((read_size = read(fd_temp_code_file,
temp_string, output_code.arg1.name_len)) <= 0)
goto end_while;
printf("%s ", temp_string);
break;
default:
printf("Bad temp code instration!/n");
exit(-1);
break;
}
/* read arg2 */
if((read_size = read(fd_temp_code_file,
&output_code.arg2.type, sizeof(CODE_TYPE))) <= 0)
goto end_while;
switch(output_code.arg2.type)
{
case null:
break;
case number:
if((read_size = read(fd_temp_code_file,
&output_code.arg2.item.val, sizeof(int))) <= 0)
goto end_while;
printf("%d ", output_code.arg2.item.val);
break;
case identifier:
if((read_size = read(fd_temp_code_file,
&output_code.arg2.name_len, sizeof(int))) <= 0)
goto end_while;
memset(temp_string, '/0', sizeof(char)*101);
if((read_size = read(fd_temp_code_file,
temp_string, output_code.arg2.name_len)) <= 0)
goto end_while;
printf("%s ", temp_string);
break;
default:
printf("Bad temp code instration!/n");
exit(-1);
break;
}
printf("/n");
}
end_while:
if(read_size < 0)
printf("read temp code file error!/n");
close(fd_temp_code_file);
}
八 实例:
TINY程序:
write 2* ( b - c * d) + 34 / (e - 90 + (f + 3432) * g) /h + 89;
dir := a + b;
read y;
read x;
write a;
if x = 0 then { don't compute if x <= 0 }
fact := 1;
x := 2;
if (x - 9) < (ll + 4) then
x := x - 9;
ll := ll + 4
else
x := ll + 4;
ll := x -9
end;
y := 3;
write fact { output factorial of x }
end;
read i;
repeat
read x;
read y;
write x + y;
i := i - 1
until i < 0;
write i * i
编译程序输出的三地址码(四元式形式):
mult temp@a&0000 c d
minus temp@a&0001 b temp@a&0000
mult temp@a&0002 2 temp@a&0001
minus temp@a&0003 e 90
plus temp@a&0004 f 3432
mult temp@a&0005 temp@a&0004 g
plus temp@a&0006 temp@a&0003 temp@a&0005
division temp@a&0007 34 temp@a&0006
division temp@a&0008 temp@a&0007 h
plus temp@a&0009 temp@a&0002 temp@a&0008
plus temp@a&0010 temp@a&0009 89
writeout temp@a&0010
plus temp@a&0011 a b
assign dir temp@a&0011
readin y
readin x
writeout a
eq temp@a&0012 x 0
iff temp@a&0012 end@a&0000
assign fact 1
assign x 2
minus temp@a&0013 x 9
plus temp@a&0014 ll 4
lt temp@a&0015 temp@a&0013 temp@a&0014
iff temp@a&0015 else@a&0000
minus temp@a&0016 x 9
assign x temp@a&0016
plus temp@a&0017 ll 4
assign ll temp@a&0017
jump end@a&0001
label else@a&0000
plus temp@a&0018 ll 4
assign x temp@a&0018
minus temp@a&0019 x 9
assign ll temp@a&0019
label end@a&0001
assign y 3
writeout fact
label end@a&0000
readin i
label start@a&0000
readin x
readin y
plus temp@a&0020 x y
writeout temp@a&0020
minus temp@a&0021 i 1
assign i temp@a&0021
lt temp@a&0022 i 0
ift temp@a&0022 start@a&0000
mult temp@a&0023 i i
writeout temp@a&0023