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
->is_parameter
= TRUE
;
149 node
->children
->symbol
->decl_linenum
= node
->linenum
;
150 ast_node_accept(node
->children
, visitor
);
154 typecheck_visit_statement_list(struct _Visitor
*visitor
, struct AstNode
*node
)
156 ast_node_accept_children(node
->children
, visitor
);
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");
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");
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");
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
))) {
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
) {
202 "Error: Incompatible types on assignment "
203 "operation in line %d.\n", node
->linenum
);
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
) {
219 "Error: Condition for if statement must be of Boolean type. "
220 "Check line %d.\n", node
->linenum
);
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
) {
236 "Error: Expression in While statement must be of "
237 "Boolean type. Check line %d.\n", expr
->linenum
);
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
) {
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
) {
263 "Error: Value of stop condition is not of Integer type. "
264 "Check line %d.\n", expr
->linenum
);
267 ast_node_accept(stmt
, visitor
);
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
) {
285 "Error: Operation '%s' over incompatible types on line %d.\n",
286 op
->name
, op
->linenum
);
291 typecheck_visit_notfactor (struct _Visitor
*visitor
, struct AstNode
*node
)
293 ast_node_accept(node
->children
, visitor
);
295 if (node
->children
->type
!= BOOLEAN
) {
298 "Error: Operation 'not' over non-boolean "
299 "operand on line %d.\n", node
->linenum
);
304 typecheck_visit_call (struct _Visitor
*visitor
, struct AstNode
*node
)
307 struct AstNode
*ident
= node
->children
;
308 struct AstNode
*plist
= ident
->sibling
;
310 ast_node_accept(ident
, visitor
);
312 if (ident
->type
== ERROR
)
315 node
->type
= ident
->symbol
->type
;
318 plist
->symbol
= ident
->symbol
;
319 ast_node_accept(plist
, visitor
);
320 params
= plist
->child_counter
;
325 if (params
!= ident
->symbol
->params
) {
327 fprintf(stderr
, "Error: Expecting %d parameters, received %d. "
329 ident
->symbol
->params
, params
, node
->linenum
);
334 typecheck_visit_callparam_list (struct _Visitor
*visitor
, struct AstNode
*node
)
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
) {
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
]) {
355 child
->type
= node
->symbol
->param_types
[i
];
357 fprintf(stderr
, "Error: Call '%s' on line %d, expecting %s "
359 node
->symbol
->name
, node
->linenum
,
360 type_get_lexeme(node
->symbol
->param_types
[i
]),
363 if (child
->children
->kind
== IDENTIFIER
)
364 fprintf(stderr
, "'%s'", child
->children
->symbol
->name
);
366 value_print(stderr
, &child
->value
, child
->type
);
368 fprintf(stderr
, "), received %s.\n", type_get_lexeme(child
->type
));
375 typecheck_visit_callparam (struct _Visitor
*visitor
, struct AstNode
*node
)
377 ast_node_accept(node
->children
, visitor
);
378 node
->type
= node
->children
->type
;
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
);
394 typecheck_visit_identifier (struct _Visitor
*visitor
, struct AstNode
*node
)
396 Symbol
*sym
= symbol_lookup(symtab
, node
->symbol
->name
);
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
);
405 node
->type
= sym
->type
;
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
))
419 __fetch_symbol(node
, sym
);
421 // Sem linha de declaracao == eh fetch de variavel nao declarada.
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.
435 node
->symbol
->type
= node
->type
= ERROR
;
436 fprintf(stderr
, "Error: Symbol '%s' already defined in line %d. "
438 _sym
->name
, _sym
->decl_linenum
, node
->linenum
);
443 // Helper functions ----------------------------------------------------------
446 _typecheck_print_stmt(struct AstNode
*node
, Type type
, const char *ptype_str
)
448 if (node
->children
->type
!= type
) {
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
);