struct expty transExp_recordExp(Tr_level level, S_table venv, S_table tenv, A_exp a, Temp_label breakk) { Ty_ty typ = actual_ty(S_look(tenv, a->u.record.typ)); A_pos pos = a->pos; // check record type if (!typ || typ->kind != Ty_record) { EM_error(pos, "record type '%s' mismatched", S_name(a->u.record.typ)); return expTy(NULL, Ty_Void()); } // check exp field type A_efieldList efields = a->u.record.fields; Ty_fieldList fields = typ->u.record; Tr_expList expl_h = Tr_ExpList(NULL, NULL), expl_p = expl_h; int size = 0; while (efields && fields) { struct expty efield = transExp(level, venv, tenv, efields->head->exp, breakk); pos = efields->head->exp->pos; if (!has_same_ty(fields->head->ty, efield.ty)) { EM_error(pos, "record field type mismatched: '%s' and '%s'", type_msg(fields->head->ty), type_msg(efield.ty)); break; } efields = efields->tail; fields = fields->tail; expl_p->tail = Tr_ExpList(efield.exp, NULL); expl_p = expl_p->tail; size += 1; } if (efields || fields) EM_error(pos, "record type mismatched"); expl_p = expl_h->tail; free(expl_h); return expTy(Tr_recordExp(expl_p, size), S_look(tenv, a->u.record.typ)); }
Tr_exp transDec_functionDec(Tr_level level, S_table venv, S_table tenv, A_dec d, Temp_label breakk) { for (A_fundecList fundecs = d->u.function; fundecs; fundecs = fundecs->tail) { S_symbol name = fundecs->head->name; Ty_tyList formals = makeFormalTyList(tenv, fundecs->head->params); for (A_fundecList f = d->u.function; f != fundecs; f = f->tail) if (f->head->name == name) EM_error(f->head->pos, "there are two functions with the same name in the same batch " "of mutually recursive functions"); Ty_ty result = (fundecs->head->result)? S_look(tenv, fundecs->head->result) : Ty_Void(); Temp_label label = Temp_newlabel(); U_boolList escapeList = NULL; for (A_fieldList l = fundecs->head->params; l; l = l->tail) // todo: handle no escape escapeList = U_BoolList(TRUE, escapeList); S_enter(venv, name, E_FunEntry(Tr_newLevel(level, label, escapeList), label, formals, result)); } for (A_fundecList fundecs = d->u.function; fundecs; fundecs = fundecs->tail) { S_symbol name = fundecs->head->name; E_enventry x = S_look(venv, name); Ty_tyList formals = x->u.fun.formals; Ty_ty result = x->u.fun.result; Tr_level lev = x->u.fun.level; S_beginScope(venv); { A_fieldList l; Ty_tyList t; Tr_accessList a; for (l = fundecs->head->params, t = formals, a = Tr_formals(lev); l; l = l->tail, t = t->tail, a = a->tail) S_enter(venv, l->head->name, E_VarEntry(a->head, t->head)); // check return type struct expty body = transExp(lev, venv, tenv, fundecs->head->body, breakk); if (!has_same_ty(result, body.ty)) { if (has_same_ty(result, Ty_Void())) EM_error(fundecs->head->pos, "procedure returns value '%s'", type_msg(body.ty)); else EM_error(fundecs->head->pos, "return type mismatched '%s' and '%s')", type_msg(result), type_msg(body.ty)); } Tr_procEntryExit(lev, body.exp, a); } S_endScope(venv); } return Tr_noExp(); }
struct expty transExp_assignExp(Tr_level level, S_table venv, S_table tenv, A_exp a, Temp_label breakk) { struct expty lvar = transVar(level, venv, tenv, a->u.assign.var, breakk); struct expty rvar = transExp(level, venv, tenv, a->u.assign.exp, breakk); if (!has_same_ty(lvar.ty, rvar.ty)) EM_error( a->u.assign.exp->pos, "cannot initialize a variable of type '%s' with an rvalue of type '%s'", type_msg(lvar.ty), type_msg(rvar.ty)); return expTy(Tr_assignExp(lvar.exp, rvar.exp), Ty_Void()); }
basic_warning::basic_warning(const std::string& where_msg, const std::string& what_msg, type t) : my_where_msg(where_msg), my_what_msg(what_msg), my_type(t) { if (warning_stream) { std::string msg = what(); if (msg != "") { // @todo This should be handled by passing the logger as // a stream (with some appropriate wrapper deriving from basic_ostream) // but for now this will have to do. if (is_active()) { // add warning to counter if (warning_count.find(t)==warning_count.end()) warning_count[t]=1; else ++warning_count[t]; // output message if (warning_stream != logger::get_stream()) { *warning_stream << msg << std::endl; } else { // to avoid interleaving with logged messages, send // a logged message logger(logger_level::ALWAYS, where_msg, "WARNING (" + type_msg(t) + ") " + my_what_msg); } } } } }
std::string basic_warning::prepare_msg() const { std::string msg = "WARNING " + type_msg(my_type); if (!my_where_msg.empty()) msg += " in " + my_where_msg; if (!my_what_msg.empty()) msg += ": " + my_what_msg; return msg; }
struct expty transVar_subscriptVar(Tr_level level, S_table venv, S_table tenv, A_var v, Temp_label breakk) { struct expty var = transVar(level, venv, tenv, v->u.subscript.var, breakk); struct expty sub = transExp(level, venv, tenv, v->u.subscript.exp, breakk); if (var.ty->kind != Ty_array) { EM_error(v->u.subscript.var->pos, "variable type '%s' is not array", type_msg(var.ty)); return expTy(NULL, Ty_Int()); } if (sub.ty->kind != Ty_int) { EM_error(v->u.subscript.exp->pos, "invalid types '%s' for array subscript", type_msg(sub.ty)); return expTy(NULL, Ty_Int()); } return expTy(Tr_subscriptVar(var.exp, sub.exp, level), actual_ty(var.ty->u.array)); }
Tr_exp transDec_varDec(Tr_level level, S_table venv, S_table tenv, A_dec d, Temp_label breakk) { struct expty init = transExp(level, venv, tenv, d->u.var.init, breakk); if (d->u.var.typ) { Ty_ty typ = S_look(tenv, d->u.var.typ); if (!has_same_ty(typ, init.ty)) EM_error(d->u.var.init->pos, "cannot initialize a variable of type '%s' with an rvalue of " "type '%s'", type_msg(typ), type_msg(init.ty)); } else if (init.ty->kind == Ty_nil) EM_error(d->u.var.init->pos, "cannot initialize a nil type without specified record type"); Tr_access access = Tr_allocLocal(level, TRUE); // todo check escape = false S_enter(venv, d->u.var.var, E_VarEntry(access, init.ty)); return Tr_assignExp(Tr_simpleVar(access, level), init.exp); }
string type_msg(Ty_ty ty) { string str = checked_malloc(200 * sizeof(char)); switch (ty->kind) { case Ty_record: strcpy(str, "record{ "); Ty_fieldList fields = ty->u.record; if (!fields) { strcat(str, type_msg(fields->head->ty)); fields = fields->tail; } for (; fields; fields = fields->tail) { strcat(str, ", "); strcat(str, type_msg(fields->head->ty)); } strcat(str, " }"); break; case Ty_nil: strcpy(str, "nil"); break; case Ty_int: strcpy(str, "int"); break; case Ty_string: strcpy(str, "string"); break; case Ty_array: strcpy(str, "array of "); strcat(str, type_msg(ty->u.array)); break; case Ty_name: if (ty->u.name.ty) strcpy(str, type_msg(actual_ty(ty))); else strcpy(str, S_name(ty->u.name.sym)); break; case Ty_void: strcpy(str, "void"); break; } return str; }
struct expty transExp_arrayExp(Tr_level level, S_table venv, S_table tenv, A_exp a, Temp_label breakk) { Ty_ty typ = actual_ty(S_look(tenv, a->u.array.typ)); struct expty size = transExp(level, venv, tenv, a->u.array.size, breakk); struct expty init = transExp(level, venv, tenv, a->u.array.init, breakk); if (!typ || typ->kind != Ty_array) { EM_error(a->pos, "array type '%s' mismatched", S_name(a->u.array.typ)); return expTy(NULL, Ty_Void()); } if (size.ty->kind != Ty_int) EM_error(a->u.array.size->pos, "integer type required"); if (!has_same_ty(init.ty, typ->u.array)) EM_error( a->u.array.init->pos, "cannot initialize a variable of type '%s' with an rvalue of type '%s'", type_msg(typ), type_msg(init.ty)); return expTy(Tr_arrayExp(size.exp, init.exp), S_look(tenv, a->u.array.typ)); }
struct expty transExp_ifExp(Tr_level level, S_table venv, S_table tenv, A_exp a, Temp_label breakk) { struct expty test = transExp(level, venv, tenv, a->u.iff.test, breakk); struct expty then = transExp(level, venv, tenv, a->u.iff.then, breakk); if (test.ty->kind != Ty_int) EM_error(a->u.iff.test->pos, "integer type required"); if (a->u.iff.elsee) { struct expty elsee = transExp(level, venv, tenv, a->u.iff.elsee, breakk); if (!has_same_ty(then.ty, elsee.ty)) EM_error(a->u.iff.elsee->pos, "types of then - else differ ('%s' and '%s')", type_msg(then.ty), type_msg(elsee.ty)); if (then.ty == Ty_Void()) return expTy(Tr_ifExp_noValue(test.exp, then.exp, elsee.exp), Ty_Void()); return expTy(Tr_ifExp(test.exp, then.exp, elsee.exp), then.ty); } if (then.ty->kind != Ty_void) EM_error(a->u.iff.then->pos, "if-then returns non unit"); return expTy(Tr_ifExp_noValue(test.exp, then.exp, NULL), then.ty); return expTy(NULL, Ty_Void()); }
struct expty transVar_fieldVar(Tr_level level, S_table venv, S_table tenv, A_var v, Temp_label breakk) { struct expty var = transVar(level, venv, tenv, v->u.field.var, breakk); if (var.ty->kind != Ty_record) EM_error(v->pos, "invalid types '%s' for record field", type_msg(var.ty)); int index = 0; Ty_fieldList fields; for (fields = var.ty->u.record; fields != NULL; fields = fields->tail, index += 1) if (fields->head->name == v->u.field.sym) break; if (!fields) { EM_error(v->pos, "field '%s' not defined in record type", S_name(v->u.field.sym)); return expTy(NULL, Ty_Int()); } return expTy(Tr_fieldVar(var.exp, index, level), actual_ty(fields->head->ty)); }
void basic_warning::output_statistics() { if (!warning_count.empty()) { std::stringstream ss; ss << "ATTENTION: Warnings were issued." << std::endl; if (warning_stream != logger::get_stream()) { *warning_stream << ss; } else { logger(logger_level::ALWAYS, "Warning statistics", ss.str()); } } for (std::map<basic_warning::type, unsigned int>::const_iterator it = warning_count.begin(); it != warning_count.end(); ++it) { std::stringstream ss; ss << "Warnings on " << type_msg(it->first) << ": " << it->second << std::endl; if (warning_stream != logger::get_stream()) { *warning_stream << ss; } else { logger(logger_level::ALWAYS, "Warning statistics", ss.str()); } } }