每个节点生成的指令都是一个长长的指令列表,那么得弄几个小工具将这些列表给连接起来。
// 将一个指令追加到表末尾
static struct List* appendIns(struct List* list, void* ins)
{
list->addTo(list, ins, list->count(list));
return list;
}
// 将 back 连接到 front 之后
static struct List* appendInsList(struct List* front, struct List* back)
{
while (0 != back->count(back)) {
appendIns(front, back->popElementAt(back, 0));
}
back->finalize(back);
return front;
}
// 这两个函数的返回值设计是为了支持链式操作,所以……
// 有些代码可能看起来很晕
指令生成,先挑简单的上。
BasicBlockNode
在符号表那里定义过两个函数 enterBasicBlock 和 leaveBasicBlock,现在它们要被调用了。
struct List* insBasicBlockNode(void* node)
{
struct BasicBlockNode* self = (struct BasicBlockNode*)node;
enterBasicBlock();
struct List* list = (struct List*)newArrayList(),* sublist;
struct AbstractSyntaxNode* sub = self->block;
while (NULL != sub) {
sublist = sub->createInstruction(sub);
appendInsList(list, sublist);
sub = sub->nextNode;
}
leaveBasicBlock();
return list;
}
这两个调用的中间,基本块的生成了内部每个语句的指令,将它们全部拼接在一起。
IntegerNode / RealNode
这两个嘛……
struct List* insIntegerNode(void* node)
{
struct List* list = (struct List*)newArrayList();
struct IntParamInstruction* loadInt = (struct IntParamInstruction*)
allocate(sizeof(struct IntParamInstruction));
loadInt->code = CONST_INT;
loadInt->param = ((struct IntegerNode*)node)->intValue;
appendIns(list, loadInt);
return list;
}
struct List* insRealNode(void* node)
{
struct List* list = (struct List*)newArrayList();
struct RealParamInstruction* loadReal = (struct RealParamInstruction*)
allocate(sizeof(struct RealParamInstruction));
loadReal->code = CONST_REAL;
loadReal->param = ((struct RealNode*)node)->realValue;
appendIns(list, loadReal);
return list;
}
小心,LOAD_XXXX 指的是从内存某个地址上取一个数到栈顶,而这里用到的是 CONST_XXX,是直接将指令中的常数放在栈顶。
ArithmaticNode
struct List* insArithmaticNode(void* node)
{
struct AbstractValueNode* arith = ((struct ArithmaticNode*)node)->arith;
AcceptType type = arith->typeOf(arith); // 取得算式的类型
struct List* insList = arith->createInstruction(arith);
struct IntParamInstruction* pop = (struct IntParamInstruction*)
allocate(sizeof(struct IntParamInstruction));
pop->code = POP; // 算式结束后,弹出栈顶的数
// 根据类型确定该怎么来弹
if (INTEGER == type) {
pop->param = INT_SIZE;
} else {
pop->param = REAL_SIZE;
}
appendIns(insList, pop);
return insList;
}
VariableNode
Q:这个难道会很简单?
A:有的时候我们得把架子搭在没有实现的东西上面。
struct List* insVariableNode(void* node)
{
struct List* getAddr = addrOfVar(node); // here,先用着再说
struct NoParamInstruction* loadVal = (struct NoParamInstruction*)
allocate(sizeof(struct NoParamInstruction));
loadVal->code = (INTEGER == ((struct VariableNode*)node)->typeOf(node)) ?
LOAD_INT : LOAD_REAL; // 确定类型
return appendIns(getAddr, loadVal); // 把 LOAD 指令加上
}
下回分解:
流程控制语句
本文解析了编译器中不同类型的节点如何生成指令,并通过具体示例展示了BasicBlockNode、IntegerNode、RealNode等的基本操作及指令生成过程。
888

被折叠的 条评论
为什么被折叠?



