已开启
曹家伟-24 第 3次 编 译 原 理 实 验 作 业语义分析 #36
H-HKAI创建于 2025年12月22日
曹家伟-24 第 3次 编 译 原 理 实 验 作 业语义分析 #36
已开启
H-HKAI创建于 2025年12月22日
4 个文件变更+1165-0
@@ -0,0 +1,5 @@
1+void main() {
2+var x: int;
3+int y;
4+return 0;
5+}
@@ -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+#include <stdio.h>
2+#include <stdlib.h>
3+#include <string.h>
4+#include <ctype.h>
5+#include <stdbool.h>
6+ 
7+#define MAX_TOKEN_LEN 100
8+#define MAX_LINE_LEN 200
9+#define MAX_SYMBOL_TABLE 1000
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+}