Problema de checagem de tipos resolvido; mais globais eliminadas; e geracao de grafo...
[toypasc.git] / typecheck_visitor.c
blobaeb8331fda9b02e07d45888ff1c2259756d4ae44
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include "typecheck_visitor.h"
5 static struct AstNode *_inside_procfunc = NULL;
6 static void _typecheck_print_stmt(struct AstNode *node, Type type, const char *ptype_str);
7 static Symbol *_complete_symbol_lookup(Symbol *sym);
9 Visitor *
10 typecheck_new()
12 Visitor *visitor = (Visitor *) malloc (sizeof(Visitor));
14 visitor->visit_program = &typecheck_visit_program;
15 visitor->visit_programdecl = &typecheck_visit_programdecl;
16 visitor->visit_vardecl_list = &typecheck_visit_vardecl_list;
17 visitor->visit_vardecl = &typecheck_visit_vardecl;
18 visitor->visit_procfunc_list = &typecheck_visit_procfunc_list;
19 visitor->visit_procedure = &typecheck_visit_procfunc;
20 visitor->visit_function = &typecheck_visit_procfunc;
21 visitor->visit_param_list = &typecheck_visit_param_list;
22 visitor->visit_parameter = &typecheck_visit_parameter;
23 visitor->visit_statement_list = &typecheck_visit_statement_list;
24 visitor->visit_printint_stmt = &typecheck_visit_printint_stmt;
25 visitor->visit_printchar_stmt = &typecheck_visit_printchar_stmt;
26 visitor->visit_printbool_stmt = &typecheck_visit_printbool_stmt;
27 visitor->visit_printline_stmt = NULL;
28 visitor->visit_assignment_stmt = &typecheck_visit_assignment_stmt;
29 visitor->visit_if_stmt = &typecheck_visit_if_stmt;
30 visitor->visit_while_stmt = &typecheck_visit_while_stmt;
31 visitor->visit_for_stmt = &typecheck_visit_for_stmt;
32 visitor->visit_rel_expr = &typecheck_visit_binary_expr;
33 visitor->visit_add_expr = &typecheck_visit_binary_expr;
34 visitor->visit_mul_expr = &typecheck_visit_binary_expr;
35 visitor->visit_notfactor = &typecheck_visit_notfactor;
36 visitor->visit_call = &typecheck_visit_call;
37 visitor->visit_callparam_list = &typecheck_visit_callparam_list;
38 visitor->visit_callparam = &typecheck_visit_callparam;
39 visitor->visit_identifier_list = &typecheck_visit_identifier_list;
40 visitor->visit_identifier = &typecheck_visit_identifier;
41 visitor->visit_literal = NULL;
42 visitor->visit_add_op = NULL;
43 visitor->visit_mul_op = NULL;
44 visitor->visit_rel_op = NULL;
45 visitor->visit_not_op = NULL;
47 return visitor;
50 void
51 typecheck_visit_program(struct _Visitor *visitor, struct AstNode *node)
53 node->symbol = symbol_new(NULL);
54 global_symtab = node->symbol;
55 symtab = global_symtab;
56 _inside_procfunc = NULL;
57 ast_node_accept_children(node->children, visitor);
60 void
61 typecheck_visit_programdecl (struct _Visitor *visitor, struct AstNode *node)
63 node->children->symbol->decl_linenum = node->linenum;
64 ast_node_accept(node->children, visitor);
67 void
68 typecheck_visit_procfunc_list (struct _Visitor *visitor, struct AstNode *node)
70 symtab = global_symtab;
72 ast_node_accept_children(node->children, visitor);
74 symtab = global_symtab;
75 _inside_procfunc = NULL;
78 void
79 typecheck_visit_vardecl_list (struct _Visitor *visitor, struct AstNode *node)
81 struct AstNode *child;
83 for (child = node->children; child != NULL; child = child->sibling)
84 ast_node_accept(child, visitor);
87 void
88 typecheck_visit_vardecl (struct _Visitor *visitor, struct AstNode *node)
90 node->children->type = node->type;
91 ast_node_accept(node->children, visitor);
94 void
95 typecheck_visit_procfunc (struct _Visitor *visitor, struct AstNode *node)
97 struct AstNode *ident;
98 struct AstNode *child;
100 _inside_procfunc = node;
102 // Identifier
103 symtab = global_symtab;
104 ident = node->children;
105 ident->type = node->type;
107 // params > -1 == identificador eh funcao
108 ident->symbol->params = 0;
110 ident->symbol->decl_linenum = node->linenum;
112 ast_node_accept(ident, visitor);
114 // ParamList, VarDeclList, Statements
115 symtab = node->symbol;
116 for (child = ident->sibling; child != NULL; child = child->sibling) {
117 if (child->kind == PARAM_LIST)
118 child->symbol = ident->symbol;
119 ast_node_accept(child, visitor);
123 void
124 typecheck_visit_param_list(struct _Visitor *visitor, struct AstNode *node)
126 int i;
127 struct AstNode *child;
129 node->child_counter = 0;
130 for (child = node->children; child != NULL; child = child->sibling) {
131 ast_node_accept(child, visitor);
132 node->child_counter++;
135 symbol_create_params(node->symbol, node->child_counter);
137 i = 0;
138 for (child = node->children; child != NULL; child = child->sibling) {
139 node->symbol->param_types[i] = child->type;
140 i++;
144 void
145 typecheck_visit_parameter (struct _Visitor *visitor, struct AstNode *node)
147 node->children->type = node->type;
148 node->children->symbol->is_parameter = TRUE;
149 node->children->symbol->decl_linenum = node->linenum;
150 ast_node_accept(node->children, visitor);
153 void
154 typecheck_visit_statement_list(struct _Visitor *visitor, struct AstNode *node)
156 ast_node_accept_children(node->children, visitor);
159 void
160 typecheck_visit_printint_stmt (struct _Visitor *visitor, struct AstNode *node)
162 ast_node_accept(node->children, visitor);
163 _typecheck_print_stmt(node, INTEGER, "Int");
166 void
167 typecheck_visit_printchar_stmt (struct _Visitor *visitor, struct AstNode *node)
169 ast_node_accept(node->children, visitor);
170 _typecheck_print_stmt(node, CHAR, "Char");
173 void
174 typecheck_visit_printbool_stmt (struct _Visitor *visitor, struct AstNode *node)
176 ast_node_accept(node->children, visitor);
177 _typecheck_print_stmt(node, BOOLEAN, "Bool");
180 void
181 typecheck_visit_assignment_stmt (struct _Visitor *visitor, struct AstNode *node)
183 struct AstNode *lnode = node->children;
184 struct AstNode *rnode = lnode->sibling;
186 ast_node_accept(lnode, visitor);
187 ast_node_accept(rnode, visitor);
189 if (symbol_is_procfunc(lnode->symbol) && (_inside_procfunc == NULL ||
190 strcmp(_inside_procfunc->children->symbol->name,
191 lnode->symbol->name))) {
192 node->type = ERROR;
193 fprintf(stderr,
194 "Error: Symbol '%s' is a function identifier, you cannot "
195 "assign a value to it from outside the said function. "
196 "Check line %d.\n", lnode->symbol->name, node->linenum);
198 } else if (lnode->type != ERROR && rnode->type != ERROR &&
199 lnode->type != rnode->type) {
200 node->type = ERROR;
201 fprintf(stderr,
202 "Error: Incompatible types on assignment "
203 "operation in line %d.\n", node->linenum);
207 void
208 typecheck_visit_if_stmt (struct _Visitor *visitor, struct AstNode *node)
210 struct AstNode *expr = node->children;
211 struct AstNode *stmt = expr->sibling;
213 ast_node_accept(expr, visitor);
214 ast_node_accept(stmt, visitor);
216 if (expr->type != BOOLEAN) {
217 node->type = ERROR;
218 fprintf(stderr,
219 "Error: Condition for if statement must be of Boolean type. "
220 "Check line %d.\n", node->linenum);
224 void
225 typecheck_visit_while_stmt (struct _Visitor *visitor, struct AstNode *node)
227 struct AstNode *expr = node->children;
228 struct AstNode *stmt = expr->sibling;
230 ast_node_accept(expr, visitor);
231 ast_node_accept(stmt, visitor);
233 if (expr->type != BOOLEAN) {
234 node->type = ERROR;
235 fprintf(stderr,
236 "Error: Expression in While statement must be of "
237 "Boolean type. Check line %d.\n", expr->linenum);
241 void
242 typecheck_visit_for_stmt (struct _Visitor *visitor, struct AstNode *node)
244 struct AstNode *asgn = node->children;
245 struct AstNode *expr = asgn->sibling;
246 struct AstNode *stmt = expr->sibling;
247 struct AstNode *id_node = asgn->children;
249 ast_node_accept(asgn, visitor);
250 ast_node_accept(expr, visitor);
252 if (id_node->type != INTEGER) {
253 node->type = ERROR;
254 fprintf(stderr,
255 "Error: Identifier '%s' is of %s type; it must be Integer. "
256 "Check line %d.\n", id_node->symbol->name,
257 type_get_lexeme(id_node->type), id_node->linenum);
260 if (expr->type != INTEGER) {
261 node->type = ERROR;
262 fprintf(stderr,
263 "Error: Value of stop condition is not of Integer type. "
264 "Check line %d.\n", expr->linenum);
267 ast_node_accept(stmt, visitor);
271 void
272 typecheck_visit_binary_expr (struct _Visitor *visitor, struct AstNode *node)
274 struct AstNode *lnode = node->children;
275 struct AstNode *op = lnode->sibling;
276 struct AstNode *rnode = op->sibling;
278 ast_node_accept(lnode, visitor);
279 ast_node_accept(rnode, visitor);
281 if (lnode->type != ERROR && rnode->type != ERROR &&
282 lnode->type != rnode->type) {
283 node->type = ERROR;
284 fprintf(stderr,
285 "Error: Operation '%s' over incompatible types on line %d.\n",
286 op->name, op->linenum);
290 void
291 typecheck_visit_notfactor (struct _Visitor *visitor, struct AstNode *node)
293 ast_node_accept(node->children, visitor);
295 if (node->children->type != BOOLEAN) {
296 node->type = ERROR;
297 fprintf(stderr,
298 "Error: Operation 'not' over non-boolean "
299 "operand on line %d.\n", node->linenum);
303 void
304 typecheck_visit_call (struct _Visitor *visitor, struct AstNode *node)
306 int params;
307 struct AstNode *ident = node->children;
308 struct AstNode *plist = ident->sibling;
310 ast_node_accept(ident, visitor);
312 if (ident->type == ERROR)
313 return;
315 node->type = ident->symbol->type;
317 if (plist != NULL) {
318 plist->symbol = ident->symbol;
319 ast_node_accept(plist, visitor);
320 params = plist->child_counter;
322 } else
323 params = 0;
325 if (params != ident->symbol->params) {
326 node->type = ERROR;
327 fprintf(stderr, "Error: Expecting %d parameters, received %d. "
328 "Check line %d\n",
329 ident->symbol->params, params, node->linenum);
333 void
334 typecheck_visit_callparam_list (struct _Visitor *visitor, struct AstNode *node)
336 int i;
337 struct AstNode *child;
339 node->child_counter = 0;
340 for (child = node->children; child != NULL; child = child->sibling)
341 node->child_counter++;
343 if (node->symbol->params != node->child_counter) {
344 node->type = ERROR;
345 return;
348 i = 0;
349 for (child = node->children; child != NULL; child = child->sibling) {
350 ast_node_accept(child, visitor);
352 if (child->type != ERROR &&
353 child->type != node->symbol->param_types[i]) {
354 node->type = ERROR;
355 child->type = node->symbol->param_types[i];
357 fprintf(stderr, "Error: Call '%s' on line %d, expecting %s "
358 "on parameter %d (",
359 node->symbol->name, node->linenum,
360 type_get_lexeme(node->symbol->param_types[i]),
361 i + 1);
363 if (child->children->kind == IDENTIFIER)
364 fprintf(stderr, "'%s'", child->children->symbol->name);
365 else
366 value_print(stderr, &child->value, child->type);
368 fprintf(stderr, "), received %s.\n", type_get_lexeme(child->type));
370 i++;
374 void
375 typecheck_visit_callparam (struct _Visitor *visitor, struct AstNode *node)
377 ast_node_accept(node->children, visitor);
378 node->type = node->children->type;
381 void
382 typecheck_visit_identifier_list (struct _Visitor *visitor, struct AstNode *node)
384 struct AstNode *child;
386 for (child = node->children; child != NULL; child = child->sibling) {
387 child->type = node->type;
388 child->symbol->decl_linenum = node->linenum;
389 ast_node_accept(child, visitor);
393 void
394 typecheck_visit_identifier (struct _Visitor *visitor, struct AstNode *node)
396 Symbol *sym = symbol_lookup(symtab, node->symbol->name);
397 Symbol *_sym = sym;
399 // O atributo 'decl_linenum' > 0 indica que o identificador referencia
400 // a declaracao de uma variavel/procedimento/funcao.
402 void __fetch_symbol(struct AstNode *node, Symbol *sym) {
403 symbol_table_destroy(node->symbol);
404 node->symbol = sym;
405 node->type = sym->type;
408 if (sym == NULL) {
410 // Simbolo possui linha de declaracao: Insira na tabela de simbolos.
411 if (node->symbol->decl_linenum > 0) {
412 node->symbol->type = node->type;
413 node->symbol->is_global = (symtab == global_symtab);
415 node->symbol = symbol_insert(symtab, node->symbol);
417 } else if ((sym = symbol_lookup(global_symtab, node->symbol->name))
418 != NULL) {
419 __fetch_symbol(node, sym);
421 // Sem linha de declaracao == eh fetch de variavel nao declarada.
422 } else {
423 node->symbol->type = node->type = ERROR;
424 fprintf(stderr, "Error: Undeclared symbol '%s' in line %d\n",
425 node->symbol->name, node->linenum);
428 // Simbolo encontrado na tabela e eh fetch: OK. Ou pode ser global.
429 } else if (node->symbol->decl_linenum == 0) {
430 __fetch_symbol(node, sym);
432 // Simbolo possui linha de declaracao mas foi encontrado na tabela:
433 // tentativa de redefinicao.
434 } else {
435 node->symbol->type = node->type = ERROR;
436 fprintf(stderr, "Error: Symbol '%s' already defined in line %d. "
437 "Check line %d.\n",
438 _sym->name, _sym->decl_linenum, node->linenum);
443 // Helper functions ----------------------------------------------------------
445 static void
446 _typecheck_print_stmt(struct AstNode *node, Type type, const char *ptype_str)
448 if (node->children->type != type) {
449 node->type = ERROR;
450 fprintf(stderr,
451 "Error: Expression Print%s statement must be of "
452 "%s type. Check line %d.\n",
453 ptype_str, type_get_lexeme(type), node->linenum);