rusi/type.c

327 lines
11 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#включить "руси.з"
// =====================================================================
// Механизм отслеживания выделенной памяти для типов
// =====================================================================
стат 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;
возврат;
}
}