int check_continue(is_continue* node) { int errors = 0; if (errors == 0) { if (node->label) node->scope = scope_get_by_name(symtab, node->label->name, t_symbol_loop); else node->scope = scope_get_by_name(symtab, NULL, t_symbol_loop); if (!node->scope) { errors++; if (node->label) pretty_error(node->line, "continue stmt label \"%s\" is undefined", node->label->name); else pretty_error(node->line, "continue stmt outside of loop"); } else node->scope->symbol->data.loop_data.continued = true; } return errors; }
int check_ternary_op(is_ternary_op* node) { char *typeA, *typeB; int errors = 0; errors += check_expr(node->if_expr); if (errors == 0 && !type_native_assign_able(t_type_native_bool, node->if_expr->s_type)) { errors++; typeA = string_type_decl(node->if_expr->s_type); pretty_error(node->line, "ternary conditional is not boolean (is of type %s)", typeA); free(typeA); } errors += check_expr(node->then_expr); errors += check_expr(node->else_expr); if (errors == 0 && !type_type_equal(node->then_expr->s_type, node->else_expr->s_type)) { errors++; typeA = string_type_decl(node->then_expr->s_type); typeB = string_type_decl(node->else_expr->s_type); pretty_error(node->line, "ternary results are not of the same type (are of types %s and %s)", typeA, typeB); free(typeA); free(typeB); } if (errors == 0) node->s_type = duplicate_type_decl(node->then_expr->s_type); return errors; }
int check_incr_op(is_incr_op* node) { is_type_native type; char* typeA; int errors = 0; errors += check_var(node->var); if (errors == 0) { if (node->var->s_type->type != t_type_decl_array_decl) { type = operators_incr_op[node->var->s_type->data.type_object->type]; if (type == ERROR) { errors++; pretty_error(node->line, "increment operation with %s type is invalid", typeA = string_type_decl(node->var->s_type)); free(typeA); } else if (!node->var->initialized) { errors++; pretty_error(node->line, "variable used in a increment op without being initialized "); } else node->s_type = duplicate_type_decl(node->var->s_type); } else { errors++; pretty_error(node->line, "increment operations are invalid between array types"); } } return errors; }
int check_break(is_break* node) { int errors = 0; SCOPE *scope_loop, *scope_switch, *aux; if (errors == 0) { node->scope = NULL; if (node->label) { scope_loop = scope_get_by_name(symtab, node->label->name, t_symbol_loop); scope_switch = scope_get_by_name(symtab, node->label->name, t_symbol_switch); } else { scope_loop = scope_get_by_name(symtab, NULL, t_symbol_loop); scope_switch = scope_get_by_name(symtab, NULL, t_symbol_switch); } if (scope_loop == NULL) { node->scope = scope_switch; node->type = t_break_switch; } else if (scope_switch == NULL) { node->scope = scope_loop; node->type = t_break_loop; } else { for (aux = scope_loop; aux != NULL; aux = aux->parent) { if (aux == scope_switch) /* switch is higher on the scope stack */ { node->scope = scope_loop; /* we want the lowest */ node->type = t_break_loop; break; } } if (node->scope == NULL) { node->scope = scope_switch; node->type = t_break_switch; } } if (!node->scope) { errors++; if (node->label) pretty_error(node->line, "break stmt label \"%s\" is undefined", node->label->name); else pretty_error(node->line, "break stmt outside of loop or switch"); } } return errors; }
int check_func_call(is_func_call* node) { is_expr_list* arg; int errors = 0; int i; char *typeA, *typeB; node->symbol = scope_lookup(symtab, node->id->name, t_symbol_func); if (!node->symbol) { pretty_error(node->line, "undefined function \"%s\"", node->id->name); errors++; } else { errors += check_func_call_arg_list(node->args); if (errors == 0) { if ((node->args == NULL && node->symbol->data.func_data.nArgs != 0) || (node->args != NULL && node->args->length != node->symbol->data.func_data.nArgs)) { pretty_error(node->line, "too %s arguments for \"%s\", got %d expected %d (declaration is here: %d)", node->args->length > node->symbol->data.func_data.nArgs ? "many" : "few", node->id->name, node->args->length, node->symbol->data.func_data.nArgs, node->symbol->line); errors++; } else { for (i = 0, arg = node->args; arg != NULL; i++, arg = arg->next) { if (!type_type_assign_able(node->symbol->data.func_data.args[i]->type, arg->node->s_type)) { errors++; pretty_error(node->line, "invalid parameter \"%d\" (%s) of function %s (got %s expected %s)", i, node->symbol->data.func_data.args[i]->id->name, node->id->name, typeA = string_type_decl(arg->node->s_type), typeB = string_type_decl(node->symbol->data.func_data.args[i]->type) ); free(typeA); free(typeB); } } if (errors == 0) node->s_type = duplicate_type_decl(node->symbol->data.func_data.type); } } } return errors; }
int check_binary_op(is_binary_op* node) { int errors = 0; char *typeA, *typeB; is_type_native type; switch (node->type) { case t_binary_op_assign: errors += check_assign_op(node->data.assign); if (errors == 0) node->s_type = duplicate_type_decl(node->data.assign->s_type); break; default: errors += check_expr(node->data.operands.left); errors += check_expr(node->data.operands.right); if (errors == 0) { if (node->data.operands.left->s_type->type == t_type_decl_array_decl || node->data.operands.right->s_type->type == t_type_decl_array_decl) { errors++; pretty_error(node->line, "binary operations are invalid between array types"); } else { type = operators_binary[node->type][node->data.operands.left->s_type->data.type_object->type][node->data.operands.right->s_type->data.type_object->type]; if (type == ERROR) { errors++; pretty_error(node->line, "invalid binary operation between %s and %s", typeA = string_type_decl(node->data.operands.left->s_type), typeB = string_type_decl(node->data.operands.right->s_type) ); free(typeA); free(typeB); } } } /* only valid for objects not arrays*/ if (errors == 0) node->s_type = insert_type_decl_object(insert_type_object(type)); break; } return errors; }
int check_while(is_while* node, is_label* label) { int errors = 0; char *string; int mylabel = ++label_counter; /* setting label for use with loops and break/continue */ if (label) node->scope = scope_new(symbol_new_loop(label->name, node->line, mylabel), false); else node->scope = scope_new(symbol_new_loop(NULL, node->line, mylabel), false); scope_push(node->scope); errors += check_expr(node->cond); if (errors == 0) { if (!type_native_assign_able(t_type_native_bool, node->cond->s_type)) { errors++; pretty_error(node->line, "invalid while condition: expected boolean, got %s", string = string_type_decl(node->cond->s_type)); free(string); } } errors += check_stmt(node->body); node->terminates = node->body->terminates; scope_pop(); return errors; }
int check_do_while(is_do_while* node, is_label* label) { int errors = 0; int mylabel = ++label_counter; /* setting label for use with loops and break/continue */ if (label) node->scope = scope_new(symbol_new_loop(label->name, node->line, mylabel), false); else node->scope = scope_new(symbol_new_loop(NULL, node->line, mylabel), false); scope_push(node->scope); errors += check_stmt(node->body); if (errors == 0) node->terminates = node->body->terminates; errors += check_expr(node->cond); if (errors == 0) { if (!type_native_assign_able(t_type_native_bool, node->cond->s_type)) { errors++; pretty_error(node->line, "invalid do..while condition (must be boolean)"); } } scope_pop(); return errors; }
int check_stmt_list(is_stmt_list* node) { int errors = 0; if (node) { errors += check_stmt(node->node); errors += check_stmt_list(node->next); if (node->node) node->terminated = node->node->terminates; else node->terminated = false; if (node->next) { node->length = node->next->length+1; if (node->terminated) pretty_error(node->line, "dead code after incoditional jump stmt"); else node->terminated = node->next->terminated; } else node->length = 1; } return errors; }
int check_unary_op(is_unary_op* node) { is_type_native type; char* typeA; int errors = 0; switch (node->type) { case t_unary_op_operation: errors += check_expr(node->data.operation.expr); if (errors == 0) { if (node->data.operation.expr->s_type->type != t_type_decl_array_decl) { type = operators_unary[node->data.operation.op][node->data.operation.expr->s_type->type]; if (type == ERROR) { errors++; pretty_error(node->line, "unary operation with %s type is invalid", typeA = string_type_decl(node->data.operation.expr->s_type)); free(typeA); } else node->s_type = duplicate_type_decl(node->data.operation.expr->s_type); } else { errors++; pretty_error(node->line, "unary operations are invalid between array types"); } } break; case t_unary_op_incr_op: errors += check_incr_op(node->data.incr); if (errors == 0) { node->s_type = duplicate_type_decl(node->data.incr->s_type); node->data.incr->used = true; } break; } return errors; }
int check_label(is_id* node) { int errors = 0; SCOPE* scope; scope = scope_get_by_name(symtab, node->name, t_symbol_loop); if (scope != NULL) { errors++; pretty_error(node->line, "ambiguous label \"%s\"", node->name); } return errors; }
int check_class_def(is_class_def* node) { int errors = 0; SYMBOL* symbol; symbol = scope_lookup(symtab, node->id->name, t_symbol_class); if (symbol) { errors++; pretty_error(node->line, "class \"%s\" is already defined (previous declaration was here: %d)", node->id->name, symbol->line); } else scope_insert(symtab, symbol = symbol_new_class(node->id->name, node->line)); node->scope = scope_new(symbol, true); /* FIXME: this should be in application and not in class def, because theoretically class should be able to access other classes */ scope_push(node->scope); errors += check_class_stmt_list(node->body, true); if (errors == 0) { symbol = scope_lookup(symtab, "main", t_symbol_func); if (!symbol) { errors++; pretty_error(node->line, "missing main entry point"); } } errors += check_class_stmt_list(node->body, false); scope_pop(); return errors; }
int check_dims_sized(is_dims_sized* node) { int errors = 0; errors += check_expr(node); if (errors == 0) { if (!type_native_assign_able(t_type_native_int, node->s_type)) { errors++; pretty_error(node->line, "invalid array size (must be convertible to int)"); } } return errors; }
int check_return(is_return* node) { int errors = 0; SCOPE* scope; is_type_decl *type = NULL, *typeR; char *typeA, *typeB; if (node->value) { errors += check_expr(node->value); typeR = node->value->s_type; } else { type = new_type_decl_void(node->line); typeR = type; } if (errors == 0) { scope = scope_get_by_name(symtab, NULL, t_symbol_func); node->symbol = scope->symbol; if (!type_type_equal(typeR, node->symbol->data.func_data.type)) { typeA = string_type_decl(typeR); typeB = string_type_decl(node->symbol->data.func_data.type); errors++; pretty_error(node->line, "invalid return type %s should be of type %s", typeA, typeB ); free(typeA); free(typeB); } } if (type) free_type_decl(type); return errors; }
int check_for(is_for* node, is_label* label) { int errors = 0, cond_errors; char* typeA; int mylabel = ++label_counter; /* setting label for use with loops and break/continue */ if (label) node->scope = scope_new(symbol_new_loop(label->name, node->line, mylabel), false); else node->scope = scope_new(symbol_new_loop(NULL, node->line, mylabel), false); scope_push(node->scope); if (node->init) errors += check_for_init(node->init); if (node->cond) { cond_errors = check_for_cond(node->cond); if (cond_errors == 0) { if (!type_native_assign_able(t_type_native_bool, node->cond->s_type)) { cond_errors++; pretty_error(node->line, "for conditional is not boolean (is of type %s)", typeA = string_type_decl(node->cond->s_type)); free(typeA); } } errors += cond_errors; } if (node->inc) errors += check_for_inc(node->inc); errors += check_stmt(node->body); if (errors == 0) node->terminates = (node->body ? node->body->terminates : true); scope_pop(); return errors; }
int check_switch(is_switch* node) { int errors = 0; int mylabel = ++label_counter; /* setting label for use with break */ char *type; if (node->label) errors += check_label(node->label); errors += check_expr(node->expr); if (errors == 0) { if (node->expr->s_type->type == t_type_decl_array_decl) { errors++; type = string_type_decl(node->expr->s_type); pretty_error(node->line, "switch statement expression must be of object type (got %s)", type); free(type); } } if (errors == 0) { if (node->label) node->scope = scope_new(symbol_new_switch(node->label->name, node->line, mylabel, node->expr->s_type->data.type_object, symtab->framepos++), false); else node->scope = scope_new(symbol_new_switch(NULL, node->line, mylabel, node->expr->s_type->data.type_object, symtab->framepos++), false); scope_push(node->scope); check_switch_stmt_list(node->list, node); if (errors == 0) node->terminates = (node->list ? node->list->terminates : true); scope_pop(); } return errors; }
int check_if(is_if* node) { int errors = 0; char* typeA; errors += check_expr(node->cond); if (errors == 0 && !type_native_assign_able(t_type_native_bool, node->cond->s_type)) { errors++; pretty_error(node->line, "if conditional is not boolean (is of type %s)", typeA = string_type_decl(node->cond->s_type)); free(typeA); } errors += check_stmt(node->then_body); node->terminates = node->then_body->terminates && node->else_body != NULL; if (node->else_body) { errors += check_stmt(node->else_body); node->terminates &= node->else_body->terminates; } return errors; }
int check_func_def_arg(is_func_def_arg* node) { int errors = 0; SYMBOL* symbol; errors += check_type_decl(node->type); if (errors == 0) { symbol = scope_local_lookup(symtab, node->id->name, t_symbol_var); if (symbol) { pretty_error(node->line, "argument \"%s\" colides with already defined variable (previous declaration was here: %d)", node->id->name, symbol->line); errors++; } else { symbol = scope_insert(symtab, symbol_new_var(node->id->name, node->line, node->type, false, symtab->framepos++)); symbol->data.var_data.initialized = true; } } return errors; }
/** * Report an error that occurs during evaluation. */ static void eval_error(struct eval_state *state) { pretty_error(state->cmdline->stderr_colors, "'%s': %s\n", state->ftwbuf->path, strerror(errno)); state->ret = -1; }
int check_func_def(is_func_def* node, bool first_pass) { SYMBOL* symbol; SCOPE* tempscope; int label; int errors = 0; is_type_decl *tmpType = NULL; if (first_pass) { errors += check_type_decl(node->type); symbol = scope_lookup(symtab, node->id->name, t_symbol_func); if (symbol) { pretty_error(node->line, "symbol \"%s\" is already defined (previous declaration was here: %d)", node->id->name, symbol->line); errors++; } else { tempscope = scope_new(NULL, false); scope_push(tempscope); errors += check_func_def_args(node->args); scope_pop(); if (strcmp(node->id->name, "main") == 0) { label = 0; if (node->args) /* no args is valid */ { if (node->args->length == 1) /* main may must not have more than two arguments */ { tmpType = insert_type_decl_array(insert_array_decl(insert_type_object(t_type_native_string), new_dims_empty_list(0, 1))); /* must be an array of Strings */ if (!type_type_equal(tmpType,node->args->node->type)) { errors++; pretty_error(node->line, "main function arguments do not match any valid prototypes"); } free_type_decl(tmpType); } else { errors++; pretty_error(node->line, "main function arguments do not match any valid prototypes"); } } tmpType = insert_type_decl_object(insert_type_object(t_type_native_int)); /* return value must be int or void */ if (!type_type_equal(tmpType,node->type)) { free_type_decl(tmpType); tmpType = new_type_decl_void(0); /* check for void */ if (!type_type_equal(tmpType,node->type)) /* none; errors occurred */ { errors++; pretty_error(node->line, "main function return type does not match any valid types (nor int nor void)"); } } free_type_decl(tmpType); } else label = ++label_counter; symbol = symbol_new_func(node->id->name, node->line, node->type, node->args, label); scope_delete(tempscope); scope_insert(symtab, symbol); node->scope = scope_new(symbol, false); } } else { scope_push(node->scope); errors += check_func_def_args(node->args); /* this will not give errors */ errors += check_stmt_list(node->body); if ((!node->body || !node->body->terminated) && !(node->type->type == t_type_decl_type_object && node->type->data.type_object->type == t_type_native_void)) { pretty_error(node->line, "reached end of non void function"); errors++; } scope_pop(); } return errors; }
int check_assign_op(is_assign_op* node) { int errors = 0; char* typeA, *typeB; is_type_native type; SYMBOL* symbol; errors += check_var(node->var); errors += check_expr(node->expr); if (errors == 0) { switch (node->type) { case t_assign_op_eq: if (!type_type_assign_able(node->var->s_type, node->expr->s_type)) { errors++; pretty_error(node->line, "invalid assignment from %s to %s", typeA = string_type_decl(node->expr->s_type), typeB = string_type_decl(node->var->s_type) ); free(typeA); free(typeB); } else { if (node->var->type == t_var_id) { symbol = scope_lookup(symtab, node->var->data.id->name, t_symbol_var); symbol->data.var_data.initialized = true; } node->s_type = duplicate_type_decl(node->var->s_type); } break; default: if (node->var->s_type->type == t_type_decl_array_decl || node->expr->s_type->type == t_type_decl_array_decl) { errors++; pretty_error(node->line, "assignment operations are invalid between array types"); } else { type = operators_binary[node->type][node->var->s_type->data.type_object->type][node->expr->s_type->data.type_object->type]; if (type == ERROR) { errors++; pretty_error(node->line, "assignment operation invalid between %s and %s", typeA = string_type_decl(node->var->s_type), typeB = string_type_decl(node->expr->s_type) ); free(typeA); free(typeB); } else node->s_type = insert_type_decl_object(insert_type_object(type)); } break; } } return errors; }
int check_switch_stmt(is_switch_stmt* node, is_switch* root) { int errors = 0; char *typeA, *typeB; is_switch_stmt_list* temp; switch (node->type) { case t_switch_stmt_default: for (temp = root->list; temp->node != node; temp = temp->next) { if (temp->node->type == t_switch_stmt_default) { errors++; pretty_error(node->line, "duplicate default label inside of switch (previous declaration was here %d)", temp->node->line); } } if (node->list) errors += check_stmt_list(node->list); break; case t_switch_stmt_case: check_constant(node->constant); if (errors == 0) { node->s_type = duplicate_type_decl(node->constant->s_type); if (!type_type_equal(root->expr->s_type, node->s_type)) { errors++; typeA = string_type_decl(root->expr->s_type); typeB = string_type_decl(node->s_type); pretty_error(node->line, "case stmt must by of type %s (but got %s)", typeA, typeB); free(typeA); free(typeB); } } if (errors == 0) { for (temp = root->list; temp->node != node; temp = temp->next) { if (temp->node->type != t_switch_stmt_default && constant_constant_equal(temp->node->constant, node->constant)) { errors++; pretty_error(node->line, "duplicate case inside of switch (previous declaration was here %d)", temp->node->line); } } } if (node->list) errors += check_stmt_list(node->list); break; } return errors; }
int check_expr(is_expr* node) { char *typeA, *typeB; int errors = 0; switch (node->type) { case t_expr_var: errors += check_var(node->data.var); if (errors == 0) { node->s_type = duplicate_type_decl(node->data.var->s_type); if (!node->data.var->initialized) { errors++; pretty_error(node->line, "variable used without being initialized"); } } break; case t_expr_new_op: errors += check_new_op(node->data.new_op); if (errors == 0) node->s_type = duplicate_type_decl(node->data.new_op->s_type); break; case t_expr_type_cast: errors += check_expr(node->data.type_cast.expr); errors += check_type_decl(node->data.type_cast.type); if (errors == 0) { if (!type_type_cast_able(node->data.type_cast.type, node->data.type_cast.expr->s_type)) { errors++; typeA = string_type_decl(node->data.type_cast.type); typeB = string_type_decl(node->data.type_cast.expr->s_type); pretty_error(node->line, "invalid typecast from %s to %s", typeA, typeB); free(typeA); free(typeB); } else node->s_type = duplicate_type_decl(node->data.type_cast.type); } break; case t_expr_constant: errors += check_constant(node->data.constant); if (errors == 0) node->s_type = duplicate_type_decl(node->data.constant->s_type); break; case t_expr_func_call: errors += check_func_call(node->data.func_call); if (errors == 0) node->s_type = duplicate_type_decl(node->data.func_call->s_type); break; case t_expr_operation: errors += check_expr_op(node->data.operation); if (errors == 0) node->s_type = duplicate_type_decl(node->data.operation->s_type); break; } return errors; }
int check_var(is_var* node) { int errors = 0; char *typeA; switch (node->type) { case t_var_id: node->symbol = scope_lookup(symtab, node->data.id->name, t_symbol_var); if (!node->symbol) { errors++; pretty_error(node->line, "undefined variable \"%s\"", node->data.id->name); node->initialized = false; } else { node->initialized = node->symbol->data.var_data.initialized; node->s_type = duplicate_type_decl(node->symbol->data.var_data.type); } break; case t_var_new_op: errors += check_new_op(node->data.new_op); node->s_type = duplicate_type_decl(node->data.new_op->s_type); node->initialized = true; break; case t_var_array: errors += check_var(node->data.array.var); errors += check_dims_sized(node->data.array.dims); if (errors == 0) { if (node->data.array.var->s_type->type == t_type_decl_array_decl) { node->s_type = decapsulate_type_decl(node->data.array.var->s_type); } else { errors++; pretty_error(node->line, "subscript of unsuscriptable type (%s)", typeA = string_type_decl(node->data.array.var->s_type) ); free(typeA); } } node->initialized = true; break; case t_var_func_call: errors += check_func_call(node->data.func_call.call); errors += check_dims_sized(node->data.array.dims); if (errors == 0) { if (node->data.func_call.call->s_type->type == t_type_decl_array_decl) { node->s_type = decapsulate_type_decl(node->data.func_call.call->s_type); } else { errors++; pretty_error(node->line, "subscript of unsuscriptable type (%s)", typeA = string_type_decl(node->data.func_call.call->s_type) ); free(typeA); } } node->initialized = true; break; } /* todo propagate node->initialized */ return errors; }
int check_var_defs(is_var_defs* node, bool first_pass) { int errors = 0; SYMBOL *symbol; is_type_decl *type = NULL; is_var_def_list *it; errors += check_type_decl(node->type); errors += check_var_def_list(node->list); for (it = node->list; it != NULL; it = it->next) { symbol = scope_local_lookup(symtab, it->node->left->id->name, t_symbol_var); if (symbol) { errors++; pretty_error(it->node->line, "symbol \"%s\" is already defined (previous declaration was here: %d)", it->node->left->id->name, symbol->line); } else { if (it->node->left->empty->size != 0) { if (node->type->type != t_type_decl_array_decl) { /* create a new type_decl (array) with it->node->left->data.empty->size dimensions */ type = insert_type_decl_array(insert_array_decl(insert_type_object(node->type->data.type_object->type), new_dims_empty_list(node->type->line, it->node->left->empty->size))); } else { /* type is already a type_decl_array, only dims update is needed */ type = duplicate_type_decl(node->type); type->data.array->dims->size += it->node->left->empty->size; } } else /* no dims updates are needed; even if the type is "dimmed" this is only a copy of the type */ type = duplicate_type_decl(node->type); if (first_pass) symbol = scope_insert(symtab, symbol_new_var(it->node->left->id->name, node->line, type, true, globalpos++)); else symbol = scope_insert(symtab, symbol_new_var(it->node->left->id->name, node->line, type, false, symtab->framepos++)); it->node->left->symbol = symbol; if (it->node->var_init) /* check initialization if it exists */ { if (type_var_init_assign_able(type, (type->type == t_type_decl_array_decl ? type->data.array->dims->size : 0), it->node->var_init)) /* if initialization is valid */ symbol->data.var_data.initialized = true; else { errors++; pretty_error(it->node->line, "variable \"%s\" initalization is invalid", it->node->left->id->name); } } } free_type_decl(type); } return errors; }