已开启
曹家伟-24 第 3次 编 译 原 理 实 验 作 业语义分析 #36
H-HKAI创建于 2025年12月22日
曹家伟-24 第 3次 编 译 原 理 实 验 作 业语义分析 #36
已开启
共 4 个文件变更+1165-0
| @@ -0,0 +1,24 @@ | |||
| 1 | +void main() { | ||
| 2 | + // 1. var声明缺少冒号 | ||
| 3 | + var x int; | ||
| 4 | + | ||
| 5 | + // 2. var声明缺少分号 | ||
| 6 | + var y: int | ||
| 7 | + | ||
| 8 | + // 3. var声明缺少标识符 | ||
| 9 | + var: int z; | ||
| 10 | + | ||
| 11 | + // 4. int声明缺少标识符 | ||
| 12 | + int ; | ||
| 13 | + | ||
| 14 | + // 5. int声明缺少分号 | ||
| 15 | + int w | ||
| 16 | + | ||
| 17 | + // 6. 混合错误:缺少类型和分号 | ||
| 18 | + var a: | ||
| 19 | + | ||
| 20 | + // 7. 无效的关键字 | ||
| 21 | + varr b: int; | ||
| 22 | + | ||
| 23 | + // 8. 缺少右大括号(故意不写) | ||
| 24 | +} | ||
| @@ -0,0 +1,17 @@ | |||
| 1 | +void main() { | ||
| 2 | + // 1. 变量重复声明(同作用域) | ||
| 3 | + var x: int; | ||
| 4 | + var x: int; // 重复声明 | ||
| 5 | + | ||
| 6 | + // 2. 不同类型重复声明 | ||
| 7 | + int y; | ||
| 8 | + var y: int; // 重复声明,不同类型 | ||
| 9 | + | ||
| 10 | + // 3. 多个重复声明 | ||
| 11 | + int z; | ||
| 12 | + var z: int; | ||
| 13 | + int z; // 第三次重复 | ||
| 14 | + | ||
| 15 | + // 4. 正确声明(用于对比) | ||
| 16 | + var unique: int; | ||
| 17 | +} | ||
| @@ -0,0 +1,1119 @@ | |||
| 1 | + | ||
| 2 | + | ||
| 3 | + | ||
| 4 | + | ||
| 5 | + | ||
| 6 | + | ||
| 7 | + | ||
| 8 | + | ||
| 9 | + | ||
| 10 | + | ||
| 11 | +/* 词法单元类型 */ | ||
| 12 | +typedef enum { | ||
| 13 | + TK_VOID, TK_INT, TK_MAIN, TK_RETURN, TK_VAR, TK_TYPE, | ||
| 14 | + TK_ID, TK_INTEGER, | ||
| 15 | + TK_PLUS, TK_MINUS, TK_MUL, TK_DIV, TK_ASSIGN, TK_EQ, TK_NE, TK_LT, TK_GT, TK_LE, TK_GE, | ||
| 16 | + TK_LPAREN, TK_RPAREN, TK_LBRACE, TK_RBRACE, TK_SEMICOLON, TK_COLON, TK_COMMA, | ||
| 17 | + TK_EOF, TK_ERROR | ||
| 18 | +} TokenType; | ||
| 19 | + | ||
| 20 | +/* 词法单元结构 */ | ||
| 21 | +typedef struct { | ||
| 22 | + TokenType type; | ||
| 23 | + char lexeme[MAX_TOKEN_LEN]; | ||
| 24 | + int value; | ||
| 25 | + int line; | ||
| 26 | +} Token; | ||
| 27 | + | ||
| 28 | +/* AST节点类型 */ | ||
| 29 | +typedef enum { | ||
| 30 | + NODE_PROGRAM, | ||
| 31 | + NODE_MAIN_DECL, | ||
| 32 | + NODE_FUNC_BODY, | ||
| 33 | + NODE_DECL_LIST, | ||
| 34 | + NODE_DECL_STAT, | ||
| 35 | + NODE_TYPE, | ||
| 36 | + NODE_ID, | ||
| 37 | + NODE_INT, | ||
| 38 | + NODE_VAR_DECL, | ||
| 39 | + NODE_EMPTY | ||
| 40 | +} NodeType; | ||
| 41 | + | ||
| 42 | +/* 语法树节点结构 */ | ||
| 43 | +typedef struct ASTNode { | ||
| 44 | + NodeType type; | ||
| 45 | + char name[50]; | ||
| 46 | + int line; | ||
| 47 | + int int_value; | ||
| 48 | + char str_value[100]; | ||
| 49 | + struct ASTNode *first_child; | ||
| 50 | + struct ASTNode *next_sibling; | ||
| 51 | +} ASTNode; | ||
| 52 | + | ||
| 53 | +/* 语义分析相关类型 */ | ||
| 54 | +typedef enum { | ||
| 55 | + TYPE_VOID, | ||
| 56 | + TYPE_INT, | ||
| 57 | + TYPE_ERROR | ||
| 58 | +} DataType; | ||
| 59 | + | ||
| 60 | +typedef enum { | ||
| 61 | + SCOPE_GLOBAL, | ||
| 62 | + SCOPE_LOCAL | ||
| 63 | +} ScopeType; | ||
| 64 | + | ||
| 65 | +typedef enum { | ||
| 66 | + ERROR_UNDECLARED_VAR, | ||
| 67 | + ERROR_REDECLARED_VAR, | ||
| 68 | + ERROR_TYPE_MISMATCH, | ||
| 69 | + ERROR_MAIN_NOT_FOUND, | ||
| 70 | + ERROR_MISSING_RETURN | ||
| 71 | +} ErrorType; | ||
| 72 | + | ||
| 73 | +/* 中间代码操作类型 */ | ||
| 74 | +typedef enum { | ||
| 75 | + IR_LABEL, | ||
| 76 | + IR_ASSIGN, | ||
| 77 | + IR_ADD, | ||
| 78 | + IR_SUB, | ||
| 79 | + IR_MUL, | ||
| 80 | + IR_DIV, | ||
| 81 | + IR_GOTO, | ||
| 82 | + IR_IF, | ||
| 83 | + IR_RETURN, | ||
| 84 | + IR_CALL, | ||
| 85 | + IR_PARAM, | ||
| 86 | + IR_FUNC_BEGIN, | ||
| 87 | + IR_FUNC_END | ||
| 88 | +} IROpType; | ||
| 89 | + | ||
| 90 | +/* 中间代码结构 */ | ||
| 91 | +typedef struct IRCode { | ||
| 92 | + IROpType op; | ||
| 93 | + char arg1[50]; | ||
| 94 | + char arg2[50]; | ||
| 95 | + char result[50]; | ||
| 96 | + int label_no; | ||
| 97 | + struct IRCode *next; | ||
| 98 | +} IRCode; | ||
| 99 | + | ||
| 100 | +/* 符号表结构 */ | ||
| 101 | +typedef struct { | ||
| 102 | + char name[50]; | ||
| 103 | + char type[20]; | ||
| 104 | + DataType data_type; | ||
| 105 | + ScopeType scope; | ||
| 106 | + int line; | ||
| 107 | + int address; | ||
| 108 | + int is_array; | ||
| 109 | + int array_size; | ||
| 110 | +} Symbol; | ||
| 111 | + | ||
| 112 | +/* 语义分析上下文 */ | ||
| 113 | +typedef struct { | ||
| 114 | + Symbol symbol_table[MAX_SYMBOL_TABLE]; | ||
| 115 | + int symbol_count; | ||
| 116 | + IRCode *ir_list; | ||
| 117 | + IRCode *ir_tail; | ||
| 118 | + int temp_var_count; | ||
| 119 | + int label_count; | ||
| 120 | + int current_scope; | ||
| 121 | + int in_main_function; | ||
| 122 | + int has_main_function; | ||
| 123 | + int has_return; | ||
| 124 | +} SemanticContext; | ||
| 125 | + | ||
| 126 | +/* 全局变量 */ | ||
| 127 | +Token current_token; | ||
| 128 | +Token lookahead; | ||
| 129 | +FILE *source_file; | ||
| 130 | +int current_line = 1; | ||
| 131 | +int has_error = 0; | ||
| 132 | +ASTNode *root = NULL; | ||
| 133 | +SemanticContext sem_ctx; | ||
| 134 | + | ||
| 135 | +/* 函数声明 */ | ||
| 136 | +void init_semantic_context(void); | ||
| 137 | +void init_scanner(const char *filename); | ||
| 138 | +void skip_whitespace(void); | ||
| 139 | +void get_next_token(void); | ||
| 140 | +void report_error(const char *message); | ||
| 141 | +void report_semantic_error(ErrorType error, int line, const char *info); | ||
| 142 | +void match(TokenType expected); | ||
| 143 | +void parse_program(void); | ||
| 144 | +void parse_main_declaration(void); | ||
| 145 | +void parse_function_body(void); | ||
| 146 | +void parse_declaration_list(void); | ||
| 147 | +void parse_declaration_stat(void); | ||
| 148 | +void parse_var_decl(void); | ||
| 149 | +int is_type_specifier(void); | ||
| 150 | +ASTNode *create_node(NodeType type, const char *name, int line); | ||
| 151 | +void add_child(ASTNode *parent, ASTNode *child); | ||
| 152 | +void print_ast(ASTNode *node, int depth); | ||
| 153 | +void free_ast(ASTNode *node); | ||
| 154 | +void semantic_check(ASTNode *node); | ||
| 155 | +void add_to_symbol_table(const char *name, const char *type, DataType data_type, | ||
| 156 | + ScopeType scope, int line, int is_array, int array_size); | ||
| 157 | +Symbol* lookup_symbol(const char *name); | ||
| 158 | +int check_symbol_exists(const char *name); | ||
| 159 | +DataType get_type_from_string(const char *type_str); | ||
| 160 | +const char* get_type_string(DataType type); | ||
| 161 | +void generate_intermediate_code(ASTNode *node); | ||
| 162 | +IRCode* create_ir_code(IROpType op, const char *arg1, const char *arg2, const char *result); | ||
| 163 | +void append_ir_code(IRCode *ir); | ||
| 164 | +char* new_temp_var(void); | ||
| 165 | +char* new_label(void); | ||
| 166 | +void generate_mips_code(void); | ||
| 167 | +void print_symbol_table(void); | ||
| 168 | +void print_ir_code(void); | ||
| 169 | +void free_ir_code(void); | ||
| 170 | +void sync_to_next_declaration(void); // 修改:更好的错误恢复函数 | ||
| 171 | + | ||
| 172 | +/* 初始化语义上下文 */ | ||
| 173 | +void init_semantic_context(void) { | ||
| 174 | + sem_ctx.symbol_count = 0; | ||
| 175 | + sem_ctx.ir_list = NULL; | ||
| 176 | + sem_ctx.ir_tail = NULL; | ||
| 177 | + sem_ctx.temp_var_count = 0; | ||
| 178 | + sem_ctx.label_count = 0; | ||
| 179 | + sem_ctx.current_scope = SCOPE_LOCAL; | ||
| 180 | + sem_ctx.in_main_function = 0; | ||
| 181 | + sem_ctx.has_main_function = 0; | ||
| 182 | + sem_ctx.has_return = 0; | ||
| 183 | +} | ||
| 184 | + | ||
| 185 | +/* 初始化扫描器 */ | ||
| 186 | +void init_scanner(const char *filename) { | ||
| 187 | + source_file = fopen(filename, "r"); | ||
| 188 | + if (source_file == NULL) { | ||
| 189 | + printf("无法打开文件: %s\n", filename); | ||
| 190 | + exit(1); | ||
| 191 | + } | ||
| 192 | + current_line = 1; | ||
| 193 | + get_next_token(); | ||
| 194 | +} | ||
| 195 | + | ||
| 196 | +/* 跳过空白字符和注释 */ | ||
| 197 | +void skip_whitespace(void) { | ||
| 198 | + int c; | ||
| 199 | + while ((c = fgetc(source_file)) != EOF) { | ||
| 200 | + if (c == '\n') { | ||
| 201 | + current_line++; | ||
| 202 | + } else if (c == ' ' || c == '\t' || c == '\r') { | ||
| 203 | + continue; | ||
| 204 | + } else if (c == '/') { | ||
| 205 | + int next = fgetc(source_file); | ||
| 206 | + if (next == '/') { | ||
| 207 | + while ((c = fgetc(source_file)) != EOF && c != '\n'); | ||
| 208 | + if (c == '\n') current_line++; | ||
| 209 | + } else if (next == '*') { | ||
| 210 | + while ((c = fgetc(source_file)) != EOF) { | ||
| 211 | + if (c == '\n') current_line++; | ||
| 212 | + if (c == '*') { | ||
| 213 | + next = fgetc(source_file); | ||
| 214 | + if (next == '/') break; | ||
| 215 | + ungetc(next, source_file); | ||
| 216 | + } | ||
| 217 | + } | ||
| 218 | + } else { | ||
| 219 | + ungetc(next, source_file); | ||
| 220 | + ungetc(c, source_file); | ||
| 221 | + break; | ||
| 222 | + } | ||
| 223 | + } else { | ||
| 224 | + ungetc(c, source_file); | ||
| 225 | + break; | ||
| 226 | + } | ||
| 227 | + } | ||
| 228 | +} | ||
| 229 | + | ||
| 230 | +/* 获取下一个词法单元 */ | ||
| 231 | +void get_next_token(void) { | ||
| 232 | + skip_whitespace(); | ||
| 233 | + | ||
| 234 | + int c = fgetc(source_file); | ||
| 235 | + if (c == EOF) { | ||
| 236 | + lookahead.type = TK_EOF; | ||
| 237 | + strcpy(lookahead.lexeme, "EOF"); | ||
| 238 | + lookahead.line = current_line; | ||
| 239 | + return; | ||
| 240 | + } | ||
| 241 | + | ||
| 242 | + lookahead.line = current_line; | ||
| 243 | + | ||
| 244 | + if (isalpha(c) || c == '_') { | ||
| 245 | + int i = 0; | ||
| 246 | + lookahead.lexeme[i++] = c; | ||
| 247 | + while (isalnum(c = fgetc(source_file)) || c == '_') { | ||
| 248 | + if (i < MAX_TOKEN_LEN - 1) { | ||
| 249 | + lookahead.lexeme[i++] = c; | ||
| 250 | + } | ||
| 251 | + } | ||
| 252 | + ungetc(c, source_file); | ||
| 253 | + lookahead.lexeme[i] = '\0'; | ||
| 254 | + | ||
| 255 | + if (strcmp(lookahead.lexeme, "void") == 0) { | ||
| 256 | + lookahead.type = TK_VOID; | ||
| 257 | + } else if (strcmp(lookahead.lexeme, "int") == 0) { | ||
| 258 | + lookahead.type = TK_INT; | ||
| 259 | + } else if (strcmp(lookahead.lexeme, "main") == 0) { | ||
| 260 | + lookahead.type = TK_MAIN; | ||
| 261 | + } else if (strcmp(lookahead.lexeme, "return") == 0) { | ||
| 262 | + lookahead.type = TK_RETURN; | ||
| 263 | + } else if (strcmp(lookahead.lexeme, "var") == 0) { | ||
| 264 | + lookahead.type = TK_VAR; | ||
| 265 | + } else { | ||
| 266 | + lookahead.type = TK_ID; | ||
| 267 | + } | ||
| 268 | + } | ||
| 269 | + else if (isdigit(c)) { | ||
| 270 | + int i = 0; | ||
| 271 | + lookahead.lexeme[i++] = c; | ||
| 272 | + int value = c - '0'; | ||
| 273 | + | ||
| 274 | + while (isdigit(c = fgetc(source_file))) { | ||
| 275 | + if (i < MAX_TOKEN_LEN - 1) { | ||
| 276 | + lookahead.lexeme[i++] = c; | ||
| 277 | + value = value * 10 + (c - '0'); | ||
| 278 | + } | ||
| 279 | + } | ||
| 280 | + ungetc(c, source_file); | ||
| 281 | + lookahead.lexeme[i] = '\0'; | ||
| 282 | + lookahead.type = TK_INTEGER; | ||
| 283 | + lookahead.value = value; | ||
| 284 | + } | ||
| 285 | + else { | ||
| 286 | + lookahead.lexeme[0] = c; | ||
| 287 | + lookahead.lexeme[1] = '\0'; | ||
| 288 | + | ||
| 289 | + switch (c) { | ||
| 290 | + case '+': lookahead.type = TK_PLUS; break; | ||
| 291 | + case '-': lookahead.type = TK_MINUS; break; | ||
| 292 | + case '*': lookahead.type = TK_MUL; break; | ||
| 293 | + case '/': lookahead.type = TK_DIV; break; | ||
| 294 | + case '=': | ||
| 295 | + c = fgetc(source_file); | ||
| 296 | + if (c == '=') { | ||
| 297 | + lookahead.type = TK_EQ; | ||
| 298 | + strcpy(lookahead.lexeme, "=="); | ||
| 299 | + } else { | ||
| 300 | + ungetc(c, source_file); | ||
| 301 | + lookahead.type = TK_ASSIGN; | ||
| 302 | + } | ||
| 303 | + break; | ||
| 304 | + case '<': | ||
| 305 | + c = fgetc(source_file); | ||
| 306 | + if (c == '=') { | ||
| 307 | + lookahead.type = TK_LE; | ||
| 308 | + strcpy(lookahead.lexeme, "<="); | ||
| 309 | + } else { | ||
| 310 | + ungetc(c, source_file); | ||
| 311 | + lookahead.type = TK_LT; | ||
| 312 | + } | ||
| 313 | + break; | ||
| 314 | + case '>': | ||
| 315 | + c = fgetc(source_file); | ||
| 316 | + if (c == '=') { | ||
| 317 | + lookahead.type = TK_GE; | ||
| 318 | + strcpy(lookahead.lexeme, ">="); | ||
| 319 | + } else { | ||
| 320 | + ungetc(c, source_file); | ||
| 321 | + lookahead.type = TK_GT; | ||
| 322 | + } | ||
| 323 | + break; | ||
| 324 | + case '!': | ||
| 325 | + c = fgetc(source_file); | ||
| 326 | + if (c == '=') { | ||
| 327 | + lookahead.type = TK_NE; | ||
| 328 | + strcpy(lookahead.lexeme, "!="); | ||
| 329 | + } else { | ||
| 330 | + ungetc(c, source_file); | ||
| 331 | + lookahead.type = TK_ERROR; | ||
| 332 | + } | ||
| 333 | + break; | ||
| 334 | + case '(': lookahead.type = TK_LPAREN; break; | ||
| 335 | + case ')': lookahead.type = TK_RPAREN; break; | ||
| 336 | + case '{': lookahead.type = TK_LBRACE; break; | ||
| 337 | + case '}': lookahead.type = TK_RBRACE; break; | ||
| 338 | + case ';': lookahead.type = TK_SEMICOLON; break; | ||
| 339 | + case ':': lookahead.type = TK_COLON; break; | ||
| 340 | + case ',': lookahead.type = TK_COMMA; break; | ||
| 341 | + default: lookahead.type = TK_ERROR; break; | ||
| 342 | + } | ||
| 343 | + } | ||
| 344 | +} | ||
| 345 | + | ||
| 346 | +/* 报告错误 */ | ||
| 347 | +void report_error(const char *message) { | ||
| 348 | + printf("第%d行:%s\n", current_token.line, message); | ||
| 349 | + has_error = 1; | ||
| 350 | +} | ||
| 351 | + | ||
| 352 | +/* 报告语义错误 */ | ||
| 353 | +void report_semantic_error(ErrorType error, int line, const char *info) { | ||
| 354 | + has_error = 1; | ||
| 355 | + | ||
| 356 | + switch (error) { | ||
| 357 | + case ERROR_UNDECLARED_VAR: | ||
| 358 | + printf("语义错误(第%d行):变量 '%s' 未声明\n", line, info); | ||
| 359 | + break; | ||
| 360 | + case ERROR_REDECLARED_VAR: | ||
| 361 | + printf("语义错误(第%d行):变量 '%s' 重复声明\n", line, info); | ||
| 362 | + break; | ||
| 363 | + case ERROR_TYPE_MISMATCH: | ||
| 364 | + printf("语义错误(第%d行):类型不匹配\n", line); | ||
| 365 | + break; | ||
| 366 | + case ERROR_MAIN_NOT_FOUND: | ||
| 367 | + printf("语义错误:未找到main函数\n"); | ||
| 368 | + break; | ||
| 369 | + case ERROR_MISSING_RETURN: | ||
| 370 | + printf("语义错误(第%d行):main函数缺少return语句\n", line); | ||
| 371 | + break; | ||
| 372 | + } | ||
| 373 | +} | ||
| 374 | + | ||
| 375 | +/* 匹配期望的词法单元 */ | ||
| 376 | +void match(TokenType expected) { | ||
| 377 | + current_token = lookahead; | ||
| 378 | + | ||
| 379 | + if (lookahead.type == expected) { | ||
| 380 | + get_next_token(); | ||
| 381 | + } else { | ||
| 382 | + char msg[100]; | ||
| 383 | + sprintf(msg, "期望的符号未找到,找到的是:%s", lookahead.lexeme); | ||
| 384 | + report_error(msg); | ||
| 385 | + // 错误恢复:如果当前token不是期望的,且不是分号或右大括号等,则跳过当前token | ||
| 386 | + if (lookahead.type != TK_SEMICOLON && lookahead.type != TK_RBRACE && lookahead.type != TK_EOF) { | ||
| 387 | + get_next_token(); | ||
| 388 | + } | ||
| 389 | + } | ||
| 390 | +} | ||
| 391 | + | ||
| 392 | +/* 同步到下一个声明或语句 */ | ||
| 393 | +void sync_to_next_declaration(void) { | ||
| 394 | + while (lookahead.type != TK_EOF && | ||
| 395 | + lookahead.type != TK_VAR && | ||
| 396 | + lookahead.type != TK_INT && | ||
| 397 | + lookahead.type != TK_RBRACE) { | ||
| 398 | + // 如果遇到分号,跳过它并停止 | ||
| 399 | + if (lookahead.type == TK_SEMICOLON) { | ||
| 400 | + get_next_token(); | ||
| 401 | + break; | ||
| 402 | + } | ||
| 403 | + get_next_token(); | ||
| 404 | + } | ||
| 405 | +} | ||
| 406 | + | ||
| 407 | +/* 创建AST节点 */ | ||
| 408 | +ASTNode *create_node(NodeType type, const char *name, int line) { | ||
| 409 | + ASTNode *node = (ASTNode *)malloc(sizeof(ASTNode)); | ||
| 410 | + node->type = type; | ||
| 411 | + strcpy(node->name, name); | ||
| 412 | + node->line = line; | ||
| 413 | + node->int_value = 0; | ||
| 414 | + node->str_value[0] = '\0'; | ||
| 415 | + node->first_child = NULL; | ||
| 416 | + node->next_sibling = NULL; | ||
| 417 | + return node; | ||
| 418 | +} | ||
| 419 | + | ||
| 420 | +/* 添加子节点 */ | ||
| 421 | +void add_child(ASTNode *parent, ASTNode *child) { | ||
| 422 | + if (parent->first_child == NULL) { | ||
| 423 | + parent->first_child = child; | ||
| 424 | + } else { | ||
| 425 | + ASTNode *sibling = parent->first_child; | ||
| 426 | + while (sibling->next_sibling != NULL) { | ||
| 427 | + sibling = sibling->next_sibling; | ||
| 428 | + } | ||
| 429 | + sibling->next_sibling = child; | ||
| 430 | + } | ||
| 431 | +} | ||
| 432 | + | ||
| 433 | +/* 判断是否为类型说明符 */ | ||
| 434 | +int is_type_specifier(void) { | ||
| 435 | + return lookahead.type == TK_INT || lookahead.type == TK_VOID; | ||
| 436 | +} | ||
| 437 | + | ||
| 438 | +/* 解析程序 */ | ||
| 439 | +void parse_program(void) { | ||
| 440 | + root = create_node(NODE_PROGRAM, "Program", 1); | ||
| 441 | + parse_main_declaration(); | ||
| 442 | + match(TK_EOF); | ||
| 443 | +} | ||
| 444 | + | ||
| 445 | +/* 解析主函数声明 */ | ||
| 446 | +void parse_main_declaration(void) { | ||
| 447 | + ASTNode *main_node = create_node(NODE_MAIN_DECL, "main_declaration", lookahead.line); | ||
| 448 | + add_child(root, main_node); | ||
| 449 | + | ||
| 450 | + if (lookahead.type == TK_VOID) { | ||
| 451 | + match(TK_VOID); | ||
| 452 | + } | ||
| 453 | + | ||
| 454 | + if (lookahead.type == TK_MAIN) { | ||
| 455 | + ASTNode *id_node = create_node(NODE_ID, "ID", current_token.line); | ||
| 456 | + strcpy(id_node->str_value, "main"); | ||
| 457 | + add_child(main_node, id_node); | ||
| 458 | + match(TK_MAIN); | ||
| 459 | + } else { | ||
| 460 | + report_error("缺少main"); | ||
| 461 | + return; | ||
| 462 | + } | ||
| 463 | + | ||
| 464 | + match(TK_LPAREN); | ||
| 465 | + match(TK_RPAREN); | ||
| 466 | + | ||
| 467 | + parse_function_body(); | ||
| 468 | +} | ||
| 469 | + | ||
| 470 | +/* 解析函数体 */ | ||
| 471 | +void parse_function_body(void) { | ||
| 472 | + ASTNode *body_node = create_node(NODE_FUNC_BODY, "function_body", lookahead.line); | ||
| 473 | + ASTNode *parent = root->first_child; | ||
| 474 | + add_child(parent, body_node); | ||
| 475 | + | ||
| 476 | + match(TK_LBRACE); | ||
| 477 | + parse_declaration_list(); | ||
| 478 | + match(TK_RBRACE); | ||
| 479 | +} | ||
| 480 | + | ||
| 481 | +/* 解析声明列表 */ | ||
| 482 | +void parse_declaration_list(void) { | ||
| 483 | + ASTNode *decl_list_node = create_node(NODE_DECL_LIST, "declaration_list", lookahead.line); | ||
| 484 | + ASTNode *parent = root->first_child->first_child->next_sibling; | ||
| 485 | + if (parent != NULL) { | ||
| 486 | + add_child(parent, decl_list_node); | ||
| 487 | + } | ||
| 488 | + | ||
| 489 | + // 一直解析直到遇到右大括号 | ||
| 490 | + while (lookahead.type != TK_RBRACE && lookahead.type != TK_EOF) { | ||
| 491 | + // 如果下一个token是var或int,解析声明语句 | ||
| 492 | + if (lookahead.type == TK_VAR || lookahead.type == TK_INT) { | ||
| 493 | + parse_declaration_stat(); | ||
| 494 | + } | ||
| 495 | + // 如果遇到分号,跳过它(可能是错误的残留分号) | ||
| 496 | + else if (lookahead.type == TK_SEMICOLON) { | ||
| 497 | + get_next_token(); | ||
| 498 | + } | ||
| 499 | + // 如果是其他token,尝试错误恢复 | ||
| 500 | + else { | ||
| 501 | + // 报告错误并跳过当前token | ||
| 502 | + char msg[100]; | ||
| 503 | + sprintf(msg, "意外的符号:%s", lookahead.lexeme); | ||
| 504 | + report_error(msg); | ||
| 505 | + get_next_token(); | ||
| 506 | + } | ||
| 507 | + } | ||
| 508 | + | ||
| 509 | + if (decl_list_node->first_child == NULL) { | ||
| 510 | + decl_list_node->type = NODE_EMPTY; | ||
| 511 | + } | ||
| 512 | +} | ||
| 513 | + | ||
| 514 | +/* 解析声明语句 */ | ||
| 515 | +void parse_declaration_stat(void) { | ||
| 516 | + ASTNode *decl_stat_node = create_node(NODE_DECL_STAT, "declaration_stat", lookahead.line); | ||
| 517 | + ASTNode *parent = root->first_child->first_child->next_sibling->first_child; | ||
| 518 | + if (parent != NULL) { | ||
| 519 | + add_child(parent, decl_stat_node); | ||
| 520 | + } | ||
| 521 | + | ||
| 522 | + if (lookahead.type == TK_VAR) { | ||
| 523 | + parse_var_decl(); | ||
| 524 | + // 如果parse_var_decl返回了,说明处理完成(可能有错误) | ||
| 525 | + // 这里不再重复匹配分号,因为parse_var_decl内部会处理 | ||
| 526 | + } else if (lookahead.type == TK_INT) { | ||
| 527 | + ASTNode *type_node = create_node(NODE_TYPE, "TYPE", lookahead.line); | ||
| 528 | + strcpy(type_node->str_value, "int"); | ||
| 529 | + add_child(decl_stat_node, type_node); | ||
| 530 | + match(TK_INT); | ||
| 531 | + | ||
| 532 | + if (lookahead.type == TK_ID) { | ||
| 533 | + ASTNode *id_node = create_node(NODE_ID, "ID", lookahead.line); | ||
| 534 | + strcpy(id_node->str_value, lookahead.lexeme); | ||
| 535 | + add_child(decl_stat_node, id_node); | ||
| 536 | + match(TK_ID); | ||
| 537 | + } else { | ||
| 538 | + report_error("缺少ID"); | ||
| 539 | + sync_to_next_declaration(); | ||
| 540 | + return; | ||
| 541 | + } | ||
| 542 | + | ||
| 543 | + // 匹配分号 | ||
| 544 | + if (lookahead.type == TK_SEMICOLON) { | ||
| 545 | + match(TK_SEMICOLON); | ||
| 546 | + } else { | ||
| 547 | + report_error("缺少分号"); | ||
| 548 | + sync_to_next_declaration(); | ||
| 549 | + } | ||
| 550 | + } | ||
| 551 | +} | ||
| 552 | + | ||
| 553 | +/* 解析变量声明 */ | ||
| 554 | +void parse_var_decl(void) { | ||
| 555 | + ASTNode *var_decl_node = create_node(NODE_VAR_DECL, "var_declaration", lookahead.line); | ||
| 556 | + ASTNode *parent = root->first_child->first_child->next_sibling->first_child->first_child; | ||
| 557 | + | ||
| 558 | + if (parent != NULL && parent->type == NODE_DECL_STAT) { | ||
| 559 | + add_child(parent, var_decl_node); | ||
| 560 | + } | ||
| 561 | + | ||
| 562 | + match(TK_VAR); | ||
| 563 | + | ||
| 564 | + // 检查 var 后面是不是直接跟着冒号(缺少标识符的情况) | ||
| 565 | + if (lookahead.type == TK_COLON) { | ||
| 566 | + report_error("变量声明缺少标识符"); | ||
| 567 | + // 跳转到下一个声明 | ||
| 568 | + sync_to_next_declaration(); | ||
| 569 | + return; | ||
| 570 | + } | ||
| 571 | + | ||
| 572 | + if (lookahead.type == TK_ID) { | ||
| 573 | + ASTNode *id_node = create_node(NODE_ID, "ID", lookahead.line); | ||
| 574 | + strcpy(id_node->str_value, lookahead.lexeme); | ||
| 575 | + add_child(var_decl_node, id_node); | ||
| 576 | + match(TK_ID); | ||
| 577 | + } else { | ||
| 578 | + report_error("缺少ID"); | ||
| 579 | + sync_to_next_declaration(); | ||
| 580 | + return; | ||
| 581 | + } | ||
| 582 | + | ||
| 583 | + if (lookahead.type == TK_COLON) { | ||
| 584 | + match(TK_COLON); | ||
| 585 | + } else { | ||
| 586 | + report_error("缺少冒号"); | ||
| 587 | + // 尝试继续解析,可能后面是类型 | ||
| 588 | + if (lookahead.type == TK_INT) { | ||
| 589 | + // 假设用户写了 var x int; 而不是 var x: int; | ||
| 590 | + ASTNode *type_node = create_node(NODE_TYPE, "TYPE", lookahead.line); | ||
| 591 | + strcpy(type_node->str_value, "int"); | ||
| 592 | + add_child(var_decl_node, type_node); | ||
| 593 | + match(TK_INT); | ||
| 594 | + // 匹配分号 | ||
| 595 | + if (lookahead.type == TK_SEMICOLON) { | ||
| 596 | + match(TK_SEMICOLON); | ||
| 597 | + } else { | ||
| 598 | + report_error("缺少分号"); | ||
| 599 | + sync_to_next_declaration(); | ||
| 600 | + } | ||
| 601 | + } else { | ||
| 602 | + sync_to_next_declaration(); | ||
| 603 | + } | ||
| 604 | + return; | ||
| 605 | + } | ||
| 606 | + | ||
| 607 | + if (lookahead.type == TK_INT) { | ||
| 608 | + ASTNode *type_node = create_node(NODE_TYPE, "TYPE", lookahead.line); | ||
| 609 | + strcpy(type_node->str_value, "int"); | ||
| 610 | + add_child(var_decl_node, type_node); | ||
| 611 | + match(TK_INT); | ||
| 612 | + } else { | ||
| 613 | + report_error("缺少类型说明符"); | ||
| 614 | + sync_to_next_declaration(); | ||
| 615 | + return; | ||
| 616 | + } | ||
| 617 | + | ||
| 618 | + // 匹配分号 | ||
| 619 | + if (lookahead.type == TK_SEMICOLON) { | ||
| 620 | + match(TK_SEMICOLON); | ||
| 621 | + } else { | ||
| 622 | + report_error("缺少分号"); | ||
| 623 | + sync_to_next_declaration(); | ||
| 624 | + } | ||
| 625 | +} | ||
| 626 | + | ||
| 627 | +/* 打印语法树 */ | ||
| 628 | +void print_ast(ASTNode *node, int depth) { | ||
| 629 | + int i; | ||
| 630 | + ASTNode *child; | ||
| 631 | + | ||
| 632 | + if (node == NULL || node->type == NODE_EMPTY) { | ||
| 633 | + return; | ||
| 634 | + } | ||
| 635 | + | ||
| 636 | + for (i = 0; i < depth; i++) { | ||
| 637 | + printf(" "); | ||
| 638 | + } | ||
| 639 | + | ||
| 640 | + switch (node->type) { | ||
| 641 | + case NODE_PROGRAM: | ||
| 642 | + case NODE_MAIN_DECL: | ||
| 643 | + case NODE_FUNC_BODY: | ||
| 644 | + case NODE_DECL_LIST: | ||
| 645 | + case NODE_DECL_STAT: | ||
| 646 | + case NODE_VAR_DECL: | ||
| 647 | + printf("%s (%d)\n", node->name, node->line); | ||
| 648 | + break; | ||
| 649 | + | ||
| 650 | + case NODE_TYPE: | ||
| 651 | + printf("%s: %s\n", node->name, node->str_value); | ||
| 652 | + break; | ||
| 653 | + | ||
| 654 | + case NODE_ID: | ||
| 655 | + printf("%s: %s\n", node->name, node->str_value); | ||
| 656 | + break; | ||
| 657 | + | ||
| 658 | + case NODE_INT: | ||
| 659 | + printf("%s: %d\n", node->name, node->int_value); | ||
| 660 | + break; | ||
| 661 | + | ||
| 662 | + default: | ||
| 663 | + break; | ||
| 664 | + } | ||
| 665 | + | ||
| 666 | + child = node->first_child; | ||
| 667 | + while (child != NULL) { | ||
| 668 | + print_ast(child, depth + 1); | ||
| 669 | + child = child->next_sibling; | ||
| 670 | + } | ||
| 671 | +} | ||
| 672 | + | ||
| 673 | +/* 释放语法树内存 */ | ||
| 674 | +void free_ast(ASTNode *node) { | ||
| 675 | + ASTNode *child; | ||
| 676 | + ASTNode *next; | ||
| 677 | + | ||
| 678 | + if (node == NULL) return; | ||
| 679 | + | ||
| 680 | + child = node->first_child; | ||
| 681 | + while (child != NULL) { | ||
| 682 | + next = child->next_sibling; | ||
| 683 | + free_ast(child); | ||
| 684 | + child = next; | ||
| 685 | + } | ||
| 686 | + | ||
| 687 | + free(node); | ||
| 688 | +} | ||
| 689 | + | ||
| 690 | +/* 添加符号到符号表 */ | ||
| 691 | +void add_to_symbol_table(const char *name, const char *type, DataType data_type, | ||
| 692 | + ScopeType scope, int line, int is_array, int array_size) { | ||
| 693 | + if (sem_ctx.symbol_count >= MAX_SYMBOL_TABLE) { | ||
| 694 | + printf("错误:符号表已满\n"); | ||
| 695 | + return; | ||
| 696 | + } | ||
| 697 | + | ||
| 698 | + if (check_symbol_exists(name)) { | ||
| 699 | + report_semantic_error(ERROR_REDECLARED_VAR, line, name); | ||
| 700 | + return; | ||
| 701 | + } | ||
| 702 | + | ||
| 703 | + { | ||
| 704 | + Symbol *sym = &sem_ctx.symbol_table[sem_ctx.symbol_count]; | ||
| 705 | + strcpy(sym->name, name); | ||
| 706 | + strcpy(sym->type, type); | ||
| 707 | + sym->data_type = data_type; | ||
| 708 | + sym->scope = scope; | ||
| 709 | + sym->line = line; | ||
| 710 | + sym->is_array = is_array; | ||
| 711 | + sym->array_size = array_size; | ||
| 712 | + | ||
| 713 | + if (scope == SCOPE_GLOBAL) { | ||
| 714 | + sym->address = sem_ctx.symbol_count * 4; | ||
| 715 | + } else { | ||
| 716 | + sym->address = -(sem_ctx.symbol_count + 1) * 4; | ||
| 717 | + } | ||
| 718 | + | ||
| 719 | + sem_ctx.symbol_count++; | ||
| 720 | + } | ||
| 721 | +} | ||
| 722 | + | ||
| 723 | +/* 查找符号 */ | ||
| 724 | +Symbol* lookup_symbol(const char *name) { | ||
| 725 | + int i; | ||
| 726 | + for (i = 0; i < sem_ctx.symbol_count; i++) { | ||
| 727 | + if (strcmp(sem_ctx.symbol_table[i].name, name) == 0) { | ||
| 728 | + return &sem_ctx.symbol_table[i]; | ||
| 729 | + } | ||
| 730 | + } | ||
| 731 | + return NULL; | ||
| 732 | +} | ||
| 733 | + | ||
| 734 | +/* 检查符号是否存在 */ | ||
| 735 | +int check_symbol_exists(const char *name) { | ||
| 736 | + return lookup_symbol(name) != NULL; | ||
| 737 | +} | ||
| 738 | + | ||
| 739 | +/* 从类型字符串获取数据类型 */ | ||
| 740 | +DataType get_type_from_string(const char *type_str) { | ||
| 741 | + if (strcmp(type_str, "int") == 0) { | ||
| 742 | + return TYPE_INT; | ||
| 743 | + } else if (strcmp(type_str, "void") == 0) { | ||
| 744 | + return TYPE_VOID; | ||
| 745 | + } | ||
| 746 | + return TYPE_ERROR; | ||
| 747 | +} | ||
| 748 | + | ||
| 749 | +/* 获取类型字符串 */ | ||
| 750 | +const char* get_type_string(DataType type) { | ||
| 751 | + switch (type) { | ||
| 752 | + case TYPE_INT: return "int"; | ||
| 753 | + case TYPE_VOID: return "void"; | ||
| 754 | + default: return "error"; | ||
| 755 | + } | ||
| 756 | +} | ||
| 757 | + | ||
| 758 | +/* 语义检查主函数 */ | ||
| 759 | +void semantic_check(ASTNode *node) { | ||
| 760 | + if (node == NULL) return; | ||
| 761 | + | ||
| 762 | + switch (node->type) { | ||
| 763 | + case NODE_PROGRAM: | ||
| 764 | + if (!sem_ctx.has_main_function) { | ||
| 765 | + report_semantic_error(ERROR_MAIN_NOT_FOUND, 0, NULL); | ||
| 766 | + } | ||
| 767 | + semantic_check(node->first_child); | ||
| 768 | + break; | ||
| 769 | + | ||
| 770 | + case NODE_MAIN_DECL: | ||
| 771 | + sem_ctx.in_main_function = 1; | ||
| 772 | + sem_ctx.has_main_function = 1; | ||
| 773 | + sem_ctx.current_scope = SCOPE_LOCAL; | ||
| 774 | + sem_ctx.has_return = 0; | ||
| 775 | + | ||
| 776 | + semantic_check(node->first_child); | ||
| 777 | + | ||
| 778 | + if (!sem_ctx.has_return) { | ||
| 779 | + report_semantic_error(ERROR_MISSING_RETURN, node->line, NULL); | ||
| 780 | + } | ||
| 781 | + | ||
| 782 | + sem_ctx.in_main_function = 0; | ||
| 783 | + break; | ||
| 784 | + | ||
| 785 | + case NODE_VAR_DECL: { | ||
| 786 | + ASTNode *id_node = node->first_child; | ||
| 787 | + ASTNode *type_node = id_node ? id_node->next_sibling : NULL; | ||
| 788 | + | ||
| 789 | + if (id_node && type_node) { | ||
| 790 | + DataType data_type = get_type_from_string(type_node->str_value); | ||
| 791 | + ScopeType scope = sem_ctx.in_main_function ? SCOPE_LOCAL : SCOPE_GLOBAL; | ||
| 792 | + | ||
| 793 | + add_to_symbol_table(id_node->str_value, type_node->str_value, | ||
| 794 | + data_type, scope, node->line, 0, 0); | ||
| 795 | + } | ||
| 796 | + break; | ||
| 797 | + } | ||
| 798 | + | ||
| 799 | + case NODE_DECL_STAT: { | ||
| 800 | + ASTNode *type_node = node->first_child; | ||
| 801 | + ASTNode *id_node = type_node ? type_node->next_sibling : NULL; | ||
| 802 | + | ||
| 803 | + if (id_node && type_node) { | ||
| 804 | + DataType data_type = get_type_from_string(type_node->str_value); | ||
| 805 | + ScopeType scope = sem_ctx.in_main_function ? SCOPE_LOCAL : SCOPE_GLOBAL; | ||
| 806 | + | ||
| 807 | + add_to_symbol_table(id_node->str_value, type_node->str_value, | ||
| 808 | + data_type, scope, node->line, 0, 0); | ||
| 809 | + } | ||
| 810 | + break; | ||
| 811 | + } | ||
| 812 | + | ||
| 813 | + case NODE_ID: { | ||
| 814 | + Symbol *sym = lookup_symbol(node->str_value); | ||
| 815 | + if (!sym) { | ||
| 816 | + report_semantic_error(ERROR_UNDECLARED_VAR, node->line, node->str_value); | ||
| 817 | + } | ||
| 818 | + break; | ||
| 819 | + } | ||
| 820 | + | ||
| 821 | + default: | ||
| 822 | + semantic_check(node->first_child); | ||
| 823 | + break; | ||
| 824 | + } | ||
| 825 | + | ||
| 826 | + semantic_check(node->next_sibling); | ||
| 827 | +} | ||
| 828 | + | ||
| 829 | +/* 创建中间代码节点 */ | ||
| 830 | +IRCode* create_ir_code(IROpType op, const char *arg1, const char *arg2, const char *result) { | ||
| 831 | + IRCode *ir = (IRCode *)malloc(sizeof(IRCode)); | ||
| 832 | + ir->op = op; | ||
| 833 | + | ||
| 834 | + if (arg1) strcpy(ir->arg1, arg1); | ||
| 835 | + else ir->arg1[0] = '\0'; | ||
| 836 | + | ||
| 837 | + if (arg2) strcpy(ir->arg2, arg2); | ||
| 838 | + else ir->arg2[0] = '\0'; | ||
| 839 | + | ||
| 840 | + if (result) strcpy(ir->result, result); | ||
| 841 | + else ir->result[0] = '\0'; | ||
| 842 | + | ||
| 843 | + ir->label_no = 0; | ||
| 844 | + ir->next = NULL; | ||
| 845 | + return ir; | ||
| 846 | +} | ||
| 847 | + | ||
| 848 | +/* 添加中间代码到列表 */ | ||
| 849 | +void append_ir_code(IRCode *ir) { | ||
| 850 | + if (sem_ctx.ir_list == NULL) { | ||
| 851 | + sem_ctx.ir_list = ir; | ||
| 852 | + sem_ctx.ir_tail = ir; | ||
| 853 | + } else { | ||
| 854 | + sem_ctx.ir_tail->next = ir; | ||
| 855 | + sem_ctx.ir_tail = ir; | ||
| 856 | + } | ||
| 857 | +} | ||
| 858 | + | ||
| 859 | +/* 生成新的临时变量名 */ | ||
| 860 | +char* new_temp_var(void) { | ||
| 861 | + static char temp_name[20]; | ||
| 862 | + sprintf(temp_name, "t%d", sem_ctx.temp_var_count++); | ||
| 863 | + return temp_name; | ||
| 864 | +} | ||
| 865 | + | ||
| 866 | +/* 生成新的标签 */ | ||
| 867 | +char* new_label(void) { | ||
| 868 | + static char label_name[20]; | ||
| 869 | + sprintf(label_name, "L%d", sem_ctx.label_count++); | ||
| 870 | + return label_name; | ||
| 871 | +} | ||
| 872 | + | ||
| 873 | +/* 生成中间代码 */ | ||
| 874 | +void generate_intermediate_code(ASTNode *node) { | ||
| 875 | + if (node == NULL) return; | ||
| 876 | + | ||
| 877 | + switch (node->type) { | ||
| 878 | + case NODE_PROGRAM: | ||
| 879 | + append_ir_code(create_ir_code(IR_FUNC_BEGIN, "main", NULL, NULL)); | ||
| 880 | + generate_intermediate_code(node->first_child); | ||
| 881 | + append_ir_code(create_ir_code(IR_FUNC_END, "main", NULL, NULL)); | ||
| 882 | + break; | ||
| 883 | + | ||
| 884 | + case NODE_MAIN_DECL: | ||
| 885 | + generate_intermediate_code(node->first_child); | ||
| 886 | + break; | ||
| 887 | + | ||
| 888 | + case NODE_VAR_DECL: { | ||
| 889 | + ASTNode *id_node = node->first_child; | ||
| 890 | + if (id_node) { | ||
| 891 | + char temp[50]; | ||
| 892 | + sprintf(temp, "%s = 0", id_node->str_value); | ||
| 893 | + append_ir_code(create_ir_code(IR_ASSIGN, "0", NULL, id_node->str_value)); | ||
| 894 | + } | ||
| 895 | + break; | ||
| 896 | + } | ||
| 897 | + | ||
| 898 | + case NODE_DECL_STAT: { | ||
| 899 | + ASTNode *id_node = node->first_child ? node->first_child->next_sibling : NULL; | ||
| 900 | + if (id_node) { | ||
| 901 | + append_ir_code(create_ir_code(IR_ASSIGN, "0", NULL, id_node->str_value)); | ||
| 902 | + } | ||
| 903 | + break; | ||
| 904 | + } | ||
| 905 | + | ||
| 906 | + default: | ||
| 907 | + generate_intermediate_code(node->first_child); | ||
| 908 | + break; | ||
| 909 | + } | ||
| 910 | + | ||
| 911 | + generate_intermediate_code(node->next_sibling); | ||
| 912 | +} | ||
| 913 | + | ||
| 914 | +/* 打印符号表 */ | ||
| 915 | +void print_symbol_table(void) { | ||
| 916 | + int i; | ||
| 917 | + const char *scope_str; | ||
| 918 | + Symbol *sym; | ||
| 919 | + | ||
| 920 | + printf("\n======= 符号表 =======\n"); | ||
| 921 | + printf("%-20s %-10s %-10s %-10s %s\n", | ||
| 922 | + "名称", "类型", "作用域", "地址", "行号"); | ||
| 923 | + printf("----------------------------------------------------------\n"); | ||
| 924 | + | ||
| 925 | + for (i = 0; i < sem_ctx.symbol_count; i++) { | ||
| 926 | + sym = &sem_ctx.symbol_table[i]; | ||
| 927 | + scope_str = (sym->scope == SCOPE_GLOBAL) ? "全局" : "局部"; | ||
| 928 | + printf("%-20s %-10s %-10s 0x%08X %-10d\n", | ||
| 929 | + sym->name, sym->type, scope_str, sym->address, sym->line); | ||
| 930 | + } | ||
| 931 | + printf("========================\n\n"); | ||
| 932 | +} | ||
| 933 | + | ||
| 934 | +/* 打印中间代码 */ | ||
| 935 | +void print_ir_code(void) { | ||
| 936 | + IRCode *current = sem_ctx.ir_list; | ||
| 937 | + int line_no = 1; | ||
| 938 | + | ||
| 939 | + printf("======= 中间代码 =======\n"); | ||
| 940 | + | ||
| 941 | + while (current != NULL) { | ||
| 942 | + printf("%3d: ", line_no++); | ||
| 943 | + | ||
| 944 | + switch (current->op) { | ||
| 945 | + case IR_LABEL: | ||
| 946 | + printf("%s:", current->arg1); | ||
| 947 | + break; | ||
| 948 | + case IR_ASSIGN: | ||
| 949 | + printf("%s = %s", current->result, current->arg1); | ||
| 950 | + break; | ||
| 951 | + case IR_ADD: | ||
| 952 | + printf("%s = %s + %s", current->result, current->arg1, current->arg2); | ||
| 953 | + break; | ||
| 954 | + case IR_SUB: | ||
| 955 | + printf("%s = %s - %s", current->result, current->arg1, current->arg2); | ||
| 956 | + break; | ||
| 957 | + case IR_MUL: | ||
| 958 | + printf("%s = %s * %s", current->result, current->arg1, current->arg2); | ||
| 959 | + break; | ||
| 960 | + case IR_DIV: | ||
| 961 | + printf("%s = %s / %s", current->result, current->arg1, current->arg2); | ||
| 962 | + break; | ||
| 963 | + case IR_GOTO: | ||
| 964 | + printf("goto %s", current->arg1); | ||
| 965 | + break; | ||
| 966 | + case IR_IF: | ||
| 967 | + printf("if %s %s goto %s", current->arg1, current->arg2, current->result); | ||
| 968 | + break; | ||
| 969 | + case IR_RETURN: | ||
| 970 | + printf("return %s", current->arg1); | ||
| 971 | + break; | ||
| 972 | + case IR_CALL: | ||
| 973 | + printf("call %s", current->arg1); | ||
| 974 | + break; | ||
| 975 | + case IR_PARAM: | ||
| 976 | + printf("param %s", current->arg1); | ||
| 977 | + break; | ||
| 978 | + case IR_FUNC_BEGIN: | ||
| 979 | + printf("func %s begin", current->arg1); | ||
| 980 | + break; | ||
| 981 | + case IR_FUNC_END: | ||
| 982 | + printf("func %s end", current->arg1); | ||
| 983 | + break; | ||
| 984 | + } | ||
| 985 | + printf("\n"); | ||
| 986 | + current = current->next; | ||
| 987 | + } | ||
| 988 | + printf("========================\n\n"); | ||
| 989 | +} | ||
| 990 | + | ||
| 991 | +/* 生成MIPS汇编代码 */ | ||
| 992 | +void generate_mips_code(void) { | ||
| 993 | + int i; | ||
| 994 | + Symbol *sym; | ||
| 995 | + IRCode *current; | ||
| 996 | + | ||
| 997 | + printf("======= MIPS汇编代码 =======\n"); | ||
| 998 | + printf(".data\n"); | ||
| 999 | + | ||
| 1000 | + /* 数据段:全局变量 */ | ||
| 1001 | + for (i = 0; i < sem_ctx.symbol_count; i++) { | ||
| 1002 | + sym = &sem_ctx.symbol_table[i]; | ||
| 1003 | + if (sym->scope == SCOPE_GLOBAL && strcmp(sym->name, "main") != 0) { | ||
| 1004 | + printf("%s: .word 0\n", sym->name); | ||
| 1005 | + } | ||
| 1006 | + } | ||
| 1007 | + | ||
| 1008 | + printf("\n.text\n"); | ||
| 1009 | + printf(".globl main\n"); | ||
| 1010 | + printf("main:\n"); | ||
| 1011 | + | ||
| 1012 | + /* 函数序言 */ | ||
| 1013 | + printf(" addiu $sp, $sp, -32 # 分配栈空间\n"); | ||
| 1014 | + printf(" sw $ra, 28($sp) # 保存返回地址\n"); | ||
| 1015 | + printf(" sw $fp, 24($sp) # 保存帧指针\n"); | ||
| 1016 | + printf(" move $fp, $sp # 设置新的帧指针\n\n"); | ||
| 1017 | + | ||
| 1018 | + /* 生成指令 */ | ||
| 1019 | + current = sem_ctx.ir_list; | ||
| 1020 | + while (current != NULL) { | ||
| 1021 | + switch (current->op) { | ||
| 1022 | + case IR_ASSIGN: | ||
| 1023 | + if (strcmp(current->arg1, "0") == 0) { | ||
| 1024 | + printf(" li $t0, 0 # %s = 0\n", current->result); | ||
| 1025 | + } else { | ||
| 1026 | + printf(" li $t0, %s # %s = %s\n", | ||
| 1027 | + current->arg1, current->result, current->arg1); | ||
| 1028 | + } | ||
| 1029 | + break; | ||
| 1030 | + | ||
| 1031 | + case IR_FUNC_END: | ||
| 1032 | + printf("\n # 函数返回\n"); | ||
| 1033 | + printf(" li $v0, 0 # 返回值0\n"); | ||
| 1034 | + printf(" lw $ra, 28($sp) # 恢复返回地址\n"); | ||
| 1035 | + printf(" lw $fp, 24($sp) # 恢复帧指针\n"); | ||
| 1036 | + printf(" addiu $sp, $sp, 32 # 恢复栈指针\n"); | ||
| 1037 | + printf(" jr $ra # 返回调用者\n"); | ||
| 1038 | + break; | ||
| 1039 | + | ||
| 1040 | + default: | ||
| 1041 | + break; | ||
| 1042 | + } | ||
| 1043 | + current = current->next; | ||
| 1044 | + } | ||
| 1045 | + | ||
| 1046 | + printf("\n# 程序结束\n"); | ||
| 1047 | + printf("============================\n"); | ||
| 1048 | +} | ||
| 1049 | + | ||
| 1050 | +/* 释放中间代码内存 */ | ||
| 1051 | +void free_ir_code(void) { | ||
| 1052 | + IRCode *current = sem_ctx.ir_list; | ||
| 1053 | + while (current != NULL) { | ||
| 1054 | + IRCode *next = current->next; | ||
| 1055 | + free(current); | ||
| 1056 | + current = next; | ||
| 1057 | + } | ||
| 1058 | + sem_ctx.ir_list = NULL; | ||
| 1059 | + sem_ctx.ir_tail = NULL; | ||
| 1060 | +} | ||
| 1061 | + | ||
| 1062 | +/* 主函数 */ | ||
| 1063 | +int main(int argc, char *argv[]) { | ||
| 1064 | + if (argc != 2) { | ||
| 1065 | + printf("使用方法: %s <源文件>\n", argv[0]); | ||
| 1066 | + return 1; | ||
| 1067 | + } | ||
| 1068 | + | ||
| 1069 | + /* 初始化语义上下文 */ | ||
| 1070 | + init_semantic_context(); | ||
| 1071 | + | ||
| 1072 | + /* 语法分析 */ | ||
| 1073 | + init_scanner(argv[1]); | ||
| 1074 | + parse_program(); | ||
| 1075 | + | ||
| 1076 | + if (!has_error) { | ||
| 1077 | + printf("? 语法分析成功!\n"); | ||
| 1078 | + | ||
| 1079 | + /* 打印语法树 */ | ||
| 1080 | + printf("\n======= 抽象语法树 =======\n"); | ||
| 1081 | + print_ast(root, 0); | ||
| 1082 | + | ||
| 1083 | + /* 语义检查 */ | ||
| 1084 | + printf("\n======= 语义分析 =======\n"); | ||
| 1085 | + semantic_check(root); | ||
| 1086 | + | ||
| 1087 | + if (!has_error) { | ||
| 1088 | + printf("? 语义分析成功!\n"); | ||
| 1089 | + | ||
| 1090 | + /* 打印符号表 */ | ||
| 1091 | + print_symbol_table(); | ||
| 1092 | + | ||
| 1093 | + /* 生成中间代码 */ | ||
| 1094 | + printf("\n======= 生成中间代码 =======\n"); | ||
| 1095 | + generate_intermediate_code(root); | ||
| 1096 | + print_ir_code(); | ||
| 1097 | + | ||
| 1098 | + /* 生成目标代码 */ | ||
| 1099 | + printf("\n======= 生成目标代码 =======\n"); | ||
| 1100 | + generate_mips_code(); | ||
| 1101 | + } else { | ||
| 1102 | + printf("? 语义分析发现错误!\n"); | ||
| 1103 | + } | ||
| 1104 | + } else { | ||
| 1105 | + printf("\n? 语法分析发现错误!\n"); | ||
| 1106 | + // 即使有语法错误,也尝试生成AST用于调试 | ||
| 1107 | + if (root != NULL) { | ||
| 1108 | + printf("\n======= 部分抽象语法树 =======\n"); | ||
| 1109 | + print_ast(root, 0); | ||
| 1110 | + } | ||
| 1111 | + } | ||
| 1112 | + | ||
| 1113 | + /* 清理 */ | ||
| 1114 | + fclose(source_file); | ||
| 1115 | + free_ast(root); | ||
| 1116 | + free_ir_code(); | ||
| 1117 | + | ||
| 1118 | + return has_error; | ||
| 1119 | +} | ||