上一次修改AbstractValueNode 时添加了一个typeOf 成员函数,这个函数用来在编译时确定AbstractValueNode 的类型。相对于确定编译时值,确定类型要简单一些。
对于IntegerNode 和RealNode ,它们的成员函数实现依然是很简单的
AcceptType typeOfInt(void* node) { return INTEGER; } AcceptType typeOfReal(void* node) { return REAL; }
而确定变量的类型,well,我们在符号表管理器中已经实现过这么一个函数
AcceptType typeOf(struct VariableNode* var);
现在摆在我们面前有两条路选,一是修改这个函数的参数类型,并在函数体内去转换这个参数类型,另一条路就是再加套一个这样的函数
AcceptType typeOfVar(void* node) { return typeOf((struct VariableNode*)node); }
哪一种就随意了。
接下来又是运算节点的类型确定了。对于UnaryOperationNode ,仅需要
AcceptType typeOfUnaryOp(void* node) { struct UnaryOperationNode* self = (struct UnaryOperationNode*)node; if (NOT == self->op && REAL == self->operand->typeOf(self->operand)) { // 报错:实型数不可以作为条件 } return self->operand->typeOf(self->operand); }
注意报错以后仍然若无其事地返回,这样也是提升容错性的一种方法。在BinaryOperationNode 的对应函数中也用到这个方法
AcceptType typeOfBinaryOp(void* node) { struct BinaryOperationNode* self = (struct BinaryOperationNode*)node; AcceptType leftType = self->leftOperand->typeOf(self->leftOperand), rightType = self->rightOperand->typeOf(self->rightOperand); if (ASSIGN == self->op) { return leftType; } if (isLogicOperator(self->op) && (REAL == leftType || REAL == rightType)) { // 报错:实型数不可以作为条件 } return leftType > rightType ? leftType : rightType; }
首先,如果这是一个赋值,那么赋值以后的类型由被赋值的变量决定,即取决于左值。最后一个?: 表达式看起来很奇怪,为什么要取两者中较大的一个呢?其实这是一个偷懒的做法,因为在定义时REAL 比INTEGER 大,所以这样做以后,如果两者中一个是INTEGER 一个是REAL ,那么会返回REAL 。不过这样做也有别的意思,比如要添加一个LONG 类型(比INTEGER范围更大的整型 ),那么将它插入到枚举的中INTEGER 与REAL 之间即可──这个取较大语句会解决这些事情。