void expr_typecheck_array(struct type *array_type, struct expr *e_list) { if (!e_list) return; struct type *t; if (e_list->kind == EXPR_LIST) t = expr_typecheck(e_list->left); else if (e_list->kind == EXPR_LIST_OUTER) t = expr_typecheck(e_list->right); if (!type_compare(t, array_type)) { printf("type error: line %d: ", e_list->line); printf("expression type "); type_print(t); printf(" ("); expr_print(e_list->right); printf(")"); printf(" found in assignment to array of type "); type_print(array_type); printf("\n"); error_count++; } expr_typecheck_array(array_type, e_list->right); }
void decl_typecheck( struct decl *d ) { if (!d) return; if (d->value) { struct type *T = expr_typecheck( d-> value ); if (!type_compare(d->type, T)) { printf("type error: cannot initialize variable (%s) of type ", d->name); type_print(d->type); printf(" and assign it a "); type_print( T ); printf("\n"); } } if (d->type->kind == TYPE_ARRAY) { // for array decl_array_typecheck(d->type, d->name); } else if (d->type->kind == TYPE_FUNCTION) { // for function return decl_array_typecheck(d->type->subtype, d->name); } if (d->code) { decl_func_sym = scope_lookup(d->name); stmt_typecheck(d->code); } if (d->next) decl_typecheck(d->next); }
// make sure declared array type has a correct size initialization void decl_array_typecheck( struct type *t, char *name ) { if (!t ) return; if (t->kind == TYPE_ARRAY) { if (!t->num_subtype) { decl_has_error = 1; printf("type error: array(%s) declaration must have a size value\n", name); } else if (expr_typecheck(t->num_subtype)->kind != TYPE_INTEGER) { decl_has_error = 1; printf("type error: array(%s) size must have integer type\n", name ); } } decl_array_typecheck(t->subtype, name); }
//checks if a function call matches up to the function types void function_typecheck(const char *function_name, struct expr *e, struct param_list *p, int param, int func_params) { if(!e && !p) return; //only for no parameters if(!e) { printf("type error: In call to function %s, expected %d parameters, but received %d\n", function_name, param, func_params); error_count++; return; } if(!p) { struct expr *e1; if(e->kind == EXPR_COMMA) e1 = e->left; else e1 = e; struct type *t = expr_typecheck(e1); printf("type error: In call to function %s, expected %d parameters, but received %d\n", function_name, param, func_params); error_count++; return; } int last_expr = 0, last_param = 0; if(e->kind != EXPR_COMMA) last_expr = 1; if(!p->next) last_param = 1; struct type *t = expr_typecheck(e->left); if(e->kind == EXPR_COMMA){ if(!type_compare(t, p->type)){ printf("type error: In call to function %s, expected parameter %d to be of type ", function_name, param); type_print(p->type); printf(". Instead, expression "); expr_print(e->left); printf(" of type "); type_print(t); printf(" was passed to parameter %d\n", param); error_count++; } } if(last_expr && last_param) return; function_typecheck(function_name, e->right, p->next, ++param, func_params); }
void resolve_array_values(struct expr *e,struct type *t,const char *name) { if(!e)return; if(e->kind == EXPR_EXPR_LIST || e->kind == EXPR_ARRAY_LIST ){resolve_array_values(e->left,t,name); resolve_array_values(e->right,t,name);} else{ const_expr++; struct type *aux2 = expr_typecheck(e); if(aux2->kind != t->kind){ get_incrementError(2); printf("Passing wrong argument to array %s: Passing int the array expression list ",name); type_print(aux2); printf(" "); expr_print(e); printf("\n"); } } }
void param_list_typecheck( struct expr * e, struct param_list *params, char *func_name) { while (e && params) { struct type *T = expr_typecheck(e); if (!type_compare(T, params->type)) { decl_has_error = 1; printf("type error: cannot pass variable of type "); type_print(T); printf(" to function %s\n", func_name); } e = e->next; params = params->next; } if (e) { decl_has_error = 1; printf("type error: pass more variables to functions call %s than needed\n", func_name); } if (params) { decl_has_error = 1; printf("type error: not enough variables to function call %s\n", func_name); } }
void param_list_typecheck(struct param_list *p, struct expr *e, const char * const name) { // this is invoked for each function invocation // we compare each item in the param list with the given expression list struct param_list *p_ptr = p; struct expr *e_ptr = e; while (p_ptr && e_ptr) { // comparing each pair struct type *expected_type = p_ptr->type; struct type *received_type = expr_typecheck(e_ptr); if (!type_is_equal(expected_type, received_type)) { // error ++error_count_type; printf("type error: function `%s` parameter %d type mismatch; expected ", name, p_ptr->symbol->which); type_print(expected_type); printf(", received "); type_print(received_type); printf("\n"); } TYPE_FREE(received_type); // move on p_ptr = p_ptr->next; e_ptr = e_ptr->next; } // ensure lengths are the same if (p_ptr != NULL || e_ptr != NULL) { ++error_count_type; printf("type error: function `%s` expected %u parameters, received %u arguments\n", name, param_list_length(p), expr_list_length(e)); } }
struct type *expr_typecheck(struct expr *e) { if(!e) return type_create(TYPE_VOID, 0, 0, 0); struct param_list *param_ptr; struct expr *expr_ptr; struct type *left; struct type *right; switch(e->kind) { case EXPR_LIST: left = expr_typecheck(e->left); right = expr_typecheck(e->right); return type_create(TYPE_VOID, 0, 0, 0); break; case EXPR_ASSIGNMENT: left = expr_typecheck(e->left); right = expr_typecheck(e->right); while(left->kind == TYPE_ARRAY) left = left->subtype; while(right->kind == TYPE_ARRAY) left = left->subtype; if(type_equal(left, right) && left->kind != TYPE_FUNCTION) { return type_copy(left); } else { printf("Cannot assign "); type_print(right); printf(" to "); type_print(left); if(e->left->name) { printf(" %s\n", e->left->name); } else { printf("\n"); } type_check_errors++; return left; } break; case EXPR_NOT_EQUALS: case EXPR_EQUALS: left = expr_typecheck(e->left); right = expr_typecheck(e->right); if(type_equal(left, right) && left->kind != TYPE_FUNCTION && left->kind != TYPE_ARRAY) { return type_create(TYPE_BOOLEAN, 0, 0, 0); } else { printf("Cannot perform logical equals operation on "); type_print(left); printf(" and "); type_print(right); printf("\n"); type_check_errors++; return type_create(TYPE_BOOLEAN, 0, 0, 0); } break; case EXPR_LT: case EXPR_GT: case EXPR_LE: case EXPR_GE: left = expr_typecheck(e->left); right = expr_typecheck(e->right); if(left->kind == TYPE_INTEGER && right->kind == TYPE_INTEGER) { return type_create(TYPE_BOOLEAN, 0, 0, 0); } else { printf("Cannot perform boolean operations on "); type_print(left); printf(" and "); type_print(right); printf("\n"); type_check_errors++; return type_create(TYPE_BOOLEAN, 0, 0, 0); } break; case EXPR_ADD: case EXPR_MINUS: case EXPR_TIMES: case EXPR_DIVIDES: case EXPR_MOD: case EXPR_POWER: left = expr_typecheck(e->left); right = expr_typecheck(e->right); if(left->kind == TYPE_INTEGER && right->kind == TYPE_INTEGER) { return type_create(TYPE_INTEGER, 0, 0, 0); } else { printf("Cannot perform arithmetic operations on "); type_print(left); printf(" and "); type_print(right); printf("\n"); type_check_errors++; return type_create(TYPE_INTEGER, 0, 0, 0); } break; case EXPR_NEGATIVE: right = expr_typecheck(e->right); if(right->kind == TYPE_INTEGER) { return type_create(TYPE_INTEGER, 0, 0, 0); } else { printf("Cannot take the negative of "); type_print(right); printf("\n"); type_check_errors++; return type_create(TYPE_INTEGER, 0, 0, 0); } break; case EXPR_OR: case EXPR_AND: left = expr_typecheck(e->left); right = expr_typecheck(e->right); if(left->kind == TYPE_BOOLEAN && right->kind == TYPE_BOOLEAN) { return type_create(TYPE_BOOLEAN, 0, 0, 0); } else { printf("Cannot perform logical operations on "); type_print(left); printf(" and "); type_print(right); printf("\n"); type_check_errors++; return type_create(TYPE_BOOLEAN, 0, 0, 0); } break; case EXPR_NOT: right = expr_typecheck(e->right); if(right->kind == TYPE_BOOLEAN) { return type_create(TYPE_BOOLEAN, 0, 0, 0); } else { printf("Cannot perform a logical not on "); type_print(right); printf("\n"); type_check_errors++; return type_create(TYPE_BOOLEAN, 0, 0, 0); } break; case EXPR_PRE_INCREMENT: case EXPR_PRE_DECREMENT: right = expr_typecheck(e->right); if(right->kind == TYPE_INTEGER) { return type_create(TYPE_INTEGER, 0, 0, 0); } else { printf("Cannot perform integer operations on "); type_print(right); printf("\n"); type_check_errors++; return type_create(TYPE_INTEGER, 0, 0, 0); } break; case EXPR_POST_INCREMENT: case EXPR_POST_DECREMENT: left = expr_typecheck(e->left); if(left->kind == TYPE_INTEGER) { return type_create(TYPE_INTEGER, 0, 0, 0); } else { printf("Cannot perform integer operations on "); type_print(left); printf("\n"); type_check_errors++; return type_create(TYPE_INTEGER, 0, 0, 0); } break; case EXPR_FUNCTION: param_ptr = e->left->symbol->type->params; expr_ptr = e->right; while(param_ptr) { if(!expr_ptr) { printf("Not enough arguments given for function %s\n", e->left->name); type_check_errors++; break; } if(!type_equal(param_ptr->type, expr_typecheck(expr_ptr->left))) { printf("Function %s requires a paramater of type ", e->left->name); type_print(param_ptr->type); printf(" but "); expr_print(expr_ptr->left); printf(" is of type "); type_print(expr_typecheck(expr_ptr->left)); printf("\n"); type_check_errors++; break; } param_ptr = param_ptr->next; expr_ptr = expr_ptr->right; } if(expr_ptr) { printf("Too many arguments given for function %s\n", e->left->name); type_check_errors++; } return e->left->symbol->type->subtype; break; case EXPR_BOOLEAN: return type_create(TYPE_BOOLEAN, 0, 0, 0); break; case EXPR_INT: return type_create(TYPE_INTEGER, 0, 0, 0); break; case EXPR_CHAR: return type_create(TYPE_CHARACTER, 0, 0, 0); break; case EXPR_STRING: return type_create(TYPE_STRING, 0, 0, 0); break; case EXPR_NAME: if (e->symbol) return e->symbol->type; return type_create(TYPE_VOID, 0, 0, 0); break; case EXPR_ARRAY: left = expr_typecheck(e->left); right = expr_typecheck(e->right); if(right->kind == TYPE_INTEGER) { return type_create(left->subtype->kind, 0, 0, 0); } else { printf("Cannot use "); type_print(right); printf(" as an array index. Must use an integer\n"); type_check_errors++; return type_create(left->subtype->kind, 0, 0, 0); } break; case EXPR_ARRAY_LITERAL: left = expr_typecheck(e->right->left); return type_create(TYPE_ARRAY, 0, 0, left->subtype); break; } return type_create(TYPE_VOID, 0, 0, 0); }
struct type * expr_typecheck( struct expr *e ) { if (!e) return type_create(TYPE_VOID, 0, 0); struct type *L; struct type *R; switch (e->kind) { case EXPR_INT_VAL: return type_create(TYPE_INTEGER, 0, 0); case EXPR_NAME: return type_copy(e->symbol->type); case EXPR_STRING_VAL: return type_create(TYPE_STRING, 0, 0); case EXPR_CHAR_VAL: return type_create(TYPE_CHARACTER, 0, 0); case EXPR_BOOLEAN_VAL: return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_ARRAY_VAL: { struct expr *vals = e->right; struct type *subtype = 0; int num_subtype = 0; while (vals) { struct type *cur_t = expr_typecheck(vals); if (!subtype) { subtype = cur_t; } if (!type_compare(subtype, cur_t)) { decl_has_error = 1; printf("type error: array of element type "); type_print(subtype); printf(" cannot have expression of type "); type_print(cur_t); printf("\n"); } num_subtype++; vals = vals->next; } struct type *t = type_create(TYPE_ARRAY, 0, subtype); t->num_subtype = expr_create_integer_literal(num_subtype); return t; } //return type_copy(e->symbol->type); case EXPR_ARRAY_SUB: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (R->kind != TYPE_INTEGER) { decl_has_error = 1; printf("type error: cannot use "); type_print(R); printf(" as index to an array\n"); } if (L->kind != TYPE_ARRAY) { decl_has_error = 1; printf("type error: access an "); type_print(R); printf(" as an array\n"); } return type_copy(L->subtype); case EXPR_FUNCTION_VAL: // need to check function params!!!!! param_list_typecheck(e->right, e->symbol->params, e->name); return type_copy(e->symbol->type->subtype); case EXPR_ADD: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) { decl_has_error = 1; printf("type error: cannot add "); type_print(L); printf(" to a "); type_print(R); printf("\n"); } return type_create(TYPE_INTEGER, 0, 0); case EXPR_SUB: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if ( !(L->kind == TYPE_INTEGER && L->kind == TYPE_INTEGER) || R->kind != TYPE_INTEGER) { decl_has_error = 1; printf("type error: cannot subtract "); type_print(L); printf(" to a "); type_print(R); printf("\n"); } return type_create(TYPE_INTEGER, 0, 0); case EXPR_MUL: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) { decl_has_error = 1; printf("type error: cannot multiply "); type_print(L); printf(" to a "); type_print(R); printf("\n"); } return type_create(TYPE_INTEGER, 0, 0); case EXPR_DIV: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) { decl_has_error = 1; printf("type error: cannot divide "); type_print(L); printf(" to a "); type_print(R); printf("\n"); } return type_create(TYPE_INTEGER, 0, 0); case EXPR_MODULO: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) { decl_has_error = 1; printf("type error: cannot module "); type_print(L); printf(" to a "); type_print(R); printf("\n"); } return type_create(TYPE_INTEGER, 0, 0); case EXPR_EXPO: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) { decl_has_error = 1; printf("type error: cannot expo "); type_print(L); printf(" to a "); type_print(R); printf("\n"); } return type_create(TYPE_INTEGER, 0, 0); case EXPR_POST_DECREASE: L = expr_typecheck(e->left); if (L->kind != TYPE_INTEGER ) { decl_has_error = 1; printf("type error: cannot decrease a "); type_print(L); printf("\n"); } return type_create(TYPE_INTEGER, 0, 0); case EXPR_POST_INCREASE: L = expr_typecheck(e->left); if (L->kind != TYPE_INTEGER ) { decl_has_error = 1; printf("type error: cannot add a "); type_print(L); printf("\n"); } return type_create(TYPE_INTEGER, 0, 0); case EXPR_GE: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) { decl_has_error = 1; printf("type error: cannot make greater equal than compare "); type_print(L); printf(" with a "); type_print(R); printf("\n"); } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_LE: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) { decl_has_error = 1; printf("type error: cannot make less equal compare "); type_print(L); printf(" with a "); type_print(R); printf("\n"); } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_GT: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) { decl_has_error = 1; printf("type error: cannot make greater than compare "); type_print(L); printf(" with a "); type_print(R); printf("\n"); } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_LT: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) { decl_has_error = 1; printf("type error: cannot make less than compare "); type_print(L); printf(" with a "); type_print(R); printf("\n"); } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_AND: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (L->kind != TYPE_BOOLEAN || R->kind != TYPE_BOOLEAN) { decl_has_error = 1; printf("type error: cannot and "); type_print(L); printf(" with a "); type_print(R); printf("\n"); } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_NOT: R = expr_typecheck(e->right); if (R->kind != TYPE_BOOLEAN) { decl_has_error = 1; printf("type error: cannot not a "); type_print(R); printf("\n"); } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_OR: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (L->kind != TYPE_BOOLEAN || R->kind != TYPE_BOOLEAN) { decl_has_error = 1; printf("type error: cannot or "); type_print(L); printf(" with a "); type_print(R); printf("\n"); } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_EQ: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (L->kind == TYPE_FUNCTION || R->kind == TYPE_FUNCTION || L->kind == TYPE_ARRAY || R->kind == TYPE_ARRAY) { decl_has_error = 1; printf("type error: cannot compare equality "); type_print(L); printf(" with a "); type_print(R); printf("\n"); } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_NEQ: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (L->kind == TYPE_FUNCTION || R->kind == TYPE_FUNCTION || L->kind == TYPE_ARRAY || R->kind == TYPE_ARRAY) { decl_has_error = 1; printf("type error: cannot compare non equality "); type_print(L); printf(" with a "); type_print(R); printf("\n"); } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_ASSIGN: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (L->kind == TYPE_FUNCTION || R->kind == TYPE_FUNCTION) { decl_has_error = 1; printf("type error: cannot assign "); type_print(R); printf(" to a "); type_print(L); printf("\n"); } if (!type_compare(L, R)) { decl_has_error = 1; printf("type error: cannot assign "); type_print(R); printf(" to a "); type_print(L); printf("\n"); } return type_copy(R); } }
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 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 compare(struct expr *e, FILE *file) { expr_codegen(e->left, file); expr_codegen(e->right, file); e->reg = register_alloc(); if(expr_typecheck(e->left)->kind==TYPE_STRING && expr_typecheck(e->right)->kind==TYPE_STRING){ fprintf(file, "\n\t#String comparison\n"); const char *left; const char *right; //get the correct string for left if(e->left->kind==EXPR_STRING_LITERAL) left = e->left->string_literal; else if(e->left->kind==EXPR_IDENT) left = e->left->symbol->string_literal; //get the correct string for right if(e->right->kind==EXPR_STRING_LITERAL) right = e->right->string_literal; else if(e->right->kind==EXPR_IDENT) right = e->right->symbol->string_literal; //compare the strings int result = strcmp(left, right); if(e->kind == EXPR_EQ){ if(result){ fprintf(file, "\tMOV $0, %s\n", register_name(e->reg)); } else { fprintf(file, "\tMOV $1, %s\n", register_name(e->reg)); } } else if(e->kind == EXPR_NE){ if(result){ fprintf(file, "\tMOV $1, %s\n", register_name(e->reg)); } else { fprintf(file, "\tMOV $0, %s\n", register_name(e->reg)); } } } else { fprintf(file, "\n\t#Comparison\n"); fprintf(file, "\tCMP %s, %s\n", register_name(e->right->reg), register_name(e->left->reg)); register_free(e->left->reg); register_free(e->right->reg); char *jump = malloc(4); switch(e->kind){ case EXPR_GE: strcpy(jump, "JGE"); break; case EXPR_LE: strcpy(jump, "JLE"); break; case EXPR_GT: strcpy(jump, "JG"); break; case EXPR_LT: strcpy(jump, "JL"); break; case EXPR_EQ: strcpy(jump, "JE"); break; case EXPR_NE: strcpy(jump, "JNE"); break; } int label_true = label_count++; int label_false = label_count++; fprintf(file, "\t%s L%d\n", jump, label_true); fprintf(file, "\tMOV $0, %s\n", register_name(e->reg)); fprintf(file, "\tJMP L%d\n", label_false); fprintf(file, "L%d:\n", label_true); fprintf(file, "\tMOV $1, %s\n", register_name(e->reg)); fprintf(file, "L%d:\n", label_false); free(jump); } }
struct type * expr_typecheck(struct expr *e) { if(!e) return type_create(TYPE_VOID, 0, 0, 0); struct type *L = expr_typecheck(e->left); struct type *R = expr_typecheck(e->right); switch(e->kind) { case EXPR_ASSIGNMENT: if(L->kind == TYPE_FUNCTION){ printf("type error: cannot use assignment operator on function "); expr_print(e->left); error_count++; } if(R->kind == TYPE_FUNCTION){ printf("type error: cannot use assignment operator on function "); expr_print(e->right); error_count++; } if(!type_compare(L, R)){ printf("type error: cannot assign "); type_print(R); printf(" "); expr_print(e->right); printf(" to "); type_print(L); printf(" "); expr_print(e->left); printf("\n"); error_count++; } return L; break; case EXPR_GE: if(L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER){ printf("type error: cannot use operator >= to compare "); type_print(L); printf(" "); expr_print(e->left); printf(" and "); type_print(R); printf(" "); expr_print(e->right); printf(". This operator can only be used on two integers.\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0, 0); break; case EXPR_LE: if(L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER){ printf("type error: cannot use operator <= to compare "); type_print(L); expr_print(e->left); printf(" and "); type_print(R); expr_print(e->right); printf(". This operator can only be used on two integers.\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0, 0); break; case EXPR_GT: if(L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER){ printf("type error: cannot use operator > to compare "); type_print(L); printf(" "); expr_print(e->left); printf(" and "); type_print(R); printf(" "); expr_print(e->right); printf(". This operator can only be used on two integers.\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0, 0); break; case EXPR_LT: if(L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER){ printf("type error: cannot use operator < to compare "); type_print(L); printf(" "); expr_print(e->left); printf(" and "); type_print(R); printf(" "); expr_print(e->right); printf(". This operator can only be used on two integers.\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0, 0); break; case EXPR_EQ: if(L->kind == TYPE_ARRAY){ printf("type error: cannot use operator == on array "); expr_print(e->left); printf("\n"); error_count++; } else if(L->kind == TYPE_FUNCTION){ printf("type error: cannot use operator == on function "); expr_print(e->left); printf("\n"); error_count++; } if(R->kind == TYPE_ARRAY){ printf("type error: cannot use operator == on array "); expr_print(e->right); printf("\n"); error_count++; } else if(R->kind == TYPE_FUNCTION){ printf("type error: cannot use operator == on function "); expr_print(e->right); printf("\n"); error_count++; } if(L->kind != R->kind){ printf("type error: cannot use operator == to compare "); type_print(L); printf(" "); expr_print(e->left); printf(" and "); type_print(R); printf(" "); expr_print(e->right); printf("\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0, 0); break; case EXPR_NE: if(L->kind == TYPE_ARRAY){ printf("type error: cannot use operator != on array "); expr_print(e->left); printf("\n"); error_count++; } else if(L->kind == TYPE_FUNCTION){ printf("type error: cannot use operator != on function "); expr_print(e->left); printf("\n"); error_count++; } if(R->kind == TYPE_ARRAY){ printf("type error: cannot use operator != on array "); expr_print(e->right); printf("\n"); error_count++; } else if(R->kind == TYPE_FUNCTION){ printf("type error: cannot use operator != on function "); expr_print(e->right); printf("\n"); error_count++; } if(L->kind != R->kind){ printf("type error: cannot use operator != to compare "); type_print(L); printf(" "); expr_print(e->left); printf(" and "); type_print(R); printf(" "); expr_print(e->right); printf("\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0, 0); break; case EXPR_ADD: if(L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER){ printf("type error: cannot add "); type_print(L); printf(" "); expr_print(e->left); printf(" to "); type_print(R); printf(" "); expr_print(e->right); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0, 0); break; case EXPR_SUB: if((L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) && L->kind != TYPE_VOID){ printf("type error: cannot subtract "); type_print(R); printf(" "); expr_print(e->right); printf(" from "); type_print(L); printf(" "); expr_print(e->left); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0, 0); break; case EXPR_MUL: if(L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER){ printf("type error: cannot multiply "); type_print(L); printf(" "); expr_print(e->left); printf(" with "); type_print(R); printf(" "); expr_print(e->right); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0, 0); break; case EXPR_DIV: if(L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER){ printf("type error: cannot divide "); type_print(R); printf(" "); expr_print(e->right); printf(" from "); type_print(L); printf(" "); expr_print(e->left); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0, 0); break; case EXPR_MOD: if(L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER){ printf("type error: cannot perform modular division "); type_print(L); printf(" "); expr_print(e->left); printf(" mod "); type_print(R); printf(" "); expr_print(e->right); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0, 0); break; case EXPR_POW: if(L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER){ printf("type error: cannot exponentiate "); type_print(L); printf(" "); expr_print(e->left); printf(" ^ "); type_print(R); printf(" "); expr_print(e->right); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0, 0); break; case EXPR_POSTFIX_PLUS: if(L->kind != TYPE_INTEGER){ printf("type error: cannot increment "); type_print(L); printf(" "); expr_print(e->left); printf("\n"); error_count++; } if(e->left->kind != EXPR_IDENT) { printf("type error: cannot increment non-variable "); expr_print(e->left); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0, 0); break; case EXPR_POSTFIX_MINUS: if(L->kind != TYPE_INTEGER){ printf("type error: cannot decrement "); type_print(L); printf(" "); expr_print(e->left); printf("\n"); error_count++; } if(e->left->kind != EXPR_IDENT) { printf("type error: cannot decrement non-variable "); expr_print(e->left); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0, 0); break; case EXPR_LOGICAL_NOT: if(R->kind != TYPE_BOOLEAN){ printf("type error: cannot negate non-boolean "); type_print(R); printf(" "); expr_print(e->right); printf("\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0, 0); break; case EXPR_LOGICAL_AND: if(L->kind != TYPE_BOOLEAN || R->kind != TYPE_BOOLEAN){ printf("type error: cannot use && to compare non-boolean "); type_print(L); printf(" "); expr_print(e->left); printf(" and "); type_print(R); printf(" "); expr_print(e->right); printf("\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0, 0); break; case EXPR_LOGICAL_OR: if(L->kind != TYPE_BOOLEAN || R->kind != TYPE_BOOLEAN){ printf("type error: cannot use && to compare non-boolean "); type_print(L); printf(" "); expr_print(e->left); printf(" and "); type_print(R); printf(" "); expr_print(e->right); printf("\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0, 0); break; case EXPR_INTEGER_LITERAL: return type_create(TYPE_INTEGER, 0, 0, 0); break; case EXPR_STRING_LITERAL: return type_create(TYPE_STRING, 0, 0, 0); break; case EXPR_CHAR_LITERAL: return type_create(TYPE_CHARACTER, 0, 0, 0); break; case EXPR_TRUE: return type_create(TYPE_BOOLEAN, 0, 0, 0); break; case EXPR_FALSE: return type_create(TYPE_BOOLEAN, 0, 0, 0); break; case EXPR_IDENT: return e->symbol->type; break; case EXPR_FCALL: if(L->kind != TYPE_FUNCTION) { printf("type error: cannot execute function call to non-function "); type_print(L); printf(" "); expr_print(e->left); printf("\n"); error_count++; } function_typecheck(e->left->name, e->right, e->left->symbol->type->params, 1, function_params(e)+1); return L->subtype; break; case EXPR_ARRCALL: if(L->kind != TYPE_ARRAY) { printf("type error: cannot index into non-array "); type_print(L); printf(" "); expr_print(e->left); printf("\n"); error_count++; } //return the number of subtypes that the index requires int i; struct type *T = L; for(i = 0; i < array_call_subtypes(e->right); i++){ T = T->subtype; } return T; break; case EXPR_ARRINDEX: if(L->kind != TYPE_INTEGER){ printf("type error: cannot index an array using non-integer "); type_print(L); printf(" "); expr_print(e->left); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0, 0); break; case EXPR_PARENS: return R; break; case EXPR_BLOCK: return type_create(TYPE_ARRAY, 0, R, exprs_in_block(e)-1); break; case EXPR_BLOCK_COMMA: if(L->kind != R->kind && R->kind != TYPE_VOID){ printf("type error: cannot have "); type_print(L); printf(" "); expr_print(e->left); printf(" and "); type_print(R); printf(" "); expr_print(e->right); printf(" in the same expression list\n"); error_count++; return type_create(TYPE_VOID,0,0,0); } return L; break; case EXPR_COMMA: return R; break; } }
struct type *expr_typecheck(struct expr *e){ if (e == NULL) { return type_create(TYPE_VOID,0,0,0); } struct type *l = malloc(sizeof(struct type)); struct type *r = malloc(sizeof(struct type)); switch (e->kind){ case (EXPR_ADD): l = expr_typecheck(e->left); r = expr_typecheck(e->right); if ((l->kind != TYPE_INTEGER) || (r->kind != TYPE_INTEGER)){ error_counter += 1; printf("Error #%i ",error_counter); printf("type error: cannot add "); type_print(l); literal_print(e->left); printf(" to "); type_print(r); literal_print(e->right); printf("\n"); e->type = 0; } else { e->type = type_create(TYPE_INTEGER,0,0,0); } break; case (EXPR_SUB): l = expr_typecheck(e->left); r = expr_typecheck(e->right); if ((l->kind != TYPE_INTEGER) || (r->kind != TYPE_INTEGER)){ error_counter += 1; printf("Error #%i ",error_counter); printf("type error: cannot subtract "); type_print(l); literal_print(e->left); printf(" from "); type_print(r); literal_print(e->right); printf("\n"); e->type = 0; } else { e->type = type_create(TYPE_INTEGER,0,0,0); } break; case (EXPR_MUL): l = expr_typecheck(e->left); r = expr_typecheck(e->right); if ((l->kind != TYPE_INTEGER) || (r->kind != TYPE_INTEGER)){ error_counter += 1; printf("Error #%i ",error_counter); printf("type error: cannot multiply "); type_print(l); literal_print(e->left); printf(" and "); type_print(r); literal_print(e->right); printf("\n"); e->type = 0; } else { e->type = type_create(TYPE_INTEGER,0,0,0); } break; case (EXPR_DIV): l = expr_typecheck(e->left); r = expr_typecheck(e->right); if ((l->kind != TYPE_INTEGER) || (r->kind != TYPE_INTEGER)){ error_counter += 1; printf("Error #%i ",error_counter); printf("type error: cannot divide "); type_print(l); literal_print(e->left); printf(" by "); type_print(r); literal_print(e->right); printf("\n"); e->type = 0; } else { e->type = type_create(TYPE_INTEGER,0,0,0); } break; case (EXPR_INCREMENT): l = expr_typecheck(e->left); if (l->kind != TYPE_INTEGER){ error_counter += 1; printf("Error #%i ",error_counter); printf("type error: cannot increment "); type_print(l); literal_print(e->left); printf("\n"); e->type = 0; } else { e->type = type_create(TYPE_INTEGER,0,0,0); } break; case (EXPR_DECREMENT): l = expr_typecheck(e->left); if (l->kind != TYPE_INTEGER){ error_counter += 1; printf("Error #%i ",error_counter); printf("type error: cannot decrement "); type_print(l); literal_print(e->left); printf("\n"); e->type = 0; } else { e->type = type_create(TYPE_INTEGER,0,0,0); } break; case (EXPR_NOT): r = expr_typecheck(e->right); if (r->kind != TYPE_BOOLEAN){ error_counter += 1; printf("Error #%i ",error_counter); printf("type error: cannot negate "); type_print(r); literal_print(e->right); printf("\n"); e->type = 0; } else { e->type = type_create(TYPE_BOOLEAN,0,0,0); } break; case (EXPR_POWER): l = expr_typecheck(e->left); r = expr_typecheck(e->right); if ((l->kind != TYPE_INTEGER) || (r->kind != TYPE_INTEGER)){ error_counter += 1; printf("Error #%i ",error_counter); printf("type error: cannot raise "); type_print(l); literal_print(e->left); printf(" to power "); type_print(r); literal_print(e->right); printf("\n"); e->type = 0; } else { e->type = type_create(TYPE_INTEGER,0,0,0); } break; case (EXPR_MODULO): l = expr_typecheck(e->left); r = expr_typecheck(e->right); if ((l->kind != TYPE_INTEGER) || (r->kind != TYPE_INTEGER)){ error_counter += 1; printf("Error #%i ",error_counter); printf("type error: cannot take modulus of "); type_print(l); literal_print(e->left); printf(" and "); type_print(r); literal_print(e->right); printf("\n"); e->type = 0; } else { e->type = type_create(TYPE_INTEGER,0,0,0); } break; case (EXPR_LESS_THAN): l = expr_typecheck(e->left); r = expr_typecheck(e->right); if ((l->kind != TYPE_INTEGER) || (r->kind != TYPE_INTEGER)){ error_counter += 1; printf("Error #%i ",error_counter); printf("type error: cannot compare "); type_print(l); literal_print(e->left); printf(" to "); type_print(r); literal_print(e->right); printf("\n"); e->type = 0; } else { e->type = type_create(TYPE_BOOLEAN,0,0,0); } break; case (EXPR_GREATER_THAN): l = expr_typecheck(e->left); r = expr_typecheck(e->right); if ((l->kind != TYPE_INTEGER) || (r->kind != TYPE_INTEGER)){ error_counter += 1; printf("Error #%i ",error_counter); printf("type error: cannot compare "); type_print(l); literal_print(e->left); printf(" to "); type_print(r); literal_print(e->right); printf("\n"); e->type = 0; } else { e->type = type_create(TYPE_BOOLEAN,0,0,0); } break; case (EXPR_LESS_THAN_OR_EQUAL): l = expr_typecheck(e->left); r = expr_typecheck(e->right); if ((l->kind != TYPE_INTEGER) || (r->kind != TYPE_INTEGER)){ error_counter += 1; printf("Error #%i ",error_counter); printf("type error: cannot compare "); type_print(l); literal_print(e->left); printf(" to "); type_print(r); literal_print(e->right); printf("\n"); e->type = 0; } else { e->type = type_create(TYPE_BOOLEAN,0,0,0); } break; case (EXPR_GREATER_THAN_OR_EQUAL): l = expr_typecheck(e->left); r = expr_typecheck(e->right); if ((l->kind != TYPE_INTEGER) || (r->kind != TYPE_INTEGER)){ error_counter += 1; printf("Error #%i ",error_counter); printf("type error: cannot compare "); type_print(l); literal_print(e->left); printf(" to "); type_print(r); literal_print(e->right); printf("\n"); e->type = 0; } else { e->type = type_create(TYPE_BOOLEAN,0,0,0); } break; case (EXPR_EQUIVALENCE_COMPARISON): l = expr_typecheck(e->left); r = expr_typecheck(e->right); if ((l->kind == TYPE_FUNCTION) || (r->kind == TYPE_FUNCTION)){ error_counter += 1; printf("Error #%i ",error_counter); printf("type error: cannot compare equivalence of functions\n"); e->type = 0; } else if ((l->kind == TYPE_ARRAY) || (r->kind == TYPE_ARRAY)){ error_counter += 1; printf("Error #%i ",error_counter); printf("type error: cannot compare equivalence of arrays\n"); e->type = 0; } else if (l->kind != r->kind){ error_counter += 1; printf("Error #%i ",error_counter); printf("type error: cannot compare equivalence of "); type_print(l); literal_print(e->left); printf(" to "); type_print(r); literal_print(e->right); printf("\n"); e->type = 0; } else { e->type = type_create(TYPE_BOOLEAN,0,0,0); } break; case (EXPR_NONEQUIVALENCE_COMPARISON): l = expr_typecheck(e->left); r = expr_typecheck(e->right); if ((l->kind == TYPE_FUNCTION) || (r->kind == TYPE_FUNCTION)){ error_counter += 1; printf("Error #%i ",error_counter); printf("type error: cannot compare equivalence of functions\n"); e->type = 0; } else if ((l->kind == TYPE_ARRAY) || (r->kind == TYPE_ARRAY)){ error_counter += 1; printf("Error #%i ",error_counter); printf("type error: cannot compare equivalence of arrays\n"); e->type = 0; } else if (l->kind != r->kind){ error_counter += 1; printf("Error #%i ",error_counter); printf("type error: cannot compare equivalence of "); type_print(l); literal_print(e->left); printf(" to "); type_print(r); literal_print(e->right); printf("\n"); e->type = 0; } else { e->type = type_create(TYPE_BOOLEAN,0,0,0); } break; case (EXPR_AND): l = expr_typecheck(e->left); r = expr_typecheck(e->right); if ((l->kind != TYPE_BOOLEAN) || (r->kind != TYPE_BOOLEAN)){ error_counter += 1; printf("Error #%i ",error_counter); printf("type error: cannot compare "); type_print(l); literal_print(e->left); printf(" to "); type_print(r); literal_print(e->right); printf("\n"); e->type = 0; } else { e->type = type_create(TYPE_BOOLEAN,0,0,0); } break; case (EXPR_OR): l = expr_typecheck(e->left); r = expr_typecheck(e->right); if ((l->kind != TYPE_BOOLEAN) || (r->kind != TYPE_BOOLEAN)){ error_counter += 1; printf("Error #%i ",error_counter); printf("type error: cannot compare "); type_print(l); literal_print(e->left); printf(" to "); type_print(r); literal_print(e->right); printf("\n"); e->type = 0; } else { e->type = type_create(TYPE_BOOLEAN,0,0,0); } break; case (EXPR_ASSIGNMENT): l = expr_typecheck(e->left); r = expr_typecheck(e->right); //if ((l->kind == TYPE_FUNCTION) || (r->kind == TYPE_FUNCTION)){ if (l->kind == TYPE_FUNCTION){ error_counter += 1; printf("Error #%i ",error_counter); printf("type error: cannot assign a function\n"); e->type = 0; } else if (l->kind != r->kind) { error_counter += 1; printf("Error #%i ",error_counter); printf("type error: cannot assign "); type_print(l); literal_print(e->left); printf(" to "); type_print(r); literal_print(e->right); printf("\n"); e->type = 0; } else { e->type = type_create(l->kind,0,0,0); } break; case (EXPR_BOOLEAN_LITERAL): e->type = type_create(TYPE_BOOLEAN, 0, 0, 0); break; case (EXPR_INTEGER_LITERAL): e->type = type_create(TYPE_INTEGER, 0, 0, 0); break; case (EXPR_CHARACTER_LITERAL): e->type = type_create(TYPE_CHARACTER, 0, 0, 0); break; case (EXPR_STRING_LITERAL): e->type = type_create(TYPE_STRING, 0, 0, 0); break; case (EXPR_IDENTIFIER): e->type = e->symbol->type; break; case (EXPR_PARENTHESES): e->type = expr_typecheck(e->left); break; case (EXPR_FUNCTION_CALL): param_list_typecheck(); e->type = e->left->symbol->type->subtype; break; case (EXPR_ARRAY_INDEX): e->type = type_create(TYPE_ARRAY, 0, 0, 0); break; } return e->type; }
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); }
struct type * expr_typecheck(struct expr *e) { if (!e) return type_create(TYPE_VOID, 0, 0); struct type *l, *r; switch(e->kind) { case EXPR_INTEGER_LITERAL: return type_create(TYPE_INTEGER, 0, 0); case EXPR_BOOLEAN_LITERAL: return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_CHAR_LITERAL: return type_create(TYPE_CHARACTER, 0, 0); case EXPR_STRING_LITERAL: return type_create(TYPE_STRING, 0, 0); case EXPR_VARIABLE: return type_create(e->symbol->type->kind, 0, 0); case EXPR_FUNCTION_CALL: param_list_typecheck(e->symbol->type->params, e->right, 0); return type_create(e->symbol->type->subtype->kind, 0, 0); case EXPR_ADD: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER) { printf("type error: line %d: cannot add type ", e->line); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf(" to type "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0); case EXPR_UNARY: r = expr_typecheck(e->right); if (r->kind != TYPE_INTEGER) { printf("type error: line %d: ", e->line); printf("unary operator (-) cannot be applied to type "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); error_count++; } return type_create(TYPE_INTEGER, 0, 0); case EXPR_ASSIGN: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind == TYPE_FUNCTION || r->kind == TYPE_FUNCTION) { printf("type error: line %d: ", e->line); printf("= operator not compatible with functions\n"); error_count++; } else if (!(type_compare(l, r))) { printf("type error: line %d: cannot assign type ", e->line); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf(" to type "); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf("\n"); error_count++; } return type_create(l->kind, 0, 0); case EXPR_LIST: l = expr_typecheck(e->left); expr_typecheck(e->right); return l; case EXPR_LIST_OUTER: r = expr_typecheck(e->right); return r;; case EXPR_SUB: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER) { printf("type error: line %d: cannot subtract type ", e->line); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf(" from type "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0); case EXPR_MUL: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER) { printf("type error: line %d: cannot multiply type ", e->line); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf(" and type "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0); case EXPR_DIV: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER) { printf("type error: line %d: cannot divide type ", e->line); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf(" by type "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0); case EXPR_MOD: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER) { printf("type error: line %d: cannot modulus type ", e->line); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf(" with type "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0); case EXPR_POW: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER) { printf("type error: line %d: cannot exponentiate type ", e->line); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf(" by type "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0); case EXPR_INCR: r = expr_typecheck(e->right); if (r->kind != TYPE_INTEGER) { printf("type error: line %d: ", e->line); printf("++ operator not compatible with type "); type_print(e->symbol->type); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0); case EXPR_DECR: r = expr_typecheck(e->right); if (r->kind != TYPE_INTEGER) { printf("type error: line %d: ", e->line); printf("-- operator not compatible with type "); type_print(e->symbol->type); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0); case EXPR_NOT: r = expr_typecheck(e->right); if (r->kind != TYPE_BOOLEAN) { printf("type error: line %d: ", e->line); printf("! operator requires boolean type boolean type operand (found "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf(" )\n" ); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_LT: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER) { printf("type error: line %d: ", e->line); printf("< operator not compatible with types "); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf(" and "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_LE: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER) { printf("type error: line %d: ", e->line); printf("<= operator not compatible with types "); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf(" and "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_GT: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER) { printf("type error: line %d: ", e->line); printf("> operator not compatible with types "); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf(" and "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_GE: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER) { printf("type error: line %d: ", e->line); printf(">= operator not compatible with types "); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf(" and "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_EQ: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind == TYPE_ARRAY || l->kind == TYPE_FUNCTION || r->kind == TYPE_ARRAY || r->kind == TYPE_FUNCTION) { printf("type error: line %d: ", e->line); printf("== operator not compatible with types "); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf(" and "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } else if (!type_compare(l, r)) { printf("type error: line %d: ", e->line); printf("cannot use == operator on non-matching types "); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf(" and "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_NE: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind == TYPE_ARRAY || l->kind == TYPE_FUNCTION || r->kind == TYPE_ARRAY || r->kind == TYPE_FUNCTION) { printf("type error: line %d:", e->line); printf("!= operator not compatible with types "); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf(" and "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } else if (!type_compare(l, r)) { printf("type error: line %d:", e->line); printf("cannot use != operator on non-matching types "); printf(" ("); expr_print(e->left); printf(")"); type_print(l); printf(" and "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_AND: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind != TYPE_BOOLEAN || r->kind != TYPE_BOOLEAN) { printf("type error: line %d: ", e->line); printf("&& operator not compatible with types "); type_print(l); printf(" ("); expr_print(e->right); printf(")"); printf(" and "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_OR: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind != TYPE_BOOLEAN || r->kind != TYPE_BOOLEAN) { printf("type error: line %d: ", e->line); printf("|| operator not compatible with types "); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf(" and "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_ARRAY_MEMBER: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind != TYPE_ARRAY && l->kind != TYPE_STRING) { printf("type error: line %d: ", e->line); printf("[] operator cannot follow a variable of type "); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf("\n"); error_count++; } return type_create(type_array_type(e), 0, 0); case EXPR_INDEX: if (e->left) { l = expr_typecheck(e->left->right); if (l->kind != TYPE_INTEGER) { printf("type error: line %d: ", e->line); printf("an array index cannot be type "); type_print(l); printf(" ("); expr_print(e->left->right); printf(")"); printf("\n"); error_count++; } expr_typecheck(e->right); } else { r = expr_typecheck(e->right); if (r->kind != TYPE_INTEGER) { printf("type error: line %d: ", e->line); printf("an array index cannot be type "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } } return type_create(TYPE_INTEGER, 0, 0); default: fprintf(stderr, "cminor: ERROR! Illegal expr type found!\n"); exit(1); } }