Mais um atributo redundante removido: is_parameter de Symbol.
[toypasc.git] / typecheck_visitor.c
blobaad4b3a667da907edae3a37ce5da1fcb501bcc10
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->decl_linenum = node->linenum;
149 ast_node_accept(node->children, visitor);
152 void
153 typecheck_visit_statement_list(struct _Visitor *visitor, struct AstNode *node)
155 ast_node_accept_children(node->children, visitor);
158 void
159 typecheck_visit_printint_stmt (struct _Visitor *visitor, struct AstNode *node)
161 ast_node_accept(node->children, visitor);
162 _typecheck_print_stmt(node, INTEGER, "Int");
165 void
166 typecheck_visit_printchar_stmt (struct _Visitor *visitor, struct AstNode *node)
168 ast_node_accept(node->children, visitor);
169 _typecheck_print_stmt(node, CHAR, "Char");
172 void
173 typecheck_visit_printbool_stmt (struct _Visitor *visitor, struct AstNode *node)
175 ast_node_accept(node->children, visitor);
176 _typecheck_print_stmt(node, BOOLEAN, "Bool");
179 void
180 typecheck_visit_assignment_stmt (struct _Visitor *visitor, struct AstNode *node)
182 struct AstNode *lnode = node->children;
183 struct AstNode *rnode = lnode->sibling;
185 ast_node_accept(lnode, visitor);
186 ast_node_accept(rnode, visitor);
188 if (symbol_is_procfunc(lnode->symbol) && (_inside_procfunc == NULL ||
189 strcmp(_inside_procfunc->children->symbol->name,
190 lnode->symbol->name))) {
191 node->type = ERROR;
192 fprintf(stderr,
193 "Error: Symbol '%s' is a function identifier, you cannot "
194 "assign a value to it from outside the said function. "
195 "Check line %d.\n", lnode->symbol->name, node->linenum);
197 } else if (lnode->type != ERROR && rnode->type != ERROR &&
198 lnode->type != rnode->type) {
199 node->type = ERROR;
200 fprintf(stderr,
201 "Error: Incompatible types on assignment "
202 "operation in line %d.\n", node->linenum);
206 void
207 typecheck_visit_if_stmt (struct _Visitor *visitor, struct AstNode *node)
209 struct AstNode *expr = node->children;
210 struct AstNode *stmt = expr->sibling;
212 ast_node_accept(expr, visitor);
213 ast_node_accept(stmt, visitor);
215 if (expr->type != BOOLEAN) {
216 node->type = ERROR;
217 fprintf(stderr,
218 "Error: Condition for if statement must be of Boolean type. "
219 "Check line %d.\n", node->linenum);
223 void
224 typecheck_visit_while_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: Expression in While statement must be of "
236 "Boolean type. Check line %d.\n", expr->linenum);
240 void
241 typecheck_visit_for_stmt (struct _Visitor *visitor, struct AstNode *node)
243 struct AstNode *asgn = node->children;
244 struct AstNode *expr = asgn->sibling;
245 struct AstNode *stmt = expr->sibling;
246 struct AstNode *id_node = asgn->children;
248 ast_node_accept(asgn, visitor);
249 ast_node_accept(expr, visitor);
251 if (id_node->type != INTEGER) {
252 node->type = ERROR;
253 fprintf(stderr,
254 "Error: Identifier '%s' is of %s type; it must be Integer. "
255 "Check line %d.\n", id_node->symbol->name,
256 type_get_lexeme(id_node->type), id_node->linenum);
259 if (expr->type != INTEGER) {
260 node->type = ERROR;
261 fprintf(stderr,
262 "Error: Value of stop condition is not of Integer type. "
263 "Check line %d.\n", expr->linenum);
266 ast_node_accept(stmt, visitor);
270 void
271 typecheck_visit_binary_expr (struct _Visitor *visitor, struct AstNode *node)
273 struct AstNode *lnode = node->children;
274 struct AstNode *op = lnode->sibling;
275 struct AstNode *rnode = op->sibling;
277 ast_node_accept(lnode, visitor);
278 ast_node_accept(rnode, visitor);
280 if (lnode->type != ERROR && rnode->type != ERROR &&
281 lnode->type != rnode->type) {
282 node->type = ERROR;
283 fprintf(stderr,
284 "Error: Operation '%s' over incompatible types on line %d.\n",
285 op->name, op->linenum);
289 void
290 typecheck_visit_notfactor (struct _Visitor *visitor, struct AstNode *node)
292 ast_node_accept(node->children, visitor);
294 if (node->children->type != BOOLEAN) {
295 node->type = ERROR;
296 fprintf(stderr,
297 "Error: Operation 'not' over non-boolean "
298 "operand on line %d.\n", node->linenum);
302 void
303 typecheck_visit_call (struct _Visitor *visitor, struct AstNode *node)
305 int params;
306 struct AstNode *ident = node->children;
307 struct AstNode *plist = ident->sibling;
309 ast_node_accept(ident, visitor);
311 if (ident->type == ERROR)
312 return;
314 node->type = ident->symbol->type;
316 if (plist != NULL) {
317 // CallParamLists apontam para o simbolo da funcao chamada
318 // para obter a quantidade e os tipos esperados dos parametros.
319 plist->symbol = ident->symbol;
321 ast_node_accept(plist, visitor);
322 params = plist->child_counter;
324 } else
325 params = 0;
327 if (params != ident->symbol->params) {
328 node->type = ERROR;
329 fprintf(stderr, "Error: Expecting %d parameters, received %d. "
330 "Check line %d\n",
331 ident->symbol->params, params, node->linenum);
335 void
336 typecheck_visit_callparam_list (struct _Visitor *visitor, struct AstNode *node)
338 int i;
339 struct AstNode *child;
341 node->child_counter = 0;
342 for (child = node->children; child != NULL; child = child->sibling)
343 node->child_counter++;
345 if (node->symbol->params != node->child_counter) {
346 node->type = ERROR;
347 return;
350 i = 0;
351 for (child = node->children; child != NULL; child = child->sibling) {
352 ast_node_accept(child, visitor);
354 if (child->type != ERROR &&
355 child->type != node->symbol->param_types[i]) {
356 node->type = ERROR;
357 child->type = node->symbol->param_types[i];
359 fprintf(stderr, "Error: Call '%s' on line %d, expecting %s "
360 "on parameter %d (",
361 node->symbol->name, node->linenum,
362 type_get_lexeme(node->symbol->param_types[i]),
363 i + 1);
365 if (child->children->kind == IDENTIFIER)
366 fprintf(stderr, "'%s'", child->children->symbol->name);
367 else
368 value_print(stderr, &child->value, child->type);
370 fprintf(stderr, "), received %s.\n", type_get_lexeme(child->type));
372 i++;
376 void
377 typecheck_visit_callparam (struct _Visitor *visitor, struct AstNode *node)
379 ast_node_accept(node->children, visitor);
380 node->type = node->children->type;
383 void
384 typecheck_visit_identifier_list (struct _Visitor *visitor, struct AstNode *node)
386 struct AstNode *child;
388 for (child = node->children; child != NULL; child = child->sibling) {
389 child->type = node->type;
390 child->symbol->decl_linenum = node->linenum;
391 ast_node_accept(child, visitor);
395 void
396 typecheck_visit_identifier (struct _Visitor *visitor, struct AstNode *node)
398 Symbol *sym = symbol_lookup(symtab, node->symbol->name);
399 Symbol *_sym = sym;
401 // O atributo 'decl_linenum' > 0 indica que o identificador referencia
402 // a declaracao de uma variavel/procedimento/funcao.
404 void __fetch_symbol(struct AstNode *node, Symbol *sym) {
405 symbol_table_destroy(node->symbol);
406 node->symbol = sym;
407 node->type = sym->type;
410 if (sym == NULL) {
412 // Simbolo possui linha de declaracao: Insira na tabela de simbolos.
413 if (node->symbol->decl_linenum > 0) {
414 node->symbol->type = node->type;
415 node->symbol->is_global = (symtab == global_symtab);
417 node->symbol = symbol_insert(symtab, node->symbol);
419 } else if ((sym = symbol_lookup(global_symtab, node->symbol->name))
420 != NULL) {
421 __fetch_symbol(node, sym);
423 // Sem linha de declaracao == eh fetch de variavel nao declarada.
424 } else {
425 node->symbol->type = node->type = ERROR;
426 fprintf(stderr, "Error: Undeclared symbol '%s' in line %d\n",
427 node->symbol->name, node->linenum);
430 // Simbolo encontrado na tabela e eh fetch: OK. Ou pode ser global.
431 } else if (node->symbol->decl_linenum == 0) {
432 __fetch_symbol(node, sym);
434 // Simbolo possui linha de declaracao mas foi encontrado na tabela:
435 // tentativa de redefinicao.
436 } else {
437 node->symbol->type = node->type = ERROR;
438 fprintf(stderr, "Error: Symbol '%s' already defined in line %d. "
439 "Check line %d.\n",
440 _sym->name, _sym->decl_linenum, node->linenum);
445 // Helper functions ----------------------------------------------------------
447 static void
448 _typecheck_print_stmt(struct AstNode *node, Type type, const char *ptype_str)
450 if (node->children->type != type) {
451 node->type = ERROR;
452 fprintf(stderr,
453 "Error: Expression Print%s statement must be of "
454 "%s type. Check line %d.\n",
455 ptype_str, type_get_lexeme(type), node->linenum);