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
);
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
;
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
);
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
);
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
;
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
);
88 typecheck_visit_vardecl (struct _Visitor
*visitor
, struct AstNode
*node
)
90 node
->children
->type
= node
->type
;
91 ast_node_accept(node
->children
, visitor
);
95 typecheck_visit_procfunc (struct _Visitor
*visitor
, struct AstNode
*node
)
97 struct AstNode
*ident
;
98 struct AstNode
*child
;
100 _inside_procfunc
= node
;
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
);
124 typecheck_visit_param_list(struct _Visitor
*visitor
, struct AstNode
*node
)
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
);
138 for (child
= node
->children
; child
!= NULL
; child
= child
->sibling
) {
139 node
->symbol
->param_types
[i
] = child
->type
;
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
);
153 typecheck_visit_statement_list(struct _Visitor
*visitor
, struct AstNode
*node
)
155 ast_node_accept_children(node
->children
, visitor
);
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");
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");
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");
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
))) {
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
) {
201 "Error: Incompatible types on assignment "
202 "operation in line %d.\n", node
->linenum
);
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
) {
218 "Error: Condition for if statement must be of Boolean type. "
219 "Check line %d.\n", node
->linenum
);
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
) {
235 "Error: Expression in While statement must be of "
236 "Boolean type. Check line %d.\n", expr
->linenum
);
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
) {
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
) {
262 "Error: Value of stop condition is not of Integer type. "
263 "Check line %d.\n", expr
->linenum
);
266 ast_node_accept(stmt
, visitor
);
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
) {
284 "Error: Operation '%s' over incompatible types on line %d.\n",
285 op
->name
, op
->linenum
);
290 typecheck_visit_notfactor (struct _Visitor
*visitor
, struct AstNode
*node
)
292 ast_node_accept(node
->children
, visitor
);
294 if (node
->children
->type
!= BOOLEAN
) {
297 "Error: Operation 'not' over non-boolean "
298 "operand on line %d.\n", node
->linenum
);
303 typecheck_visit_call (struct _Visitor
*visitor
, struct AstNode
*node
)
306 struct AstNode
*ident
= node
->children
;
307 struct AstNode
*plist
= ident
->sibling
;
309 ast_node_accept(ident
, visitor
);
311 if (ident
->type
== ERROR
)
314 node
->type
= ident
->symbol
->type
;
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
;
327 if (params
!= ident
->symbol
->params
) {
329 fprintf(stderr
, "Error: Expecting %d parameters, received %d. "
331 ident
->symbol
->params
, params
, node
->linenum
);
336 typecheck_visit_callparam_list (struct _Visitor
*visitor
, struct AstNode
*node
)
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
) {
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
]) {
357 child
->type
= node
->symbol
->param_types
[i
];
359 fprintf(stderr
, "Error: Call '%s' on line %d, expecting %s "
361 node
->symbol
->name
, node
->linenum
,
362 type_get_lexeme(node
->symbol
->param_types
[i
]),
365 if (child
->children
->kind
== IDENTIFIER
)
366 fprintf(stderr
, "'%s'", child
->children
->symbol
->name
);
368 value_print(stderr
, &child
->value
, child
->type
);
370 fprintf(stderr
, "), received %s.\n", type_get_lexeme(child
->type
));
377 typecheck_visit_callparam (struct _Visitor
*visitor
, struct AstNode
*node
)
379 ast_node_accept(node
->children
, visitor
);
380 node
->type
= node
->children
->type
;
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
);
396 typecheck_visit_identifier (struct _Visitor
*visitor
, struct AstNode
*node
)
398 Symbol
*sym
= symbol_lookup(symtab
, node
->symbol
->name
);
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
);
407 node
->type
= sym
->type
;
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
))
421 __fetch_symbol(node
, sym
);
423 // Sem linha de declaracao == eh fetch de variavel nao declarada.
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.
437 node
->symbol
->type
= node
->type
= ERROR
;
438 fprintf(stderr
, "Error: Symbol '%s' already defined in line %d. "
440 _sym
->name
, _sym
->decl_linenum
, node
->linenum
);
445 // Helper functions ----------------------------------------------------------
448 _typecheck_print_stmt(struct AstNode
*node
, Type type
, const char *ptype_str
)
450 if (node
->children
->type
!= type
) {
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
);