--- /dev/null
+// 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"
+#define TUP(x,y) (((x)<<16)|(y))
+
+void
+convlit(Node *n, Node *t)
+{
+ int et;
+
+ if(n->op != OLITERAL)
+ return;
+ if(t == N)
+ return;
+ n->type = t;
+ et = t->etype;
+
+ switch(whatis(n)) {
+ case Wlitint:
+ if(isptrto(t, TSTRING)) {
+ Rune rune;
+ int l;
+ String *s;
+
+ rune = n->val.vval;
+ l = runelen(rune);
+ s = mal(sizeof(*s)+l);
+ s->len = l;
+ runetochar((char*)(s->s), &rune);
+
+ n->val.sval = s;
+ n->val.ctype = CTSTR;
+ break;
+ }
+ if(isint[et]) {
+ if(n->val.vval < minintval[et])
+ goto bad2;
+ if(n->val.vval > maxintval[et])
+ goto bad2;
+ break;
+ }
+ if(isfloat[et]) {
+ if(n->val.vval < minfloatval[et])
+ goto bad2;
+ if(n->val.vval > maxfloatval[et])
+ goto bad2;
+ n->val.dval = n->val.vval;
+ n->val.ctype = CTFLT;
+ break;
+ }
+ goto bad1;
+
+ case Wlitfloat:
+ if(isint[et]) {
+ if(n->val.dval < minintval[et])
+ goto bad2;
+ if(n->val.dval > maxintval[et])
+ goto bad2;
+ n->val.vval = n->val.dval;
+ n->val.ctype = CTINT;
+ break;
+ }
+ if(isfloat[et]) {
+ if(n->val.dval < minfloatval[et])
+ goto bad2;
+ if(n->val.dval > maxfloatval[et])
+ goto bad2;
+ break;
+ }
+ goto bad1;
+ }
+ return;
+
+bad1:
+ yyerror("illegal conversion of constant to %T", t);
+ return;
+
+bad2:
+ yyerror("overflow converting constant to %T", t);
+ return;
+}
+
+void
+evconst(Node *n)
+{
+ Node *t, *nl, *nr;
+ long len;
+ String *str;
+ int wl, wr;
+
+ nl = n->left;
+ if(nl == N)
+ return;
+
+ switch(n->op) {
+ case OCONV:
+ t = n->type;
+ *n = *nl;
+ n->type = t;
+ return;
+ }
+
+ wl = whatis(nl);
+ switch(wl) {
+ default:
+ return;
+
+ case Wlitint:
+ case Wlitfloat:
+ case Wlitbool:
+ case Wlitstr:
+ break;
+ }
+
+ nr = n->right;
+ if(nr == N)
+ goto unary;
+
+ wr = whatis(nr);
+ switch(wr) {
+ default:
+ return;
+
+ case Wlitint:
+ case Wlitfloat:
+ case Wlitbool:
+ case Wlitstr:
+ break;
+ }
+ if(wl != wr) {
+ yyerror("illegal combination of literals %d %d", nl->etype, nr->etype);
+ return;
+ }
+
+ switch(TUP(n->op, wl)) {
+ default:
+ yyerror("illegal combination of literals %O %d", n->op, wl);
+ return;
+
+ case TUP(OADD, Wlitint):
+ nl->val.vval += nr->val.vval;
+ break;
+ case TUP(OSUB, Wlitint):
+ nl->val.vval -= nr->val.vval;
+ break;
+ case TUP(OMUL, Wlitint):
+ nl->val.vval *= nr->val.vval;
+ break;
+ case TUP(ODIV, Wlitint):
+ nl->val.vval /= nr->val.vval;
+ break;
+ case TUP(OMOD, Wlitint):
+ nl->val.vval %= nr->val.vval;
+ break;
+ case TUP(OLSH, Wlitint):
+ nl->val.vval <<= nr->val.vval;
+ break;
+ case TUP(ORSH, Wlitint):
+ nl->val.vval >>= nr->val.vval;
+ break;
+ case TUP(OOR, Wlitint):
+ nl->val.vval |= nr->val.vval;
+ break;
+ case TUP(OAND, Wlitint):
+ nl->val.vval &= nr->val.vval;
+ break;
+
+ case TUP(OADD, Wlitfloat):
+ nl->val.dval += nr->val.dval;
+ break;
+ case TUP(OSUB, Wlitfloat):
+ nl->val.dval -= nr->val.dval;
+ break;
+ case TUP(OMUL, Wlitfloat):
+ nl->val.dval *= nr->val.dval;
+ break;
+ case TUP(ODIV, Wlitfloat):
+ nl->val.dval /= nr->val.dval;
+ break;
+
+ case TUP(OEQ, Wlitint):
+ if(nl->val.vval == nr->val.vval)
+ goto settrue;
+ goto setfalse;
+ case TUP(ONE, Wlitint):
+ if(nl->val.vval != nr->val.vval)
+ goto settrue;
+ goto setfalse;
+ case TUP(OLT, Wlitint):
+ if(nl->val.vval < nr->val.vval)
+ goto settrue;
+ goto setfalse;
+ case TUP(OLE, Wlitint):
+ if(nl->val.vval <= nr->val.vval)
+ goto settrue;
+ goto setfalse;
+ case TUP(OGE, Wlitint):
+ if(nl->val.vval >= nr->val.vval)
+ goto settrue;
+ goto setfalse;
+ case TUP(OGT, Wlitint):
+ if(nl->val.vval > nr->val.vval)
+ goto settrue;
+ goto setfalse;
+
+ case TUP(OEQ, Wlitfloat):
+ if(nl->val.dval == nr->val.dval)
+ goto settrue;
+ goto setfalse;
+ case TUP(ONE, Wlitfloat):
+ if(nl->val.dval != nr->val.dval)
+ goto settrue;
+ goto setfalse;
+ case TUP(OLT, Wlitfloat):
+ if(nl->val.dval < nr->val.dval)
+ goto settrue;
+ goto setfalse;
+ case TUP(OLE, Wlitfloat):
+ if(nl->val.dval <= nr->val.dval)
+ goto settrue;
+ goto setfalse;
+ case TUP(OGE, Wlitfloat):
+ if(nl->val.dval >= nr->val.dval)
+ goto settrue;
+ goto setfalse;
+ case TUP(OGT, Wlitfloat):
+ if(nl->val.dval > nr->val.dval)
+ goto settrue;
+ goto setfalse;
+
+
+ case TUP(OEQ, Wlitstr):
+ if(cmpslit(nl, nr) == 0)
+ goto settrue;
+ goto setfalse;
+ case TUP(ONE, Wlitstr):
+ if(cmpslit(nl, nr) != 0)
+ goto settrue;
+ goto setfalse;
+ case TUP(OLT, Wlitstr):
+ if(cmpslit(nl, nr) < 0)
+ goto settrue;
+ goto setfalse;
+ case TUP(OLE, Wlitstr):
+ if(cmpslit(nl, nr) <= 0)
+ goto settrue;
+ goto setfalse;
+ case TUP(OGE, Wlitstr):
+ if(cmpslit(nl, nr) >= 0l)
+ goto settrue;
+ goto setfalse;
+ case TUP(OGT, Wlitstr):
+ if(cmpslit(nl, nr) > 0)
+ goto settrue;
+ goto setfalse;
+ case TUP(OADD, Wlitstr):
+ len = nl->val.sval->len + nr->val.sval->len;
+ str = mal(sizeof(*str) + len);
+ str->len = len;
+ memcpy(str->s, nl->val.sval->s, nl->val.sval->len);
+ memcpy(str->s+nl->val.sval->len, nr->val.sval->s, nr->val.sval->len);
+ str->len = len;
+ nl->val.sval = str;
+ break;
+
+ case TUP(OOROR, Wlitbool):
+ if(nl->val.vval || nr->val.vval)
+ goto settrue;
+ goto setfalse;
+ case TUP(OANDAND, Wlitbool):
+ if(nl->val.vval && nr->val.vval)
+ goto settrue;
+ goto setfalse;
+ }
+ *n = *nl;
+ return;
+
+settrue:
+ *n = *booltrue;
+ return;
+
+setfalse:
+ *n = *boolfalse;
+ return;
+
+unary:
+ switch(TUP(n->op, wl)) {
+ default:
+ yyerror("illegal combination of literals %O %d", n->op, wl);
+ return;
+
+ case TUP(OPLUS, Wlitint):
+ nl->val.vval = +nl->val.vval;
+ break;
+ case TUP(OMINUS, Wlitint):
+ nl->val.vval = -nl->val.vval;
+ break;
+ case TUP(OCOM, Wlitint):
+ nl->val.vval = ~nl->val.vval;
+ break;
+
+ case TUP(OPLUS, Wlitfloat):
+ nl->val.dval = +nl->val.dval;
+ break;
+ case TUP(OMINUS, Wlitfloat):
+ nl->val.dval = -nl->val.dval;
+ break;
+
+ case TUP(ONOT, Wlitbool):
+ if(nl->val.vval)
+ goto settrue;
+ goto setfalse;
+ }
+ *n = *nl;
+}
+
+void
+defaultlit(Node *n)
+{
+ if(n == N)
+ return;
+ if(n->type != N)
+ return;
+ if(n->op != OLITERAL)
+ return;
+
+ switch(n->val.ctype) {
+ default:
+ yyerror("defaultlit: unknown literal: %N", n);
+ break;
+ case CTINT:
+ case CTSINT:
+ case CTUINT:
+ n->type = types[TINT32];
+ break;
+ case CTFLT:
+ n->type = types[TFLOAT64];
+ break;
+ case CTBOOL:
+ n->type = types[TBOOL];
+ break;
+ case CTSTR:
+ n->type = types[TSTRING];
+ break;
+ }
+}
+
+int
+cmpslit(Node *l, Node *r)
+{
+ long l1, l2, i, m;
+ uchar *s1, *s2;
+
+ l1 = l->val.sval->len;
+ l2 = r->val.sval->len;
+ s1 = l->val.sval->s;
+ s2 = r->val.sval->s;
+
+ m = l1;
+ if(l2 < m)
+ m = l2;
+
+ for(i=0; i<m; i++) {
+ if(s1[i] == s2[i])
+ continue;
+ if(s1[i] > s2[i])
+ return +1;
+ return -1;
+ }
+ if(l1 == l2)
+ return 0;
+ if(l1 > l2)
+ return +1;
+ return -1;
+}
--- /dev/null
+// 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 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;
+ s->oname = n;
+ 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;
+
+ 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;
+}
+
+/*
+ * 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(void)
+{
+ 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)
+ d = d->link;
+ dclstack = d;
+}
+
+void
+markdcl(void)
+{
+ Sym *d;
+
+ d = push();
+ d->name = nil; // used as a mark in fifo
+// if(debug['d'])
+// print("markdcl\n");
+}
+
+void
+markdclstack(void)
+{
+ Sym *d, *s;
+
+ markdcl();
+
+ // 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
+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;
+}
--- /dev/null
+// 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
+markexport(Node *n)
+{
+ Sym *s;
+ Dcl *d, *r;
+
+loop:
+ if(n == N)
+ return;
+ if(n->op == OLIST) {
+ markexport(n->left);
+ n = n->right;
+ goto loop;
+ }
+ if(n->op != OEXPORT)
+ fatal("markexport: op no OEXPORT: %O", n->op);
+
+ s = n->sym;
+ if(n->psym != S)
+ s = pkglookup(n->sym->name, n->psym->name);
+
+ if(s->export != 0)
+ return;
+ s->export = 1;
+
+ d = mal(sizeof(*d));
+ d->dsym = s;
+ d->dnode = N;
+ d->lineno = curio.lineno;
+
+ r = exportlist;
+ d->back = r->back;
+ r->back->forw = d;
+ r->back = d;
+}
+
+void
+reexport(Node *t)
+{
+ Sym *s;
+
+ if(t == N)
+ fatal("reexport: type nil\n");
+
+ s = t->sym;
+ if(s == S/* || s->name[0] == '_'*/) {
+ exportgen++;
+ snprint(namebuf, sizeof(namebuf), "_e%.3ld", exportgen);
+ s = lookup(namebuf);
+ s->lexical = LATYPE;
+ s->otype = t;
+ t->sym = s;
+ }
+ dumpexporttype(s);
+}
+
+void
+dumpexportconst(Sym *s)
+{
+ Node *n, *t;
+
+ if(s->exported != 0)
+ return;
+ s->exported = 1;
+
+ n = s->oconst;
+ if(n == N || n->op != OLITERAL)
+ fatal("dumpexportconst: oconst nil: %S\n", s);
+
+ t = n->type; // may or may not be specified
+ if(t != N)
+ reexport(t);
+
+ Bprint(bout, "\tconst ");
+ if(s->export != 0)
+ Bprint(bout, "!");
+ Bprint(bout, "%lS ", s);
+ if(t != N)
+ Bprint(bout, "%lS ", t->sym);
+
+ switch(n->val.ctype) {
+ default:
+ fatal("dumpexportconst: unknown ctype: %S\n", s);
+ case CTINT:
+ case CTSINT:
+ case CTUINT:
+ case CTBOOL:
+ Bprint(bout, "0x%llux\n", n->val.vval);
+ break;
+ case CTFLT:
+ Bprint(bout, "%.17e\n", n->val.dval);
+ break;
+ case CTSTR:
+ Bprint(bout, "\"%Z\"\n", n->val.sval);
+ break;
+ }
+}
+
+void
+dumpexportvar(Sym *s)
+{
+ Node *n, *t;
+
+ if(s->exported != 0)
+ return;
+ s->exported = 1;
+
+ n = s->oname;
+ if(n == N || n->type == N)
+ fatal("dumpexportvar: oname nil: %S\n", s);
+
+ t = n->type;
+ reexport(t);
+
+ Bprint(bout, "\tvar ");
+ if(s->export != 0)
+ Bprint(bout, "!");
+ Bprint(bout, "%lS %lS\n", s, t->sym);
+}
+
+void
+dumpexporttype(Sym *s)
+{
+ Node *t, *f;
+ Sym *ts;
+ int et;
+
+ if(s->exported != 0)
+ return;
+ s->exported = 1;
+
+ t = s->otype;
+ if(t == N || t->op != OTYPE)
+ fatal("dumpexporttype: otype nil: %S\n", s);
+ if(t->sym != s)
+ fatal("dumpexporttype: cross reference: %S\n", s);
+
+ et = t->etype;
+ switch(et) {
+ default:
+ if(et < 0 || et >= nelem(types) || types[et] == N)
+ fatal("dumpexporttype: basic type: %E\n", et);
+ /* type 5 */
+ Bprint(bout, "\ttype %lS %d\n", s, et);
+ break;
+
+ case TARRAY:
+ reexport(t->type);
+
+ /* type 2 */
+ Bprint(bout, "\ttype ");
+ if(s->export != 0)
+ Bprint(bout, "!");
+ Bprint(bout, "%lS [%lud] %lS\n", s, t->bound, t->type->sym);
+ break;
+
+ case TPTR:
+ reexport(t->type);
+
+ /* type 6 */
+ Bprint(bout, "\ttype ");
+ if(s->export != 0)
+ Bprint(bout, "!");
+ Bprint(bout, "%lS *%lS\n", s, t->type->sym);
+ break;
+
+ case TFUNC:
+ for(f=t->type; f!=N; f=f->down) {
+ if(f->op != OTYPE || f->etype != TSTRUCT)
+ fatal("dumpexporttype: funct not field: %O/%E\n",
+ f->op, f->etype);
+ reexport(f);
+ }
+
+ /* type 3 */
+ Bprint(bout, "\ttype ");
+ if(s->export != 0)
+ Bprint(bout, "!");
+ Bprint(bout, "%lS (", s);
+ for(f=t->type; f!=N; f=f->down) {
+ if(f != t->type)
+ Bprint(bout, " ");
+ Bprint(bout, "%lS", f->sym);
+ }
+ Bprint(bout, ")\n");
+ break;
+
+ case TSTRUCT:
+ case TINTER:
+ for(f=t->type; f!=N; f=f->down) {
+ if(f->op != OTYPE || f->etype != TFIELD)
+ fatal("dumpexporttype: funct not field: %O/%E\n",
+ f->op, f->etype);
+ reexport(f->type);
+ }
+
+ /* type 4 */
+ Bprint(bout, "\ttype ");
+ if(s->export)
+ Bprint(bout, "!");
+ Bprint(bout, "%lS %c", s, (et==TSTRUCT)? '{': '<');
+ for(f=t->type; f!=N; f=f->down) {
+ ts = f->type->sym;
+ if(f != t->type)
+ Bprint(bout, " ");
+ Bprint(bout, "%s %lS", f->sym->name, ts);
+ }
+ Bprint(bout, "%c\n", (et==TSTRUCT)? '}': '>');
+ break;
+ }
+}
+
+void
+dumpe(Sym *s)
+{
+ switch(s->lexical) {
+ default:
+ yyerror("unknown export symbol: %S\n", s, s->lexical);
+ break;
+ case LPACK:
+ yyerror("package export symbol: %S\n", s);
+ break;
+ case LATYPE:
+ case LBASETYPE:
+ dumpexporttype(s);
+ break;
+ case LNAME:
+ dumpexportvar(s);
+ break;
+ case LACONST:
+ dumpexportconst(s);
+ break;
+ }
+}
+
+void
+dumpexport(void)
+{
+ Dcl *d;
+ long lno;
+
+ lno = dynlineno;
+
+ Bprint(bout, " import\n");
+ Bprint(bout, " ((\n");
+
+ // print it depth first
+ for(d=exportlist->forw; d!=D; d=d->forw) {
+ dynlineno = d->lineno;
+ dumpe(d->dsym);
+ }
+
+ Bprint(bout, " ))\n");
+
+ dynlineno = lno;
+}
+
+/*
+ * ******* import *******
+ */
+Node*
+importlooktype(Node *n)
+{
+ Sym *s;
+
+ if(n->op != OIMPORT)
+ fatal("importlooktype: oops1 %N\n", n);
+
+ s = pkglookup(n->sym->name, n->psym->name);
+ if(s->otype == N)
+ fatal("importlooktype: oops2 %S\n", s);
+
+ return s->otype;
+}
+
+Node**
+importstotype(Node *n, Node **t, Node *uber)
+{
+ Node *f;
+ Iter save;
+
+ n = listfirst(&save, &n);
+
+loop:
+ if(n == N) {
+ *t = N;
+ return t;
+ }
+
+ f = nod(OTYPE, N, N);
+ f->etype = TFIELD;
+ f->type = importlooktype(n);
+ f->uberstruct = uber;
+
+ if(n->fsym != S) {
+ f->nname = newname(n->fsym);
+ } else {
+ vargen++;
+ snprint(namebuf, sizeof(namebuf), "_m%.3ld", vargen);
+ f->nname = newname(lookup(namebuf));
+ }
+ f->sym = f->nname->sym;
+ f->nname->uberstruct = uber;
+
+ *t = f;
+ t = &f->down;
+
+ n = listnext(&save);
+ goto loop;
+}
+
+int
+importcount(Node *t)
+{
+ int i;
+ Node *f;
+
+ if(t == N || t->op != OTYPE || t->etype != TSTRUCT)
+ fatal("importcount: not a struct: %N", t);
+
+ i = 0;
+ for(f=t->type; f!=N; f=f->down)
+ i = i+1;
+ return i;
+}
+
+void
+importfuncnam(Node *t)
+{
+ Node *n, *n1;
+
+ if(t->etype != TFUNC)
+ fatal("importfuncnam: not func %T\n", t);
+
+ if(t->thistuple > 0) {
+ n1 = t->type;
+ if(n1->sym == S)
+ fatal("importfuncnam: no this");
+ n = newname(n1->sym);
+ vargen++;
+ n->vargen = vargen;
+ n1->nname = n;
+ }
+ if(t->outtuple > 0) {
+ n1 = t->type->down;
+ if(n1->sym == S)
+ fatal("importfuncnam: no output");
+ n = newname(n1->sym);
+ vargen++;
+ n->vargen = vargen;
+ n1->nname = n;
+ }
+ if(t->intuple > 0) {
+ n1 = t->type->down->down;
+ if(n1->sym == S)
+ fatal("importfuncnam: no input");
+ n = newname(n1->sym);
+ vargen++;
+ n->vargen = vargen;
+ n1->nname = n;
+ }
+}
+
+Sym*
+getimportsym(Node *ss)
+{
+ char *pkg;
+ Sym *s;
+
+ pkg = ss->psym->name;
+ if(ss->kaka) {
+ pkg = package;
+ if(pkgmyname != S)
+ pkg = pkgmyname->name;
+ }
+ s = pkglookup(ss->sym->name, pkg);
+ /* botch - need some diagnostic checking for the following assignment */
+ s->opackage = ss->osym->name;
+ return s;
+}
+
+void
+importaddtyp(Node *ss, Node *t)
+{
+ Sym *s;
+
+ s = getimportsym(ss);
+ if(s->otype == N || !eqtype(t, s->otype, 0)) {
+ addtyp(newtype(s), t, PEXTERN);
+ }
+}
+
+/*
+ * LCONST importsym LITERAL
+ * untyped constant
+ */
+void
+doimportc1(Node *ss, Val *v)
+{
+ Node *n;
+ Sym *s;
+
+ n = nod(OLITERAL, N, N);
+ n->val = *v;
+
+ s = getimportsym(ss);
+ if(s->oconst == N) {
+ // botch sould ask if already declared the same
+ dodclconst(newname(s), n);
+ }
+}
+
+/*
+ * LCONST importsym importsym LITERAL
+ * typed constant
+ */
+void
+doimportc2(Node *ss, Node *st, Val *v)
+{
+ Node *n, *t;
+ Sym *s;
+
+ n = nod(OLITERAL, N, N);
+ n->val = *v;
+
+ t = importlooktype(st);
+ n->type = t;
+
+ s = getimportsym(ss);
+ if(s->oconst == N) {
+ // botch sould ask if already declared the same
+ dodclconst(newname(s), n);
+ }
+}
+
+/*
+ * LVAR importsym importsym
+ * variable
+ */
+void
+doimportv1(Node *ss, Node *st)
+{
+ Node *t;
+ Sym *s;
+
+ t = importlooktype(st);
+ s = getimportsym(ss);
+ if(s->oname == N || !eqtype(t, s->oname->type, 0)) {
+ addvar(newname(s), t, dclcontext);
+ }
+}
+
+/*
+ * LTYPE importsym [ importsym ] importsym
+ * array type
+ */
+void
+doimport1(Node *ss, Node *ss1, Node *s)
+{
+ fatal("doimport1");
+}
+
+/*
+ * LTYPE importsym [ LLITERAL ] importsym
+ * array type
+ */
+void
+doimport2(Node *ss, Val *b, Node *st)
+{
+ Node *t;
+ Sym *s;
+
+ t = nod(OTYPE, N, N);
+ t->etype = TARRAY;
+ t->bound = b->vval;
+ s = pkglookup(st->sym->name, st->psym->name);
+ t->type = s->otype;
+
+ importaddtyp(ss, t);
+}
+
+/*
+ * LTYPE importsym '(' importsym_list ')'
+ * function/method type
+ */
+void
+doimport3(Node *ss, Node *n)
+{
+ Node *t;
+
+ t = nod(OTYPE, N, N);
+ t->etype = TFUNC;
+
+ t->type = importlooktype(n->left);
+ t->type->down = importlooktype(n->right->left);
+ t->type->down->down = importlooktype(n->right->right);
+
+ t->thistuple = importcount(t->type);
+ t->outtuple = importcount(t->type->down);
+ t->intuple = importcount(t->type->down->down);
+
+ importfuncnam(t);
+
+ importaddtyp(ss, t);
+}
+
+/*
+ * LTYPE importsym '{' importsym_list '}'
+ * structure type
+ */
+void
+doimport4(Node *ss, Node *n)
+{
+ Node *t;
+
+ t = nod(OTYPE, N, N);
+ t->etype = TSTRUCT;
+ importstotype(n, &t->type, t);
+
+ importaddtyp(ss, t);
+}
+
+/*
+ * LTYPE importsym LLITERAL
+ * basic type
+ */
+void
+doimport5(Node *ss, Val *v)
+{
+ int et;
+ Node *t;
+
+ et = v->vval;
+ if(et <= 0 || et >= nelem(types) || types[et] == N)
+ fatal("doimport5: bad type index: %E\n", et);
+
+ t = nod(OTYPE, 0, 0);
+ t->etype = et;
+ t->sym = S;
+
+ importaddtyp(ss, t);
+}
+
+/*
+ * LTYPE importsym * importsym
+ * pointer type
+ */
+void
+doimport6(Node *ss, Node *st)
+{
+ Node *t;
+ Sym *s;
+
+ s = pkglookup(st->sym->name, st->psym->name);
+ t = s->otype;
+ if(t == N)
+ t = forwdcl(s);
+ else
+ t = ptrto(t);
+
+ importaddtyp(ss, t);
+}
+
+/*
+ * LTYPE importsym '<' importsym '>'
+ * interface type
+ */
+void
+doimport7(Node *ss, Node *n)
+{
+ Node *t;
+
+ t = nod(OTYPE, N, N);
+ t->etype = TINTER;
+ importstotype(n, &t->type, t);
+
+ importaddtyp(ss, t);
+}
--- /dev/null
+// 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"
+
+#undef EXTERN
+#define EXTERN
+#include "gen.h"
+
+static Node* curfn;
+
+void
+compile(Node *fn)
+{
+ Plist *pl;
+
+ if(fn->nbody == N)
+ return;
+ if(nerrors != 0) {
+ walk(fn);
+ return;
+ }
+
+ if(debug['w'])
+ dump("--- pre walk ---", fn->nbody);
+ walk(fn);
+ if(nerrors != 0)
+ return;
+ if(debug['w'])
+ dump("--- post walk ---", fn->nbody);
+
+ curfn = fn;
+
+ continpc = P;
+ breakpc = P;
+
+ pc = mal(sizeof(*pc));
+ firstpc = pc;
+ pc->op = PEND;
+ pc->addr.type = ANONE;
+ pc->loc = 1;
+ inarggen();
+ gen(curfn->nbody);
+
+ if(curfn->type->outtuple != 0)
+ gopcodet(PPANIC, N, N);
+
+ if(debug['p'])
+ proglist();
+
+ pl = mal(sizeof(*pl));
+ pl->name = curfn->nname;
+ pl->locals = autodcl;
+ pl->firstpc = firstpc;
+
+ if(plist == nil)
+ plist = pl;
+ else
+ plast->link = pl;
+ plast = pl;
+
+ if(debug['f'])
+ frame(0);
+}
+
+/*
+ * compile statements
+ */
+void
+gen(Node *n)
+{
+ long lno;
+ Prog *scontin, *sbreak;
+ Prog *p1, *p2, *p3;
+ Sym *s;
+
+ lno = dynlineno;
+
+loop:
+ if(n == N)
+ goto ret;
+ dynlineno = n->lineno; // for diagnostics
+
+ switch(n->op) {
+ default:
+ dump("gen: unknown op", n);
+ break;
+
+ case ODCLTYPE:
+ break;
+
+ case OLIST:
+ gen(n->left);
+ n = n->right;
+ goto loop;
+
+ case OPANIC:
+ case OPRINT:
+ genprint(n->left);
+ if(n->op == OPANIC)
+ gopcodet(PPANIC, N, N);
+ break;
+
+ case OCASE:
+ case OFALL:
+ case OXCASE:
+ case OXFALL:
+ case OEMPTY:
+ break;
+
+ case OLABEL:
+ // before declaration, s->label points at
+ // a link list of PXGOTO instructions.
+ // after declaration, s->label points
+ // at a PGOTO to .+1
+
+ s = n->left->sym;
+ p1 = (Prog*)s->label;
+
+ if(p1 != P) {
+ if(p1->op == PGOTO) {
+ yyerror("label redeclared: %S", s);
+ break;
+ }
+ while(p1 != P) {
+ if(p1->op != PGOTOX)
+ fatal("bad label pointer: %S", s);
+ p2 = p1->addr.branch;
+ p1->addr.branch = pc;
+ p1->op = PGOTO;
+ p1 = p2;
+ }
+ }
+
+ s->label = pc;
+ p1 = gbranch(PGOTO, N);
+ patch(p1, pc);
+ break;
+
+ case OGOTO:
+ s = n->left->sym;
+ p1 = (Prog*)s->label;
+ if(p1 != P && p1->op == PGOTO) {
+ // already declared
+ p2 = gbranch(PGOTO, N);
+ patch(p2, p1->addr.branch);
+ break;
+ }
+
+ // not declaraed yet
+ p2 = gbranch(PGOTOX, N);
+ p2->addr.node = n; // info for diagnostic if never declared
+ patch(p2, p1);
+ s->label = p2;
+ break;
+
+ case OBREAK:
+ if(breakpc == P) {
+ yyerror("gen: break is not in a loop");
+ break;
+ }
+ patch(gbranch(PGOTO, N), breakpc);
+ break;
+
+ case OCONTINUE:
+ if(continpc == P) {
+ yyerror("gen: continue is not in a loop");
+ break;
+ }
+ patch(gbranch(PGOTO, N), continpc);
+ break;
+
+ case OFOR:
+ gen(n->ninit); // init
+ p1 = gbranch(PGOTO, N); // goto test
+ sbreak = breakpc;
+ breakpc = gbranch(PGOTO, N); // break: goto done
+ scontin = continpc;
+ continpc = pc;
+ gen(n->nincr); // contin: incr
+ patch(p1, pc); // test:
+ bgen(n->ntest, 0, breakpc); // if(!test) goto break
+ gen(n->nbody); // body
+ patch(gbranch(PGOTO, N), continpc); // goto contin
+ patch(breakpc, pc); // done:
+ continpc = scontin;
+ breakpc = sbreak;
+ break;
+
+ case OIF:
+ gen(n->ninit); // init
+ p1 = gbranch(PGOTO, N); // goto test
+ p2 = gbranch(PGOTO, N); // p2: goto else
+ patch(p1, pc); // test:
+ bgen(n->ntest, 0, p2); // if(!test) goto p2
+ gen(n->nbody); // then
+ p3 = gbranch(PGOTO, N); // goto done
+ patch(p2, pc); // else:
+ gen(n->nelse); // else
+ patch(p3, pc); // done:
+ break;
+
+ case OSWITCH:
+ gen(n->ninit); // init
+ p1 = gbranch(PGOTO, N); // goto test
+ sbreak = breakpc;
+ breakpc = gbranch(PGOTO, N); // break: goto done
+ patch(p1, pc); // test:
+ swgen(n); // switch(test) body
+ patch(breakpc, pc); // done:
+ breakpc = sbreak;
+ break;
+
+ case OASOP:
+ cgen_asop(n->left, n->right, n->kaka);
+ break;
+
+ case ODCLVAR:
+ case OCOLAS:
+ case OAS:
+ cgen_as(n->left, n->right, n->op, n->kaka);
+ break;
+
+ case OCALL:
+ case OCALLPTR:
+ case OCALLMETH:
+ case OCALLINTER:
+ cgen_call(n, 1);
+ break;
+
+ case ORETURN:
+ cgen_ret(n);
+ break;
+ }
+
+ret:
+ dynlineno = lno;
+}
+
+/*
+ * compile expression to (unnamed) reg
+ */
+void
+cgen(Node *n)
+{
+ long lno;
+ Node *nl, *nr, *r, *r1;
+ int a;
+ Prog *p1, *p2, *p3;
+
+ if(n == N)
+ return;
+
+ lno = dynlineno;
+ if(n->op != ONAME)
+ dynlineno = n->lineno; // for diagnostics
+
+ nl = n->left;
+ nr = n->right;
+
+ if(nr != N && nr->ullman >= UINF && nl != N && nl->ullman >= UINF) {
+ cgen(nr);
+ r = tempname(n->type);
+ gopcodet(PSTORE, n->type, r);
+ nr = r;
+ }
+
+ switch(n->op) {
+ default:
+ yyerror("cgen: unknown op %O", n->op);
+ break;
+
+ case ONAME:
+ case OLITERAL:
+ gopcodet(PLOAD, n->type, n);
+ break;
+
+ case ONEW:
+ gopcodet(PNEW, n->type, n);
+ break;
+
+ // these call bgen to get a bool value
+ case OOROR:
+ case OANDAND:
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OLE:
+ case OGE:
+ case OGT:
+ case ONOT:
+ p1 = gbranch(PGOTO, N);
+ p2 = gopcodet(PLOAD, n->type, booltrue);
+ p3 = gbranch(PGOTO, N);
+ patch(p1, pc);
+ bgen(n, 1, p2);
+ p2 = gopcodet(PLOAD, n->type, boolfalse);
+ patch(p3, pc);
+ goto ret;
+
+ case OPLUS:
+ cgen(nl);
+ goto ret;
+
+ // unary
+ case OMINUS:
+ case OCOM:
+ a = optopop(n->op);
+ goto uop;
+
+ // symmetric binary
+ case OAND:
+ case OOR:
+ case OXOR:
+ case OADD:
+ case OMUL:
+ a = optopop(n->op);
+ goto sbop;
+
+ // asymmetric binary
+ case OMOD:
+ case OSUB:
+ case ODIV:
+ case OLSH:
+ case ORSH:
+ case OCAT:
+ a = optopop(n->op);
+ goto abop;
+
+ case OCONV:
+ if(isbytearray(nl->type)) {
+ if(nl->type->etype == TPTR)
+ cgen(nl);
+ else
+ agen(nl);
+ gopcode(PCONV, PTNIL, nod(OCONV, n->type, nl->type));
+ break;
+ }
+
+ cgen(nl);
+ gopcode(PCONV, PTNIL, nod(OCONV, n->type, nl->type));
+ break;
+
+ case OINDEXSTR:
+ nl = n->left;
+ nr = n->right;
+ if(nl->addable) {
+ cgen(nr);
+ gopcodet(PINDEXZ, nr->type, nl);
+ break;
+ }
+ cgen(nl);
+ r = tempname(nl->type);
+ gopcodet(PSTORE, nl->type, r);
+ cgen(nr);
+ gopcodet(PINDEXZ, nr->type, r);
+ break;
+
+ case OSLICE:
+ nl = n->left;
+ nr = n->right;
+
+ r = nr->left;
+ if(usesptr(nr->left)) {
+ cgen(nr->left);
+ r = tempname(nr->left->type);
+ gopcodet(PSTORE, nr->left->type, r);
+ }
+
+ r1 = nr->right;
+ if(!nr->right->addable) {
+ cgen(nr->right);
+ r1 = tempname(nr->right->type);
+ gopcodet(PSTORE, nr->right->type, r1);
+ }
+
+ // string into PTADDR
+ if(!nl->addable) {
+ cgen(nl);
+ gconv(PTADDR, nl->type->etype);
+ } else
+ gopcode(PLOAD, PTADDR, nl);
+
+ // offset in int reg
+ cgen(nr->left);
+
+ // len addressed
+ gopcodet(PSLICE, nr->left->type, nr->right);
+ break;
+
+ case OINDEXPTR:
+ case OINDEX:
+ case ODOT:
+ case ODOTPTR:
+ case OIND:
+ agen(n);
+ gopcodet(PLOADI, n->type, N);
+ break;
+
+ case OLEN:
+ cgen(nl);
+ gopcodet(PLEN, nl->type, nl);
+ break;
+
+ case ODOTMETH:
+ case ODOTINTER:
+ cgen(n->left);
+ break;
+
+ case OADDR:
+ agen(nl);
+ gconv(PTPTR, PTADDR);
+ break;
+
+ case OCALL:
+ case OCALLPTR:
+ case OCALLMETH:
+ case OCALLINTER:
+ cgen_call(n, 0);
+ cgen_callret(n, N);
+ break;
+ }
+ goto ret;
+
+sbop: // symmetric
+ if(nl->ullman < nr->ullman) {
+ r = nl;
+ nl = nr;
+ nr = r;
+ }
+
+abop: // asymmetric
+ if(nr->addable) {
+ cgen(nl);
+ gopcodet(a, n->type, nr);
+ goto ret;
+ }
+
+ cgen(nr);
+ r = tempname(n->type);
+ gopcodet(PSTORE, n->type, r);
+ cgen(nl);
+ gopcodet(a, n->type, r);
+ goto ret;
+
+uop: // unary
+ cgen(nl);
+ gopcodet(a, n->type, N);
+ goto ret;
+
+ret:
+ dynlineno = lno;
+}
+
+/*
+ * compile the address of a value
+ */
+void
+agen(Node *n)
+{
+ Node *nl, *nr;
+ Node *t, *r;
+
+ if(n == N || n->type == N)
+ return;
+ switch(n->op) {
+ default:
+ dump("agen: unknown op", n);
+ break;
+
+ case ONAME:
+ gopcode(PADDR, PTADDR, n);
+ break;
+
+ case OINDEXPTR:
+ nl = n->left;
+ nr = n->right;
+ if(nl->addable) {
+ cgen(nr);
+ gopcode(PLOAD, PTADDR, nl);
+ genindex(n);
+ break;
+ }
+ if(nr->addable) {
+ cgen(nl);
+ gconv(PTADDR, nl->type->etype);
+ cgen(nr);
+ genindex(n);
+ break;
+ }
+ cgen(nr);
+ r = tempname(n->type);
+ gopcodet(PSTORE, n->type, r);
+ cgen(nl);
+ gconv(PTADDR, nl->type->etype);
+ cgen(r);
+ genindex(n);
+ break;
+
+ case OINDEX:
+ nl = n->left;
+ nr = n->right;
+ if(nl->addable) {
+ cgen(nr);
+ agen(nl);
+ genindex(n);
+ break;
+ }
+ if(nr->addable) {
+ agen(nl);
+ cgen(nr);
+ genindex(n);
+ break;
+ }
+ cgen(nr);
+ r = tempname(n->type);
+ gopcodet(PSTORE, n->type, r);
+ agen(nl);
+ cgen(r);
+ genindex(n);
+ break;
+
+ case OIND:
+ nl = n->left;
+ if(nl->addable) {
+ gopcode(PLOAD, PTADDR, nl);
+ break;
+ }
+ cgen(nl);
+ gconv(PTADDR, nl->type->etype);
+ break;
+
+ case ODOT:
+ case ODOTPTR:
+ nl = n->left;
+ nr = n->right;
+ t = nl->type;
+ switch(t->etype) {
+ default:
+ badtype(n->op, n->left->type, n->right->type);
+ break;
+
+ case TPTR:
+ if(nl->op != ONAME) {
+ cgen(nl);
+ gconv(PTADDR, nl->type->etype);
+ } else
+ gopcode(PLOAD, PTADDR, nl);
+ gaddoffset(nr);
+ break;
+
+ case TSTRUCT:
+ agen(nl);
+ gaddoffset(nr);
+ break;
+ }
+ break;
+ }
+}
+
+/*
+ * compile boolean expression
+ * true is branch-true or branch-false
+ * to is where to branch
+ */
+void
+bgen(Node *n, int true, Prog *to)
+{
+ long lno;
+ int et, a;
+ Node *nl, *nr, *r;
+ Prog *p1, *p2;
+
+ if(n == N)
+ n = booltrue;
+
+ lno = dynlineno;
+ if(n->op != ONAME)
+ dynlineno = n->lineno; // for diagnostics
+
+ if(n == N)
+ goto ret;
+ if(n->type == N) {
+ convlit(n, types[TBOOL]);
+ if(n->type == N)
+ goto ret;
+ }
+
+ et = n->type->etype;
+ if(et != TBOOL) {
+ yyerror("cgen: bad type %T for %O", n->type, n->op);
+ patch(gbranch(PERROR, N), to);
+ goto ret;
+ }
+ nl = N;
+ nr = N;
+
+ switch(n->op) {
+ default:
+ cgen(n);
+ gopcodet(PTEST, n->type, N);
+ a = PBTRUE;
+ if(!true)
+ a = PBFALSE;
+ patch(gbranch(a, n->type), to);
+ goto ret;
+
+ case OLITERAL:
+ if(!true == !n->val.vval)
+ patch(gbranch(PGOTO, N), to);
+ goto ret;
+
+ case ONAME:
+ gopcodet(PTEST, n->type, n);
+ a = PBTRUE;
+ if(!true)
+ a = PBFALSE;
+ patch(gbranch(a, n->type), to);
+ goto ret;
+
+ case OANDAND:
+ if(!true)
+ goto caseor;
+
+ caseand:
+ p1 = gbranch(PGOTO, N);
+ p2 = gbranch(PGOTO, N);
+ patch(p1, pc);
+ bgen(n->left, !true, p2);
+ bgen(n->right, !true, p2);
+ p1 = gbranch(PGOTO, N);
+ patch(p1, to);
+ patch(p2, pc);
+ goto ret;
+
+ case OOROR:
+ if(!true)
+ goto caseand;
+
+ caseor:
+ bgen(n->left, true, to);
+ bgen(n->right, true, to);
+ goto ret;
+
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OGT:
+ case OLE:
+ case OGE:
+ nr = n->right;
+ if(nr == N || nr->type == N)
+ goto ret;
+
+ case ONOT: // unary
+ nl = n->left;
+ if(nl == N || nl->type == N)
+ goto ret;
+ }
+
+ switch(n->op) {
+
+ case ONOT:
+ bgen(nl, !true, to);
+ goto ret;
+
+ case OEQ: a = PBEQ; goto br;
+ case ONE: a = PBNE; goto br;
+ case OLT: a = PBLT; goto br;
+ case OGT: a = PBGT; goto br;
+ case OLE: a = PBLE; goto br;
+ case OGE: a = PBGE; goto br;
+ br:
+ if(!true)
+ a = brcom(a);
+
+ // make simplest on right
+ if(nl->ullman < nr->ullman) {
+ a = brrev(a);
+ r = nl;
+ nl = nr;
+ nr = r;
+ }
+
+ if(nr->addable) {
+ cgen(nl);
+ gopcodet(PCMP, nr->type, nr);
+ patch(gbranch(a, nr->type), to);
+ break;
+ }
+ cgen(nr);
+ r = tempname(nr->type);
+ gopcodet(PSTORE, nr->type, r);
+ cgen(nl);
+ gopcodet(PCMP, nr->type, r);
+ patch(gbranch(a, nr->type), to);
+ break;
+ }
+ goto ret;
+
+ret:
+ dynlineno = lno;
+}
+
+void
+swgen(Node *n)
+{
+ Node *c1, *c2;
+ Case *s0, *se, *s;
+ Prog *p1, *dflt;
+ long lno;
+ int any;
+ Iter save1, save2;
+
+ lno = dynlineno;
+
+ p1 = gbranch(PGOTO, N);
+ s0 = C;
+ se = C;
+
+ // walk thru the body placing breaks
+ // and labels into the case statements
+
+ any = 0;
+ dflt = P;
+ c1 = listfirst(&save1, &n->nbody);
+ while(c1 != N) {
+ dynlineno = c1->lineno; // for diagnostics
+ if(c1->op != OCASE) {
+ if(s0 == C)
+ yyerror("unreachable statements in a switch");
+ gen(c1);
+
+ any = 1;
+ if(c1->op == OFALL)
+ any = 0;
+ c1 = listnext(&save1);
+ continue;
+ }
+
+ // put in the break between cases
+ if(any) {
+ patch(gbranch(PGOTO, N), breakpc);
+ any = 0;
+ }
+
+ // over case expressions
+ c2 = listfirst(&save2, &c1->left);
+ if(c2 == N)
+ dflt = pc;
+
+ while(c2 != N) {
+
+ s = mal(sizeof(*s));
+ if(s0 == C)
+ s0 = s;
+ else
+ se->slink = s;
+ se = s;
+
+ s->scase = c2; // case expression
+ s->sprog = pc; // where to go
+
+ c2 = listnext(&save2);
+ }
+
+ c1 = listnext(&save1);
+ }
+
+ if(any)
+ patch(gbranch(PGOTO, N), breakpc);
+
+ patch(p1, pc);
+ c1 = tempname(n->ntest->type);
+ cgen(n->ntest);
+ gopcodet(PSTORE, n->ntest->type, c1);
+
+ for(s=s0; s!=C; s=s->slink) {
+ cgen(s->scase);
+ gopcodet(PCMP, n->ntest->type, c1);
+ patch(gbranch(PBEQ, n->ntest->type), s->sprog);
+ }
+ if(dflt != P) {
+ patch(gbranch(PGOTO, N), dflt);
+ goto ret;
+ }
+ patch(gbranch(PGOTO, N), breakpc);
+
+ret:
+ dynlineno = lno;
+}
+
+/*
+ * does this tree use
+ * the pointer register
+ */
+int
+usesptr(Node *n)
+{
+// if(n->addable)
+// return 0;
+ return 1;
+}
+
+void
+cgen_as(Node *nl, Node *nr, int op, int kaka)
+{
+ Node *r;
+
+loop:
+ switch(op) {
+ default:
+ fatal("cgen_as: unknown op %O", op);
+
+ case ODCLVAR:
+ if(nr == N && nl->op == OLIST) {
+ kaka = PAS_SINGLE;
+ cgen_as(nl->left, nr, op, kaka);
+ nl = nl->right;
+ goto loop;
+ }
+
+ case OCOLAS:
+ case OAS:
+ switch(kaka) {
+ default:
+ yyerror("cgen_as: unknown param %d %d", kaka, PAS_CALLM);
+ break;
+
+ case PAS_CALLM: // function returning multi values
+ cgen_call(nr, 0);
+ cgen_callret(nr, nl);
+ break;
+
+ case PAS_SINGLE: // single return val used in expr
+ if(nr == N) {
+ if(nl->addable) {
+ gopcodet(PSTOREZ, nl->type, nl);
+ break;
+ }
+ agen(nl);
+ gopcodet(PSTOREZIP, nl->type, N);
+ break;
+ }
+
+ if(nl->addable) {
+ cgen(nr);
+ genconv(nl->type, nr->type);
+ gopcodet(PSTORE, nl->type, nl);
+ break;
+ }
+
+ if(nr->addable && !needconvert(nl->type, nr->type)) {
+ agen(nl);
+ gopcodet(PSTOREI, nr->type, nr);
+ break;
+ }
+ if(!usesptr(nr)) {
+ cgen(nr);
+ genconv(nl->type, nr->type);
+ agen(nl);
+ gopcodet(PSTOREI, nr->type, N);
+ break;
+ }
+ agen(nl);
+ r = tempname(ptrto(nl->type));
+ gopcode(PSTORE, PTADDR, r);
+ cgen(nr);
+ genconv(nl->type, nr->type);
+ gopcode(PLOAD, PTADDR, r);
+ gopcodet(PSTOREI, nl->type, N);
+ break;
+
+ case PAS_STRUCT: // structure assignment
+ r = ptrto(nr->type);
+ if(!usesptr(nr)) {
+ agen(nr);
+ agen(nl);
+ gopcodet(PLOAD, N, r);
+ gopcodet(PERROR, nr->type, N);
+ break;
+ }
+ r = tempname(r);
+ agen(nr);
+ gopcode(PSTORE, PTADDR, r);
+
+ agen(nl);
+ gopcodet(PERROR, nr->type, r);
+ break;
+ }
+ break;
+ }
+}
+
+void
+cgen_asop(Node *nl, Node *nr, int op)
+{
+ Node *r;
+ int a;
+
+ a = optopop(op);
+ if(nr->addable) {
+ if(nl->addable) {
+ gopcodet(PLOAD, nl->type, nl);
+ gopcodet(a, nr->type, nr);
+ gopcodet(PSTORE, nl->type, nl);
+ return;
+ }
+
+ agen(nl);
+ gopcodet(PLOADI, nl->type, N);
+ gopcodet(a, nr->type, nr);
+ gopcodet(PSTOREI, nl->type, N);
+ return;
+ }
+
+ r = tempname(nr->type);
+ cgen(nr);
+ gopcodet(PSTORE, nr->type, r);
+
+ agen(nl);
+ gopcodet(PLOADI, nl->type, N);
+ gopcodet(a, nr->type, r);
+ gopcodet(PSTOREI, nl->type, N);
+}
+
+void
+inarggen(void)
+{
+ Iter save;
+ Node *arg, *t;
+ int i;
+
+ t = curfn->type;
+
+ arg = structfirst(&save, getthis(t));
+ if(arg != N) {
+ fnparam(t, 0, 0);
+ gopcodet(PSTORE, arg->type, arg->nname);
+ }
+
+ i = 0;
+ arg = structfirst(&save, getinarg(t));
+ while(arg != N) {
+ fnparam(t, 2, i);
+ gopcodet(PLOADI, arg->type, arg->nname);
+
+ arg = structnext(&save);
+ i++;
+ }
+}
+
+void
+cgen_ret(Node *n)
+{
+ Node *arg, *a, *f;
+ Iter save;
+
+ arg = listfirst(&save, &n->left); // expr list
+ a = getoutargx(curfn->type);
+ f = a->type;
+ for(;;) {
+ if(arg == N)
+ break;
+ if(f->etype != TFIELD)
+ fatal("cgen_ret: not field");
+ if(arg->addable && !needconvert(f->type, arg->type)) {
+ gopcode(PLOAD, PTADDR, a->nname);
+ gopcode(PADDO, PTADDR, f->nname);
+ gopcodet(PSTOREI, arg->type, arg);
+ } else {
+ cgen(arg);
+ genconv(f->type, arg->type);
+ gopcode(PLOAD, PTADDR, a->nname);
+ gopcode(PADDO, PTADDR, f->nname);
+ gopcodet(PSTOREI, arg->type, N);
+ }
+ arg = listnext(&save);
+ f = f->down;
+ }
+ gopcodet(PRETURN, N, N);
+}
+
+void
+cgen_call(Node *n, int toss)
+{
+ Node *t, *at, *ae, *sn;
+ Iter save;
+ int i;
+
+ /*
+ * open a block
+ */
+ gopcodet(PCALL1, N, n->left);
+
+ /*
+ * prepare the input args
+ */
+ t = n->left->type;
+ if(t->etype == TPTR)
+ t = t->type;
+
+ at = *getinarg(t); // parameter struct
+ sn = at->nname; // in arg structure name
+
+ at = at->type; // parameter fields
+ ae = listfirst(&save, &n->right); // expr list
+
+ for(i=0; i<t->intuple; i++) {
+ if(ae == N)
+ fatal("cgen_call: tupleness");
+
+ if(ae->addable && !needconvert(at->type, ae->type)) {
+ gopcode(PADDR, PTADDR, sn);
+ gopcode(PADDO, PTADDR, at->nname);
+ gopcodet(PSTOREI, at->type, ae);
+ } else {
+ cgen(ae);
+ genconv(at->type, ae->type);
+ gopcode(PADDR, PTADDR, sn);
+ gopcode(PADDO, PTADDR, at->nname);
+ gopcodet(PSTOREI, at->type, N);
+ }
+ ae = listnext(&save);
+ at = at->down;
+ }
+
+ /*
+ * call the function
+ */
+ switch(n->op) {
+ default:
+ fatal("cgen_call: %O", n->op);
+
+ case OCALL:
+ gopcodet(PCALL2, N, n->left);
+ break;
+
+ case OCALLPTR:
+ cgen(n->left);
+ gopcodet(PCALLI2, N, n->left);
+ break;
+
+ case OCALLMETH:
+ cgen(n->left);
+ gopcodet(PCALLM2, N, n->left);
+ break;
+
+ case OCALLINTER:
+ cgen(n->left);
+ gopcodet(PCALLF2, N, n->left);
+ break;
+ }
+
+ /*
+ * toss the output args
+ */
+ if(toss) {
+ gopcodet(PCALL3, N, n->left);
+ return;
+ }
+}
+
+void
+cgen_callret(Node *n, Node *mas)
+{
+ Node *t, *at, *ae, *sn;
+ Iter save;
+ int i;
+
+ t = n->left->type;
+ if(t->etype == TPTR)
+ t = t->type;
+
+ at = *getoutarg(t); // parameter struct
+ sn = at->nname; // out arg structure name
+ at = at->type; // parameter fields
+
+ // call w single return val to a register
+ if(mas == N) {
+ gopcode(PADDR, PTADDR, sn);
+ gopcode(PADDO, PTADDR, at->nname);
+ gopcodet(PLOADI, at->type, N);
+ gopcodet(PCALL3, N, N);
+ return;
+ }
+
+ // call w multiple values to lval list
+ ae = listfirst(&save, &mas); // expr list
+ for(i=0; i<t->outtuple; i++) {
+ if(ae == N)
+ fatal("cgen_callret: output arguments do not match");
+
+ if(ae->addable) {
+ gopcode(PADDR, PTADDR, sn);
+ gopcode(PADDO, PTADDR, at->nname);
+ gopcodet(PLOADI, at->type, ae);
+ } else {
+ agen(ae);
+ gopcode(PADDR, PTADDR, sn);
+ gopcode(PADDO, PTADDR, at->nname);
+ gopcodet(PLOADI, at->type, N);
+ }
+
+ ae = listnext(&save);
+ at = at->down;
+ }
+
+ gopcodet(PCALL3, N, N);
+}
+
+void
+genprint(Node *n)
+{
+ Node *arg;
+ Iter save;
+
+ arg = listfirst(&save, &n);
+ while(arg != N) {
+ cgen(arg);
+ gopcodet(PPRINT, arg->type, N);
+ arg = listnext(&save);
+ }
+}
+
+int
+needconvert(Node *tl, Node *tr)
+{
+ if(isinter(tl))
+ if(isptrto(tr, TSTRUCT) || isinter(tr))
+ return 1;
+ if(isptrto(tl, TSTRUCT))
+ if(isinter(tr))
+ return 1;
+ return 0;
+}
+
+void
+genconv(Node *tl, Node *tr)
+{
+ if(needconvert(tl, tr))
+ gopcode(PCONV, PTNIL, nod(OCONV, tl, tr));
+}
+
+void
+genindex(Node *n)
+{
+ gopcode(PINDEX, n->right->type->etype, n);
+}
+
+int
+optopop(int op)
+{
+ int a;
+
+ switch(op) {
+ default:
+ fatal("optopop: unknown op %O\n", op);
+
+ case OMINUS: a = PMINUS; break;
+ case OCOM: a = PCOM; break;
+ case OAND: a = PAND; break;
+ case OOR: a = POR; break;
+ case OXOR: a = PXOR; break;
+ case OADD: a = PADD; break;
+ case OMUL: a = PMUL; break;
+ case OMOD: a = PMOD; break;
+ case OSUB: a = PSUB; break;
+ case ODIV: a = PDIV; break;
+ case OLSH: a = PLSH; break;
+ case ORSH: a = PRSH; break;
+ case OCAT: a = PCAT; break;
+ }
+ return a;
+}
--- /dev/null
+// 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.
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+typedef struct Prog Prog;
+typedef struct Addr Addr;
+
+struct Addr
+{
+ int type;
+ Node* node;
+ Prog* branch;
+};
+
+enum
+{
+ AXXX = 0,
+ ANONE,
+ ANODE,
+ ABRANCH,
+};
+
+struct Prog
+{
+ int op; // opcode
+ int pt;
+ int pt1;
+ int param;
+ long lineno; // source line
+ long loc; // program counter for print
+ int mark;
+ Addr addr; // operand
+ Prog* link;
+};
+#define P ((Prog*)0)
+
+typedef struct Plist Plist;
+struct Plist
+{
+ Node* name;
+ Dcl* locals;
+ Prog* firstpc;
+ int recur;
+ Plist* link;
+};
+
+typedef struct Sig Sig;
+struct Sig
+{
+ char* fun;
+ ulong hash;
+ int offset;
+ Sig* link;
+};
+
+enum
+{
+ PTxxx,
+
+ PTINT8 = TINT8,
+ PTUINT8 = TUINT8,
+ PTINT16 = TINT16,
+ PTUINT16 = TUINT16,
+ PTINT32 = TINT32,
+ PTUINT32 = TUINT32,
+ PTINT64 = TINT64,
+ PTUINT64 = TUINT64,
+ PTFLOAT32 = TFLOAT32,
+ PTFLOAT64 = TFLOAT64,
+ PTFLOAT80 = TFLOAT80,
+ PTBOOL = TBOOL,
+ PTPTR = TPTR,
+ PTSTRUCT = TSTRUCT,
+ PTINTER = TINTER,
+ PTARRAY = TARRAY,
+ PTSTRING = TSTRING,
+ PTCHAN = TCHAN,
+ PTMAP = TMAP,
+
+ PTNIL = NTYPE,
+ PTADDR,
+ PTERROR,
+
+ NPTYPE,
+};
+
+enum
+{
+ PXXX = 0,
+
+ PERROR, PPANIC, PPRINT, PGOTO, PGOTOX,
+
+ PCMP, PTEST, PNEW, PLEN,
+ PCALL1, PCALL2, PCALLI2, PCALLM2, PCALLF2, PCALL3, PRETURN,
+
+ PBEQ, PBNE,
+ PBLT, PBLE, PBGE, PBGT,
+ PBTRUE, PBFALSE,
+
+ PLOAD, PLOADI,
+ PSTORE, PSTOREI,
+ PSTOREZ, PSTOREZIP,
+ PCONV, PADDR, PADDO, PINDEX, PINDEXZ,
+ PSLICE,
+
+ PADD, PSUB, PMUL, PDIV, PLSH, PRSH, PMOD,
+ PAND, POR, PXOR, PCAT,
+
+ PMINUS, PCOM,
+
+ PEND,
+};
+
+typedef struct Case Case;
+struct Case
+{
+ Prog* sprog;
+ Node* scase;
+ Case* slink;
+};
+#define C ((Case*)0)
+
+EXTERN Prog* continpc;
+EXTERN Prog* breakpc;
+EXTERN Prog* pc;
+EXTERN Prog* firstpc;
+EXTERN Plist* plist;
+EXTERN Plist* plast;
+EXTERN Biobuf* bout;
+EXTERN long dynloc;
+
+/*
+ * gen.c
+ */
+void compile(Node*);
+void proglist(void);
+void gen(Node*);
+void cgen(Node*);
+void agen(Node*);
+void bgen(Node*, int, Prog*);
+void swgen(Node*);
+Node* lookdot(Node*, Node*, int);
+int usesptr(Node*);
+void inarggen(void);
+void cgen_as(Node*, Node*, int, int);
+void cgen_asop(Node*, Node*, int);
+void cgen_ret(Node*);
+void cgen_call(Node*, int);
+void cgen_callret(Node*, Node*);
+void genprint(Node*);
+int needconvert(Node*, Node*);
+void genconv(Node*, Node*);
+void genindex(Node*);
+
+/*
+ * gsubr.c
+ */
+int Aconv(Fmt*);
+int Pconv(Fmt*);
+void proglist(void);
+Prog* gbranch(int, Node*);
+void patch(Prog*, Prog*);
+Prog* prog(int);
+Node* tempname(Node*);
+Prog* gopcode(int, int, Node*);
+Prog* gopcodet(int, Node*, Node*);
+void gaddoffset(Node*);
+void gconv(int, int);
+int conv2pt(Node*);
+void belexinit(int);
+vlong convvtox(vlong, int);
+int brcom(int);
+int brrev(int);
+void fnparam(Node*, int, int);
+Sig* lsort(Sig*, int(*)(Sig*, Sig*));
+
+/*
+ * obj.c
+ */
+void dumpobj(void);
+void litrl(Prog*);
+void obj(Prog*);
+void follow(Prog*);
+Prog* gotochain(Prog*);
+int Xconv(Fmt*);
+int Rconv(Fmt*);
+int Qconv(Fmt*);
+int Dconv(Fmt*);
+int Cconv(Fmt*);
+void dumpexterns(void);
+void dumpfunct(Plist*);
+void dumpsignatures(void);
+void doframe(Dcl*, char*);
+void docall1(Prog*);
+void docall2(Prog*);
+void docalli2(Prog*);
+void docallm2(Prog*);
+void docallf2(Prog*);
+void docall3(Prog*);
+void doconv(Prog*);
+char* getfmt(int);
+void dumpmethods(void);
--- /dev/null
+// 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.
+
+/*
+todo:
+ 1. dyn arrays
+ 2. multi
+ 3. block 0
+tothinkabout:
+ 1. alias name name.name.name
+ 2. argument in import
+*/
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+enum
+{
+ NHUNK = 50000,
+ BUFSIZ = 8192,
+ NSYMB = 500,
+ NHASH = 1024,
+ STRINGSZ = 200,
+ YYMAXDEPTH = 500,
+ MAXALIGN = 7,
+ UINF = 100,
+
+ PRIME1 = 3,
+ PRIME2 = 10007,
+ PRIME3 = 10009,
+ PRIME4 = 10037,
+ PRIME5 = 10039,
+ PRIME6 = 10061,
+ PRIME7 = 10067,
+ PRIME8 = 10079,
+ PRIME9 = 10091,
+};
+
+/* note this is the representation
+ * of the compilers string literals,
+ * it happens to also be the runtime
+ * representation, but that may change */
+typedef struct String String;
+struct String
+{
+ long len;
+ uchar s[3]; // variable
+};
+
+typedef struct Val Val;
+struct Val
+{
+ int ctype;
+ double dval;
+ vlong vval;
+ String* sval;
+};
+
+typedef struct Sym Sym;
+typedef struct Node Node;
+struct Node
+{
+ int op;
+
+ // most nodes
+ Node* left;
+ Node* right;
+ Node* type;
+
+ // for-body
+ Node* ninit;
+ Node* ntest;
+ Node* nincr;
+ Node* nbody;
+
+ // if-body
+ Node* nelse;
+
+ // OTYPE-TFIELD
+ Node* down; // also used in TMAP
+ Node* uberstruct;
+
+ // cases
+ Node* ncase;
+
+ // OTYPE-TPTR
+ Node* nforw;
+
+ // OTYPE-TFUNCT
+ Node* this;
+ Node* argout;
+ Node* argin;
+ Node* nname;
+ int thistuple;
+ int outtuple;
+ int intuple;
+
+ // OTYPE-TARRAY
+ long bound;
+
+ // OLITERAL
+ Val val;
+
+ Sym* osym; // import
+ Sym* fsym; // import
+ Sym* psym; // import
+ Sym* sym; // various
+ uchar ullman; // sethi/ullman number
+ uchar addable; // type of addressability - 0 is not addressable
+ uchar recur; // to detect loops
+ uchar trecur; // to detect loops
+ uchar etype; // is an op for OASOP, is etype for OTYPE
+ uchar chan;
+ uchar kaka;
+ uchar multi; // type of assignment or call
+ long vargen; // unique name for OTYPE/ONAME
+ long lineno;
+};
+#define N ((Node*)0)
+
+struct Sym
+{
+ char* opackage; // original package name
+ char* package; // package name
+ char* name; // variable name
+ Node* oname; // ONAME node if a var
+ Node* otype; // OTYPE node if a type
+ Node* oconst; // OLITERAL node if a const
+ Node* forwtype; // OTYPE/TPTR iff foreward declared
+ void* label; // pointer to Prog* of label
+ long lexical;
+ long vargen; // unique variable number
+ uchar undef; // a diagnostic has been generated
+ uchar export; // marked as export
+ uchar exported; // has been exported
+ Sym* link;
+};
+#define S ((Sym*)0)
+
+typedef struct Dcl Dcl;
+struct Dcl
+{
+ int op; // ONAME for var, OTYPE for type, Oxxx for const
+ Sym* dsym; // for printing only
+ Node* dnode; // otype or oname
+ long lineno;
+
+ Dcl* forw;
+ Dcl* back; // sentinel has pointer to last
+};
+#define D ((Dcl*)0)
+
+typedef struct Iter Iter;
+struct Iter
+{
+ int done;
+ Node** an;
+ Node* n;
+};
+
+enum
+{
+ OXXX,
+
+ OTYPE, OCONST, OVAR, OEXPORT, OIMPORT,
+
+ ONAME,
+ ODOT, ODOTPTR, ODOTMETH, ODOTINTER,
+ ODCLFUNC, ODCLCONST, ODCLVAR,
+ ODCLTYPE, ODCLFIELD, ODCLARG,
+ OLIST,
+ OPTR, OARRAY,
+ ORETURN, OFOR, OIF, OSWITCH,
+ OAS, OASOP, OCOLAS, OCASE, OXCASE, OFALL, OXFALL,
+ OGOTO, OPROC, ONEW, OPANIC, OPRINT, OEMPTY,
+
+ OOROR,
+ OANDAND,
+ OEQ, ONE, OLT, OLE, OGE, OGT,
+ OADD, OSUB, OOR, OXOR, OCAT,
+ OMUL, ODIV, OMOD, OLSH, ORSH, OAND,
+ ODEC, OINC,
+ OLEN,
+ OFUNC,
+ OLABEL,
+ OBREAK,
+ OCONTINUE,
+ OADDR,
+ OIND,
+ OCALL, OCALLPTR, OCALLMETH, OCALLINTER,
+ OINDEX, OINDEXPTR, OINDEXSTR, OINDEXMAP, OINDEXPTRMAP,
+ OSLICE,
+ ONOT, OCOM, OPLUS, OMINUS, OSEND, ORECV,
+ OLITERAL,
+ OCONV,
+ OBAD,
+
+ OEND,
+};
+enum
+{
+ Txxx,
+
+ TINT8, TUINT8,
+ TINT16, TUINT16,
+ TINT32, TUINT32,
+ TINT64, TUINT64,
+
+ TFLOAT32,
+ TFLOAT64,
+ TFLOAT80,
+
+ TBOOL,
+
+ TPTR,
+ TFUNC,
+ TARRAY,
+ TDARRAY,
+ TSTRUCT,
+ TCHAN,
+ TMAP,
+ TINTER,
+ TFORW,
+ TFIELD,
+ TPOLY,
+ TSTRING,
+
+ NTYPE,
+};
+enum
+{
+ CTxxx,
+
+ CTINT,
+ CTSINT,
+ CTUINT,
+ CTFLT,
+
+ CTSTR,
+ CTBOOL,
+ CTNIL,
+};
+
+enum
+{
+ /* indications for whatis() */
+ Wnil = 0,
+ Wtnil,
+
+ Wtfloat,
+ Wtint,
+ Wtbool,
+ Wtstr,
+
+ Wlitfloat,
+ Wlitint,
+ Wlitbool,
+ Wlitstr,
+
+ Wtunkn,
+};
+
+enum
+{
+ /* types of channel */
+ Cxxx,
+ Cboth,
+ Crecv,
+ Csend,
+};
+
+enum
+{
+ Pxxx,
+
+ PEXTERN, // declaration context
+ PAUTO,
+
+ PCALL_NIL, // no return value
+ PCALL_SINGLE, // single return value
+ PCALL_MULTI, // multiple return values
+
+ PAS_SINGLE, // top level walk->gen hints for OAS
+ PAS_MULTI, // multiple values
+ PAS_CALLM, // multiple values from a call
+ PAS_STRUCT, // structure assignment
+};
+
+typedef struct Io Io;
+struct Io
+{
+ char* infile;
+ Biobuf* bin;
+ long lineno;
+ int peekc;
+};
+
+EXTERN Io curio;
+EXTERN Io pushedio;
+
+EXTERN char* outfile;
+EXTERN char* package;
+EXTERN Biobuf* bout;
+EXTERN int nerrors;
+EXTERN char namebuf[NSYMB];
+EXTERN char debug[256];
+EXTERN long dynlineno;
+EXTERN Sym* hash[NHASH];
+EXTERN Sym* dclstack;
+EXTERN Sym* b0stack;
+EXTERN Sym* pkgmyname; // my name for package
+
+EXTERN Node* types[NTYPE];
+EXTERN uchar isint[NTYPE];
+EXTERN uchar isfloat[NTYPE];
+EXTERN uchar okforeq[NTYPE];
+EXTERN uchar okforadd[NTYPE];
+EXTERN uchar okforand[NTYPE];
+EXTERN double minfloatval[NTYPE];
+EXTERN double maxfloatval[NTYPE];
+EXTERN vlong minintval[NTYPE];
+EXTERN vlong maxintval[NTYPE];
+
+EXTERN Dcl* autodcl;
+EXTERN Dcl* externdcl;
+EXTERN Dcl* exportlist;
+EXTERN int dclcontext; // PEXTERN/PAUTO
+EXTERN int importflag;
+
+EXTERN Node* booltrue;
+EXTERN Node* boolfalse;
+EXTERN ulong iota;
+EXTERN long vargen;
+EXTERN long exportgen;
+
+EXTERN Node* retnil;
+EXTERN Node* fskel;
+
+EXTERN char* context;
+EXTERN int thechar;
+EXTERN char* thestring;
+EXTERN char* hunk;
+EXTERN long nhunk;
+EXTERN long thunk;
+
+/*
+ * y.tab.c
+ */
+int yyparse(void);
+
+/*
+ * lex.c
+ */
+int main(int, char*[]);
+void importfile(Val*);
+void unimportfile();
+long yylex(void);
+void lexinit(void);
+char* lexname(int);
+long getr(void);
+int getnsc(void);
+long escchar(long, int*);
+int getc(void);
+void ungetc(int);
+void mkpackage(char*);
+
+/*
+ * mpatof.c
+ */
+int mpatof(char*, double*);
+int mpatov(char*, vlong*);
+
+/*
+ * subr.c
+ */
+void myexit(int);
+void* mal(long);
+void* remal(void*, long, long);
+void errorexit(void);
+ulong stringhash(char*);
+Sym* lookup(char*);
+Sym* pkglookup(char*, char*);
+void yyerror(char*, ...);
+void warn(char*, ...);
+void fatal(char*, ...);
+Node* nod(int, Node*, Node*);
+Dcl* dcl(void);
+Node* rev(Node*);
+Node* unrev(Node*);
+void dodump(Node*, int);
+void dump(char*, Node*);
+Node* aindex(Node*, Node*);
+int isptrto(Node*, int);
+int isinter(Node*);
+int isbytearray(Node*);
+int eqtype(Node*, Node*, int);
+ulong typehash(Node*, int);
+void frame(int);
+Node* literal(long);
+Node* dobad(void);
+void ullmancalc(Node*);
+void badtype(int, Node*, Node*);
+Node* ptrto(Node*);
+Node* cleanidlist(Node*);
+
+Node** getthis(Node*);
+Node** getoutarg(Node*);
+Node** getinarg(Node*);
+
+Node* getthisx(Node*);
+Node* getoutargx(Node*);
+Node* getinargx(Node*);
+
+Node* listfirst(Iter*, Node**);
+Node* listnext(Iter*);
+Node* structfirst(Iter*, Node**);
+Node* structnext(Iter*);
+
+int Econv(Fmt*);
+int Jconv(Fmt*);
+int Oconv(Fmt*);
+int Sconv(Fmt*);
+int Tconv(Fmt*);
+int Nconv(Fmt*);
+int Zconv(Fmt*);
+
+/*
+ * dcl.c
+ */
+void dodclvar(Node*, Node*);
+void dodcltype(Node*, Node*);
+void dodclconst(Node*, Node*);
+void defaultlit(Node*);
+int listcount(Node*);
+Node* functype(Node*, Node*, Node*);
+char* thistypenam(Node*);
+void funcnam(Node*, char*);
+void funchdr(Node*);
+void funcargs(Node*);
+void funcbody(Node*);
+Node* dostruct(Node*, int);
+Node** stotype(Node*, Node**, Node*);
+Node* sortinter(Node*);
+void markdcl(void);
+void popdcl(void);
+void markdclstack(void);
+Sym* pushdcl(Sym*);
+void addvar(Node*, Node*, int);
+void addtyp(Node*, Node*, int);
+Node* newname(Sym*);
+Node* oldname(Sym*);
+Node* newtype(Sym*);
+Node* oldtype(Sym*);
+Node* forwdcl(Sym*);
+
+/*
+ * export.c
+ */
+void markexport(Node*);
+void dumpe(Sym*);
+void dumpexport(void);
+void dumpexporttype(Sym*);
+void dumpexportvar(Sym*);
+void dumpexportconst(Sym*);
+void doimportv1(Node*, Node*);
+void doimportc1(Node*, Val*);
+void doimportc2(Node*, Node*, Val*);
+void doimport1(Node*, Node*, Node*);
+void doimport2(Node*, Val*, Node*);
+void doimport3(Node*, Node*);
+void doimport4(Node*, Node*);
+void doimport5(Node*, Val*);
+void doimport6(Node*, Node*);
+void doimport7(Node*, Node*);
+
+/*
+ * walk.c
+ */
+void walk(Node*);
+void walktype(Node*, int);
+Node* walkswitch(Node*, Node*, Node*(*)(Node*, Node*));
+int casebody(Node*);
+int whatis(Node*);
+void walkdot(Node*);
+void walkslice(Node*);
+void ascompatee(int, Node**, Node**);
+void ascompatet(int, Node**, Node**);
+void ascompatte(int, Node**, Node**);
+void ascompattt(int, Node**, Node**);
+int ascompat(Node*, Node*);
+void prcompat(Node**);
+
+/*
+ * const.c
+ */
+void convlit(Node*, Node*);
+void evconst(Node*);
+int cmpslit(Node *l, Node *r);
+
+/*
+ * gen.c/gsubr.c/obj.c
+ */
+void belexinit(int);
+vlong convvtox(vlong, int);
+void compile(Node*);
+void proglist(void);
+void dumpobj(void);
+int optopop(int);
--- /dev/null
+// 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"
+%}
+%union {
+ Node* node;
+ Sym* sym;
+ struct Val val;
+ int lint;
+}
+%token <sym> LNAME LBASETYPE LATYPE LANY LPACK LACONST
+%token <val> LLITERAL LASOP
+%token LPACKAGE LIMPORT LEXPORT
+%token LMAP LCHAN LINTERFACE LFUNC LSTRUCT
+%token LCOLAS LFALL LRETURN
+%token LNEW LLEN
+%token LVAR LTYPE LCONST LCONVERT
+%token LFOR LIF LELSE LSWITCH LCASE LDEFAULT
+%token LBREAK LCONTINUE LGO LGOTO LRANGE
+%token LOROR LANDAND LEQ LNE LLE LLT LGE LGT
+%token LLSH LRSH LINC LDEC
+%token LNIL LTRUE LFALSE LIOTA
+%token LPANIC LPRINT LIGNORE
+
+%type <sym> sym laconst lname latype
+%type <lint> chantype
+%type <node> xdcl xdcl_list_r oxdcl_list common_dcl
+%type <node> oarg_type_list arg_type_list_r arg_type
+%type <node> stmt empty_stmt else_stmt
+%type <node> complex_stmt compound_stmt stmt_list_r ostmt_list
+%type <node> for_stmt for_body for_header
+%type <node> if_stmt if_body if_header
+%type <node> range_header range_body range_stmt
+%type <node> simple_stmt osimple_stmt
+%type <node> expr uexpr pexpr expr_list oexpr oexpr_list expr_list_r
+%type <node> name name_name new_name new_name_list_r
+%type <node> type polytype
+%type <node> new_type
+%type <node> vardcl_list_r vardcl
+%type <node> constdcl_list_r constdcl
+%type <node> typedcl_list_r typedcl
+%type <node> interfacedcl_list_r interfacedcl
+%type <node> structdcl_list_r structdcl
+%type <node> export_list_r export
+%type <node> hidden_importsym_list_r ohidden_importsym_list hidden_importsym isym
+%type <node> hidden_importfield_list_r ohidden_importfield_list hidden_importfield
+%type <node> fntype fnbody fntypeh fnlitdcl intype
+%type <node> fnres fnliteral xfndcl fndcl
+%type <node> keyval_list_r keyval
+
+%left LOROR
+%left LANDAND
+%left LEQ LNE LLE LGE LLT LGT
+%left '+' '-' '|' '^'
+%left '*' '/' '%' '&' LLSH LRSH
+%%
+file:
+ package imports oxdcl_list
+ {
+ if(debug['f'])
+ frame(1);
+ }
+
+package:
+ {
+ yyerror("package statement must be first");
+ mkpackage("main");
+ }
+| LPACKAGE sym
+ {
+ mkpackage($2->name);
+ }
+
+imports:
+| imports import
+
+import:
+ LIMPORT import_stmt
+| LIMPORT '(' import_stmt_list_r osemi ')'
+
+import_stmt:
+ import_here import_there
+
+import_here:
+ LLITERAL
+ {
+ // import with original name
+ pkgmyname = S;
+ importfile(&$1);
+ }
+| sym LLITERAL
+ {
+ // import with given name
+ pkgmyname = $1;
+ pkgmyname->lexical = LPACK;
+ importfile(&$2);
+ }
+| '.' LLITERAL
+ {
+ // import with my name
+ pkgmyname = lookup(package);
+ importfile(&$2);
+ }
+
+import_there:
+ hidden_import_list_r ')' ')'
+ {
+ unimportfile();
+ }
+| LIMPORT '(' '(' hidden_import_list_r ')' ')'
+
+/*
+ * declarations
+ */
+xdcl:
+ common_dcl
+| LEXPORT export_list_r
+ {
+ markexport(rev($2));
+ }
+| LEXPORT '(' export_list_r ')'
+ {
+ markexport(rev($3));
+ }
+| xfndcl
+| ';'
+ {
+ $$ = N;
+ }
+
+common_dcl:
+ LVAR vardcl
+ {
+ $$ = $2;
+ }
+| LVAR '(' vardcl_list_r osemi ')'
+ {
+ $$ = rev($3);
+ }
+| LCONST constdcl
+ {
+ $$ = $2;
+ iota = 0;
+ }
+| LCONST '(' constdcl_list_r osemi ')'
+ {
+ $$ = rev($3);
+ iota = 0;
+ }
+| LTYPE typedcl
+ {
+ $$ = $2;
+ }
+| LTYPE '(' typedcl_list_r osemi ')'
+ {
+ $$ = rev($3);
+ }
+
+vardcl:
+ new_name_list_r type
+ {
+ $$ = rev($1);
+ dodclvar($$, $2);
+
+ $$ = nod(ODCLVAR, $$, N);
+ $$->type = $2;
+ }
+| new_name_list_r type '=' oexpr_list
+ {
+ $$ = rev($1);
+ dodclvar($$, $2);
+
+ $$ = nod(ODCLVAR, $$, $4);
+ $$->type = $2;
+ }
+| new_name '=' expr
+ {
+ walktype($3, 0); // this is a little harry
+ defaultlit($3);
+ dodclvar($1, $3->type);
+
+ $$ = nod(ODCLVAR, $1, $3);
+ $$->type = $3->type;
+ }
+
+constdcl:
+ new_name '=' expr
+ {
+ walktype($3, 0);
+ dodclconst($1, $3);
+
+ $$ = nod(ODCLCONST, $1, $3);
+ iota += 1;
+ }
+| new_name type '=' expr
+ {
+ walktype($4, 0);
+ convlit($4, $2);
+ dodclconst($1, $4);
+
+ $$ = nod(ODCLCONST, $1, $4);
+ iota += 1;
+ }
+
+typedcl:
+ new_type type
+ {
+ dodcltype($1, $2);
+
+ $$ = nod(ODCLTYPE, $1, N);
+ $$->type = $2;
+ }
+
+/*
+ * statements
+ */
+stmt:
+ error ';'
+ {
+ $$ = N;
+ context = nil;
+ }
+| common_dcl ';'
+ {
+ $$ = $1;
+ }
+| simple_stmt ';'
+| complex_stmt
+| compound_stmt
+| empty_stmt
+
+empty_stmt:
+ ';'
+ {
+ $$ = nod(OEMPTY, N, N);
+ }
+
+else_stmt:
+ stmt
+ {
+ $$ = $1;
+ switch($$->op) {
+ case OLABEL:
+ case OXCASE:
+ case OXFALL:
+ yyerror("statement cannot be labeled");
+ }
+ }
+
+simple_stmt:
+ expr
+ {
+ $$ = $1;
+ }
+| expr LINC
+ {
+ $$ = nod(OASOP, $1, literal(1));
+ $$->kaka = OADD;
+ }
+| expr LDEC
+ {
+ $$ = nod(OASOP, $1, literal(1));
+ $$->kaka = OSUB;
+ }
+| expr LASOP expr
+ {
+ $$ = nod(OASOP, $1, $3);
+ $$->kaka = $2.vval; // rathole to pass opcode
+ }
+| expr_list '=' expr_list
+ {
+ $$ = nod(OAS, $1, $3);
+ }
+| new_name LCOLAS expr
+ {
+ walktype($3, 0); // this is a little harry
+ defaultlit($3);
+ dodclvar($1, $3->type);
+ $$ = nod(OCOLAS, $1, $3);
+ }
+
+complex_stmt:
+ LFOR for_stmt
+ {
+ /* FOR and WHILE are the same keyword */
+ popdcl();
+ $$ = $2;
+ }
+| LSWITCH if_stmt
+ {
+ popdcl();
+ if(!casebody($2->nbody))
+ yyerror("switch statement must have case labels");
+ $$ = $2;
+ $$->op = OSWITCH;
+ }
+| LIF if_stmt
+ {
+ popdcl();
+ $$ = $2;
+ }
+| LIF if_stmt LELSE else_stmt
+ {
+ popdcl();
+ $$ = $2;
+ $$->nelse = $4;
+ }
+| LRANGE range_stmt
+ {
+ popdcl();
+ $$ = $2;
+ }
+| LRETURN oexpr_list ';'
+ {
+ $$ = nod(ORETURN, $2, N);
+ }
+| LCASE expr_list ':'
+ {
+ // will be converted to OCASE
+ // right will point to next case
+ // done in casebody()
+ popdcl();
+ markdcl();
+ $$ = nod(OXCASE, $2, N);
+ }
+| LDEFAULT ':'
+ {
+ popdcl();
+ markdcl();
+ $$ = nod(OXCASE, N, N);
+ }
+| LFALL ';'
+ {
+ // will be converted to OFALL
+ $$ = nod(OXFALL, N, N);
+ }
+| LBREAK oexpr ';'
+ {
+ $$ = nod(OBREAK, $2, N);
+ }
+| LCONTINUE oexpr ';'
+ {
+ $$ = nod(OCONTINUE, $2, N);
+ }
+| LGO pexpr '(' oexpr_list ')' ';'
+ {
+ $$ = nod(OPROC, $2, $4);
+ }
+| LPRINT expr_list ';'
+ {
+ $$ = nod(OPRINT, $2, N);
+ }
+| LPANIC oexpr_list ';'
+ {
+ $$ = nod(OPANIC, $2, N);
+ }
+| LGOTO new_name ';'
+ {
+ $$ = nod(OGOTO, $2, N);
+ }
+| new_name ':'
+ {
+ $$ = nod(OLABEL, $1, N);
+ }
+
+compound_stmt:
+ '{'
+ {
+ markdcl();
+ } ostmt_list '}'
+ {
+ $$ = $3;
+ if($$ == N)
+ $$ = nod(OEMPTY, N, N);
+ popdcl();
+ }
+
+for_header:
+ osimple_stmt ';' osimple_stmt ';' osimple_stmt
+ {
+ // init ; test ; incr
+ $$ = nod(OFOR, N, N);
+ $$->ninit = $1;
+ $$->ntest = $3;
+ $$->nincr = $5;
+ }
+| osimple_stmt
+ {
+ // test
+ $$ = nod(OFOR, N, N);
+ $$->ninit = N;
+ $$->ntest = $1;
+ $$->nincr = N;
+ }
+
+for_body:
+ for_header compound_stmt
+ {
+ $$ = $1;
+ $$->nbody = $2;
+ }
+
+for_stmt:
+ { markdcl(); } for_body
+ {
+ $$ = $2;
+ }
+
+if_header:
+ osimple_stmt
+ {
+ // test
+ $$ = nod(OIF, N, N);
+ $$->ninit = N;
+ $$->ntest = $1;
+ }
+| osimple_stmt ';' osimple_stmt
+ {
+ // init ; test
+ $$ = nod(OIF, N, N);
+ $$->ninit = $1;
+ $$->ntest = $3;
+ }
+
+if_body:
+ if_header compound_stmt
+ {
+ $$ = $1;
+ $$->nbody = $2;
+ }
+
+if_stmt:
+ { markdcl(); } if_body
+ {
+ $$ = $2;
+ }
+
+range_header:
+ new_name LCOLAS expr
+ {
+ $$ = N;
+ }
+| new_name ',' new_name LCOLAS expr
+ {
+ $$ = N;
+ }
+| new_name ',' new_name '=' expr
+ {
+ yyerror("range statement only allows := assignment");
+ $$ = N;
+ }
+
+range_body:
+ range_header compound_stmt
+ {
+ $$ = $1;
+ $$->nbody = $2;
+ }
+
+range_stmt:
+ { markdcl(); } range_body
+ {
+ $$ = $2;
+ }
+
+/*
+ * expressions
+ */
+expr:
+ uexpr
+| expr LOROR expr
+ {
+ $$ = nod(OOROR, $1, $3);
+ }
+| expr LANDAND expr
+ {
+ $$ = nod(OANDAND, $1, $3);
+ }
+| expr LEQ expr
+ {
+ $$ = nod(OEQ, $1, $3);
+ }
+| expr LNE expr
+ {
+ $$ = nod(ONE, $1, $3);
+ }
+| expr LLT expr
+ {
+ $$ = nod(OLT, $1, $3);
+ }
+| expr LLE expr
+ {
+ $$ = nod(OLE, $1, $3);
+ }
+| expr LGE expr
+ {
+ $$ = nod(OGE, $1, $3);
+ }
+| expr LGT expr
+ {
+ $$ = nod(OGT, $1, $3);
+ }
+| expr '+' expr
+ {
+ $$ = nod(OADD, $1, $3);
+ }
+| expr '-' expr
+ {
+ $$ = nod(OSUB, $1, $3);
+ }
+| expr '|' expr
+ {
+ $$ = nod(OOR, $1, $3);
+ }
+| expr '^' expr
+ {
+ $$ = nod(OXOR, $1, $3);
+ }
+| expr '*' expr
+ {
+ $$ = nod(OMUL, $1, $3);
+ }
+| expr '/' expr
+ {
+ $$ = nod(ODIV, $1, $3);
+ }
+| expr '%' expr
+ {
+ $$ = nod(OMOD, $1, $3);
+ }
+| expr '&' expr
+ {
+ $$ = nod(OAND, $1, $3);
+ }
+| expr LLSH expr
+ {
+ $$ = nod(OLSH, $1, $3);
+ }
+| expr LRSH expr
+ {
+ $$ = nod(ORSH, $1, $3);
+ }
+
+uexpr:
+ pexpr
+| LCONVERT '(' type ',' expr ')'
+ {
+ $$ = nod(OCONV, $5, N);
+ $$->type = $3;
+ }
+| '*' uexpr
+ {
+ $$ = nod(OIND, $2, N);
+ }
+| '&' uexpr
+ {
+ $$ = nod(OADDR, $2, N);
+ }
+| '+' uexpr
+ {
+ $$ = nod(OPLUS, $2, N);
+ }
+| '-' uexpr
+ {
+ $$ = nod(OMINUS, $2, N);
+ }
+| '!' uexpr
+ {
+ $$ = nod(ONOT, $2, N);
+ }
+| '~' uexpr
+ {
+ yyerror("the OCOM operator is ^");
+ $$ = nod(OCOM, $2, N);
+ }
+| '^' uexpr
+ {
+ $$ = nod(OCOM, $2, N);
+ }
+| LLT uexpr
+ {
+ $$ = nod(ORECV, $2, N);
+ }
+| LGT uexpr
+ {
+ $$ = nod(OSEND, $2, N);
+ }
+
+pexpr:
+ LLITERAL
+ {
+ $$ = nod(OLITERAL, N, N);
+ $$->val = $1;
+ }
+| laconst
+ {
+ $$ = nod(OLITERAL, N, N);
+ $$->val = $1->oconst->val;
+ $$->type = $1->oconst->type;
+ }
+| LNIL
+ {
+ $$ = nod(OLITERAL, N, N);
+ $$->val.ctype = CTNIL;
+ $$->val.vval = 0;
+ }
+| LTRUE
+ {
+ $$ = booltrue;
+ }
+| LFALSE
+ {
+ $$ = boolfalse;
+ }
+| LIOTA
+ {
+ $$ = literal(iota);
+ }
+| name
+| '(' expr ')'
+ {
+ $$ = $2;
+ }
+| pexpr '.' sym
+ {
+ $$ = nod(ODOT, $1, newname($3));
+ }
+| pexpr '[' expr ']'
+ {
+ $$ = nod(OINDEX, $1, $3);
+ }
+| pexpr '[' keyval ']'
+ {
+ $$ = nod(OSLICE, $1, $3);
+ }
+| pexpr '(' oexpr_list ')'
+ {
+ $$ = nod(OCALL, $1, $3);
+ }
+| LLEN '(' name ')'
+ {
+ $$ = nod(OLEN, $3, N);
+ }
+| LNEW '(' type ')'
+ {
+ $$ = nod(ONEW, N, N);
+ $$->type = ptrto($3);
+ }
+| fnliteral
+| '[' expr_list ']'
+ {
+ // array literal
+ $$ = N;
+ }
+| '[' keyval_list_r ']'
+ {
+ // map literal
+ $$ = N;
+ }
+| latype '(' oexpr_list ')'
+ {
+ // struct literal and conversions
+ $$ = nod(OCONV, $3, N);
+ $$->type = $1->otype;
+ }
+
+/*
+ * lexical symbols that can be
+ * from other packages
+ */
+lpack:
+ LPACK
+ {
+ context = $1->name;
+ }
+
+laconst:
+ LACONST
+| lpack '.' LACONST
+ {
+ $$ = $3;
+ context = nil;
+ }
+
+lname:
+ LNAME
+| lpack '.' LNAME
+ {
+ $$ = $3;
+ context = nil;
+ }
+
+latype:
+ LATYPE
+| lpack '.' LATYPE
+ {
+ $$ = $3;
+ context = nil;
+ }
+
+/*
+ * names and types
+ * newname is used before declared
+ * oldname is used after declared
+ */
+name_name:
+ LNAME
+ {
+ $$ = newname($1);
+ }
+
+new_name:
+ sym
+ {
+ $$ = newname($1);
+ }
+
+new_type:
+ sym
+ {
+ $$ = newtype($1);
+ }
+
+sym:
+ LATYPE
+| LNAME
+| LACONST
+| LPACK
+
+name:
+ lname
+ {
+ $$ = oldname($1);
+ }
+
+type:
+ latype
+ {
+ $$ = oldtype($1);
+ }
+| '[' oexpr ']' type
+ {
+ $$ = aindex($2, $4);
+ }
+| LCHAN chantype polytype
+ {
+ $$ = nod(OTYPE, N, N);
+ $$->etype = TCHAN;
+ $$->type = $3;
+ $$->chan = $2;
+ }
+| LMAP '[' type ']' polytype
+ {
+ $$ = nod(OTYPE, N, N);
+ $$->etype = TMAP;
+ $$->down = $3;
+ $$->type = $5;
+ }
+| LSTRUCT '{' structdcl_list_r osemi '}'
+ {
+ $$ = dostruct(rev($3), TSTRUCT);
+ }
+| LSTRUCT '{' '}'
+ {
+ $$ = dostruct(N, TSTRUCT);
+ }
+| LINTERFACE '{' interfacedcl_list_r osemi '}'
+ {
+ $$ = dostruct(rev($3), TINTER);
+ $$ = sortinter($$);
+ }
+| LINTERFACE '{' '}'
+ {
+ $$ = dostruct(N, TINTER);
+ }
+| fntypeh
+| '*' type
+ {
+ $$ = ptrto($2);
+ }
+| '*' lname
+ {
+ // dont know if this is an error or not
+ if(dclcontext != PEXTERN)
+ yyerror("foreward type in function body %s", $2->name);
+ $$ = forwdcl($2);
+ }
+
+polytype:
+ type
+| LANY
+ {
+ $$ = nod(OTYPE, N, N);
+ $$->etype = TPOLY;
+ }
+
+chantype:
+ {
+ $$ = Cboth;
+ }
+| LLT
+ {
+ $$ = Crecv;
+ }
+| LGT
+ {
+ $$ = Csend;
+ }
+
+keyval:
+ expr ':' expr
+ {
+ $$ = nod(OLIST, $1, $3);
+ }
+
+/*
+ * function stuff
+ * all in one place to show how crappy it all is
+ */
+xfndcl:
+ LFUNC fndcl fnbody
+ {
+ $$ = $2;
+ $$->nbody = $3;
+ funcbody($$);
+ }
+
+fndcl:
+ new_name '(' oarg_type_list ')' fnres
+ {
+ b0stack = dclstack; // mark base for fn literals
+ $$ = nod(ODCLFUNC, N, N);
+ $$->nname = $1;
+ $$->type = functype(N, $3, $5);
+ funchdr($$);
+ }
+| '(' oarg_type_list ')' new_name '(' oarg_type_list ')' fnres
+ {
+ b0stack = dclstack; // mark base for fn literals
+ if($2 == N || $2->op == OLIST)
+ yyerror("syntax error in method receiver");
+ $$ = nod(ODCLFUNC, N, N);
+ $$->nname = $4;
+ $$->type = functype($2, $6, $8);
+ funchdr($$);
+ }
+
+fntypeh:
+ LFUNC '(' oarg_type_list ')' fnres
+ {
+ $$ = functype(N, $3, $5);
+ funcnam($$, nil);
+ }
+/* i dont believe that this form is useful for nothing */
+| LFUNC '(' oarg_type_list ')' '.' '(' oarg_type_list ')' fnres
+ {
+ if($3 == N || $3->op == OLIST)
+ yyerror("syntax error in method receiver");
+ $$ = functype($3, $7, $9);
+ funcnam($$, nil);
+ }
+
+fntype:
+ fntypeh
+| latype
+ {
+ $$ = oldtype($1);
+ if($$ == N || $$->etype != TFUNC)
+ yyerror("illegal type for function literal");
+ }
+
+fnlitdcl:
+ fntype
+ {
+ markdclstack(); // save dcl stack and revert to block0
+ $$ = $1;
+ funcargs($$);
+ }
+
+fnliteral:
+ fnlitdcl '{' ostmt_list '}'
+ {
+ popdcl();
+
+ vargen++;
+ snprint(namebuf, sizeof(namebuf), "_f%.3ld", vargen);
+
+ $$ = newname(lookup(namebuf));
+ addvar($$, $1, PEXTERN);
+
+ {
+ Node *n;
+
+ n = nod(ODCLFUNC, N, N);
+ n->nname = $$;
+ n->type = $1;
+ n->nbody = $3;
+ if(n->nbody == N)
+ n->nbody = nod(ORETURN, N, N);
+ compile(n);
+ }
+
+ $$ = nod(OADDR, $$, N);
+ }
+
+fnbody:
+ compound_stmt
+ {
+ $$ = $1;
+ if($$->op == OEMPTY)
+ $$ = nod(ORETURN, N, N);
+ }
+| ';'
+ {
+ $$ = N;
+ }
+
+fnres:
+ {
+ $$ = N;
+ }
+| type
+ {
+ $$ = nod(ODCLFIELD, N, N);
+ $$->type = $1;
+ $$ = cleanidlist($$);
+ }
+| '(' oarg_type_list ')'
+ {
+ $$ = $2;
+ }
+
+/*
+ * lists of things
+ * note that they are left recursive
+ * to conserve yacc stack. they need to
+ * be reversed to interpret correctly
+ */
+xdcl_list_r:
+ xdcl
+| xdcl_list_r xdcl
+ {
+ $$ = nod(OLIST, $1, $2);
+ }
+
+vardcl_list_r:
+ vardcl
+| vardcl_list_r ';' vardcl
+ {
+ $$ = nod(OLIST, $1, $3);
+ }
+
+constdcl_list_r:
+ constdcl
+| constdcl_list_r ';' constdcl
+ {
+ $$ = nod(OLIST, $1, $3);
+ }
+
+typedcl_list_r:
+ typedcl
+| typedcl_list_r ';' typedcl
+ {
+ $$ = nod(OLIST, $1, $3);
+ }
+
+structdcl_list_r:
+ structdcl
+ {
+ $$ = cleanidlist($1);
+ }
+| structdcl_list_r ';' structdcl
+ {
+ $$ = cleanidlist($3);
+ $$ = nod(OLIST, $1, $$);
+ }
+
+interfacedcl_list_r:
+ interfacedcl
+ {
+ $$ = cleanidlist($1);
+ }
+| interfacedcl_list_r ';' interfacedcl
+ {
+ $$ = cleanidlist($3);
+ $$ = nod(OLIST, $1, $$);
+ }
+
+structdcl:
+ new_name ',' structdcl
+ {
+ $$ = nod(ODCLFIELD, $1, N);
+ $$ = nod(OLIST, $$, $3);
+ }
+| new_name type
+ {
+ $$ = nod(ODCLFIELD, $1, N);
+ $$->type = $2;
+ }
+
+interfacedcl:
+ new_name ',' interfacedcl
+ {
+ $$ = nod(ODCLFIELD, $1, N);
+ $$ = nod(OLIST, $$, $3);
+ }
+| new_name intype
+ {
+ $$ = nod(ODCLFIELD, $1, N);
+ $$->type = $2;
+ }
+
+intype:
+ '(' oarg_type_list ')' fnres
+ {
+ // without func keyword
+ $$ = functype(N, $2, $4);
+ funcnam($$, nil);
+ }
+| LFUNC '(' oarg_type_list ')' fnres
+ {
+ // with func keyword
+ $$ = functype(N, $3, $5);
+ funcnam($$, nil);
+ }
+| latype
+ {
+ $$ = oldtype($1);
+ if($$ == N || $$->etype != TFUNC)
+ yyerror("illegal type for function literal");
+ }
+
+arg_type:
+ name_name
+ {
+ $$ = nod(ODCLFIELD, $1, N);
+ }
+| type
+ {
+ $$ = nod(ODCLFIELD, N, N);
+ $$->type = $1;
+ }
+| new_name type
+ {
+ $$ = nod(ODCLFIELD, $1, N);
+ $$->type = $2;
+ }
+
+arg_type_list_r:
+ arg_type
+| arg_type_list_r ',' arg_type
+ {
+ $$ = nod(OLIST, $1, $3);
+ }
+
+stmt_list_r:
+ stmt
+ {
+ $$ = $1;
+ }
+| stmt_list_r stmt
+ {
+ $$ = nod(OLIST, $1, $2);
+ }
+
+expr_list_r:
+ expr
+| expr_list_r ',' expr
+ {
+ $$ = nod(OLIST, $1, $3);
+ }
+
+new_name_list_r:
+ new_name
+| new_name_list_r ',' new_name
+ {
+ $$ = nod(OLIST, $1, $3);
+ }
+
+export_list_r:
+ export
+| export_list_r ocomma export
+ {
+ $$ = nod(OLIST, $1, $3);
+ }
+
+export:
+ sym
+ {
+ $$ = nod(OEXPORT, N, N);
+ $$->sym = $1;
+ }
+| sym '.' sym
+ {
+ $$ = nod(OEXPORT, N, N);
+ $$->psym = $1;
+ $$->sym = $3;
+ }
+
+import_stmt_list_r:
+ import_stmt
+| import_stmt_list_r osemi import_stmt
+
+hidden_import_list_r:
+ hidden_import
+| hidden_import_list_r hidden_import
+
+hidden_importsym_list_r:
+ hidden_importsym
+| hidden_importsym_list_r hidden_importsym
+ {
+ $$ = nod(OLIST, $1, $2);
+ }
+
+hidden_importfield_list_r:
+ hidden_importfield
+| hidden_importfield_list_r hidden_importfield
+ {
+ $$ = nod(OLIST, $1, $2);
+ }
+
+keyval_list_r:
+ keyval
+| keyval_list_r ',' keyval
+ {
+ $$ = nod(OLIST, $1, $3);
+ }
+
+/*
+ * the one compromise of a
+ * non-reversed list
+ */
+expr_list:
+ expr_list_r
+ {
+ $$ = rev($1);
+ }
+
+/*
+ * optional things
+ */
+osemi:
+| ';'
+
+ocomma:
+| ','
+
+oexpr:
+ {
+ $$ = N;
+ }
+| expr
+
+oexpr_list:
+ {
+ $$ = N;
+ }
+| expr_list
+
+osimple_stmt:
+ {
+ $$ = N;
+ }
+| simple_stmt
+
+ostmt_list:
+ {
+ $$ = N;
+ }
+| stmt_list_r
+ {
+ $$ = rev($1);
+ }
+
+oxdcl_list:
+ {
+ $$ = N;
+ }
+| xdcl_list_r
+ {
+ $$ = rev($1);
+ }
+
+ohidden_importsym_list:
+ {
+ $$ = N;
+ }
+| hidden_importsym_list_r
+ {
+ $$ = rev($1);
+ }
+
+ohidden_importfield_list:
+ {
+ $$ = N;
+ }
+| hidden_importfield_list_r
+ {
+ $$ = rev($1);
+ }
+
+oarg_type_list:
+ {
+ $$ = N;
+ }
+| arg_type_list_r
+ {
+ $$ = cleanidlist(rev($1));
+ }
+
+/*
+ * import syntax from header of
+ * an output package
+ */
+hidden_import:
+ /* variables */
+ LVAR hidden_importsym hidden_importsym
+ {
+ // var
+ doimportv1($2, $3);
+ }
+
+ /* constants */
+| LCONST hidden_importsym LLITERAL
+ {
+ doimportc1($2, &$3);
+ }
+| LCONST hidden_importsym hidden_importsym LLITERAL
+ {
+ doimportc2($2, $3, &$4);
+ }
+
+ /* types */
+| LTYPE hidden_importsym '[' hidden_importsym ']' hidden_importsym
+ {
+ // type map
+ doimport1($2, $4, $6);
+ }
+| LTYPE hidden_importsym '[' LLITERAL ']' hidden_importsym
+ {
+ // type array
+ doimport2($2, &$4, $6);
+ }
+| LTYPE hidden_importsym '(' ohidden_importsym_list ')'
+ {
+ // type function
+ doimport3($2, $4);
+ }
+| LTYPE hidden_importsym '{' ohidden_importfield_list '}'
+ {
+ // type structure
+ doimport4($2, $4);
+ }
+| LTYPE hidden_importsym LLITERAL
+ {
+ // type basic
+ doimport5($2, &$3);
+ }
+| LTYPE hidden_importsym '*' hidden_importsym
+ {
+ // type pointer
+ doimport6($2, $4);
+ }
+| LTYPE hidden_importsym LLT ohidden_importfield_list LGT
+ {
+ // type interface
+ doimport7($2, $4);
+ }
+
+isym:
+ sym '.' sym
+ {
+ $$ = nod(OIMPORT, N, N);
+ $$->osym = $1;
+ $$->psym = $1;
+ $$->sym = $3;
+ }
+| '(' sym ')' sym '.' sym
+ {
+ $$ = nod(OIMPORT, N, N);
+ $$->osym = $2;
+ $$->psym = $4;
+ $$->sym = $6;
+ }
+
+hidden_importsym:
+ isym
+| '!' isym
+ {
+ $$ = $2;
+ $$->kaka = 1;
+ }
+
+hidden_importfield:
+ sym isym
+ {
+ $$ = $2;
+ $$->fsym = $1;
+ }
--- /dev/null
+// 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 "gen.h"
+
+Prog*
+gbranch(int op, Node *t)
+{
+ Prog *p;
+
+ p = prog(op);
+ p->addr.type = ABRANCH;
+ p->pt = conv2pt(t);
+ return p;
+}
+
+Prog*
+gopcode(int op, int pt, Node *n)
+{
+ Prog *p;
+
+ p = prog(op);
+ p->pt = pt;
+ p->addr.node = n;
+ if(n == N) {
+ p->addr.type = ANONE;
+ return p;
+ }
+ if(n->op == OTYPE) {
+ p->pt1 = conv2pt(n);
+ p->addr.type = ANONE;
+ return p;
+ }
+ p->addr.type = ANODE;
+// p->param = n->param;
+ return p;
+}
+
+Prog*
+gopcodet(int op, Node *t, Node *n)
+{
+ return gopcode(op, conv2pt(t), n);
+}
+
+void
+gaddoffset(Node *n)
+{
+ Prog *p;
+
+ if(n == N || n->op != ONAME || n->sym == S)
+ goto bad;
+ p = gopcode(PADDO, PTADDR, n);
+ return;
+
+bad:
+ fatal("gaddoffset: %N", n);
+
+}
+
+void
+gconv(int t1, int t2)
+{
+ Prog *p;
+
+ p = gopcode(PCONV, t1, N);
+ p->pt1 = t2;
+}
+
+int
+conv2pt(Node *t)
+{
+ if(t == N)
+ return PTxxx;
+ switch(t->etype) {
+ case TPTR:
+ t = t->type;
+ if(t == N)
+ return PTERROR;
+ switch(t->etype) {
+ case PTSTRING:
+ case PTCHAN:
+ case PTMAP:
+ return t->etype;
+ }
+ return TPTR;
+ }
+ return t->etype;
+}
+
+void
+patch(Prog *p, Prog *to)
+{
+ if(p->addr.type != ABRANCH)
+ yyerror("patch: not a branch");
+ p->addr.branch = to;
+}
+
+Prog*
+prog(int as)
+{
+ Prog *p;
+
+ p = pc;
+ pc = mal(sizeof(*pc));
+
+ pc->op = PEND;
+ pc->addr.type = ANONE;
+ pc->loc = p->loc+1;
+
+ p->op = as;
+ p->lineno = dynlineno;
+ p->link = pc;
+ return p;
+}
+
+void
+proglist(void)
+{
+ Prog *p;
+
+ print("--- prog list ---\n");
+ for(p=firstpc; p!=P; p=p->link)
+ print("%P\n", p);
+}
+
+char* ptnames[] =
+{
+ [PTxxx] = "",
+ [PTINT8] = "I8",
+ [PTUINT8] = "U8",
+ [PTINT16] = "I16",
+ [PTUINT16] = "U16",
+ [PTINT32] = "I32",
+ [PTUINT32] = "U32",
+ [PTINT64] = "I64",
+ [PTUINT64] = "U64",
+ [PTFLOAT32] = "F32",
+ [PTFLOAT64] = "F64",
+ [PTFLOAT80] = "F80",
+ [PTBOOL] = "B",
+ [PTPTR] = "P",
+ [PTADDR] = "A",
+ [PTINTER] = "I",
+ [PTNIL] = "N",
+ [PTSTRUCT] = "S",
+ [PTSTRING] = "Z",
+ [PTCHAN] = "C",
+ [PTMAP] = "M",
+ [PTERROR] = "?",
+};
+
+int
+Xconv(Fmt *fp)
+{
+ char buf[100];
+ int pt;
+
+ pt = va_arg(fp->args, int);
+ if(pt < 0 || pt >= nelem(ptnames) || ptnames[pt] == nil) {
+ snprint(buf, sizeof(buf), "PT(%d)", pt);
+ return fmtstrcpy(fp, buf);
+ }
+ return fmtstrcpy(fp, ptnames[pt]);
+}
+
+int
+Qconv(Fmt *fp)
+{
+ char buf[100];
+ int pt;
+
+ pt = va_arg(fp->args, int);
+ if(pt == PTADDR)
+ pt = PTPTR;
+ snprint(buf, sizeof(buf), "_T_%X", pt);
+ return fmtstrcpy(fp, buf);
+}
+
+int
+Rconv(Fmt *fp)
+{
+ char buf[100];
+ int pt;
+
+ pt = va_arg(fp->args, int);
+ if(pt == PTADDR)
+ snprint(buf, sizeof(buf), "_R_%X", pt);
+ else
+ snprint(buf, sizeof(buf), "_U._R_%X", pt);
+ return fmtstrcpy(fp, buf);
+}
+
+/*
+s%[ ]*%%g
+s%(\/\*.*)*%%g
+s%,%\n%g
+s%\n+%\n%g
+s%(=0)*%%g
+s%^P(.+)% [P\1] = "\1",%g
+s%^ ........*\] =%&~%g
+s% =~%=%g
+*/
+
+static char*
+pnames[] =
+{
+ [PXXX] = "XXX",
+ [PERROR] = "ERROR",
+ [PPANIC] = "PANIC",
+ [PPRINT] = "PRINT",
+ [PGOTO] = "GOTO",
+ [PGOTOX] = "GOTOX",
+ [PCMP] = "CMP",
+ [PNEW] = "NEW",
+ [PLEN] = "LEN",
+ [PTEST] = "TEST",
+ [PCALL1] = "CALL1",
+ [PCALL2] = "CALL2",
+ [PCALLI2] = "CALLI2",
+ [PCALLM2] = "CALLM2",
+ [PCALLF2] = "CALLF2",
+ [PCALL3] = "CALL3",
+ [PRETURN] = "RETURN",
+ [PBEQ] = "BEQ",
+ [PBNE] = "BNE",
+ [PBLT] = "BLT",
+ [PBLE] = "BLE",
+ [PBGE] = "BGE",
+ [PBGT] = "BGT",
+ [PBTRUE] = "BTRUE",
+ [PBFALSE] = "BFALSE",
+ [PLOAD] = "LOAD",
+ [PLOADI] = "LOADI",
+ [PSTORE] = "STORE",
+ [PSTOREI] = "STOREI",
+ [PSTOREZ] = "STOREZ",
+ [PCONV] = "CONV",
+ [PADDR] = "ADDR",
+ [PADDO] = "ADDO",
+ [PINDEX] = "INDEX",
+ [PINDEXZ] = "INDEXZ",
+ [PCAT] = "CAT",
+ [PADD] = "ADD",
+ [PSUB] = "SUB",
+ [PSLICE] = "SLICE",
+ [PMUL] = "MUL",
+ [PDIV] = "DIV",
+ [PLSH] = "LSH",
+ [PRSH] = "RSH",
+ [PMOD] = "MOD",
+ [PMINUS] = "MINUS",
+ [PCOM] = "COM",
+ [PAND] = "AND",
+ [POR] = "OR",
+ [PXOR] = "XOR",
+ [PEND] = "END",
+};
+
+int
+Aconv(Fmt *fp)
+{
+ char buf[100], buf1[100];
+ Prog *p;
+ int o;
+
+ p = va_arg(fp->args, Prog*);
+ if(p == P) {
+ snprint(buf, sizeof(buf), "<P>");
+ goto ret;
+ }
+
+ o = p->op;
+ if(o < 0 || o >= nelem(pnames) || pnames[o] == nil)
+ snprint(buf, sizeof(buf), "(A%d)", o);
+ else
+ snprint(buf, sizeof(buf), "%s", pnames[o]);
+
+ o = p->pt;
+ if(o != PTxxx) {
+ snprint(buf1, sizeof(buf1), "-%X", o);
+ strncat(buf, buf1, sizeof(buf));
+ }
+
+ o = p->pt1;
+ if(o != PTxxx) {
+ snprint(buf1, sizeof(buf1), "-%X", o);
+ strncat(buf, buf1, sizeof(buf));
+ }
+
+ret:
+ return fmtstrcpy(fp, buf);
+}
+
+int
+Pconv(Fmt *fp)
+{
+ char buf[500], buf1[500];
+ Prog *p;
+
+ p = va_arg(fp->args, Prog*);
+ snprint(buf1, sizeof(buf1), "%4ld %4ld %-9A", p->loc, p->lineno, p);
+
+ switch(p->addr.type) {
+ default:
+ snprint(buf, sizeof(buf), "?%d", p->addr.type);
+ break;
+
+ case ANONE:
+ goto out;
+
+ case ANODE:
+ snprint(buf, sizeof(buf), "%N", p->addr.node);
+ break;
+
+ case ABRANCH:
+ if(p->addr.branch == P) {
+ snprint(buf, sizeof(buf), "<nil>");
+ break;
+ }
+ snprint(buf, sizeof(buf), "%ld", p->addr.branch->loc);
+ break;
+ }
+
+ strncat(buf1, " ", sizeof(buf1));
+ strncat(buf1, buf, sizeof(buf1));
+
+out:
+ return fmtstrcpy(fp, buf1);
+}
+
+static char*
+typedefs[] =
+{
+ "int", "int32",
+ "uint", "uint32",
+ "rune", "uint32",
+ "short", "int16",
+ "ushort", "uint16",
+ "long", "int32",
+ "ulong", "uint32",
+ "vlong", "int64",
+ "uvlong", "uint64",
+ "float", "float32",
+ "double", "float64",
+
+};
+
+void
+belexinit(int lextype)
+{
+ int i;
+ Sym *s0, *s1;
+
+ for(i=0; i<nelem(typedefs); i+=2) {
+ s1 = lookup(typedefs[i+1]);
+ if(s1->lexical != lextype)
+ yyerror("need %s to define %s",
+ typedefs[i+1], typedefs[i+0]);
+ s0 = lookup(typedefs[i+0]);
+ s0->lexical = s1->lexical;
+ s0->otype = s1->otype;
+ }
+
+ fmtinstall('A', Aconv); // asm opcodes
+ fmtinstall('P', Pconv); // asm instruction
+ fmtinstall('R', Rconv); // interpreted register
+ fmtinstall('Q', Qconv); // interpreted etype
+ fmtinstall('X', Xconv); // interpreted etype
+
+ fmtinstall('D', Dconv); // addressed operand
+ fmtinstall('C', Cconv); // C type
+}
+
+vlong
+convvtox(vlong v, int et)
+{
+ /* botch - do truncation conversion when energetic */
+ return v;
+}
+
+/*
+ * return !(op)
+ * eg == <=> !=
+ */
+int
+brcom(int a)
+{
+ switch(a) {
+ case PBEQ: return PBNE;
+ case PBNE: return PBEQ;
+ case PBLT: return PBGE;
+ case PBGT: return PBLE;
+ case PBLE: return PBGT;
+ case PBGE: return PBLT;
+ case PBTRUE: return PBFALSE;
+ case PBFALSE: return PBTRUE;
+ }
+ fatal("brcom: no com for %A\n", a);
+ return PERROR;
+}
+
+/*
+ * return reverse(op)
+ * eg a op b <=> b r(op) a
+ */
+int
+brrev(int a)
+{
+ switch(a) {
+ case PBEQ: return PBEQ;
+ case PBNE: return PBNE;
+ case PBLT: return PBGT;
+ case PBGT: return PBLT;
+ case PBLE: return PBGE;
+ case PBGE: return PBLE;
+ }
+ fatal("brcom: no rev for %A\n", a);
+ return PERROR;
+}
+
+/*
+ * codegen the address of the ith
+ * element in the jth argument.
+ */
+void
+fnparam(Node *t, int j, int i)
+{
+ Node *a, *f;
+
+ switch(j) {
+ default:
+ fatal("fnparam: bad j");
+ case 0:
+ a = getthisx(t);
+ break;
+ case 1:
+ a = getoutargx(t);
+ break;
+ case 2:
+ a = getinargx(t);
+ break;
+ }
+
+ f = a->type;
+ while(i > 0) {
+ f = f->down;
+ i--;
+ }
+ if(f->etype != TFIELD)
+ fatal("fnparam: not field");
+
+ gopcode(PLOAD, PTADDR, a->nname);
+ gopcode(PADDO, PTADDR, f->nname);
+}
+
+Sig*
+lsort(Sig *l, int(*f)(Sig*, Sig*))
+{
+ Sig *l1, *l2, *le;
+
+ if(l == 0 || l->link == 0)
+ return l;
+
+ l1 = l;
+ l2 = l;
+ for(;;) {
+ l2 = l2->link;
+ if(l2 == 0)
+ break;
+ l2 = l2->link;
+ if(l2 == 0)
+ break;
+ l1 = l1->link;
+ }
+
+ l2 = l1->link;
+ l1->link = 0;
+ l1 = lsort(l, f);
+ l2 = lsort(l2, f);
+
+ /* set up lead element */
+ if((*f)(l1, l2) < 0) {
+ l = l1;
+ l1 = l1->link;
+ } else {
+ l = l2;
+ l2 = l2->link;
+ }
+ le = l;
+
+ for(;;) {
+ if(l1 == 0) {
+ while(l2) {
+ le->link = l2;
+ le = l2;
+ l2 = l2->link;
+ }
+ le->link = 0;
+ break;
+ }
+ if(l2 == 0) {
+ while(l1) {
+ le->link = l1;
+ le = l1;
+ l1 = l1->link;
+ }
+ break;
+ }
+ if((*f)(l1, l2) < 0) {
+ le->link = l1;
+ le = l1;
+ l1 = l1->link;
+ } else {
+ le->link = l2;
+ le = l2;
+ l2 = l2->link;
+ }
+ }
+ le->link = 0;
+ return l;
+}
--- /dev/null
+// 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.
+
+
+#define EXTERN
+#include "go.h"
+#include "y.tab.h"
+
+#define DBG if(!debug['x']);else print
+enum
+{
+ EOF = -1,
+};
+
+int
+main(int argc, char *argv[])
+{
+ int c;
+
+ outfile = nil;
+ package = "____";
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 && c < sizeof(debug))
+ debug[c]++;
+ break;
+
+ case 'o':
+ outfile = ARGF();
+ break;
+
+ case 'k':
+ package = ARGF();
+ break;
+ } ARGEND
+
+ if(argc != 1)
+ goto usage;
+
+ fmtinstall('O', Oconv); // node opcodes
+ fmtinstall('E', Econv); // etype opcodes
+ fmtinstall('J', Jconv); // all the node flags
+ fmtinstall('S', Sconv); // sym pointer
+ fmtinstall('T', Tconv); // type pointer
+ fmtinstall('N', Nconv); // node pointer
+ fmtinstall('Z', Zconv); // escaped string
+ lexinit();
+
+ curio.infile = argv[0];
+
+ curio.bin = Bopen(curio.infile, OREAD);
+ if(curio.bin == nil)
+ fatal("cant open: %s", curio.infile);
+
+ externdcl = mal(sizeof(*externdcl));
+ externdcl->back = externdcl;
+ dclcontext = PEXTERN;
+
+ exportlist = mal(sizeof(*exportlist));
+ exportlist->back = exportlist;
+
+ // function field skeleton
+ fskel = nod(OLIST, N, nod(OLIST, N, N));
+ fskel->left = nod(ODCLFIELD, N, N);
+ fskel->right->left = nod(ODCLFIELD, N, N);
+ fskel->right->right = nod(ODCLFIELD, N, N);
+
+ curio.peekc = 0;
+ curio.lineno = 1;
+ nerrors = 0;
+ yyparse();
+ if(nerrors == 0) {
+ dumpobj();
+ }
+
+ Bterm(curio.bin);
+ if(bout != nil)
+ Bterm(bout);
+
+ if(nerrors)
+ errorexit();
+
+ myexit(0);
+ return 0;
+
+usage:
+ print("flags:\n");
+ print(" -d print declarations\n");
+ print(" -f print stack frame structure\n");
+ print(" -k name specify package name\n");
+ print(" -o file specify output file\n");
+ print(" -p print the assembly language\n");
+ print(" -w print the parse tree after typing\n");
+ print(" -x print lex tokens\n");
+ print(" -h panic on an error\n");
+ myexit(0);
+ return 0;
+}
+
+void
+importfile(Val *f)
+{
+ Biobuf *imp;
+ long c;
+
+ if(f->ctype != CTSTR) {
+ yyerror("import statement not a string");
+ return;
+ }
+ snprint(namebuf, sizeof(namebuf), "%Z.go.c", f->sval);
+
+ imp = Bopen(namebuf, OREAD);
+ if(imp == nil) {
+ yyerror("cant open import: %s", namebuf);
+ return;
+ }
+
+ /*
+ * position the input right
+ * after (( and return
+ */
+ pushedio = curio;
+ curio.bin = imp;
+ curio.lineno = 1;
+ curio.peekc = 0;
+ curio.infile = strdup(namebuf);
+ for(;;) {
+ c = getc();
+ if(c == EOF)
+ break;
+ if(c != '(')
+ continue;
+ c = getc();
+ if(c == EOF)
+ break;
+ if(c != '(')
+ continue;
+ return;
+ }
+ yyerror("no import in: %Z", f->sval);
+ unimportfile();
+}
+
+void
+unimportfile(void)
+{
+ if(curio.bin != nil && pushedio.bin != nil) {
+ Bterm(curio.bin);
+ curio = pushedio;
+ pushedio.bin = nil;
+ }
+}
+
+long
+yylex(void)
+{
+ long c, c1;
+ char *cp;
+ Rune rune;
+ int escflag;
+ Sym *s;
+
+l0:
+ c = getc();
+ if(isspace(c))
+ goto l0;
+
+ if(c >= Runeself) {
+ /* all multibyte runes are alpha */
+ cp = namebuf;
+ goto talph;
+ }
+
+ if(isalpha(c)) {
+ cp = namebuf;
+ goto talph;
+ }
+
+ if(isdigit(c))
+ goto tnum;
+
+ switch(c) {
+ case EOF:
+ ungetc(EOF);
+ return -1;
+
+ case '_':
+ cp = namebuf;
+ goto talph;
+
+ case '.':
+ c1 = getc();
+ if(isdigit(c1)) {
+ cp = namebuf;
+ *cp++ = c;
+ c = c1;
+ c1 = 0;
+ goto casedot;
+ }
+ break;
+
+ case '"':
+ /* "..." */
+ strcpy(namebuf, "\"<string>\"");
+ cp = mal(sizeof(long));
+ c1 = 4;
+
+ caseq:
+ for(;;) {
+ c = escchar('"', &escflag);
+ if(c == EOF)
+ break;
+ if(escflag) {
+ cp = remal(cp, c1, 1);
+ cp[c1++] = c;
+ } else {
+ rune = c;
+ c = runelen(rune);
+ cp = remal(cp, c1, c);
+ runetochar(cp+c1, &rune);
+ c1 += c;
+ }
+ }
+ goto catem;
+
+ case '`':
+ /* `...` */
+ strcpy(namebuf, "`<string>`");
+ cp = mal(sizeof(long));
+ c1 = 4;
+
+ casebq:
+ for(;;) {
+ c = getc();
+ if(c == EOF || c == '`')
+ break;
+ cp = remal(cp, c1, 1);
+ cp[c1++] = c;
+ }
+
+ catem:
+ for(;;) {
+ /* it takes 2 peekc's to skip comments */
+ c = getc();
+ if(isspace(c))
+ continue;
+ if(c == '"')
+ goto caseq;
+ if(c == '`')
+ goto casebq;
+ ungetc(c);
+ break;
+ }
+
+ *(long*)cp = c1-4; // length
+ do {
+ cp = remal(cp, c1, 1);
+ cp[c1++] = 0;
+ } while(c1 & MAXALIGN);
+ yylval.val.sval = (String*)cp;
+ yylval.val.ctype = CTSTR;
+ DBG("lex: string literal\n");
+ return LLITERAL;
+
+ case '\'':
+ /* '.' */
+ c = escchar('\'', &escflag);
+ if(c == EOF)
+ c = '\'';
+ c1 = escchar('\'', &escflag);
+ if(c1 != EOF) {
+ yyerror("missing '");
+ ungetc(c1);
+ }
+ yylval.val.vval = c;
+ yylval.val.ctype = CTINT;
+ DBG("lex: codepoint literal\n");
+ return LLITERAL;
+
+ case '/':
+ c1 = getc();
+ if(c1 == '*') {
+ for(;;) {
+ c = getr();
+ while(c == '*') {
+ c = getr();
+ if(c == '/')
+ goto l0;
+ }
+ if(c == EOF) {
+ yyerror("eof in comment");
+ errorexit();
+ }
+ }
+ }
+ if(c1 == '/') {
+ for(;;) {
+ c = getr();
+ if(c == '\n')
+ goto l0;
+ if(c == EOF) {
+ yyerror("eof in comment");
+ errorexit();
+ }
+ }
+ }
+ if(c1 == '=') {
+ c = ODIV;
+ goto asop;
+ }
+ break;
+
+ case ':':
+ c1 = getc();
+ if(c1 == '=') {
+ c = LCOLAS;
+ goto lx;
+ }
+ break;
+
+ case '*':
+ c1 = getc();
+ if(c1 == '=') {
+ c = OMUL;
+ goto asop;
+ }
+ break;
+
+ case '%':
+ c1 = getc();
+ if(c1 == '=') {
+ c = OMOD;
+ goto asop;
+ }
+ break;
+
+ case '+':
+ c1 = getc();
+ if(c1 == '+') {
+ c = LINC;
+ goto lx;
+ }
+ if(c1 == '=') {
+ c = OADD;
+ goto asop;
+ }
+ break;
+
+ case '-':
+ c1 = getc();
+ if(c1 == '-') {
+ c = LDEC;
+ goto lx;
+ }
+ if(c1 == '=') {
+ c = OSUB;
+ goto asop;
+ }
+ break;
+
+ case '>':
+ c1 = getc();
+ if(c1 == '>') {
+ c = LRSH;
+ c1 = getc();
+ if(c1 == '=') {
+ c = ORSH;
+ goto asop;
+ }
+ break;
+ }
+ if(c1 == '=') {
+ c = LGE;
+ goto lx;
+ }
+ c = LGT;
+ break;
+
+ case '<':
+ c1 = getc();
+ if(c1 == '<') {
+ c = LLSH;
+ c1 = getc();
+ if(c1 == '=') {
+ c = OLSH;
+ goto asop;
+ }
+ break;
+ }
+ if(c1 == '=') {
+ c = LLE;
+ goto lx;
+ }
+ c = LLT;
+ break;
+
+ case '=':
+ c1 = getc();
+ if(c1 == '=') {
+ c = LEQ;
+ goto lx;
+ }
+ break;
+
+ case '!':
+ c1 = getc();
+ if(c1 == '=') {
+ c = LNE;
+ goto lx;
+ }
+ break;
+
+ case '&':
+ c1 = getc();
+ if(c1 == '&') {
+ c = LANDAND;
+ goto lx;
+ }
+ if(c1 == '=') {
+ c = OAND;
+ goto asop;
+ }
+ break;
+
+ case '|':
+ c1 = getc();
+ if(c1 == '|') {
+ c = LOROR;
+ goto lx;
+ }
+ if(c1 == '=') {
+ c = OOR;
+ goto asop;
+ }
+ break;
+
+ case '^':
+ c1 = getc();
+ if(c1 == '=') {
+ c = OXOR;
+ goto asop;
+ }
+ break;
+
+ default:
+ goto lx;
+ }
+ ungetc(c1);
+
+lx:
+ if(c > 0xff)
+ DBG("lex: TOKEN %s\n", lexname(c));
+ else
+ DBG("lex: TOKEN '%c'\n", c);
+ return c;
+
+asop:
+ yylval.val.vval = c; // rathole to hold which asop
+ DBG("lex: TOKEN ASOP %c\n", c);
+ return LASOP;
+
+talph:
+ /*
+ * cp is set to namebuf and some
+ * prefix has been stored
+ */
+ for(;;) {
+ if(c >= Runeself) {
+ for(c1=0;;) {
+ cp[c1++] = c;
+ if(fullrune(cp, c1))
+ break;
+ c = getc();
+ }
+ cp += c1;
+ c = getc();
+ continue;
+ }
+ if(!isalnum(c) && c != '_')
+ break;
+ *cp++ = c;
+ c = getc();
+ }
+ *cp = 0;
+ ungetc(c);
+
+ s = lookup(namebuf);
+ if(s->lexical == LIGNORE)
+ goto l0;
+
+ if(context != nil) {
+ s = pkglookup(s->name, context);
+ if(s->lexical == LIGNORE)
+ goto l0;
+ }
+
+ DBG("lex: %S %s\n", s, lexname(s->lexical));
+ yylval.sym = s;
+ if(s->lexical == LBASETYPE)
+ return LATYPE;
+ return s->lexical;
+
+tnum:
+ c1 = 0;
+ cp = namebuf;
+ if(c != '0') {
+ for(;;) {
+ *cp++ = c;
+ c = getc();
+ if(isdigit(c))
+ continue;
+ goto dc;
+ }
+ }
+ *cp++ = c;
+ c = getc();
+ if(c == 'x' || c == 'X')
+ for(;;) {
+ *cp++ = c;
+ c = getc();
+ if(isdigit(c))
+ continue;
+ if(c >= 'a' && c <= 'f')
+ continue;
+ if(c >= 'A' && c <= 'F')
+ continue;
+ if(cp == namebuf+2)
+ yyerror("malformed hex constant");
+ goto ncu;
+ }
+ if(c < '0' || c > '7')
+ goto dc;
+ for(;;) {
+ if(c >= '0' && c <= '7') {
+ *cp++ = c;
+ c = getc();
+ continue;
+ }
+ goto ncu;
+ }
+
+dc:
+ if(c == '.')
+ goto casedot;
+ if(c == 'e' || c == 'E')
+ goto casee;
+
+ncu:
+ *cp = 0;
+ ungetc(c);
+ if(mpatov(namebuf, &yylval.val.vval)) {
+ yyerror("overflow in constant");
+ yylval.val.vval = 0;
+ }
+ yylval.val.ctype = CTINT;
+ DBG("lex: integer literal\n");
+ return LLITERAL;
+
+casedot:
+ for(;;) {
+ *cp++ = c;
+ c = getc();
+ if(!isdigit(c))
+ break;
+ }
+ if(c != 'e' && c != 'E')
+ goto caseout;
+
+casee:
+ *cp++ = 'e';
+ c = getc();
+ if(c == '+' || c == '-') {
+ *cp++ = c;
+ c = getc();
+ }
+ if(!isdigit(c))
+ yyerror("malformed fp constant exponent");
+ while(isdigit(c)) {
+ *cp++ = c;
+ c = getc();
+ }
+
+caseout:
+ *cp = 0;
+ ungetc(c);
+ if(mpatof(namebuf, &yylval.val.dval)) {
+ yyerror("overflow in float constant");
+ yylval.val.dval = 0;
+ }
+ yylval.val.ctype = CTFLT;
+ DBG("lex: floating literal\n");
+ return LLITERAL;
+}
+
+int
+getc(void)
+{
+ int c;
+
+ c = curio.peekc;
+ if(c != 0) {
+ curio.peekc = 0;
+ if(c == '\n')
+ curio.lineno++;
+ return c;
+ }
+
+ c = Bgetc(curio.bin);
+ switch(c) {
+ case 0:
+ case EOF:
+ return EOF;
+
+ case '\n':
+ curio.lineno++;
+ break;
+
+ }
+ return c;
+}
+
+void
+ungetc(int c)
+{
+ curio.peekc = c;
+ if(c == '\n')
+ curio.lineno--;
+}
+
+long
+getr(void)
+{
+ int c, i;
+ char str[UTFmax+1];
+ Rune rune;
+
+ c = getc();
+ if(c < Runeself)
+ return c;
+ i = 0;
+ str[i++] = c;
+
+loop:
+ c = getc();
+ str[i++] = c;
+ if(!fullrune(str, i))
+ goto loop;
+ c = chartorune(&rune, str);
+ if(rune == Runeerror && c == 1) {
+ yyerror("illegal rune in string");
+ for(c=0; c<i; c++)
+ print(" %.2x", *(uchar*)(str+c));
+ print("\n");
+ }
+ return rune;
+}
+
+int
+getnsc(void)
+{
+ int c;
+
+ c = getc();
+ for(;;) {
+ if(!isspace(c))
+ return c;
+ if(c == '\n') {
+ curio.lineno++;
+ return c;
+ }
+ c = getc();
+ }
+ return 0;
+}
+
+
+long
+escchar(long e, int *escflg)
+{
+ long c, l;
+ int i;
+
+ *escflg = 0;
+
+loop:
+ c = getr();
+ if(c == '\n') {
+ yyerror("newline in string");
+ return EOF;
+ }
+ if(c != '\\') {
+ if(c == e)
+ c = EOF;
+ return c;
+ }
+ c = getr();
+ switch(c) {
+ case '\n':
+ goto loop;
+
+ case 'x':
+ i = 2;
+ goto hex;
+
+ case 'u':
+ i = 4;
+ goto hex;
+
+ case 'U':
+ i = 8;
+ goto hex;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ goto oct;
+
+ case 'a': return '\a';
+ case 'b': return '\b';
+ case 'f': return '\f';
+ case 'n': return '\n';
+ case 'r': return '\r';
+ case 't': return '\t';
+ case 'v': return '\v';
+
+ default:
+ warn("unknown escape sequence: %c", c);
+ }
+ return c;
+
+hex:
+ l = 0;
+ for(; i>0; i--) {
+ c = getc();
+ if(c >= '0' && c <= '9') {
+ l = l*16 + c-'0';
+ continue;
+ }
+ if(c >= 'a' && c <= 'f') {
+ l = l*16 + c-'a' + 10;
+ continue;
+ }
+ if(c >= 'A' && c <= 'F') {
+ l = l*16 + c-'A' + 10;
+ continue;
+ }
+ warn("non-hex character in escape sequence: %c", c);
+ ungetc(c);
+ break;
+ }
+ *escflg = 1;
+ return l;
+
+oct:
+ l = c - '0';
+ for(i=2; i>0; i--) {
+ c = getc();
+ if(c >= '0' && c <= '7') {
+ l = l*8 + c-'0';
+ continue;
+ }
+ warn("non-oct character in escape sequence: %c", c);
+ ungetc(c);
+ }
+ if(l > 255)
+ warn("oct escape value > 255: %d", l);
+ *escflg = 1;
+ return l;
+}
+
+static struct
+{
+ char* name;
+ int lexical;
+ int etype;
+} syms[] =
+{
+/* name lexical etype
+ */
+/* basic types */
+ "int8", LBASETYPE, TINT8,
+ "int16", LBASETYPE, TINT16,
+ "int32", LBASETYPE, TINT32,
+ "int64", LBASETYPE, TINT64,
+
+ "uint8", LBASETYPE, TUINT8,
+ "uint16", LBASETYPE, TUINT16,
+ "uint32", LBASETYPE, TUINT32,
+ "uint64", LBASETYPE, TUINT64,
+
+ "float32", LBASETYPE, TFLOAT32,
+ "float64", LBASETYPE, TFLOAT64,
+ "float80", LBASETYPE, TFLOAT80,
+
+ "bool", LBASETYPE, TBOOL,
+ "byte", LBASETYPE, TUINT8,
+ "char", LBASETYPE, TUINT8, // temp??
+ "string", LBASETYPE, TSTRING,
+
+/* keywords */
+ "any", LANY, Txxx,
+ "break", LBREAK, Txxx,
+ "case", LCASE, Txxx,
+ "chan", LCHAN, Txxx,
+ "const", LCONST, Txxx,
+ "continue", LCONTINUE, Txxx,
+ "convert", LCONVERT, Txxx,
+ "default", LDEFAULT, Txxx,
+ "else", LELSE, Txxx,
+ "export", LEXPORT, Txxx,
+ "fallthrough", LFALL, Txxx,
+ "false", LFALSE, Txxx,
+ "for", LFOR, Txxx,
+ "func", LFUNC, Txxx,
+ "go", LGO, Txxx,
+ "goto", LGOTO, Txxx,
+ "if", LIF, Txxx,
+ "import", LIMPORT, Txxx,
+ "interface", LINTERFACE, Txxx,
+ "iota", LIOTA, Txxx,
+ "map", LMAP, Txxx,
+ "new", LNEW, Txxx,
+ "len", LLEN, Txxx,
+ "nil", LNIL, Txxx,
+ "package", LPACKAGE, Txxx,
+ "panic", LPANIC, Txxx,
+ "print", LPRINT, Txxx,
+ "range", LRANGE, Txxx,
+ "return", LRETURN, Txxx,
+ "struct", LSTRUCT, Txxx,
+ "switch", LSWITCH, Txxx,
+ "true", LTRUE, Txxx,
+ "type", LTYPE, Txxx,
+ "var", LVAR, Txxx,
+
+ "notwithstanding", LIGNORE, Txxx,
+ "thetruthofthematter", LIGNORE, Txxx,
+ "despiteallobjections", LIGNORE, Txxx,
+ "whereas", LIGNORE, Txxx,
+ "insofaras", LIGNORE, Txxx,
+};
+
+void
+lexinit(void)
+{
+ int i, etype, lex;
+ Sym *s;
+ Node *t;
+
+
+ for(i=TINT8; i<=TUINT64; i++)
+ isint[i] = 1;
+ for(i=TFLOAT32; i<=TFLOAT80; i++)
+ isfloat[i] = 1;
+
+ /*
+ * initialize okfor
+ */
+ for(i=0; i<NTYPE; i++) {
+ if(isint[i]) {
+ okforeq[i] = 1;
+ okforadd[i] = 1;
+ okforand[i] = 1;
+ }
+ if(isfloat[i]) {
+ okforeq[i] = 1;
+ okforadd[i] = 1;
+ }
+ switch(i) {
+ case TBOOL:
+ okforeq[i] = 1;
+ break;
+ case TPTR:
+ okforeq[i] = 1;
+ break;
+ }
+ minfloatval[i] = 0.0;
+ maxfloatval[i] = 0.0;
+ minintval[i] = 0;
+ maxintval[i] = 0;
+ }
+// this stuff smells - really need to do constants
+// in multi precision arithmetic
+
+ maxintval[TINT8] = 0x7f;
+ minintval[TINT8] = -maxintval[TINT8]-1;
+ maxintval[TINT16] = 0x7fff;
+ minintval[TINT16] = -maxintval[TINT16]-1;
+ maxintval[TINT32] = 0x7fffffffL;
+ minintval[TINT32] = -maxintval[TINT32]-1;
+ maxintval[TINT64] = 0x7fffffffffffffffLL;
+ minintval[TINT64] = -maxintval[TINT64]-1;
+
+ maxintval[TUINT8] = 0xff;
+ maxintval[TUINT16] = 0xffff;
+ maxintval[TUINT32] = 0xffffffffL;
+ maxintval[TUINT64] = 0xffffffffffffffffLL;
+
+ maxfloatval[TFLOAT32] = 3.40282347e+38;
+ minfloatval[TFLOAT32] = -maxfloatval[TFLOAT32];
+ maxfloatval[TFLOAT64] = 1.7976931348623157e+308;
+ minfloatval[TFLOAT64] = -maxfloatval[TFLOAT64]-1;
+
+ /*
+ * initialize basic types array
+ * initialize known symbols
+ */
+ for(i=0; i<nelem(syms); i++) {
+ lex = syms[i].lexical;
+ s = lookup(syms[i].name);
+ s->lexical = lex;
+
+ if(lex != LBASETYPE)
+ continue;
+
+ etype = syms[i].etype;
+ if(etype < 0 || etype >= nelem(types))
+ fatal("lexinit: %s bad etype", s->name);
+
+ t = types[etype];
+ if(t != N) {
+ s->otype = t;
+ continue;
+ }
+ t = nod(OTYPE, N, N);
+ t->etype = etype;
+ switch(etype) {
+ case TSTRING:
+ case TCHAN:
+ case TMAP:
+ t = ptrto(t);
+ }
+ t->sym = s;
+ t->recur = 1; // supresses printing beyond name
+
+ types[etype] = t;
+ s->otype = t;
+ }
+
+ /* pick up the backend typedefs */
+ belexinit(LBASETYPE);
+
+ booltrue = nod(OLITERAL, N, N);
+ booltrue->val.ctype = CTBOOL;
+ booltrue->val.vval = 1;
+ booltrue->type = types[TBOOL];
+
+ boolfalse = nod(OLITERAL, N, N);
+ boolfalse->val.ctype = CTBOOL;
+ boolfalse->val.vval = 0;
+ booltrue->type = types[TBOOL];
+}
+
+struct
+{
+ int lex;
+ char* name;
+} lexn[] =
+{
+ LANDAND, "ANDAND",
+ LASOP, "ASOP",
+ LACONST, "ACONST",
+ LATYPE, "ATYPE",
+ LBASETYPE, "BASETYPE",
+ LBREAK, "BREAK",
+ LCASE, "CASE",
+ LCHAN, "CHAN",
+ LCOLAS, "COLAS",
+ LCONST, "CONST",
+ LCONTINUE, "CONTINUE",
+ LDEC, "DEC",
+ LELSE, "ELSE",
+ LEQ, "EQ",
+ LFUNC, "FUNC",
+ LGE, "GE",
+ LGO, "GO",
+ LGOTO, "GOTO",
+ LGT, "GT",
+ LIF, "IF",
+ LINC, "INC",
+ LINTERFACE, "INTERFACE",
+ LLE, "LE",
+ LLITERAL, "LITERAL",
+ LLSH, "LSH",
+ LLT, "LT",
+ LMAP, "MAP",
+ LNAME, "NAME",
+ LNE, "NE",
+ LOROR, "OROR",
+ LPACK, "PACK",
+ LRANGE, "RANGE",
+ LRETURN, "RETURN",
+ LRSH, "RSH",
+ LSTRUCT, "STRUCT",
+ LSWITCH, "SWITCH",
+ LTYPE, "TYPE",
+ LVAR, "VAR",
+ LFOR, "FOR",
+ LNEW, "NEW",
+ LLEN, "LEN",
+ LFALL, "FALL",
+ LCONVERT, "CONVERT",
+ LIOTA, "IOTA",
+ LPRINT, "PRINT",
+ LPACKAGE, "PACKAGE",
+ LIMPORT, "IMPORT",
+ LEXPORT, "EXPORT",
+ LPANIC, "PANIC",
+};
+
+char*
+lexname(int lex)
+{
+ int i;
+ static char buf[100];
+
+ for(i=0; i<nelem(lexn); i++)
+ if(lexn[i].lex == lex)
+ return lexn[i].name;
+ snprint(buf, sizeof(buf), "LEX-%d", lex);
+ return buf;
+}
+
+void
+mkpackage(char* pkg)
+{
+ Sym *s;
+ long h;
+
+ if(bout != nil) {
+ yyerror("mkpackage: called again %s %s", pkg, package);
+ return;
+ }
+
+ // defefine all names to be this package
+ package = pkg;
+ for(h=0; h<NHASH; h++)
+ for(s = hash[h]; s != S; s = s->link) {
+ s->package = package;
+ s->opackage = package;
+ }
+
+ if(outfile == nil) {
+ snprint(namebuf, sizeof(namebuf), "%s.go.c", package);
+ outfile = strdup(namebuf);
+ }
+
+ bout = Bopen(outfile, OWRITE);
+ if(bout == nil)
+ fatal("cant open %s", outfile);
+}
--- /dev/null
+// 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 <u.h>
+#include <libc.h>
+
+int mpatof(char*, double*);
+int mpatov(char *s, vlong *v);
+
+enum
+{
+ Mpscale = 29, /* safely smaller than bits in a long */
+ Mpprec = 36, /* Mpscale*Mpprec sb > largest fp exp */
+ Mpbase = 1L<<Mpscale,
+};
+
+typedef
+struct
+{
+ long a[Mpprec];
+ char ovf;
+} Mp;
+
+static void mpint(Mp*, int);
+static void mppow(Mp*, int, int);
+static void mpmul(Mp*, int);
+static void mpadd(Mp*, Mp*);
+static int mptof(Mp*, double*);
+
+/*
+ * convert a string, s, to floating in *d
+ * return conversion overflow.
+ * required syntax is [+-]d*[.]d*[e[+-]d*]
+ */
+int
+mpatof(char *s, double *d)
+{
+ Mp a, b;
+ int dp, c, f, ef, ex, zer;
+ double d1, d2;
+
+ dp = 0; /* digits after decimal point */
+ f = 0; /* sign */
+ ex = 0; /* exponent */
+ zer = 1; /* zero */
+ memset(&a, 0, sizeof(a));
+ for(;;) {
+ switch(c = *s++) {
+ default:
+ goto bad;
+ case '-':
+ f = 1;
+ case ' ':
+ case '\t':
+ case '+':
+ continue;
+ case '.':
+ dp = 1;
+ continue;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ zer = 0;
+ case '0':
+ mpint(&b, c-'0');
+ mpmul(&a, 10);
+ mpadd(&a, &b);
+ if(dp)
+ dp++;
+ continue;
+ case 'E':
+ case 'e':
+ ex = 0;
+ ef = 0;
+ for(;;) {
+ c = *s++;
+ if(c == '+' || c == ' ' || c == '\t')
+ continue;
+ if(c == '-') {
+ ef = 1;
+ continue;
+ }
+ if(c >= '0' && c <= '9') {
+ ex = ex*10 + (c-'0');
+ continue;
+ }
+ break;
+ }
+ if(ef)
+ ex = -ex;
+ case 0:
+ break;
+ }
+ break;
+ }
+ if(a.ovf)
+ goto bad;
+ if(zer) {
+ *d = 0;
+ return 0;
+ }
+ if(dp)
+ dp--;
+ dp -= ex;
+ if(dp > 0) {
+ /*
+ * must divide by 10**dp
+ */
+ if(mptof(&a, &d1))
+ goto bad;
+
+ /*
+ * trial exponent of 8**dp
+ * 8 (being between 5 and 10)
+ * should pick up all underflows
+ * in the division of 5**dp.
+ */
+ d2 = frexp(d1, &ex);
+ d2 = ldexp(d2, ex-3*dp);
+ if(d2 == 0)
+ goto bad;
+
+ /*
+ * decompose each 10 into 5*2.
+ * create 5**dp in fixed point
+ * and then play with the exponent
+ * for the remaining 2**dp.
+ * note that 5**dp will overflow
+ * with as few as 134 input digits.
+ */
+ mpint(&a, 1);
+ mppow(&a, 5, dp);
+ if(mptof(&a, &d2))
+ goto bad;
+ d1 = frexp(d1/d2, &ex);
+ d1 = ldexp(d1, ex-dp);
+ if(d1 == 0)
+ goto bad;
+ } else {
+ /*
+ * must multiply by 10**|dp| --
+ * just do it in fixed point.
+ */
+ mppow(&a, 10, -dp);
+ if(mptof(&a, &d1))
+ goto bad;
+ }
+ if(f)
+ d1 = -d1;
+ *d = d1;
+ return 0;
+
+bad:
+ return 1;
+}
+
+/*
+ * convert a to floating in *d
+ * return conversion overflow
+ */
+static int
+mptof(Mp *a, double *d)
+{
+ double f, g;
+ long x, *a1;
+ int i;
+
+ if(a->ovf)
+ return 1;
+ a1 = a->a;
+ f = ldexp(*a1++, 0);
+ for(i=Mpscale; i<Mpprec*Mpscale; i+=Mpscale)
+ if(x = *a1++) {
+ g = ldexp(x, i);
+ /*
+ * NOTE: the test (g==0) is plan9
+ * specific. ansi compliant overflow
+ * is signaled by HUGE and errno==ERANGE.
+ * change this for your particular ldexp.
+ */
+ if(g == 0)
+ return 1;
+ f += g; /* this could bomb! */
+ }
+ *d = f;
+ return 0;
+}
+
+/*
+ * return a += b
+ */
+static void
+mpadd(Mp *a, Mp *b)
+{
+ int i, c;
+ long x, *a1, *b1;
+
+ if(b->ovf)
+ a->ovf = 1;
+ if(a->ovf)
+ return;
+ c = 0;
+ a1 = a->a;
+ b1 = b->a;
+ for(i=0; i<Mpprec; i++) {
+ x = *a1 + *b1++ + c;
+ c = 0;
+ if(x >= Mpbase) {
+ x -= Mpbase;
+ c = 1;
+ }
+ *a1++ = x;
+ }
+ a->ovf = c;
+}
+
+/*
+ * return a = c
+ */
+static void
+mpint(Mp *a, int c)
+{
+
+ memset(a, 0, sizeof(*a));
+ a->a[0] = c;
+}
+
+/*
+ * return a *= c
+ */
+static void
+mpmul(Mp *a, int c)
+{
+ Mp p;
+ int b;
+ memmove(&p, a, sizeof(p));
+ if(!(c & 1))
+ memset(a, 0, sizeof(*a));
+ c &= ~1;
+ for(b=2; c; b<<=1) {
+ mpadd(&p, &p);
+ if(c & b) {
+ mpadd(a, &p);
+ c &= ~b;
+ }
+ }
+}
+
+/*
+ * return a *= b**e
+ */
+static void
+mppow(Mp *a, int b, int e)
+{
+ int b1;
+
+ b1 = b*b;
+ b1 = b1*b1;
+ while(e >= 4) {
+ mpmul(a, b1);
+ e -= 4;
+ if(a->ovf)
+ return;
+ }
+ while(e > 0) {
+ mpmul(a, b);
+ e--;
+ }
+}
+
+/*
+ * convert a string, s, to vlong in *v
+ * return conversion overflow.
+ * required syntax is [0[x]]d*
+ */
+int
+mpatov(char *s, vlong *v)
+{
+ vlong n, nn;
+ int c;
+ n = 0;
+ c = *s;
+ if(c == '0')
+ goto oct;
+ while(c = *s++) {
+ if(c >= '0' && c <= '9')
+ nn = n*10 + c-'0';
+ else
+ goto bad;
+ if(n < 0 && nn >= 0)
+ goto bad;
+ n = nn;
+ }
+ goto out;
+oct:
+ s++;
+ c = *s;
+ if(c == 'x' || c == 'X')
+ goto hex;
+ while(c = *s++) {
+ if(c >= '0' || c <= '7')
+ nn = n*8 + c-'0';
+ else
+ goto bad;
+ if(n < 0 && nn >= 0)
+ goto bad;
+ n = nn;
+ }
+ goto out;
+hex:
+ s++;
+ while(c = *s++) {
+ if(c >= '0' && c <= '9')
+ c += 0-'0';
+ else
+ if(c >= 'a' && c <= 'f')
+ c += 10-'a';
+ else
+ if(c >= 'A' && c <= 'F')
+ c += 10-'A';
+ else
+ goto bad;
+ nn = n*16 + c;
+ if(n < 0 && nn >= 0)
+ goto bad;
+ n = nn;
+ }
+out:
+ *v = n;
+ return 0;
+
+bad:
+ *v = ~0;
+ return 1;
+}
--- /dev/null
+// 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 "gen.h"
+
+static Prog* firstp;
+static Prog* lastp;
+static int typeexpand;
+
+void
+dumpobj(void)
+{
+ Plist *pl;
+ Prog *p;
+ long lno;
+
+ Bprint(bout, "\n\n/*\n");
+ Bprint(bout, " * automatic code generated from\n");
+ Bprint(bout, " * %s in package \"%s\"\n", curio.infile, package);
+ dumpexport();
+ Bprint(bout, " */\n", curio.infile, package);
+ Bprint(bout, "#include \"gort.h\"\n");
+
+ // put out external variables and types
+ doframe(externdcl, "external");
+ dumpmethods();
+
+ // put out signatures
+ dumpsignatures();
+
+ // put out functions
+ for(pl=plist; pl!=nil; pl=pl->link) {
+ /* print out the function header */
+ dumpfunct(pl);
+
+ /* clear the marks */
+ for(p=pl->firstpc; p!=nil; p=p->link)
+ p->mark = 0;
+
+ /* relinearize the object code */
+ firstp = mal(sizeof(*firstp));
+ lastp = firstp;
+ follow(pl->firstpc);
+ lastp->link = P;
+ pl->firstpc = firstp->link;
+
+ /* clear the marks - relabel the locations */
+ for(p=pl->firstpc; p!=nil; p=p->link)
+ p->mark = 0;
+
+ /* mark the labels */
+ for(p=pl->firstpc; p!=nil; p=p->link) {
+ if(p->addr.branch != P)
+ p->addr.branch->mark = 1;
+ }
+
+ /* interpret the instructions */
+ lno = dynlineno;
+ for(p=pl->firstpc; p!=nil; p=p->link) {
+ dynlineno = p->lineno;
+ dynloc = p->loc;
+ obj(p);
+ }
+ dynlineno = lno;
+ Bprint(bout, "}\n");
+ }
+}
+
+void
+obj1(Prog *p)
+{
+ Node *n;
+ static long uloc, olino;
+
+ Bprint(bout, "\n\t// %P\n", p);
+ if(p->mark)
+ Bprint(bout, "_L%ld:\n", p->loc);
+
+ uloc++;
+ if(p->lineno != 0)
+ olino = p->lineno;
+ Bprint(bout, "\tgotrace(%ld, %ld);\n", uloc, olino);
+
+ switch(p->op) {
+ default:
+ warn("obj: unknown opcode %A", p);
+ Bprint(bout, "\tprintf(\"unknown line %ld-%ld: %A\\n\");\n",
+ dynloc, dynlineno, p);
+
+ case PPANIC:
+ Bprint(bout, "\tprintf(\"panic line %ld\\n\");\n", dynlineno);
+ Bprint(bout, "\tgoexit(1);\n");
+ break;
+
+ case PPRINT:
+ Bprint(bout, "\tprint%s(%R);\n", getfmt(p->pt), p->pt);
+ break;
+
+ case PGOTO:
+ Bprint(bout, "\tgoto %D;\n", p);
+ break;
+
+ case PGOTOX:
+ yyerror("label not declared: %S", p->addr.node->left->sym);
+ break;
+
+ case PCMP:
+ if(p->pt == PTSTRING)
+ goto pcmpz;
+
+ switch(p->link->op) {
+ case PBEQ:
+ Bprint(bout, "\tif(%R == %D) {\n", p->pt, p);
+ break;
+ case PBNE:
+ Bprint(bout, "\tif(%R != %D) {\n", p->pt, p);
+ break;
+ case PBLT:
+ Bprint(bout, "\tif(%R < %D) {\n", p->pt, p);
+ break;
+ case PBLE:
+ Bprint(bout, "\tif(%R <= %D) {\n", p->pt, p);
+ break;
+ case PBGE:
+ Bprint(bout, "\tif(%R >= %D) {\n", p->pt, p);
+ break;
+ case PBGT:
+ Bprint(bout, "\tif(%R > %D) {\n", p->pt, p);
+ break;
+ }
+ break;
+
+ pcmpz:
+ Bprint(bout, "\tif(cmpZ(%D) ", p);
+ switch(p->link->op) {
+ case PBEQ:
+ Bprint(bout, "== 0) {\n");
+ break;
+ case PBNE:
+ Bprint(bout, "!= 0) {\n");
+ break;
+ case PBLT:
+ Bprint(bout, "< 0) {\n");
+ break;
+ case PBLE:
+ Bprint(bout, "<= 0) {\n");
+ break;
+ case PBGE:
+ Bprint(bout, ">= 0) {\n");
+ break;
+ case PBGT:
+ Bprint(bout, "> 0) {\n");
+ break;
+ }
+ break;
+
+ case PTEST:
+ switch(p->link->op) {
+ case PBTRUE:
+ Bprint(bout, "\tif(%D != 0) {\n", p);
+ break;
+ case PBFALSE:
+ Bprint(bout, "\tif(%D == 0) {\n", p);
+ break;
+ }
+ break;
+
+ case PBEQ:
+ case PBNE:
+ case PBLT:
+ case PBLE:
+ case PBGE:
+ case PBGT:
+ case PBTRUE:
+ case PBFALSE:
+ Bprint(bout, "\t\tgoto %D; }\n", p);
+ break;
+
+ case PLEN:
+ Bprint(bout, "\t%R = %D->len;\n", PTINT32, p);
+ break;
+
+ case PNEW:
+ if(p->addr.type != ANODE)
+ goto bad;
+ n = p->addr.node;
+ n = n->type;
+ n = n->type;
+ if(n == N || n->op != OTYPE)
+ goto bad;
+ Bprint(bout, "\t%R = gomal(sizeof(%C%lC));\n", p->pt, n, n);
+ break;
+
+ case PLOAD:
+ if(p->pt == PTPTR || p->pt == PTADDR) {
+ Bprint(bout, "\t%R = (%Q)%D;\n", p->pt, PTPTR, p);
+ break;
+ }
+ Bprint(bout, "\t%R = %D;\n", p->pt, p);
+ break;
+
+ case PLOADI: // R/D = *(A)
+ Bprint(bout, "\t%D = *(%Q*)%R;\n", p, p->pt, PTADDR);
+ break;
+
+ case PSTORE:
+ if(p->pt == PTPTR || p->pt == PTADDR) {
+ if(p->addr.type != ANODE)
+ goto bad;
+ n = p->addr.node;
+ if(n == N || n->type == N)
+ goto bad;
+ Bprint(bout, "\t%D = (%C)%R;\n", p, n->type, p->pt);
+ break;
+ }
+ Bprint(bout, "\t%D = %R;\n", p, p->pt);
+ break;
+
+ case PSTOREI: // *(A) = R/D
+ Bprint(bout, "\t*(%Q*)%R = %D;\n", p->pt, PTADDR, p);
+ break;
+
+ case PSTOREZ:
+ switch(p->pt) {
+ default:
+ Bprint(bout, "\t%D = 0;\n", p);
+ break;
+
+ case PTARRAY:
+ case PTSTRUCT:
+ Bprint(bout, "\tmemset(&%D, 0, sizeof(%D));\n", p, p);
+ break;
+
+ case PTINTER:
+ Bprint(bout, "\t%D.s = 0; %D.m = 0;\n", p, p);
+ break;
+
+ case PTSTRING:
+ Bprint(bout, "\t%D = &nilstring;\n", p);
+ break;
+ }
+ break;
+
+ case PCONV:
+ doconv(p);
+ break;
+
+ case PADDR:
+ Bprint(bout, "\t%R = (%Q)&%D;\n", p->pt, p->pt, p);
+ break;
+
+ case PADDO:
+ if(p->addr.type != ANODE)
+ goto bad;
+ n = p->addr.node;
+ if(n == N || n->op != ONAME || n->sym == S)
+ goto bad;
+ if(n->uberstruct == N || n->uberstruct->etype != TSTRUCT)
+ goto bad;
+
+ Bprint(bout, "\t%R = (%Q)((char*)%R + offsetof(_T_%ld, %s));\n",
+ p->pt, PTADDR, p->pt,
+// n->uberstruct->nname->sym->package,
+ n->uberstruct->vargen, n->sym->name);
+ break;
+
+ case PINDEXZ:
+ Bprint(bout, "\t%R = %D->string[%R];\n",
+ PTUINT8, p, p->pt);
+ break;
+
+ case PINDEX:
+ if(p->addr.type != ANODE)
+ goto bad;
+ n = p->addr.node;
+ Bprint(bout, "\t%R += (%R)*sizeof(%C);\n",
+ PTADDR, p->pt, n->type);
+ break;
+
+ case PSLICE:
+ if(p->addr.type != ANODE)
+ goto bad;
+ n = p->addr.node;
+ Bprint(bout, "\tsliceZ(%R, %D);\n", p->pt, p);
+ break;
+
+ case PCAT:
+ Bprint(bout, "\tcatZ(%D);\n", p);
+ break;
+
+ case PADD:
+ Bprint(bout, "\t%R += %D;\n", p->pt, p);
+ break;
+
+ case PSUB:
+ Bprint(bout, "\t%R -= %D;\n", p->pt, p);
+ break;
+
+ case PMUL:
+ Bprint(bout, "\t%R *= %D;\n", p->pt, p);
+ break;
+
+ case PDIV:
+ Bprint(bout, "\t%R /= %D;\n", p->pt, p);
+ break;
+
+ case PLSH:
+ Bprint(bout, "\t%R <<= %D;\n", p->pt, p);
+ break;
+
+ case PRSH:
+ Bprint(bout, "\t%R >>= %D;\n", p->pt, p);
+ break;
+
+ case PMOD:
+ Bprint(bout, "\t%R %%= %D;\n", p->pt, p);
+ break;
+
+ case PAND:
+ Bprint(bout, "\t%R &= %D;\n", p->pt, p);
+ break;
+
+ case POR:
+ Bprint(bout, "\t%R |= %D;\n", p->pt, p);
+ break;
+
+ case PXOR:
+ Bprint(bout, "\t%R ^= %D;\n", p->pt, p);
+ break;
+
+ case PMINUS:
+ Bprint(bout, "\t%R = -%R;\n", p->pt, p->pt);
+ break;
+
+ case PCOM:
+ Bprint(bout, "\t%R = ~%R;\n", p->pt, p->pt);
+ break;
+
+ case PRETURN:
+ Bprint(bout, "\treturn;\n");
+ break;
+
+ case PCALL1: //Â process the arguments
+ docall1(p);
+ break;
+
+ case PCALL2: //Â call the normal function
+ docall2(p);
+ break;
+
+ case PCALLI2: //Â call the indirect function
+ docalli2(p);
+ break;
+
+ case PCALLM2: //Â call the method function
+ docallm2(p);
+ break;
+
+ case PCALLF2: //Â call the interface method function
+ docallf2(p);
+ break;
+
+ case PCALL3: //Â process the return
+ docall3(p);
+ break;
+
+ case PEND:
+ Bprint(bout, "\treturn;\n");
+ break;
+ }
+ return;
+
+bad:
+ print("bad code generation on\n\t// %P\n", p);
+}
+
+
+void
+follow(Prog *p)
+{
+ Prog *q;
+ int i, op;
+
+loop:
+ if(p == P)
+ return;
+
+ if(p->op == PGOTO) {
+ q = p->addr.branch;
+ if(q != P) {
+ p->mark = 1;
+ p = q;
+ if(p->mark == 0)
+ goto loop;
+ }
+ }
+
+ if(p->mark) {
+ /* copy up to 4 instructions to avoid branch */
+ for(i=0, q=p; i<4; i++, q=q->link) {
+ if(q == P)
+ break;
+ if(q == lastp)
+ break;
+ if(q->op == PGOTO)
+ break;
+ if(q->addr.branch == P)
+ continue;
+ if(q->addr.branch->mark)
+ continue;
+ if(q->op == PCALL1)
+ continue;
+
+ // we found an invertable now copy
+// for(;;) {
+// q = copyp(p);
+// p = p->link;
+// q->mark = 1;
+// lastp->link = q;
+// lastp = q;
+// if(q->op != a || q->addr.branch == P || q->addr.branch->mark)
+// continue;
+//
+// q->op = relinv(q->op);
+// p = q->addr.branch;
+// q->addr.branch = q->link;
+// q->link = p;
+// follow(q->link);
+// p = q->link;
+// if(p->mark)
+// return;
+// goto loop;
+// }
+ }
+
+ q = mal(sizeof(*q));
+ q->op = PGOTO;
+ q->lineno = p->lineno;
+ q->addr.type = ABRANCH;
+ q->addr.branch = gotochain(p);
+ p = q;
+ }
+
+ p->mark = 1;
+ p->loc = lastp->loc+1;
+ lastp->link = p;
+ lastp = p;
+
+ op = p->op;
+ if(op == PGOTO || op == PRETURN || op == OEND)
+ return;
+
+ if(op == PCALL1 || p->addr.branch == P) {
+ p = p->link;
+ goto loop;
+ }
+
+ q = gotochain(p->link);
+ if(q != P && q->mark) {
+ p->op = brcom(op);
+ p->link = p->addr.branch;
+ p->addr.branch = q;
+ }
+ follow(p->link);
+ q = gotochain(p->addr.branch);
+ p->addr.branch = q;
+ if(q != P && q->mark)
+ return;
+
+ p = q;
+ goto loop;
+}
+
+void
+obj(Prog *p)
+{
+ Node *n;
+ String *s;
+ long i;
+
+ if(p->addr.type != ANODE)
+ goto out;
+ n = p->addr.node;
+ if(n == N || n->op != OLITERAL)
+ goto out;
+ if(p->pt != PTSTRING)
+ goto out;
+
+ s = n->val.sval;
+ Bprint(bout, "\t{ static struct {_T_U32 l;_T_U8 s[%d]; } slit = { %d", s->len, s->len);
+ for(i=0; i<s->len; i++) {
+ if(i%16 == 0)
+ Bprint(bout, "\n\t\t");
+ Bprint(bout, ",%d", s->s[i]);
+ }
+ Bprint(bout, " };\n");
+
+ obj1(p);
+ Bprint(bout, "\t}\n");
+ return;
+
+out:
+ obj1(p);
+}
+
+Prog*
+gotochain(Prog *p)
+{
+ int i;
+
+ for(i=0; i<20; i++) {
+ if(p == P || p->op != PGOTO)
+ return p;
+ p = p->addr.branch;
+ }
+ return P;
+}
+
+/*
+ * print a C type
+ */
+int
+Cconv(Fmt *fp)
+{
+ char buf[1000], buf1[100];
+ Node *t, *f, *n;
+ Iter it;
+ int pt;
+ long v1, v2;
+
+ t = va_arg(fp->args, Node*);
+ if(t == N)
+ return fmtstrcpy(fp, "<C>");
+
+ t->recur++;
+ if(t->op != OTYPE) {
+ snprint(buf, sizeof(buf), "C-%O", t->op);
+ goto out;
+ }
+ if(t->recur > 5) {
+ snprint(buf, sizeof(buf), "C-%E ...", t->etype);
+ goto out;
+ }
+
+ // post-name format
+ if(fp->flags & FmtLong) {
+ strcpy(buf, "");
+ switch(t->etype) {
+ default:
+ break;
+ case TARRAY:
+ snprint(buf, sizeof(buf), "[%ld]", t->bound);
+ break;
+ case TFUNC:
+ if(t->thistuple > 0) {
+ f = *getthis(t);
+ v1 = 9999;
+ v2 = 9999;
+ if(f != N) {
+ v1 = f->vargen;
+ if(f->nname != N)
+ v2 = f->nname->vargen;
+ }
+ snprint(buf1, sizeof(buf1), "(_T_%ld* _V_%ld",
+ v1, v2);
+ strncat(buf, buf1, sizeof(buf));
+ } else
+ strncat(buf, "(void* _dummythis", sizeof(buf));
+
+ if(t->outtuple > 0) {
+ f = *getoutarg(t);
+ v1 = 9999;
+ v2 = 9999;
+ if(f != N) {
+ v1 = f->vargen;
+ if(f->nname != N)
+ v2 = f->nname->vargen;
+ }
+ snprint(buf1, sizeof(buf1), ", _T_%ld* _V_%ld",
+ v1, v2);
+ strncat(buf, buf1, sizeof(buf));
+ } else
+ strncat(buf, ", void* _dummyout", sizeof(buf));
+
+ if(t->intuple > 0) {
+ f = *getinarg(t);
+ v1 = 9999;
+ v2 = 9999;
+ if(f != N) {
+ v1 = f->vargen;
+ if(f->nname != N)
+ v2 = f->nname->vargen;
+ }
+ snprint(buf1, sizeof(buf1), ", _T_%ld* _V_%ld)",
+ v1, v2);
+ strncat(buf, buf1, sizeof(buf));
+ } else
+ strncat(buf, ", void* _dummyin)", sizeof(buf));
+ break;
+ }
+ goto out;
+ }
+
+ if(t->vargen != 0 && !typeexpand) {
+ if(t->etype == TFUNC) {
+ strcpy(buf, "void");
+ goto out;
+ }
+ snprint(buf, sizeof(buf), "_T_%ld", t->vargen);
+ goto out;
+ }
+
+ switch(t->etype) {
+ default:
+ pt = conv2pt(t);
+ snprint(buf, sizeof(buf), "%Q", pt);
+ break;
+
+ case TSTRUCT:
+ if(fp->flags & FmtShort) {
+ strcpy(buf, "{");
+ } else {
+ if(t->vargen != 0) {
+ snprint(buf, sizeof(buf), "_T_%ld", t->vargen);
+ goto out;
+ }
+ strcpy(buf, "struct{");
+ }
+
+ f = structfirst(&it, &t);
+ while(f != N) {
+ n = f->type;
+ if(n->etype == TFUNC)
+ goto next;
+ if(f->sym == S)
+ snprint(buf1, sizeof(buf1), "%C;", n);
+ else
+ snprint(buf1, sizeof(buf1), "%C %s;", n, f->sym->name);
+ strncat(buf, buf1, sizeof(buf));
+ next:
+ f = structnext(&it);
+ }
+ strncat(buf, "}", sizeof(buf));
+ break;
+
+ case TPTR:
+ if(isptrto(t, TSTRING)) {
+ snprint(buf, sizeof(buf), "%C", t->type);
+ break;
+ }
+ snprint(buf, sizeof(buf), "%C*", t->type);
+ break;
+
+ case TARRAY:
+ snprint(buf, sizeof(buf), "%C", t->type);
+ break;
+
+ case TFUNC:
+ strcpy(buf, "void");
+ break;
+ }
+
+out:
+ t->recur--;
+ return fmtstrcpy(fp, buf);
+}
+
+/*
+ * print Prog operand
+ */
+int
+Dconv(Fmt *fp)
+{
+ char buf[500];
+ Prog *p;
+ Node *n;
+
+ if(fp->flags & FmtLong) {
+ p = nil;
+ n = va_arg(fp->args, Node*);
+ goto prnode;
+ }
+ p = va_arg(fp->args, Prog*);
+
+ switch(p->addr.type) {
+ default:
+ snprint(buf, sizeof(buf), "addr.type=%d", p->addr.type);
+ break;
+
+ case ANONE:
+ snprint(buf, sizeof(buf), "%R", p->pt);
+ break;
+
+ case ANODE:
+ n = p->addr.node;
+ goto prnode;
+
+ case ABRANCH:
+ p = p->addr.branch;
+ if(p == P) {
+ snprint(buf, sizeof(buf), "addr.branch=nil");
+ break;
+ }
+ snprint(buf, sizeof(buf), "_L%ld", p->loc);
+ break;
+ }
+ goto out;
+
+prnode:
+ if(n == N) {
+ snprint(buf, sizeof(buf), "addr.node=nil");
+ goto out;
+ }
+ switch(n->op) {
+ default:
+ snprint(buf, sizeof(buf), "%N", p->addr.node);
+ break;
+
+ case ONAME:
+ if(n->vargen != 0) {
+ snprint(buf, sizeof(buf), "_V_%ld", n->vargen);
+ break;
+ }
+ snprint(buf, sizeof(buf), "%s_%s", n->sym->opackage, n->sym->name);
+ break;
+
+ case OLITERAL:
+ switch(p->pt) {
+ badlit:
+ default:
+ snprint(buf, sizeof(buf), "BADLIT-%d pt-%d", p->pt, n->val.ctype);
+ break;
+ case PTINT8:
+ case PTINT16:
+ case PTINT32:
+ case PTUINT8:
+ case PTUINT16:
+ case PTUINT32:
+ switch(n->val.ctype) {
+ default:
+ goto badlit;
+ case CTINT:
+ case CTSINT:
+ case CTUINT:
+ if(n->val.vval < 0)
+ snprint(buf, sizeof(buf), "-0x%llux", -n->val.vval);
+ else
+ snprint(buf, sizeof(buf), "0x%llux", n->val.vval);
+ break;
+ }
+ break;
+ case PTINT64:
+ case PTUINT64:
+ switch(n->val.ctype) {
+ default:
+ goto badlit;
+ case CTINT:
+ case CTSINT:
+ case CTUINT:
+ snprint(buf, sizeof(buf), "0x%lluxll", n->val.vval);
+ break;
+ }
+ break;
+ case PTFLOAT32:
+ case PTFLOAT64:
+ case PTFLOAT80:
+ switch(n->val.ctype) {
+ default:
+ goto badlit;
+ case CTFLT:
+ snprint(buf, sizeof(buf), "%.17e", n->val.dval);
+ break;
+ }
+ break;
+ case PTBOOL:
+ switch(n->val.ctype) {
+ default:
+ goto badlit;
+ case CTBOOL:
+ snprint(buf, sizeof(buf), "%lld", n->val.vval);
+ break;
+ }
+ break;
+ case PTPTR:
+ switch(n->val.ctype) {
+ default:
+ goto badlit;
+ case CTSTR:
+ snprint(buf, sizeof(buf), "\"%Z\"", n->val.sval);
+ break;
+ case CTNIL:
+ snprint(buf, sizeof(buf), "(void*)0", n->val.sval);
+ break;
+ }
+ break;
+
+ case PTSTRING:
+ snprint(buf, sizeof(buf), "(_T_Z)&slit");
+ break;
+
+ }
+ break;
+ }
+
+out:
+ return fmtstrcpy(fp, buf);
+}
+
+char*
+thistypenam(Node *t)
+{
+ char *typ;
+ Node *n;
+
+ typ = "???";
+ if(t == N)
+ return typ;
+ n = getthisx(t); // struct{field a *T}
+ if(n != N)
+ n = n->type; // field a *T
+ if(n != N)
+ n = n->type; // *T
+ if(n != N)
+ n = n->type; // T
+ if(n != N && n->sym != S)
+ typ = n->sym->name;
+ return typ;
+}
+
+void
+dumpfunct(Plist *pl)
+{
+ Node *t;
+ char *pkg, *typ, *fun;
+
+ t = pl->name->type;
+ pkg = pl->name->sym->opackage;
+ fun = pl->name->sym->name;
+
+ if(t->thistuple > 0) {
+ typ = thistypenam(t); // struct{field a *T}
+ Bprint(bout, "\n%C %s_%s_%s%lC", t, pkg, typ, fun, t);
+ } else {
+ Bprint(bout, "\n%C %s_%s%lC", t, pkg, fun, t);
+ }
+
+ Bprint(bout, "\n{\n");
+ doframe(pl->locals, "local");
+}
+
+void
+dumpmethods()
+{
+ Node *t;
+ char *pkg, *typ, *fun;
+ Plist *pl;
+
+ for(pl=plist; pl!=nil; pl=pl->link) {
+ t = pl->name->type;
+ if(t->thistuple > 0) {
+ pkg = pl->name->sym->opackage;
+ fun = pl->name->sym->name;
+ typ = thistypenam(t);
+ Bprint(bout, "\n%C %s_%s_%s%lC;\n", t, pkg, typ, fun, t);
+ }
+ }
+}
+
+static int
+sigcmp(Sig *a, Sig *b)
+{
+ return strcmp(a->fun, b->fun);
+}
+
+void
+dumpsignatures(void)
+{
+ Dcl *d;
+ Node *t, *f;
+ Sym *s1, *s;
+ char *pkg, *typ, *fun;
+ int et, o, any;
+ Sig *a, *b;
+
+ /* put all the names into a linked
+ * list so that it may be generated in sorted order.
+ * the runtime will be linear rather than quadradic
+ */
+
+ any = 1;
+ for(d=externdcl; d!=D; d=d->forw) {
+ if(d->op != OTYPE)
+ continue;
+
+ t = d->dnode;
+ et = t->etype;
+ if(et != TSTRUCT && et != TINTER)
+ continue;
+
+ s = d->dsym;
+ if(s == S)
+ continue;
+
+ typ = s->name;
+ if(typ[0] == '_')
+ continue;
+
+ pkg = s->opackage;
+ if(pkg != package) {
+ if(et == TINTER)
+ Bprint(bout, "extern _Sigi sig_%s_%s[];\n", pkg, typ);
+ else
+ Bprint(bout, "extern _Sigs sig_%s_%s[];\n", pkg, typ);
+ continue;
+ }
+
+ a = nil;
+ o = 0;
+ for(f=t->type; f!=N; f=f->down) {
+ if(f->type->etype != TFUNC)
+ continue;
+
+ if(f->etype != TFIELD)
+ fatal("dumpsignatures: not field");
+
+ s1 = f->sym;
+ if(s1 == nil)
+ continue;
+ fun = s1->name;
+ if(fun[0] == '_')
+ continue;
+
+ b = mal(sizeof(*b));
+ b->link = a;
+ a = b;
+
+ a->fun = fun;
+ a->hash = PRIME8*stringhash(fun) + PRIME9*typehash(f->type, 0);
+ a->offset = o;
+ o++;
+ }
+
+ if(1 || et == TINTER || a != nil) {
+ if(any) {
+ Bprint(bout, "\n");
+ any = 0;
+ }
+
+ a = lsort(a, sigcmp);
+
+ if(et == TINTER) {
+ o = 0;
+ for(b=a; b!=nil; b=b->link)
+ o++;
+ Bprint(bout, "_Sigi sig_%s_%s[] =\n", pkg, typ);
+ Bprint(bout, "{\n");
+ Bprint(bout, "\t{ \"\", 0, %d}, // count\n", o);
+ for(b=a; b!=nil; b=b->link) {
+ Bprint(bout, "\t{ \"%s\", 0x%.8lux, %d},\n",
+ b->fun, b->hash, b->offset);
+ }
+ } else {
+ Bprint(bout, "_Sigs sig_%s_%s[] =\n", pkg, typ);
+ Bprint(bout, "{\n");
+ for(b=a; b!=nil; b=b->link) {
+ Bprint(bout, "\t{ \"%s\", 0x%.8lux, &%s_%s_%s },\n",
+ b->fun, b->hash, pkg, typ, b->fun);
+ }
+ }
+ Bprint(bout, "\t{ 0,0,0 }\n");
+ Bprint(bout, "};\n");
+ }
+ }
+}
+
+int
+istypstr(Node *t)
+{
+ if(t == N)
+ fatal("istypstr: t nil");
+ if(t->etype == TSTRUCT)
+ return 1;
+ return 0;
+}
+
+static int XXX = 0;
+static int YYY = 0;
+
+int
+alldefined(Node *t, int first)
+{
+ Node *t1;
+
+ if(t == N)
+ return 1;
+
+ if(t->op != OTYPE)
+ fatal("alldefined: not OTYPE: %O", t->op);
+
+ if(t->recur)
+ return 1;
+
+ if(!first && t->sym!=S && t->sym->undef != 0)
+ return 1;
+
+ t->recur++;
+
+ switch(t->etype) {
+ default:
+ // should be basic types
+ return 1;
+
+ case TPTR:
+ case TARRAY:
+ case TFIELD:
+ if(!alldefined(t->type, 0))
+ goto no;
+ break;
+
+ case TSTRUCT:
+ case TFUNC:
+ for(t1=t->type; t1!=N; t1=t1->down) {
+ if(!alldefined(t1, 0))
+ goto no;
+ }
+ break;
+ }
+
+ t->recur--;
+ return 1;
+
+no:
+ t->recur--;
+ return 0;
+}
+
+void
+doframe(Dcl *r, char *msg)
+{
+ Sym *s;
+ Dcl *d;
+ Node *n, *t;
+ int flag, pass, any;
+ char *tab, *nam, *pkg, *typ;
+
+ tab = "\t";
+ if(msg[0] != 'l')
+ tab = "";
+
+ // put out types
+ flag = 1;
+ typeexpand = 1;
+ for(pass=0;; pass++) {
+if(XXX)print("\npass %d\n\n", pass);
+ any = 0;
+ for(d=r; d!=D; d=d->forw) {
+ if(d->op != OTYPE)
+ continue;
+
+ if(flag) {
+ Bprint(bout, "\n%s// %s types\n", tab, msg);
+ flag = 0;
+ }
+
+ n = d->dnode;
+ nam = "???";
+ s = d->dsym;
+ if(s != S)
+ nam = s->name;
+
+ if(pass == 0) {
+ if(s != S)
+ s->undef = 0;
+ if(istypstr(n)) {
+ Bprint(bout, "%stypedef struct _T_%ld _T_%ld; // %s\n",
+ tab, n->vargen, n->vargen, nam);
+if(XXX)print("\t1 pass-%d ", pass);
+if(XXX)print("typedef struct _T_%ld _T_%ld; // %s\n", n->vargen, n->vargen, nam);
+ }
+ any = 1;
+ continue;
+ }
+
+if(XXX)if(s != S) print("looking at %s undef=%d: %lT\n", s->name, s->undef, n);
+
+ if(s != S && s->undef == 0 && alldefined(n, 1)) {
+if(XXX)print("\t2 pass-%d ", pass);
+ if(istypstr(n)) {
+ Bprint(bout, "%sstruct _T_%ld %hC; // %s\n",
+ tab, n->vargen, n, nam);
+if(XXX)print("struct _T_%ld %hC; // %s\n", n->vargen, n, nam);
+ } else {
+ if(n->etype != TFUNC)
+ Bprint(bout, "%stypedef %C _T_%ld%lC; // %s\n",
+ tab, n, n->vargen, n, nam);
+if(XXX)print("typedef %C _T_%ld%lC; // %s\n", n, n->vargen, n, nam);
+ }
+ s->undef = 1;
+ any = 1;
+ }
+ }
+ if(any)
+ continue;
+
+ for(d=r; d!=D; d=d->forw) {
+ if(d->op != OTYPE)
+ continue;
+ n = d->dnode;
+ s = d->dsym;
+ if(s != S) {
+ if(s->undef == 0)
+ fatal("doframe: couldnt resolve type %s %lT\n",
+ s->name, n);
+ continue;
+ }
+if(XXX)print("\t-3 pass-%d ", pass);
+ if(istypstr(n)) {
+ Bprint(bout, "%sstruct _T_%ld %hC;\n",
+ tab, n->vargen, n);
+if(XXX)print("struct _T_%ld %hC;\n", n->vargen, n);
+ } else {
+ Bprint(bout, "%stypedef %C _T_%ld%lC;\n",
+ tab, n, n->vargen, n);
+if(XXX)print("typedef %C _T_%ld%lC;\n", n, n->vargen, n);
+ }
+ }
+ break;
+ }
+ typeexpand = 0;
+
+ flag = 1;
+ for(d=r; d!=D; d=d->forw) {
+ if(d->op != ONAME)
+ continue;
+
+ if(flag) {
+ Bprint(bout, "\n%s// %s variables\n", tab, msg);
+ flag = 0;
+ }
+
+ nam = "???";
+ pkg = nam;
+ s = d->dsym;
+ if(s != S) {
+ nam = s->name;
+ pkg = s->opackage;
+ }
+
+ n = d->dnode;
+ t = n->type;
+ if(n->vargen != 0) {
+if(YYY) print("nam-1 %s\n", nam);
+ Bprint(bout, "%s%C _V_%ld%lC; // %s\n",
+ tab, t, n->vargen, t, nam);
+ continue;
+ }
+
+ if(t->etype == TFUNC && t->thistuple > 0) {
+if(YYY) print("nam-2 %s\n", nam);
+ typ = thistypenam(t);
+ Bprint(bout, "%s%C %s_%s_%s%lC;\n",
+ tab, t, pkg, typ, nam, t);
+ continue;
+ }
+
+if(YYY) print("nam-3 %E %s %lT\n", t->etype, nam, t);
+ Bprint(bout, "%s%C %s_%s%lC;\n",
+ tab, t, pkg, nam, t);
+ }
+}
+
+/*
+ * open the frame
+ * declare dummy this/in/out args
+ */
+void
+docall1(Prog *p)
+{
+ Node *f, *t, *n;
+
+ if(p->addr.type != ANODE)
+ goto bad;
+
+ f = p->addr.node;
+ if(f == N)
+ goto bad;
+ t = f->type;
+ if(t == N)
+ goto bad;
+ if(t->etype == TPTR)
+ t = t->type;
+ if(t->etype != TFUNC)
+ goto bad;
+
+ Bprint(bout, "\t{\n"); // open a block - closed in CALL2/CALL3
+
+ if(t->thistuple > 0) {
+ n = *getthis(t);
+ if(n->nname == N)
+ goto bad;
+ Bprint(bout, "\t\t_T_%ld _V_%ld; // %S\n", n->vargen, n->nname->vargen, n->sym);
+ }
+ if(t->outtuple > 0) {
+ n = *getoutarg(t);
+ if(n->nname == N)
+ goto bad;
+ Bprint(bout, "\t\t_T_%ld _V_%ld; // %S\n", n->vargen, n->nname->vargen, n->sym);
+ }
+ if(t->intuple > 0) {
+ n = *getinarg(t);
+ if(n->nname == N)
+ goto bad;
+ Bprint(bout, "\t\t_T_%ld _V_%ld; // %S\n", n->vargen, n->nname->vargen, n->sym);
+ }
+
+ return;
+
+bad:
+ fatal("docall1: bad %P", p);
+}
+
+/*
+ * call the function
+ */
+void
+docall2(Prog *p)
+{
+ Node *f, *t, *n;
+
+ if(p->addr.type != ANODE)
+ goto bad;
+ f = p->addr.node;
+ if(f == N)
+ goto bad;
+ t = f->type;
+ if(t == N || t->etype != TFUNC)
+ goto bad;
+
+ Bprint(bout, "\t%D(", p);
+
+ if(t->thistuple > 0) {
+ n = *getthis(t);
+ Bprint(bout, "&_V_%ld", n->nname->vargen);
+ } else
+ Bprint(bout, "0");
+
+ if(t->outtuple > 0) {
+ n = *getoutarg(t);
+ Bprint(bout, ", &_V_%ld", n->nname->vargen);
+ } else
+ Bprint(bout, ", 0");
+
+ if(t->intuple > 0) {
+ n = *getinarg(t);
+ Bprint(bout, ", &_V_%ld);\n", n->nname->vargen);
+ } else
+ Bprint(bout, ", 0);\n");
+
+ return;
+
+bad:
+ fatal("docall2: bad");
+}
+
+/*
+ * call the function indirect
+ */
+void
+docalli2(Prog *p)
+{
+ Node *f, *t, *n;
+
+ if(p->addr.type != ANODE)
+ goto bad;
+ f = p->addr.node;
+ if(f == N)
+ goto bad;
+ t = f->type;
+ if(t == N || t->etype != TPTR)
+ goto bad;
+ t = t->type;
+ if(t->etype != TFUNC)
+ goto bad;
+
+ // pass one -- declare the prototype
+ if(t->outtuple > 0) {
+ n = *getoutarg(t);
+ Bprint(bout, "\t(*(void(*)(void*, _T_%ld*", n->vargen);
+ } else
+ Bprint(bout, "\t(*(void(*)(void*, void*");
+
+ if(t->intuple > 0) {
+ n = *getinarg(t);
+ Bprint(bout, ", _T_%ld*)", n->vargen);
+ } else
+ Bprint(bout, ", void*)");
+
+ // pass two -- pass the arguments
+ if(t->outtuple > 0) {
+ n = *getoutarg(t);
+ Bprint(bout, ")%R)(0, &_V_%ld", PTPTR, n->nname->vargen);
+ } else
+ Bprint(bout, ")%R)(0, 0", PTPTR);
+
+ if(t->intuple > 0) {
+ n = *getinarg(t);
+ Bprint(bout, ", &_V_%ld);\n", n->nname->vargen);
+ } else
+ Bprint(bout, ", 0);\n");
+
+ return;
+
+bad:
+ fatal("docalli2: bad");
+}
+
+/*
+ * call the method
+ */
+void
+docallm2(Prog *p)
+{
+ Node *f, *t, *n;
+ char *pkg, *typ, *nam;
+
+ if(p->addr.type != ANODE)
+ goto bad;
+ f = p->addr.node;
+ if(f == N || f->op != ODOTMETH)
+ goto bad;
+ t = f->type;
+ if(t == N || t->etype != TFUNC)
+ goto bad;
+
+ nam = "???";
+ pkg = nam;
+ typ = nam;
+
+ // get the structure name
+ n = f->left;
+ if(n != N)
+ n = n->type;
+ if(n->op == OTYPE && n->etype == TPTR)
+ n = n->type;
+ if(n->sym != S) {
+ typ = n->sym->name;
+ pkg = n->sym->opackage;
+ }
+
+ // get the function name
+ n = f->right;
+ if(n != N && n->op == ONAME && n->sym != S)
+ nam = n->sym->name;
+
+ Bprint(bout, "\t%s_%s_%s(%R", pkg, typ, nam, PTPTR);
+
+ if(t->outtuple > 0) {
+ n = *getoutarg(t);
+ Bprint(bout, ", (void*)&_V_%ld", n->nname->vargen);
+ } else
+ Bprint(bout, ", 0");
+
+ if(t->intuple > 0) {
+ n = *getinarg(t);
+ Bprint(bout, ", (void*)&_V_%ld);\n", n->nname->vargen);
+ } else
+ Bprint(bout, ", 0);\n");
+
+ return;
+
+bad:
+ fatal("docallm2: bad");
+}
+
+/*
+ * call the interface method
+ */
+void
+docallf2(Prog *p)
+{
+ Node *f, *t, *n;
+ int offset;
+
+ if(p->addr.type != ANODE)
+ goto bad;
+ f = p->addr.node;
+ if(f == N || f->op != ODOTINTER)
+ goto bad;
+ t = f->type;
+ if(t == N || t->etype != TFUNC)
+ goto bad;
+
+ offset = 0;
+
+ Bprint(bout, "\t(_U._R_I.m->fun[%d])(_U._R_I.s", f->kaka);
+
+ if(t->outtuple > 0) {
+ n = *getoutarg(t);
+ Bprint(bout, ", (void*)&_V_%ld", n->nname->vargen);
+ } else
+ Bprint(bout, ", 0");
+
+ if(t->intuple > 0) {
+ n = *getinarg(t);
+ Bprint(bout, ", (void*)&_V_%ld);\n", n->nname->vargen);
+ } else
+ Bprint(bout, ", 0);\n");
+
+ return;
+
+bad:
+ fatal("docallf2: bad");
+}
+
+/*
+ * close the frame
+ */
+void
+docall3(Prog *p)
+{
+ Bprint(bout, "\t}\n");
+}
+
+char*
+signame(Node *t)
+{
+// this code sb merged with thistypename
+ static char name[100];
+ char *typ, *pkg;
+
+ typ = "???";
+ pkg = typ;
+
+ if(t == N || t->op != OTYPE)
+ goto out;
+
+ if(t->etype == TPTR) {
+ t = t->type;
+ if(t == N)
+ goto out;
+ }
+ if(t->sym == S)
+ goto out;
+ typ = t->sym->name;
+ pkg = t->sym->opackage; // this may not be correct
+
+out:
+ snprint(name, sizeof(name), "sig_%s_%s", pkg, typ);
+ return name;
+}
+
+void
+doconv(Prog *p)
+{
+ Node *n, *tl, *tr;
+ int l, pt;
+
+ if(p->pt != PTNIL) {
+ Bprint(bout, "\t%R = %R;\n", p->pt, p->pt1);
+ return;
+ }
+
+ n = p->addr.node;
+ if(p->addr.type != ANODE || n == N || n->op != OCONV)
+ fatal("doconv: PCONV-N not OCONV");
+
+ tl = n->left;
+ tr = n->right;
+
+ if(isinter(tl)) {
+ if(isptrto(tr, TSTRUCT)) {
+ Bprint(bout, "\tconvertStoI(%s, ", signame(tl));
+ Bprint(bout, "%s); // _U._R_I = _U._R_P\n",
+ signame(tr));
+ return;
+ }
+ if(isinter(tr)) {
+ Bprint(bout, "\tconvertItoI(%s); // _U._R_I = _U._R_I\n",
+ signame(tl));
+ return;
+ }
+ }
+ if(isptrto(tl, TSTRUCT) && isinter(tr)) {
+ Bprint(bout, "\t%R = %R.s;\n", TPTR, PTINTER);
+ return;
+ }
+ if(isint[tl->etype] || isfloat[tl->etype]) {
+ if(isint[tr->etype] || isfloat[tr->etype]) {
+ Bprint(bout, "\t%R = %R;\n", conv2pt(tl), conv2pt(tr));
+ return;
+ }
+ }
+
+ if(isptrto(tl, TSTRING)) {
+ if(isint[tr->etype]) {
+ Bprint(bout, "\tconvertItoZ(%R);\n", conv2pt(tr));
+ return;
+ }
+ l = isbytearray(tr);
+ if(l > 0) {
+ pt = PTADDR;
+ if(tr->etype == TPTR)
+ pt = TPTR;
+ Bprint(bout, "\tconvertBtoZ(%R, %d);\n", pt, l-1);
+ return;
+ }
+ }
+
+ fatal("doconv: %T = %T", tl, tr);
+}
+
+char*
+getfmt(int pt)
+{
+ switch(pt) {
+ default:
+ return "D";
+
+ case PTUINT8:
+ case PTUINT16:
+ case PTUINT32:
+ case PTUINT64:
+ return "UD";
+
+ case PTFLOAT32:
+ case PTFLOAT64:
+ case PTFLOAT80:
+ return "F";
+
+ case PTSTRING:
+ return "Z";
+ }
+}
--- /dev/null
+// 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
+errorexit(void)
+{
+ if(outfile)
+ remove(outfile);
+ myexit(1);
+}
+
+void
+myexit(int x)
+{
+ if(x)
+ exits("error");
+ exits(nil);
+}
+
+void
+yyerror(char *fmt, ...)
+{
+ va_list arg;
+ long lno;
+
+ lno = dynlineno;
+ if(lno == 0)
+ lno = curio.lineno;
+
+ print("%s:%ld: ", curio.infile, lno);
+ va_start(arg, fmt);
+ vfprint(1, fmt, arg);
+ va_end(arg);
+ print("\n");
+ if(debug['h'])
+ *(int*)0 = 0;
+
+ nerrors++;
+ if(nerrors >= 10)
+ fatal("too many errors");
+}
+
+void
+warn(char *fmt, ...)
+{
+ va_list arg;
+ long lno;
+
+ lno = dynlineno;
+ if(lno == 0)
+ lno = curio.lineno;
+
+ print("%s:%ld: ", curio.infile, lno);
+ va_start(arg, fmt);
+ vfprint(1, fmt, arg);
+ va_end(arg);
+ print("\n");
+ if(debug['h'])
+ *(int*)0 = 0;
+}
+
+void
+fatal(char *fmt, ...)
+{
+ va_list arg;
+ long lno;
+
+ lno = dynlineno;
+ if(lno == 0)
+ lno = curio.lineno;
+
+ print("%s:%ld: fatal error: ", curio.infile, lno);
+ va_start(arg, fmt);
+ vfprint(1, fmt, arg);
+ va_end(arg);
+ print("\n");
+ if(debug['h'])
+ *(int*)0 = 0;
+ myexit(1);
+}
+
+ulong
+stringhash(char *p)
+{
+ long h;
+ int c;
+
+ h = 0;
+ for(;;) {
+ c = *p++;
+ if(c == 0)
+ break;
+ h = h*PRIME1 + c;
+ }
+
+ if(h < 0) {
+ h = -h;
+ if(h < 0)
+ h = 0;
+ }
+ return h;
+}
+
+Sym*
+lookup(char *p)
+{
+ Sym *s;
+ ulong h;
+ int c;
+
+ h = stringhash(p) % NHASH;
+ c = p[0];
+
+ for(s = hash[h]; s != S; s = s->link) {
+ if(s->name[0] != c)
+ continue;
+ if(strcmp(s->name, p) == 0)
+ if(strcmp(s->package, package) == 0)
+ return s;
+ }
+
+ s = mal(sizeof(*s));
+ s->lexical = LNAME;
+ s->name = mal(strlen(p)+1);
+ s->opackage = package;
+ s->package = package;
+
+ strcpy(s->name, p);
+
+ s->link = hash[h];
+ hash[h] = s;
+
+ return s;
+}
+
+Sym*
+pkglookup(char *p, char *k)
+{
+ Sym *s;
+ ulong h;
+ int c;
+
+ h = stringhash(p) % NHASH;
+ c = p[0];
+ for(s = hash[h]; s != S; s = s->link) {
+ if(s->name[0] != c)
+ continue;
+ if(strcmp(s->name, p) == 0)
+ if(strcmp(s->package, k) == 0)
+ return s;
+ }
+
+ s = mal(sizeof(*s));
+ s->lexical = LNAME;
+ s->name = mal(strlen(p)+1);
+ strcpy(s->name, p);
+
+ s->package = mal(strlen(k)+1);
+ s->opackage = s->package;
+ strcpy(s->package, k);
+
+ s->link = hash[h];
+ hash[h] = s;
+
+ return s;
+}
+
+void
+gethunk(void)
+{
+ char *h;
+ long nh;
+
+ nh = NHUNK;
+ if(thunk >= 10L*NHUNK)
+ nh = 10L*NHUNK;
+ h = (char*)malloc(nh);
+ if(h == (char*)-1) {
+ yyerror("out of memory");
+ errorexit();
+ }
+ hunk = h;
+ nhunk = nh;
+ thunk += nh;
+}
+
+void*
+mal(long n)
+{
+ void *p;
+
+ while((ulong)hunk & MAXALIGN) {
+ hunk++;
+ nhunk--;
+ }
+ while(nhunk < n)
+ gethunk();
+
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+remal(void *p, long on, long n)
+{
+ void *q;
+
+ q = (uchar*)p + on;
+ if(q != hunk || nhunk < n) {
+ while(nhunk < on+n)
+ gethunk();
+ memmove(hunk, p, on);
+ p = hunk;
+ hunk += on;
+ nhunk -= on;
+ }
+ hunk += n;
+ nhunk -= n;
+ return p;
+}
+
+Dcl*
+dcl(void)
+{
+ Dcl *d;
+
+ d = mal(sizeof(*d));
+ d->lineno = dynlineno;
+ return d;
+}
+
+Node*
+nod(int op, Node *nleft, Node *nright)
+{
+ Node *n;
+
+ n = mal(sizeof(*n));
+ n->op = op;
+ n->left = nleft;
+ n->right = nright;
+ n->lineno = dynlineno;
+ if(dynlineno == 0)
+ n->lineno = curio.lineno;
+ return n;
+}
+
+Node*
+dobad(void)
+{
+ return nod(OBAD, N, N);
+}
+
+Node*
+rev(Node *na)
+{
+ Node *i, *n;
+
+ /*
+ * since yacc wants to build lists
+ * stacked down on the left -
+ * this routine converts them to
+ * stack down on the right -
+ * in memory without recursion
+ */
+
+ if(na == N || na->op != OLIST)
+ return na;
+ i = na;
+ for(n = na->left; n != N; n = n->left) {
+ if(n->op != OLIST)
+ break;
+ i->left = n->right;
+ n->right = i;
+ i = n;
+ }
+ i->left = n;
+ return i;
+}
+
+Node*
+unrev(Node *na)
+{
+ Node *i, *n;
+
+ /*
+ * this restores a reverse list
+ */
+ if(na == N || na->op != OLIST)
+ return na;
+ i = na;
+ for(n = na->right; n != N; n = n->right) {
+ if(n->op != OLIST)
+ break;
+ i->right = n->left;
+ n->left = i;
+ i = n;
+ }
+ i->right = n;
+ return i;
+}
+
+Node*
+aindex(Node *b, Node *t)
+{
+ Node *r;
+
+ r = nod(OTYPE, N, N);
+ r->type = t;
+ r->etype = TARRAY;
+
+ if(t->etype == TDARRAY)
+ yyerror("dynamic array type cannot be a dynamic array");
+
+ walktype(b, 0);
+ switch(whatis(b)) {
+ default:
+ yyerror("array bound must be a constant integer expression");
+ break;
+
+ case Wnil: // default zero lb
+ r->bound = 0;
+ break;
+
+ case Wlitint: // fixed lb
+ r->bound = b->val.vval;
+ break;
+ }
+ return r;
+}
+
+void
+indent(int dep)
+{
+ int i;
+
+ for(i=0; i<dep; i++)
+ print(". ");
+}
+
+void
+dodump(Node *n, int dep)
+{
+
+loop:
+ if(n == N)
+ return;
+
+ switch(n->op) {
+ case OLIST:
+ if(n->left != N && n->left->op == OLIST)
+ dodump(n->left, dep+1);
+ else
+ dodump(n->left, dep);
+ n = n->right;
+ goto loop;
+
+ case ODCLFUNC:
+ dodump(n->nname, dep);
+ if(n->this) {
+ indent(dep);
+ print("%O-this\n", n->op);
+ dodump(n->this, dep+1);
+ }
+ if(n->argout) {
+ indent(dep);
+ print("%O-outarg\n", n->op);
+ dodump(n->argout, dep+1);
+ }
+ if(n->argin) {
+ indent(dep);
+ print("%O-inarg\n", n->op);
+ dodump(n->argin, dep+1);
+ }
+ n = n->nbody;
+ goto loop;
+
+ case OIF:
+ case OSWITCH:
+ case OFOR:
+ dodump(n->ninit, dep);
+ break;
+ }
+
+ indent(dep);
+ if(dep > 10) {
+ print("...\n");
+ return;
+ }
+
+ switch(n->op) {
+ default:
+ print("%N\n", n);
+ break;
+
+ case OTYPE:
+ print("%O-%E %lT\n", n->op, n->etype, n);
+ break;
+
+ case OIF:
+ print("%O%J\n", n->op, n);
+ dodump(n->ntest, dep+1);
+ if(n->nbody != N) {
+ indent(dep);
+ print("%O-then\n", n->op);
+ dodump(n->nbody, dep+1);
+ }
+ if(n->nelse != N) {
+ indent(dep);
+ print("%O-else\n", n->op);
+ dodump(n->nelse, dep+1);
+ }
+ return;
+
+ case OSWITCH:
+ case OFOR:
+ print("%O%J\n", n->op, n);
+ dodump(n->ntest, dep+1);
+
+ if(n->nbody != N) {
+ indent(dep);
+ print("%O-body\n", n->op);
+ dodump(n->nbody, dep+1);
+ }
+
+ if(n->nincr != N) {
+ indent(dep);
+ print("%O-incr\n", n->op);
+ dodump(n->nincr, dep+1);
+ }
+ return;
+
+ case OCASE:
+ // the right side points to the next case
+ print("%O%J\n", n->op, n);
+ dodump(n->left, dep+1);
+ return;
+ }
+
+ dodump(n->left, dep+1);
+ n = n->right;
+ dep++;
+ goto loop;
+}
+
+void
+dump(char *s, Node *n)
+{
+ print("%s\n", s);
+ dodump(n, 1);
+}
+
+int
+whatis(Node *n)
+{
+ Node *t;
+
+ if(n == N)
+ return Wnil;
+
+ if(n->op == OLITERAL) {
+ switch(n->val.ctype) {
+ default:
+ break;
+ case CTINT:
+ case CTSINT:
+ case CTUINT:
+ return Wlitint;
+ case CTFLT:
+ return Wlitfloat;
+ case CTBOOL:
+ return Wlitbool;
+ case CTSTR:
+ return Wlitstr;
+ }
+ return Wtunkn;
+ }
+
+ t = n->type;
+ if(t == N)
+ return Wtnil;
+
+ switch(t->etype) {
+ case TINT8:
+ case TINT16:
+ case TINT32:
+ case TINT64:
+ case TUINT8:
+ case TUINT16:
+ case TUINT32:
+ case TUINT64:
+ return Wtint;
+ case TFLOAT32:
+ case TFLOAT64:
+ case TFLOAT80:
+ return Wtfloat;
+ case TBOOL:
+ return Wtbool;
+
+ case TPTR:
+ if(isptrto(t, TSTRING))
+ return Wtstr;
+ break;
+ }
+ return Wtunkn;
+}
+
+/*
+s%,%,\n%g
+s%\n+%\n%g
+s%^[ ]*O%%g
+s%,.*%%g
+s%.+% [O&] = "&",%g
+s%^ ........*\]%&~%g
+s%~ %%g
+*/
+
+static char*
+opnames[] =
+{
+ [OADDR] = "ADDR",
+ [OADD] = "ADD",
+ [OANDAND] = "ANDAND",
+ [OAND] = "AND",
+ [OARRAY] = "ARRAY",
+ [OASOP] = "ASOP",
+ [OAS] = "AS",
+ [OBAD] = "BAD",
+ [OBREAK] = "BREAK",
+ [OCALL] = "CALL",
+ [OCALLPTR] = "CALLPTR",
+ [OCALLMETH] = "CALLMETH",
+ [OCALLINTER] = "CALLINTER",
+ [OCAT] = "CAT",
+ [OCASE] = "CASE",
+ [OXCASE] = "XCASE",
+ [OFALL] = "FALL",
+ [OCONV] = "CONV",
+ [OCOLAS] = "COLAS",
+ [OCOM] = "COM",
+ [OCONST] = "CONST",
+ [OCONTINUE] = "CONTINUE",
+ [ODCLARG] = "DCLARG",
+ [ODCLCONST] = "DCLCONST",
+ [ODCLFIELD] = "DCLFIELD",
+ [ODCLFUNC] = "DCLFUNC",
+ [ODCLTYPE] = "DCLTYPE",
+ [ODCLVAR] = "DCLVAR",
+ [ODIV] = "DIV",
+ [ODOT] = "DOT",
+ [ODOTPTR] = "DOTPTR",
+ [ODOTMETH] = "DOTMETH",
+ [ODOTINTER] = "DOTINTER",
+ [OEMPTY] = "EMPTY",
+ [OEND] = "END",
+ [OEQ] = "EQ",
+ [OFOR] = "FOR",
+ [OFUNC] = "FUNC",
+ [OGE] = "GE",
+ [OPROC] = "PROC",
+ [OGOTO] = "GOTO",
+ [OGT] = "GT",
+ [OIF] = "IF",
+ [OINDEX] = "INDEX",
+ [OINDEXPTR] = "INDEXPTR",
+ [OINDEXSTR] = "INDEXSTR",
+ [OINDEXMAP] = "INDEXMAP",
+ [OINDEXPTRMAP] = "INDEXPTRMAP",
+ [OIND] = "IND",
+ [OLABEL] = "LABEL",
+ [OLE] = "LE",
+ [OLEN] = "LEN",
+ [OLIST] = "LIST",
+ [OLITERAL] = "LITERAL",
+ [OLSH] = "LSH",
+ [OLT] = "LT",
+ [OMINUS] = "MINUS",
+ [OMOD] = "MOD",
+ [OMUL] = "MUL",
+ [ONAME] = "NAME",
+ [ONE] = "NE",
+ [ONOT] = "NOT",
+ [OOROR] = "OROR",
+ [OOR] = "OR",
+ [OPLUS] = "PLUS",
+ [ODEC] = "DEC",
+ [OINC] = "INC",
+ [OSEND] = "SEND",
+ [ORECV] = "RECV",
+ [OPTR] = "PTR",
+ [ORETURN] = "RETURN",
+ [ORSH] = "RSH",
+ [OSLICE] = "SLICE",
+ [OSUB] = "SUB",
+ [OSWITCH] = "SWITCH",
+ [OTYPE] = "TYPE",
+ [OVAR] = "VAR",
+ [OEXPORT] = "EXPORT",
+ [OIMPORT] = "IMPORT",
+ [OXOR] = "XOR",
+ [ONEW] = "NEW",
+ [OFALL] = "FALL",
+ [OXFALL] = "XFALL",
+ [OPANIC] = "PANIC",
+ [OPRINT] = "PRINT",
+ [OXXX] = "XXX",
+};
+
+int
+Oconv(Fmt *fp)
+{
+ char buf[500];
+ int o;
+
+ o = va_arg(fp->args, int);
+ if(o < 0 || o >= nelem(opnames) || opnames[o] == nil) {
+ snprint(buf, sizeof(buf), "O-%d", o);
+ return fmtstrcpy(fp, buf);
+ }
+ return fmtstrcpy(fp, opnames[o]);
+}
+
+/*
+s%,%,\n%g
+s%\n+%\n%g
+s%^[ ]*T%%g
+s%,.*%%g
+s%.+% [T&] = "&",%g
+s%^ ........*\]%&~%g
+s%~ %%g
+*/
+
+static char*
+etnames[] =
+{
+ [TINT8] = "INT8",
+ [TUINT8] = "UINT8",
+ [TINT16] = "INT16",
+ [TUINT16] = "UINT16",
+ [TINT32] = "INT32",
+ [TUINT32] = "UINT32",
+ [TINT64] = "INT64",
+ [TUINT64] = "UINT64",
+ [TFLOAT32] = "FLOAT32",
+ [TFLOAT64] = "FLOAT64",
+ [TFLOAT80] = "FLOAT80",
+ [TBOOL] = "BOOL",
+ [TPTR] = "PTR",
+ [TFUNC] = "FUNC",
+ [TARRAY] = "ARRAY",
+ [TDARRAY] = "DARRAY",
+ [TSTRUCT] = "STRUCT",
+ [TCHAN] = "CHAN",
+ [TMAP] = "MAP",
+ [TINTER] = "INTER",
+ [TFORW] = "FORW",
+ [TFIELD] = "FIELD",
+ [TSTRING] = "STRING",
+ [TCHAN] = "CHAN",
+};
+
+int
+Econv(Fmt *fp)
+{
+ char buf[500];
+ int et;
+
+ et = va_arg(fp->args, int);
+ if(et < 0 || et >= nelem(etnames) || etnames[et] == nil) {
+ snprint(buf, sizeof(buf), "E-%d", et);
+ return fmtstrcpy(fp, buf);
+ }
+ return fmtstrcpy(fp, etnames[et]);
+}
+
+int
+Jconv(Fmt *fp)
+{
+ char buf[500], buf1[100];
+ Node *n;
+
+ n = va_arg(fp->args, Node*);
+ strcpy(buf, "");
+
+ if(n->ullman != 0) {
+ snprint(buf1, sizeof(buf1), " u(%d)", n->ullman);
+ strncat(buf, buf1, sizeof(buf));
+ }
+
+ if(n->addable != 0) {
+ snprint(buf1, sizeof(buf1), " a(%d)", n->addable);
+ strncat(buf, buf1, sizeof(buf));
+ }
+
+ if(n->vargen != 0) {
+ snprint(buf1, sizeof(buf1), " g(%ld)", n->vargen);
+ strncat(buf, buf1, sizeof(buf));
+ }
+
+ if(n->lineno != 0) {
+ snprint(buf1, sizeof(buf1), " l(%ld)", n->lineno);
+ strncat(buf, buf1, sizeof(buf));
+ }
+
+ return fmtstrcpy(fp, buf);
+}
+
+int
+Gconv(Fmt *fp)
+{
+ char buf[100];
+ Node *t;
+
+ t = va_arg(fp->args, Node*);
+
+ if(t->etype == TFUNC) {
+ if(t->vargen != 0) {
+ snprint(buf, sizeof(buf), "-%d%d%d g(%ld)",
+ t->thistuple, t->outtuple, t->intuple, t->vargen);
+ goto out;
+ }
+ snprint(buf, sizeof(buf), "-%d%d%d",
+ t->thistuple, t->outtuple, t->intuple);
+ goto out;
+ }
+ if(t->vargen != 0) {
+ snprint(buf, sizeof(buf), " g(%ld)", t->vargen);
+ goto out;
+ }
+ strcpy(buf, "");
+
+out:
+ return fmtstrcpy(fp, buf);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ char buf[500];
+ Sym *s;
+ char *opk, *pkg, *nam;
+
+ s = va_arg(fp->args, Sym*);
+ if(s == S) {
+ snprint(buf, sizeof(buf), "<S>");
+ goto out;
+ }
+
+ pkg = "<nil>";
+ nam = pkg;
+ opk = pkg;
+
+ if(s->opackage != nil)
+ opk = s->opackage;
+ if(s->package != nil)
+ pkg = s->package;
+ if(s->name != nil)
+ nam = s->name;
+
+ if(strcmp(pkg, package) || strcmp(opk, package) || (fp->flags & FmtLong)) {
+ if(strcmp(opk, pkg) == 0) {
+ snprint(buf, sizeof(buf), "%s.%s", pkg, nam);
+ goto out;
+ }
+ snprint(buf, sizeof(buf), "(%s)%s.%s", opk, pkg, nam);
+ goto out;
+ }
+ snprint(buf, sizeof(buf), "%s", nam);
+
+out:
+ return fmtstrcpy(fp, buf);
+}
+
+int
+Tconv(Fmt *fp)
+{
+ char buf[500], buf1[500];
+ Node *t, *t1;
+ int et;
+
+ t = va_arg(fp->args, Node*);
+ if(t == N)
+ return fmtstrcpy(fp, "<T>");
+
+ t->trecur++;
+ if(t->op != OTYPE) {
+ snprint(buf, sizeof(buf), "T-%O", t->op);
+ goto out;
+ }
+ et = t->etype;
+
+ strcpy(buf, "");
+ if(t->sym != S) {
+ snprint(buf, sizeof(buf), "<%S>", t->sym);
+ }
+ if(t->trecur > 5) {
+ strncat(buf, "...", sizeof(buf));
+ goto out;
+ }
+
+ switch(et) {
+ default:
+ snprint(buf1, sizeof(buf1), "%E", et);
+ strncat(buf, buf1, sizeof(buf));
+ if(t->type != N) {
+ snprint(buf1, sizeof(buf1), " %T", t->type);
+ strncat(buf, buf1, sizeof(buf));
+ }
+ break;
+
+ case TFIELD:
+ snprint(buf1, sizeof(buf1), "%T", t->type);
+ strncat(buf, buf1, sizeof(buf));
+ break;
+
+ case TFUNC:
+ snprint(buf1, sizeof(buf1), "%d%d%d(%lT,%lT,%lT)",
+ t->thistuple, t->outtuple, t->intuple,
+ t->type, t->type->down, t->type->down->down);
+ strncat(buf, buf1, sizeof(buf));
+ break;
+
+ case TINTER:
+ strncat(buf, "I{", sizeof(buf));
+ if(fp->flags & FmtLong) {
+ for(t1=t->type; t1!=N; t1=t1->down) {
+ snprint(buf1, sizeof(buf1), "%T;", t1);
+ strncat(buf, buf1, sizeof(buf));
+ }
+ }
+ strncat(buf, "}", sizeof(buf));
+ break;
+
+ case TSTRUCT:
+ strncat(buf, "{", sizeof(buf));
+ if(fp->flags & FmtLong) {
+ for(t1=t->type; t1!=N; t1=t1->down) {
+ snprint(buf1, sizeof(buf1), "%T;", t1);
+ strncat(buf, buf1, sizeof(buf));
+ }
+ }
+ strncat(buf, "}", sizeof(buf));
+ break;
+
+ case TMAP:
+ snprint(buf, sizeof(buf), "[%T]%T", t->down, t->type);
+ break;
+
+ case TARRAY:
+ snprint(buf1, sizeof(buf1), "[%ld]%T", t->bound, t->type);
+ strncat(buf, buf1, sizeof(buf));
+ break;
+
+ case TDARRAY:
+ snprint(buf1, sizeof(buf1), "[]%T", t->type);
+ strncat(buf, buf1, sizeof(buf));
+ break;
+
+ case TPTR:
+ snprint(buf1, sizeof(buf1), "*%T", t->type);
+ strncat(buf, buf1, sizeof(buf));
+ break;
+ }
+
+out:
+ t->trecur--;
+ return fmtstrcpy(fp, buf);
+}
+
+int
+Nconv(Fmt *fp)
+{
+ char buf[500], buf1[500];
+ Node *n;
+
+ n = va_arg(fp->args, Node*);
+ if(n == N) {
+ snprint(buf, sizeof(buf), "<N>");
+ goto out;
+ }
+
+ switch(n->op) {
+ default:
+ snprint(buf, sizeof(buf), "%O%J", n->op, n);
+ break;
+
+ case ONAME:
+ if(n->sym == S) {
+ snprint(buf, sizeof(buf), "%O%J", n->op, n);
+ break;
+ }
+ snprint(buf, sizeof(buf), "%O-%S G%ld%J", n->op,
+ n->sym, n->sym->vargen, n);
+ goto ptyp;
+
+ case OLITERAL:
+ switch(n->val.ctype) {
+ default:
+ snprint(buf1, sizeof(buf1), "LITERAL-%d", n->val.ctype);
+ break;
+ case CTINT:
+ snprint(buf1, sizeof(buf1), "I%lld", n->val.vval);
+ break;
+ case CTSINT:
+ snprint(buf1, sizeof(buf1), "S%lld", n->val.vval);
+ break;
+ case CTUINT:
+ snprint(buf1, sizeof(buf1), "U%lld", n->val.vval);
+ break;
+ case CTFLT:
+ snprint(buf1, sizeof(buf1), "F%g", n->val.dval);
+ break;
+ case CTSTR:
+ snprint(buf1, sizeof(buf1), "S\"%Z\"", n->val.sval);
+ break;
+ case CTBOOL:
+ snprint(buf1, sizeof(buf1), "B%lld", n->val.vval);
+ break;
+ case CTNIL:
+ snprint(buf1, sizeof(buf1), "N");
+ break;
+ }
+ snprint(buf, sizeof(buf1), "%O-%s%J", n->op, buf1, n);
+ break;
+
+ case OASOP:
+ snprint(buf, sizeof(buf), "%O-%O%J", n->op, n->kaka, n);
+ break;
+
+ case OTYPE:
+ snprint(buf, sizeof(buf), "%O-%E%J", n->op, n->etype, n);
+ break;
+ }
+ if(n->sym != S) {
+ snprint(buf1, sizeof(buf1), " %S G%ld", n->sym, n->sym->vargen);
+ strncat(buf, buf1, sizeof(buf));
+ }
+
+ptyp:
+ if(n->type != N) {
+ snprint(buf1, sizeof(buf1), " %T", n->type);
+ strncat(buf, buf1, sizeof(buf));
+ }
+
+out:
+ return fmtstrcpy(fp, buf);
+}
+
+int
+Zconv(Fmt *fp)
+{
+ uchar *s, *se;
+ char *p;
+ char buf[500];
+ int c;
+ String *sp;
+
+ sp = va_arg(fp->args, String*);
+ if(sp == nil) {
+ snprint(buf, sizeof(buf), "<nil>");
+ goto out;
+ }
+ s = sp->s;
+ se = s + sp->len;
+
+ p = buf;
+
+loop:
+ c = *s++;
+ if(s > se)
+ c = 0;
+ switch(c) {
+ default:
+ *p++ = c;
+ break;
+ case 0:
+ *p = 0;
+ goto out;
+ case '\t':
+ *p++ = '\\';
+ *p++ = 't';
+ break;
+ case '\n':
+ *p++ = '\\';
+ *p++ = 'n';
+ break;
+ }
+ goto loop;
+
+out:
+ return fmtstrcpy(fp, buf);
+}
+
+int
+isptrto(Node *t, int et)
+{
+ if(t == N)
+ return 0;
+ if(t->etype != TPTR)
+ return 0;
+ t = t->type;
+ if(t == N)
+ return 0;
+ if(t->etype != et)
+ return 0;
+ return 1;
+}
+
+int
+isinter(Node *t)
+{
+ if(t != N && t->etype == TINTER)
+ return 1;
+ return 0;
+}
+
+int
+isbytearray(Node *t)
+{
+ if(t == N)
+ return 0;
+ if(t->etype == TPTR) {
+ t = t->type;
+ if(t == N)
+ return 0;
+ }
+ if(t->etype != TARRAY)
+ return 0;
+ return t->bound+1;
+}
+
+int
+eqtype(Node *t1, Node *t2, int d)
+{
+ if(d >= 10)
+ return 1;
+
+ if(t1 == t2)
+ return 1;
+ if(t1 == N || t2 == N)
+ return 0;
+ if(t1->op != OTYPE || t2->op != OTYPE)
+ fatal("eqtype: oops %O %O", t1->op, t2->op);
+
+ if(t1->etype != t2->etype)
+ return 0;
+
+ switch(t1->etype) {
+ case TINTER:
+ case TSTRUCT:
+ t1 = t1->type;
+ t2 = t2->type;
+ for(;;) {
+ if(!eqtype(t1, t2, 0))
+ return 0;
+ if(t1 == N)
+ return 1;
+ if(t1->nname != N && t1->nname->sym != S) {
+ if(t2->nname == N || t2->nname->sym == S)
+ return 0;
+ if(strcmp(t1->nname->sym->name, t2->nname->sym->name) != 0)
+ return 0;
+ }
+ t1 = t1->down;
+ t2 = t2->down;
+ }
+ return 1;
+
+ case TFUNC:
+ t1 = t1->type;
+ t2 = t2->type;
+ 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;
+ }
+ return eqtype(t1->type, t2->type, d+1);
+}
+
+ulong
+typehash(Node *at, int d)
+{
+ ulong h;
+ Node *t;
+
+ if(at == N)
+ return PRIME2;
+ if(d >= 5)
+ return PRIME3;
+
+ if(at->op != OTYPE)
+ fatal("typehash: oops %O", at->op);
+
+ if(at->recur)
+ return 0;
+ at->recur = 1;
+
+ h = at->etype*PRIME4;
+
+ switch(at->etype) {
+ default:
+ h += PRIME5 * typehash(at->type, d+1);
+ break;
+
+ case TINTER:
+ // botch -- should be sorted?
+ for(t=at->type; t!=N; t=t->down)
+ h += PRIME6 * typehash(t, d+1);
+ break;
+
+ case TSTRUCT:
+ for(t=at->type; t!=N; t=t->down)
+ h += PRIME7 * typehash(t, d+1);
+ break;
+
+ case TFUNC:
+ t = at->type;
+ // skip this argument
+ if(t != N)
+ t = t->down;
+ for(; t!=N; t=t->down)
+ h += PRIME7 * typehash(t, d+1);
+ break;
+ }
+
+ at->recur = 0;
+ return h;
+}
+
+Node*
+ptrto(Node *t)
+{
+ Node *p;
+
+ p = nod(OTYPE, N, N);
+ p->etype = TPTR;
+ p->type = t;
+ return p;
+}
+
+Node*
+literal(long v)
+{
+ Node *n;
+
+ n = nod(OLITERAL, N, N);
+ n->val.ctype = CTINT;
+ n->val.vval = v;
+ return n;
+}
+
+void
+frame(int context)
+{
+ char *p;
+ Dcl *d;
+ int flag;
+
+ p = "stack";
+ d = autodcl;
+ if(context) {
+ p = "external";
+ d = externdcl;
+ }
+
+ flag = 1;
+ for(; d!=D; d=d->forw) {
+ switch(d->op) {
+ case ONAME:
+ if(flag)
+ print("--- %s frame ---\n", p);
+ print("%O %S G%ld T\n", d->op, d->dsym, d->dnode->vargen, d->dnode->type);
+ flag = 0;
+ break;
+
+ case OTYPE:
+ if(flag)
+ print("--- %s frame ---\n", p);
+ print("%O %lT\n", d->op, d->dnode);
+ flag = 0;
+ break;
+ }
+ }
+}
+
+/*
+ * calculate sethi/ullman number
+ * roughly how many registers needed to
+ * compile a node. used to compile the
+ * hardest side first to minimize registers.
+ */
+void
+ullmancalc(Node *n)
+{
+ int ul, ur;
+
+ if(n == N)
+ return;
+
+ switch(n->op) {
+ case OLITERAL:
+ case ONAME:
+ ul = 0;
+ goto out;
+ case OCALL:
+ ul = UINF;
+ goto out;
+ }
+ ul = 0;
+ if(n->left != N)
+ ul = n->left->ullman;
+ ur = 0;
+ if(n->right != N)
+ ur = n->right->ullman;
+ if(ul == ur)
+ ul += 1;
+ if(ur > ul)
+ ul = ur;
+
+out:
+ n->ullman = ul;
+}
+
+void
+badtype(int o, Node *tl, Node *tr)
+{
+ yyerror("illegal types for operand");
+ if(tl != N)
+ print(" (%T)", tl);
+ print(" %O ", o);
+ if(tr != N)
+ print("(%T)", tr);
+ print("\n");
+}
+
+/*
+ * this routine gets the parsing of
+ * a parameter list that can have
+ * name, type and name-type.
+ * it must distribute lone names
+ * with trailing types to give every
+ * name a type. (a,b,c int) comes out
+ * (a int, b int, c int).
+ */
+Node*
+cleanidlist(Node *r)
+{
+ Node *t, *l, *n, *nn;
+
+ t = N; // untyped name
+ nn = r; // next node to take
+
+loop:
+ n = nn;
+ if(n == N) {
+ if(t != N) {
+ yyerror("syntax error in parameter list");
+ l = types[TINT32];
+ goto distrib;
+ }
+ return r;
+ }
+
+ l = n;
+ nn = N;
+ if(l->op == OLIST) {
+ nn = l->right;
+ l = l->left;
+ }
+
+ if(l->op != ODCLFIELD)
+ fatal("cleanformal: %O", n->op);
+
+ if(l->type == N) {
+ if(t == N)
+ t = n;
+ goto loop;
+ }
+
+ if(t == N)
+ goto loop;
+
+ l = l->type; // type to be distributed
+
+distrib:
+ while(t != n) {
+ if(t->op != OLIST) {
+ if(t->type == N)
+ t->type = l;
+ break;
+ }
+ if(t->left->type == N)
+ t->left->type = l;
+ t = t->right;
+ }
+
+ t = N;
+ goto loop;
+}
+
+/*
+ * iterator to walk a structure declaration
+ */
+Node*
+structfirst(Iter *s, Node **nn)
+{
+ Node *r, *n;
+
+ n = *nn;
+ if(n == N || n->op != OTYPE)
+ goto bad;
+
+ switch(n->etype) {
+ default:
+ goto bad;
+
+ case TSTRUCT:
+ case TINTER:
+ case TFUNC:
+ break;
+ }
+
+ r = n->type;
+ if(r == N)
+ goto rnil;
+
+ if(r->op != OTYPE || r->etype != TFIELD)
+ fatal("structfirst: not field %N", r);
+
+ s->n = r;
+ return r;
+
+bad:
+ fatal("structfirst: not struct %N", n);
+
+rnil:
+ return N;
+}
+
+Node*
+structnext(Iter *s)
+{
+ Node *n, *r;
+
+ n = s->n;
+ r = n->down;
+ if(r == N)
+ goto rnil;
+
+ if(r->op != OTYPE || r->etype != TFIELD)
+ goto bad;
+
+ s->n = r;
+ return r;
+
+bad:
+ fatal("structnext: not struct %N", n);
+
+rnil:
+ return N;
+}
+
+/*
+ * iterator to walk a list
+ */
+Node*
+listfirst(Iter *s, Node **nn)
+{
+ Node *n;
+
+ n = *nn;
+ if(n == N) {
+ s->done = 1;
+ s->an = &s->n;
+ s->n = N;
+ return N;
+ }
+
+ if(n->op == OLIST) {
+ s->done = 0;
+ s->n = n;
+ s->an = &n->left;
+ return n->left;
+ }
+
+ s->done = 1;
+ s->an = nn;
+ return n;
+}
+
+Node*
+listnext(Iter *s)
+{
+ Node *n, *r;
+
+ if(s->done) {
+ s->an = &s->n;
+ s->n = N;
+ return N;
+ }
+
+ n = s->n;
+ r = n->right;
+ if(r->op == OLIST) {
+ s->n = r;
+ s->an = &r->left;
+ return r->left;
+ }
+
+ s->done = 1;
+ s->an = &n->right;
+ return n->right;
+}
+
+Node**
+getthis(Node *t)
+{
+ if(t->etype != TFUNC)
+ fatal("getthis: not a func %N", t);
+ return &t->type;
+}
+
+Node**
+getoutarg(Node *t)
+{
+ if(t->etype != TFUNC)
+ fatal("getoutarg: not a func %N", t);
+ return &t->type->down;
+}
+
+Node**
+getinarg(Node *t)
+{
+ if(t->etype != TFUNC)
+ fatal("getinarg: not a func %N", t);
+ return &t->type->down->down;
+}
+
+Node*
+getthisx(Node *t)
+{
+ return *getthis(t);
+}
+
+Node*
+getoutargx(Node *t)
+{
+ return *getoutarg(t);
+}
+
+Node*
+getinargx(Node *t)
+{
+ return *getinarg(t);
+}
--- /dev/null
+
+
+/*
+ * automatic code generated from
+ * test.go in package "test"
+ */
+
+// basic types
+typedef unsigned char _T_U8;
+typedef signed char _T_I8;
+typedef unsigned short _T_U16;
+typedef signed short _T_I16;
+typedef unsigned long _T_U32;
+typedef signed long _T_I32;
+typedef unsigned long long _T_U64;
+typedef signed long long _T_I64;
+typedef float _T_F32;
+typedef double _T_F64;
+typedef double _T_F80;
+typedef int _T_B;
+typedef unsigned char* _T_P;
+
+#define offsetof(s, m) (_T_U32)(&(((s*)0)->m))
+
+typedef struct{_T_U32 I1; _T_U32 I2; _T_U32 I3;} _T_I;
+typedef struct{_T_U32 O1; _T_U32 O2;} _T_O;
+
+void test_main(void);
+_T_O test_simple(_T_I);
+int printf(char*, ...);
+
+// external variables
+
+void
+test_main(void)
+{
+
+ // registers
+ register union
+ {
+ _T_U8 _R_U8;
+ _T_I8 _R_I8;
+ _T_U16 _R_U16;
+ _T_I16 _R_I16;
+ _T_U32 _R_U32;
+ _T_I32 _R_I32;
+ _T_U64 _R_U64;
+ _T_I64 _R_I64;
+ _T_F32 _R_F32;
+ _T_F64 _R_F64;
+ _T_F80 _R_F80;
+ _T_B _R_B;
+ _T_P _R_P;
+ } _U;
+
+ // local variables
+ _T_I32 _V_3; // x
+ _T_I32 _V_4; // y
+
+ {
+ _T_I I;
+ _T_O O;
+ I.I1 = 10;
+ I.I2 = 20;
+ I.I3 = 30;
+ O = test_simple(I);
+ _V_3 = O.O1;
+ _V_4 = O.O2;
+ }
+
+ // 1 7 LOAD_I32 NAME a(1) p(3) l(7) x G0 INT32
+ _U._R_I32 = _V_3;
+
+ // 2 10 CMP_I32 I15 LITERAL a(1) l(10) INT32
+ if(_U._R_I32 == 15)
+
+ // 3 10 BEQ_I32 4
+ goto _L4;
+
+ printf("no 1 %d\n", _V_3);
+
+ // 4 7 LOAD_I32 NAME a(1) p(4) l(7) y G0 INT32
+_L4:
+ _U._R_I32 = _V_4;
+
+ // 5 11 CMP_I32 I50 LITERAL a(1) l(11) INT32
+ if(_U._R_I32 == 50)
+
+ // 6 11 BEQ_I32 7
+ goto _L7;
+
+ printf("no 2 %d\n", _V_4);
+
+ // 7 0 END
+_L7:
+ ;
+}
+
+_T_O
+test_simple(_T_I I)
+{
+
+ // registers
+ register union
+ {
+ _T_U8 _R_U8;
+ _T_I8 _R_I8;
+ _T_U16 _R_U16;
+ _T_I16 _R_I16;
+ _T_U32 _R_U32;
+ _T_I32 _R_I32;
+ _T_U64 _R_U64;
+ _T_I64 _R_I64;
+ _T_F32 _R_F32;
+ _T_F64 _R_F64;
+ _T_F80 _R_F80;
+ _T_B _R_B;
+ _T_P _R_P;
+ } _U;
+
+ _T_O O;
+
+ int ia, ib, ic;
+ ia = I.I1;
+ ib = I.I2;
+ ic = I.I3;
+
+ O.O1 = ia+5;
+ O.O2 = ib+ic;
+ return O;
+}
+
+int
+main(void)
+{
+ test_main();
+ return 0;
+}
--- /dev/null
+// 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"
+
+static Node* sw1(Node*, Node*);
+static Node* sw2(Node*, Node*);
+static Node* sw3(Node*, Node*);
+static Node* curfn;
+
+void
+walk(Node *fn)
+{
+ curfn = fn;
+ walktype(fn->nbody, 1);
+}
+
+void
+walktype(Node *n, int top)
+{
+ Node *t, *r;
+ Sym *s;
+ long lno;
+ int et;
+
+ /*
+ * walk the whole tree of the body of a function.
+ * the types expressions are calculated.
+ * compile-time constants are evaluated.
+ */
+
+ lno = dynlineno;
+
+loop:
+ if(n == N)
+ goto ret;
+ if(n->op != ONAME)
+ dynlineno = n->lineno; // for diagnostics
+
+ t = N;
+ et = Txxx;
+
+ switch(n->op) {
+ default:
+ fatal("walktype: switch 1 unknown op %N", n);
+ goto ret;
+
+ case ODCLTYPE:
+ goto ret;
+
+ case OPANIC:
+ case OPRINT:
+ walktype(n->left, 0);
+ prcompat(&n->left);
+ goto ret;
+
+ case OLITERAL:
+ n->addable = 1;
+ ullmancalc(n);
+ goto ret;
+
+ case ONAME:
+ n->addable = 1;
+ ullmancalc(n);
+ if(n->type == N) {
+ s = n->sym;
+ if(s->undef == 0) {
+ yyerror("walktype: %N undeclared", n);
+ s->undef = 1;
+ }
+ }
+ goto ret;
+
+ case OLIST:
+ walktype(n->left, top);
+ n = n->right;
+ goto loop;
+
+ case OFOR:
+ if(!top)
+ goto nottop;
+ walktype(n->ninit, 1);
+ walktype(n->ntest, 1);
+ walktype(n->nincr, 1);
+ n = n->nbody;
+ goto loop;
+
+ case OSWITCH:
+ if(!top)
+ goto nottop;
+
+ if(n->ntest == N)
+ n->ntest = booltrue;
+ walktype(n->ninit, 1);
+ walktype(n->ntest, 1);
+ walktype(n->nbody, 1);
+
+ // find common type
+ if(n->ntest->type == N)
+ n->ntest->type = walkswitch(n->ntest, n->nbody, sw1);
+
+ // if that fails pick a type
+ if(n->ntest->type == N)
+ n->ntest->type = walkswitch(n->ntest, n->nbody, sw2);
+
+ // set the type on all literals
+ if(n->ntest->type != N)
+ walkswitch(n->ntest, n->nbody, sw3);
+
+ n = n->nincr;
+ goto loop;
+
+ case OEMPTY:
+ if(!top)
+ goto nottop;
+ goto ret;
+
+ case OIF:
+ if(!top)
+ goto nottop;
+ walktype(n->ninit, 1);
+ walktype(n->ntest, 1);
+ walktype(n->nelse, 1);
+ n = n->nbody;
+ goto loop;
+
+ case OCALL:
+ case OCALLPTR:
+ case OCALLMETH:
+ case OCALLINTER:
+ walktype(n->left, 0);
+ if(n->left == N)
+ goto ret;
+ t = n->left->type;
+ if(t == N)
+ goto ret;
+
+ if(n->left->op == ODOTMETH)
+ n->op = OCALLMETH;
+ if(n->left->op == ODOTINTER)
+ n->op = OCALLINTER;
+
+ if(t->etype == TPTR) {
+ t = t->type;
+ n->op = OCALLPTR;
+ }
+
+ if(t->etype != TFUNC) {
+ yyerror("call of a non-function %T", t);
+ goto ret;
+ }
+
+ n->type = *getoutarg(t);
+ switch(t->outtuple) {
+ default:
+ n->kaka = PCALL_MULTI;
+ if(!top)
+ yyerror("function call must be single valued (%d)", et);
+ break;
+ case 0:
+ n->kaka = PCALL_NIL;
+ break;
+ case 1:
+ n->kaka = PCALL_SINGLE;
+ n->type = n->type->type->type;
+ break;
+ }
+
+ r = n->right;
+ walktype(r, 0);
+ ascompatte(n->op, getinarg(t), &n->right);
+ goto ret;
+
+ case OCOLAS:
+ case ODCLVAR:
+ case OAS:
+ if(!top)
+ goto nottop;
+
+ n->kaka = PAS_SINGLE;
+ r = n->left;
+ if(r != N && r->op == OLIST)
+ n->kaka = PAS_MULTI;
+
+ walktype(r, 0);
+
+ r = n->right;
+ if(r == N)
+ goto ret;
+
+ if(r->op == OCALL && n->kaka == PAS_MULTI) {
+ walktype(r, 1);
+ if(r->kaka == PCALL_MULTI) {
+ ascompatet(n->op, &n->left, &r->type);
+ n->kaka = PAS_CALLM;
+ goto ret;
+ }
+ }
+
+ walktype(n->right, 0);
+ ascompatee(n->op, &n->left, &n->right);
+
+ if(n->kaka == PAS_SINGLE) {
+ t = n->right->type;
+ if(t != N && t->etype == TSTRUCT)
+ n->kaka = PAS_STRUCT;
+ }
+ goto ret;
+
+ case OBREAK:
+ case OCONTINUE:
+ case OGOTO:
+ case OLABEL:
+ goto ret;
+
+ case OXCASE:
+ yyerror("case statement out of place");
+ n->op = OCASE;
+
+ case OCASE:
+ n = n->left;
+ goto loop;
+
+ case OXFALL:
+ yyerror("fallthrough statement out of place");
+ n->op = OFALL;
+
+ case OFALL:
+ goto ret;
+
+ case OCONV:
+ walktype(n->left, 0);
+ if(n->left == N)
+ goto ret;
+ convlit(n->left, n->type);
+ if(eqtype(n->type, n->left->type, 0))
+ *n = *n->left;
+ goto ret;
+
+ case ORETURN:
+ walktype(n->left, 0);
+ ascompatte(n->op, getoutarg(curfn->type), &n->left);
+ goto ret;
+
+ case ONOT:
+ walktype(n->left, 0);
+ if(n->left == N || n->left->type == N)
+ goto ret;
+ et = n->left->type->etype;
+ break;
+
+ case OASOP:
+ if(!top)
+ goto nottop;
+
+ case OLSH:
+ case ORSH:
+ case OMOD:
+ case OAND:
+ case OOR:
+ case OXOR:
+ case OANDAND:
+ case OOROR:
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OLE:
+ case OGE:
+ case OGT:
+ case OADD:
+ case OSUB:
+ case OMUL:
+ case ODIV:
+ case OCAT:
+ walktype(n->left, 0);
+ walktype(n->right, 0);
+ if(n->left == N || n->right == N)
+ goto ret;
+ convlit(n->left, n->right->type);
+ convlit(n->right, n->left->type);
+ evconst(n);
+ if(n->op == OLITERAL)
+ goto ret;
+ if(n->left->type == N || n->right->type == N)
+ goto ret;
+ if(!ascompat(n->left->type, n->right->type))
+ goto badt;
+ break;
+
+ case OPLUS:
+ case OMINUS:
+ case OCOM:
+ walktype(n->left, 0);
+ if(n->left == N)
+ goto ret;
+ evconst(n);
+ ullmancalc(n);
+ if(n->op == OLITERAL)
+ goto ret;
+ break;
+
+ case OLEN:
+ walktype(n->left, 0);
+ evconst(n);
+ ullmancalc(n);
+ t = n->left->type;
+ if(t != N && t->etype == TPTR)
+ t = t->type;
+ if(t == N)
+ goto ret;
+ switch(t->etype) {
+ default:
+ goto badt;
+ case TSTRING:
+ break;
+ }
+ n->type = types[TINT32];
+ goto ret;
+
+ case OINDEX:
+ case OINDEXPTR:
+ case OINDEXSTR:
+ case OINDEXMAP:
+ case OINDEXPTRMAP:
+ walktype(n->left, 0);
+ walktype(n->right, 0);
+ ullmancalc(n);
+ if(n->left == N || n->right == N)
+ goto ret;
+ t = n->left->type;
+ if(t == N)
+ goto ret;
+
+ // map - left and right sides must match
+ if(t->etype == TMAP || isptrto(t, TMAP)) {
+ n->ullman = UINF;
+ n->op = OINDEXMAP;
+ if(isptrto(t, TMAP)) {
+ n->op = OINDEXPTRMAP;
+ t = t->type;
+ if(t == N)
+ goto ret;
+ }
+ convlit(n->right, t->down);
+ if(!ascompat(t->down, n->right->type))
+ goto badt;
+ n->type = t->type;
+ goto ret;
+ }
+
+ // right side must be an int
+ if(n->right->type == N)
+ convlit(n->right, types[TINT32]);
+ if(n->left->type == N || n->right->type == N)
+ goto ret;
+ if(!isint[n->right->type->etype])
+ goto badt;
+
+ // left side is string
+ if(isptrto(t, TSTRING)) {
+ n->op = OINDEXSTR;
+ n->type = types[TUINT8];
+ goto ret;
+ }
+
+ // left side is array
+ if(t->etype == TPTR) {
+ t = t->type;
+ n->op = OINDEXPTR;
+ }
+ if(t->etype != TARRAY && t->etype != TDARRAY)
+ goto badt;
+ n->type = t->type;
+ goto ret;
+
+ case OSLICE:
+ walkslice(n);
+ goto ret;
+
+ case ODOT:
+ case ODOTPTR:
+ case ODOTMETH:
+ case ODOTINTER:
+ walkdot(n);
+ goto ret;
+
+ case OADDR:
+ walktype(n->left, 0);
+ if(n->left == N)
+ goto ret;
+ t = n->left->type;
+ if(t == N)
+ goto ret;
+ n->type = ptrto(t);
+ goto ret;
+
+ case OIND:
+ walktype(n->left, 0);
+ if(n->left == N)
+ goto ret;
+ t = n->left->type;
+ if(t == N)
+ goto ret;
+ if(t->etype != TPTR)
+ goto badt;
+ n->type = t->type;
+ goto ret;
+
+ case ONEW:
+ if(n->left != N)
+ yyerror("dont know what new(,e) means");
+ goto ret;
+ }
+
+/*
+ * ======== second switch ========
+ */
+
+ switch(n->op) {
+ default:
+ fatal("walktype: switch 2 unknown op %N", n);
+ goto ret;
+
+ case OASOP:
+ break;
+
+ case ONOT:
+ case OANDAND:
+ case OOROR:
+ et = n->left->type->etype;
+ if(et != TBOOL)
+ goto badt;
+ t = types[TBOOL];
+ break;
+
+ case OEQ:
+ case ONE:
+ et = n->left->type->etype;
+ if(!okforeq[et])
+ goto badt;
+ t = types[TBOOL];
+ break;
+
+ case OLT:
+ case OLE:
+ case OGE:
+ case OGT:
+ et = n->left->type->etype;
+ if(!okforadd[et])
+ if(!isptrto(n->left->type, TSTRING))
+ goto badt;
+ t = types[TBOOL];
+ break;
+
+ case OCAT:
+ case OADD:
+ if(isptrto(n->left->type, TSTRING)) {
+ n->op = OCAT;
+ break;
+ }
+
+ case OSUB:
+ case OMUL:
+ case ODIV:
+ case OPLUS:
+ case OMINUS:
+ et = n->left->type->etype;
+ if(!okforadd[et])
+ goto badt;
+ break;
+
+ case OLSH:
+ case ORSH:
+ case OAND:
+ case OOR:
+ case OXOR:
+ case OMOD:
+ case OCOM:
+ et = n->left->type->etype;
+ if(!okforand[et])
+ goto badt;
+ break;
+ }
+
+ if(t == N)
+ t = n->left->type;
+ n->type = t;
+ ullmancalc(n);
+ goto ret;
+
+nottop:
+ fatal("walktype: not top %O", n->op);
+
+badt:
+ if(n->right == N) {
+ if(n->left == N) {
+ badtype(n->op, N, N);
+ goto ret;
+ }
+ badtype(n->op, n->left->type, N);
+ goto ret;
+ }
+ badtype(n->op, n->left->type, n->right->type);
+ goto ret;
+
+ret:
+ dynlineno = lno;
+}
+
+/*
+ * return the first type
+ */
+Node*
+sw1(Node *c, Node *place)
+{
+ if(place == N)
+ return c->type;
+ return place;
+}
+
+/*
+ * return a suitable type
+ */
+Node*
+sw2(Node *c, Node *place)
+{
+ return types[TINT32]; // botch
+}
+
+/*
+ * check that selected type
+ * is compat with all the cases
+ */
+Node*
+sw3(Node *c, Node *place)
+{
+ if(place == N)
+ return c->type;
+ if(c->type == N)
+ c->type = place;
+ convlit(c, place);
+ if(!ascompat(place, c->type))
+ badtype(OSWITCH, place, c->type);
+ return place;
+}
+
+Node*
+walkswitch(Node *test, Node *body, Node*(*call)(Node*, Node*))
+{
+ Node *n, *c;
+ Node *place;
+
+ place = call(test, N);
+
+ n = body;
+ if(n->op == OLIST)
+ n = n->left;
+
+ for(; n!=N; n=n->right) {
+ if(n->op != OCASE)
+ fatal("walkswitch: not case %O\n", n->op);
+ for(c=n->left; c!=N; c=c->right) {
+ if(c->op != OLIST) {
+ place = call(c, place);
+ break;
+ }
+ place = call(c->left, place);
+ }
+ }
+ return place;
+}
+
+int
+casebody(Node *n)
+{
+ Node *oc, *ot, *t;
+ Iter save;
+
+
+ /*
+ * look to see if statements at top level have
+ * case labels attached to them. convert the illegal
+ * ops XFALL and XCASE into legal ops FALL and CASE.
+ * all unconverted ops will thus be caught as illegal
+ */
+
+ oc = N; // last case statement
+ ot = N; // last statement (look for XFALL)
+
+ t = listfirst(&save, &n);
+
+ if(t->op != OXCASE)
+ return 0;
+
+loop:
+ if(t == N) {
+ if(oc == N)
+ return 0;
+ return 1;
+ }
+ if(t->op == OXCASE) {
+ /* rewrite and link top level cases */
+ t->op = OCASE;
+ if(oc != N)
+ oc->right = t;
+ oc = t;
+
+ /* rewrite top fall that preceed case */
+ if(ot != N && ot->op == OXFALL)
+ ot->op = OFALL;
+ }
+
+ /* if first statement is not case then return 0 */
+ if(oc == N)
+ return 0;
+
+ ot = t;
+ t = listnext(&save);
+ goto loop;
+}
+
+/*
+ * allowable type combinations for
+ * normal binary operations.
+ */
+
+Node*
+lookdot(Node *n, Node *t, int d)
+{
+ Node *r, *f, *c;
+ Sym *s;
+ int o;
+
+ r = N;
+ s = n->sym;
+ if(d > 0)
+ goto deep;
+
+ o = 0;
+ for(f=t->type; f!=N; f=f->down) {
+ f->kaka = o;
+ o++;
+
+ if(f->sym == S)
+ continue;
+ if(f->sym != s)
+ continue;
+ if(r != N) {
+ yyerror("ambiguous DOT reference %s", s->name);
+ break;
+ }
+ r = f;
+ }
+ return r;
+
+deep:
+ /* deeper look after shallow failed */
+ for(f=t->type; f!=N; f=f->down) {
+ // only look at unnamed sub-structures
+ // BOTCH no such thing -- all are assigned temp names
+ if(f->sym != S)
+ continue;
+ c = f->type;
+ if(c->etype != TSTRUCT)
+ continue;
+ c = lookdot(n, c, d-1);
+ if(c == N)
+ continue;
+ if(r != N) {
+ yyerror("ambiguous unnamed DOT reference %s", s->name);
+ break;
+ }
+ r = c;
+ }
+ return r;
+}
+
+void
+walkdot(Node *n)
+{
+ Node *t, *f;
+ int i;
+
+ if(n->left == N || n->right == N)
+ return;
+
+ walktype(n->left, 0);
+ if(n->right->op != ONAME) {
+ yyerror("rhs of . must be a name");
+ return;
+ }
+
+ t = n->left->type;
+ if(t == N)
+ return;
+
+ if(t->etype == TPTR) {
+ t = t->type;
+ if(t == N)
+ return;
+ n->op = ODOTPTR;
+ }
+
+ if(n->right->op != ONAME)
+ fatal("walkdot: not name %O", n->right->op);
+
+ switch(t->etype) {
+ default:
+ badtype(ODOT, t, N);
+ return;
+
+ case TSTRUCT:
+ case TINTER:
+ for(i=0; i<5; i++) {
+ f = lookdot(n->right, t, i);
+ if(f != N)
+ break;
+ }
+ if(f == N) {
+ yyerror("undefined DOT reference %N", n->right);
+ break;
+ }
+ n->right = f->nname; // substitute real name
+ n->type = f->type;
+ if(n->type->etype == TFUNC) {
+ n->op = ODOTMETH;
+ if(t->etype == TINTER) {
+ n->op = ODOTINTER;
+ n->kaka = f->kaka;
+ }
+ }
+ break;
+ }
+}
+
+void
+walkslice(Node *n)
+{
+ Node *l, *r;
+
+ if(n->left == N || n->right == N)
+ return;
+ walktype(n->left, 0);
+ if(!isptrto(n->left->type, TSTRING)) {
+ badtype(OSLICE, n->left->type, N);
+ return;
+ }
+ if(n->right->op != OLIST)
+ fatal("slice not a list");
+
+ // check for type errors
+ walktype(n->right, 0);
+ l = n->right->left;
+ r = n->right->right;
+ convlit(l, types[TINT32]);
+ convlit(r, types[TINT32]);
+ if(l == N || r == N ||
+ l->type == N || r->type == N)
+ return;
+ if(!isint[l->type->etype] || !isint[l->type->etype]) {
+ badtype(OSLICE, l->type, r->type);
+ return;
+ }
+
+ // now convert to int32
+ n->right->left = nod(OCONV, n->right->left, N);
+ n->right->left->type = types[TINT32];
+ n->right->right = nod(OCONV, n->right->right, N);
+ n->right->right->type = types[TINT32];
+ walktype(n->right, 0);
+
+ n->type = n->left->type;
+}
+
+/*
+ * test tuple type list against each other
+ * called in four contexts
+ * 1. a,b = c,d ...ee
+ * 2. a,b = fn() ...et
+ * 3. call(fn()) ...tt
+ * 4. call(a,b) ...te
+ */
+void
+ascompatee(int op, Node **nl, Node **nr)
+{
+ Node *l, *r;
+ Iter savel, saver;
+ int sa, na;
+
+ l = listfirst(&savel, nl);
+ r = listfirst(&saver, nr);
+ na = 0; // number of assignments - looking for multi
+ sa = 0; // one of the assignments is a structure assignment
+
+loop:
+ if(l == N || r == N) {
+ if(l != r)
+ yyerror("error in shape across assignment");
+ if(sa != 0 && na > 1)
+ yyerror("cant do multi-struct assignments");
+ return;
+ }
+
+ convlit(r, l->type);
+
+ if(!ascompat(l->type, r->type)) {
+ badtype(op, l->type, r->type);
+ return;
+ }
+ if(l->type != N && l->type->etype == TSTRUCT)
+ sa = 1;
+
+ l = listnext(&savel);
+ r = listnext(&saver);
+ na++;
+ goto loop;
+}
+
+void
+ascompatet(int op, Node **nl, Node **nr)
+{
+ Node *l, *r;
+ Iter savel, saver;
+
+ l = listfirst(&savel, nl);
+ r = structfirst(&saver, nr);
+
+loop:
+ if(l == N || r == N) {
+ if(l != r)
+ yyerror("error in shape across assignment");
+ return;
+ }
+
+ if(!ascompat(l->type, r->type)) {
+ badtype(op, l->type, r->type);
+ return;
+ }
+
+ l = listnext(&savel);
+ r = structnext(&saver);
+
+ goto loop;
+}
+
+void
+ascompatte(int op, Node **nl, Node **nr)
+{
+ Node *l, *r;
+ Iter savel, saver;
+
+ l = structfirst(&savel, nl);
+ r = listfirst(&saver, nr);
+
+loop:
+ if(l == N || r == N) {
+ if(l != r)
+ yyerror("error in shape across assignment");
+ return;
+ }
+
+ convlit(r, l->type);
+
+ if(!ascompat(l->type, r->type)) {
+ badtype(op, l->type, r->type);
+ return;
+ }
+
+ l = structnext(&savel);
+ r = listnext(&saver);
+
+ goto loop;
+}
+
+void
+ascompattt(int op, Node **nl, Node **nr)
+{
+ Node *l, *r;
+ Iter savel, saver;
+
+ l = structfirst(&savel, nl);
+ r = structfirst(&saver, nr);
+
+loop:
+ if(l == N || r == N) {
+ if(l != r)
+ yyerror("error in shape across assignment");
+ return;
+ }
+
+ if(!ascompat(l->type, r->type)) {
+ badtype(op, l->type, r->type);
+ return;
+ }
+
+ l = structnext(&savel);
+ r = structnext(&saver);
+
+ goto loop;
+}
+
+/*
+ * can we assign var of type t2 to var of type t1
+ */
+int
+ascompat(Node *t1, Node *t2)
+{
+ if(eqtype(t1, t2, 0))
+ return 1;
+// if(eqtype(t1, nilptr, 0))
+// return 1;
+// if(eqtype(t2, nilptr, 0))
+// return 1;
+ if(isinter(t1))
+ if(isptrto(t2, TSTRUCT) || isinter(t2))
+ return 1;
+ if(isinter(t2))
+ if(isptrto(t1, TSTRUCT))
+ return 1;
+ return 0;
+}
+
+void
+prcompat(Node **n)
+{
+ Node *l, *t;
+ Iter save;
+ int w;
+
+ l = listfirst(&save, n);
+
+loop:
+ if(l == N)
+ return;
+
+ t = N;
+ w = whatis(l);
+ switch(w) {
+ default:
+ badtype((*n)->op, l->type, N);
+ break;
+ case Wtint:
+ case Wtfloat:
+ case Wtbool:
+ case Wtstr:
+ break;
+ case Wlitint:
+ t = types[TINT32];
+ break;
+ case Wlitfloat:
+ t = types[TFLOAT64];
+ break;
+ case Wlitbool:
+ t = types[TBOOL];
+ break;
+ case Wlitstr:
+ t = types[TSTRING];
+ break;
+ }
+
+ if(t != N)
+ convlit(l, t);
+
+ l = listnext(&save);
+ goto loop;
+}