void stmt_typecheck(struct stmt *s, struct type *ret, int *returned) { if(!s) return; switch(s -> kind) { struct type *expr; struct expr *curr; case STMT_DECL: decl_typecheck(s -> decl); break; case STMT_EXPR: // need to typecheck, but don't need type type_delete(expr_typecheck(s -> expr)); break; case STMT_IF_ELSE: expr = expr_typecheck(s -> expr); if(expr -> kind != TYPE_BOOLEAN) { fprintf(stderr, "TYPE_ERROR: cannot use a(n) "); type_fprint(stderr, expr); fprintf(stderr, " as the if statement expression (currently "); expr_fprint(stderr, s -> expr); fprintf(stderr, ") requires a boolean\n"); type_error_count++; } stmt_typecheck(s -> body, ret, returned); stmt_typecheck(s -> else_body, ret, returned); type_delete(expr); break; case STMT_FOR: type_delete(expr_typecheck(s -> init_expr)); expr = expr_typecheck(s -> expr); // need to check that the middle // expression is actually there if(expr && expr -> kind != TYPE_BOOLEAN) { fprintf(stderr, "TYPE_ERROR: cannot use a "); type_fprint(stderr, expr); fprintf(stderr, " as the middle expression requires a boolean (or an empty expression)\n"); type_error_count++; } type_delete(expr); type_delete(expr_typecheck(s -> next_expr)); stmt_typecheck(s -> body, ret, returned); break; case STMT_WHILE: break; case STMT_PRINT: curr = s -> expr; while(curr) { expr = expr_typecheck(curr); // pass type through new symbol if(!type_is_atomic(expr)) { fprintf(stderr, "TYPE_ERROR: cannot print (print "); expr_fprint(stderr, s -> expr); fprintf(stderr, ") a non-atomic value ("); type_fprint(stderr, expr); fprintf(stderr, ")\n"); type_error_count++; } switch(expr -> kind) { case TYPE_BOOLEAN: curr -> print_type = 1; break; case TYPE_CHARACTER: curr -> print_type = 2; break; case TYPE_INTEGER: curr -> print_type = 3; break; case TYPE_STRING: curr -> print_type = 4; break; case TYPE_ARRAY: curr -> print_type = 0; fprintf(stderr, "Bad entry into switch on type_kind in stmt_typecheck (case STMT_PRINT)\n"); exit(1); break; case TYPE_ARRAY_DECL: curr -> print_type = 0; fprintf(stderr, "Bad entry into switch on type_kind in stmt_typecheck (case STMT_PRINT)\n"); exit(1); break; case TYPE_FUNCTION: curr -> print_type = 0; fprintf(stderr, "Bad entry into switch on type_kind in stmt_typecheck (case STMT_PRINT)\n"); exit(1); break; case TYPE_VOID: curr -> print_type = 0; fprintf(stderr, "Bad entry into switch on type_kind in stmt_typecheck (case STMT_PRINT)\n"); exit(1); break; } type_delete(expr); curr = curr -> next; } break; case STMT_RET: // always set to 1 *returned = 1; expr = expr_typecheck(s -> expr); if(!s -> expr) { type_delete(expr); expr = type_create(TYPE_VOID, 0, 0, 0); } if(!type_compare(expr, ret)) { fprintf(stderr, "TYPE_ERROR: the return statement (return "); expr_fprint(stderr, s -> expr); fprintf(stderr, ") does not match the function return type ("); type_fprint(stderr, ret); fprintf(stderr, ")\n"); type_error_count++; } type_delete(expr); break; case STMT_BLOCK: stmt_typecheck(s -> body, ret, returned); break; } stmt_typecheck(s -> next, ret, returned); }
void decl_typecheck(struct decl *d){ if(!d)return; if(d->value){ if(d->type->kind!=TYPE_ARRAY){ struct type* t; t = expr_typecheck(d->value); if(d->type-> kind != t->kind){ printf("Cannot assign "); expr_print(d->value); printf(" to "); type_print(d->type); printf("\n"); get_incrementError(2); } }else { if(d->value->kind!=EXPR_ARRAY_LIST){ printf("Cannot assign "); expr_print(d->value); printf(" to array %s\n",d->name); get_incrementError(2); } else{ struct type* aux_type = d->type; int lenght = 1; if(aux_type->expression){ while(aux_type->kind == TYPE_ARRAY){ if(aux_type->expression && aux_type->expression->kind!= EXPR_INTEGER_LITERAL){ printf("Array %s must have a literal value as index\n",d->name); lenght = 99999; break; } else{ lenght*=aux_type->expression->literal_value; } aux_type = aux_type->subtype; } } else{ lenght = 99999; while(aux_type->kind == TYPE_ARRAY)aux_type = aux_type->subtype; } resolve_array_values(d->value,aux_type,d->name); if(const_expr > lenght){ get_incrementError(2); printf("Too many arguments on inicialization of array %s\n",d->name); } } } } if(d->symbol->kind == SYMBOL_GLOBAL) { const_expr = 0; expr_constant(d->value); if(const_expr>0){ get_incrementError(1); printf("Tried to assign not constant variable in the declaration of %s\n",d->name); } } if(d->code)stmt_typecheck(d->code,d->type->subtype); decl_typecheck(d->next); }
void stmt_typecheck( struct stmt *s, struct decl * current_function ) { if (!s) { return; } struct type * T = expr_typecheck(s->expr); switch (s -> kind) { case STMT_IF_ELSE: T = expr_typecheck(s->expr); if(T->kind != TYPE_BOOLEAN){ printf("type error: if condition is of type "); type_print(T); printf(" ("); expr_print(s->expr); printf("), where a boolean value is required\n"); error_count++; } stmt_typecheck(s->body,current_function); stmt_typecheck(s->else_body,current_function); break; // decl can't be a function decl if outside of global scope case STMT_DECL: if(s->decl->type->kind == TYPE_FUNCTION){ printf("type error: cannot declare a function (%s) nested in another function (%s)\n",s->decl->name,current_function->name); error_count++; } decl_typecheck(s->decl); break; case STMT_EXPR: expr_typecheck(s->expr); break; case STMT_FOR: expr_typecheck(s->init_expr); T = expr_typecheck(s->expr); if(T->kind != TYPE_BOOLEAN && T->kind != TYPE_VOID){ printf("type error: for loop conditional is of type "); type_print(T); printf(" ("); expr_print(s->expr); printf("), where a boolean value is required\n"); error_count++; } expr_typecheck(s->next_expr); stmt_typecheck(s->body,current_function); break; case STMT_PRINT: expr_typecheck(s->expr); break; // check that value being returned matches the subtype of the function it is called in (the return values must match) case STMT_RETURN: if(current_function->type->subtype->kind != expr_typecheck(s->expr)->kind){ printf("type error: cannot return "); type_print(expr_typecheck(s->expr)); printf(" in function (%s) that returns ",current_function->name); type_print(current_function->type->subtype); printf("\n"); error_count++; } break; case STMT_BLOCK: stmt_typecheck(s->body,current_function); break; case STMT_EMPTY: // do nothing break; } stmt_typecheck(s->next,current_function); }