Um comentario relevante adicionado.
[toypasc.git] / typecheck_visitor.c
blobff95a808f4376d0bf18250096b98c0e7d0e6a650
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 // CallParamLists apontam para o simbolo da funcao chamada
319 // para obter a quantidade e os tipos esperados dos parametros.
320 plist->symbol = ident->symbol;
322 ast_node_accept(plist, visitor);
323 params = plist->child_counter;
325 } else
326 params = 0;
328 if (params != ident->symbol->params) {
329 node->type = ERROR;
330 fprintf(stderr, "Error: Expecting %d parameters, received %d. "
331 "Check line %d\n",
332 ident->symbol->params, params, node->linenum);
336 void
337 typecheck_visit_callparam_list (struct _Visitor *visitor, struct AstNode *node)
339 int i;
340 struct AstNode *child;
342 node->child_counter = 0;
343 for (child = node->children; child != NULL; child = child->sibling)
344 node->child_counter++;
346 if (node->symbol->params != node->child_counter) {
347 node->type = ERROR;
348 return;
351 i = 0;
352 for (child = node->children; child != NULL; child = child->sibling) {
353 ast_node_accept(child, visitor);
355 if (child->type != ERROR &&
356 child->type != node->symbol->param_types[i]) {
357 node->type = ERROR;
358 child->type = node->symbol->param_types[i];
360 fprintf(stderr, "Error: Call '%s' on line %d, expecting %s "
361 "on parameter %d (",
362 node->symbol->name, node->linenum,
363 type_get_lexeme(node->symbol->param_types[i]),
364 i + 1);
366 if (child->children->kind == IDENTIFIER)
367 fprintf(stderr, "'%s'", child->children->symbol->name);
368 else
369 value_print(stderr, &child->value, child->type);
371 fprintf(stderr, "), received %s.\n", type_get_lexeme(child->type));
373 i++;
377 void
378 typecheck_visit_callparam (struct _Visitor *visitor, struct AstNode *node)
380 ast_node_accept(node->children, visitor);
381 node->type = node->children->type;
384 void
385 typecheck_visit_identifier_list (struct _Visitor *visitor, struct AstNode *node)
387 struct AstNode *child;
389 for (child = node->children; child != NULL; child = child->sibling) {
390 child->type = node->type;
391 child->symbol->decl_linenum = node->linenum;
392 ast_node_accept(child, visitor);
396 void
397 typecheck_visit_identifier (struct _Visitor *visitor, struct AstNode *node)
399 Symbol *sym = symbol_lookup(symtab, node->symbol->name);
400 Symbol *_sym = sym;
402 // O atributo 'decl_linenum' > 0 indica que o identificador referencia
403 // a declaracao de uma variavel/procedimento/funcao.
405 void __fetch_symbol(struct AstNode *node, Symbol *sym) {
406 symbol_table_destroy(node->symbol);
407 node->symbol = sym;
408 node->type = sym->type;
411 if (sym == NULL) {
413 // Simbolo possui linha de declaracao: Insira na tabela de simbolos.
414 if (node->symbol->decl_linenum > 0) {
415 node->symbol->type = node->type;
416 node->symbol->is_global = (symtab == global_symtab);
418 node->symbol = symbol_insert(symtab, node->symbol);
420 } else if ((sym = symbol_lookup(global_symtab, node->symbol->name))
421 != NULL) {
422 __fetch_symbol(node, sym);
424 // Sem linha de declaracao == eh fetch de variavel nao declarada.
425 } else {
426 node->symbol->type = node->type = ERROR;
427 fprintf(stderr, "Error: Undeclared symbol '%s' in line %d\n",
428 node->symbol->name, node->linenum);
431 // Simbolo encontrado na tabela e eh fetch: OK. Ou pode ser global.
432 } else if (node->symbol->decl_linenum == 0) {
433 __fetch_symbol(node, sym);
435 // Simbolo possui linha de declaracao mas foi encontrado na tabela:
436 // tentativa de redefinicao.
437 } else {
438 node->symbol->type = node->type = ERROR;
439 fprintf(stderr, "Error: Symbol '%s' already defined in line %d. "
440 "Check line %d.\n",
441 _sym->name, _sym->decl_linenum, node->linenum);
446 // Helper functions ----------------------------------------------------------
448 static void
449 _typecheck_print_stmt(struct AstNode *node, Type type, const char *ptype_str)
451 if (node->children->type != type) {
452 node->type = ERROR;
453 fprintf(stderr,
454 "Error: Expression Print%s statement must be of "
455 "%s type. Check line %d.\n",
456 ptype_str, type_get_lexeme(type), node->linenum);