#include "c.h" #include static Field isfield(const char *, Field); static Type type(int, Type, int, int, void *); static struct entry { struct type type; struct entry *link; } *typetable[128]; static int maxlevel; static Symbol pointersym; Type chartype; /* char */ Type doubletype; /* double */ Type floattype; /* float */ Type inttype; /* signed int */ Type longdouble; /* long double */ Type longtype; /* long */ Type longlong; /* long long */ Type shorttype; /* signed short int */ Type signedchar; /* signed char */ Type unsignedchar; /* unsigned char */ Type unsignedlong; /* unsigned long int */ Type unsignedlonglong; /* unsigned long long int */ Type unsignedshort; /* unsigned short int */ Type unsignedtype; /* unsigned int */ Type funcptype; /* void (*)() */ Type charptype; /* char* */ Type voidptype; /* void* */ Type voidtype; /* basic types: void */ Type unsignedptr; /* unsigned type to hold void* */ Type signedptr; /* signed type to hold void* */ Type widechar; /* unsigned type that represents wchar_t */ static Type xxinit(int op, char *name, Metrics m) { Symbol p = install(string(name), &types, GLOBAL, PERM); Type ty = type(op, 0, m.size, m.align, p); assert(ty->align == 0 || ty->size%ty->align == 0); p->type = ty; p->addressed = m.outofline; switch (ty->op) { case INT: p->u.limits.max.i = ones(8*ty->size)>>1; p->u.limits.min.i = -p->u.limits.max.i - 1; break; case UNSIGNED: p->u.limits.max.u = ones(8*ty->size); p->u.limits.min.u = 0; break; case FLOAT: if (ty->size == sizeof (float)) p->u.limits.max.d = FLT_MAX; else if (ty->size == sizeof (double)) p->u.limits.max.d = DBL_MAX; else p->u.limits.max.d = LDBL_MAX; p->u.limits.min.d = -p->u.limits.max.d; break; default: assert(0); } return ty; } static Type type(int op, Type ty, int size, int align, void *sym) { unsigned h = (op^((unsigned long)ty>>3)) &(NELEMS(typetable)-1); struct entry *tn; if (op != FUNCTION && (op != ARRAY || size > 0)) for (tn = typetable[h]; tn; tn = tn->link) if (tn->type.op == op && tn->type.type == ty && tn->type.size == size && tn->type.align == align && tn->type.u.sym == sym) return &tn->type; NEW0(tn, PERM); tn->type.op = op; tn->type.type = ty; tn->type.size = size; tn->type.align = align; tn->type.u.sym = sym; tn->link = typetable[h]; typetable[h] = tn; return &tn->type; } void type_init(int argc, char *argv[]) { static int inited; int i; if (inited) return; inited = 1; if (!IR) return; for (i = 1; i < argc; i++) { int size, align, outofline; if (strncmp(argv[i], "-unsigned_char=", 15) == 0) IR->unsigned_char = argv[i][15] - '0'; #define xx(name) \ else if (sscanf(argv[i], "-" #name "=%d,%d,%d", &size, &align, &outofline) == 3) { \ IR->name.size = size; IR->name.align = align; \ IR->name.outofline = outofline; } xx(charmetric) xx(shortmetric) xx(intmetric) xx(longmetric) xx(longlongmetric) xx(floatmetric) xx(doublemetric) xx(longdoublemetric) xx(ptrmetric) xx(structmetric) #undef xx } #define xx(v,name,op,metrics) v=xxinit(op,name,IR->metrics) xx(chartype, "char", IR->unsigned_char ? UNSIGNED : INT,charmetric); xx(doubletype, "double", FLOAT, doublemetric); xx(floattype, "float", FLOAT, floatmetric); xx(inttype, "int", INT, intmetric); xx(longdouble, "long double", FLOAT, longdoublemetric); xx(longtype, "long int", INT, longmetric); xx(longlong, "long long int", INT, longlongmetric); xx(shorttype, "short", INT, shortmetric); xx(signedchar, "signed char", INT, charmetric); xx(unsignedchar, "unsigned char", UNSIGNED,charmetric); xx(unsignedlong, "unsigned long", UNSIGNED,longmetric); xx(unsignedshort, "unsigned short", UNSIGNED,shortmetric); xx(unsignedtype, "unsigned int", UNSIGNED,intmetric); xx(unsignedlonglong,"unsigned long long",UNSIGNED,longlongmetric); #undef xx { Symbol p; p = install(string("void"), &types, GLOBAL, PERM); voidtype = type(VOID, NULL, 0, 0, p); p->type = voidtype; } pointersym = install(string("T*"), &types, GLOBAL, PERM); pointersym->addressed = IR->ptrmetric.outofline; pointersym->u.limits.max.p = (void*)ones(8*IR->ptrmetric.size); pointersym->u.limits.min.p = 0; voidptype = ptr(voidtype); funcptype = ptr(func(voidtype, NULL, 1)); charptype = ptr(chartype); #define xx(v,t) if (v==NULL && t->size==voidptype->size && t->align==voidptype->align) v=t xx(unsignedptr,unsignedshort); xx(unsignedptr,unsignedtype); xx(unsignedptr,unsignedlong); xx(unsignedptr,unsignedlonglong); if (unsignedptr == NULL) unsignedptr = type(UNSIGNED, NULL, voidptype->size, voidptype->align, voidptype->u.sym); xx(signedptr,shorttype); xx(signedptr,inttype); xx(signedptr,longtype); xx(signedptr,longlong); if (signedptr == NULL) signedptr = type(INT, NULL, voidptype->size, voidptype->align, voidptype->u.sym); #undef xx widechar = unsignedshort; for (i = 0; i < argc; i++) { #define xx(name,type) \ if (strcmp(argv[i], "-wchar_t=" #name) == 0) \ widechar = type; xx(unsigned_char,unsignedchar) xx(unsigned_int,unsignedtype) xx(unsigned_short,unsignedshort) } #undef xx } void rmtypes(int lev) { if (maxlevel >= lev) { int i; maxlevel = 0; for (i = 0; i < NELEMS(typetable); i++) { struct entry *tn, **tq = &typetable[i]; while ((tn = *tq) != NULL) if (tn->type.op == FUNCTION) tq = &tn->link; else if (tn->type.u.sym && tn->type.u.sym->scope >= lev) *tq = tn->link; else { if (tn->type.u.sym && tn->type.u.sym->scope > maxlevel) maxlevel = tn->type.u.sym->scope; tq = &tn->link; } } } } Type ptr(Type ty) { return type(POINTER, ty, IR->ptrmetric.size, IR->ptrmetric.align, pointersym); } Type deref(Type ty) { if (isptr(ty)) ty = ty->type; else error("type error: %s\n", "pointer expected"); return isenum(ty) ? unqual(ty)->type : ty; } Type array(Type ty, int n, int a) { assert(ty); if (isfunc(ty)) { error("illegal type `array of %t'\n", ty); return array(inttype, n, 0); } if (isarray(ty) && ty->size == 0) error("missing array size\n"); if (ty->size == 0) { if (unqual(ty) == voidtype) error("illegal type `array of %t'\n", ty); else if (Aflag >= 2) warning("declaring type array of %t' is undefined\n", ty); } else if (n > INT_MAX/ty->size) { error("size of `array of %t' exceeds %d bytes\n", ty, INT_MAX); n = 1; } return type(ARRAY, ty, n*ty->size, a ? a : ty->align, NULL); } Type atop(Type ty) { if (isarray(ty)) return ptr(ty->type); error("type error: %s\n", "array expected"); return ptr(ty); } Type qual(int op, Type ty) { if (isarray(ty)) ty = type(ARRAY, qual(op, ty->type), ty->size, ty->align, NULL); else if (isfunc(ty)) warning("qualified function type ignored\n"); else if (isconst(ty) && op == CONST || isvolatile(ty) && op == VOLATILE) error("illegal type `%k %t'\n", op, ty); else { if (isqual(ty)) { op += ty->op; ty = ty->type; } ty = type(op, ty, ty->size, ty->align, NULL); } return ty; } Type func(Type ty, Type *proto, int style) { if (ty && (isarray(ty) || isfunc(ty))) error("illegal return type `%t'\n", ty); ty = type(FUNCTION, ty, 0, 0, NULL); ty->u.f.proto = proto; ty->u.f.oldstyle = style; return ty; } Type freturn(Type ty) { if (isfunc(ty)) return ty->type; error("type error: %s\n", "function expected"); return inttype; } int variadic(Type ty) { if (isfunc(ty) && ty->u.f.proto) { int i; for (i = 0; ty->u.f.proto[i]; i++) ; return i > 1 && ty->u.f.proto[i-1] == voidtype; } return 0; } Type newstruct(int op, char *tag) { Symbol p; assert(tag); if (*tag == 0) tag = stringd(genlabel(1)); else if ((p = lookup(tag, types)) != NULL && (p->scope == level || p->scope == PARAM && level == PARAM+1)) { if (p->type->op == op && !p->defined) return p->type; error("redefinition of `%s' previously defined at %w\n", p->name, &p->src); } p = install(tag, &types, level, PERM); p->type = type(op, NULL, 0, 0, p); if (p->scope > maxlevel) maxlevel = p->scope; p->src = src; return p->type; } Field newfield(char *name, Type ty, Type fty) { Field p, *q = &ty->u.sym->u.s.flist; if (name == NULL) name = stringd(genlabel(1)); for (p = *q; p; q = &p->link, p = *q) if (p->name == name) error("duplicate field name `%s' in `%t'\n", name, ty); NEW0(p, PERM); *q = p; p->name = name; p->type = fty; if (xref) { /* omit */ if (ty->u.sym->u.s.ftab == NULL) /* omit */ ty->u.sym->u.s.ftab = table(NULL, level); /* omit */ install(name, &ty->u.sym->u.s.ftab, 0, PERM)->src = src;/* omit */ } /* omit */ return p; } int eqtype(Type ty1, Type ty2, int ret) { if (ty1 == ty2) return 1; if (ty1->op != ty2->op) return 0; switch (ty1->op) { case ENUM: case UNION: case STRUCT: case UNSIGNED: case INT: case FLOAT: return 0; case POINTER: return eqtype(ty1->type, ty2->type, 1); case VOLATILE: case CONST+VOLATILE: case CONST: return eqtype(ty1->type, ty2->type, 1); case ARRAY: if (eqtype(ty1->type, ty2->type, 1)) { if (ty1->size == ty2->size) return 1; if (ty1->size == 0 || ty2->size == 0) return ret; } return 0; case FUNCTION: if (eqtype(ty1->type, ty2->type, 1)) { Type *p1 = ty1->u.f.proto, *p2 = ty2->u.f.proto; if (p1 == p2) return 1; if (p1 && p2) { for ( ; *p1 && *p2; p1++, p2++) if (eqtype(unqual(*p1), unqual(*p2), 1) == 0) return 0; if (*p1 == NULL && *p2 == NULL) return 1; } else { if (variadic(p1 ? ty1 : ty2)) return 0; if (p1 == NULL) p1 = p2; for ( ; *p1; p1++) { Type ty = unqual(*p1); if (promote(ty) != (isenum(ty) ? ty->type : ty)) return 0; } return 1; } } return 0; } assert(0); return 0; } Type promote(Type ty) { ty = unqual(ty); switch (ty->op) { case ENUM: return inttype; case INT: if (ty->size < inttype->size) return inttype; break; case UNSIGNED: if (ty->size < inttype->size) return inttype; if (ty->size < unsignedtype->size) return unsignedtype; break; case FLOAT: if (ty->size < doubletype->size) return doubletype; } return ty; } Type signedint(Type ty) { if (ty->op == INT) return ty; assert(ty->op == UNSIGNED); #define xx(t) if (ty->size == t->size) return t xx(inttype); xx(longtype); xx(longlong); #undef xx assert(0); return NULL; } Type compose(Type ty1, Type ty2) { if (ty1 == ty2) return ty1; assert(ty1->op == ty2->op); switch (ty1->op) { case POINTER: return ptr(compose(ty1->type, ty2->type)); case CONST+VOLATILE: return qual(CONST, qual(VOLATILE, compose(ty1->type, ty2->type))); case CONST: case VOLATILE: return qual(ty1->op, compose(ty1->type, ty2->type)); case ARRAY: { Type ty = compose(ty1->type, ty2->type); if (ty1->size && (ty1->type->size && ty2->size == 0 || ty1->size == ty2->size)) return array(ty, ty1->size/ty1->type->size, ty1->align); if (ty2->size && ty2->type->size && ty1->size == 0) return array(ty, ty2->size/ty2->type->size, ty2->align); return array(ty, 0, 0); } case FUNCTION: { Type *p1 = ty1->u.f.proto, *p2 = ty2->u.f.proto; Type ty = compose(ty1->type, ty2->type); List tlist = NULL; if (p1 == NULL && p2 == NULL) return func(ty, NULL, 1); if (p1 && p2 == NULL) return func(ty, p1, ty1->u.f.oldstyle); if (p2 && p1 == NULL) return func(ty, p2, ty2->u.f.oldstyle); for ( ; *p1 && *p2; p1++, p2++) { Type ty = compose(unqual(*p1), unqual(*p2)); if (isconst(*p1) || isconst(*p2)) ty = qual(CONST, ty); if (isvolatile(*p1) || isvolatile(*p2)) ty = qual(VOLATILE, ty); tlist = append(ty, tlist); } assert(*p1 == NULL && *p2 == NULL); return func(ty, ltov(&tlist, PERM), 0); } } assert(0); return NULL; } int ttob(Type ty) { switch (ty->op) { case CONST: case VOLATILE: case CONST+VOLATILE: return ttob(ty->type); case VOID: case INT: case UNSIGNED: case FLOAT: return ty->op + sizeop(ty->size); case POINTER: return POINTER + sizeop(voidptype->size); case FUNCTION: return POINTER + sizeop(funcptype->size); case ARRAY: case STRUCT: case UNION: return STRUCT; case ENUM: return INT + sizeop(inttype->size); } assert(0); return INT; } Type btot(int op, int size) { #define xx(ty) if (size == (ty)->size) return ty; switch (optype(op)) { case F: xx(floattype); xx(doubletype); xx(longdouble); assert(0); return 0; case I: if (chartype->op == INT) xx(chartype); xx(signedchar); xx(shorttype); xx(inttype); xx(longtype); xx(longlong); assert(0); return 0; case U: if (chartype->op == UNSIGNED) xx(chartype); xx(unsignedchar); xx(unsignedshort); xx(unsignedtype); xx(unsignedlong); xx(unsignedlonglong); assert(0); return 0; case P: xx(voidptype); xx(funcptype); assert(0); return 0; } #undef xx assert(0); return 0; } int hasproto(Type ty) { if (ty == 0) return 1; switch (ty->op) { case CONST: case VOLATILE: case CONST+VOLATILE: case POINTER: case ARRAY: return hasproto(ty->type); case FUNCTION: return hasproto(ty->type) && ty->u.f.proto; case STRUCT: case UNION: case VOID: case FLOAT: case ENUM: case INT: case UNSIGNED: return 1; } assert(0); return 0; } /* fieldlist - construct a flat list of fields in type ty */ Field fieldlist(Type ty) { return ty->u.sym->u.s.flist; } /* fieldref - find field name of type ty, return entry */ Field fieldref(const char *name, Type ty) { Field p = isfield(name, unqual(ty)->u.sym->u.s.flist); if (p && xref) { Symbol q; assert(unqual(ty)->u.sym->u.s.ftab); q = lookup(name, unqual(ty)->u.sym->u.s.ftab); assert(q); use(q, src); } return p; } /* ftype - return a function type for rty function (ty,...)' */ Type ftype(Type rty, Type ty) { List list = append(ty, NULL); list = append(voidtype, list); return func(rty, ltov(&list, PERM), 0); } /* isfield - if name is a field in flist, return pointer to the field structure */ static Field isfield(const char *name, Field flist) { for ( ; flist; flist = flist->link) if (flist->name == name) break; return flist; } /* outtype - output type ty */ void outtype(Type ty, FILE *f) { switch (ty->op) { case CONST+VOLATILE: case CONST: case VOLATILE: fprint(f, "%k %t", ty->op, ty->type); break; case STRUCT: case UNION: case ENUM: assert(ty->u.sym); if (ty->size == 0) fprint(f, "incomplete "); assert(ty->u.sym->name); if (*ty->u.sym->name >= '1' && *ty->u.sym->name <= '9') { Symbol p = findtype(ty); if (p == 0) fprint(f, "%k defined at %w", ty->op, &ty->u.sym->src); else fprint(f, p->name); } else { fprint(f, "%k %s", ty->op, ty->u.sym->name); if (ty->size == 0) fprint(f, " defined at %w", &ty->u.sym->src); } break; case VOID: case FLOAT: case INT: case UNSIGNED: fprint(f, ty->u.sym->name); break; case POINTER: fprint(f, "pointer to %t", ty->type); break; case FUNCTION: fprint(f, "%t function", ty->type); if (ty->u.f.proto && ty->u.f.proto[0]) { int i; fprint(f, "(%t", ty->u.f.proto[0]); for (i = 1; ty->u.f.proto[i]; i++) if (ty->u.f.proto[i] == voidtype) fprint(f, ",..."); else fprint(f, ",%t", ty->u.f.proto[i]); fprint(f, ")"); } else if (ty->u.f.proto && ty->u.f.proto[0] == 0) fprint(f, "(void)"); break; case ARRAY: if (ty->size > 0 && ty->type && ty->type->size > 0) { fprint(f, "array %d", ty->size/ty->type->size); while (ty->type && isarray(ty->type) && ty->type->type->size > 0) { ty = ty->type; fprint(f, ",%d", ty->size/ty->type->size); } } else fprint(f, "incomplete array"); if (ty->type) fprint(f, " of %t", ty->type); break; default: assert(0); } } /* printdecl - output a C declaration for symbol p of type ty */ void printdecl(Symbol p, Type ty) { switch (p->sclass) { case AUTO: fprint(stderr, "%s;\n", typestring(ty, p->name)); break; case STATIC: case EXTERN: fprint(stderr, "%k %s;\n", p->sclass, typestring(ty, p->name)); break; case TYPEDEF: case ENUM: break; default: assert(0); } } /* printproto - output a prototype declaration for function p */ void printproto(Symbol p, Symbol callee[]) { if (p->type->u.f.proto) printdecl(p, p->type); else { int i; List list = 0; if (callee[0] == 0) list = append(voidtype, list); else for (i = 0; callee[i]; i++) list = append(callee[i]->type, list); printdecl(p, func(freturn(p->type), ltov(&list, PERM), 0)); } } /* prtype - print details of type ty on f with given indent */ static void prtype(Type ty, FILE *f, int indent, unsigned mark) { switch (ty->op) { default: fprint(f, "(%d %d %d [%p])", ty->op, ty->size, ty->align, ty->u.sym); break; case FLOAT: case INT: case UNSIGNED: case VOID: fprint(f, "(%k %d %d [\"%s\"])", ty->op, ty->size, ty->align, ty->u.sym->name); break; case CONST+VOLATILE: case CONST: case VOLATILE: case POINTER: case ARRAY: fprint(f, "(%k %d %d ", ty->op, ty->size, ty->align); prtype(ty->type, f, indent+1, mark); fprint(f, ")"); break; case STRUCT: case UNION: fprint(f, "(%k %d %d [\"%s\"]", ty->op, ty->size, ty->align, ty->u.sym->name); if (ty->x.marked != mark) { Field p; ty->x.marked = mark; for (p = ty->u.sym->u.s.flist; p; p = p->link) { fprint(f, "\n%I", indent+1); prtype(p->type, f, indent+1, mark); fprint(f, " %s@%d", p->name, p->offset); if (p->lsb) fprint(f, ":%d..%d", fieldsize(p) + fieldright(p), fieldright(p)); } fprint(f, "\n%I", indent); } fprint(f, ")"); break; case ENUM: fprint(f, "(%k %d %d [\"%s\"]", ty->op, ty->size, ty->align, ty->u.sym->name); if (ty->x.marked != mark) { int i; Symbol *p = ty->u.sym->u.idlist; ty->x.marked = mark; for (i = 0; p[i] != NULL; i++) fprint(f, "%I%s=%d\n", indent+1, p[i]->name, p[i]->u.value); } fprint(f, ")"); break; case FUNCTION: fprint(f, "(%k %d %d ", ty->op, ty->size, ty->align); prtype(ty->type, f, indent+1, mark); if (ty->u.f.proto) { int i; fprint(f, "\n%I{", indent+1); for (i = 0; ty->u.f.proto[i]; i++) { if (i > 0) fprint(f, "%I", indent+2); prtype(ty->u.f.proto[i], f, indent+2, mark); fprint(f, "\n"); } fprint(f, "%I}", indent+1); } fprint(f, ")"); break; } } /* printtype - print details of type ty on fd */ void printtype(Type ty, int fd) { static unsigned mark; prtype(ty, fd == 1 ? stdout : stderr, 0, ++mark); fprint(fd == 1 ? stdout : stderr, "\n"); } /* typestring - return ty as C declaration for str, which may be "" */ char *typestring(Type ty, char *str) { for ( ; ty; ty = ty->type) { Symbol p; switch (ty->op) { case CONST+VOLATILE: case CONST: case VOLATILE: if (isptr(ty->type)) str = stringf("%k %s", ty->op, str); else return stringf("%k %s", ty->op, typestring(ty->type, str)); break; case STRUCT: case UNION: case ENUM: assert(ty->u.sym); if ((p = findtype(ty)) != NULL) return *str ? stringf("%s %s", p->name, str) : p->name; if (*ty->u.sym->name >= '1' && *ty->u.sym->name <= '9') warning("unnamed %k in prototype\n", ty->op); if (*str) return stringf("%k %s %s", ty->op, ty->u.sym->name, str); else return stringf("%k %s", ty->op, ty->u.sym->name); case VOID: case FLOAT: case INT: case UNSIGNED: return *str ? stringf("%s %s", ty->u.sym->name, str) : ty->u.sym->name; case POINTER: if (!ischar(ty->type) && (p = findtype(ty)) != NULL) return *str ? stringf("%s %s", p->name, str) : p->name; str = stringf(isarray(ty->type) || isfunc(ty->type) ? "(*%s)" : "*%s", str); break; case FUNCTION: if ((p = findtype(ty)) != NULL) return *str ? stringf("%s %s", p->name, str) : p->name; if (ty->u.f.proto == 0) str = stringf("%s()", str); else if (ty->u.f.proto[0]) { int i; str = stringf("%s(%s", str, typestring(ty->u.f.proto[0], "")); for (i = 1; ty->u.f.proto[i]; i++) if (ty->u.f.proto[i] == voidtype) str = stringf("%s, ...", str); else str = stringf("%s, %s", str, typestring(ty->u.f.proto[i], "")); str = stringf("%s)", str); } else str = stringf("%s(void)", str); break; case ARRAY: if ((p = findtype(ty)) != NULL) return *str ? stringf("%s %s", p->name, str) : p->name; if (ty->type && ty->type->size > 0) str = stringf("%s[%d]", str, ty->size/ty->type->size); else str = stringf("%s[]", str); break; default: assert(0); } } assert(0); return 0; }