int basetype; // the type of a declaration, make it global for convenience int expr_type; // the type of an expression
void global_declaration() { // global_declaration ::= enum_decl | variable_decl | function_decl // // enum_decl ::= 'enum' [id] '{' id ['=' 'num'] {',' id ['=' 'num'} '}' // // variable_decl ::= type {'*'} id { ',' {'*'} id } ';' // // function_decl ::= type {'*'} id '(' parameter_decl ')' '{' body_decl '}'
int type; // tmp, actual type for variable int i; // tmp
basetype = INT;
// parse enum, this should be treated alone. if (token == Enum) { // enum [id] { a = 10, b = 20, ... } match(Enum); if (token != '{') { match(Id); // skip the [id] part } if (token == '{') { // parse the assign part match('{'); enum_declaration(); match('}'); }
match(';'); return; }
// parse type information if (token == Int) { match(Int); } else if (token == Char) { match(Char); basetype = CHAR; }
// parse the comma seperated variable declaration. while (token != ';' && token != '}') { type = basetype; // parse pointer type, note that there may exist `int ****x;` while (token == Mul) { match(Mul); type = type + PTR; }
if (token != Id) { // invalid declaration printf("%d: bad global declaration\n", line); exit(-1); } if (current_id[Class]) { // identifier exists printf("%d: duplicate global declaration\n", line); exit(-1); } match(Id); current_id[Type] = type;
if (token == '(') { current_id[Class] = Fun; current_id[Value] = (int)(text + 1); // the memory address of function function_declaration(); } else { // variable declaration current_id[Class] = Glo; // global variable current_id[Value] = (int)data; // assign memory address data = data + sizeof(int); }
if (token == ',') { match(','); } } next(); }
看了上面的代码,能大概理解吗?这里我们讲解其中的一些细节。
向前看标记 :其中的 if (token == xxx) 语句就是用来向前查看标记以确定使用哪一个产生式,例如只要遇到 enum 我们就知道是需要解析枚举类型。而如果只解析到类型,如 int identifier 时我们并不能确定 identifier 是一个普通的变量还是一个函数,所以还需要继续查看后续的标记,如果遇到 ( 则可以断定是函数了,反之则是变量。
变量类型的表示 :我们的编译器支持指针类型,那意味着也支持指针的指针,如
int **data;。那么我们如何表示指针类型呢?前文中我们定义了支持的类型:
// types of variable/function enum { CHAR, INT, PTR };
所以一个类型首先有基本类型,如 CHAR 或 INT,当它是一个指向基本类型的指针时,如 int *data,我们就将它的类型加上 PTR 即代码中的:type = type + PTR;。同理,如果是指针的指针,则再加上 PTR。