diff options
Diffstat (limited to 'src/old/c/dcl.c')
-rw-r--r-- | src/old/c/dcl.c | 807 |
1 files changed, 807 insertions, 0 deletions
diff --git a/src/old/c/dcl.c b/src/old/c/dcl.c new file mode 100644 index 000000000..6cf10e16d --- /dev/null +++ b/src/old/c/dcl.c @@ -0,0 +1,807 @@ +// 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, Node *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(Node *n, Node *t) +{ + +loop: + if(n == N) + return; + + if(n->op == OLIST) { + dodcltype(n->left, t); + n = n->right; + goto loop; + } + + 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 + */ +Node* +functype(Node *this, Node *in, Node *out) +{ + Node *t; + + t = nod(OTYPE, N, N); + t->etype = 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); + + return t; +} + +void +funcnam(Node *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(Node *t1, Node *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 == N || t2 == N) + 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; +} + +/* + * add a method, declared as a function, + * into the structure + */ +void +addmethod(Node *n, Node *pa, Node *t) +{ + Node *p, *f, *d; + Sym *s; + + if(n->op != ONAME) + goto bad; + s = n->sym; + if(s == S) + goto bad; + if(pa == N) + goto bad; + if(pa->etype != TPTR) + goto bad; + p = pa->type; + if(p == N) + goto bad; + if(p->etype != TSTRUCT) + goto bad; + if(p->sym == S) + goto bad; + + if(p->type == N) { + n = nod(ODCLFIELD, newname(s), N); + n->type = t; + + stotype(n, &p->type, p); + return; + } + + d = N; // last found + for(f=p->type; f!=N; 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 == N) { + 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 == N) + stotype(n, &p->type, p); + else + stotype(n, &d->down, p); + 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); + } + + // check for foreward declaration + if(on == N || !eqtype(n->type, on->type, 0)) { + // 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 { + // identical redeclaration + // steal previous names + n->nname = on; + n->type = on->type; + 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) { + Node *n1; + n1 = *getthis(n->type); + addmethod(n->nname, n1->type->type, n->type); + } +} + +void +funcargs(Node *t) +{ + Node *n1; + Iter save; + + // declare the this argument + n1 = structfirst(&save, getthis(t)); + if(n1 != N) { + if(n1->nname != N) + addvar(n1->nname, n1->type, PAUTO); + } + + // declare the incoming arguments + n1 = structfirst(&save, getinarg(t)); + while(n1 != N) { + if(n1->nname != N) + addvar(n1->nname, n1->type, PAUTO); + n1 = structnext(&save); + } + + // declare the outgoing arguments +// n1 = structfirst(&save, getoutarg(t)); +// while(n1 != N) { +// n1->left = newname(n1->sym); +// if(n1->nname != N) +// addvar(n1->nname, n1->type, PAUTO); +// 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"); + dclcontext = PEXTERN; + popdcl("func"); +} + +/* + * turn a parsed struct into a type + */ +Node** +stotype(Node *n, Node **t, Node *uber) +{ + Node *f; + Iter save; + + n = listfirst(&save, &n); + +loop: + if(n == N) { + *t = N; + return t; + } + + if(n->op == OLIST) { + // recursive because it can be lists of lists + t = stotype(n, t, uber); + goto next; + } + + if(n->op != ODCLFIELD || n->type == N) + fatal("stotype: oops %N\n", n); + + if(n->type->etype == TDARRAY) + yyerror("type of a structure field cannot be an open array"); + + f = nod(OTYPE, N, N); + f->etype = TFIELD; + f->type = n->type; + f->uberstruct = uber; + + 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; + f->nname->uberstruct = uber; // can reach parent from element + + *t = f; + t = &f->down; + +next: + n = listnext(&save); + goto loop; +} + +Node* +dostruct(Node *n, int et) +{ + Node *t; + + /* + * convert a parsed id/type list into + * a type for struct/interface/arglist + */ + + t = nod(OTYPE, N, N); + stotype(n, &t->type, t); + t->etype = et; + return t; +} + +Node* +sortinter(Node *n) +{ + return n; +} + +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, Node *t, int ctxt) +{ + Dcl *r, *d; + Sym *s; + Node *on; + int gen; + + if(n==N || n->sym == S || n->op != ONAME || t == N) + fatal("addvar: n=%N t=%N nil", n, t); + + on = t; + if(on->etype == TPTR) + on = on->type; + if(on->etype == TSTRUCT && on->vargen == 0) { + vargen++; + snprint(namebuf, sizeof(namebuf), "_s%.3ld", vargen); + addtyp(newtype(lookup(namebuf)), on, 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; + } + + pushdcl(s); + s->vargen = gen; + s->oname = n; + + n->type = t; + n->vargen = gen; + + 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(Node *n, Node *t, int ctxt) +{ + Dcl *r, *d; + Sym *s; + Node *f, *ot; + + if(n==N || n->sym == S || n->op != OTYPE || t == N) + fatal("addtyp: n=%N t=%N nil", n, t); + + s = n->sym; + + r = autodcl; + if(ctxt == PEXTERN) { + ot = s->otype; + if(ot != N) { + // allow nil interface to be + // redeclared as an interface + if(ot->etype == TINTER && ot->type == N && 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; + } + + pushdcl(s); + vargen++; + s->vargen = vargen; + s->otype = t; + s->lexical = LATYPE; + + if(t->sym != S) + warn("addtyp: renaming %S to %S", t->sym, s); + + t->sym = s; + t->vargen = vargen; + + for(f=s->forwtype; f!=N; f=f->nforw) { + if(f->op != OTYPE && f->etype != TPTR) + fatal("addtyp: foreward"); + f->type = t; + } + s->forwtype = N; + + d = dcl(); + d->dsym = s; + d->dnode = 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); + } +} + +/* + * make a new variable + */ +Node* +tempname(Node *t) +{ + Sym *s; + Node *n; + + if(t == N) { + yyerror("tempname called with nil type"); + t = types[TINT32]; + } + + s = lookup("!tmpname!"); + n = newname(s); + dodclvar(n, 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 = N; + 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 + */ +Node* +newtype(Sym *s) +{ + Node *n; + + n = nod(OTYPE, N, N); + n->etype = TFORW; + n->sym = s; + n->type = N; + return n; +} + +Node* +oldtype(Sym *s) +{ + Node *n; + + n = s->otype; + if(n == N) + fatal("%S not a type", s); // cant happen + return n; +} + +Node* +forwdcl(Sym *s) +{ + Node *n; + + // this type has no meaning and + // will cause an error if referenced. + // it will be patched when/if the + // type is ever assigned. + n = nod(OTYPE, N, N); + n->etype = TFORW; + n = ptrto(n); + + n->nforw = s->forwtype; + s->forwtype = n; + return n; +} |