summaryrefslogtreecommitdiff
path: root/src/old/c/dcl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/old/c/dcl.c')
-rw-r--r--src/old/c/dcl.c807
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;
+}