| // 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); |
| } |