scc

Simple C99 Compiler
Log | Files | Refs | README | LICENSE

commit ec0bbf93d441cac0db795007d80b1dcdc32e91d0
parent 7cce9dc9462e67e8ebfd5a507b49707f3a1e1013
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Sat, 15 Mar 2014 14:13:33 +0100

Refactoring of type system

The type system was broken and this commit refactorize all the code,
so it is not an incremental commit, it is a new code.

Diffstat:
decl.c | 674++++++++++++++++++++++++++++++-------------------------------------------------
expr.c | 17+++++++----------
flow.c | 52+++++++++++++++++-----------------------------------
lex.c | 195+++++++++++++++++++++++++++++--------------------------------------------------
main.c | 10+++-------
symbol.c | 144+++++++++++++++++++++++++++++++++++--------------------------------------------
symbol.h | 105++++++++++++++++++++++++++++++++++++++-----------------------------------------
syntax.h | 7++-----
tokens.h | 79+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
tree.c | 1+
types.c | 310+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
11 files changed, 742 insertions(+), 852 deletions(-)

diff --git a/decl.c b/decl.c @@ -1,5 +1,6 @@ #include <assert.h> #include <stddef.h> +#include <stdint.h> #include <string.h> #include "sizes.h" @@ -8,59 +9,76 @@ #include "syntax.h" #include "symbol.h" -char parser_out_home; -/* - * Number of nested declarations: - * Number of nested struct declarations - * +1 for the function declaration - * +1 for the field declaration - */ -static unsigned char nr_tags = NS_TAG; -static unsigned char nested_tags; +int8_t forbid_eof; -static struct symbol *declarator(struct ctype *tp, - unsigned char ns, unsigned char isfun); +static struct dcldata + *declarator0(struct dcldata *dp, uint8_t ns, int8_t flags); -static struct symbol * -directdcl(register struct ctype *tp, unsigned char ns, unsigned char isfun) +struct dcldata { + uint8_t op; + union { + unsigned short nelem; + struct symbol *sym; + struct funpars *pars; + uint8_t qlf; + } u; +}; + +static struct dcldata * +arydcl(struct dcldata *dp) +{ + expect('['); + expect(']'); + if (dp->op == 255) + error("too much declarators"); + dp->u.nelem = 0; + dp->op = ARY; + return dp + 1; +} + +static struct dcldata * +fundcl(struct dcldata *dp) +{ + expect('('); + expect(')');; + if (dp->op == 255) + error("too much declarators"); + dp->op = FTN; + dp->u.pars = NULL; + return dp + 1; +} + +static struct dcldata* +directdcl(struct dcldata *dp, uint8_t ns, int8_t flags) { register struct symbol *sym; - register char *err; + char *err; if (accept('(')) { - sym = declarator(tp, ns, isfun); + dp = declarator0(dp, ns, flags); expect(')'); - } else if (ns != NS_TYPE) { - if (yytoken == IDEN) { + } else if (flags) { + if (yytoken != IDEN) { + if (flags > 0) + goto expected; + sym = install(NULL, ns); + } else { sym = lookup(yytext, ns); - if (!sym->ctype.type) - sym->ctx = curctx; - else if (sym->ctx == curctx) + if (sym && sym->ctx == curctx) goto redeclared; + sym = install(yytext, ns); next(); - } else if (!isfun) { - goto expected; } + dp->op = IDEN; + dp->u.sym = sym; + ++dp; } for (;;) { - if (accept('(')) { - pushtype(FTN); - if (yytoken != ')') - ; /* TODO: prototyped function */; - expect(')'); - } else if (accept('[')) { - unsigned len = '0'; - - if (yytoken != ']') { - expect(CONSTANT); - len = yyval->i; - } - expect(']'); - pushtype(len); - pushtype(ARY); - } else { - return sym; + switch (yytoken) { + case '(': dp = fundcl(dp); break; + case '[': dp = arydcl(dp); break; + default: return dp; } } @@ -72,459 +90,272 @@ expected: error: error(err, yytext); } -struct ctype * -ctype(struct ctype *tp, unsigned char tok) +static struct dcldata* +declarator0(struct dcldata *dp, uint8_t ns, int8_t flags) { - register unsigned char type; - static char *err; - - type = tp->type; + if (accept('*')) { + register uint8_t qlf = 0; + while (yytoken == TQUALIFIER) { + qlf |= yylval.sym->u.c; + next(); + } + dp = declarator0(dp, ns, flags); + if (dp->op == 255) + error("too much declarators"); + dp->op = PTR; + dp->u.qlf = qlf; + return dp + 1; + } else { + return directdcl(dp, ns, TQUALIFIER); + } +} +static struct symbol * +declarator(struct ctype *tp, uint8_t ns, int8_t flags) +{ + struct dcldata data[NR_DECLARATORS+1]; + register struct dcldata *bp; + struct symbol *sym; - switch (tok) { - case VOID: case BOOL: case STRUCT: case UNION: case ENUM: case BITFLD: - if (type) - goto two_or_more;; - type = tok; - if (tp->c_signed || tp->c_unsigned) - goto invalid_sign; - break; - case CHAR: - if (type) - goto two_or_more; - type = CHAR; - break; - case SHORT: - if (type && type != INT) - goto two_or_more; - type = SHORT; - break; - case INT: - switch (type) { - case 0: type = INT; break; - case SHORT: type = SHORT; break; - case LONG: type = LONG; break; - default: goto two_or_more; - } - break; - case LONG: - switch (type) { - case 0: - case INT: type = LONG; break; - case LONG: type = LLONG; break; - case DOUBLE: type = LDOUBLE; break; - case LLONG: - case LDOUBLE: error("too much long"); - } - break; - case FLOAT: - if (type) - goto two_or_more; - type = FLOAT; - if (tp->c_signed || tp->c_unsigned) - goto invalid_sign; - break; - case DOUBLE: - if (type) - goto two_or_more; - if (!type) - type = DOUBLE; - else if (type == LONG) - type = LDOUBLE; - if (tp->c_signed || tp->c_unsigned) - goto invalid_sign; - break; - case UNSIGNED: - if (tp->c_unsigned) - goto duplicated; - if (tp->c_signed) - goto both_sign; - tp->c_unsigned = 1; - goto check_sign; - case SIGNED: - if (tp->c_signed) - goto duplicated; - if (tp->c_unsigned) - goto both_sign; - tp->c_signed = 1; - -check_sign: switch (type) { - case VOID: case BOOL: case FLOAT: case DOUBLE: case LDOUBLE: - goto invalid_sign; + data[NR_DECLARATORS].op = 255; + for (bp = declarator0(data, ns, flags); bp >= data; --bp) { + switch (bp->op) { + case PTR: + tp = qualifier(mktype(tp, PTR, NULL, 0), bp->u.qlf); + break; + case ARY: + tp = mktype(tp, ARY, NULL, bp->u.nelem); + break; + case FTN: + tp = mktype(tp, FTN, NULL, 0); + break; + case IDEN: + sym = bp->u.sym; + break; } - break; - case TYPENAME: - assert(!type); - if (tp->c_signed || tp->c_unsigned) - goto invalid_sign; - type = TYPEDEF; - break; - default: - assert(0); } - tp->type = type; - return tp; - -both_sign: - err = "both 'signed' and 'unsigned' in declaration specifiers"; - goto error; -duplicated: - err = "duplicated '%s'"; - goto error; -invalid_sign: - err = "invalid sign modifier"; - goto error; -two_or_more: - err = "two or more basic types"; -error: error(err, yytext); + sym->type = tp; + return sym; } -static void structdcl(register struct ctype *tp); -static void enumdcl(struct ctype *base); +static struct ctype *structdcl(void), *enumdcl(void); -static void -specifier(register struct ctype *tp, char *store, char *qlf) +static struct ctype * +specifier(int8_t *sclass) { - unsigned char tok; + struct ctype *tp = NULL; + int8_t qlf, sign, type, cls, cplex, size; + + qlf = sign = type = cls = size = cplex = 0; + + for (;;) { + register uint8_t *p; + struct symbol *sym = yylval.sym; - for (;; next()) { switch (yytoken) { + case SCLASS: p = &cls; break; case TQUALIFIER: - if (*qlf && !options.repeat) - error("duplicated '%s'", yytext); - if (yyval->c == RESTRICT) - error("invalid use of restrict"); - *qlf |= yyval->c; - break; - case STORAGE: - if (*store) - error("two or more storage specifier"); - /* TODO: check bad storage in file-scope */ - *store |= yyval->c; - break; + if ((qlf |= sym->u.c) & RESTRICT) + goto invalid_type; + goto next_token; case TYPE: - tp = ctype(tp, tok = yyval->c); - switch (tok) { - case ENUM: case STRUCT: case UNION: - next(); - if (tok == ENUM) - enumdcl(tp); - else - structdcl(tp); - return; + switch (sym->u.c) { + case ENUM: + tp = enumdcl(); goto set_type; + case STRUCT: case UNION: + tp = structdcl(); goto set_type; case TYPENAME: - tp->base = &yyval->ctype; - break; + tp = yylval.sym->type; + case VOID: case BOOL: case CHAR: + case INT: case FLOAT: case DOUBLE: +set_type: p = &type; break; + case SIGNED: case UNSIGNED: + p = &sign; break; + case LONG: + if (size == LONG) { + size = LONG+LONG; + goto next_token; + } + case SHORT: + p = &size; break; + case COMPLEX: case IMAGINARY: + p = &cplex; break; } break; default: - goto check_type; + goto check_types; } + if (*p) + goto invalid_type; + *p = sym->u.c; +next_token: next(); } -check_type: - if (!tp->c_signed && !tp->c_unsigned) { - switch (tp->type) { - case CHAR: - if (!options.charsign) { - case BOOL: tp->c_unsigned = 1; - break; - } - case INT: case SHORT: case LONG: case LLONG: - tp->c_signed = 1; +check_types: + if (!type) { + if (!sign && !size) { + warn(options.implicit, + "type defaults to 'int' in declaration"); } - } else if (!tp->type) { - tp->type = INT; + type = INT; } - return; -} - -static struct symbol * -declarator(struct ctype *tp, unsigned char ns, unsigned char isfun) -{ - unsigned char qlf[NR_DECLARATORS]; - register unsigned char *bp; - register unsigned char n = 0; - struct symbol *sym; - - if (yytoken == '*') { - for (bp = qlf; n < NR_DECLARATORS ; ++n) { - if (yytoken == '*') - *bp++ = PTR; - else if (yytoken == TQUALIFIER) - *bp++ = yyval->c; - else - goto direct; - } - error("Too much type declarators"); + if (sign && type != INT && type != CHAR || + cplex && type != FLOAT && type != DOUBLE || + size == SHORT && type != INT || + size == LONG && type != INT && type != DOUBLE || + size == LONG+LONG && type != INT) { + goto invalid_type; } - -direct: sym = directdcl(tp, ns, isfun); - - for (bp = qlf; n--; pushtype(*bp++)) - /* nothing */; - return sym; + if (sclass) + *sclass = cls; + if (!tp) + tp = ctype(type, sign, size, cplex); + return (qlf) ? qualifier(tp, qlf) : tp; + +invalid_type: + error("invalid type specification"); } static struct node * initializer(register struct ctype *tp) { if (accept('{')) { - struct compound c; - - c.tree = NULL; - addstmt(&c, initializer(tp)); - while (accept(',')) { - if (accept('}')) - return c.tree; - addstmt(&c, initializer(tp)); - } + initializer(tp); expect('}'); - return c.tree; } else { - return expr(); + do { + expr(); + } while (accept(',')); } } -static struct node * -listdcl(struct ctype *base, - char store, char qlf, - unsigned char ns, unsigned char isfun) +static struct ctype * +structdcl(void) { - struct compound c; - char *err; - - c.tree = NULL; - - if (yytoken == ';') - return NULL; - - do { - struct node *np, *aux; - register struct ctype *tp; - register struct symbol *sym; + uint8_t type = yylval.sym->u.c; - sym = declarator(base, ns, isfun); - sym->store = store; - sym->qlf = qlf; - sym->ctype = *decl_type(base); - if (sym->store) { - sym->tok = TYPE; - sym->c = TYPENAME; - } - tp = &sym->ctype; - aux = NULL; - - switch (tp->type) { - case FTN: - if (ns != NS_IDEN) - goto bad_type; - if (yytoken == '{') { - if (curctx != CTX_OUTER) - goto local_fun; - aux = function(sym); - addstmt(&c, node(ODEF, nodesym(sym), aux)); - return c.tree; - } - goto add_stmt; - case INT: case BOOL: - if (ns != NS_IDEN && accept(':')) { - expect(CONSTANT); - tp = ctype(NULL, BITFLD); - tp->len = yyval->i; - goto add_stmt; - } - goto add_init; - case STRUCT: case UNION: - if (tp->forward) - goto incomplete; - default: - add_init: - if (ns == NS_IDEN) { - if (accept('=')) - aux = initializer(tp); - } - add_stmt: - addstmt(&c, node(ODEF, nodesym(sym), aux)); - } - } while (accept(',')); - - return c.tree; - -bad_type: - err = "incorrect type for field"; - goto error; -local_fun: - err = "cannot use local functions"; - goto error; -incomplete: - err = "declaration of variable with incomplete type"; -error: error(err); + next(); + if (yytoken == IDEN) { + } + return NULL; } -static unsigned char -newtag(unsigned char type) +static struct ctype * +enumdcl(void) { - if (type == ENUM) - return 0; - if (nr_tags == NS_TAG + NR_MAXSTRUCTS) - error("too much structs/unions defined"); - return ++nr_tags; + return NULL; } -static struct symbol * -aggregate(register struct ctype *tp) +struct node * +decl(void) { - struct symbol *sym = NULL; - - tp->forward = 1; - if (yytoken == IDEN) { - register struct ctype *aux; - - sym = lookup(yytext, NS_TAG); - aux = &sym->ctype; - if (aux->type) { - if (aux->type != tp->type) - goto bad_type; - *tp = *aux; - } else { - tp->tag = sym->name; - tp->ns = newtag(tp->type); - sym->ctype = *tp; - } - next(); - } else { - tp->ns = newtag(tp->type); + struct ctype *tp; + struct symbol *sym; + int8_t sclass; + + tp = specifier(&sclass); + if (yytoken != ';') { + do { + sym = declarator(tp, NS_IDEN, 1); + /* assign storage class */ + if (accept('=')) + initializer(sym->type); + } while (accept(',')); } - return sym; - -bad_type: - error("'%s' defined as wrong kind of tag", yytext); + expect(';'); + return NULL; } -static void -structdcl(register struct ctype *tp) +static struct symbol * +fielddcl(void) { + struct ctype *tp; struct symbol *sym; - sym = aggregate(tp); - - if (!accept('{')) - return; - - if (sym && !sym->ctype.forward) - error("struct/union already defined"); - - if (nested_tags == NR_STRUCT_LEVEL) - error("too much nested structs/unions"); - - ++nested_tags; - while (!accept('}')) { - struct ctype base; - struct node *np; - char store = 0, qlf = 0; - - initctype(&base); - specifier(&base, &store, &qlf); - - if (store) - error("storage specifier in a struct/union field declaration"); - - listdcl(&base, store, qlf, tp->ns, 0); - expect(';'); + switch (yytoken) { + case IDEN: + warn(options.implicit, + "type defaults to 'int' in declaration"); + tp = inttype; + break; + case SCLASS: + error("storage class '%s' in struct/union field", yytext); + case TYPE: case TQUALIFIER: + tp = specifier(NULL); + break; + case ';': + break; + default: + error("declaration expected"); } - --nested_tags; - if (sym) - sym->ctype.forward = 0; - tp->forward = 0; -} - -static void -enumdcl(struct ctype *base) -{ - static int val; - - aggregate(base); - if (!accept('{')) - return; - val = 0; - - do { - register struct symbol *sym; - register struct ctype *tp; - - if (yytoken != IDEN) - break; - sym = lookup(yytext, NS_IDEN); - tp = &sym->ctype; - if (tp->type && sym->ctx == curctx) - error("'%s' redefined", yytext); - next(); - if (accept('=')) { - expect(CONSTANT); - val = yyval->i; - } - ctype(tp, INT); - tp->base = base; - sym->i = val++; - } while (accept(',')); - - expect('}'); -} - -struct node * -decl(unsigned char ns) -{ - struct ctype base; - struct node *np; - char store = 0, qlf = 0; - - initctype(&base); - specifier(&base, &store, &qlf); - - if (store && ns != NS_IDEN) - error("storage specifier in a struct/union field declaration"); + if (yytoken != ';') { + do { + sym = declarator(tp, 0, 1); + if (accept(':')) + ; /* TODO: bitfields */ + /* TODO: add to the aggregate */ + } while (accept(',')); + } - np = listdcl(&base, store, qlf, ns, 0); expect(';'); - return np; + return NULL; } -void -type_name(struct ctype *tp) +struct node * +typename(void) { - char store = 0, qlf = 0; - - initctype(tp); - specifier(tp, &store, &qlf); - declarator(tp, NS_TYPE, 0); - return; + declarator(specifier(NULL), NS_IDEN, -1)->type; + return NULL; } struct node * extdecl(void) { - struct ctype base; - struct node *np; - char store = 0, qlf = 0; + struct ctype *tp; + int8_t sclass; + struct symbol *sym; + extern struct symbol *curfun; - initctype(&base); + forbid_eof = 1; switch (yytoken) { case IDEN: warn(options.implicit, "type defaults to 'int' in declaration"); - base.type = INT; + tp = inttype; + break; + case TYPE: case SCLASS: case TQUALIFIER: + tp = specifier(&sclass); + if (sclass == REGISTER || sclass == AUTO) + error("incorrect storage class for file-scope declaration"); break; - case TYPE: case STORAGE: case TQUALIFIER: - specifier(&base, &store, &qlf); + case ';': break; default: error("declaration expected"); } - np = listdcl(&base, store, qlf, 0, 0); + if (yytoken != ';') { + do { + extern void printtype(struct ctype *tp); + sym = declarator(tp, NS_IDEN, 1); + printtype(sym->type); + /* assign storage class */ + if (isfun(sym)) { + if (yytoken == '{') { + curfun = sym; + context(function); + freesyms(NS_LABEL); + } + } else if (accept('=')) { + initializer(sym->type); + } + } while (accept(',')); + } + + forbid_eof = 0; expect(';'); -}- \ No newline at end of file + return NULL; +} diff --git a/expr.c b/expr.c @@ -1,4 +1,5 @@ #include <stddef.h> +#include <stdint.h> #include <stdio.h> #include "cc.h" @@ -17,14 +18,12 @@ primary(void) switch (yytoken) { case IDEN: - sym = lookup(yytext, NS_IDEN); - if (!sym->ctype.type) + if ((sym = lookup(yytext, NS_IDEN)) == NULL) error("'%s' undeclared", yytext); next(); np = nodesym(sym); break; case CONSTANT: - sym = yyval; next(); np = nodesym(sym); break; @@ -92,10 +91,9 @@ unary(void) case SIZEOF: /* TODO: Implement sizeof */ next(); if (accept('(')) { - struct ctype type; switch (yytoken) { - case STORAGE: case TQUALIFIER: case TYPE: - type_name(&type); + case TQUALIFIER: case TYPE: + context(typename); break; default: expr(); @@ -129,13 +127,12 @@ call_unary: static struct node * cast(void) { - struct ctype type; - repeat: if (yytoken == '(') { switch (ahead()) { - case STORAGE: case TQUALIFIER: case TYPE: + case TQUALIFIER: case TYPE: next(); - type_name(&type); /* TODO: type_name should return a np*/ + /* TODO: type_name should return a np*/ + context(typename); expect(')'); goto repeat; default: diff --git a/flow.c b/flow.c @@ -1,5 +1,6 @@ #include <assert.h> +#include <stdint.h> #include <stdio.h> #include "cc.h" @@ -13,7 +14,7 @@ static struct node *stmt(void); static unsigned char blocks[NR_BLOCK]; static unsigned char *blockp = blocks; -static struct symbol *curfun; +struct symbol *curfun; static void push(register unsigned char b) @@ -139,10 +140,8 @@ label(void) { register struct symbol *sym = lookup(yytext, NS_LABEL); - if (sym->label) - error("label '%s' already defined", yytext); - insert(sym, CTX_FUNC); - sym->label = 1; + /* TODO: detect repeated labels */ + /* TODO: install in symbol table */ next(), next(); /* skip IDEN and ':' */ return node(OLABEL, nodesym(sym), stmt()); } @@ -221,28 +220,19 @@ Default(void) static struct node * compound(void) { - register struct node *np; - unsigned char nodecl = 0; - struct compound c; - - c.tree = NULL; expect('{'); - new_ctx(); - while (!accept('}')) { - if (np = decl(0)) { - if (nodecl) { - warn(options.mixdcls, - "mixed declarations and code"); - } - } else { - np = stmt(); - nodecl = 1; - } - addstmt(&c, np); - } - del_ctx(); - return c.tree; +repeat: switch (yytoken) { + case TYPE: case SCLASS: case TQUALIFIER: + decl(); + goto repeat; + case '}': + next(); + return NULL; + default: + stmt(); + goto repeat; + } } static struct node * @@ -251,7 +241,7 @@ stmt(void) register struct node *np; switch (yytoken) { - case '{': return compound(); + case '{': return context(compound); case SWITCH: return Switch(); case IF: return If(); case FOR: return For(); @@ -271,16 +261,8 @@ stmt(void) } struct node * -function(register struct symbol *sym) +function(void) { - curfun = sym; return node(OFTN, compound(), NULL); } -void -run(register struct node *np) -{ - prtree(np); - putchar('\n'); - freesyms(); -} diff --git a/lex.c b/lex.c @@ -1,4 +1,5 @@ +#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -9,70 +10,39 @@ #include "symbol.h" #include "sizes.h" -unsigned char yytoken; -char yytext[IDENTSIZ + 1]; -static char yybuf[IDENTSIZ + 1]; +static FILE *yyin; +const char *filename; unsigned linenum; unsigned columnum; -const char *filename; -struct keyword { - char *str; - unsigned char tok; - unsigned char value; -}; +uint8_t yytoken, yyntoken;; +union yystype yylval; +char yytext[IDENTSIZ + 1]; -static FILE *yyin; -static struct symbol yysym = {.name = ""}, *yynval = &yysym; -struct symbol *yyval = &yysym; +static union yystype yynlval; +static char yybuf[IDENTSIZ + 1]; -struct symbol * +static uint8_t integer(char *s, char base) { static struct ctype *tp; - register struct symbol *sym; - static long long v; static char ch; - tp = initctype(xmalloc(sizeof(*tp))); + /* TODO: implement again */ type: switch (ch = toupper(getc(yyin))) { case 'L': - tp = ctype(tp, LONG); goto type; case 'U': - tp = ctype(tp, UNSIGNED); goto type; default: ungetc(ch, yyin); } - v = strtoll(s, NULL, base); - sym = lookup(NULL, NS_IDEN); - sym->tok = CONSTANT; - sym->ctype = *tp; - - switch (tp->type) { - case INT: - sym->i = v; - break; - case SHORT: - sym->s = v; - break; - case LONG: - sym->l = xmalloc(sizeof(long)); - *sym->l = v; - break; - case LLONG: - sym->ll = xmalloc(sizeof(long long)); - *sym->ll = v; - break; - } - - return sym; + return CONSTANT; } -static struct symbol * +static uint8_t number(void) { register char *bp, ch; @@ -118,8 +88,11 @@ end: if (bp == &yybuf[IDENTSIZ]) void init_keywords(void) { - static struct keyword buff[] = { - {"auto", STORAGE, AUTO}, + static struct { + char *str; + uint8_t token, value; + } *bp, buff[] = { + {"auto", SCLASS, AUTO}, {"break", BREAK, BREAK}, {"_Bool", TYPE, BOOL}, {"_Complex", TYPE, COMPLEX}, @@ -132,7 +105,7 @@ init_keywords(void) {"double", TYPE, DOUBLE}, {"else", ELSE, ELSE}, {"enum", TYPE, ENUM}, - {"extern", STORAGE, EXTERN}, + {"extern", SCLASS, EXTERN}, {"float", TYPE, FLOAT}, {"for", FOR, FOR}, {"goto", GOTO, GOTO}, @@ -140,16 +113,16 @@ init_keywords(void) {"int", TYPE, INT}, {"_Imaginary", TYPE, IMAGINARY}, {"long", TYPE, LONG}, - {"register", STORAGE, REGISTER}, + {"register", SCLASS, REGISTER}, {"restrict", TQUALIFIER, RESTRICT}, {"return", RETURN, RETURN}, {"short", TYPE, SHORT}, {"signed", TYPE, SIGNED}, {"sizeof", SIZEOF, SIZEOF}, - {"static", STORAGE, STATIC}, + {"static", SCLASS, STATIC}, {"struct", TYPE, STRUCT}, {"switch", SWITCH, SWITCH}, - {"typedef", STORAGE, TYPEDEF}, + {"typedef", SCLASS, TYPEDEF}, {"union", TYPE, UNION}, {"unsigned", TYPE, UNSIGNED}, {"void", TYPE, VOID}, @@ -157,61 +130,38 @@ init_keywords(void) {"while", WHILE, WHILE}, {NULL, 0, 0}, }; - register struct keyword *bp; register struct symbol *sym; - for (bp = buff; bp->str; ++bp) { - sym = lookup(bp->str, NS_IDEN); - sym->tok = bp->tok; - sym->c = bp->value; + for (bp = buff; bp->str; ++bp) { + sym = install(bp->str, NS_KEYWORD); + sym->token = bp->token; + sym->u.c = bp->value; } } -static struct symbol * +static uint8_t iden(void) { - register char ch, *bp; + register char *bp; + register int c; - for (bp = yybuf; bp < &yybuf[IDENTSIZ]; *bp++ = ch) { - if (!isalnum(ch = getc(yyin)) && ch != '_') + for (bp = yybuf; bp < &yybuf[IDENTSIZ]; *bp++ = c) { + if (!isalnum(c = getc(yyin)) && c != '_') break; } if (bp == &yybuf[IDENTSIZ]) error("identifier too long %s", yybuf); *bp = '\0'; - ungetc(ch, yyin); - - return lookup(yybuf, NS_IDEN); -} - -static unsigned char -skip(void) -{ - static int c; - extern char parser_out_home; - - if (c != EOF) { - while (c != EOF && isspace(c = getc(yyin))) { - switch (c) { - case '\n': ++linenum, columnum = 1; break; - case '\t': columnum += 8; break; - default: ++columnum; break; - } - } - } - if (c == EOF) { - if (parser_out_home) - error("Find EOF while parsing"); - return 0; - } ungetc(c, yyin); - return 1; + + yynlval.sym = lookup(yybuf, NS_IDEN); + return (yynlval.sym) ? yynlval.sym->token : IDEN; } -static unsigned char -follow(unsigned char op, unsigned char eq, unsigned char rep) +static uint8_t +follow(uint8_t op, uint8_t eq, uint8_t rep) { - register char c = getc(yyin); + register int c = getc(yyin); yybuf[1] = c; yybuf[2] = '\0'; @@ -225,14 +175,14 @@ follow(unsigned char op, unsigned char eq, unsigned char rep) return op; } -static unsigned char -rel_shift(unsigned char op) +static uint8_t +rel_shift(uint8_t op) { - static char tokens[2][3] = { + static uint8_t tokens[2][3] = { {GE, SHL, SHL_EQ}, {LE, SHR, SHR_EQ} }; - register char c = getc(yyin); + register int c = getc(yyin); register char *tp = tokens[op == '>']; yybuf[1] = c; @@ -253,7 +203,7 @@ rel_shift(unsigned char op) return op; } -static unsigned char +static uint8_t minus(void) { register int c = getc(yyin); @@ -270,10 +220,10 @@ minus(void) } } -static unsigned char +static uint8_t operator(void) { - register unsigned char c = getc(yyin); + register uint8_t c = getc(yyin); yybuf[0] = c; yybuf[1] = '\0'; @@ -292,47 +242,46 @@ operator(void) } } -void +uint8_t next(void) { - register unsigned char c; + static int c; + extern int8_t forbid_eof; strcpy(yytext, yybuf); - yyval = yynval; - yytoken = yynval->tok; - yynval = &yysym; - - if (!skip()) { - yysym.tok = EOFTOK; - } else { - ungetc(c = getc(yyin), yyin); - if (isalpha(c) || c == '_') - yynval = iden(); - else if (isdigit(c)) - yynval = number(); - else - yysym.tok = operator(); + yylval = yynlval; + if ((yytoken = yyntoken) == EOFTOK) { + if (forbid_eof) + error("Find EOF while parsing"); + goto ret; } -} -unsigned char -ahead(void) -{ - return yynval->tok; -} + while (isspace(c = getc(yyin))) { + switch (c) { + case '\n': ++linenum, columnum = 1; break; + case '\t': columnum += 8; break; + default: ++columnum; break; + } + } -char -accept(register unsigned char tok) -{ - if (yytoken == tok) { - next(); - return 1; + if (c == EOF) { + yyntoken = EOFTOK; + goto ret; } - return 0; + + ungetc(c, yyin); + if (isalpha(c) || c == '_') + yyntoken = iden(); + else if (isdigit(c)) + yyntoken = number(); + else + yyntoken = operator(); + +ret: return yytoken; } void -expect(register unsigned char tok) +expect(register uint8_t tok) { if (yytoken != tok) error("unexpected %s", yytext); diff --git a/main.c b/main.c @@ -1,25 +1,21 @@ #include <stddef.h> +#include <stdint.h> #include "cc.h" #include "tokens.h" #include "syntax.h" extern void open_file(const char *file); -extern void run(struct node *np); struct user_opt options; - - int main(int argc, char *argv[]) { - struct node *np; - init_keywords(); open_file(NULL); - for (next(); yytoken != EOFTOK; run(np)) - np = extdecl(); + for (next(); yytoken != EOFTOK; extdecl()); + /* nothing */; return 0; } diff --git a/symbol.c b/symbol.c @@ -1,5 +1,6 @@ -#include <assert.h> +#include <stdint.h> +#include <stdint.h> #include <stdlib.h> #include <string.h> @@ -9,117 +10,100 @@ #define NR_SYM_HASH 32 -unsigned char curctx; +uint8_t curctx; +uint8_t namespace = NS_KEYWORD + 1 ; -static struct symbol *htab[NR_SYM_HASH]; -static struct symbol *head, *headfun; +static struct symtab { + struct symbol *head; + struct symbol *htab[NR_SYM_HASH]; +} symtab [NR_NAMESPACES]; - -unsigned char +static inline uint8_t hash(register const char *s) { - register unsigned char h, ch; + register uint8_t h, ch; for (h = 0; ch = *s++; h += ch) /* nothing */; - return h; -} - -void -new_ctx(void) -{ - ++curctx; + return h & NR_SYM_HASH - 1; } void -del_ctx(void) +freesyms(uint8_t ns) { - register struct symbol *sym, *next; - static char *s; + static struct symtab *tbl; + register struct symbol *sym; - for (sym = head; sym; sym = next) { + tbl = &symtab[ns]; + for (sym = tbl->head; sym; sym = sym->next) { if (sym->ctx <= curctx) break; - if ((s = sym->name) != NULL) - htab[hash(s) & NR_SYM_HASH - 1] = sym->hash; - next = sym->next; - sym->next = headfun; - headfun = sym; + tbl->htab[hash(sym->name)] = sym->hash; + free(sym->name); + free(sym); } - --curctx; } -void -freesyms(void) +struct node * +context(struct node * (*fun)(void)) { - register struct symbol *sym, *next; - - if (curctx == CTX_OUTER) { - for (sym = headfun; sym; sym = next) { - next = sym->next; - free(sym->name); - free(sym); - } - } + uint8_t ns; + struct node *np; + + ns = namespace; + ++curctx; + np = fun(); + --curctx; + namespace = ns; + + freesyms(NS_IDEN); + freesyms(NS_TAG); + + return np; } struct symbol * -lookup(register const char *s, unsigned char ns) +lookup(register char *s, uint8_t ns) { + extern union yystype yylval; + static struct symtab *tbl; register struct symbol *sym; - extern struct symbol *yyval; - static unsigned char key; - register char *t; - if (s == NULL) { - sym = xcalloc(1, sizeof(*sym)); - sym->next = head; + if (ns == NS_IDEN && (sym = yylval.sym) && !strcmp(sym->name, s)) return sym; - } - if (yyval->ns == ns && !strcmp(yyval->name, s)) - return yyval; - key = hash(s) & NR_SYM_HASH - 1; - for (sym = htab[key]; sym; sym = sym->hash) { - t = sym->name; - if (ns == sym->ns && *t == *s && !strcmp(t, s)) + tbl = &symtab[(ns >= NR_NAMESPACES) ? NS_IDEN : ns]; + for (sym = tbl->htab[hash(s)]; sym; sym = sym->hash) { + register char *t = sym->name; + if (sym->ns == ns && t && *t == *s && !strcmp(t, s)) return sym; } - sym = xcalloc(1, sizeof(*sym)); - sym->name = xstrdup(s); - sym->next = head; - sym->ctx = curctx; - sym->ns = ns; - sym->tok = IDEN; - head = sym; - sym->hash = htab[key]; - htab[key] = sym; - - return sym; + return NULL; } -void -insert(struct symbol *sym, unsigned char ctx) +struct symbol * +install(char *s, uint8_t ns) { - register struct symbol *p, *q; + register struct symbol *sym; + register struct symbol **t; + struct symtab *tbl; - for (q = p = head; p; q = p, p = p->next) { - if (p == sym) - break; - } - assert(p); /* sym must be in the list */ - q->next = p->next; /* remove from the list */ + if (ns == NS_KEYWORD) + ns = NS_IDEN; + else if (s != NULL) + s = xstrdup(s); - for (q = p = head; p; q = p, p = p->next) { - if (p->ctx <= ctx) - break; - } - if (q == NULL) { - head = sym; - sym->next = NULL; - } else { - q->next = sym; - sym->next = p; - } + sym = xcalloc(1, sizeof(*sym)); + sym->name = s; + sym->ctx = curctx; + sym->token = IDEN; + tbl = &symtab[(ns >= NR_NAMESPACES) ? NS_IDEN : ns]; + sym->next = tbl->head; + tbl->head = sym; + t = &tbl->htab[hash(s)]; + sym->hash = *t; + *t = sym; + + return sym; } diff --git a/symbol.h b/symbol.h @@ -1,80 +1,77 @@ -#pragma once #ifndef SYMBOL_H #define SYMBOL_H -#if ! __bool_true_false_are_defined -# include <stdbool.h> -#endif - #define CTX_OUTER 0 #define CTX_FUNC 1 +#define isfun(t) 0 + enum { NS_IDEN = 0, - NS_TYPE, NS_LABEL, - NS_TAG + NS_TAG, + NR_NAMESPACES, + NS_KEYWORD, + NS_FREE }; +struct funpars; +struct symbol; struct ctype { - unsigned type : 5; - bool c_const : 1; - bool c_restrict : 1; - bool c_volatile : 1; - bool c_unsigned : 1; - bool c_signed : 1; - bool forward : 1; - union { - struct { - unsigned char ns; - char *tag; - }; - unsigned len; - }; - struct ctype *base; + uint8_t op; /* type builder operator */ + uint8_t size; /* size of variables */ + uint16_t nelem; /* number of elements in arrays */ + unsigned forward : 1; /* forward type */ + unsigned cplex : 1; /* complex specifier */ + unsigned imag : 1; + unsigned sign : 1; /* sign type */ + struct symbol *sym; /* symbol of the tag identifier */ + struct ctype *type; /* base type */ + struct ctype *next; /* next element in the hash */ + struct funpars *pars; /* function parameters */ +}; + +struct funpars { + struct ctype *type; + struct funpars *next; }; struct symbol { - struct ctype ctype; - char store; - char qlf; - unsigned char ctx; - unsigned char ns; char *name; - unsigned char tok; - struct { - union { - char c; /* numerical constants */ - short s; - int i; - long *l; - long long *ll; - unsigned char label; - }; - }; + struct ctype *type; + uint8_t ctx; + uint8_t token; + uint8_t ns; + union { + char c; + } u; struct symbol *next; struct symbol *hash; }; +extern void freesyms(uint8_t ns); -extern struct ctype *decl_type(struct ctype *t); -extern void pushtype(unsigned mod); -extern struct ctype *ctype(struct ctype *tp, unsigned char tok); -extern void new_ctx(void); -extern void del_ctx(void); -extern void freesyms(void); -extern struct symbol *lookup(const char *s, unsigned char ns); -extern void insert(struct symbol *sym, unsigned char ctx); -extern void delctype(struct ctype *tp); -extern unsigned char hash(register const char *s); -extern struct ctype *initctype(register struct ctype *tp); +extern struct ctype *qualifier(struct ctype *tp, uint8_t qlf), + *ctype(int8_t type, int8_t sign, int8_t size, int8_t cplex), + *mktype(struct ctype *tp, + uint8_t op, struct symbol *tag, uint16_t nelem); -#ifndef NDEBUG -extern void ptype(register struct ctype *t); -#else -# define ptype(t) -#endif +extern struct symbol + *lookup(char *s, unsigned char ns), + *install(char *s, unsigned char ns); + +extern struct node *context(struct node * (*fun)(void)); + +extern struct ctype *voidtype, + *uchartype, *chartype, + *uinttype, *inttype, + *ushortype, *shortype, + *longtype, *ulongtype, + *ullongtype, *llongtype, + *floattype, *cfloattype, *ifloattype, + *doubletype, *cdoubletype, *idoubletype, + *ldoubletype, *cldoubletype,*ildoubletype; #endif diff --git a/syntax.h b/syntax.h @@ -28,11 +28,8 @@ struct compound { struct node_op2 *last; }; -extern struct node *expr(void); -extern struct node *extdecl(void); -extern struct node *decl(unsigned char ns); -extern void type_name(struct ctype *tp); -extern struct node *function(struct symbol *sym); +extern struct node *expr(void), *extdecl(void), *decl(void), + *typename(void), *function(void); extern struct node *node(unsigned char op, struct node *l, struct node *r); extern struct node *nodesym(struct symbol *sym); diff --git a/tokens.h b/tokens.h @@ -5,21 +5,47 @@ # include <stdbool.h> #endif +#define FLOAT 1 +#define INT 2 +#define BOOL 3 +#define PTR 4 +#define ARY 5 +#define FTN 6 + +#define VOID 7 +#define STRUCT 8 +#define UNION 9 +#define ENUM 10 +#define TYPENAME 11 + +#define CHAR 12 +#define DOUBLE 13 +#define SHORT 14 +#define LONG 15 + +#define COMPLEX 16 +#define IMAGINARY 17 +#define UNSIGNED 18 +#define SIGNED 19 + +#define BITFLD 20 + +#define CONST (1<<0) +#define VOLATILE (1<<1) +#define RESTRICT (1<<2) + +#define TYPEDEF 1 +#define EXTERN 2 +#define STATIC 3 +#define AUTO 4 +#define REGISTER 5 + +#define accept(t) ((bool) (yytoken == (t) ? next() : 0)) +#define ahead() yyntoken -/* Don't change this codification because program used it!!! */ enum tokens { - /* types */ - INT = 1, CHAR, FLOAT, LONG, LLONG, SHORT, VOID, DOUBLE, - LDOUBLE, STRUCT, UNION, ENUM, BOOL, ARY, PTR, FTN, - COMPLEX, IMAGINARY, BITFLD, TYPENAME, TYPE, - /* type qualifier */ - TQUALIFIER, - /* sign specifier */ - UNSIGNED, SIGNED, - /* storage specifier */ - STORAGE, - /* other tokens */ - IDEN = 128, CONSTANT, SIZEOF, + TQUALIFIER = 128, TYPE, IDEN, SCLASS, + CONSTANT, SIZEOF, INDIR, INC, DEC, SHL, SHR, LE, GE, EQ, NE, AND, OR, MUL_EQ, DIV_EQ, MOD_EQ, ADD_EQ, SUB_EQ, AND_EQ, @@ -29,28 +55,17 @@ enum tokens { CONTINUE, BREAK, RETURN, EOFTOK, NOTOK }; -#define TYPEDEF (1<<0) -#define EXTERN (1<<1) -#define STATIC (1<<2) -#define AUTO (1<<3) -#define REGISTER (1<<4) - -#define VOLATILE (1<<0) -#define CONST (1<<1) -#define RESTRICT (1<<2) - struct symbol; -extern struct symbol *yyval; +union yystype { + struct symbol *sym; +}; +extern union yystype yylval; extern char yytext[]; -extern size_t yylen; -extern unsigned char yytoken; +extern uint8_t yytoken, yyntoken; + +extern void init_lex(void), init_keywords(void), expect(uint8_t tok); +extern uint8_t next(void); -extern void init_lex(void); -extern void next(void); -extern char accept(unsigned char tok); -extern void expect(unsigned char tok); -extern void init_keywords(void); -extern unsigned char ahead(void); #endif diff --git a/tree.c b/tree.c @@ -1,5 +1,6 @@ #include <assert.h> +#include <stdint.h> #include <stdio.h> #include "cc.h" diff --git a/types.c b/types.c @@ -1,5 +1,5 @@ -#include <assert.h> +#include <stdint.h> #include <stdlib.h> #include <string.h> @@ -8,112 +8,254 @@ #include "tokens.h" #include "symbol.h" +#define NR_TYPE_HASH 16 +#define PTRSIZE 2 +#define CHARSIZE 1 +#define SHORTSIZE 2 +#define INTSIZE 2 +#define LONGSIZE 4 +#define LLONGSIZE 8 +#define FLOATSIZE 4 +#define LFLOATSIZE 8 +#define LLFLOATSIZE 16 -static unsigned char stack[NR_DECLARATORS]; -static unsigned char *stackp = stack; +struct ctype + *voidtype = &(struct ctype) { + .op = VOID + }, + *uchartype = &(struct ctype) { + .op = INT, + .size = CHARSIZE, + .sign = 1 + }, + *chartype = &(struct ctype) { + .op = INT, + .size = CHARSIZE, + }, + *uinttype = &(struct ctype) { + .op = INT, + .size = INTSIZE, + .sign = 1 + }, + *inttype = &(struct ctype) { + .op = INT, + .size = INTSIZE, + .sign = 1 + }, + *ushortype = &(struct ctype) { + .op = INT, + .size = SHORTSIZE, + }, + *shortype = &(struct ctype) { + .op = INT, + .size = INTSIZE, + }, + *longtype = &(struct ctype) { + .op = INT, + .size = LONGSIZE, + }, + *ulongtype = &(struct ctype) { + .op = INT, + .size = LONGSIZE, + .sign = 1 + }, + *ullongtype = &(struct ctype) { + .op = INT, + .size = LLONGSIZE, + .sign = 1 + }, + *llongtype = &(struct ctype) { + .op = INT, + .size = LLONGSIZE, + }, + *floattype = &(struct ctype) { + .op = FLOAT, + .size = FLOATSIZE + }, + *cfloattype = &(struct ctype) { + .op = FLOAT, + .size = FLOATSIZE, + .cplex = 1 + }, + *ifloattype = &(struct ctype) { + .op = FLOAT, + .size = FLOATSIZE, + .imag = 1 + }, + *doubletype = &(struct ctype) { + .op = FLOAT, + .size = FLOATSIZE + }, + *cdoubletype = &(struct ctype) { + .op = FLOAT, + .size = 0, + .cplex = 1 + }, + *idoubletype = &(struct ctype) { + .op = FLOAT, + .size = 0, + .imag = 1 + }, + *ldoubletype = &(struct ctype) { + .op = FLOAT, + .size = LLFLOATSIZE + }, + *cldoubletype = &(struct ctype) { + .op = FLOAT, + .size = 0, + .cplex = 1 + }, + *ildoubletype = &(struct ctype) { + .op = FLOAT, + .size = 0, + .imag = 1 + }; struct ctype * -initctype(register struct ctype *tp) +ctype(int8_t type, int8_t sign, int8_t size, int8_t cplex) { - memset(tp, 0, sizeof(*tp)); - tp->forward = 1; - return tp; -} + if (type == CHAR && !sign) + sign = options.charsign; + if (sign == SIGNED) + sign = 0; + if (type == DOUBLE) + type = FLOAT, size += LONG; -void -delctype(register struct ctype *tp) -{ - if (!tp) - return; - if (tp->base) - delctype(tp->base); - free(tp); + switch (type) { + case VOID: return voidtype; + case CHAR: return (sign) ? uchartype : chartype; + case INT: switch (size) { + case 0: return (sign) ? uinttype : inttype; + case SHORT: return (sign) ? ushortype : shortype; + case LONG: return (sign) ? longtype : ulongtype; + case LONG+LONG: return (sign) ? ullongtype : llongtype; + } + case FLOAT: switch (size) { + case 0: switch (cplex) { + case 0: return floattype; + case COMPLEX: return cfloattype; + case IMAGINARY: return ifloattype; + } + case LONG: switch (cplex) { + case 0: return doubletype; + case COMPLEX: return cdoubletype; + case IMAGINARY: return ifloattype; + } + case LONG+LONG: switch (cplex) { + case 0: return ldoubletype; + case COMPLEX: return cldoubletype; + case IMAGINARY: return ildoubletype; + } + } + } } -static struct ctype * -mktype(register struct ctype *tp, unsigned char op) +struct ctype * +mktype(struct ctype *tp, uint8_t op, + struct symbol *sym, uint16_t nelem) { - unsigned len; + static struct ctype *typetab[NR_TYPE_HASH], **tbl; + static uint8_t t; + static unsigned short size; + register struct ctype *bp; - switch (op) { - case ARY: - assert(stackp != stack); - len = *--stackp; - case PTR: case FTN: { - register struct ctype *aux = tp; - - tp = xmalloc(sizeof(*tp)); - initctype(tp); - tp->type = op; - tp->base = aux; - tp->len = len; - break; - } - case VOLATILE: - tp->c_volatile = 1; - break; - case RESTRICT: - tp->c_restrict = 1; - break; - case CONST: - tp->c_const = 1; - break; - default: - assert(0); + t = (op ^ (uint8_t) ((unsigned short) tp >> 3)) + & NR_TYPE_HASH-1; + tbl = &typetab[t]; + if (op != FTN) { + for (bp = *tbl; bp; bp = bp->next) { + if (bp->type == tp && bp->op == op && + bp->sym == sym && bp->nelem == nelem) { + return bp; + } + } } - return tp; -} -void -pushtype(unsigned mod) -{ - if (stackp == stack + NR_DECLARATORS) - error("Too much type declarators"); - *stackp++ = mod; + switch (op) { + case PTR: size = PTRSIZE; break; + case FTN: size = 0; break; + case ARY: size = tp->size * nelem; break; + default: size = tp->size; break; + } + bp = xmalloc(sizeof(*bp)); + bp->next = *tbl; + bp->type = tp; + bp->op = op; + bp->nelem = nelem; + bp->sym = sym; + bp->pars = NULL; + bp->size = size; + return *tbl = bp; } struct ctype * -decl_type(struct ctype *tp) +qualifier(struct ctype *tp, uint8_t qlf) { - struct ctype *new = xmalloc(sizeof(*new)); - *new = *tp; + uint8_t q = tp->op; - while (stackp != stack) - new = mktype(new, *--stackp); - return new; + if (q & TQUALIFIER) { + if (q == qlf) + return tp; + tp = tp->type; + qlf |= q; + } + return mktype(tp, qlf|TQUALIFIER, NULL, 0); } +#include <stdio.h> +static void +ptype(struct ctype *tp) +{ + uint8_t op; + struct funpars *fp; -#ifndef NDEBUG -#include <stdio.h> + if (!tp) + return; + op = tp->op; + if (op & TQUALIFIER) { + if (op & CONST) + fputs("const ", stdout); + if (op & VOLATILE) + fputs("volatile ", stdout); + if (op & RESTRICT) + fputs("restrict ", stdout); + } else { + switch (op) { + case PTR: fputs("pointer ", stdout); break; + case ARY: fputs("array ", stdout); break; + case STRUCT: fputs("struct", stdout); break; + case UNION: fputs("union", stdout); break; + case ENUM: fputs("enum", stdout); break; + case BOOL: fputs("bool", stdout); break; + case INT: + printf("int size=%u sign=%u", tp->size, tp->sign); + break; + case FLOAT: + printf("float size=%u cplex=%u", tp->size, tp->cplex); + break; + case TYPENAME: + printf("typename %s type ", tp->sym->name); + break; + case FTN: + fputs("function(", stdout); + for (fp = tp->pars; fp; fp = fp->next) { + ptype(tp); + if (fp->next) + fputs(", ", stdout); + } + fputs(") ", stdout); + break; + } + } + ptype(tp->type); +} void -ptype(register struct ctype *tp) +printtype(struct ctype *tp) { - static const char *strings[] = { - [0] = "[no type]", - [ARY] = "array of ", - [PTR] = "pointer to ", - [FTN] = "function that returns ", - [VOLATILE] = "volatile ", - [RESTRICT] = "restrict ", - [CONST] = "const ", - [INT] = "int ", - [CHAR] = "char ", - [FLOAT] = "float ", - [LONG] = "long ", - [LLONG] = "long long ", - [SHORT] = "short ", - [VOID] = "void ", - [DOUBLE] = "double ", - [LDOUBLE] = "long double " - }; - assert(tp); - - for (; tp; tp = tp->base) - fputs(strings[tp->type], stdout); + printf("type = %p ", tp); + ptype(tp); putchar('\n'); } -#endif