-
Notifications
You must be signed in to change notification settings - Fork 0
/
semantic.c
282 lines (229 loc) · 7.31 KB
/
semantic.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
#include "globals.h"
static int ignore_array_without_index = FALSE;
// for expression, check symtab
static Type check_symtab(Ast node) {
assert(node != NULL);
Entry entry = NULL;
Type type = -1;
switch(node->kind) {
case Decl_Var:
case Decl_Param:
case Decl_Fun:
error(Bug, "declaration ast node should not attend in check_symtab()");
case Stat_Compound:
case Stat_Select:
case Stat_Iterate:
case Stat_Return:
case Stat_Empty:
case Stat_Expression:
error(Bug, "statement ast node should not attend in check_symtab()");
case Expr_Assign:
type = check_symtab(node->children[0]);
if(type != IntT) {
yylineno = node->lineno;
error(TypeError, "left value must be INT");
}
type = check_symtab(node->children[1]);
if(type != IntT) {
yylineno = node->lineno;
error(TypeError, "right value must be INT");
}
return IntT;
case Expr_Binary:
type = check_symtab(node->children[0]);
if(type != IntT) {
yylineno = node->lineno;
error(TypeError, "left expression of operator \"%s\" must be INT",
operator_to_str(node->operator));
}
type = check_symtab(node->children[1]);
if(type != IntT) {
yylineno = node->lineno;
error(TypeError, "right expression of operator \"%s\" must be INT",
operator_to_str(node->operator));
}
switch(node->operator) {
case '+':
case '-':
case '*':
case '/':
return IntT;
case EQ:
case NE:
case LT:
case LE:
case GT:
case GE:
return BoolT;
default:
error(Bug, "unknown operator");
}
case Expr_Fun:
; // a label can only be part of a statement and a declaration is not a statement
FunInfo funinfo = lookup_funinfo(node->name);
if(funinfo == NULL) {
yylineno = node->lineno;
error(SemanticError, "undefined function \"%s\"", node->name);
}
entry = funinfo->symtab->head;
Ast param = node->children[0];
while(entry != NULL && param != NULL) { // parameter order: form right to left
if(entry->type == IntArrayT && param->kind == Expr_Var) { // special case (very restricted)
//fprintf(stderr, "%s,%s\n", entry->name, param->name);
ignore_array_without_index = TRUE;
}
type = check_symtab(param);
ignore_array_without_index = FALSE;
if(type != entry->type) {
yylineno = node->lineno;
error(SemanticError,
"type mismatch between actual parameter \"%s\" and formal parameter \"%s\" of function \"%s\"",
param->name, entry->name, node->name);
}
entry = entry->next;
param = param->sibling; // list of expression, only here
}
if(entry != NULL || param != NULL) {
yylineno = node->lineno;
error(SemanticError, "unmatched parameter number of function \"%s\"", node->name);
}
return funinfo->type; // IntT or VoidT
case Expr_Var:
entry = lookup_entry(node->name);
if(entry == NULL) {
yylineno = node->lineno;
error(SemanticError, "undefined variable \"%s\"", node->name);
}
if(entry->type == IntArrayT && node->type == IntArrayT) {
type = check_symtab(node->children[0]);
if(type != IntT) {
yylineno = node->lineno;
error(TypeError, "index of array \"%s\" must be INT", node->name);
}
return IntT; // 返回值是IntT,代表加下标后的计算结果是IntT;
//但 node->type = IntArrayT,代表本结点是以数组+下标的形式描述。
} else if(entry->type == IntArrayT && node->type == IntT) {
if(ignore_array_without_index) { // only usage of ignore_array_without_index
return IntArrayT; // 返回值是IntArrayT,代表这个变量是一个数组名;
//但 node->type = IntT,代表本结点是以单个变量不带名称的形式描述。
} else {
yylineno = node->lineno;
error(TypeError, "array variable \"%s\" should followed by []", node->name);
}
} else if(entry->type == IntT && node->type == IntArrayT) {
yylineno = node->lineno;
error(TypeError, "single variable \"%s\" cannot followed by []", node->name);
} else {
assert(entry->type == IntT && node->type == IntT);
return IntT;
}
case Expr_Const:
return IntT;
default:
error(Bug, "unknown ast node kind");
}
}
// for declaration, build symtab
// for statement, walk through
static void build_symtab(Ast node) {
FunInfo funinfo = NULL;
Type type = -1;
while(node != NULL) {
switch(node->kind) {
case Decl_Var:
insert_entry(node->name, node->type, node->number, node->lineno);
break;
case Decl_Param: // similar to Decl_Var
insert_entry(node->name, node->type, node->number, node->lineno);
break;
case Decl_Fun:
funinfo = lookup_funinfo(node->name);
if(funinfo != NULL) {
yylineno = node->lineno;
error(SemanticError, "duplicated declaration of function \"%s\"", node->name);
}
node->symtab = new_symtab(Fun_Param);
push_symtab(node->symtab);
funinfo = new_funinfo(node->name, node->type, node->symtab);
push_funinfo(funinfo);
build_symtab(node->children[0]); // recursion
build_symtab(node->children[1]); // recursion
pop_symtab();
break;
case Stat_Compound: // similar to Decl_Fun, except without funinfo
node->symtab = new_symtab(Compound_Var);
push_symtab(node->symtab);
build_symtab(node->children[0]); // recursion
pop_symtab();
break;
case Stat_Select:
type = check_symtab(node->children[0]);
if(type != BoolT) {
yylineno = node->lineno;
error(TypeError, "condiction of if-statement must be BOOL");
}
build_symtab(node->children[1]); // recursion
build_symtab(node->children[2]); // recursion(不检查has_else,因为NULL是安全的)
break;
case Stat_Iterate:
type = check_symtab(node->children[0]);
if(type != BoolT) {
yylineno = node->lineno;
error(TypeError, "condiction of while-loop must be BOOL");
}
build_symtab(node->children[1]); // recursion
break;
case Stat_Return:
funinfo = top_funinfo();
if(funinfo->type == IntT && node->type == IntT) {
type = check_symtab(node->children[0]);
if(type != IntT) {
yylineno = node->lineno;
error(TypeError, "return value must be INT");
}
} else if (funinfo->type == VoidT && node->type == VoidT) {
; // do nothing;
} else {
assert((funinfo->type == IntT && node->type == VoidT)
|| (funinfo->type == VoidT && node->type == IntT));
yylineno = node->lineno;
error(TypeError, "type mismatch between return statement and function prototype");
}
break;
case Stat_Empty:
break;
case Stat_Expression:
check_symtab(node->children[0]);
break;
case Expr_Assign:
case Expr_Binary:
case Expr_Fun:
case Expr_Var:
case Expr_Const:
error(Bug, "expression ast node should not attend in build_symtab()");
default:
error(Bug, "unknown ast node kind");
}
node = node->sibling;
}
}
void build_symtab_root(Ast root) {
// prelude symtab: global variable
push_symtab(new_symtab(Global_Var));
// prelude functions: input() & output()
push_funinfo(prelude_input_funinfo());
push_funinfo(prelude_output_funinfo());
// build symtab and check type recursively
build_symtab(root);
// make sure the correctness of symtab stack
if(top_symtab()->kind != Global_Var) {
error(Bug, "symtab stack not clean after semantic analysis");
}
// check the position of main()
if(strcmp(top_funinfo()->name, "main") != 0) {
yylineno = -1;
error(SemanticError, "the last function must be main()");
}
// reverse the fun_list
reverse_fun_list();
}