%{ #include #include #include #include #include "ccc.h" %} %union { Sym *sym; Symlist *symlist; Type *type; Typelist *typelist; struct Tspec { Btype; Dtype *dtype; } tspec; struct Decl { Btype btype; Dtype *dtype; Symlist *slist; Type *chantype; } decl; struct Sumembs { Names *names; Symlist *slist; } sumembs; int ival; double dval; } %type xasdecl %type declors %type paramlist paramlist1 %type declor declor1 name tycl sue %type abdeclor abdeclor1 abdeclor2 abdeclor3 param %type tcqspec %type sdecls %type zival su %token LNAME LVOID LCHAR LSHORT LINT LLONG LFLOAT %token LDOUBLE LSIGNED LUNSIGNED LCONST LVOLATILE %token LAUTO LREGISTER LSTATIC LEXTERN LTYPEDEF %token LUNION LENUM LSTRUCT LTYPE %token LIVAL %token LDVAL %token LCHAN %% unit: | unit xadecl xadecl: xasdecl { if($1.chantype != nil) { setchantype($1.slist, $1.chantype); printchandecls($1.slist); nocopyout(); } else { settype($1.slist, &$1.btype, $1.dtype); copyout(); } symlistfree($1.slist); } xasdecl: tcqspec ';' { btypeclean(&$1); $$.btype = $1; $$.dtype = $1.dtype; $$.slist = nil; $$.chantype = nil; } | tcqspec declors ';' { btypeclean(&$1); $$.btype = $1; $$.dtype = $1.dtype; $$.slist = $2; $$.chantype = nil; } | LCHAN '(' param ')' declors ';' { $$.btype = BZ; $$.dtype = nil; $$.slist = $5; $$.chantype = $3; } tcqspec: { $$ = (struct Tspec){BZ, nil}; } | tcqspec tycl { $$.tycl = addspec($1.tycl, $2->tycl); } | tcqspec sue { $$.sue = addsue(&$1, $2); } | tcqspec LTYPE { $$ = *addtypedef(&$1, $2->type); } declors: declor { $$ = addsym(symlist(), $1); } | declors ',' declor { $$ = addsym($1, $3); } declor: declor1 | '*' declor { dtype($2->newtype, TPTR); $$ = $2; } declor1: LNAME { $1->newtype = type(); $$ = $1; } | '(' declor ')' { $$ = $2; } | declor1 '[' zival ']' { Dtype *d; d = dtype($1->newtype, TARR); d->alen = $3; $$ = $1; } | declor1 '(' paramlist ')' { Dtype *d; d = dtype($1->newtype, TFUNC); d->param = $3; $$ = $1; } paramlist: paramlist1 | paramlist1 ',' '.' '.' '.' { Type *t; t = type(); t->tycl = 1<newtype; $2->newtype = nil; btypeclean(&$1); *(Btype*)$$ = $1; } | tcqspec abdeclor { $$ = $2; btypeclean(&$1); *(Btype*)$$ = $1; } abdeclor: { $$ = type(); } | abdeclor1 abdeclor1: abdeclor2 | '*' { $$ = type(); dtype($$, TPTR); } | '*' abdeclor1 { dtype($2, TPTR); $$ = $2; } abdeclor2: abdeclor3 | abdeclor2 '(' paramlist ')' { Dtype *d; d = dtype($1, TFUNC); d->param = $3; $$ = $1; } | abdeclor2 '[' zival ']' { Dtype *d; d = dtype($1, TARR); d->alen = $3; $$ = $1; } abdeclor3: '[' zival ']' { Dtype *d; $$ = type(); d = dtype($$, TARR); d->alen = $2; } | '(' abdeclor1 ')' { $$ = $2; } sue: su name { $2->suetype = $1; $$ = $2; } | su name '{' sdecls '}' { $2->sunames = $4.names; $2->sulist = $4.slist; $2->suetype = $1; $$ = $2; } | su '{' sdecls '}' { $$ = sym(nil, nil); $$->sunames = $3.names; $$->sulist = $3.slist; $$->suetype = $1; } | e name { $2->suetype = TENUM; $$ = $2; } su: LSTRUCT { suelookup = 1; $$ = TSTRUCT; } | LUNION { suelookup = 1; $$ = TUNION; } e: LENUM { suelookup = 1; } sdecls: { $$.names = pushnames(nil); $$.slist = symlist(); } | sdecls xasdecl { if($2.slist == nil) anonmemb(&$1, $2.btype.sue); else addsumembs(&$1, &$2); symlistfree($2.slist); $$ = $1; } zival: { $$ = -1; } | LIVAL name: LNAME | LTYPE tycl: LVOID | LCHAR | LSHORT | LINT | LLONG | LFLOAT | LDOUBLE | LSIGNED | LUNSIGNED | LCONST | LVOLATILE | LAUTO | LREGISTER | LSTATIC | LEXTERN | LTYPEDEF %% Btype BZ = {0}; void btypeclean(Btype *btype) { int i, t; u32int tycl; Sym *sue; tycl = btype->tycl; sue = btype->sue; if(sue != nil) { if(tycl & (BTYPE|BSIGN)) error("Cannot be a basic type and a structure type."); return; } for(i = TVOID; i < NTYPE; i++) { if(tycl & 1<tycl = tycl; } void settype(Symlist *symlist, Btype *btype, Dtype *dtype) { Sym **s, *sym; Type *type, *newtype; if(symlist == nil) return; for(s = symlist->sp; s < symlist->ep; s++) { sym = *s; type = sym->type; newtype = sym->newtype; *(Btype*)newtype = *btype; *newtype->dtail = dtype; if(type != nil) { if(typeeq(type, newtype) != 0) error("Types do not match %S: %D, %D", sym->name, type, newtype); typefree(type); } sym->type = newtype; sym->newtype = nil; if(btype->tycl & 1<lex = LTYPE; } } void setchantype(Symlist *symlist, Type *t) { Sym **s, *sym; Type *type, *newtype; if(symlist == nil) return; for(s = symlist->sp; s < symlist->ep; s++) { sym = *s; type = sym->type; newtype = sym->newtype; newtype->chantype = t; if(type != nil) { if(typeeq(type, newtype) != 0) error("Chan types do not match %S: %D, %D", sym->name, type, newtype); typefree(type); } sym->type = newtype; } } Type* paramconv(Type *t) { Dtype *d; if((d = t->dtype) != nil) switch(d->t) { case TARR: d->alen = 0; d->t = TPTR; break; case TFUNC: t->dtype = dtype(nil, TPTR); t->dtype->link = d; break; } return t; } static int tycleq(u32int t1, u32int t2) { if((t1^t2) & (BTYPE|BSIGN)) return 1; return 0; } static int sueeq(Sym*, Sym*) { return 0; } static int parameq(Typelist *l1, Typelist *l2) { Type **ti1, **ti2; if(l1 !=nil && l2 != nil) goto check; if(l1 == nil && l2 == nil) return 0; return 1; check: for(ti1 = l1->sp, ti2 = l2->sp; ti1 < l1->ep; ti1++, ti2++) { if(ti2 == l2->ep) return 1; if(typeeq(*ti1, *ti2) != 0) return 1; } return 0; } static int dtypeeq(Dtype *d1, Dtype *d2) { loop: if(d1 != nil && d2 != nil) goto check; if(d1 == nil && d2 == nil) return 0; return 1; check: if(d1->t != d2->t) return 1; if(d1->alen != d2->alen) return 1; if(parameq(d1->param, d2->param) != 0) return 1; d1 = d1->link; d2 = d2->link; goto loop; } int typeeq(Type *t1, Type *t2) { if(t1 != nil && t2 != nil) goto check; if(t1 == nil && t2 == nil) return 0; return 1; check: if(tycleq(t1->tycl, t2->tycl) != 0) return 1; if(sueeq(t1->sue, t2->sue) != 0) return 1; if(typeeq(t1->chantype, t2->chantype) != 0) return 1; if(dtypeeq(t1->dtype, t2->dtype) != 0) return 1; return 0; } u32int addspec(u32int t, int tycl) { if(tycl < NTYPE) { if(tycl == TLONG) { if(t & 1<sue != nil) error("Multiple struct declarations."); if(btype->tycl & BTYPE) error("Cannot be a struct and a basic type."); btype->sue = sue; return sue; } struct Tspec* addtypedef(struct Tspec *tspec, Type *t) { if(tspec->sue != nil || tspec->tycl & (BTYPE|BSIGN)) error("Overspecified typedef application."); tspec->dtype = t->dtype; tspec->sue = t->sue; tspec->tycl |= t->tycl; return tspec; } void anonmemb(struct Sumembs *m, Sym *s) { if(s == nil || s->suetype == TENUM) error("Anonymous member must be a struct or union."); addparent(m->names, s->sunames); addsym(m->slist, s); } void addsumembs(struct Sumembs *m, struct Decl *d) { Sym **si, *s, *t; for(si = d->slist->sp; si < d->slist->ep; si++) { t = *si; s = lookup(m->names, t->name); if(s != nil) error("Structure member already defined: %S", s->name); s = sym(m->names, t->name); addsym(m->slist, s); s->type = t->newtype; *(Btype*)s->type = d->btype; *s->type->dtail = d->dtype; t->newtype = nil; } }