在上一节中,我们实现了函数的调用和返回,在这一节中,我们来处理真正的全局变量。当我们把变量定义的语句放入Block语句分析函数中,我们只能分析Block中的变量定义,即不能处理全局变量。所以我决定将全局变量声明移出函数声明。实际上,我也将变量声明的解析留在了函数内部,因为稍后我们会将它们更改为局部变量声明。此外,我们还会实现可以同时声明多个相同类型的变量,例如
int x, y, z;
完整的变量定义语法
编译单元 CompUnit → [ CompUnit ] ( Decl | FuncDef )
声明 Decl → ConstDecl | VarDecl
基本类型 BType → ‘int’
变量声明 VarDecl → BType VarDef { ‘,’ VarDef } ‘;’
变量定义 VarDef → Ident { ‘[’ ConstExp ‘]’ }
函数定义 FuncDef → FuncType Ident ‘(’ [FuncFParams] ‘)’ Block
语句块 Block → ‘{’ { BlockItem } ‘}’
语句块项 BlockItem → Decl | Stmt
修改词法分析
新增单词’,’,并将其定义为T_COMMA类型。在scan()函数中添加对’,'的解析语句
case ',': t->token = T_COMMA; break;
新增parse_type()
函数,来识别数据类型
// 解析当前单词并返回类型枚举值,同时扫描下一个单词
int parse_type()
{
int type;
switch (Token.token)
{
case T_VOID: type = P_VOID; break;
case T_KEYINT: type = P_INT; break;
default:
{
fprintf(stderr, "Illegal type, token:%d on line %d\n", Token.token, Line);
exit(1);
}
}
scan(&Token);
return type;
}
修改var_declaration()
,使其能解析’,'的情况
// 解析一个或多个全局变量或函数
void global_declarations()
{
struct ASTnode *tree;
int type;
while (1)
{
type = parse_type();
ident();
if (Token.token == T_LPAREN)
{
// 解析函数声明,并生成汇编代码
tree = function_declaration(type);
code_generator(tree, NOREG, 0);
}
else
{
// 解析全局变量声明
var_declaration(type);
}
// 遇到EOF结束
if (Token.token == T_EOF) break;
}
}
同时,在function_declaration
函数中,做出对应的修改
// 分析简单函数声明
struct ASTnode *function_declaration(int type)
{
struct ASTnode *tree, *finalstmt;
int nameslot, endlabel;
// 匹配'void'或'int'、函数名和'(' ')',
// 但不