首先回顾一下符号表提供的接口
AcceptType typeOf(struct VariableNode* var); int staticOffset(struct VariableNode* var, int* offsets);
前面一个获取类型在这里并不是特别需要——那是在加载变量值的时候考虑的。至于 staticOffset 这个函数,功能已经非常强大了,我们现在要做的就是,计算运行时才能确定的地址。先搭个架子,明确一下我们要干的主要工作
struct List* addrOfVar(void* node) { struct VariableNode* self = (struct VariableNode*)node; struct List* insList = (struct List*)newArrayList(); // 获取维数 int addr, nrDim = self->dimInfor->length(self->dimInfor); struct IntParamInstruction* loadBase = (struct IntParamInstruction*) allocate(sizeof(struct IntParamInstruction)); loadBase->code = CONST_INT; appendIns(insList, loadBase); if (0 == nrDim) { // 普通变量, 静态时就能确定地址. loadBase->param = staticOffset(self, NULL); } else { // 是数组, 这里是我们要做的 } return insList; }
当然首先得用符号表的接口,像这样
int* dims = (int*)allocate(nrDim * sizeof(int)); // 申请一块空间, 用来存放数组大小信息 int i; struct IntParamInstruction* loadOffset; struct NoParamInstruction* cast,* mult,* add; struct AbstractValueNode* value; addr = staticOffset(self, dims); // 取~ loadBase->param = addr; // 这里增加指令 revert(dims); // 记得干掉这些空间. PS: GCC似乎是支持在栈中直接写变长数组的, 如 int dim[nrDim];
剩下的就是一个筛选过程了,筛选传入的数组中那些值为 -1 的项目,不过呢,因为我们没有限定数组下标必须是整数(声明时必须是,但是引用时可以是实型量),因此我们还要承担变量转型的责任(注意到上面的代码中,声明的无参数指令中有一个叫做 cast)
for (i = 0; i < nrDim; ++i) { if (-1 != dims[i]) { // 这一维是变量~ loadOffset = (struct IntParamInstruction*) allocate(sizeof(struct IntParamInstruction)); loadOffset->code = CONST_INT; loadOffset->param = dims[i]; // 取数组这一维的偏移量(还记得吧, 是偏移量哦) appendIns(insList, loadOffset); value = (struct AbstractValueNode*) (self->dimInfor->peekAt(self->dimInfor, i)); appendInsList(insList, value->createInstruction(value)); // 下标的指令 if (REAL == value->typeOf(value)) { // 如果是实型, 转型 cast = (struct NoParamInstruction*) allocate(sizeof(struct NoParamInstruction)); cast->code = REAL_2_INT; appendIns(insList, cast); } mult = (struct NoParamInstruction*) allocate(sizeof(struct NoParamInstruction)); mult->code = INT_MULTIPLY; // 将偏移量和下标相乘 appendIns(insList, mult); add = (struct NoParamInstruction*) allocate(sizeof(struct NoParamInstruction)); add->code = INT_PLUS; // 累加 appendIns(insList, add); } }
这样就完成了变量取址。还原一个完整的函数
struct List* addrOfVar(void* node) { struct VariableNode* self = (struct VariableNode*)node; struct List* insList = (struct List*)newArrayList(); int addr, nrDim = self->dimInfor->length(self->dimInfor); struct IntParamInstruction* loadBase = (struct IntParamInstruction*) allocate(sizeof(struct IntParamInstruction)); loadBase->code = CONST_INT; appendIns(insList, loadBase); if (0 == nrDim) { loadBase->param = staticOffset(self, NULL); } else { int* dims = (int*)allocate(nrDim * sizeof(int)); int i; struct IntParamInstruction* loadOffset; struct NoParamInstruction* cast,* mult,* add; struct AbstractValueNode* value; addr = staticOffset(self, dims); loadBase->param = addr; for (i = 0; i < nrDim; ++i) { if (-1 != dims[i]) { loadOffset = (struct IntParamInstruction*) allocate(sizeof(struct IntParamInstruction)); loadOffset->code = CONST_INT; loadOffset->param = dims[i]; appendIns(insList, loadOffset); value = (struct AbstractValueNode*) (self->dimInfor->peekAt(self->dimInfor, i)); appendInsList(insList, value->createInstruction(value)); if (REAL == value->typeOf(value)) { cast = (struct NoParamInstruction*) allocate(sizeof(struct NoParamInstruction)); cast->code = REAL_2_INT; appendIns(insList, cast); } mult = (struct NoParamInstruction*) allocate(sizeof(struct NoParamInstruction)); mult->code = INT_MULTIPLY; appendIns(insList, mult); add = (struct NoParamInstruction*) allocate(sizeof(struct NoParamInstruction)); add->code = INT_PLUS; appendIns(insList, add); } } revert(dims); } return insList; }