/* exp op exp, rules: * 1. +,-,*,/ only apply to integer operands * 2. =,<>,>,<,>=,<= apply to: * integers * record or array of the same type: compare pointers * strings: compare contents */ struct expty transOpExp(S_table venv, S_table tenv, A_exp e) { struct expty left = transExp(venv, tenv, e->u.op.left); struct expty right = transExp(venv, tenv, e->u.op.right); switch (e->u.op.oper) { case A_plusOp: case A_minusOp: case A_timesOp: case A_divideOp: if (left.ty->kind != Ty_int) { EM_error(e->u.op.left->pos, "integer required"); } if (right.ty->kind != Ty_int) { EM_error(e->u.op.right->pos, "integer required"); } return ExpTy(NULL, Ty_Int()); case A_eqOp: case A_neqOp: case A_ltOp: case A_leOp: case A_gtOp: case A_geOp: if (!Ty_is_compatible(left.ty, right.ty)) { EM_error(e->pos, "operands type mismatch"); } return ExpTy(NULL, Ty_Int()); } assert(0); }
static struct expty transVar(Tr_level level, Tr_exp breakk, S_table venv, S_table tenv, A_var v) { if (!v) {return expTy(Tr_noExp(), Ty_Void());} /*!those several var is ugly*/ E_enventry x; struct expty et,et2; Ty_fieldList fl; Tr_exp trans; switch (v->kind) { case A_simpleVar:/* var id (a)*/ x = S_look(venv, v->u.simple); trans = Tr_noExp(); if (x && x->kind == E_varEntry) { trans = Tr_simpleVar(x->u.var.access, level); return expTy(trans, actual_ty(x->u.var.ty)); } else { EM_error(v->pos, "undefined var %s", S_name(v->u.simple)); return expTy(trans, Ty_Int()); } break; case A_fieldVar:/* var record (a.b)*/ et = transVar(level, breakk, venv, tenv, v->u.field.var); trans = Tr_noExp(); if (et.ty->kind != Ty_record) { EM_error(v->pos, "not a record type"); } else { int i = 0; for (fl = et.ty->u.record; fl; fl = fl->tail, i++) { /*fl is Ty_fieldList*/ if (fl->head->name == v->u.field.sym) { trans = Tr_fieldVar(et.exp, i); return expTy(trans, actual_ty(fl->head->ty)); } } EM_error(v->pos, "no such field in record %s", S_name(v->u.field.sym)); } return expTy(trans, Ty_Int()); break; case A_subscriptVar: /*var array (a[b])*/ et = transVar(level, breakk, venv, tenv, v->u.subscript.var); trans = Tr_noExp(); if (et.ty->kind != Ty_array) { EM_error(v->pos, "not a array type"); } else { et2 = transExp(level, breakk, venv, tenv, v->u.subscript.exp); if (et2.ty->kind != Ty_int) { EM_error(v->pos, "int required"); } else { trans = Tr_subscriptVar(et.exp, et2.exp); return expTy(trans, actual_ty(et.ty->u.array)); } } return expTy(trans, Ty_Int()); default: assert(0); } }
Ty_ty transTy(S_table tenv, A_ty a) { assert(a != NULL); switch (a->kind) { case A_nameTy: { Ty_ty ty = S_look(tenv, a->u.name); if (ty != NULL) { return ty; } else { return Ty_Int(); } } case A_recordTy: { if (!a->u.record) { return Ty_Record(NULL); } Ty_fieldList tfl, tfl_p; tfl = tfl_p = NULL; A_fieldList fl; for (fl = a->u.record; fl; fl = fl->tail) { Ty_ty ty = S_look(tenv, fl->head->typ); if (!ty) { EM_error(a->pos, "undefined field type"); return Ty_Int(); } if (tfl) { tfl_p->tail = Ty_FieldList(Ty_Field(fl->head->name, ty), NULL); tfl_p = tfl_p->tail; } else { tfl = Ty_FieldList(Ty_Field(fl->head->name, ty), NULL); tfl_p = tfl; } } return Ty_Record(tfl); } case A_arrayTy: { Ty_ty ty; ty = S_look(tenv, a->u.array); if (ty != NULL) { return Ty_Array(ty); } else { return Ty_Int(); } } default: { assert(0); } } }
S_table E_base_venv(void) { S_table t = S_empty(); S_enter( t, S_Symbol("print"), E_FunEntry(Ty_TyList(Ty_String(), NULL), Ty_Void()) ); S_enter( t, S_Symbol("flush"), E_FunEntry(NULL, Ty_Void()) ); S_enter( t, S_Symbol("getchar"), E_FunEntry(NULL, Ty_String()) ); S_enter( t, S_Symbol("ord"), E_FunEntry(Ty_TyList(Ty_String(), NULL), Ty_Int()) ); S_enter( t, S_Symbol("chr"), E_FunEntry(Ty_TyList(Ty_Int(), NULL), Ty_String()) ); S_enter( t, S_Symbol("size"), E_FunEntry(Ty_TyList(Ty_String(), NULL), Ty_Int()) ); S_enter( t, S_Symbol("substring"), E_FunEntry(Ty_TyList(Ty_String(), Ty_TyList(Ty_Int(), Ty_TyList(Ty_Int(), NULL))), Ty_String()) ); S_enter( t, S_Symbol("concat"), E_FunEntry(Ty_TyList(Ty_String(), Ty_TyList(Ty_String(), NULL)), Ty_String()) ); S_enter( t, S_Symbol("not"), E_FunEntry(Ty_TyList(Ty_Int(), NULL), Ty_Int()) ); S_enter( t, S_Symbol("exit"), E_FunEntry(Ty_TyList(Ty_Int(), NULL), Ty_Void()) ); return t; }
struct expty transVar(S_table venv, S_table tenv, A_var v) { switch (v->kind) { case A_simpleVar: { E_enventry x = S_look(venv, v->u.simple); if (x && x->kind == E_varEntry) return expTy(NULL, actual_ty(x->u.var.ty)); else { //EM_error(v->pos, "undefined variable %s", S_name(v->u.simple)); return expTy(NULL, Ty_Int()); } } case A_fieldVar: { struct expty res = transVar(venv, tenv, v->u.field.var); Ty_ty ty = res.ty; if (ty->kind == Ty_record) { Ty_fieldList fieldList = ty->u.record; while (fieldList != NULL) { if (fieldList->head->name == v->u.field.sym) { return expTy(NULL, actual_ty(fieldList->head->ty)); } else { fieldList = fieldList->tail; } } //EM_error(v->pos, "undefined field %s", S_name(v->u.field.sym)); return expTy(NULL, Ty_Int()); } else { //EM_error(v->pos, "undefined field %s", S_name(v->u.field.sym)); return expTy(NULL, Ty_Int()); } } case A_subscriptVar: { struct expty res = transVar(venv, tenv, v->u.subscript.var); struct expty index = transExp(venv, tenv, v->u.subscript.exp); Ty_ty ty = res.ty; if (ty->kind == Ty_array && index.ty->kind == Ty_int) { return expTy(NULL, actual_ty(ty->u.array)); } else { EM_error(v->pos, "array index error"); return expTy(NULL, Ty_Int()); } } default: { assert(0); } } }
Tr_exp transDec_typeDec(Tr_level level, S_table venv, S_table tenv, A_dec d, Temp_label breakk) { for (A_nametyList decs = d->u.type; decs; decs = decs->tail) { S_symbol name = decs->head->name; for (A_nametyList ds = d->u.type; ds != decs; ds = ds->tail) if (ds->head->name == name) EM_error(d->pos, "there are two types with the same name in the same batch of " "mutually recursive types"); S_enter(tenv, name, Ty_Name(name, NULL)); } for (A_nametyList decs = d->u.type; decs; decs = decs->tail) { Ty_ty type = S_look(tenv, decs->head->name); type->u.name.ty = transTy(level, tenv, decs->head->ty); } for (A_nametyList decs = d->u.type; decs; decs = decs->tail) { Ty_ty type = S_look(tenv, decs->head->name); if (type->u.name.sym == actual_ty(type)->u.name.sym) { EM_error(decs->head->ty->pos, "mutually recursive types declaration"); type->u.name.ty = Ty_Int(); } } return Tr_noExp(); }
S_table E_base_tenv(void) { S_table init_t = S_empty(); S_enter(init_t, S_Symbol("int"), Ty_Int()); S_enter(init_t, S_Symbol("string"), Ty_String()); S_enter(init_t, S_Symbol("double"), Ty_Double()); return init_t; }
Ty_ty transTy(Tr_level level, S_table tenv, A_ty a) { switch (a->kind) { case A_nameTy: { return Ty_Name(a->u.name, S_look(tenv, a->u.name)); } case A_recordTy: { Ty_fieldList h = Ty_FieldList(NULL, NULL), p = h, fields; for (A_fieldList efields = a->u.record; efields; efields = efields->tail) { Ty_ty typ = S_look(tenv, efields->head->typ); if (!typ) { EM_error(efields->head->pos, "type '%s' undefined", S_name(efields->head->name)); typ = Ty_Int(); } p->tail = Ty_FieldList(Ty_Field(efields->head->name, typ), NULL); p = p->tail; } fields = h->tail; free(h); return Ty_Record(fields); } case A_arrayTy: { return Ty_Array(S_look(tenv, a->u.array)); } } }
struct expty transVar (S_table venv, S_table tenv, A_var v) { switch (v->kind) { case A_simpleVar: { E_enventry x = S_look (venv, v->u.simple); if (x && x->kind == E_varEntry) { return expTy (NULL, actual_ty (x->u.var.ty)); } else { EM_error (v->pos, "undefined variable %s", S_name (v->u.simple)); return expTy (NULL, Ty_Int()); } } case A_fieldVar: { struct expty var = transVar (venv, tenv, v->u.field.var); Ty_fieldList fList = var.ty->u.record; while (fList && fList->head->name != v->u.field.sym) { fList = fList->tail; } if (!fList) { EM_error (v->pos, "undefined subName %s", S_name (v->u.field.sym)); return expTy (NULL, Ty_Int()); } else { return expTy (NULL, actual_ty (fList->head->ty)); } } case A_subscriptVar: { struct expty var = transVar (venv, tenv, v->u.subscript.var); struct expty exp = transExp (venv, tenv, v->u.subscript.exp); if (exp.ty->kind != Ty_int) { EM_error (v->pos, "subscript should be int"); return expTy (NULL, Ty_Int()); } else { return expTy (NULL, actual_ty (var.ty->u.array)); } } } assert (0); }
struct expty transVar(S_table venv, S_table tenv, A_var v) { switch (v->kind) { case A_simpleVar: { E_enventry x = S_look(venv, v->u.simple); if (x && x->kind == E_varEntry) { return expTy(NULL, actual_ty(x->u.var.ty)); } EM_error(v->pos, (string)"undeclared variable '%s'", S_name(v->u.simple)); return expTy(NULL, Ty_Int()); } case A_fieldVar: { struct expty res = transVar(venv, tenv, v->u.field.var); Ty_ty ty = res.ty; if (ty->kind == Ty_record) { Ty_fieldList tfl = ty->u.record; for (tfl = ty->u.record; tfl; tfl = tfl->tail) { if (tfl->head->name == v->u.field.sym) { return expTy(NULL, actual_ty(tfl->head->ty)); } } EM_error(v->pos, "field '%s' not in record type", S_name(v->u.field.sym)); return expTy(NULL, Ty_Int()); } EM_error(v->pos, "variable not record"); return expTy(NULL, Ty_Int()); } case A_subscriptVar: { struct expty res = transVar(venv, tenv, v->u.subscript.var); struct expty index = transExp(venv, tenv, v->u.subscript.exp); Ty_ty ty = res.ty; if (ty->kind != Ty_array) { EM_error(v->pos, "variable not array"); return expTy(NULL, Ty_Int()); } if (index.ty->kind != Ty_int) { EM_error(v->pos, "array index error"); return expTy(NULL, Ty_Int()); } return expTy(NULL, actual_ty(ty->u.array)); } default: { assert(0); } } }
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)); }
struct expty transVar_simpleVar(Tr_level level, S_table venv, S_table tenv, A_var v, Temp_label breakk) { E_enventry x = S_look(venv, v->u.simple); if (!x || x->kind != E_varEntry) { EM_error(v->pos, "undeclared variable '%s'", S_name(v->u.simple)); return expTy(NULL, Ty_Int()); } return expTy(Tr_simpleVar(x->u.var.access, level), actual_ty(x->u.var.ty)); }
/* translate expression */ struct expty transExp(S_table venv, S_table tenv, A_exp e) { switch (e->kind) { case A_varExp: return transVar(venv, tenv, e->u.var); case A_nilExp: return ExpTy(NULL, Ty_Nil()); case A_intExp: return ExpTy(NULL, Ty_Int()); case A_stringExp: return ExpTy(NULL, Ty_String()); case A_callExp: return transCallExp(venv, tenv, e); case A_opExp: return transOpExp(venv, tenv, e); case A_recordExp: return transRecordExp(venv, tenv, e); case A_seqExp: return transSeqExp(venv, tenv, e->u.seq); case A_assignExp: return transAssignExp(venv, tenv, e); case A_ifExp: return transIfExp(venv, tenv, e); case A_whileExp: return transWhileExp(venv, tenv, e); case A_forExp: return transForExp(venv, tenv, e); case A_breakExp: return transBreakExp(venv, tenv, e); case A_letExp: return transLetExp(venv, tenv, e); case A_arrayExp: return transArrayExp(venv, tenv, e); } assert(0); }
/* for id := exp1 to exp2 do exp3 * 1. both exp1 and exp2 are integer type * 2. exp3 is void type * 3. id is a new variable implicitly declared by the for * statement, whose scope covers only exp3 */ struct expty transForExp(S_table venv, S_table tenv, A_exp e) { struct expty lo = transExp(venv, tenv, e->u.forr.lo); struct expty hi = transExp(venv, tenv, e->u.forr.hi); struct expty body; if (lo.ty != Ty_Int() || hi.ty != Ty_Int()) { EM_error(e->pos, "low or high range type is not integer"); } S_beginScope(venv); transDec(venv, tenv, A_VarDec(e->pos, e->u.forr.var, S_Symbol("int"), e->u.forr.lo)); body = transExp(venv, tenv, e->u.forr.body); if (body.ty != Ty_Void()) { EM_error(e->pos, "body of for is not void"); } S_endScope(venv); return ExpTy(NULL, Ty_Void()); }
/* while exp1 do exp2 * 1. exp1's type is integer * 2. exp2 produces no value */ struct expty transWhileExp(S_table venv, S_table tenv, A_exp e) { struct expty test = transExp(venv, tenv, e->u.whilee.test); struct expty body = transExp(venv, tenv, e->u.whilee.body); if (test.ty != Ty_Int()) { EM_error(e->pos, "test type of while is not integer"); } if (body.ty != Ty_Void()) { EM_error(e->pos, "body's type of while must be void"); } return ExpTy(NULL, Ty_Void()); }
static struct expty transVar(Tr_level level, S_table venv, S_table tenv, A_var v) { E_enventry x; struct expty et,et2; Ty_fieldList fl; switch (v->kind) { case A_simpleVar:/* var id (a)*/ x = S_look(venv, v->u.simple); if (x && x->kind == E_varEntry) { return expTy(NULL, actual_ty(x->u.var.ty)); } else { EM_error(v->pos, "undefined var %s", S_name(v->u.simple)); return expTy(NULL, Ty_Int()); } break; case A_fieldVar:/* var record (a.b)*/ et = transVar(level, venv, tenv, v->u.field.var); if (et.ty->kind != Ty_record) { EM_error(v->pos, "not a record type"); return expTy(NULL, Ty_Record(NULL)); } else { for (fl = et.ty->u.record; fl; fl = fl->tail) { if (fl->head->name == v->u.field.sym) { return expTy(NULL, actual_ty(fl->head->ty)); } } EM_error(v->pos, "no such field in record %s", S_name(v->u.field.sym)); } return expTy(NULL, Ty_Record(NULL)); break; case A_subscriptVar:/*var array (a[b])*/ et = transVar(level, venv, tenv, v->u.subscript.var); if (et.ty->kind != Ty_array) { EM_error(v->pos, "not a array type"); } else { et2 = transExp(level, venv, tenv, v->u.subscript.exp); if (et2.ty->kind != Ty_int) { EM_error(v->pos, "int required"); } else { return expTy(NULL, actual_ty(et.ty->u.array)); } } return expTy(NULL, Ty_Array(NULL)); default: assert(0); } }
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)); }
struct expty transExp_opExp(Tr_level level, S_table venv, S_table tenv, A_exp a, Temp_label breakk) { A_oper oper = a->u.op.oper; struct expty left = transExp(level, venv, tenv, a->u.op.left , breakk); struct expty right = transExp(level, venv, tenv, a->u.op.right, breakk); if (oper == A_plusOp || oper == A_minusOp || oper == A_timesOp || oper == A_divideOp || oper == A_ltOp || oper == A_leOp || oper == A_gtOp || oper == A_geOp) { if (left.ty->kind != Ty_int) EM_error(a->u.op.left->pos, "operate of incompatible types"); if (right.ty->kind != Ty_int) EM_error(a->u.op.right->pos, "operate of incompatible types"); } if (oper == A_eqOp || oper == A_neqOp) { if (left.ty->kind != right.ty->kind && !(left.ty->kind == Ty_nil && right.ty->kind == Ty_record) && !(left.ty->kind == Ty_record && right.ty->kind == Ty_nil)) EM_error(a->u.op.right->pos, "same type required"); } Tr_exp op_exp; switch (oper) { case A_plusOp: op_exp = Tr_addOpExp( left.exp, right.exp); break; case A_minusOp: op_exp = Tr_minusOpExp( left.exp, right.exp); break; case A_timesOp: op_exp = Tr_timesOpExp( left.exp, right.exp); break; case A_divideOp: op_exp = Tr_divideOpExp(left.exp, right.exp); break; case A_ltOp: op_exp = Tr_ltOpExp( left.exp, right.exp); break; case A_leOp: op_exp = Tr_leOpExp( left.exp, right.exp); break; case A_gtOp: op_exp = Tr_gtOpExp( left.exp, right.exp); break; case A_geOp: op_exp = Tr_geOpExp( left.exp, right.exp); break; case A_eqOp: if (left.ty->kind == Ty_string) op_exp = Tr_stringEqExp(left.exp, right.exp); else op_exp = Tr_eqExp( left.exp, right.exp);break; case A_neqOp: if (left.ty->kind == Ty_string) op_exp = Tr_stringNeExp(left.exp, right.exp); else op_exp = Tr_neqExp( left.exp, right.exp); break; } return expTy(op_exp, Ty_Int()); }
struct expty transExp(Tr_level level, S_table venv, S_table tenv, A_exp a, Temp_label breakk) { switch (a->kind) { case A_varExp: return transVar(level, venv, tenv, a->u.var, breakk); case A_nilExp: return expTy(Tr_nilExp(), Ty_Nil()); case A_intExp: return expTy(Tr_intExp(a->u.intt), Ty_Int()); case A_stringExp: return expTy(Tr_stringExp(a->u.stringg), Ty_String()); case A_breakExp: return expTy(Tr_breakExp(breakk), Ty_Void()); case A_callExp: return transExp_callExp( level, venv, tenv, a, breakk); case A_opExp: return transExp_opExp( level, venv, tenv, a, breakk); case A_recordExp: return transExp_recordExp(level, venv, tenv, a, breakk); case A_seqExp: return transExp_seqExp( level, venv, tenv, a, breakk); case A_assignExp: return transExp_assignExp(level, venv, tenv, a, breakk); case A_ifExp: return transExp_ifExp( level, venv, tenv, a, breakk); case A_whileExp: return transExp_whileExp( level, venv, tenv, a, breakk); case A_forExp: return transExp_forExp( level, venv, tenv, a, breakk); case A_letExp: return transExp_letExp( level, venv, tenv, a, breakk); case A_arrayExp: return transExp_arrayExp( level, venv, tenv, a, breakk); } assert(0); /* should have returned from some clause of the switch */ }
/* type-id[exp1] of exp2 * 1. type-id is array * 2. exp1 is integer */ struct expty transArrayExp(S_table venv, S_table tenv, A_exp e) { struct expty size = transExp(venv, tenv, e->u.array.size); struct expty init = transExp(venv, tenv, e->u.array.init); Ty_ty typ = S_look(tenv, e->u.array.typ); if (size.ty != Ty_Int()) { EM_error(e->pos, "type of array size is not integer"); } if (typ->kind != Ty_array) { EM_error(e->pos, "%s is not a array", S_name(e->u.array.typ)); } if (init.ty != typ->u.array) { EM_error(e->pos, "type of element of array mismatch"); } return ExpTy(NULL, typ); }
/* if exp1 then exp2 [else exp3] * 1. exp1 is integer type * 2. exp2 and exp3 are the same type if exp3 exists * 3. exp2 produce no value if exp3 does not exists */ struct expty transIfExp(S_table venv, S_table tenv, A_exp e) { struct expty test = transExp(venv, tenv, e->u.iff.test); struct expty then = transExp(venv, tenv, e->u.iff.then); if (test.ty != Ty_Int()) { EM_error(e->pos, "test exp of if is not integer"); } if (e->u.iff.elsee) { struct expty elsee = transExp(venv, tenv, e->u.iff.elsee); if (!Ty_is_compatible(then.ty, elsee.ty)) { EM_error(e->pos, "then and elsee type of if mismatch"); } return ExpTy(NULL, elsee.ty); } else { if (then.ty != Ty_Void()) { EM_error(e->pos, "then type of if is NOT void"); } return ExpTy(NULL, Ty_Void()); } }
struct expty transExp(S_table venv, S_table tenv, A_exp a) { /* S_beginScope(venv); */ /* S_beginScope(tenv); */ switch(a->kind) { case A_varExp: return transVar( venv , tenv , a->u.var ); break; case A_nilExp: return _expTy( NULL, Ty_Nil() ); break; case A_intExp: return _expTy( NULL, Ty_Int() ); break; case A_stringExp: return _expTy( NULL, Ty_String() ); break; case A_callExp: return transExpCall( venv, tenv, a ); break; case A_opExp: case A_recordExp: case A_seqExp: case A_assignExp: case A_ifExp: case A_whileExp: case A_forExp: case A_breakExp: case A_letExp: case A_arrayExp: //break; default: assert(0); } /* S_endScope(tenv); */ /* S_endScope(venv); */ }
static struct expty transExp(Tr_level level, S_table v, S_table t, A_exp e){ A_oper oper; struct expty left, right, final, final2, final3, final4, final5, lo, hi; A_expList list; A_decList decs; E_enventry callinfo; Ty_ty recty, arrayty; switch (e->kind) { case A_varExp: return transVar(level, v, t, e->u.var); case A_nilExp: return expTy(NULL, Ty_Nil()); case A_callExp: callinfo = S_look(v, e->u.call.func); /*get params and return from tenv*/ if (callinfo && callinfo->kind == E_funEntry){ if (args_match(level, v, t, e->u.call.args, callinfo->u.fun.formals, e)) {/*check params is matched*/ if (callinfo->u.fun.result) { return expTy(NULL, actual_ty(callinfo->u.fun.result)); } else { return expTy(NULL, Ty_Void()); } } } else { EM_error(e->pos, "undefined function %s\n", S_name(e->u.call.func)); } return expTy(NULL, Ty_Void()); case A_recordExp: recty = actual_ty(S_look(t, e->u.record.typ)); if (!recty) { /*cant find record-type in table tenv*/ EM_error(e->pos, "undefined type %s (debug recordExp)", S_name(e->u.record.typ)); } else { if (recty->kind != Ty_record){ EM_error(e->pos, "%s is not a record type", S_name(e->u.record.typ)); return expTy(NULL, Ty_Record(NULL)); } if (efields_match(level, v, t, recty, e)) {/*check record field is matched*/ return expTy(NULL, recty); } } return expTy(NULL, Ty_Record(NULL)); case A_arrayExp: arrayty = actual_ty(S_look(t, e->u.array.typ)); if (!arrayty) { EM_error(e->pos, "undeined array type %s", S_name(e->u.array.typ)); return expTy(NULL, Ty_Array(NULL)); } if (arrayty->kind != Ty_array) { EM_error(e->pos, "%s is not a array type", S_name(e->u.array.typ)); return expTy(NULL, Ty_Array(NULL)); } final2 = transExp(level, v, t, e->u.array.size); final3 = transExp(level, v, t, e->u.array.init); if (final2.ty->kind != Ty_int) { EM_error(e->pos, "array size should be int %s", S_name(e->u.array.typ)); } else if (!ty_match(final3.ty, arrayty->u.array)){ EM_error(e->pos, "unmatched array type in %s", S_name(e->u.array.typ)); } else { return expTy(NULL, arrayty); } return expTy(NULL, Ty_Array(NULL)); case A_seqExp: list = e->u.seq; if (!list) { return expTy(NULL, Ty_Void()); } while (list->tail) { transExp(level, v, t, list->head); list = list->tail; } return transExp(level, v, t, list->head); case A_whileExp: final = transExp(level, v, t, e->u.whilee.test); if (final.ty->kind != Ty_int) { EM_error(e->pos, "int required"); } transExp(level, v, t, e->u.whilee.body); return expTy(NULL, Ty_Void()); case A_assignExp: final4 = transVar(level, v, t, e->u.assign.var); final5 = transExp(level, v, t, e->u.assign.exp); if (!ty_match(final4.ty, final5.ty)) { EM_error(e->pos, "unmatched assign exp"); } return expTy(NULL, Ty_Void()); case A_breakExp: return expTy(NULL, Ty_Void()); case A_forExp: { struct expty lo = transExp(level, v, t, e->u.forr.lo); struct expty hi = transExp(level, v, t, e->u.forr.hi); struct expty body; if (lo.ty != Ty_Int() || hi.ty != Ty_Int()) { EM_error(e->pos, "low or high range type is not integer"); } S_beginScope(v); transDec(level, v, t, A_VarDec(e->pos, e->u.forr.var, S_Symbol("int"), e->u.forr.lo)); body = transExp(level, v, t, e->u.forr.body); S_endScope(v); return expTy(NULL, Ty_Void()); } case A_letExp: S_beginScope(v); S_beginScope(t); for (decs = e->u.let.decs; decs; decs = decs->tail) { transDec(level, v, t, decs->head); } final = transExp(level, v, t, e->u.let.body); S_endScope(v); S_endScope(t); return final; case A_opExp: oper = e->u.op.oper; left = transExp(level, v, t, e->u.op.left); right = transExp(level, v, t, e->u.op.right); if (0 <= oper && oper < 4) {/* check +,-,*,/ */ if (left.ty->kind != Ty_int && left.ty->kind != Ty_double){ EM_error(e->u.op.left->pos, "int or double required(op)"); } if (right.ty->kind != Ty_int && right.ty->kind != Ty_double) { EM_error(e->u.op.right->pos, "int or double required(op)"); } if (left.ty->kind == Ty_int && right.ty->kind == Ty_int && oper != 3) { return expTy(NULL, Ty_Int()); } else { /*TODO divide when return double when return int*/ /* return expTy(NULL, Ty_Int()); */ return expTy(NULL, Ty_Int()); } } else if (3 < oper && oper < 10) { if (oper == 4 || oper == 5) {/*check record type can be nil*/ if (left.ty->kind == Ty_record && right.ty->kind == Ty_nil) { return expTy(NULL, Ty_Int()); } if (left.ty->kind == Ty_nil && right.ty->kind == Ty_record) { return expTy(NULL, Ty_Int()); } } if(left.ty->kind != Ty_int && left.ty->kind != Ty_double && left.ty->kind != Ty_string){ EM_error(e->u.op.left->pos, "int or double or record-nil required"); } if (right.ty->kind != Ty_int && right.ty->kind != Ty_double && right.ty->kind !=Ty_string) { EM_error(e->u.op.right->pos, "int or double or record-nil required"); } return expTy(NULL, Ty_Int()); } else { assert(0); } case A_ifExp: final = transExp(level, v, t, e->u.iff.test); final2 = transExp(level, v, t, e->u.iff.then); if (e->u.iff.elsee) { /*no else-part*/ final3 = transExp(level, v, t, e->u.iff.elsee); if (final.ty->kind != Ty_int){ EM_error(e->u.iff.test->pos, "int required"); } else if(!ty_match(final2.ty, final3.ty)) {
struct expty transExp(S_table venv, S_table tenv, A_exp e) { if (e == NULL) { return expTy(NULL, Ty_Void()); } switch (e->kind) { case A_varExp: { return transVar(venv, tenv, e->u.var); } case A_nilExp: { return expTy(NULL, Ty_Nil()); } case A_intExp: { return expTy(NULL, Ty_Int()); } case A_stringExp: { return expTy(NULL, Ty_String()); } case A_callExp: { E_enventry fun = S_look(venv, e->u.call.func); if (fun == NULL || fun->kind == E_varEntry) { //EM_error(e->pos, "undefined function %s", S_name(e->u.call.func)); return expTy(NULL, Ty_Int()); } else { if (fun->u.fun.formals == NULL && e->u.call.args == NULL) { return expTy(NULL, actual_ty(fun->u.fun.result)); } else if (fun->u.fun.formals == NULL && e->u.call.args != NULL) { EM_error(e->pos, "incorrect function prototype %s", S_name(e->u.call.func) ); return expTy(NULL, actual_ty(fun->u.fun.result)); } else if (fun->u.fun.formals != NULL && e->u.call.args == NULL) { EM_error(e->pos, "incorrect function prototype %s", S_name(e->u.call.func) ); return expTy(NULL, actual_ty(fun->u.fun.result)); } else { return expTy(NULL, actual_ty(fun->u.fun.result)); } } } case A_opExp: { A_oper oper = e->u.op.oper; struct expty left = transExp(venv, tenv, e->u.op.left); struct expty right = transExp(venv, tenv, e->u.op.right); if (oper == A_plusOp || oper == A_minusOp || oper == A_timesOp || oper == A_divideOp) { if (left.ty->kind != Ty_int) EM_error(e->u.op.left->pos, "integer required"); if (right.ty->kind != Ty_int) EM_error(e->u.op.right->pos, "integer required"); return expTy(NULL, Ty_Int()); } else if (oper == A_eqOp || oper == A_neqOp) { if (left.ty->kind == Ty_int && right.ty->kind == Ty_int) { return expTy(NULL, Ty_Int()); } else if (left.ty->kind == Ty_string && right.ty->kind == Ty_string) { return expTy(NULL, Ty_Int()); } else if (left.ty->kind == Ty_record && right.ty->kind == Ty_record) { if (left.ty == right.ty) { return expTy(NULL, Ty_Int()); } else { EM_error(e->pos, "same record type required"); return expTy(NULL, Ty_Int()); } } else if (left.ty->kind == Ty_array && right.ty->kind == Ty_array) { if (left.ty == right.ty) { return expTy(NULL, Ty_Int()); } else { EM_error(e->pos, "same array type required"); return expTy(NULL, Ty_Int()); } } else if (left.ty->kind == Ty_record && right.ty->kind == Ty_nil) { return expTy(NULL, Ty_Int()); } else if (left.ty->kind == Ty_nil && right.ty->kind == Ty_record) { return expTy(NULL, Ty_Int()); } else { EM_error(e->pos, "type not match"); return expTy(NULL, Ty_Int()); } } else if (oper == A_ltOp || oper == A_leOp || oper == A_gtOp || oper == A_geOp) { if (left.ty->kind == Ty_int && right.ty->kind == Ty_int) { return expTy(NULL, Ty_Int()); } else { EM_error(e->pos, "type not match"); return expTy(NULL, Ty_Int()); } } } case A_recordExp: { Ty_ty ty = S_look(tenv, e->u.record.typ); if (ty != NULL) { ty = actual_ty(ty); } if (ty == NULL || ty->kind != Ty_record) { EM_error(e->pos, "undefined record type %s", S_name(e->u.record.typ)); return expTy(NULL, Ty_Nil()); } else { Ty_fieldList fieldList = ty->u.record; A_efieldList efieldList = e->u.record.fields; while (fieldList != NULL && efieldList != NULL) { if (fieldList->head->name != efieldList->head->name) { EM_error(e->pos, "record field not match"); return expTy(NULL, Ty_Nil()); } struct expty res = transExp(venv, tenv, efieldList->head->exp); Ty_ty fieldty = actual_ty(fieldList->head->ty); if (fieldty->kind == Ty_record && res.ty->kind == Ty_nil) { } else if (fieldty->kind == Ty_record && res.ty->kind == Ty_record) { if (fieldty == res.ty) { } else { EM_error(e->pos, "record field not match"); return expTy(NULL, Ty_Nil()); } } else if (fieldty->kind == Ty_array && res.ty->kind == Ty_array) { if (fieldty == res.ty) { } else { EM_error(e->pos, "record field not match"); return expTy(NULL, Ty_Nil()); } } else { if (fieldty->kind != res.ty->kind) { EM_error(e->pos, "record field not match"); return expTy(NULL, Ty_Nil()); } } fieldList = fieldList->tail; efieldList = efieldList->tail; } if (fieldList != NULL && efieldList != NULL) { EM_error(e->pos, "record field not match"); return expTy(NULL, Ty_Nil()); } } return expTy(NULL, ty); } case A_seqExp: { if (e->u.seq == NULL) { return expTy(NULL, Ty_Void()); } else { return expTy(NULL, transExp(venv, tenv, e->u.seq->head).ty); } } case A_assignExp: { struct expty left = transVar(venv, tenv, e->u.assign.var); struct expty right = transExp(venv, tenv, e->u.assign.exp); if (left.ty->kind == Ty_nil) { if (right.ty->kind == Ty_nil) { return expTy(NULL, Ty_Void()); } else if (right.ty->kind == Ty_record && left.ty == right.ty) { return expTy(NULL, Ty_Void()); } else { EM_error(e->pos, "type not match"); return expTy(NULL, Ty_Void()); } } else if (left.ty->kind == Ty_array) { if (right.ty->kind == Ty_array && left.ty == right.ty) { return expTy(NULL, Ty_Void()); } else { EM_error(e->pos, "type not match"); return expTy(NULL, Ty_Void()); } } else if (left.ty->kind == right.ty->kind) { return expTy(NULL, Ty_Void()); } else { EM_error(e->pos, "type not match"); return expTy(NULL, Ty_Void()); } } case A_ifExp: { struct expty test = transExp(venv, tenv, e->u.iff.test); if (test.ty->kind != Ty_int) { EM_error(e->pos, "if-else clause integer test required"); return expTy(NULL, Ty_Void()); } else { struct expty then = transExp(venv, tenv, e->u.iff.then); if (e->u.iff.elsee == NULL) { if (then.ty->kind != Ty_void) { EM_error(e->pos, "if-then clause void then required"); return expTy(NULL, Ty_Void()); } else { return expTy(NULL, Ty_Void()); } } else { struct expty elsee = transExp(venv, tenv, e->u.iff.elsee); if (then.ty->kind == Ty_record) { if (elsee.ty->kind == Ty_record && then.ty == elsee.ty) { return expTy(NULL, then.ty); } else if (elsee.ty->kind == Ty_nil) { return expTy(NULL, then.ty); } } else if (then.ty->kind == Ty_nil && elsee.ty->kind == Ty_record) { return expTy(NULL, elsee.ty); } else if (then.ty->kind == Ty_array && elsee.ty->kind == Ty_array) { if (then.ty == elsee.ty) { return expTy(NULL, then.ty); } else { EM_error(e->pos, "then and else type not match"); return expTy(NULL, Ty_Void()); } } else if (then.ty->kind == elsee.ty->kind) { return expTy(NULL, then.ty); } else { EM_error(e->pos, "then and else type not match"); return expTy(NULL, Ty_Void()); } } } } case A_whileExp: { struct expty test = transExp(venv, tenv, e->u.whilee.test); struct expty body = transExp(venv, tenv, e->u.whilee.body); if (test.ty->kind != Ty_int) { EM_error(e->pos, "test clause integer required"); return expTy(NULL, Ty_Void()); } else { if (body.ty->kind != Ty_void) { //EM_error(e->pos, "while clause must produce no value"); return expTy(NULL, Ty_Void()); } else { return expTy(NULL, Ty_Void()); } } } case A_forExp: { struct expty lo = transExp(venv, tenv, e->u.forr.lo); struct expty hi = transExp(venv, tenv, e->u.forr.hi); if (lo.ty->kind != Ty_int || hi.ty->kind != Ty_int) { EM_error(e->pos, "for clause lo and hi integer required"); return expTy(NULL, Ty_Void()); } else { struct expty body = transExp(venv, tenv, e->u.forr.body); if (body.ty->kind != Ty_void) { EM_error(e->pos, "for clause body no-value required"); return expTy(NULL, Ty_Void()); } else { return expTy(NULL, Ty_Void()); } } } case A_breakExp: { return expTy(NULL, Ty_Void()); } case A_letExp: { //S_beginScope(venv); //S_beginScope(tenv); struct expty exp = transExp(venv, tenv, e->u.let.body); //S_endScope(tenv); //S_endScope(venv); return expTy(NULL, exp.ty); } case A_arrayExp: { struct expty size = transExp(venv, tenv, e->u.array.size); struct expty init = transExp(venv, tenv, e->u.array.init); Ty_ty ty = actual_ty(S_look(tenv, e->u.array.typ)); if (ty == NULL || ty->kind != Ty_array) { //EM_error(e->pos, "undefined array type %s", S_name(e->u.array.typ)); return expTy(NULL, Ty_Void()); } Ty_ty ty2 = actual_ty(ty->u.array); if (size.ty->kind != Ty_int) { EM_error(e->pos, "size int value required"); return expTy(NULL, actual_ty(ty)); } else if (ty2->kind == Ty_record) { if ((init.ty->kind == Ty_nil) || (init.ty->kind == Ty_record && ty2 == init.ty)) { return expTy(NULL, ty); } else { EM_error(e->pos, "array init fail:type not match"); return expTy(NULL, ty); } } else if(ty2->kind == Ty_array) { if (init.ty->kind == Ty_array && ty2 == init.ty) { return expTy(NULL, ty); } else { EM_error(e->pos, "array init fail:type not match"); return expTy(NULL, ty); } } else if (ty2->kind == init.ty->kind) { return expTy(NULL, ty); } else { EM_error(e->pos, "array init fail:type not match"); return expTy(NULL, ty); } } default: { assert(0); } } }
struct expty transExp(S_table venv, S_table tenv, A_exp e) { if (e == NULL) { return expTy(NULL, Ty_Void()); } switch (e->kind) { case A_varExp: { return transVar(venv, tenv, e->u.var); } case A_nilExp: { return expTy(NULL, Ty_Nil()); } case A_intExp: { return expTy(NULL, Ty_Int()); } case A_stringExp: { return expTy(NULL, Ty_String()); } case A_callExp: { E_enventry fun = (E_enventry)S_look(venv, e->u.call.func); if (!fun || fun->kind == E_varEntry) { EM_error(e->pos, (string)"undefined function '%s'", S_name(e->u.call.func)); return expTy(NULL, Ty_Int()); } if ((!fun->u.fun.formals && e->u.call.args) || (fun->u.fun.formals && !e->u.call.args)) { EM_error(e->pos, (string)"incorrect function prototype '%s'", S_name(e->u.call.func)); return expTy(NULL, Ty_Int()); } Ty_tyList ttl; A_expList el; for (ttl = fun->u.fun.formals, el = e->u.call.args; ttl || el; ttl = ttl->tail, el = el->tail) { if (ttl && !el) { EM_error(e->pos, (string)"formals are more than actuals"); return expTy(NULL, Ty_Int()); } if (!ttl && el) { EM_error(e->pos, (string)"formals are less than actuals"); return expTy(NULL, Ty_Int()); } struct expty arg = transExp(venv, tenv, el->head); if (actual_ty(ttl->head)->kind != actual_ty(arg.ty)->kind) { EM_error(e->pos, (string)"formals and actuals have different types"); return expTy(NULL, Ty_Int()); } } if (!fun->u.fun.result) { return expTy(NULL, Ty_Void()); } return expTy(NULL, actual_ty(fun->u.fun.result)); } case A_opExp: { A_oper oper = e->u.op.oper; struct expty left = transExp(venv, tenv, e->u.op.left); struct expty right = transExp(venv, tenv, e->u.op.right); if (oper == A_plusOp || oper == A_minusOp || oper == A_timesOp || oper == A_divideOp) { if (left.ty->kind != Ty_int || right.ty->kind != Ty_int) { EM_error(e->u.op.left->pos, (string)"integer required"); return expTy(NULL, Ty_Int()); } return expTy(NULL, Ty_Int()); } if (oper == A_eqOp || oper == A_neqOp) { if (isSameTy(left.ty, right.ty)) { return expTy(NULL, Ty_Int()); } EM_error(e->pos, (string)"same type required"); return expTy(NULL, Ty_Int()); } if (oper == A_ltOp || oper == A_leOp || oper == A_gtOp || oper == A_geOp) { if (left.ty->kind == Ty_int && right.ty->kind == Ty_int) { return expTy(NULL, Ty_Int()); } if (left.ty->kind == Ty_string && right.ty->kind == Ty_string) { return expTy(NULL, Ty_Int()); } EM_error(e->pos, "comparison of incompatible type"); return expTy(NULL, Ty_Int()); } assert(0); } case A_recordExp: { Ty_ty ty = (Ty_ty)S_look(tenv, e->u.record.typ); if (!ty) { EM_error(e->pos, "undefined record type '%s'", S_name(e->u.record.typ)); return expTy(NULL, Ty_Nil()); } ty = actual_ty(ty); if (ty->kind != Ty_record) { EM_error(e->pos, "'%s' is not a record", S_name(e->u.record.typ)); } else { Ty_fieldList tfl; A_efieldList efl; for (tfl = ty->u.record, efl = e->u.record.fields; tfl || efl; tfl = tfl->tail, efl = efl->tail) { if (tfl && !efl) { EM_error(e->pos, "record field is less than need"); return expTy(NULL, Ty_Nil()); } if (!tfl && efl) { EM_error(e->pos, "record field is more than need"); return expTy(NULL, Ty_Nil()); } if (tfl->head->name != efl->head->name) { EM_error(e->pos, "record field mismatch"); return expTy(NULL, Ty_Nil()); } struct expty res = transExp(venv, tenv, efl->head->exp); Ty_ty fieldty = actual_ty(tfl->head->ty); if (!isSameTy(fieldty, res.ty)) { EM_error(e->pos, (string)"record field mismatch"); return expTy(NULL, Ty_Nil()); } } } return expTy(NULL, ty); } case A_seqExp: { A_expList el = e->u.seq; if (el) { while (el->tail) { transExp(venv, tenv, el->head); el = el->tail; } return expTy(NULL, transExp(venv, tenv, el->head).ty); } return expTy(NULL, Ty_Void()); } case A_assignExp: { struct expty left = transVar(venv, tenv, e->u.assign.var); struct expty right = transExp(venv, tenv, e->u.assign.exp); if (isSameTy(left.ty, right.ty)) { return expTy(NULL, Ty_Void()); } EM_error(e->pos, "type mismatch"); return expTy(NULL, Ty_Void()); } case A_ifExp: { struct expty test = transExp(venv, tenv, e->u.iff.test); if (test.ty->kind != Ty_int) { EM_error(e->pos, "if-else clause integer test required"); return expTy(NULL, Ty_Void()); } struct expty then = transExp(venv, tenv, e->u.iff.then); if (e->u.iff.elsee == NULL) { if (then.ty->kind != Ty_void) { EM_error(e->pos, "if-then returns non unit"); return expTy(NULL, Ty_Void()); } return expTy(NULL, Ty_Void()); } struct expty elsee = transExp(venv, tenv, e->u.iff.elsee); if (isSameTy(then.ty, elsee.ty)) { return expTy(NULL, then.ty); } EM_error(e->pos, "types of then - else differ"); return expTy(NULL, Ty_Void()); } case A_whileExp: { struct expty test = transExp(venv, tenv, e->u.whilee.test); struct expty body = transExp(venv, tenv, e->u.whilee.body); if (test.ty->kind != Ty_int) { EM_error(e->pos, "test clause integer required"); return expTy(NULL, Ty_Void()); } if (body.ty->kind != Ty_void) { EM_error(e->pos, "body of while not void"); return expTy(NULL, Ty_Void()); } return expTy(NULL, Ty_Void()); } case A_forExp: { struct expty lo = transExp(venv, tenv, e->u.forr.lo); struct expty hi = transExp(venv, tenv, e->u.forr.hi); if (lo.ty->kind != Ty_int || hi.ty->kind != Ty_int) { EM_error(e->pos, "for clause lo and hi integer required"); return expTy(NULL, Ty_Void()); } S_beginScope(venv); if (!S_look(venv, e->u.forr.var)) { S_enter(venv, e->u.forr.var, E_VarEntry(Ty_Int())); } struct expty body = transExp(venv, tenv, e->u.forr.body); S_endScope(venv); if (body.ty->kind != Ty_void) { EM_error(e->pos, "for clause body no-value required"); return expTy(NULL, Ty_Void()); } return expTy(NULL, Ty_Void()); } case A_breakExp: { return expTy(NULL, Ty_Void()); } case A_letExp: { A_decList d; S_beginScope(venv); S_beginScope(tenv); for (d = e->u.let.decs; d; d = d->tail) { transDec(venv, tenv, d->head); } struct expty exp = transExp(venv, tenv, e->u.let.body); S_endScope(venv); S_endScope(tenv); return exp; } case A_arrayExp: { struct expty size = transExp(venv, tenv, e->u.array.size); struct expty init = transExp(venv, tenv, e->u.array.init); Ty_ty ty = (Ty_ty)S_look(tenv, e->u.array.typ); if (!ty) { EM_error(e->pos, "undefined array type '%s'", S_name(e->u.array.typ)); return expTy(NULL, Ty_Void()); } ty = actual_ty(ty); if (ty->kind != Ty_array) { EM_error(e->pos, "'%s' is not a array", S_name(e->u.array.typ)); return expTy(NULL, Ty_Void()); } if (size.ty->kind != Ty_int) { EM_error(e->pos, "size int value required"); return expTy(NULL, actual_ty(ty)); } Ty_ty ty2 = actual_ty(ty->u.array); if (!isSameTy(ty2, init.ty)) { EM_error(e->pos, "initializing exp and array type differ"); return expTy(NULL, Ty_Void()); } return expTy(NULL, ty); } default: { assert(0); } } }
Ty_ty transTy(S_table tenv, A_ty a) { assert(a != NULL); switch(a->kind) { case A_nameTy: { Ty_ty ty = S_look(tenv, a->u.name); if(ty != NULL) { return ty; } else { //EM_error(a->pos, "undefined type %s", S_name(a->u.name)); return Ty_Int(); } } case A_recordTy: { Ty_ty ty,ty2; Ty_fieldList fields,tailptr; A_fieldList afields; if(a->u.record == NULL) { fields = NULL; ty = Ty_Record(fields); return ty; } else { fields = tailptr = NULL; afields = a->u.record; while(afields != NULL) { ty2 = S_look(tenv, afields->head->typ); if(ty2 != NULL) { if(fields == NULL) { fields = Ty_FieldList(Ty_Field(afields->head->name, ty2), NULL); tailptr = fields; } else { tailptr->tail = Ty_FieldList(Ty_Field(afields->head->name, ty2), NULL); tailptr = tailptr->tail; } } else { //EM_error(a->pos, "undefined field type"); return Ty_Int(); } afields = afields->tail; } ty = Ty_Record(fields); return ty; } } case A_arrayTy: { Ty_ty ty; ty = S_look(tenv, a->u.array); if(ty != NULL) { return Ty_Array(ty); } else { //EM_error(a->pos, "undefined type %s", S_name(a->u.array)); return Ty_Int(); } } default: { assert(0); } } }
struct expty transExp (S_table venv, S_table tenv, A_exp a) { switch (a->kind) { case A_opExp: { A_oper oper = a->u.op.oper; struct expty left = transExp (venv, tenv, a->u.op.left); struct expty right = transExp (venv, tenv, a->u.op.right); if (oper == A_plusOp || oper == A_minusOp || oper == A_timesOp || oper == A_divideOp) { if (left.ty->kind != Ty_int) { EM_error (a->u.op.left->pos, "integer required"); } if (right.ty->kind != Ty_int) { EM_error (a->u.op.right->pos, "integer required"); } } else { if (left.ty->kind != right.ty->kind) { EM_error (a->u.op.right->pos, "left type should be same as right"); } } return expTy (NULL, Ty_Int()); } case A_varExp: { return transVar (venv, tenv, a->u.var); } case A_nilExp: { return expTy (NULL, Ty_Nil()); } case A_intExp: { return expTy (NULL, Ty_Int()); } case A_stringExp: { return expTy (NULL, Ty_String()); } case A_callExp: { E_enventry x = S_look (venv, a->u.call.func); if (x && x->kind == E_funEntry) { Ty_tyList tList; A_expList eList; for (tList = x->u.fun.formals, eList = a->u.call.args; tList && eList; tList = tList->tail, eList = eList->tail) { Ty_ty expTyName = transExp (venv, tenv, eList->head).ty; if (tList->head->kind != expTyName->kind) { if (tList->head->kind == Ty_record && expTyName->kind == Ty_nil) { continue; } EM_error (eList->head->pos, "field type is wrong"); return expTy (NULL, Ty_Int()); } } if (tList || eList) { EM_error (a->u.call.args->head->pos, "field type number is wrong"); return expTy (NULL, Ty_Int()); } return expTy (NULL, x->u.fun.result); } EM_error (a->pos, "undefined function name %s", S_name (a->u.call.func)); return expTy (NULL, Ty_Int()); } case A_recordExp: { Ty_ty record = S_look (tenv, a->u.record.typ); if (!record) { EM_error (a->pos, "undefined record type %s", S_name (a->u.record.typ)); return expTy (NULL, record); } if (record->kind != Ty_record) { EM_error (a->pos, "type should be an record"); return expTy (NULL, Ty_Int()); } else { A_efieldList efieldList = NULL; Ty_fieldList fieldList = record->u.record; for (efieldList = a->u.record.fields; efieldList && fieldList; efieldList = efieldList->tail, fieldList = fieldList->tail) { Ty_ty field = actual_ty(fieldList->head->ty); Ty_ty expTyName = transExp (venv, tenv, efieldList->head->exp).ty; if (field->kind != expTyName->kind) { if (field->kind == Ty_record && expTyName->kind == Ty_nil) { continue; } EM_error (a->pos, "field type wrong"); } } if (efieldList || fieldList) { EM_error (a->pos, "field number wrong"); } return expTy (NULL, record); } } case A_arrayExp: { Ty_ty array = S_look (tenv, a->u.array.typ); if (!array) { EM_error (a->pos, "undefined array type %s", S_name (a->u.array.typ)); return expTy (NULL, array); } if (array->kind != Ty_array) { EM_error (a->pos, "type should be an array"); return expTy (NULL, Ty_Int()); } else { if (transExp (venv, tenv, a->u.array.size).ty->kind != Ty_int) { EM_error (a->pos, "array size should be int"); } if (transExp (venv, tenv, a->u.array.init).ty->kind != array->u.array->kind) { EM_error (a->pos, "array type should be same as init"); } return expTy (NULL, array); } } case A_seqExp: { A_expList d; for (d = a->u.seq; d && d->tail; d = d->tail) { transExp (venv, tenv, d->head); } if (d) { return transExp (venv, tenv, d->head); } else { return expTy (NULL, Ty_Void()); } } case A_assignExp: { transVar (venv, tenv, a->u.assign.var); transExp (venv, tenv, a->u.assign.exp); return expTy (NULL, Ty_Void()); } case A_ifExp: { transExp (venv, tenv, a->u.iff.test); if (a->u.iff.elsee) { struct expty then = transExp (venv, tenv, a->u.iff.then); struct expty elsee = transExp (venv, tenv, a->u.iff.elsee); if (then.ty->kind != elsee.ty->kind) { EM_error (a->u.iff.elsee->pos, "then should be same as else"); } return then; } else { struct expty then = transExp (venv, tenv, a->u.iff.then); if (then.ty->kind != Ty_void) { EM_error (a->u.iff.then->pos, "then should be void"); } return expTy (NULL, Ty_Void()); } } case A_whileExp: { transExp (venv, tenv, a->u.whilee.test); struct expty body = transExp (venv, tenv, a->u.whilee.body); if (body.ty->kind != Ty_void) { EM_error (a->u.whilee.body->pos, "body of while error, it should return void"); } return expTy (NULL, Ty_Void()); } case A_forExp: { S_enter (venv, a->u.forr.var, E_VarEntry (Ty_Int())); struct expty lo = transExp (venv, tenv, a->u.forr.lo); struct expty hi = transExp (venv, tenv, a->u.forr.hi); if (lo.ty->kind != Ty_int) { EM_error (a->u.forr.lo->pos, "lo exp of for should be int"); } if (hi.ty->kind != Ty_int) { EM_error(a->u.forr.hi->pos, "hi exp of for should be int"); } S_beginScope (venv); //if (a->u.forr.body->kind == A_seqExp) { // A_expList test = a->u.forr.body->u.seq; // while (test) { // if (test->head->kind == A_assignExp) { // } // } //} struct expty body = transExp (venv, tenv, a->u.forr.body); if (body.ty->kind != Ty_void) { EM_error (a->u.forr.body->pos, "body of for error, it should return void"); } S_endScope(venv); return expTy (NULL, Ty_Void()); } case A_breakExp: { return expTy (NULL, Ty_Void()); } case A_letExp: { struct expty exp; A_decList d; S_beginScope (venv); S_beginScope (tenv); for (d = a->u.let.decs; d; d = d->tail) { transDec (venv, tenv, d->head); } exp = transExp (venv, tenv, a->u.let.body); S_endScope (tenv); S_endScope (venv); return exp; } } assert (0); }
//here static struct expty transExp(Tr_level level,Tr_exp breakk,S_table v, S_table t, A_exp e){ A_oper oper; struct expty left,right,final,final2,final3,final4,final5,lo,hi; A_expList list; A_decList decs; E_enventry callinfo; Ty_ty recty,arrayty; if (!e) { return expTy(Tr_noExp(), Ty_Void()); } switch(e->kind){ case A_varExp: return transVar(level,breakk,v,t,e->u.var); break; case A_nilExp: return expTy(Tr_nilExp(),Ty_Nil()); break; case A_callExp: callinfo =S_look(v,e->u.call.func); A_expList args=NULL; Tr_expList argList=NULL; for (args=e->u.call.args;args;args=args->tail){ struct expty arg = transExp(level, breakk, v, t, args->head); Tr_expList_prepend(arg.exp, &argList); } Tr_exp trans = Tr_noExp(); if (callinfo&&callinfo->kind==E_funEntry) { trans = Tr_callExp(callinfo->u.fun.label, callinfo->u.fun.level, level, &argList); //检查参数个数、类型匹配 if (args_match(level, breakk, v, t, e->u.call.args, callinfo->u.fun.formals, e)) {/*check params is matched*/ if (callinfo->u.fun.result) { return expTy(trans, actual_ty(callinfo->u.fun.result)); } } /* if (args_match(level,v,t,e->u.call.args,callinfo->u.fun.formals,e)){ return expTy(NULL, actual_ty(callinfo->u.fun.result)); }else{ return expTy(NULL, Ty_Void()); } */ }else { EM_error(e->pos, "undefined function %s\n", S_name(e->u.call.func)); } return expTy(trans, Ty_Void()); break; case A_recordExp: recty = actual_ty(S_look(t, e->u.record.typ)); if (!recty) { /*cant find record-type in table tenv*/ EM_error(e->pos, "undefined type %s (debug recordExp)", S_name(e->u.record.typ)); }else{ if (recty->kind != Ty_record){ EM_error(e->pos, "%s is not a record type", S_name(e->u.record.typ)); return expTy(Tr_noExp(), Ty_Record(NULL)); } if (efields_match(level,breakk,v, t, recty, e)) {/*check record field is matched*/ Tr_expList l=NULL; int n=0; A_efieldList el; for (el=e->u.record.fields;el;el=el->tail,n++){ struct expty val = transExp(level, breakk, v, t, el->head->exp); Tr_expList_prepend(val.exp,&l); } return expTy(Tr_recordExp(n, l), recty); } } return expTy(Tr_noExp(), Ty_Record(NULL)); break; case A_arrayExp: arrayty=actual_ty(S_look(t,e->u.array.typ)); if (!arrayty) { EM_error(e->pos, "undeined array type %s", S_name(e->u.array.typ)); return expTy(Tr_noExp(), Ty_Array(NULL)); } if (arrayty->kind != Ty_array) { EM_error(e->pos, "%s is not a array type", S_name(e->u.array.typ)); return expTy(Tr_noExp(), Ty_Array(NULL)); } final2 = transExp(level,breakk,v, t, e->u.array.size);//数组大小 表达式 final3 = transExp(level,breakk,v, t, e->u.array.init);//数组初始化 表达式 if (final2.ty->kind != Ty_int) { EM_error(e->pos, "array size should be int %s", S_name(e->u.array.typ)); }else if (!ty_match(final3.ty, arrayty->u.array)){ EM_error(e->pos, "unmatched array type in %s", S_name(e->u.array.typ)); } else { return expTy(Tr_arrayExp(final2.exp, final3.exp), arrayty); } return expTy(Tr_noExp(), Ty_Int()); break; case A_seqExp:{ Tr_expList l = NULL; list = e->u.seq; struct expty seqone; if (!list) { return expTy(Tr_noExp(), Ty_Void()); } /*while (list->tail) { seqone= transExp(level,breakk,v, t, list->head); Tr_expList_prepend(seqone.exp, &l); list = list->tail; } */ for (; list; list = list->tail) { seqone = transExp(level, breakk, v, t, list->head); Tr_expList_prepend(seqone.exp, &l); } printf("A_seqExp\n"); return expTy(Tr_seqExp(l), seqone.ty); } break; case A_whileExp: final = transExp(level,breakk,v, t, e->u.whilee.test); if (final.ty->kind != Ty_int) { EM_error(e->pos, "int required"); } Tr_exp done = Tr_doneExp(); struct expty body=transExp(level,done,v, t, e->u.whilee.body); return expTy(Tr_whileExp(final.exp, body.exp, done), Ty_Void()); break; case A_assignExp: final4 = transVar(level,breakk,v, t, e->u.assign.var); final5 = transExp(level,breakk,v, t, e->u.assign.exp); if (!ty_match(final4.ty, final5.ty)) { EM_error(e->pos, "unmatched assign exp"); } return expTy(Tr_assignExp(final4.exp, final5.exp), Ty_Void()); case A_breakExp: if (!breakk) return expTy(Tr_noExp(), Ty_Void()); return expTy(Tr_breakExp(breakk), Ty_Void()); case A_forExp:{ /* struct expty lo = transExp(level,v, t, e->u.forr.lo); struct expty hi = transExp(level,v, t, e->u.forr.hi); struct expty body; if (lo.ty != Ty_Int() || hi.ty != Ty_Int()) { EM_error(e->pos, "low or high range type is not integer"); } S_beginScope(v); transDec(level,v, t, A_VarDec(e->pos, e->u.forr.var, S_Symbol("int"), e->u.forr.lo)); body = transExp(level,v, t, e->u.forr.body); S_endScope(v); return expTy(NULL, Ty_Void()); */ EM_error(e->pos, "\nsome one said for is better than while\nmake them unhappy \nahahaha"); return expTy(Tr_noExp(), Ty_Int()); } break; case A_letExp:{ Tr_expList l = NULL; S_beginScope(v); S_beginScope(t); for (decs=e->u.let.decs;decs;decs=decs->tail){ //transDec(level,v,t,decs->head); ; Tr_expList_prepend(transDec(level, breakk, v, t, decs->head), &l); } final=transExp(level,breakk,v,t,e->u.let.body); Tr_expList_prepend(final.exp, &l); S_endScope(t); S_endScope(v); printf("A_letExp\n"); return expTy(Tr_seqExp(l), final.ty);; } break; case A_opExp:{ A_oper oper = e->u.op.oper; struct expty left = transExp(level, breakk, v, t, e->u.op.left); struct expty right = transExp(level, breakk, v, t, e->u.op.right); if (0 <= oper && oper < 4) {/* check +,-,*,/ */ if (left.ty->kind != Ty_int ){ EM_error(e->u.op.left->pos, "int or double required(op)"); } else if (left.ty->kind == Ty_int && right.ty->kind == Ty_int) { return expTy(Tr_arithExp(oper, left.exp, right.exp), Ty_Int()); } return expTy(Tr_noExp(), Ty_Int()); } else if (3 < oper && oper < 10) { Tr_exp translation = Tr_noExp(); if (oper == 4 || oper == 5) {/*check record type can be nil(=, <>)*/ switch(left.ty->kind) { case Ty_int: //case Ty_double:/*see is double query like int TODO*/ if (right.ty->kind == Ty_int ) translation = Tr_eqExp(oper, left.exp, right.exp); else {EM_error(e->u.op.right->pos, "unexpected type in comparsion");} break; case Ty_string: if (ty_match(right.ty, left.ty)) translation = Tr_eqStringExp(oper, left.exp, right.exp); else {EM_error(e->u.op.right->pos, "unexpected type in comparsion");} break; case Ty_array: if (ty_match(right.ty, left.ty)) translation = Tr_eqRef(oper, left.exp, right.exp); else {EM_error(e->u.op.right->pos, "unexpected type in comparsion");} break; case Ty_record: if (ty_match(right.ty, left.ty) || right.ty->kind == Ty_nil) translation = Tr_eqRef(oper, left.exp, right.exp); else {EM_error(e->u.op.right->pos, "unexpected type in comparsion");} break; default: EM_error(e->u.op.right->pos, "unexpected expression in comparsion"); } return expTy(translation, Ty_Int()); } else { switch(left.ty->kind) { //case Ty_double: case Ty_int: if ( right.ty->kind == Ty_int) translation = Tr_relExp(oper, left.exp, right.exp); else {EM_error(e->u.op.right->pos, "unexpected type in comparsion");} break; case Ty_string: if (right.ty->kind == Ty_string) translation = Tr_eqStringExp(oper, left.exp, right.exp); else {EM_error(e->u.op.right->pos, "unexpected type in comparsion");} break; default: EM_error(e->u.op.right->pos, "unexpected type in comparsion"); } return expTy(translation, Ty_Int()); } } else { assert(0); } } break; case A_ifExp: final = transExp(level,breakk,v, t, e->u.iff.test); final2 = transExp(level,breakk,v, t, e->u.iff.then); //final3 = {NULL, NULL}; if (e->u.iff.elsee) { /*no else-part*/ final3 = transExp(level,breakk,v, t, e->u.iff.elsee); if (final.ty->kind != Ty_int){ EM_error(e->u.iff.test->pos, "int required"); } else if(!ty_match(final2.ty, final3.ty)) {
static struct expty transExp(Tr_level level, Tr_exp breakk, S_table v, S_table t, A_exp e){ if (!e) { return expTy(Tr_noExp(), Ty_Void()); } switch (e->kind) { case A_varExp: return transVar(level, breakk, v, t, e->u.var); case A_nilExp: return expTy(Tr_nilExp(), Ty_Nil()); case A_callExp: { E_enventry callinfo = S_look(v, e->u.call.func); /*get params and return from tenv*/ A_expList args = NULL; Tr_expList argList = NULL; Ty_tyList formals; Tr_exp trans = Tr_noExp(); if (callinfo && callinfo->kind == E_funEntry){ formals = callinfo->u.fun.formals; /* if (args_match(level, breakk, v, t, e->u.call.args, callinfo->u.fun.formals, e)) {//check params is matched if (callinfo->u.fun.result) { return expTy(trans, actual_ty(callinfo->u.fun.result)); } }*/ for (args = e->u.call.args; args && formals; args = args->tail, formals = formals->tail) { /*memory args-info by order*/ struct expty arg = transExp(level, breakk, v, t, args->head); if (!ty_match(arg.ty, formals->head)) EM_error(args->head->pos, "unmatched type in function %s", S_name(e->u.call.func)); Tr_expList_prepend(arg.exp, &argList); } if (!args && formals) EM_error(e->pos, "short few paras"); if (args && !formals) EM_error(e->pos, "too many paras"); trans = Tr_callExp(callinfo->u.fun.label, callinfo->u.fun.level, level, &argList); return expTy(trans, actual_ty(callinfo->u.fun.result)); } else { EM_error(e->pos, "undefined function %s\n", S_name(e->u.call.func)); return expTy(trans, Ty_Int()); } } case A_recordExp: {/*record create*/ Ty_ty recty = actual_ty(S_look(t, e->u.record.typ)); if (!recty) { /*cant find record-type in table tenv*/ EM_error(e->pos, "undefined type %s (debug recordExp)", S_name(e->u.record.typ)); } else { if (recty->kind != Ty_record){ EM_error(e->pos, "%s is not a record type", S_name(e->u.record.typ)); return expTy(Tr_noExp(), Ty_Record(NULL)); } /* if (efields_match(level, breakk, v, t, recty, e)) {//check record field is matched Tr_expList l = NULL; int n = 0; A_efieldList el; for (el = e->u.record.fields; el; el = el->tail, n++) { struct expty val = transExp(level, breakk, v, t, el->head->exp); Tr_expList_prepend(val.exp, &l); } return expTy(Tr_recordExp(n, l), recty); }*/ Ty_fieldList fieldTys = recty->u.record; A_efieldList recList; Tr_expList list = NULL; int n = 0; for (recList = e->u.record.fields; recList; recList = recList->tail, fieldTys = fieldTys->tail, n++) { struct expty et = transExp(level, breakk, v, t, recList->head->exp); if (recList->head->name != fieldTys->head->name) EM_error(e->pos, "%s not a valid field name", recList->head->name); if (!ty_match(fieldTys->head->ty, et.ty)) EM_error(recList->head->exp->pos, "type error: given %s but expected %s"); Tr_expList_prepend(et.exp, &list); } return expTy(Tr_recordExp(n, list), recty); } return expTy(Tr_noExp(), Ty_Record(NULL)); } case A_arrayExp: {/*array create*/ Ty_ty arrayty = actual_ty(S_look(t, e->u.array.typ)); if (!arrayty) { EM_error(e->pos, "undeined array type %s", S_name(e->u.array.typ)); return expTy(Tr_noExp(), Ty_Int()); } if (arrayty->kind != Ty_array) { EM_error(e->pos, "%s is not a array type", S_name(e->u.array.typ)); return expTy(Tr_noExp(), Ty_Int()); } struct expty final2 = transExp(level, breakk, v, t, e->u.array.size); struct expty final3 = transExp(level, breakk, v, t, e->u.array.init); if (final2.ty->kind != Ty_int) { EM_error(e->pos, "array size should be int %s", S_name(e->u.array.typ)); } else if (!ty_match(final3.ty, arrayty->u.array)){ EM_error(e->pos, "unmatched array type in %s", S_name(e->u.array.typ)); } else { return expTy(Tr_arrayExp(final2.exp, final3.exp), arrayty); } return expTy(Tr_noExp(), Ty_Int()); } case A_seqExp: { Tr_expList l = NULL; A_expList list = e->u.seq; struct expty seqone; if (!list) { return expTy(Tr_noExp(), Ty_Void()); } for (; list; list = list->tail) { seqone = transExp(level, breakk, v, t, list->head); Tr_expList_prepend(seqone.exp, &l); } return expTy(Tr_seqExp(l), seqone.ty); } case A_whileExp: { struct expty final = transExp(level, breakk, v, t, e->u.whilee.test); if (final.ty->kind != Ty_int) { EM_error(e->pos, "int required"); } Tr_exp done = Tr_doneExp(); struct expty body = transExp(level, done, v, t, e->u.whilee.body); return expTy(Tr_whileExp(final.exp, body.exp, done), Ty_Void()); } case A_assignExp: { struct expty final4 = transVar(level, breakk, v, t, e->u.assign.var); struct expty final5 = transExp(level, breakk, v, t, e->u.assign.exp); if (!ty_match(final4.ty, final5.ty)) { EM_error(e->pos, "unmatched assign exp"); } return expTy(Tr_assignExp(final4.exp, final5.exp), Ty_Void()); } case A_breakExp: if (!breakk) return expTy(Tr_noExp(), Ty_Void()); return expTy(Tr_breakExp(breakk), Ty_Void()); case A_forExp: { EM_error(e->pos, "\nsome one said for is better than while\nmake them unhappy \nahahaha"); return expTy(Tr_noExp(), Ty_Int()); } case A_letExp: { A_decList decs; Tr_expList l = NULL; S_beginScope(v); S_beginScope(t); for (decs = e->u.let.decs; decs; decs = decs->tail) { Tr_expList_prepend(transDec(level, breakk, v, t, decs->head), &l); } struct expty final = transExp(level, breakk, v, t, e->u.let.body); Tr_expList_prepend(final.exp, &l); S_endScope(v); S_endScope(t); return expTy(Tr_seqExp(l), final.ty); } case A_opExp: { A_oper oper = e->u.op.oper; struct expty left = transExp(level, breakk, v, t, e->u.op.left); struct expty right = transExp(level, breakk, v, t, e->u.op.right); if (0 <= oper && oper < 4) {/* check +,-,*,/ */ if (left.ty->kind != Ty_int && left.ty->kind != Ty_double){ EM_error(e->u.op.left->pos, "int or double required(op)"); } else if (right.ty->kind != Ty_int && right.ty->kind != Ty_double) { EM_error(e->u.op.right->pos, "int or double required(op)"); } else if (left.ty->kind == Ty_int && right.ty->kind == Ty_int) { return expTy(Tr_arithExp(oper, left.exp, right.exp), Ty_Int()); } else { return expTy(Tr_arithExp(oper, left.exp, right.exp), Ty_Double()); } return expTy(Tr_noExp(), Ty_Int()); } else if (3 < oper && oper < 10) { Tr_exp translation = Tr_noExp(); if (oper == 4 || oper == 5) {/*check record type can be nil(=, <>)*/ switch(left.ty->kind) { case Ty_int: case Ty_double:/*see is double query like int TODO*/ if (right.ty->kind == Ty_int || right.ty->kind == Ty_double) translation = Tr_eqExp(oper, left.exp, right.exp); else {EM_error(e->u.op.right->pos, "unexpected type in comparsion");} break; case Ty_string: if (ty_match(right.ty, left.ty)) translation = Tr_eqStringExp(oper, left.exp, right.exp); else {EM_error(e->u.op.right->pos, "unexpected type in comparsion");} break; case Ty_array: if (ty_match(right.ty, left.ty)) translation = Tr_eqRef(oper, left.exp, right.exp); else {EM_error(e->u.op.right->pos, "unexpected type in comparsion");} break; case Ty_record: if (ty_match(right.ty, left.ty) || right.ty->kind == Ty_nil) translation = Tr_eqRef(oper, left.exp, right.exp); else {EM_error(e->u.op.right->pos, "unexpected type in comparsion");} break; default: EM_error(e->u.op.right->pos, "unexpected expression in comparsion"); } return expTy(translation, Ty_Int()); } else { switch(left.ty->kind) { case Ty_double: case Ty_int: if (right.ty->kind == Ty_double || right.ty->kind == Ty_int) translation = Tr_relExp(oper, left.exp, right.exp); else {EM_error(e->u.op.right->pos, "unexpected type in comparsion");} break; case Ty_string: if (right.ty->kind == Ty_string) translation = Tr_eqStringExp(oper, left.exp, right.exp); else {EM_error(e->u.op.right->pos, "unexpected type in comparsion");} break; default: EM_error(e->u.op.right->pos, "unexpected type in comparsion"); } return expTy(translation, Ty_Int()); } } else { assert(0); } } case A_ifExp: { struct expty final = transExp(level, breakk, v, t, e->u.iff.test); struct expty final2 = transExp(level, breakk, v, t, e->u.iff.then); struct expty final3 = {NULL, NULL}; if (e->u.iff.elsee) { /*no else-part*/ final3 = transExp(level, breakk, v, t, e->u.iff.elsee); if (final.ty->kind != Ty_int){ EM_error(e->u.iff.test->pos, "int required"); } if(!ty_match(final2.ty, final3.ty)) { EM_error(e->pos, "if-else sentence must return same type"); } } return expTy(Tr_ifExp(final.exp, final2.exp, final3.exp), final2.ty); } case A_stringExp: return expTy(Tr_stringExp(e->u.stringg), Ty_String()); case A_intExp: return expTy(Tr_intExp(e->u.intt), Ty_Int()); case A_doubleExp: return expTy(Tr_doubleExp(e->u.doublee), Ty_Double()); default: assert(0); }
static struct expty transVar(Tr_level level,Tr_exp breakk, S_table venv,S_table tenv,A_var v){ if (!v) { return expTy(Tr_noExp(), Ty_Void()); } E_enventry x; struct expty et,et2; Ty_fieldList fl; Tr_exp trans; switch(v->kind){ case A_simpleVar: /*var id*/ x=S_look(venv,v->u.simple); trans = Tr_noExp(); if (x&&x->kind==E_varEntry){ trans= Tr_simpleVar(x->u.var.access, level); return expTy(trans,actual_ty(x->u.var.ty)); }else{ //变量未定义 EM_error(v->pos, "undefined var %s", S_name(v->u.simple)); return expTy(trans, Ty_Int()); } break; case A_fieldVar:/* a.b a.b.c*/ //得到 a 的type 是 record还是 array还是 simplevar et=transVar(level,breakk,venv,tenv,v->u.field.var); trans = Tr_noExp(); if (et.ty->kind!=Ty_record) { EM_error(v->pos, "not a record type"); return expTy(NULL, Ty_Record(NULL)); }else{ int i=0; for (fl = et.ty->u.record;fl;fl=fl->tail,i++) { //地址比较 if (fl->head->name==v->u.field.sym) { trans = Tr_fieldVar(et.exp,i); return expTy(trans, actual_ty(fl->head->ty)); } } EM_error(v->pos, "no such field in record %s", S_name(v->u.field.sym)); } return expTy(trans, Ty_Int()); break; case A_subscriptVar:/*a[i]*/ et = transVar(level,breakk,venv, tenv, v->u.subscript.var); trans = Tr_noExp(); if (et.ty->kind!=Ty_array){ EM_error(v->pos, "not a array type"); }else{ et2=transExp(level,breakk,venv,tenv,v->u.subscript.exp); if (et2.ty->kind != Ty_int) { EM_error(v->pos, "int required"); }else{ trans = Tr_subscriptVar(et.exp, et2.exp); return expTy(trans, actual_ty(et.ty->u.array)); } } return expTy(trans, Ty_Int()); break; } }