Typecheck pronto. Gerando grafos melhores.
[toypasc.git] / typecheck_visitor.c
blob9e1c70a67469057792752405a79f2a50ca95df6e
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include "typecheck_visitor.h"
5 static bool _is_vardecl = FALSE;
6 static struct AstNode *_inside_procfunc = NULL;
7 static Symbol *_procfunc_symbol = NULL;
8 static void _typecheck_print_stmt(struct AstNode *node, Type type, const char *ptype_str);
9 static Symbol *_complete_symbol_lookup(Symbol *sym);
11 Visitor *
12 typecheck_new()
14 Visitor *visitor = (Visitor *) malloc (sizeof(Visitor));
16 visitor->visit_program = &typecheck_visit_program;
17 visitor->visit_programdecl = &typecheck_visit_programdecl;
18 visitor->visit_vardecl_list = &typecheck_visit_vardecl_list;
19 visitor->visit_vardecl = &typecheck_visit_vardecl;
20 visitor->visit_procfunc_list = &typecheck_visit_procfunc_list;
21 visitor->visit_procedure = &typecheck_visit_procfunc;
22 visitor->visit_function = &typecheck_visit_procfunc;
23 visitor->visit_param_list = &typecheck_visit_param_list;
24 visitor->visit_parameter = &typecheck_visit_parameter;
25 visitor->visit_statement_list = &typecheck_visit_statement_list;
26 visitor->visit_printint_stmt = &typecheck_visit_printint_stmt;
27 visitor->visit_printchar_stmt = &typecheck_visit_printchar_stmt;
28 visitor->visit_printbool_stmt = &typecheck_visit_printbool_stmt;
29 visitor->visit_printline_stmt = NULL;
30 visitor->visit_assignment_stmt = &typecheck_visit_assignment_stmt;
31 visitor->visit_if_stmt = &typecheck_visit_if_stmt;
32 visitor->visit_while_stmt = &typecheck_visit_while_stmt;
33 visitor->visit_for_stmt = &typecheck_visit_for_stmt;
34 visitor->visit_rel_expr = &typecheck_visit_binary_expr;
35 visitor->visit_add_expr = &typecheck_visit_binary_expr;
36 visitor->visit_mul_expr = &typecheck_visit_binary_expr;
37 visitor->visit_notfactor = &typecheck_visit_notfactor;
38 visitor->visit_call = &typecheck_visit_call;
39 visitor->visit_callparam_list = &typecheck_visit_callparam_list;
40 visitor->visit_callparam = &typecheck_visit_callparam;
41 visitor->visit_identifier_list = &typecheck_visit_identifier_list;
42 visitor->visit_identifier = &typecheck_visit_identifier;
43 visitor->visit_literal = NULL;
44 visitor->visit_add_op = NULL;
45 visitor->visit_mul_op = NULL;
46 visitor->visit_rel_op = NULL;
47 visitor->visit_not_op = NULL;
49 return visitor;
52 void
53 typecheck_visit_program(struct _Visitor *visitor, struct AstNode *node)
55 _is_vardecl = FALSE;
56 node->symbol = symbol_new(NULL);
57 global_symtab = node->symbol;
58 symtab = global_symtab;
59 _inside_procfunc = NULL;
60 ast_node_accept_children(node->children, visitor);
63 void
64 typecheck_visit_programdecl (struct _Visitor *visitor, struct AstNode *node)
66 _is_vardecl = TRUE;
67 node->children->symbol->decl_linenum = node->linenum;
68 ast_node_accept(node->children, visitor);
69 _is_vardecl = FALSE;
72 void
73 typecheck_visit_procfunc_list (struct _Visitor *visitor, struct AstNode *node)
75 symtab = global_symtab;
77 ast_node_accept_children(node->children, visitor);
79 symtab = global_symtab;
80 _inside_procfunc = NULL;
83 void
84 typecheck_visit_procfunc (struct _Visitor *visitor, struct AstNode *node)
86 struct AstNode *ident;
87 struct AstNode *child;
89 _inside_procfunc = node;
90 _procfunc_symbol = node->children->symbol;
92 // Identifier
93 symtab = global_symtab;
94 ident = node->children;
95 _is_vardecl = TRUE;
97 ident->symbol->is_procfunc = TRUE;
98 ident->symbol->decl_linenum = node->linenum;
100 ast_node_accept(ident, visitor);
102 symtab = node->symbol;
104 // ParamList, VarDeclList, Statements
105 for (child = ident->sibling; child != NULL; child = child->sibling) {
106 ast_node_accept(child, visitor);
107 if (child->kind == PARAM_LIST)
108 ident->symbol->params = child->child_counter;
112 void
113 typecheck_visit_vardecl_list (struct _Visitor *visitor, struct AstNode *node)
115 struct AstNode *child;
117 _is_vardecl = TRUE;
119 for (child = node->children; child != NULL; child = child->sibling)
120 ast_node_accept(child, visitor);
122 _is_vardecl = FALSE;
125 void
126 typecheck_visit_vardecl (struct _Visitor *visitor, struct AstNode *node)
128 node->children->type = node->type;
129 ast_node_accept(node->children, visitor);
132 void
133 typecheck_visit_param_list(struct _Visitor *visitor, struct AstNode *node)
135 int i;
136 struct AstNode *child;
138 _is_vardecl = TRUE;
140 node->child_counter = 0;
141 for (child = node->children; child != NULL; child = child->sibling) {
142 ast_node_accept(child, visitor);
143 node->child_counter++;
146 child = node->children;
147 _procfunc_symbol->param_types = (int *) malloc
148 (sizeof(int) * node->child_counter);
150 for (i = 0; i < node->child_counter; i++) {
151 _procfunc_symbol->param_types[i] = child->type;
152 child = child->sibling;
155 _procfunc_symbol->params = node->child_counter;
156 _is_vardecl = FALSE;
160 void
161 typecheck_visit_parameter (struct _Visitor *visitor, struct AstNode *node)
163 node->children->type = node->type;
164 node->children->symbol->is_parameter = TRUE;
165 node->children->symbol->decl_linenum = node->linenum;
166 ast_node_accept(node->children, visitor);
169 void
170 typecheck_visit_statement_list(struct _Visitor *visitor, struct AstNode *node)
172 ast_node_accept_children(node->children, visitor);
175 void
176 typecheck_visit_printint_stmt (struct _Visitor *visitor, struct AstNode *node)
178 ast_node_accept(node->children, visitor);
179 _typecheck_print_stmt(node, INTEGER, "Int");
182 void
183 typecheck_visit_printchar_stmt (struct _Visitor *visitor, struct AstNode *node)
185 ast_node_accept(node->children, visitor);
186 _typecheck_print_stmt(node, CHAR, "Char");
189 void
190 typecheck_visit_printbool_stmt (struct _Visitor *visitor, struct AstNode *node)
192 ast_node_accept(node->children, visitor);
193 _typecheck_print_stmt(node, BOOLEAN, "Bool");
196 void
197 typecheck_visit_assignment_stmt (struct _Visitor *visitor, struct AstNode *node)
199 struct AstNode *lnode = node->children;
200 struct AstNode *rnode = lnode->sibling;
202 ast_node_accept(lnode, visitor);
203 ast_node_accept(rnode, visitor);
205 if (lnode->symbol->is_procfunc && (_inside_procfunc == NULL ||
206 strcmp(_inside_procfunc->children->symbol->name,
207 lnode->symbol->name))) {
208 node->type = ERROR;
209 fprintf(stderr,
210 "Error: Symbol '%s' is a function identifier, you cannot "
211 "assign a value to it from outside the said function. "
212 "Check line %d.\n", lnode->symbol->name, node->linenum);
214 } else if (lnode->type != ERROR && rnode->type != ERROR &&
215 lnode->type != rnode->type) {
216 node->type = ERROR;
217 fprintf(stderr,
218 "Error: Incompatible types on assignment "
219 "operation in line %d.\n", node->linenum);
223 void
224 typecheck_visit_if_stmt (struct _Visitor *visitor, struct AstNode *node)
226 struct AstNode *expr = node->children;
227 struct AstNode *stmt = expr->sibling;
229 ast_node_accept(expr, visitor);
230 ast_node_accept(stmt, visitor);
232 if (expr->type != BOOLEAN) {
233 node->type = ERROR;
234 fprintf(stderr,
235 "Error: Condition for if statement must be of Boolean type. "
236 "Check line %d.\n", node->linenum);
240 void
241 typecheck_visit_while_stmt (struct _Visitor *visitor, struct AstNode *node)
243 struct AstNode *expr = node->children;
244 struct AstNode *stmt = expr->sibling;
246 ast_node_accept(expr, visitor);
247 ast_node_accept(stmt, visitor);
249 if (expr->type != BOOLEAN) {
250 node->type = ERROR;
251 fprintf(stderr,
252 "Error: Expression in While statement must be of "
253 "Boolean type. Check line %d.\n", expr->linenum);
257 void
258 typecheck_visit_for_stmt (struct _Visitor *visitor, struct AstNode *node)
260 struct AstNode *asgn = node->children;
261 struct AstNode *expr = asgn->sibling;
262 struct AstNode *stmt = expr->sibling;
263 struct AstNode *id_node = asgn->children;
265 ast_node_accept(asgn, visitor);
266 ast_node_accept(expr, visitor);
268 if (id_node->type != INTEGER) {
269 node->type = ERROR;
270 fprintf(stderr,
271 "Error: Identifier '%s' is of %s type; it must be Integer. "
272 "Check line %d.\n", id_node->symbol->name,
273 type_get_lexeme(id_node->type), id_node->linenum);
276 if (expr->type != INTEGER) {
277 node->type = ERROR;
278 fprintf(stderr,
279 "Error: Value of stop condition is not of Integer type. "
280 "Check line %d.\n", expr->linenum);
283 ast_node_accept(stmt, visitor);
287 void
288 typecheck_visit_binary_expr (struct _Visitor *visitor, struct AstNode *node)
290 struct AstNode *lnode = node->children;
291 struct AstNode *op = lnode->sibling;
292 struct AstNode *rnode = op->sibling;
294 ast_node_accept(lnode, visitor);
295 ast_node_accept(rnode, visitor);
297 if (lnode->type != ERROR && rnode->type != ERROR &&
298 lnode->type != rnode->type) {
299 node->type = ERROR;
300 fprintf(stderr,
301 "Error: Operation '%s' over incompatible types on line %d.\n",
302 op->name, op->linenum);
306 void
307 typecheck_visit_notfactor (struct _Visitor *visitor, struct AstNode *node)
309 ast_node_accept(node->children, visitor);
311 if (node->children->type != BOOLEAN) {
312 node->type = ERROR;
313 fprintf(stderr,
314 "Error: Operation 'not' over non-boolean "
315 "operand on line %d.\n", node->linenum);
319 void
320 typecheck_visit_call (struct _Visitor *visitor, struct AstNode *node)
322 int params;
323 Symbol *previous_procfunc;
324 struct AstNode *ident = node->children;
325 struct AstNode *plist = ident->sibling;
327 ast_node_accept(ident, visitor);
329 previous_procfunc = _procfunc_symbol;
330 _procfunc_symbol = ident->symbol;
331 node->type = _procfunc_symbol->type;
333 ast_node_accept(plist, visitor);
335 params = (plist == NULL) ? 0 : plist->child_counter;
336 if (params != ident->symbol->params) {
337 node->type = ERROR;
338 fprintf(stderr, "Error: Expecting %d parameters, received %d. "
339 "Check line %d\n",
340 ident->symbol->params, params, node->linenum);
343 _procfunc_symbol = previous_procfunc;
346 void
347 typecheck_visit_callparam_list (struct _Visitor *visitor, struct AstNode *node)
349 int i;
350 struct AstNode *child;
352 node->child_counter = 0;
353 for (child = node->children; child != NULL; child = child->sibling)
354 node->child_counter++;
356 if (_procfunc_symbol->params != node->child_counter) {
357 node->type = ERROR;
358 return;
361 i = 0;
362 for (child = node->children; child != NULL; child = child->sibling) {
363 ast_node_accept(child, visitor);
365 if (child->type != _procfunc_symbol->param_types[i]) {
366 node->type = ERROR;
367 fprintf(stderr, "Error: Call '%s' on line %d, expecting %s "
368 "on parameter %d (",
369 _procfunc_symbol->name, node->linenum,
370 type_get_lexeme(_procfunc_symbol->param_types[i]),
371 i + 1);
373 if (child->children->symbol != NULL)
374 fprintf(stderr, "'%s'", child->children->symbol->name);
375 else
376 value_print(stderr, &child->value, child->type);
378 fprintf(stderr, "), received %s.\n", type_get_lexeme(child->type));
380 i++;
384 void
385 typecheck_visit_callparam (struct _Visitor *visitor, struct AstNode *node)
387 ast_node_accept(node->children, visitor);
388 node->type = node->children->type;
391 void
392 typecheck_visit_identifier_list (struct _Visitor *visitor, struct AstNode *node)
394 struct AstNode *child;
396 for (child = node->children; child != NULL; child = child->sibling) {
397 child->type = node->type;
398 child->symbol->decl_linenum = node->linenum;
399 ast_node_accept(child, visitor);
403 void
404 typecheck_visit_identifier (struct _Visitor *visitor, struct AstNode *node)
406 Symbol *sym;
408 //fprintf(stderr, "====== identifier[%s(gl?%d)]->decl_linenum: %d\n",
409 // node->symbol->name, (symtab==global_symtab), node->symbol->decl_linenum);
413 if (sym == NULL && node->symbol->decl_linenum > 0) {
414 node->symbol->type = node->type;
415 node->symbol->is_global = (symtab == global_symtab);
417 sym = symbol_insert(symtab, node->symbol);
419 if (sym != node->symbol) {
420 node->type = ERROR;
421 fprintf(stderr, "Error: Symbol '%s' already defined in line %d. "
422 "Check line %d.\n",
423 sym->name, sym->decl_linenum, node->linenum);
424 } else {
425 node->type = node->symbol->type;
426 node->symbol->decl_linenum = node->linenum;
429 } else {
430 sym = _complete_symbol_lookup(node->symbol);
432 if (sym != NULL) {
433 node->symbol = sym;
434 node->type = sym->type;
436 } else {
437 node->symbol->decl_linenum = 0;
438 node->type = ERROR;
439 fprintf(stderr, "Error: Undeclared symbol '%s' in line %d\n",
440 node->symbol->name, node->linenum);
445 sym = symbol_lookup(symtab, node->symbol->name);
447 if (sym == NULL) {
448 if (node->symbol->decl_linenum > 0) {
449 node->symbol->type = node->type;
450 node->symbol->is_global = (symtab == global_symtab);
452 sym = symbol_insert(symtab, node->symbol);
454 } else {
455 node->type = ERROR;
456 fprintf(stderr, "Error: Undeclared symbol '%s' in line %d\n",
457 node->symbol->name, node->linenum);
460 } else if (node->symbol->decl_linenum == 0) {
461 symbol_table_destroy(node->symbol);
462 node->symbol = sym;
463 node->type = sym->type;
465 } else {
466 node->type = ERROR;
467 fprintf(stderr, "Error: Symbol '%s' already defined in line %d. "
468 "Check line %d.\n",
469 sym->name, sym->decl_linenum, node->linenum);
474 // Helper functions ----------------------------------------------------------
476 static void
477 _typecheck_print_stmt(struct AstNode *node, Type type, const char *ptype_str)
479 if (node->children->type != type) {
480 node->type = ERROR;
481 fprintf(stderr,
482 "Error: Expression Print%s statement must be of "
483 "%s type. Check line %d.\n",
484 ptype_str, type_get_lexeme(type), node->linenum);