Project 2: 语义分析

在Project 2中,你将继续构建BUPT编程语言(BPL)编译器的功能,专注于语义分析阶段。在前一个项目中完成词法和语法分析后,你已经能够生成语法有效的BPL程序的语法树。现在,语义分析阶段将确保程序有一个明确的定义,即验证程序的逻辑正确性,例如变量是否已声明、类型是否匹配等。

  1. 语义分析:

    • 作用:语义分析主要确保程序中的所有声明和表达式在逻辑上是有意义和合法的,包括类型检查、变量声明、函数调用等。
    • 实现方式:不同于前一个项目中的工具辅助(如Flex和Bison),在这一阶段,你需要手动编写代码来实现语义分析,这可能是实现BPL编译器中最费力的部分。你需要设计各种数据结构(如符号表和数据类型表示)并仔细考虑它们最合适的实现方式。
  2. 符号表:

    • 概述:符号表是映射名字到其关联信息的数据结构。在语义分析过程中,编译器将不断更新表中的信息以反映作用域内的内容。符号表的两个典型操作是插入和查找特定符号。
    • 实现:可以使用各种抽象数据类型来实现符号表,包括链表、二叉搜索树和哈希表。每种数据结构在空间/时间复杂性和实现难度方面有所不同。你可以选择适合你需求的数据结构。
  3. 作用域检查:

    • 概述:作用域检查是确定程序中的标识符是否在该位置可访问的过程。你可以使用不同的方法来实现支持作用域的符号表,比如命令式单一表方法或功能式独立表方法。
    • 实现:可以采用单一全局表,每个作用域内的符号在退出时移除;或者使用作用域栈,每个新的作用域开启一个新的符号表,并在作用域关闭时将其弹出。
  4. 类型检查:

    • 类型系统:在编程语言中,类型是一组值和在这些值上操作的集合。BPL有两类数据类型:基本类型(由硬件直接提供,如int、char和float)和派生类型(由基本类型或派生类型聚合而成,如数组、结构体等)。
    • 类型等价性:如何确定两个类型是否等价?对于基本类型,问题很简单,例如int只等价于int。对于派生类型,事情就复杂多了。通常有两种类型等价性:命名等价性和结构等价性。命名等价性考虑类型的名称,而结构等价性考虑类型的结构。
    • 派生类型表示:实现层面上,代表原始类型使用常量就足够了。对于派生类型,例如数组和结构体,表示它们就比较复杂了。常见的技术是存储定义类型的基本信息为多级链表。
  5. 项目要求:

    • 输入格式:与上一个项目相同,即执行文件bplc接受表示BPL程序路径的单个命令行参数。对于语义上合法的BPL程序,你的语义分析器不应该产生任何输出信息;否则,应该打印出有意义的错误信息。
    • 错误检测:你的分析器应该能够检测到一系列的语义错误,如未定义变量的使用、类型不匹配、函数调用参数不匹配等,并能够报告错误类型和行号。

通过这个项目,你将学习如何实现一个编译器的语义分析阶段,这是编译器理解程序并检测错误的关键环节。这个阶段需要对语言的类型系统、作用域规则和其他语义规则有深入的理解。

lex.l

c++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
%{
#include"syntax.tab.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define MAX_ID_SIZE 256

int line = 1;
typedef struct Head
{
int terminal;
char type[200];
char id[200];
char value_type[200]; //用于标记EXP的类型
int rvalue; //用于标记是否是右值
int lineno;
struct Head* child;
struct Head* next;
}Node;
struct Head* create_Node(int terminal,char* type, char* id, Node* child,Node* next,int lineno);

Node* create_Node(int terminal, char* type, char* id, Node* child, Node* next, int lineno)
{
Node* newNode = malloc(sizeof(Node));
if (newNode == NULL) {
perror("Memory allocation error");
exit(EXIT_FAILURE);
}

newNode->terminal = terminal;
newNode->lineno = (lineno == 0 && child != NULL) ? child->lineno : lineno;

if (type != NULL) {
strncpy(newNode->type, type, sizeof(newNode->type) - 1);
newNode->type[sizeof(newNode->type) - 1] = '\0';
} else {
newNode->type[0] = '\0';
}

if (id != NULL) {
strncpy(newNode->id, id, sizeof(newNode->id) - 1);
newNode->id[sizeof(newNode->id) - 1] = '\0';
} else {
newNode->id[0] = '\0';
}

newNode->child = child;
newNode->next = next;
newNode->rvalue = 0;

return newNode;
}

void print_tree(Node* root, int depth)
{
if (root == NULL) {
return;
}

// 对于非空节点,进行缩进处理
if (strcmp(root->type, "empty") != 0) {
for (int i = 0; i < depth; i++) {
printf(" ");
}
}

// 打印终端节点(叶子节点)的信息
if (root->terminal == 1) {
printf("%s", root->type);

// 对特定类型的节点,打印额外的信息
if (strcmp(root->type, "ID") == 0 || strcmp(root->type,"TYPE") == 0 ||
strcmp(root->type, "INT") == 0 || strcmp(root->type,"FLOAT") == 0 ||
strcmp(root->type, "CHAR") == 0) {
printf(": %s", root->id);
}
printf("\n");
} else if (strcmp(root->type, "empty") != 0) {
// 对于非终端且非空节点,打印节点类型和所在行号
printf("%s (%d)\n", root->type, root->lineno);
}

// 递归打印子节点,增加缩进深度
print_tree(root->child, depth + 1);

// 递归打印兄弟节点,保持当前缩进深度
print_tree(root->next, depth);
}
%}

%option noyywrap

int_ [0-9]+|0x[0-9a-fA-F]+
float_ [0-9]+"."[0-9]+
id_ [a-zA-Z_][a-zA-Z0-9_]*
char_ \'.\'|\'\\x[0-9a-fA-F]{2}\'

%%
"int" { yylval.node=create_Node(1,"TYPE",yytext,NULL,NULL,line);return TYPE; }
"float" { yylval.node=create_Node(1,"TYPE",yytext,NULL,NULL,line);return TYPE; }
"char" { yylval.node=create_Node(1,"TYPE",yytext,NULL,NULL,line);return TYPE; }
"struct" { yylval.node=create_Node(1,"STRUCT",yytext,NULL,NULL,line);return STRUCT; }
"if" { yylval.node=create_Node(1,"IF",yytext,NULL,NULL,line);return IF; }
"else" { yylval.node=create_Node(1,"ELSE",yytext,NULL,NULL,line);return ELSE; }
"while" { yylval.node=create_Node(1,"WHILE",yytext,NULL,NULL,line);return WHILE; }
"return" { yylval.node=create_Node(1,"RETURN",yytext,NULL,NULL,line);return RETURN; }
{int_} {yylval.node=create_Node(1,"INT",yytext,NULL,NULL,line);return INT;}
{float_} { yylval.node=create_Node(1,"FLOAT",yytext,NULL,NULL,line);return FLOAT; }
{id_} { yylval.node=create_Node(1,"ID",yytext,NULL,NULL,line);return ID; }
{char_} { yylval.node=create_Node(1,"CHAR",yytext,NULL,NULL,line);return CHAR; }

"." { yylval.node=create_Node(1,"DOT",yytext,NULL,NULL,line);return DOT; }
";" { yylval.node=create_Node(1,"SEMI",yytext,NULL,NULL,line);return SEMI; }
"," { yylval.node=create_Node(1,"COMMA",yytext,NULL,NULL,line);return COMMA; }
"=" { yylval.node=create_Node(1,"ASSIGN",yytext,NULL,NULL,line);return ASSIGN; }
"<" { yylval.node=create_Node(1,"LT",yytext,NULL,NULL,line);return LT; }
">" { yylval.node=create_Node(1,"GT",yytext,NULL,NULL,line);return GT; }
"<=" { yylval.node=create_Node(1,"LE",yytext,NULL,NULL,line);return LE; }
">=" { yylval.node=create_Node(1,"GE",yytext,NULL,NULL,line);return GE; }
"!=" { yylval.node=create_Node(1,"NE",yytext,NULL,NULL,line);return NE; }
"==" { yylval.node=create_Node(1,"EQ",yytext,NULL,NULL,line);return EQ; }
"+" { yylval.node=create_Node(1,"PLUS",yytext,NULL,NULL,line);return PLUS; }
"-" { yylval.node=create_Node(1,"MINUS",yytext,NULL,NULL,line);return MINUS; }
"*" { yylval.node=create_Node(1,"MUL",yytext,NULL,NULL,line);return MUL; }
"/" { yylval.node=create_Node(1,"DIV",yytext,NULL,NULL,line);return DIV; }
"&&" { yylval.node=create_Node(1,"AND",yytext,NULL,NULL,line);return AND; }
"||" { yylval.node=create_Node(1,"OR",yytext,NULL,NULL,line);return OR; }
"!" { yylval.node=create_Node(1,"NOT",yytext,NULL,NULL,line);return NOT; }
"(" { yylval.node=create_Node(1,"LP",yytext,NULL,NULL,line);return LP; }
")" { yylval.node=create_Node(1,"RP",yytext,NULL,NULL,line);return RP; }
"[" { yylval.node=create_Node(1,"LB",yytext,NULL,NULL,line);return LB; }
"]" { yylval.node=create_Node(1,"RB",yytext,NULL,NULL,line);return RB; }
"{" { yylval.node=create_Node(1,"LC",yytext,NULL,NULL,line);return LC; }
"}" { yylval.node=create_Node(1,"RC",yytext,NULL,NULL,line);return RC; }

"/*"([^*]|[*][^/]|[*][*]+[^*/])*"*/" {/* ignore comments */}
[ \t\r]+ {/* ignore whitespace */}
"\n" {line++;}

0x([0-9a-fA-F]|[g-zG-Z])+ { yylval.node=create_Node(1,"ILLEGAL_HEX_INT", yytext, NULL, NULL, line); return ILLEGAL_HEX_INT; }
[0-9]{id_} { yylval.node=create_Node(1,"ILLEGAL_ID", yytext, NULL, NULL, line); return ILLEGAL_ID; }
'\\x.*' { yylval.node=create_Node(1,"ILLEGAL_CHAR", yytext, NULL, NULL, line); return ILLEGAL_CHAR; }
. { yylval.node = create_Node(1,"ILLEGAL", yytext, NULL, NULL, line); return ILLEGAL; }
%%



syntax.y

c++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
%{
#include "lex.yy.c"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>

#include "myhead.h"

void yyerror();

Node* root=NULL;
int flag=0;



void connect_to_next(int next_num, ...)
{
if (next_num <= 0) {
// 如果没有节点或参数数量为负,不执行任何操作
return;
}

va_list valist;
va_start(valist, next_num);

Node* temp = va_arg(valist, Node*); // 获取第一个节点
Node* prev = temp;
for (int i = 1; i < next_num; i++)
{
temp = va_arg(valist, Node*); // 获取下一个节点
if (prev) {
prev->next = temp;
}
prev = temp; // 更新
}

if (temp) {
temp->next = NULL;
}

va_end(valist);
}

bool is_in_function=false;//标记当前是否在函数体内部,如果不是,则不允许定义变量
char *current_function_name;//标记当前所在的函数名
bool index_error=false; //标记数组下标是否出错
void find_compst_return(Node *Compst, char *expected_type);
void check_nested_statements(Node *stmt, char *expected_type);


/* 结构体操作 */
void insert_vardec(Node *node) {
if (!node->child->next) {
// 如果子节点没有next成员,则不是数组类型
add_dec(node->child->id, last_type, node->lineno);
} else {
// 如果子节点有next成员,则为数组类型
if (add_dec(node->child->child->id, "array", node->lineno)) {
add_array(node->child->child->id, last_type, node->lineno);
}
}
}

void insert_ExtDecList(Node* node) {
// 处理当前变量声明
insert_vardec(node->child);
if (node->child->next) {
// 如果存在多个变量声明(逗号分隔),递归处理余下的声明
insert_ExtDecList(node->child->next->next);
}
}

void add_struct_member_deflist(Node* node, char* struct_name)
{
//用于处理struct内部的成员声明
//node为DefList
//struct_name为结构体名
if(!node||!node->child)
{
return;
}
Node* temp=node->child;
//temp即Def
Node* temp2=temp->child;
//temp2即Specifier
//char* type=temp2->child->id;
char *type;
if (strcmp(temp2->child->type,"TYPE")==0)
{
//不是结构体
type=temp2->child->id;
}
else
{
//是结构体
type=temp2->child->child->next->id;
}
Node *temp3=temp->child->next;
//temp3即DecList
while(temp3)
{
Node* temp4=temp3->child;
//temp4即Dec
Node* temp5=temp4->child;
//temp5即VarDec
if(temp5->child->next==NULL)
{
//不是数组
add_struct_member(struct_name,temp5->child->id,type,temp5->lineno);
}
else
{
//是数组
add_struct_member(struct_name,temp5->child->child->id,"array",temp5->lineno);
add_array(temp5->child->child->id,type,temp5->lineno);
}
if(temp3->child->next)
{
//Dec COMMA DecList
temp3=temp3->child->next->next;
}
else
{
//Dec
break;
}
}
if(node->child)
{
//Def DefList
add_struct_member_deflist(node->child->next,struct_name);
}
else
{
//Def
return;
}
return;
}


/* 函数参数和变量插入 */
void insert_function_args(char *func_name, Node *node) {
if (node == NULL) {
// 如果节点为空,没有更多的变量需要处理,返回
return;
}

// 处理当前的ParamDec节点
Node *param = node->child;
Node *specifier = param->child;
Node *vardec = specifier->next;
char *type = specifier->child->id; // 获取类型
char *name = vardec->child->id; // 获取变量名
// 为简单起见,此处假设参数是非数组类型
add_func_args(func_name, name, type, param->lineno);

// 如果存在COMMA,说明后面还有参数,递归处理后续的VarList
Node *nextParam = node->child->next;
if (nextParam != NULL && strcmp(nextParam->type, "COMMA") == 0) {
insert_function_args(func_name, nextParam->next);
}
}

void insert_func_variables(Node *Dec) {
// 如果不在函数内部或输入节点为空,则不需要处理
if (!is_in_function || Dec == NULL) {
return;
}

// 在函数体内部
Node *VarDec = Dec->child;
char *var_name;
char *var_type;

// 判断是否为数组类型
if (VarDec->child->next) {
// 处理数组类型的变量
var_name = VarDec->child->child->id;
var_type = "array";
add_func_variables(current_function_name, var_name, var_type, VarDec->lineno);
add_array(var_name, last_type, VarDec->lineno);
} else {
// 处理普通变量
var_name = VarDec->child->id;
var_type = last_type;
add_func_variables(current_function_name, var_name, var_type, VarDec->lineno);
}

// 检查赋值语句并验证类型匹配
Node *Assign = VarDec->next;
if (Assign && strcmp(Assign->type, "ASSIGN") == 0) {
Node *Exp = Assign->next;
if (strcmp(Exp->value_type, "error") != 0 && strcmp(Exp->value_type, last_type) != 0) {
printf("Error type 5 at line %d: Type mismatched for assignment\n", Exp->lineno);
}
}
}


/* 表达式检查 */
void check_type(Node *exp, const char *expected_type, int error_type, int lineno) {
if (strcmp(exp->value_type, "error") == 0) {
// 类型已经是错误,之前的步骤中已经报错,此处不再重复。
return;
}
if (expected_type != NULL && strcmp(exp->value_type, expected_type) != 0) {
printf("Error type %d at line %d: Type mismatched for operands\n", error_type, lineno);
}
}

void check_single_arithmetic_exp(Node *exp) {
// 检查单个Exp的类型是否为int或者float
check_type(exp, NULL, 7, exp->lineno);
if (strcmp(exp->value_type, "int") != 0 && strcmp(exp->value_type, "float") != 0) {
printf("Error type 7 at line %d: Type mismatched for operands, expected int or float\n", exp->lineno);
}
}

void check_single_logical_exp(Node *exp) {
// 检查单个Exp的类型是否为int
check_type(exp, "int", 7, exp->lineno);
}

void check_exp_arithmetic_symbols(Node *exp1, Node *exp2) {
// 假设算术运算只能由int或float类型的变量进行
check_type(exp1, NULL, 7, exp1->lineno);
check_type(exp2, NULL, 7, exp2->lineno);
if ((strcmp(exp1->value_type, "int") != 0 && strcmp(exp1->value_type, "float") != 0) ||
(strcmp(exp2->value_type, "int") != 0 && strcmp(exp2->value_type, "float") != 0)) {
printf("Error type 7 at line %d: Type mismatched for operands, expected int or float\n", exp1->lineno);
}
if (strcmp(exp1->value_type, exp2->value_type) != 0) {
printf("Error type 7 at line %d: Type mismatched for operands, expected same type\n", exp1->lineno);
}
}

void check_exp_logical_symbols(Node *exp1, Node *exp2) {
// 假设逻辑运算只能由int类型的变量进行
check_type(exp1, "int", 7, exp1->lineno);
check_type(exp2, "int", 7, exp2->lineno);
}

void check_exp_assign(Node *exp1, Node *exp2) {
// 用于检查赋值语句左右两边的类型是否匹配
check_type(exp1, NULL, 6, exp1->lineno);
check_type(exp2, NULL, 5, exp2->lineno);
if (exp1->rvalue) {
printf("Error type 6 at line %d: rvalue on the left side of assignment operator\n", exp1->lineno);
return;
}
if (strcmp(exp1->value_type, exp2->value_type) != 0) {
printf("Error type 5 at line %d: Type mismatched for assignment\n", exp1->lineno);
}
}

void check_Exp_with_specific_type(Node *Exp, char *expected_type) {
// 用于检查Exp的类型是否为expected_type
check_type(Exp, expected_type, 7, Exp->lineno);
}

void check_Def(Node *Def) {
// expected_type 为定义的类型
char *expected_type = last_type;
Node *DecList = Def->child->next;

// 循环处理定义列表中的所有声明
while (DecList) {
Node *Dec = DecList->child;
Node *VarDec = Dec->child;

// 如果存在赋值(ASSIGN),检查表达式(Exp)的类型是否匹配
Node *Assign = VarDec->next;
if (Assign && strcmp(Assign->type, "ASSIGN") == 0) {
Node *Exp = Assign->next;
if (strcmp(Exp->value_type, "error") != 0 && strcmp(Exp->value_type, expected_type) != 0) {
printf("Error type 5 at line %d: Type mismatched for assignment\n", Exp->lineno);
}
}

// 移动到下一个声明,如果存在
DecList = (Dec->next && strcmp(Dec->next->type, "COMMA") == 0) ? Dec->next->next : NULL;
}
}

//设置节点的值为右值
void set_rvalue(Node *node) {
if (node) {
node->rvalue = 1;
}
}

//设置节点的类型
void set_EXP_value_type(Node *node, char *type) {
if (node && type) {
strcpy(node->value_type, type);
}
}


/* 函数参数和返回类型检查 */
void check_func_return_type(Node* Compst, char *expected_type) {
if (!is_in_function || Compst == NULL) {
// 如果不在函数内部或者Compst为空,则不需要处理
return;
}
// 递归检查函数体中的返回语句
find_compst_return(Compst, expected_type);
}

void find_compst_return(Node *Compst, char *expected_type) {
Node *stmtlist = Compst->child->next->next;
while (stmtlist && stmtlist->child) {
Node *stmt = stmtlist->child;
if (strcmp(stmt->child->type, "RETURN") == 0) {
Node *exp = stmt->child->next;
if (exp && strcmp(exp->value_type, expected_type) != 0 && strcmp(exp->value_type, "error") != 0) {
printf("Error type 8 at line %d: The return type mismatched\n", exp->lineno);
}
} else if (strcmp(stmt->child->type, "CompSt") == 0) {
find_compst_return(stmt->child, expected_type);
} else {
// 处理可能嵌套的结构,如if-else和while语句
check_nested_statements(stmt, expected_type);
}
stmtlist = stmtlist->next ? stmtlist->next->child : NULL;
}
}

void check_nested_statements(Node *stmt, char *expected_type) {
Node *head = stmt->child;
while (head) {
if (strcmp(head->type, "Stmt") == 0) {
if (strcmp(head->child->type, "CompSt") == 0) {
find_compst_return(head->child, expected_type);
} else if (strcmp(head->child->type, "RETURN") == 0) {
Node *exp = head->child->next;
if (exp && strcmp(exp->value_type, expected_type) != 0 && strcmp(exp->value_type, "error") != 0) {
printf("Error type 8 at line %d: The return type mismatched\n", exp->lineno);
}
}
}
head = head->next;
}
}

void check_func_args(char *func_name, Node *Args, int arg_index) {
// 查找函数定义
int func_index;
for(func_index = 0; func_index < def_num; func_index++) {
if(strcmp(def[func_index].name, func_name) == 0) {
break;
}
}
// 如果没有找到函数,直接返回
if(func_index == def_num) return;

Node *current_arg = Args->child;
// 检查参数个数和类型是否匹配
if(arg_index < def[func_index].arg_num) {
if(strcmp(current_arg->value_type, def[func_index].args[arg_index].type) != 0) {
printf("Error type 9 at line %d: Unmatched argument type for Function \"%s\"\n", current_arg->lineno, func_name);
return;
}
} else {
printf("Error type 9 at line %d: Too many arguments for Function \"%s\"\n", current_arg->lineno, func_name);
return;
}
// 递归检查下一个参数,如果存在
if(current_arg->next) {
check_func_args(func_name, current_arg->next->next, arg_index + 1);
} else if(arg_index + 1 < def[func_index].arg_num) {
printf("Error type 9 at line %d: Too few arguments for Function \"%s\"\n", current_arg->lineno, func_name);
}
}

void check_func_without_args(char *func_name, int lineno) {
// 查找函数定义
int func_index;
for(func_index = 0; func_index < def_num; func_index++) {
if(strcmp(def[func_index].name, func_name) == 0) {
break;
}
}
// 如果没有找到函数,直接返回
if(func_index == def_num) return;

if(def[func_index].arg_num != 0) {
printf("Error type 9 at line %d: Function \"%s\" expects no arguments\n", lineno, func_name);
}
}


/* 数组操作检查 */
bool check_exp_array(Node *array_exp, Node *index_exp) {
// 如果下标或数组表达式的类型已经是错误,不再进行检查
if (strcmp(index_exp->value_type, "error") == 0 || strcmp(array_exp->value_type, "error") == 0) {
return false;
}
// 检查是否应用了下标操作符到非数组类型的变量上
if (strcmp(array_exp->value_type, "array") != 0) {
printf("Error type 10 at line %d: Indexing operator ([...]) applied to non-array variable \"%s\".\n", array_exp->lineno, array_exp->id);
return false;
}
// 检查下标是否为整型
if (strcmp(index_exp->value_type, "int") != 0) {
printf("Error type 12 at line %d: Array index is not an integer.\n", index_exp->lineno);
index_error = true; // 确保外部标记了存在下标错误
return true;
}
return true;
}

char* find_array_elem_type(Node *exp) {
// 找到数组的ID节点
Node *id = NULL;
bool found = false;
while (exp->child && !found) {
exp = exp->child;
Node *temp = exp;
while (temp) {
if (strcmp(temp->type, "ID") == 0) {
id = temp;
found = true;
break;
}
temp = temp->next;
}
}
// 在定义中查找匹配的数组并返回其元素类型
for (int i = 0; i < def_num; i++) {
if (strcmp(def[i].name, id->id) == 0) {
return def[i].elem_type;
}
}
return NULL; // 如果没有找到匹配的定义,返回NULL
}

/* 结构体成员检查 */
bool check_exp_structure(Node *structure_exp, Node *member_id) {
// 如果表达式类型有错误,则不再检查
if (strcmp(structure_exp->value_type, "error") == 0 || strcmp(member_id->value_type, "error") == 0) {
return false;
}

// 检查是否为结构体
bool is_structure_found = false;
for (int i = 0; i < dec_num && !is_structure_found; i++) {
if (strcmp(dec[i].name, structure_exp->value_type) == 0) {
if (strcmp(dec[i].type, "structure") != 0) {
printf("Error type 13 at line %d: Illegal member access on non-structure variable \"%s\"\n",
structure_exp->lineno, structure_exp->id);
return false;
}
is_structure_found = true;
}
}

// 如果没有找到对应的结构体定义,则报错
if (!is_structure_found) {
printf("Error type 13 at line %d: Illegal member access on non-structure variable \"%s\"\n",
structure_exp->lineno, structure_exp->id);
return false;
}

// 检查结构体内是否有该成员
char *type = find_structure_member_type(structure_exp->value_type, member_id->id);
if (!type) {
printf("Error type 14 at line %d: Structure '%s' has no member named '%s'\n",
structure_exp->lineno, structure_exp->value_type, member_id->id);
return false;
}

return true;
}


/* 函数调用检查 */
bool check_if_func_exist(char *name, int lineno) {
// 首先检查全局声明是否包含该名称
for (int i = 0; i < dec_num; ++i) {
if (strcmp(dec[i].name, name) == 0) {
// 名称匹配,检查是否为函数类型
if (strcmp(dec[i].type, "function") != 0) {
printf("Error type 11 at Line %d: '%s' is not a function name.\n", lineno, name);
return false;
}
return true;
}
}

// 接下来检查当前函数内部是否有同名的参数或局部声明
for (int i = 0; i < def_num; ++i) {
if (strcmp(def[i].name, current_function_name) == 0) {
// 检查参数
for (int j = 0; j < def[i].arg_num; ++j) {
if (strcmp(def[i].args[j].name, name) == 0) {
printf("Error type 11 at Line %d: '%s' is a parameter, not a function.\n", lineno, name);
return false;
}
}
// 检查局部声明
for (int j = 0; j < def[i].dec_num; ++j) {
if (strcmp(def[i].dec[j].name, name) == 0) {
if (strcmp(def[i].dec[j].type, "function") != 0) {
printf("Error type 11 at Line %d: '%s' is not a function name.\n", lineno, name);
return false;
}
return true;
}
}
}
}

// 如果前面的检查都没有返回,意味着函数未定义
printf("Error type 2 at Line %d: Function \"%s\" is invoked without definition.\n", lineno, name);
return false;
}


/* 变量检查 */
char* check_exp_id(Node *id) {
char *type = "error"; // 默认类型为 "error"

// 首先在全局声明中检索
for (int i = 0; i < dec_num; ++i) {
if (strcmp(dec[i].name, id->id) == 0) {
return dec[i].type; // 找到匹配,返回对应类型
}
}

// 再检查是否为某个结构体定义的成员
for (int i = 0; i < def_num; ++i) {
for (int j = 0; j < def[i].dec_num; ++j) {
if (strcmp(def[i].dec[j].name, id->id) == 0) {
return def[i].dec[j].type; // 找到匹配,返回对应类型
}
}
}

// 最后检查是否为当前函数的参数或局部变量
for (int i = 0; i < def_num; ++i) {
if (strcmp(def[i].name, current_function_name) == 0) {
// 检查参数
for (int j = 0; j < def[i].arg_num; ++j) {
if (strcmp(def[i].args[j].name, id->id) == 0) {
return def[i].args[j].type; // 找到匹配,返回对应类型
}
}
// 检查局部变量
for (int j = 0; j < def[i].dec_num; ++j) {
if (strcmp(def[i].dec[j].name, id->id) == 0) {
return def[i].dec[j].type; // 找到匹配,返回对应类型
}
}
}
}

// 如果标识符未定义并且处于函数内部,则打印错误信息
if (strcmp(type, "error") == 0 && is_in_function) {
printf("Error type 1 at line %d: Undefined variable \"%s\".\n", id->lineno, id->id);
}
return type; // 如果没有找到匹配的声明,返回 "error"
}
%}



%union
{
int num;
char* str;
struct Head* node; /*"struct" is indispensable*/
}



%right ASSIGN
%left OR
%left AND
%left LT LE GT GE NE EQ
%left PLUS MINUS
%left MUL DIV
%right NOT NEGATIVE
%nonassoc LC RC LB RB LP RP DOT

%token <node> ID INT FLOAT CHAR STRUCT RETURN IF ELSE WHILE PLUS MINUS MUL DIV AND OR LT LE GT GE NE EQ NOT ASSIGN TYPE LP RP LB RB LC RC SEMI COMMA DOT ILLEGAL ILLEGAL_ID ILLEGAL_HEX_INT ILLEGAL_CHAR

%type <node> Program ExtDefList ExtDef ExtDecList Specifier StructSpecifier VarDec FunDec VarList ParamDec CompSt StmtList Stmt DefList Def DecList Dec Exp Args
%%

Program: ExtDefList {$$=create_Node(0,"Program","",$1,NULL,0);root=$$;}

ExtDefList: ExtDef ExtDefList {connect_to_next(2,$1,$2);$$=create_Node(0,"ExtDefList","",$1,NULL,0);}
| /* empty */ {$$=create_Node(0,"empty","",NULL,NULL,100);}

ExtDef: Specifier ExtDecList SEMI {connect_to_next(3,$1,$2,$3);$$=create_Node(0,"ExtDef","",$1,NULL,0);insert_ExtDecList($2);}
| Specifier ExtDecList error {printf("Error type B at line %d: missing semicolon ';'\n", $1->lineno);}
| Specifier SEMI {connect_to_next(2,$1,$2);$$=create_Node(0,"ExtDef","",$1,NULL,0);}
| Specifier FunDec CompSt {connect_to_next(3,$1,$2,$3);$$=create_Node(0,"ExtDef","",$1,NULL,0);if(is_in_function){set_func_return_type(current_function_name,$1->child->id);check_func_return_type($3,$1->child->id);}is_in_function=false;}

ExtDecList: VarDec {$$=create_Node(0,"ExtDecList","",$1,NULL,0);}
| VarDec COMMA ExtDecList {connect_to_next(3,$1,$2,$3);$$=create_Node(0,"ExtDecList","",$1,NULL,0);}

Specifier: TYPE {$$=create_Node(0,"Specifier","",$1,NULL,0);set_last_type($1->id);}
| StructSpecifier {$$=create_Node(0,"Specifier","",$1,NULL,0);}

StructSpecifier: STRUCT ID LC DefList RC {connect_to_next(5,$1,$2,$3,$4,$5);$$=create_Node(0,"StructSpecifier","",$1,NULL,0);if(add_dec($2->id,"structure",$2->lineno)&&add_func_or_struct($2->id,$2->lineno,"structure")){add_struct_member_deflist($4,$2->id);}}
| STRUCT ID {connect_to_next(2,$1,$2);$$=create_Node(0,"StructSpecifier","",$1,NULL,0);set_last_type($2->id);}

VarDec: ID {$$=create_Node(0,"VarDec","",$1,NULL,0);}
| ILLEGAL_ID error {printf("Error type A at line %d: illegal identifier '%s'\n", $1->lineno,$1->id);}
| VarDec LB INT RB {connect_to_next(4,$1,$2,$3,$4);$$=create_Node(0,"VarDec","",$1,NULL,0);}

FunDec: ID LP VarList RP {connect_to_next(4,$1,$2,$3,$4);$$=create_Node(0,"FunDec","",$1,NULL,0);if(add_dec($1->id,"function",$1->lineno)&&add_func_or_struct($1->id,$1->lineno,"function")){insert_function_args($1->id,$3);current_function_name=$1->id;is_in_function=true;} else{is_in_function=false;}}
| ID LP RP {connect_to_next(3,$1,$2,$3);$$=create_Node(0,"FunDec","",$1,NULL,0);if(add_dec($1->id,"function",$1->lineno)&&add_func_or_struct($1->id,$1->lineno,"function")){current_function_name=$1->id;is_in_function=true;} else{is_in_function=false;}}
| ID LP VarList error {printf("Error type B at line %d: missing closing symbols ')'\n", $1->lineno);}
| ID LP error {printf("Error type B at line %d: missing closing symbols ')'\n", $1->lineno);}

VarList: ParamDec COMMA VarList {connect_to_next(3,$1,$2,$3);$$=create_Node(0,"VarList","",$1,NULL,0);}
| ParamDec {$$=create_Node(0,"VarList","",$1,NULL,0);}

ParamDec: Specifier VarDec {connect_to_next(2,$1,$2);$$=create_Node(0,"ParamDec","",$1,NULL,0);}

CompSt: LC DefList StmtList RC {connect_to_next(4,$1,$2,$3,$4);$$=create_Node(0,"CompSt","",$1,NULL,0);}

StmtList: Stmt StmtList {connect_to_next(2,$1,$2);$$=create_Node(0,"StmtList","",$1,NULL,0);}
|Stmt Def StmtList error {printf("Error type B at line %d: definition after statement\n", $2->lineno);}
| /* empty */ {$$=create_Node(0,"empty","",NULL,NULL,100);}

Stmt: Exp SEMI {connect_to_next(2,$1,$2);$$=create_Node(0,"Stmt","",$1,NULL,0);}
| CompSt {$$=create_Node(0,"Stmt","",$1,NULL,0);}
| RETURN Exp SEMI {connect_to_next(3,$1,$2,$3);$$=create_Node(0,"Stmt","",$1,NULL,0);}
| RETURN Exp error {printf("Error type B at line %d: missing semicolon ';'\n", $1->lineno);}
| IF LP Exp RP Stmt {connect_to_next(5,$1,$2,$3,$4,$5);$$=create_Node(0,"Stmt","",$1,NULL,0);}
| IF LP Exp RP Stmt ELSE Stmt {connect_to_next(7,$1,$2,$3,$4,$5,$6,$7);$$=create_Node(0,"Stmt","",$1,NULL,0);}
| WHILE LP Exp RP Stmt {connect_to_next(5,$1,$2,$3,$4,$5);$$=create_Node(0,"Stmt","",$1,NULL,0);}

DefList: Def DefList {connect_to_next(2,$1,$2);$$=create_Node(0,"DefList","",$1,NULL,0);}
| /* empty */ {$$=create_Node(0,"empty","",NULL,NULL,100);}

Def: Specifier DecList SEMI {connect_to_next(3,$1,$2,$3);$$=create_Node(0,"Def","",$1,NULL,0);check_Def($$);}
| Specifier DecList error {printf("Error type B at line %d: missing semicolon ';'\n", $1->lineno);}

DecList: Dec {$$=create_Node(0,"DecList","",$1,NULL,0);}
| Dec COMMA DecList {connect_to_next(3,$1,$2,$3);$$=create_Node(0,"DecList","",$1,NULL,0);}

Dec: VarDec {$$=create_Node(0,"Dec","",$1,NULL,0);insert_func_variables($$);}
| VarDec ASSIGN Exp {connect_to_next(3,$1,$2,$3);$$=create_Node(0,"Dec","",$1,NULL,0);insert_func_variables($$);}

Exp: Exp ASSIGN Exp {connect_to_next(3,$1,$2,$3);$$=create_Node(0,"Exp","",$1,NULL,0);check_exp_assign($1,$3);set_rvalue($$);set_EXP_value_type($$,"int");}
| Exp AND Exp {connect_to_next(3,$1,$2,$3);$$=create_Node(0,"Exp","",$1,NULL,0);check_exp_logical_symbols($1,$3);set_rvalue($$);set_EXP_value_type($$,"int");}
| Exp OR Exp {connect_to_next(3,$1,$2,$3);$$=create_Node(0,"Exp","",$1,NULL,0);check_exp_logical_symbols($1,$3);set_rvalue($$);set_EXP_value_type($$,"int");}
| Exp LT Exp {connect_to_next(3,$1,$2,$3);$$=create_Node(0,"Exp","",$1,NULL,0);check_exp_logical_symbols($1,$3);set_rvalue($$);set_EXP_value_type($$,"int");}
| Exp LE Exp {connect_to_next(3,$1,$2,$3);$$=create_Node(0,"Exp","",$1,NULL,0);check_exp_logical_symbols($1,$3);set_rvalue($$);set_EXP_value_type($$,"int");}
| Exp GT Exp {connect_to_next(3,$1,$2,$3);$$=create_Node(0,"Exp","",$1,NULL,0);check_exp_logical_symbols($1,$3);set_rvalue($$);set_EXP_value_type($$,"int");}
| Exp GE Exp {connect_to_next(3,$1,$2,$3);$$=create_Node(0,"Exp","",$1,NULL,0);check_exp_logical_symbols($1,$3);set_rvalue($$);set_EXP_value_type($$,"int");}
| Exp NE Exp {connect_to_next(3,$1,$2,$3);$$=create_Node(0,"Exp","",$1,NULL,0);check_exp_logical_symbols($1,$3);set_rvalue($$);set_EXP_value_type($$,"int");}
| Exp EQ Exp {connect_to_next(3,$1,$2,$3);$$=create_Node(0,"Exp","",$1,NULL,0);check_exp_logical_symbols($1,$3);set_rvalue($$);set_EXP_value_type($$,"int");}
| Exp PLUS Exp {connect_to_next(3,$1,$2,$3);$$=create_Node(0,"Exp","",$1,NULL,0);check_exp_arithmetic_symbols($1,$3);set_rvalue($$);set_EXP_value_type($$,$1->value_type);}
| Exp MINUS Exp {connect_to_next(3,$1,$2,$3);$$=create_Node(0,"Exp","",$1,NULL,0);check_exp_arithmetic_symbols($1,$3);set_rvalue($$);set_EXP_value_type($$,$1->value_type);}
| Exp MUL Exp {connect_to_next(3,$1,$2,$3);$$=create_Node(0,"Exp","",$1,NULL,0);check_exp_arithmetic_symbols($1,$3);set_rvalue($$);set_EXP_value_type($$,$1->value_type);}
| Exp DIV Exp {connect_to_next(3,$1,$2,$3);$$=create_Node(0,"Exp","",$1,NULL,0);check_exp_arithmetic_symbols($1,$3);set_rvalue($$);set_EXP_value_type($$,$1->value_type);}
| LP Exp RP {connect_to_next(3,$1,$2,$3);$$=create_Node(0,"Exp","",$1,NULL,0);strcpy($$->value_type,$2->value_type);$$->rvalue=$2->rvalue;} //(b)
| LP Exp error {printf("Error type B at line %d: missing closing symbols ')'\n", $1->lineno);}
| MINUS Exp {connect_to_next(2,$1,$2);$$=create_Node(0,"Exp","",$1,NULL,0);check_single_arithmetic_exp($2);$$->rvalue=$2->rvalue;set_EXP_value_type($$,$2->value_type);}
| NOT Exp {connect_to_next(2,$1,$2);$$=create_Node(0,"Exp","",$1,NULL,0);check_single_logical_exp($2);$$->rvalue=$2->rvalue;set_EXP_value_type($$,$2->value_type);}
| ID LP Args RP {connect_to_next(4,$1,$2,$3,$4);$$=create_Node(0,"Exp","",$1,NULL,0);if(check_if_func_exist($1->id,$1->lineno)){check_func_args($1->id,$3,0);set_EXP_value_type($$,find_func_return_type($1->id));} else{set_EXP_value_type($$,"error");}} //调用函数a(...)
| ID LP Args error {printf("Error type B at line %d: missing closing symbols ')'\n", $1->lineno);}
| ID LP RP {connect_to_next(3,$1,$2,$3);$$=create_Node(0,"Exp","",$1,NULL,0);if(check_if_func_exist($1->id,$1->lineno)){check_func_without_args($1->id,$1->lineno);set_EXP_value_type($$,find_func_return_type($1->id));} else{set_EXP_value_type($$,"error");}} //调用函数,无参数
| Exp LB Exp RB {connect_to_next(4,$1,$2,$3,$4);$$=create_Node(0,"Exp","",$1,NULL,0);if(check_exp_array($1,$3)){if(index_error){set_EXP_value_type($$,"None");index_error=false;}else{set_EXP_value_type($$,find_array_elem_type($1));}}else{set_EXP_value_type($$,"error");}} //数组访问a[...]
| Exp DOT ID {connect_to_next(3,$1,$2,$3);$$=create_Node(0,"Exp","",$1,NULL,0);if(check_exp_structure($1,$3)){set_EXP_value_type($$,find_structure_member_type($1->value_type,$3->id));}else{strcpy($$->value_type,"None");}} //结构体
| ID {$$=create_Node(0,"Exp","",$1,NULL,0);set_EXP_value_type($$,check_exp_id($1));}
| INT {$$=create_Node(0,"Exp","",$1,NULL,0);set_EXP_value_type($$,"int");$$->rvalue=1;}
| FLOAT {$$=create_Node(0,"Exp","",$1,NULL,0);set_EXP_value_type($$,"float");$$->rvalue=1;}
| CHAR {$$=create_Node(0,"Exp","",$1,NULL,0);set_EXP_value_type($$,"char");$$->rvalue=1;}
| ILLEGAL error {printf("Error type A at line %d: unknown lexeme '%s'\n", $1->lineno,$1->id);}
| ILLEGAL_HEX_INT error {printf("Error type A at line %d: illegal hexadecimal integer '%s'\n", $1->lineno,$1->id);}
| ILLEGAL_CHAR error {printf("Error type A at line %d: illegal hex_character '%s'\n", $1->lineno,$1->id);}
| Exp ILLEGAL Exp error {printf("Error type A at line %d: illegal operator '%s'\n", $2->lineno,$2->id);}


Args: Exp COMMA Args {connect_to_next(3,$1,$2,$3);$$=create_Node(0,"Args","",$1,NULL,0);}
| Exp {$$=create_Node(0,"Args","",$1,NULL,0);}

%%


void yyerror() {
//printf("Syntax error at line %d: %s\n", line, s);
//printf("Error type B at line ");
flag=1;
return ;
}



int main(int argc, char **argv) {
if (argc != 2) {
fprintf(stderr, "Usage: %s <file_path>\n", argv[0]);
exit(-1);
} else if (!(yyin = fopen(argv[1], "r"))) {
perror(argv[1]);
exit(-1);
}
yyparse();
if(flag==0)
{
//print_tree(root,0);
}

/*
printf("\ntables:\n");
//打印符号表
for(int i=0;i<dec_num;i++)
{
printf("%s %s\n",dec[i].name,dec[i].type);
}

//打印定义表
for(int i=0;i<def_num;i++)
{
printf("%s \n",def[i].name);
for(int j=0;j<def[i].arg_num;j++)
{
printf("%s %s\n",def[i].args[j].name,def[i].args[j].type);
}
for(int j=0;j<def[i].dec_num;j++)
{
printf("%s %s\n",def[i].dec[j].name,def[i].dec[j].type);
}
printf("return_type:%s\n",def[i].return_type);
}
*/
return 0;
}

Makefile

makefile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
CC=gcc
FLEX=flex
BISON=bison

.PHONY: bplc clean

bplc: bin/bplc

bin/bplc: bin myhead.o syntax.tab.o
$(CC) -o bin/bplc myhead.o syntax.tab.o -lfl -ly

myhead.o: myhead.cpp
$(CXX) -c myhead.cpp -o myhead.o

syntax.tab.o: syntax.tab.c
$(CC) -c syntax.tab.c -o syntax.tab.o

syntax.tab.c: syntax.y lex.yy.c
$(BISON) -t -d syntax.y

lex.yy.c: lex.l
$(FLEX) lex.l

bin:
mkdir bin

clean:
@rm -f lex.yy.c syntax.tab.* ./bin/* *.o

bplc_test.py

python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import pathlib
import re
import subprocess


DATA = pathlib.Path('test')


def jsonparser_output(json_file):
out = subprocess.check_output(['./bin/bplc', json_file])
return out.decode().strip()

def check_jsonchecker_fail_syntaxonly():
data = DATA
for bplfile in data.glob('*.bpl'):
out = jsonparser_output(bplfile)
print(f'For file {bplfile.name}:')
print(out)
print('#'*80)
subfolder_name = "out"
temp=bplfile.name[0:10]
file_name = f"./{subfolder_name}/"+temp+".out"
with open(file_name, 'w') as file:
file.write(out)



# check_jsonchecker_fail_withlexical()
check_jsonchecker_fail_syntaxonly()

myhead.h

c++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#ifndef MYHEAD_H_  // 防止头文件重复包含
#define MYHEAD_H_

#ifdef __cplusplus // 允许C++调用C语言代码
extern "C" {
#endif

#include <stdbool.h>

// 定义一个结构体,用于描述变量声明
typedef struct {
char name[100]; // 变量名
char type[100]; // 变量类型
} declare;

// 定义一个结构体,用于描述复杂类型的定义,包括数组、结构体和函数
typedef struct {
char name[100]; // 名称
char elem_type[100]; // 对于数组类型,表示元素的类型
declare dec[100]; // 存储结构体成员或函数内部变量
char return_type[100]; // 对于函数类型,表示返回值类型
declare args[100]; // 对于函数,存储参数列表
int arg_num; // 函数参数的数量
int dec_num; // dec数组中的元素数量
} definition;

extern declare dec[100]; // 全局变量表
extern int dec_num; // 全局变量数目
extern definition def[100]; // 复杂类型定义数组
extern int def_num; // 复杂类型定义数目
extern char last_type[100]; // 上一次定义的类型名称

// 函数声明
void set_last_type(char *type);
bool add_dec(char *name, char *type, int lineno);
void add_array(char *name, char *elem_type, int lineno);
bool add_func_or_struct(char *name, int lineno, char *type);
void build_func_and_struct_dec(char *name, char *dec_name, char *type);
char* find_id_type(char *name);
declare* find_func_or_struct_dec(char *name);
char* find_func_return_type(char *name);
void add_struct_member(char *struct_name, char *member_name, char *member_type, int lineno);
void add_func_args(char *func_name, char *arg_name, char *arg_type, int lineno);
void add_func_variables(char *func_name, char *variable_name, char *variable_type, int lineno);
char* find_structure_member_type(char *struct_name, char *member_name);
void set_func_return_type(char *func_name, char *return_type);

#ifdef __cplusplus
}
#endif

#endif /* MYHEAD_H_ */

myhead.cpp

c++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#include "myhead.h"
#include <cstdio>
#include <cstring>

declare dec[100];//定义的变量表
int dec_num=0;//定义的变量数目
definition def[100];//定义的array,struct,function
int def_num=0;//定义的array,struct,function数目
char last_type[100];//最后一次定义的类型

void set_last_type(char *type) {
strcpy(last_type, type); // 直接复制类型名称到 last_type
}

bool add_dec(char *name, char *type, int lineno) {
// 检查变量是否已经被定义过
for (int i = 0; i < dec_num; ++i) {
if (strcmp(dec[i].name, name) == 0) {
// 根据已存在变量类型区分错误类型
const char *errorType =
strcmp(dec[i].type, "function") == 0 ? "function" :
strcmp(dec[i].type, "structure") == 0 ? "structure" :
"variable";
int errorTypeCode = strcmp(errorType, "function") == 0 ? 4 :
strcmp(errorType, "structure") == 0 ? 15 :
3;
printf("Error type %d at Line %d: Redefined %s \"%s\".\n", errorTypeCode, lineno, errorType, name);
return false;
}
}

// 添加新的定义
strcpy(dec[dec_num].name, name);
strcpy(dec[dec_num].type, type);
dec_num++; // 增加定义计数
return true;
}

void add_array(char *name, char *elem_type, int lineno) {
// 检查数组是否已经被定义过
for (int i = 0; i < def_num; ++i) {
if (strcmp(def[i].name, name) == 0) {
printf("Error type 3 at Line %d: Redefined variable \"%s\".\n", lineno, name);
return;
}
}

// 添加新的数组定义
strcpy(def[def_num].name, name);
strcpy(def[def_num].elem_type, elem_type);
def[def_num].dec_num = 0; // 初始化数组内部变量计数为0
def_num++; // 增加定义计数
}

bool add_func_or_struct(char *name, int lineno, char *type) {
// 检查是否已经定义过同名的函数或结构体
for (int i = 0; i < def_num; ++i) {
if (strcmp(def[i].name, name) == 0) {
// 错误处理,根据类型输出不同的错误信息
int errorTypeCode = strcmp(type, "function") == 0 ? 4 : 15;
const char *typeText = strcmp(type, "function") == 0 ? "function" : "structure";
printf("Error type %d at Line %d: Redefined %s \"%s\".\n", errorTypeCode, lineno, typeText, name);
return false;
}
}

// 添加新的函数或结构体定义
strcpy(def[def_num].name, name);
if (strcmp(type, "function") == 0) {
def[def_num].arg_num = 0; // 为函数初始化参数数量
}
def[def_num].dec_num = 0; // 初始化成员或局部变量数量
def_num++; // 增加定义计数
return true;
}

void build_func_and_struct_dec(char *name, char *dec_name, char *type) {
// 查找并为特定的函数或结构体添加成员定义
for (int i = 0; i < def_num; ++i) {
if (strcmp(def[i].name, name) == 0) {
strcpy(def[i].dec[def[i].dec_num].name, dec_name);
strcpy(def[i].dec[def[i].dec_num].type, type);
def[i].dec_num++; // 更新成员计数
return;
}
}
}

char* find_id_type(char *name) {
// 遍历变量表,查找匹配的变量类型
for (int i = 0; i < dec_num; ++i) {
if (strcmp(dec[i].name, name) == 0) {
return dec[i].type; // 返回找到的变量类型
}
}
return NULL; // 找不到时返回NULL
}

declare* find_func_or_struct_dec(char *name) {
// 遍历定义列表,寻找匹配的函数或结构体
for (int i = 0; i < def_num; i++) {
if (strcmp(def[i].name, name) == 0) {
return def[i].dec; // 找到后返回其声明数组
}
}
return NULL; // 未找到返回NULL
}

char* find_func_return_type(char *name) {
// 遍历定义列表,寻找匹配的函数
for (int i = 0; i < def_num; i++) {
if (strcmp(def[i].name, name) == 0) {
return def[i].return_type; // 找到后返回其返回类型
}
}
return NULL; // 未找到返回NULL
}

void add_struct_member(char *struct_name, char *member_name, char *member_type, int lineno) {
// 遍历定义列表以查找指定的结构体
for (int i = 0; i < def_num; i++) {
if (strcmp(def[i].name, struct_name) == 0) {
// 检查成员是否已经定义在结构体中
for (int j = 0; j < def[i].dec_num; j++) {
if (strcmp(def[i].dec[j].name, member_name) == 0) {
printf("Error type 15 at Line %d: Redefined field \"%s\".\n", lineno, member_name);
return; // 找到重复定义,报错并退出
}
}
// 将新成员添加到结构体定义中
strcpy(def[i].dec[def[i].dec_num].name, member_name);
strcpy(def[i].dec[def[i].dec_num].type, member_type);
def[i].dec_num++; // 更新成员数量
return; // 成功添加后退出
}
}
}

void add_func_args(char *func_name, char *arg_name, char *arg_type, int lineno) {
// 遍历定义列表以查找指定的函数
for (int i = 0; i < def_num; i++) {
if (strcmp(def[i].name, func_name) == 0) {
// 检查参数是否已经定义在函数中
for (int j = 0; j < def[i].arg_num; j++) {
if (strcmp(def[i].args[j].name, arg_name) == 0) {
printf("Error type 3 at Line %d: Redefined variable \"%s\".\n", lineno, arg_name);
return; // 找到重复定义,报错并退出
}
}
// 将新参数添加到函数定义中
strcpy(def[i].args[def[i].arg_num].name, arg_name);
strcpy(def[i].args[def[i].arg_num].type, arg_type);
def[i].arg_num++; // 更新参数数量
return; // 成功添加后退出
}
}
}

void add_func_variables(char *func_name, char *variable_name, char *variable_type, int lineno) {
// 遍历已定义列表以查找指定函数
for (int i = 0; i < def_num; i++) {
if (strcmp(def[i].name, func_name) == 0) {
// 在找到的函数中遍历检查是否存在同名变量
for (int j = 0; j < def[i].dec_num; j++) {
if (strcmp(def[i].dec[j].name, variable_name) == 0) {
printf("Error type 3 at Line %d: Redefined variable \"%s\".\n", lineno, variable_name);
return; // 发现重复定义,报错并退出
}
}
// 若未发现重复定义,则添加新变量
strcpy(def[i].dec[def[i].dec_num].name, variable_name);
strcpy(def[i].dec[def[i].dec_num].type, variable_type);
def[i].dec_num++; // 更新变量数量
return; // 添加成功后退出
}
}
}

char* find_structure_member_type(char *struct_name, char *member_name) {
// 遍历定义列表查找指定结构体
for (int i = 0; i < def_num; i++) {
if (strcmp(def[i].name, struct_name) == 0) {
// 在找到的结构体中遍历检查是否存在指定成员
for (int j = 0; j < def[i].dec_num; j++) {
if (strcmp(def[i].dec[j].name, member_name) == 0) {
return def[i].dec[j].type; // 找到成员,返回其类型
}
}
return NULL; // 指定成员不存在
}
}
return NULL; // 指定结构体不存在
}

void set_func_return_type(char *name, char *type) {
// 遍历已定义列表以查找指定函数
for (int i = 0; i < def_num; i++) {
if (strcmp(def[i].name, name) == 0) {
strcpy(def[i].return_type, type); // 找到函数,设置返回类型
return; // 设置成功后退出
}
}
}