summaryrefslogtreecommitdiff
path: root/src/old/c/subr.c
diff options
context:
space:
mode:
authorRob Pike <r@golang.org>2008-06-04 14:46:07 -0700
committerRob Pike <r@golang.org>2008-06-04 14:46:07 -0700
commit5cf1e37b96825023b2da8de9be3a07d1987bb306 (patch)
treefda9e615c7d6ddb748cee567027fae05ba9215ae /src/old/c/subr.c
parent0a2697043d69739b27b6ba872b2092a4c2bb61a8 (diff)
downloadgolang-5cf1e37b96825023b2da8de9be3a07d1987bb306.tar.gz
move old code into 'old' directory
add src/test dir SVN=121166
Diffstat (limited to 'src/old/c/subr.c')
-rw-r--r--src/old/c/subr.c1522
1 files changed, 1522 insertions, 0 deletions
diff --git a/src/old/c/subr.c b/src/old/c/subr.c
new file mode 100644
index 000000000..1bb6ac520
--- /dev/null
+++ b/src/old/c/subr.c
@@ -0,0 +1,1522 @@
+// 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",
+ [OCOM] = "COM",
+ [OCONST] = "CONST",
+ [OCONTINUE] = "CONTINUE",
+ [ODCLARG] = "DCLARG",
+ [ODCLFIELD] = "DCLFIELD",
+ [ODCLFUNC] = "DCLFUNC",
+ [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",
+ [OINDEXPTRSTR] = "INDEXPTRSTR",
+ [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",
+ [OSLICESTR] = "SLICESTR",
+ [OSLICEPTRSTR] = "SLICEPTRSTR",
+ [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
+isnil(Node *n)
+{
+ if(n == N)
+ return 0;
+ if(n->op != OLITERAL)
+ return 0;
+ if(n->val.ctype != CTNIL)
+ return 0;
+ return 1;
+}
+
+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) {
+ // assigned names dont count
+ if(t1->nname->sym->name[0] != '_' ||
+ 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);
+}
+
+/*
+ * are the arg names of two
+ * functions the same. we know
+ * that eqtype has been called
+ * and has returned true.
+ */
+int
+eqargs(Node *t1, Node *t2)
+{
+ if(t1 == t2)
+ return 1;
+ if(t1 == N || t2 == N)
+ return 0;
+ if(t1->op != OTYPE || t2->op != OTYPE)
+ fatal("eqargs: oops %O %O", t1->op, t2->op);
+
+ if(t1->etype != t2->etype)
+ return 0;
+
+ if(t1->etype != TFUNC)
+ fatal("eqargs: oops %E", t1->etype);
+
+ t1 = t1->type;
+ t2 = t2->type;
+ for(;;) {
+ if(t1 == t2)
+ break;
+ if(!eqtype(t1, t2, 0))
+ return 0;
+ t1 = t1->down;
+ t2 = t2->down;
+ }
+ return 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);
+}