每个节点生成的指令都是一个长长的指令列表,那么得弄几个小工具将这些列表给连接起来。
// 将一个指令追加到表末尾 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 指令加上 }
下回分解:
流程控制语句