diff options
Diffstat (limited to 'src/cmd/gc/dcl.c')
| -rw-r--r-- | src/cmd/gc/dcl.c | 814 |
1 files changed, 814 insertions, 0 deletions
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c new file mode 100644 index 000000000..3eae5f33b --- /dev/null +++ b/src/cmd/gc/dcl.c @@ -0,0 +1,814 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "go.h" +#include "y.tab.h" + +void +dodclvar(Node *n, Type *t) +{ + +loop: + if(n == N) + return; + + if(n->op == OLIST) { + dodclvar(n->left, t); + n = n->right; + goto loop; + } + + addvar(n, t, dclcontext); +} + +void +dodcltype(Type *n, Type *t) +{ + + if(n == T) + return; + addtyp(n, t, dclcontext); +} + +void +dodclconst(Node *n, Node *e) +{ + Sym *s; + Dcl *r, *d; + +loop: + if(n == N) + return; + if(n->op == OLIST) { + dodclconst(n->left, e); + n = n->right; + goto loop; + } + + if(n->op != ONAME) + fatal("dodclconst: not a name"); + + if(e->op != OLITERAL) { + yyerror("expression must be a constant"); + goto loop; + } + s = n->sym; + + s->oconst = e; + s->lexical = LACONST; + + r = autodcl; + if(dclcontext == PEXTERN) + r = externdcl; + + d = dcl(); + d->dsym = s; + d->dnode = e; + d->op = OCONST; + + r->back->forw = d; + r->back = d; + + if(debug['d']) + print("const-dcl %S %N\n", n->sym, n->sym->oconst); +} + +/* + * return nelem of list + */ +int +listcount(Node *n) +{ + int v; + + v = 0; + while(n != N) { + v++; + if(n->op != OLIST) + break; + n = n->right; + } + return v; +} + +/* + * turn a parsed function declaration + * into a type + */ +Type* +functype(Node *this, Node *in, Node *out) +{ + Type *t; + + t = typ(TFUNC); + + t->type = dostruct(this, TSTRUCT); + t->type->down = dostruct(out, TSTRUCT); + t->type->down->down = dostruct(in, TSTRUCT); + + t->thistuple = listcount(this); + t->outtuple = listcount(out); + t->intuple = listcount(in); + + dowidth(t); + return t; +} + +void +funcnam(Type *t, char *nam) +{ + Node *n; + Sym *s; + char buf[100]; + + if(nam == nil) { + vargen++; + snprint(buf, sizeof(buf), "_f%.3ld", vargen); + nam = buf; + } + + if(t->etype != TFUNC) + fatal("funcnam: not func %T\n", t); + + if(t->thistuple > 0) { + vargen++; + snprint(namebuf, sizeof(namebuf), "_t%.3ld", vargen); + s = lookup(namebuf); + addtyp(newtype(s), t->type, PEXTERN); + n = newname(s); + n->vargen = vargen; + t->type->nname = n; + } + if(t->outtuple > 0) { + vargen++; + snprint(namebuf, sizeof(namebuf), "_o%.3ld", vargen); + s = lookup(namebuf); + addtyp(newtype(s), t->type->down, PEXTERN); + n = newname(s); + n->vargen = vargen; + t->type->down->nname = n; + } + if(t->intuple > 0) { + vargen++; + snprint(namebuf, sizeof(namebuf), "_i%.3ld", vargen); + s = lookup(namebuf); + addtyp(newtype(s), t->type->down->down, PEXTERN); + n = newname(s); + n->vargen = vargen; + t->type->down->down->nname = n; + } +} + +int +methcmp(Type *t1, Type *t2) +{ + if(t1->etype != TFUNC) + return 0; + if(t2->etype != TFUNC) + return 0; + + t1 = t1->type->down; // skip this arg + t2 = t2->type->down; // skip this arg + for(;;) { + if(t1 == t2) + break; + if(t1 == T || t2 == T) + return 0; + if(t1->etype != TSTRUCT || t2->etype != TSTRUCT) + return 0; + + if(!eqtype(t1->type, t2->type, 0)) + return 0; + + t1 = t1->down; + t2 = t2->down; + } + return 1; +} + +Node* +methodname(Node *n, Type *t) +{ + if(isptr[t->etype]) + t = t->type; + if(t->etype != TSTRUCT) + goto bad; + if(t->sym == S) + goto bad; + + snprint(namebuf, sizeof(namebuf), "%s_%s", t->sym->name, n->sym->name); + return newname(lookup(namebuf)); + +bad: + yyerror("illegal <this> pointer"); + return n; +} + +/* + * add a method, declared as a function, + * into the structure + */ +void +addmethod(Node *n, Type *pa, Type *t) +{ + Type *f, *d, *p; + Sym *s; + + if(n->op != ONAME) + goto bad; + s = n->sym; + if(s == S) + goto bad; + if(pa == T) + goto bad; + if(!isptr[pa->etype]) + goto bad; + p = pa->type; + if(p == T) + goto bad; + if(p->etype != TSTRUCT) + goto bad; + if(p->sym == S) + goto bad; + + if(p->type == T) { + n = nod(ODCLFIELD, newname(s), N); + n->type = t; + + stotype(n, &p->type); + return; + } + + d = T; // last found + for(f=p->type; f!=T; f=f->down) { + if(f->etype != TFIELD) + fatal("addmethod: not TFIELD: %N", f); + + if(strcmp(s->name, f->sym->name) != 0) { + d = f; + continue; + } + + // if a field matches a non-this function + // then delete it and let it be redeclared + if(methcmp(t, f->type)) { + if(d == T) { + p->type = f->down; + continue; + } + d->down = f->down; + continue; + } + if(!eqtype(t, f->type, 0)) + yyerror("field redeclared as method: %S", s); + return; + } + + n = nod(ODCLFIELD, newname(s), N); + n->type = t; + + if(d == T) + stotype(n, &p->type); + else + stotype(n, &d->down); + return; + +bad: + yyerror("unknown method pointer: %T", pa); +} + +/* + * declare the function proper. + * and declare the arguments + * called in extern-declaration context + * returns in auto-declaration context. + */ +void +funchdr(Node *n) +{ + Node *on; + Sym *s; + + s = n->nname->sym; + on = s->oname; + + // check for same types + if(on != N) { + if(eqtype(n->type, on->type, 0)) { + if(!eqargs(n->type, on->type)) + yyerror("foreward declarations not the same: %S", s); + } else { + yyerror("redeclare of function: %S", s); + on = N; + } + } + + // check for foreward declaration + if(on == N) { + // initial declaration or redeclaration + // declare fun name, argument types and argument names + funcnam(n->type, s->name); + n->nname->type = n->type; + if(n->type->thistuple == 0) + addvar(n->nname, n->type, PEXTERN); + else + n->nname->class = PEXTERN; + } else { + // identical redeclaration + // steal previous names + n->nname = on; + n->type = on->type; + n->class = on->class; + n->sym = s; + if(debug['d']) + print("forew var-dcl %S %T\n", n->sym, n->type); + } + + // change the declaration context from extern to auto + autodcl = dcl(); + autodcl->back = autodcl; + + if(dclcontext != PEXTERN) + fatal("funchdr: dclcontext"); + + dclcontext = PAUTO; + markdcl("func"); + funcargs(n->type); + + if(n->type->thistuple > 0) { + Type *t; + t = *getthis(n->type); + addmethod(n->nname, t->type->type, n->type); + } +} + +void +funcargs(Type *t) +{ + Type *n1; + Iter save; + + // declare the this argument + n1 = funcfirst(&save, t); + while(n1 != T) { + if(n1->nname != N) + addvar(n1->nname, n1->type, PPARAM); + n1 = funcnext(&save); + } + + // declare the outgoing arguments +// n1 = structfirst(&save, getoutarg(t)); +// while(n1 != T) { +// n1->left = newname(n1->sym); +// if(n1->nname != N) +// addvar(n1->nname, n1->type, PPARAM); +// n1 = structnext(&save); +// } +} + +/* + * compile the function. + * called in auto-declaration context. + * returns in extern-declaration context. + */ +void +funcbody(Node *n) +{ + + compile(n); + + // change the declaration context from auto to extern + if(dclcontext != PAUTO) + fatal("funcbody: dclcontext"); + popdcl("func"); + dclcontext = PEXTERN; +} + +/* + * turn a parsed struct into a type + */ +Type** +stotype(Node *n, Type **t) +{ + Type *f; + Iter save; + + n = listfirst(&save, &n); + +loop: + if(n == N) { + *t = T; + return t; + } + + if(n->op == OLIST) { + // recursive because it can be lists of lists + t = stotype(n, t); + goto next; + } + + if(n->op != ODCLFIELD || n->type == T) + fatal("stotype: oops %N\n", n); + + if(n->type->etype == TDARRAY) + yyerror("type of a structure field cannot be an open array"); + + f = typ(TFIELD); + f->type = n->type; + + if(n->left != N && n->left->op == ONAME) { + f->nname = n->left; + } else { + vargen++; + snprint(namebuf, sizeof(namebuf), "_e%.3ld", vargen); + f->nname = newname(lookup(namebuf)); + } + f->sym = f->nname->sym; + + *t = f; + t = &f->down; + +next: + n = listnext(&save); + goto loop; +} + +Type* +dostruct(Node *n, int et) +{ + Type *t; + + /* + * convert a parsed id/type list into + * a type for struct/interface/arglist + */ + + t = typ(et); + stotype(n, &t->type); + dowidth(t); + return t; +} + +Type* +sortinter(Type *t) +{ + return t; +} + +void +dcopy(Sym *a, Sym *b) +{ + a->name = b->name; + a->oname = b->oname; + a->otype = b->otype; + a->oconst = b->oconst; + a->package = b->package; + a->opackage = b->opackage; + a->forwtype = b->forwtype; + a->lexical = b->lexical; + a->undef = b->undef; + a->vargen = b->vargen; +} + +Sym* +push(void) +{ + Sym *d; + + d = mal(sizeof(*d)); + d->link = dclstack; + dclstack = d; + return d; +} + +Sym* +pushdcl(Sym *s) +{ + Sym *d; + + d = push(); + dcopy(d, s); + return d; +} + +void +popdcl(char *why) +{ + Sym *d, *s; + +// if(debug['d']) +// print("revert\n"); + for(d=dclstack; d!=S; d=d->link) { + if(d->name == nil) + break; + s = pkglookup(d->name, d->package); + dcopy(s, d); + if(debug['d']) + print("\t%ld pop %S\n", curio.lineno, s); + } + if(d == S) + fatal("popdcl: no mark"); + if(strcmp(why, d->package) != 0) + fatal("popdcl: pushed as %s poped as %s", d->package, why); + dclstack = d->link; +} + +void +poptodcl(void) +{ + Sym *d, *s; + + for(d=dclstack; d!=S; d=d->link) { + if(d->name == nil) + break; + s = pkglookup(d->name, d->package); + dcopy(s, d); + if(debug['d']) + print("\t%ld pop %S\n", curio.lineno, s); + } + if(d == S) + fatal("poptodcl: no mark"); +} + +void +markdcl(char *why) +{ + Sym *d; + + d = push(); + d->name = nil; // used as a mark in fifo + d->package = why; // diagnostic for unmatched +// if(debug['d']) +// print("markdcl\n"); +} + +void +markdclstack(void) +{ + Sym *d, *s; + + markdcl("fnlit"); + + // copy the entire pop of the stack + // all the way back to block0. + // after this the symbol table is at + // block0 and popdcl will restore it. + for(d=dclstack; d!=S; d=d->link) { + if(d == b0stack) + break; + if(d->name != nil) { + s = pkglookup(d->name, d->package); + pushdcl(s); + dcopy(s, d); + } + } +} + +void +testdclstack(void) +{ + Sym *d; + + for(d=dclstack; d!=S; d=d->link) { + if(d->name == nil) { + yyerror("mark left on the stack"); + continue; + } + } +} + +void +addvar(Node *n, Type *t, int ctxt) +{ + Dcl *r, *d; + Sym *s; + Type *ot; + Node *on; + int gen; + + if(n==N || n->sym == S || n->op != ONAME || t == T) + fatal("addvar: n=%N t=%T nil", n, t); + + ot = t; + if(isptr[ot->etype]) + ot = ot->type; + + if(ot->etype == TSTRUCT && ot->vargen == 0) { + vargen++; + snprint(namebuf, sizeof(namebuf), "_s%.3ld", vargen); + s = lookup(namebuf); + addtyp(newtype(s), ot, PEXTERN); + } + + s = n->sym; + vargen++; + gen = vargen; + + r = autodcl; + if(ctxt == PEXTERN) { + on = s->oname; + if(on != N) { + if(eqtype(t, on->type, 0)) { + warn("%S redeclared", s); + return; + } + yyerror("%S redeclared (%T %T)", s, + on->type, t); + } + r = externdcl; + gen = 0; + } + + if(ctxt != PEXTERN) + pushdcl(s); + + s->vargen = gen; + s->oname = n; + s->offset = 0; + + n->type = t; + n->vargen = gen; + n->class = ctxt; + + d = dcl(); + d->dsym = s; + d->dnode = n; + d->op = ONAME; + + r->back->forw = d; + r->back = d; + + if(debug['d']) { + if(ctxt == PEXTERN) + print("extern var-dcl %S G%ld %T\n", s, s->vargen, t); + else + print("auto var-dcl %S G%ld %T\n", s, s->vargen, t); + } +} + +void +addtyp(Type *n, Type *t, int ctxt) +{ + Dcl *r, *d; + Sym *s; + Type *f, *ot; + + if(n==T || n->sym == S || t == T) + fatal("addtyp: n=%T t=%T nil", n, t); + + s = n->sym; + + r = autodcl; + if(ctxt == PEXTERN) { + ot = s->otype; + if(ot != T) { + // allow nil interface to be + // redeclared as an interface + if(ot->etype == TINTER && ot->type == T && t->etype == TINTER) { + if(debug['d']) + print("forew typ-dcl %S G%ld %T\n", s, s->vargen, t); + s->otype = t; + return; + } + if(eqtype(t, ot, 0)) { + warn("%S redeclared", s); + return; + } + yyerror("%S redeclared (%T %T)", s, + ot, t); + } + r = externdcl; + } + + if(ctxt != PEXTERN) + pushdcl(s); + + if(t->sym != S) + warn("addtyp: renaming %S/%lT to %S/%lT", t->sym, t->sym->otype, s, n); + + vargen++; + s->vargen = vargen; + s->otype = t; + s->lexical = LATYPE; + + t->sym = s; + t->vargen = vargen; + + for(f=s->forwtype; f!=T; f=f->nforw) { + if(!isptr[f->etype]) + fatal("addtyp: foreward"); + f->type = t; + } + s->forwtype = T; + + d = dcl(); + d->dsym = s; + d->dtype = t; + d->op = OTYPE; + + r->back->forw = d; + r->back = d; + + if(debug['d']) { + if(ctxt == PEXTERN) + print("extern typ-dcl %S G%ld %T\n", s, s->vargen, t); + else + print("auto typ-dcl %S G%ld %T\n", s, s->vargen, t); + } +} + +Node* +fakethis(void) +{ + Node *n; + Type *t; + + n = nod(ODCLFIELD, N, N); + t = dostruct(N, TSTRUCT); + t = ptrto(t); + n->type = t; + return n; +} + +/* + * this generates a new name that is + * pushed down on the declaration list. + * no diagnostics are produced as this + * name will soon be declared. + */ +Node* +newname(Sym *s) +{ + Node *n; + + n = nod(ONAME, N, N); + n->sym = s; + n->type = T; + n->addable = 1; + n->ullman = 0; + return n; +} + +/* + * this will return an old name + * that has already been pushed on the + * declaration list. a diagnostic is + * generated if no name has been defined. + */ +Node* +oldname(Sym *s) +{ + Node *n; + + n = s->oname; + if(n == N) { + yyerror("%S undefined", s); + n = newname(s); + dodclvar(n, types[TINT32]); + } + return n; +} + +/* + * same for types + */ +Type* +newtype(Sym *s) +{ + Type *t; + + t = typ(TFORW); + t->sym = s; + t->type = T; + return t; +} + +Type* +oldtype(Sym *s) +{ + Type *t; + + t = s->otype; + if(t == T) + fatal("%S not a type", s); // cant happen + return t; +} + +Type* +forwdcl(Sym *s) +{ + Type *t; + + // this type has no meaning and + // will cause an error if referenced. + // it will be patched when/if the + // type is ever assigned. + + t = typ(TFORW); + t = ptrto(t); + + t->nforw = s->forwtype; + s->forwtype = t; + return t; +} |
