计足够灵活的数据结构。C语言的变量声明包括两部分,一部分叫说明符(specifier),这部分对应各种数据类型关键字,int long, extern, struct等。另一部分叫修饰符,由变量名以及星号,中括号组成,例如 *a, a[10] 等。
说明符部分是有限的,毕竟关键字的数量有限,因此关键字的组合方式也有限,但是,修饰符部分就相当灵活,例如星号*就可以有多个,*和[]又可以相互组合,因此C语言的类型必须由两部分组成,一部分表示说明符部分,另一部分表示修饰符部分。整个类型系统就由包含这两种结构的链表构成。例如声明语句:
short in Quasimodo;
long *Gringoire;
他们的类型系统如下:
类型系统中,说明符部分只有一个,而修饰符部分可以有多个,当然也可以没有,同时,说明符始终放在链表的末尾。通过把链表顺序念下来,就可以读出变量声明语句,例如对于第二个队列,顺序读下来就是:Gringoire is a pointer to long.
如果是一个长整形数组,例如 long Coppenole[10],类型系统的表示如下:
一个指向10个长整形元素的数组指针,long (*Frollo)[10],类型系统表示如下:
这种类型系统有个显著特点是,容易促进代码生成。后面我们可以看到这个效果。
类型系统的实现
修饰符的实现比较简单,代码如下:
public class Declarator {
public static int POINTER = 0;
public static int ARRAY = 1;
public static int FUNCTION = 2;
private int declareType = POINTER;
private int numberOfElements = 0;
public Declarator(int type) {
if (type < POINTER) {
declareType = POINTER;
}
if (type > FUNCTION) {
declareType = FUNCTION;
}
}
public void setElementNum(int num) {
if (num < 0) {
numberOfElements = 0;
} else {
numberOfElements = num;
}
}
public int getType() {
return declareType ;
}
public int getElementNum() {
return numberOfElements;
}
}
上面代码中,declareType 用来表示要修饰的变量是一个指针,数组,还是函数,如果是数组的话,numberOfElements 这个成员用来表示数组含有多少个元素。
说明符的实现稍微麻烦些,代码如下:
public class Specifier {
//type
public static int INT = 0;
public static int CHAR = 1;
public static int VOID = 2;
public static int STRUCTURE = 3;
public static int LABEL = 4;
//storage
public static int FIXED = 0;
public static int REGISTER = 1;
public static int AUTO = 2;
public static int TYPEDEF = 3;
public static int CONSTANT = 4;
public static int NO_OCLASS = 0; //如果内存类型是auto, 那么存储类型就是NO_OCLASS
public static int PUBLIC = 1;
public static int PRIVATE = 2;
public static int EXTERN = 3;
public static int COMMON = 4;
private int basicType;
public void setType(int type) {
basicType = type;
}
public int getType() {
return basicType;
}
private int storageClass;
public void setStorageClass(int s) {
storageClass = s;
}
public int getStorageClass() {
return storageClass;
}
private int outputClass;
public void setOutputClass(int c) {
outputClass = c;
}
public int getOutputClass() {
return outputClass;
}
private boolean isLong = false;
public void setLong(boolean l) {
isLong = l;
}
public boolean getLong() {
return isLong;
}
private boolean isSigned = false;
public void setSign(boolean signed) {
isSigned = signed;
}
public boolean isSign() {
return isSigned;
}
private boolean isStatic = false;
public void setStatic(boolean s) {
isStatic = s;
}
public boolean isStatic() {
return isStatic;
}
private boolean isExternal = false;
public void setExternal(boolean e) {
isExternal = e;
}
public boolean isExternal() {
return isExternal;
}
private int constantValue = 0;
public void setConstantVal(int v) {
constantValue = v;
}
public int getConstantVal() {
return constantValue;
}
private StructDefine vStruct;
}
basicType用来表明变量属于什么类型,当前要做的编译器暂时只支持4种类型,int , char, void , struct, label. storageClass 表示变量的存储方式,FIXED表示变量只能存放在固定的内存地址,AUTO表示当前变量是局部变量,可以存放在堆栈上。如果当前变量是经过typedef修饰的,那么他的值也会设置成TYPEDEF, 例如:
typedef char single;
那么变量single对应的说明符中,storageClass的值等于TYPEDEF。
CONSTANT 用来标识常量类型,加入你声明了一个枚举类型:
enum days {
MON, TUE, WED, TUR, FRI, SAU, SUN
};
编译器会将MON,TUE等当做int类型的常值变量加入符号表:
constant int MON = 0;
于是MON, TUE, 等对应的Specifier类中,storageClass的值就是CONSTANT. 同时constantValue也会做相应的设置,例如MON对应的Specifier类,constantValue 等于0, TUE对应的specifier类的constantV