首先回顾一下符号表提供的接口
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;
}
本文介绍了一种用于计算变量运行时地址的算法实现细节,重点在于处理数组变量的复杂情况,包括数组维数、偏移量计算及必要的类型转换。
1555

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



