static CTy * directdeclarator(CTy *basety, char **name) { CTy *ty, *stub; *name = 0; switch(tok->k) { case '(': expect('('); stub = gcmalloc(sizeof(CTy)); *stub = *basety; ty = declarator(stub, name, 0); expect(')'); *stub = *declaratortail(basety); return ty; case TOKIDENT: if(name) *name = tok->v; next(); return declaratortail(basety); default: if(!name) errorposf(&tok->pos, "expected ident or ( but got %s", tokktostr(tok->k)); return declaratortail(basety); } errorf("unreachable"); return 0; }
static Val * randstruct(int depth) { Val *r, *p; int i, n; char buff[1024]; r = gcmalloc(sizeof(Val)); r->t = STRUCT; r->Cstruct.members = vec(); n = rand() % MAXSTRUCTM; for(i = 0; i < n; i++) vecappend(r->Cstruct.members, randval(depth + 1)); snprintf(buff, sizeof buff, "s%d", structcount++); r->Cstruct.name = gcstrdup(buff); printf("struct %s {\n", r->Cstruct.name); for(i = 0; i < r->Cstruct.members->len; i++) { p = vecget(r->Cstruct.members, i); printf("\t"); printvaltype(p); printf(" m%d;\n", i); } printf("};\n"); return r; }
List * list() { List *l; l = gcmalloc(sizeof(List)); return l; }
static CTy * newtype(int type) { CTy *t; t = gcmalloc(sizeof(CTy)); t->t = type; return t; }
static Node * mknode(int type, SrcPos *p) { Node *n; n = gcmalloc(sizeof(Node)); n->pos = *p; n->t = type; return n; }
static NameTy * newnamety(char *n, CTy *t) { NameTy *nt; nt = gcmalloc(sizeof(NameTy)); nt->name = n; nt->type = t; return nt; }
void listprepend(List *l, void *v) { ListEnt *e; e = gcmalloc(sizeof(ListEnt)); e->v = v; e->next = l->head; l->head = e; }
static Testcase * randtestcase() { Testcase *t; int n, i; t = gcmalloc(sizeof(Testcase)); t->vals = vec(); t->ret = randval(0); n = rand() % MAXPARAMS; for(i = 0; i < n; i++) vecappend(t->vals, randval(0)); return t; }
static Val * randval(int depth) { Val *r; again: switch(rand() % TEND) { case CHAR: r = gcmalloc(sizeof(Val)); r->t = CHAR; r->Cchar.v = rand(); break; case SHORT: r = gcmalloc(sizeof(Val)); r->t = SHORT; r->Cshort.v = rand(); break; case INT: r = gcmalloc(sizeof(Val)); r->t = INT; r->Cint.v = rand(); break; case LONG: r = gcmalloc(sizeof(Val)); r->t = LONG; r->Clong.v = rand(); break; case LLONG: r = gcmalloc(sizeof(Val)); r->t = LLONG; r->Cllong.v = rand(); break; case FLOAT: r = gcmalloc(sizeof(Val)); r->t = FLOAT; r->Cfloat.v = (float)rand(); break; case DOUBLE: r = gcmalloc(sizeof(Val)); r->t = DOUBLE; r->Cdouble.v = (double)rand(); break; case STRUCT: if(depth > MAXNEST) goto again; r = randstruct(depth); break; default: panic("internal error randval"); } return r; }
static Sym * defineenum(SrcPos *p, char *name, CTy *type, int64 v) { Sym *sym; sym = gcmalloc(sizeof(Sym)); sym->pos = p; sym->name = name; sym->type = type; sym->k = SYMENUM; sym->Enum.v = v; if(!define(syms, name, sym)) errorposf(p, "redefinition of %s", name); return sym; }
char * newlabel(void) { char *s; int n; n = snprintf(0, 0, "L%d", labelcount); if(n < 0) panic("internal error"); n += 1; s = gcmalloc(n); if(snprintf(s, n, "L%d", labelcount) < 0) panic("internal error"); labelcount++; return s; }
void listappend(List *l, void *v) { ListEnt *e, *ne; ne = gcmalloc(sizeof(ListEnt)); ne->v = v; if(l->head == 0) { l->head = ne; return; } e = l->head; while(e->next) e = e->next; e->next = ne; }
static void pushlex(char *path) { Lexer *l; if(nlexers == MAXINCLUDE) panic("include depth limit reached!"); l = gcmalloc(sizeof(Lexer)); l->pos.file = path; l->prevpos.file = path; l->markpos.file = path; l->pos.line = 1; l->pos.col = 1; l->f = fopen(path, "r"); if (!l->f) errorf("error opening file %s\n", path); lexers[nlexers] = l; nlexers += 1; }
static CTy * usualarithconv(Node **a, Node **b) { Node **large, **small; CTy *t; if(!isarithtype((*a)->type) || !isarithtype((*b)->type)) panic("internal error\n"); if(convrank((*a)->type) < convrank((*b)->type)) { large = a; small = b; } else { large = b; small = a; } if(isftype((*large)->type)) { *small = mkcast(&(*small)->pos, *small, (*large)->type); return (*large)->type; } *large = ipromote(*large); *small = ipromote(*small); if(sametype((*large)->type, (*small)->type)) return (*large)->type; if((*large)->type->Prim.issigned == (*small)->type->Prim.issigned ) { *small = mkcast(&(*small)->pos, *small, (*large)->type); return (*large)->type; } if(!(*large)->type->Prim.issigned) { *small = mkcast(&(*small)->pos, *small, (*large)->type); return (*large)->type; } if((*large)->type->Prim.issigned && canrepresent((*large)->type, (*small)->type)) { *small = mkcast(&(*small)->pos, *small, (*large)->type); return (*large)->type; } t = gcmalloc(sizeof(CTy)); *t = *((*large)->type); t->Prim.issigned = 0; *large = mkcast(&(*large)->pos, *large, t); *small = mkcast(&(*small)->pos, *small, t); return t; }
void addstructmember(SrcPos *pos, CTy *t, char *name, CTy *membt) { StructMember *sm, *subsm; int i, align, sz; sm = gcmalloc(sizeof(StructMember)); sm->name = name; sm->type = membt; if(!isstruct(t)) panic("internal error"); if(sm->name == 0 && isstruct(sm->type)) { for(i = 0; i < sm->type->Struct.members->len; i++) { subsm = vecget(sm->type->Struct.members, i); addstructmember(pos, t, subsm->name, subsm->type); } return; } if(sm->name) { for(i = 0; i < t->Struct.members->len; i++) { subsm = vecget(t->Struct.members, i); if(subsm->name) if(strcmp(sm->name, subsm->name) == 0) errorposf(pos ,"struct already has a member named %s", sm->name); } } if(membt->align < t->align) t->align = membt->align; sz = t->size; align = membt->align; if(sz % align) sz = sz + align - (sz % align); sm->offset = sz; sz += sm->type->size; t->size = sz; vecappend(t->Struct.members, sm); }
static Sym * definesym(SrcPos *p, int sclass, char *name, CTy *type, Node *n) { Sym *sym; if(sclass == SCAUTO || n != 0) if(type->incomplete) errorposf(p, "cannot use incomplete type in this context"); if(sclass == SCAUTO && isglobal()) errorposf(p, "defining local symbol in global scope"); sym = mapget(syms[nscopes - 1], name); if(sym) { switch(sym->k) { case SYMTYPE: if(sclass != SCTYPEDEF || !sametype(sym->type, type)) errorposf(p, "incompatible redefinition of typedef %s", name); break; case SYMGLOBAL: if(sym->Global.sclass != sclass) errorposf(p, "redefinition of %s with differing storage class", name); if(sym->init && n) errorposf(p, "%s already initialized", name); if(!sym->init && n) { sym->init = n; emitsym(sym); removetentativesym(sym); } break; default: errorposf(p, "redefinition of %s", name); } return sym; } sym = gcmalloc(sizeof(Sym)); sym->name = name; sym->type = type; sym->init = n; switch(sclass) { case SCAUTO: sym->k = SYMLOCAL; sym->Local.slot = gcmalloc(sizeof(StkSlot)); sym->Local.slot->size = sym->type->size; sym->Local.slot->align = sym->type->align; vecappend(curfunc->Func.stkslots, sym->Local.slot); break; case SCTYPEDEF: sym->k = SYMTYPE; break; case SCGLOBAL: sym->k = SYMGLOBAL; sym->Global.label = name; sym->Global.sclass = SCGLOBAL; break; case SCSTATIC: sym->k = SYMGLOBAL; sym->Global.label = newlabel(); sym->Global.sclass = SCSTATIC; break; } if(sym->k == SYMGLOBAL) { if(sym->init) emitsym(sym); else if(!isfunc(sym->type)) addtentativesym(sym); } if(!define(syms, name, sym)) panic("internal error"); return sym; }