#include #include #include #include #include "type.h" #define builtin_scalar(_t) { \ .ttype = T_SCALAR, \ .size = sizeof(_t), \ .t = { .scalar = { .name = #_t } }, \ } type_t t_void = builtin_scalar(void); type_t t_char = builtin_scalar(char); type_t t_uchar = builtin_scalar(unsigned char); type_t t_short = builtin_scalar(short); type_t t_ushort = builtin_scalar(unsigned short); type_t t_int = builtin_scalar(int); type_t t_uint = builtin_scalar(unsigned int); type_t t_long = builtin_scalar(long); type_t t_ulong = builtin_scalar(unsigned long); type_t t_llong = builtin_scalar(long long); type_t t_ullong = builtin_scalar(unsigned long long); type_t *builtin_types[] = { &t_void, &t_char, &t_uchar, &t_short, &t_ushort, &t_int, &t_uint, &t_long, &t_ulong, &t_llong, &t_ullong, NULL }; struct type_list { type_t **type; size_t len; } types; void type_dump_func(type_t *t, FILE *fp) { field_t *arg; type_dump(t->t.func.type, fp); fprintf(fp, " (*%s)(", t->t.func.name ? : ""); if (!t->t.func.args) { fputs("void)", fp); return; } for (arg = t->t.func.args; arg->type; arg++) { if (arg != t->t.func.args) fputs(", ", fp); type_dump(arg->type, fp); } fputc(')', fp); } void type_dump(type_t *t, FILE *fp) { if (!t) { fputs("", fp); return; } switch (t->ttype){ case T_TYPEDEF: fputs(t->t.tdef.name, fp); break; case T_SCALAR: fputs(t->t.scalar.name, fp); break; case T_POINTER: type_dump(t->t.pointer.type, fp); fputs(" *", fp); break; case T_ARRAY: type_dump(t->t.array.type, fp); fprintf(fp, "[%zu]", t->t.array.len); break; case T_STRUCT: fputs("struct ", fp); fputs(t->t.sou.name, fp); break; case T_UNION: fputs("union ", fp); fputs(t->t.sou.name, fp); break; case T_FUNC: type_dump_func(t, fp); break; case T_MAP: fputs("map [", fp); type_dump(t->t.map.ktype, fp); fputs("] ", fp); type_dump(t->t.map.vtype, fp); break; } } void type_dump_cdecl_sou(type_t *t, FILE *fp) { field_t *f; type_dump(t, fp); fputs(" {\n", fp); for (f = t->t.sou.fields; f->type; f++) { fputc('\t', fp); type_dump(f->type, fp); fprintf(fp, " %s;\n", f->name); } fputs("}", fp); } void type_dump_cdecl(type_t *t, FILE *fp) { switch (t->ttype) { case T_TYPEDEF: fputs("typedef ", fp); type_dump(t->t.tdef.type, fp); fprintf(fp, " %s", t->t.tdef.name); break; case T_STRUCT: case T_UNION: type_dump_cdecl_sou(t, fp); break; case T_SCALAR: case T_POINTER: case T_ARRAY: case T_MAP: case T_FUNC: type_dump(t, fp); break; } } void types_dump_cdecl(FILE *fp) { size_t i; for (i = 0; i < types.len; i++) { type_t *t = types.type[i]; type_dump_cdecl(t, stdout); printf(" \n", t->size); } } type_t *type_map_of(type_t *ktype, type_t *vtype) { type_t *t; size_t i; for (i = 0; i < types.len; i++) { t = types.type[i]; if ((t->ttype == T_MAP) && (t->t.map.ktype == ktype) && (t->t.map.vtype == vtype)) return t; } t = calloc(1, sizeof(*t)); t->ttype = T_MAP; t->t.map.vtype = vtype; t->t.map.ktype = ktype; type_add(t); return t; } type_t *type_ptr_of(type_t *type) { type_t *t; size_t i; for (i = 0; i < types.len; i++) { t = types.type[i]; if ((t->ttype == T_POINTER) && (t->t.pointer.type == type)) return t; } t = calloc(1, sizeof(*t)); t->ttype = T_POINTER; t->t.pointer.type = type; type_add(t); return t; } type_t *type_normalize(type_t *t) { while (t->ttype == T_TYPEDEF) t = t->t.tdef.type; return t; } int type_equal(type_t *a, type_t *b) { /* TODO */ return a == b; } int type_compatible(type_t *a, type_t *b) { a = type_normalize(a); b = type_normalize(b); if (a->ttype != b->ttype) return 0; switch (a->ttype){ case T_SCALAR: return 1; case T_POINTER: return 1; case T_ARRAY: if (a->t.array.len != b->t.array.len) return 0; return type_compatible(a->t.array.type, b->t.array.type); case T_STRUCT: case T_UNION: return !strcmp(a->t.sou.name, b->t.sou.name); case T_FUNC: return type_compatible(a->t.func.type, b->t.func.type); case T_MAP: return type_compatible(a->t.map.vtype, b->t.map.vtype); case T_TYPEDEF: assert(0); } assert(0); return 0; } void type_size_set_sou(type_t *t) { field_t *f; size_t size = 0; if (!t->t.sou.fields) return; for (f = t->t.sou.fields; f->name; f++) { /* size of all members is now known yet, abort */ if (!f->type->size) return; if (!t->t.sou.packed) size += size % f->type->size; size += f->type->size; f->offset = size; } if (!t->t.sou.packed && size) { /* align complete struct to requirements of first * member, if struct keep going downwards */ f = t->t.sou.fields; while (f->type->ttype == T_STRUCT) f = f->type->t.sou.fields; size += size % f->type->size; } t->size = size; } void type_size_set(type_t *t) { switch (t->ttype) { case T_TYPEDEF: t->size = t->t.tdef.type->size; break; case T_STRUCT: case T_UNION: type_size_set_sou(t); break; case T_FUNC: t->size = t->t.func.type->size; break; case T_SCALAR: break; case T_POINTER: t->size = sizeof(void *); break; case T_ARRAY: t->size = t->t.array.len * t->t.array.type->size; break; case T_MAP: /* map fds are s64:s */ t->size = 8; break; } } int type_cmp(const void *_a, const void *_b) { const type_t *a = *((type_t **)_a); const type_t *b = *((type_t **)_b); return a - b; } int type_add(type_t *t) { if (bsearch(t, types.type, types.len, sizeof(*types.type), type_cmp)) return 0; type_size_set(t); types.type = realloc(types.type, ++types.len * sizeof(*types.type)); types.type[types.len - 1] = t; qsort(types.type, types.len, sizeof(*types.type), type_cmp); return 0; } int type_add_list(type_t **ts) { int err; for (; *ts; ts++) { err = type_add(*ts); if (err) return err; } return 0; } __attribute__((constructor)) static void type_init(void) { type_add_list(builtin_types); }