parameter_decl ::= type {'*'} id {',' type {'*'} id}
解析函数的参数就是解析以逗号分隔的一个个标识符,同时记录它们的位置与类型。
int index_of_bp; // index of bp pointer on stack
voidfunction_parameter() { int type; int params; params = 0; while (token != ')') { // ①
// int name, ... type = INT; if (token == Int) { match(Int); } elseif (token == Char) { type = CHAR; match(Char); }
// pointer type while (token == Mul) { match(Mul); type = type + PTR; }
// parameter name if (token != Id) { printf("%d: bad parameter declaration\n", line); exit(-1); } if (current_id[Class] == Loc) { printf("%d: duplicate parameter declaration\n", line); exit(-1); }
match(Id);
//② // store the local variable current_id[BClass] = current_id[Class]; current_id[Class] = Loc; current_id[BType] = current_id[Type]; current_id[Type] = type; current_id[BValue] = current_id[Value]; current_id[Value] = params++; // index of current parameter
if (token == ',') { match(','); } }
// ③ index_of_bp = params+1; }
其中①与全局变量定义的解析十分一样,用于解析该参数的类型。
而②则与上节中提到的“局部变量覆盖全局变量”相关,先将全局变量的信息保存(无论是是否真的在全局中用到了这个变量)在 BXXX 中,再赋上局部变量相关的信息,如 Value 中存放的是参数的位置(是第几个参数)。
③则与汇编代码的生成有关,index_of_bp 就是前文提到的 new_bp 的位置。
函数体的解析
我们实现的 C 语言与现代的 C 语言不太一致,我们需要所有的变量定义出现在所有的语句之前。函数体的代码如下:
voidfunction_body() { // type func_name (...) {...} // -->| |<--
int pos_local; // position of local variables on the stack. int type; pos_local = index_of_bp;
// ① while (token == Int || token == Char) { // local variable declaration, just like global ones. basetype = (token == Int) ? INT : CHAR; match(token);
while (token != ';') { type = basetype; while (token == Mul) { match(Mul); type = type + PTR; }
if (token != Id) { // invalid declaration printf("%d: bad local declaration\n", line); exit(-1); } if (current_id[Class] == Loc) { // identifier exists printf("%d: duplicate local declaration\n", line); exit(-1); } match(Id);
// store the local variable current_id[BClass] = current_id[Class]; current_id[Class] = Loc; current_id[BType] = current_id[Type]; current_id[Type] = type; current_id[BValue] = current_id[Value]; current_id[Value] = ++pos_local; // index of current parameter
if (token == ',') { match(','); } } match(';'); }
// ② // save the stack size for local variables *++text = ENT; *++text = pos_local - index_of_bp;
// statements while (token != '}') { statement(); }
// emit code for leaving the sub function *++text = LEV; }