#включить "руси.з" // ===================================================================== // Механизм отслеживания выделенной памяти для типов // ===================================================================== стат Type **все_типы = NULL; стат цел счётчик_типов = 0; стат цел ёмкость_типов = 0; стат пусто отследить_тип(Type *тип) { если (счётчик_типов == ёмкость_типов) { ёмкость_типов = ёмкость_типов ? ёмкость_типов * 2 : 1024; все_типы = realloc(все_типы, ёмкость_типов * размер(Type *)); } все_типы[счётчик_типов++] = тип; } пусто free_all_types(пусто) { для (цел ш = 0; ш < счётчик_типов; ш++) { free(все_типы[ш]); } free(все_типы); все_типы = NULL; счётчик_типов = 0; ёмкость_типов = 0; } // ===================================================================== Type *ty_void = &(Type){TY_VOID, 1, 1}; Type *ty_bool = &(Type){TY_BOOL, 1, 1}; Type *ty_char = &(Type){TY_CHAR, 1, 1}; Type *ty_short = &(Type){TY_SHORT, 2, 2}; Type *ty_int = &(Type){TY_INT, 4, 4}; Type *ty_long = &(Type){TY_LONG, 8, 8}; Type *ty_uchar = &(Type){TY_CHAR, 1, 1, истина}; Type *ty_ushort = &(Type){TY_SHORT, 2, 2, истина}; Type *ty_uint = &(Type){TY_INT, 4, 4, истина}; Type *ty_ulong = &(Type){TY_LONG, 8, 8, истина}; Type *ty_float = &(Type){TY_FLOAT, 4, 4}; Type *ty_double = &(Type){TY_DOUBLE, 8, 8}; Type *ty_ldouble = &(Type){TY_LDOUBLE, 16, 16}; стат Type *выделить_тип(TypeKind вид, цел разм, цел выравн) { Type *тип = calloc(1, размер(Type)); тип->kind = вид; тип->size = разм; тип->align = выравн; отследить_тип(тип); возврат тип; } бул is_integer(Type *тип) { TypeKind вид = тип->kind; возврат вид == TY_BOOL || вид == TY_CHAR || вид == TY_SHORT || вид == TY_INT || вид == TY_LONG || вид == TY_ENUM; } бул is_flonum(Type *тип) { возврат тип->kind == TY_FLOAT || тип->kind == TY_DOUBLE || тип->kind == TY_LDOUBLE; } бул is_numeric(Type *тип) { возврат is_integer(тип) || is_flonum(тип); } бул is_compatible(Type *т1, Type *т2) { если (т1 == т2) возврат истина; если (т1->origin) возврат is_compatible(т1->origin, т2); если (т2->origin) возврат is_compatible(т1, т2->origin); если (т1->kind != т2->kind) возврат ложь; выбор (т1->kind) { случай TY_CHAR: случай TY_SHORT: случай TY_INT: случай TY_LONG: возврат т1->is_unsigned == т2->is_unsigned; случай TY_FLOAT: случай TY_DOUBLE: случай TY_LDOUBLE: возврат истина; случай TY_PTR: возврат is_compatible(т1->base, т2->base); случай TY_FUNC: { если (!is_compatible(т1->return_ty, т2->return_ty)) возврат ложь; если (т1->is_variadic != т2->is_variadic) возврат ложь; Type *пар1 = т1->params; Type *пар2 = т2->params; для (; пар1 && пар2; пар1 = пар1->next, пар2 = пар2->next) если (!is_compatible(пар1, пар2)) возврат ложь; возврат пар1 == NULL && пар2 == NULL; } случай TY_ARRAY: если (!is_compatible(т1->base, т2->base)) возврат ложь; возврат т1->array_len < 0 && т2->array_len < 0 && т1->array_len == т2->array_len; } возврат ложь; } Type *copy_type(Type *тип) { Type *копия = calloc(1, размер(Type)); *копия = *тип; копия->origin = тип; отследить_тип(копия); возврат копия; } Type *pointer_to(Type *база) { Type *указ = выделить_тип(TY_PTR, 8, 8); указ->base = база; указ->is_unsigned = истина; возврат указ; } Type *func_type(Type *возвр_тип) { Type *фн = выделить_тип(TY_FUNC, 1, 1); фн->return_ty = возвр_тип; возврат фн; } Type *array_of(Type *база, цел длина) { Type *масс = выделить_тип(TY_ARRAY, база->size * длина, база->align); масс->base = база; масс->array_len = длина; возврат масс; } Type *vla_of(Type *база, Node *узел_длины) { Type *вла = выделить_тип(TY_VLA, 8, 8); вла->base = база; вла->vla_len = узел_длины; возврат вла; } Type *enum_type(пусто) { возврат выделить_тип(TY_ENUM, 4, 4); } Type *struct_type(пусто) { возврат выделить_тип(TY_STRUCT, 0, 1); } стат Type *общий_тип(Type *т1, Type *т2) { если (т1->base) возврат pointer_to(т1->base); если (т1->kind == TY_FUNC) возврат pointer_to(т1); если (т2->kind == TY_FUNC) возврат pointer_to(т2); если (т1->kind == TY_LDOUBLE || т2->kind == TY_LDOUBLE) возврат ty_ldouble; если (т1->kind == TY_DOUBLE || т2->kind == TY_DOUBLE) возврат ty_double; если (т1->kind == TY_FLOAT || т2->kind == TY_FLOAT) возврат ty_float; если (т1->size < 4) т1 = ty_int; если (т2->size < 4) т2 = ty_int; если (т1->size != т2->size) возврат (т1->size < т2->size) ? т2 : т1; если (т2->is_unsigned) возврат т2; возврат т1; } стат пусто арифм_преобразование(Node **лев, Node **прав) { Type *общий = общий_тип((*лев)->ty, (*прав)->ty); *лев = new_cast(*лев, общий); *прав = new_cast(*прав, общий); } пусто add_type(Node *узел) { если (!узел || узел->ty) возврат; add_type(узел->lhs); add_type(узел->rhs); add_type(узел->cond); add_type(узел->then); add_type(узел->els); add_type(узел->init); add_type(узел->inc); для (Node *п = узел->body; п; п = п->next) add_type(п); для (Node *п = узел->args; п; п = п->next) add_type(п); выбор (узел->kind) { случай ND_NUM: узел->ty = ty_int; возврат; случай ND_ADD: случай ND_SUB: случай ND_MUL: случай ND_DIV: случай ND_MOD: случай ND_BITAND: случай ND_BITOR: случай ND_BITXOR: арифм_преобразование(&узел->lhs, &узел->rhs); узел->ty = узел->lhs->ty; возврат; случай ND_NEG: { Type *рез_тип = общий_тип(ty_int, узел->lhs->ty); узел->lhs = new_cast(узел->lhs, рез_тип); узел->ty = рез_тип; возврат; } случай ND_ASSIGN: если (узел->lhs->ty->kind == TY_ARRAY) error_tok(узел->lhs->tok, "не lvalue"); если (узел->lhs->ty->kind != TY_STRUCT) узел->rhs = new_cast(узел->rhs, узел->lhs->ty); узел->ty = узел->lhs->ty; возврат; случай ND_EQ: случай ND_NE: случай ND_LT: случай ND_LE: арифм_преобразование(&узел->lhs, &узел->rhs); узел->ty = ty_int; возврат; случай ND_FUNCALL: узел->ty = узел->func_ty->return_ty; возврат; случай ND_NOT: случай ND_LOGOR: случай ND_LOGAND: узел->ty = ty_int; возврат; случай ND_BITNOT: случай ND_SHL: случай ND_SHR: узел->ty = узел->lhs->ty; возврат; случай ND_VAR: случай ND_VLA_PTR: узел->ty = узел->var->ty; возврат; случай ND_COND: если (узел->then->ty->kind == TY_VOID || узел->els->ty->kind == TY_VOID) { узел->ty = ty_void; } иначе { арифм_преобразование(&узел->then, &узел->els); узел->ty = узел->then->ty; } возврат; случай ND_COMMA: узел->ty = узел->rhs->ty; возврат; случай ND_MEMBER: узел->ty = узел->member->ty; возврат; случай ND_ADDR: { Type *тип_операнда = узел->lhs->ty; если (тип_операнда->kind == TY_ARRAY) узел->ty = pointer_to(тип_операнда->base); иначе узел->ty = pointer_to(тип_операнда); возврат; } случай ND_DEREF: если (!узел->lhs->ty->base) error_tok(узел->tok, "недопустимое разыменование указателя"); если (узел->lhs->ty->base->kind == TY_VOID) error_tok(узел->tok, "разыменование указателя на void"); узел->ty = узел->lhs->ty->base; возврат; случай ND_STMT_EXPR: если (узел->body) { Node *оп = узел->body; пока (оп->next) оп = оп->next; если (оп->kind == ND_EXPR_STMT) { узел->ty = оп->lhs->ty; возврат; } } error_tok(узел->tok, "выражение-инструкция, возвращающая void, не поддерживается"); возврат; случай ND_LABEL_VAL: узел->ty = pointer_to(ty_void); возврат; случай ND_CAS: add_type(узел->cas_addr); add_type(узел->cas_old); add_type(узел->cas_new); узел->ty = ty_bool; если (узел->cas_addr->ty->kind != TY_PTR) error_tok(узел->cas_addr->tok, "ожидался указатель"); если (узел->cas_old->ty->kind != TY_PTR) error_tok(узел->cas_old->tok, "ожидался указатель"); возврат; случай ND_EXCH: если (узел->lhs->ty->kind != TY_PTR) error_tok(узел->cas_addr->tok, "ожидался указатель"); узел->ty = узел->lhs->ty->base; возврат; } }