diff options
author | Rob Pike <r@golang.org> | 2008-06-04 14:37:38 -0700 |
---|---|---|
committer | Rob Pike <r@golang.org> | 2008-06-04 14:37:38 -0700 |
commit | 0a2697043d69739b27b6ba872b2092a4c2bb61a8 (patch) | |
tree | eae29cc83bbd362fbdc03748f1bd2eb13deec5e8 /src/cmd/cc | |
parent | 9d4eba9a1b1af656bbefab37240ca739af479cc0 (diff) | |
download | golang-0a2697043d69739b27b6ba872b2092a4c2bb61a8.tar.gz |
Add compiler source to new directory structure
SVN=121164
Diffstat (limited to 'src/cmd/cc')
-rw-r--r-- | src/cmd/cc/acid.c | 331 | ||||
-rw-r--r-- | src/cmd/cc/bits.c | 119 | ||||
-rw-r--r-- | src/cmd/cc/cc.h | 795 | ||||
-rw-r--r-- | src/cmd/cc/cc.y | 1205 | ||||
-rw-r--r-- | src/cmd/cc/com.c | 1378 | ||||
-rw-r--r-- | src/cmd/cc/com64.c | 643 | ||||
-rw-r--r-- | src/cmd/cc/dcl.c | 1664 | ||||
-rw-r--r-- | src/cmd/cc/dpchk.c | 524 | ||||
-rw-r--r-- | src/cmd/cc/funct.c | 430 | ||||
-rw-r--r-- | src/cmd/cc/lex.c | 1542 | ||||
-rw-r--r-- | src/cmd/cc/lexbody | 723 | ||||
-rw-r--r-- | src/cmd/cc/mac.c | 33 | ||||
-rw-r--r-- | src/cmd/cc/macbody | 842 | ||||
-rw-r--r-- | src/cmd/cc/omachcap.c | 38 | ||||
-rw-r--r-- | src/cmd/cc/pgen.c | 550 | ||||
-rw-r--r-- | src/cmd/cc/pickle.c | 298 | ||||
-rw-r--r-- | src/cmd/cc/pswt.c | 168 | ||||
-rw-r--r-- | src/cmd/cc/scon.c | 636 | ||||
-rw-r--r-- | src/cmd/cc/sub.c | 2054 |
19 files changed, 13973 insertions, 0 deletions
diff --git a/src/cmd/cc/acid.c b/src/cmd/cc/acid.c new file mode 100644 index 000000000..62be5e82b --- /dev/null +++ b/src/cmd/cc/acid.c @@ -0,0 +1,331 @@ +// Inferno utils/cc/acid.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/acid.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "cc.h" + +static char *kwd[] = +{ + "$adt", "$aggr", "$append", "$complex", "$defn", + "$delete", "$do", "$else", "$eval", "$head", "$if", + "$local", "$loop", "$return", "$tail", "$then", + "$union", "$whatis", "$while", +}; + +char* +amap(char *s) +{ + int i, bot, top, new; + + bot = 0; + top = bot + nelem(kwd) - 1; + while(bot <= top){ + new = bot + (top - bot)/2; + i = strcmp(kwd[new]+1, s); + if(i == 0) + return kwd[new]; + + if(i < 0) + bot = new + 1; + else + top = new - 1; + } + return s; +} + +Sym* +acidsue(Type *t) +{ + int h; + Sym *s; + + if(t != T) + for(h=0; h<nelem(hash); h++) + for(s = hash[h]; s != S; s = s->link) + if(s->suetag && s->suetag->link == t) + return s; + return 0; +} + +Sym* +acidfun(Type *t) +{ + int h; + Sym *s; + + for(h=0; h<nelem(hash); h++) + for(s = hash[h]; s != S; s = s->link) + if(s->type == t) + return s; + return 0; +} + +char acidchar[NTYPE]; +Init acidcinit[] = +{ + TCHAR, 'C', 0, + TUCHAR, 'b', 0, + TSHORT, 'd', 0, + TUSHORT, 'u', 0, + TLONG, 'D', 0, + TULONG, 'U', 0, + TVLONG, 'V', 0, + TUVLONG, 'W', 0, + TFLOAT, 'f', 0, + TDOUBLE, 'F', 0, + TARRAY, 'a', 0, + TIND, 'X', 0, + -1, 0, 0, +}; + +static void +acidinit(void) +{ + Init *p; + + for(p=acidcinit; p->code >= 0; p++) + acidchar[p->code] = p->value; + + acidchar[TINT] = acidchar[TLONG]; + acidchar[TUINT] = acidchar[TULONG]; + if(types[TINT]->width != types[TLONG]->width) { + acidchar[TINT] = acidchar[TSHORT]; + acidchar[TUINT] = acidchar[TUSHORT]; + if(types[TINT]->width != types[TSHORT]->width) + warn(Z, "acidmember int not long or short"); + } + +} + +void +acidmember(Type *t, long off, int flag) +{ + Sym *s, *s1; + Type *l; + static int acidcharinit = 0; + + if(acidcharinit == 0) { + acidinit(); + acidcharinit = 1; + } + s = t->sym; + switch(t->etype) { + default: + Bprint(&outbuf, " T%d\n", t->etype); + break; + + case TIND: + if(s == S) + break; + if(flag) { + for(l=t; l->etype==TIND; l=l->link) + ; + if(typesu[l->etype]) { + s1 = acidsue(l->link); + if(s1 != S) { + Bprint(&outbuf, " 'A' %s %ld %s;\n", + amap(s1->name), + t->offset+off, amap(s->name)); + break; + } + } + } else { + Bprint(&outbuf, + "\tprint(\"\t%s\t\", addr.%s\\X, \"\\n\");\n", + amap(s->name), amap(s->name)); + break; + } + + case TINT: + case TUINT: + case TCHAR: + case TUCHAR: + case TSHORT: + case TUSHORT: + case TLONG: + case TULONG: + case TVLONG: + case TUVLONG: + case TFLOAT: + case TDOUBLE: + case TARRAY: + if(s == S) + break; + if(flag) { + Bprint(&outbuf, " '%c' %ld %s;\n", + acidchar[t->etype], t->offset+off, amap(s->name)); + } else { + Bprint(&outbuf, "\tprint(\"\t%s\t\", addr.%s, \"\\n\");\n", + amap(s->name), amap(s->name)); + } + break; + + case TSTRUCT: + case TUNION: + s1 = acidsue(t->link); + if(s1 == S) + break; + if(flag) { + if(s == S) { + Bprint(&outbuf, " {\n"); + for(l = t->link; l != T; l = l->down) + acidmember(l, t->offset+off, flag); + Bprint(&outbuf, " };\n"); + } else { + Bprint(&outbuf, " %s %ld %s;\n", + amap(s1->name), + t->offset+off, amap(s->name)); + } + } else { + if(s != S) { + Bprint(&outbuf, "\tprint(\"%s %s {\\n\");\n", + amap(s1->name), amap(s->name)); + Bprint(&outbuf, "\t%s(addr.%s);\n", + amap(s1->name), amap(s->name)); + Bprint(&outbuf, "\tprint(\"}\\n\");\n"); + } else { + Bprint(&outbuf, "\tprint(\"%s {\\n\");\n", + amap(s1->name)); + Bprint(&outbuf, "\t\t%s(addr+%ld);\n", + amap(s1->name), t->offset+off); + Bprint(&outbuf, "\tprint(\"}\\n\");\n"); + } + } + break; + } +} + +void +acidtype(Type *t) +{ + Sym *s; + Type *l; + Io *i; + int n; + char *an; + + if(!debug['a']) + return; + if(debug['a'] > 1) { + n = 0; + for(i=iostack; i; i=i->link) + n++; + if(n > 1) + return; + } + s = acidsue(t->link); + if(s == S) + return; + switch(t->etype) { + default: + Bprint(&outbuf, "T%d\n", t->etype); + return; + + case TUNION: + case TSTRUCT: + if(debug['s']) + goto asmstr; + an = amap(s->name); + Bprint(&outbuf, "sizeof%s = %ld;\n", an, t->width); + Bprint(&outbuf, "aggr %s\n{\n", an); + for(l = t->link; l != T; l = l->down) + acidmember(l, 0, 1); + Bprint(&outbuf, "};\n\n"); + + Bprint(&outbuf, "defn\n%s(addr) {\n\tcomplex %s addr;\n", an, an); + for(l = t->link; l != T; l = l->down) + acidmember(l, 0, 0); + Bprint(&outbuf, "};\n\n"); + break; + asmstr: + if(s == S) + break; + for(l = t->link; l != T; l = l->down) + if(l->sym != S) + Bprint(&outbuf, "#define\t%s.%s\t%ld\n", + s->name, + l->sym->name, + l->offset); + break; + } +} + +void +acidvar(Sym *s) +{ + int n; + Io *i; + Type *t; + Sym *s1, *s2; + + if(!debug['a'] || debug['s']) + return; + if(debug['a'] > 1) { + n = 0; + for(i=iostack; i; i=i->link) + n++; + if(n > 1) + return; + } + t = s->type; + while(t && t->etype == TIND) + t = t->link; + if(t == T) + return; + if(t->etype == TENUM) { + Bprint(&outbuf, "%s = ", amap(s->name)); + if(!typefd[t->etype]) + Bprint(&outbuf, "%lld;\n", s->vconst); + else + Bprint(&outbuf, "%f\n;", s->fconst); + return; + } + if(!typesu[t->etype]) + return; + s1 = acidsue(t->link); + if(s1 == S) + return; + switch(s->class) { + case CAUTO: + case CPARAM: + s2 = acidfun(thisfn); + if(s2) + Bprint(&outbuf, "complex %s %s:%s;\n", + amap(s1->name), amap(s2->name), amap(s->name)); + break; + + case CSTATIC: + case CEXTERN: + case CGLOBL: + case CLOCAL: + Bprint(&outbuf, "complex %s %s;\n", + amap(s1->name), amap(s->name)); + break; + } +} diff --git a/src/cmd/cc/bits.c b/src/cmd/cc/bits.c new file mode 100644 index 000000000..31e788c8a --- /dev/null +++ b/src/cmd/cc/bits.c @@ -0,0 +1,119 @@ +// Inferno utils/cc/bits.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/bits.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "cc.h" + +Bits +bor(Bits a, Bits b) +{ + Bits c; + int i; + + for(i=0; i<BITS; i++) + c.b[i] = a.b[i] | b.b[i]; + return c; +} + +Bits +band(Bits a, Bits b) +{ + Bits c; + int i; + + for(i=0; i<BITS; i++) + c.b[i] = a.b[i] & b.b[i]; + return c; +} + +/* +Bits +bnot(Bits a) +{ + Bits c; + int i; + + for(i=0; i<BITS; i++) + c.b[i] = ~a.b[i]; + return c; +} +*/ + +int +bany(Bits *a) +{ + int i; + + for(i=0; i<BITS; i++) + if(a->b[i]) + return 1; + return 0; +} + +int +beq(Bits a, Bits b) +{ + int i; + + for(i=0; i<BITS; i++) + if(a.b[i] != b.b[i]) + return 0; + return 1; +} + +int +bnum(Bits a) +{ + int i; + long b; + + for(i=0; i<BITS; i++) + if(b = a.b[i]) + return 32*i + bitno(b); + diag(Z, "bad in bnum"); + return 0; +} + +Bits +blsh(uint n) +{ + Bits c; + + c = zbits; + c.b[n/32] = 1L << (n%32); + return c; +} + +int +bset(Bits a, uint n) +{ + if(a.b[n/32] & (1L << (n%32))) + return 1; + return 0; +} diff --git a/src/cmd/cc/cc.h b/src/cmd/cc/cc.h new file mode 100644 index 000000000..db1cf94ee --- /dev/null +++ b/src/cmd/cc/cc.h @@ -0,0 +1,795 @@ +// Inferno utils/cc/cc.h +// http://code.google.com/p/inferno-os/source/browse/utils/cc/cc.h +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <ctype.h> +#include "compat.h" + +#pragma lib "../cc/cc.a$O" + +#ifndef EXTERN +#define EXTERN extern +#endif + +typedef struct Node Node; +typedef struct Sym Sym; +typedef struct Type Type; +typedef struct Funct Funct; +typedef struct Decl Decl; +typedef struct Io Io; +typedef struct Hist Hist; +typedef struct Term Term; +typedef struct Init Init; +typedef struct Bits Bits; + +#define NHUNK 50000L +#define BUFSIZ 8192 +#define NSYMB 500 +#define NHASH 1024 +#define STRINGSZ 200 +#define HISTSZ 20 +#define YYMAXDEPTH 500 +#define NTERM 10 +#define MAXALIGN 7 + +#define SIGN(n) ((vlong)1<<(n-1)) +#define MASK(n) (SIGN(n)|(SIGN(n)-1)) + +#define BITS 5 +#define NVAR (BITS*sizeof(ulong)*8) +struct Bits +{ + ulong b[BITS]; +}; + +struct Node +{ + Node* left; + Node* right; + void* label; + long pc; + int reg; + long xoffset; + double fconst; /* fp constant */ + vlong vconst; /* non fp const */ + char* cstring; /* character string */ + ushort* rstring; /* rune string */ + + Sym* sym; + Type* type; + long lineno; + uchar op; + uchar oldop; + uchar xcast; + uchar class; + uchar etype; + uchar complex; + uchar addable; + uchar scale; + uchar garb; +}; +#define Z ((Node*)0) + +struct Sym +{ + Sym* link; + Type* type; + Type* suetag; + Type* tenum; + char* macro; + long varlineno; + long offset; + vlong vconst; + double fconst; + Node* label; + ushort lexical; + char *name; + ushort block; + ushort sueblock; + uchar class; + uchar sym; + uchar aused; + uchar sig; +}; +#define S ((Sym*)0) + +enum{ + SIGNONE = 0, + SIGDONE = 1, + SIGINTERN = 2, + + SIGNINTERN = 1729*325*1729, +}; + +struct Decl +{ + Decl* link; + Sym* sym; + Type* type; + long varlineno; + long offset; + short val; + ushort block; + uchar class; + uchar aused; +}; +#define D ((Decl*)0) + +struct Type +{ + Sym* sym; + Sym* tag; + Funct* funct; + Type* link; + Type* down; + long width; + long offset; + long lineno; + uchar shift; + uchar nbits; + uchar etype; + uchar garb; +}; + +#define T ((Type*)0) +#define NODECL ((void(*)(int, Type*, Sym*))0) + +struct Init /* general purpose initialization */ +{ + int code; + ulong value; + char* s; +}; + +EXTERN struct +{ + char* p; + int c; +} fi; + +struct Io +{ + Io* link; + char* p; + char b[BUFSIZ]; + short c; + short f; +}; +#define I ((Io*)0) + +struct Hist +{ + Hist* link; + char* name; + long line; + long offset; +}; +#define H ((Hist*)0) +EXTERN Hist* hist; + +struct Term +{ + vlong mult; + Node *node; +}; + +enum +{ + Axxx, + Ael1, + Ael2, + Asu2, + Aarg0, + Aarg1, + Aarg2, + Aaut3, + NALIGN, +}; + +enum +{ + DMARK, + DAUTO, + DSUE, + DLABEL, +}; +enum +{ + OXXX, + OADD, + OADDR, + OAND, + OANDAND, + OARRAY, + OAS, + OASI, + OASADD, + OASAND, + OASASHL, + OASASHR, + OASDIV, + OASHL, + OASHR, + OASLDIV, + OASLMOD, + OASLMUL, + OASLSHR, + OASMOD, + OASMUL, + OASOR, + OASSUB, + OASXOR, + OBIT, + OBREAK, + OCASE, + OCAST, + OCOMMA, + OCOND, + OCONST, + OCONTINUE, + ODIV, + ODOT, + ODOTDOT, + ODWHILE, + OENUM, + OEQ, + OFOR, + OFUNC, + OGE, + OGOTO, + OGT, + OHI, + OHS, + OIF, + OIND, + OINDREG, + OINIT, + OLABEL, + OLDIV, + OLE, + OLIST, + OLMOD, + OLMUL, + OLO, + OLS, + OLSHR, + OLT, + OMOD, + OMUL, + ONAME, + ONE, + ONOT, + OOR, + OOROR, + OPOSTDEC, + OPOSTINC, + OPREDEC, + OPREINC, + OPROTO, + OREGISTER, + ORETURN, + OSET, + OSIGN, + OSIZE, + OSTRING, + OLSTRING, + OSTRUCT, + OSUB, + OSWITCH, + OUNION, + OUSED, + OWHILE, + OXOR, + ONEG, + OCOM, + OPOS, + OELEM, + + OTST, /* used in some compilers */ + OINDEX, + OFAS, + OREGPAIR, + + OEND +}; +enum +{ + TXXX, + TCHAR, + TUCHAR, + TSHORT, + TUSHORT, + TINT, + TUINT, + TLONG, + TULONG, + TVLONG, + TUVLONG, + TFLOAT, + TDOUBLE, + TIND, + TFUNC, + TARRAY, + TVOID, + TSTRUCT, + TUNION, + TENUM, + NTYPE, + + TAUTO = NTYPE, + TEXTERN, + TSTATIC, + TTYPEDEF, + TTYPESTR, + TREGISTER, + TCONSTNT, + TVOLATILE, + TUNSIGNED, + TSIGNED, + TDOT, + TFILE, + TOLD, + NALLTYPES, +}; +enum +{ + CXXX, + CAUTO, + CEXTERN, + CGLOBL, + CSTATIC, + CLOCAL, + CTYPEDEF, + CTYPESTR, + CPARAM, + CSELEM, + CLABEL, + CEXREG, + NCTYPES, +}; +enum +{ + GXXX = 0, + GCONSTNT = 1<<0, + GVOLATILE = 1<<1, + NGTYPES = 1<<2, + + GINCOMPLETE = 1<<2, +}; +enum +{ + BCHAR = 1L<<TCHAR, + BUCHAR = 1L<<TUCHAR, + BSHORT = 1L<<TSHORT, + BUSHORT = 1L<<TUSHORT, + BINT = 1L<<TINT, + BUINT = 1L<<TUINT, + BLONG = 1L<<TLONG, + BULONG = 1L<<TULONG, + BVLONG = 1L<<TVLONG, + BUVLONG = 1L<<TUVLONG, + BFLOAT = 1L<<TFLOAT, + BDOUBLE = 1L<<TDOUBLE, + BIND = 1L<<TIND, + BFUNC = 1L<<TFUNC, + BARRAY = 1L<<TARRAY, + BVOID = 1L<<TVOID, + BSTRUCT = 1L<<TSTRUCT, + BUNION = 1L<<TUNION, + BENUM = 1L<<TENUM, + BFILE = 1L<<TFILE, + BDOT = 1L<<TDOT, + BCONSTNT = 1L<<TCONSTNT, + BVOLATILE = 1L<<TVOLATILE, + BUNSIGNED = 1L<<TUNSIGNED, + BSIGNED = 1L<<TSIGNED, + BAUTO = 1L<<TAUTO, + BEXTERN = 1L<<TEXTERN, + BSTATIC = 1L<<TSTATIC, + BTYPEDEF = 1L<<TTYPEDEF, + BTYPESTR = 1L<<TTYPESTR, + BREGISTER = 1L<<TREGISTER, + + BINTEGER = BCHAR|BUCHAR|BSHORT|BUSHORT|BINT|BUINT| + BLONG|BULONG|BVLONG|BUVLONG, + BNUMBER = BINTEGER|BFLOAT|BDOUBLE, + +/* these can be overloaded with complex types */ + + BCLASS = BAUTO|BEXTERN|BSTATIC|BTYPEDEF|BTYPESTR|BREGISTER, + BGARB = BCONSTNT|BVOLATILE, +}; + +struct Funct +{ + Sym* sym[OEND]; + Sym* castto[NTYPE]; + Sym* castfr[NTYPE]; +}; + +EXTERN struct +{ + Type* tenum; /* type of entire enum */ + Type* cenum; /* type of current enum run */ + vlong lastenum; /* value of current enum */ + double floatenum; /* value of current enum */ +} en; + +EXTERN int autobn; +EXTERN long autoffset; +EXTERN int blockno; +EXTERN Decl* dclstack; +EXTERN char debug[256]; +EXTERN Hist* ehist; +EXTERN long firstbit; +EXTERN Sym* firstarg; +EXTERN Type* firstargtype; +EXTERN Decl* firstdcl; +EXTERN int fperror; +EXTERN Sym* hash[NHASH]; +EXTERN char* hunk; +EXTERN char* include[20]; +EXTERN Io* iofree; +EXTERN Io* ionext; +EXTERN Io* iostack; +EXTERN long lastbit; +EXTERN char lastclass; +EXTERN Type* lastdcl; +EXTERN long lastfield; +EXTERN Type* lasttype; +EXTERN long lineno; +EXTERN long nearln; +EXTERN int nerrors; +EXTERN int newflag; +EXTERN long nhunk; +EXTERN int ninclude; +EXTERN Node* nodproto; +EXTERN Node* nodcast; +EXTERN Biobuf outbuf; +EXTERN Biobuf diagbuf; +EXTERN char* outfile; +EXTERN char* pathname; +EXTERN int peekc; +EXTERN long stkoff; +EXTERN Type* strf; +EXTERN Type* strl; +EXTERN char symb[NSYMB]; +EXTERN Sym* symstring; +EXTERN int taggen; +EXTERN Type* tfield; +EXTERN Type* tufield; +EXTERN int thechar; +EXTERN char* thestring; +EXTERN Type* thisfn; +EXTERN long thunk; +EXTERN Type* types[NTYPE]; +EXTERN Type* fntypes[NTYPE]; +EXTERN Node* initlist; +EXTERN Term term[NTERM]; +EXTERN int nterm; +EXTERN int packflg; +EXTERN int fproundflg; +EXTERN int profileflg; +EXTERN int ncontin; +EXTERN int canreach; +EXTERN int warnreach; +EXTERN Bits zbits; + +extern char *onames[], *tnames[], *gnames[]; +extern char *cnames[], *qnames[], *bnames[]; +extern uchar tab[NTYPE][NTYPE]; +extern uchar comrel[], invrel[], logrel[]; +extern long ncast[], tadd[], tand[]; +extern long targ[], tasadd[], tasign[], tcast[]; +extern long tdot[], tfunct[], tindir[], tmul[]; +extern long tnot[], trel[], tsub[]; + +extern uchar typeaf[]; +extern uchar typefd[]; +extern uchar typei[]; +extern uchar typesu[]; +extern uchar typesuv[]; +extern uchar typeu[]; +extern uchar typev[]; +extern uchar typec[]; +extern uchar typeh[]; +extern uchar typeil[]; +extern uchar typeilp[]; +extern uchar typechl[]; +extern uchar typechlv[]; +extern uchar typechlvp[]; +extern uchar typechlp[]; +extern uchar typechlpfd[]; + +EXTERN uchar* typeword; +EXTERN uchar* typecmplx; + +extern ulong thash1; +extern ulong thash2; +extern ulong thash3; +extern ulong thash[]; + +/* + * compat.c/unix.c/windows.c + */ +int mywait(int*); +int mycreat(char*, int); +int systemtype(int); +int pathchar(void); +int myaccess(char*); +char* mygetwd(char*, int); +int myexec(char*, char*[]); +int mydup(int, int); +int myfork(void); +int mypipe(int*); +void* mysbrk(ulong); + +/* + * parser + */ +int yyparse(void); +int mpatov(char*, vlong*); + +/* + * lex.c + */ +void* allocn(void*, long, long); +void* alloc(long); +void cinit(void); +int compile(char*, char**, int); +void errorexit(void); +int filbuf(void); +int getc(void); +long getr(void); +int getnsc(void); +Sym* lookup(void); +void main(int, char*[]); +void newfile(char*, int); +void newio(void); +void pushio(void); +long escchar(long, int, int); +Sym* slookup(char*); +void syminit(Sym*); +void unget(int); +long yylex(void); +int Lconv(Fmt*); +int Tconv(Fmt*); +int FNconv(Fmt*); +int Oconv(Fmt*); +int Qconv(Fmt*); +int VBconv(Fmt*); +void setinclude(char*); + +/* + * mac.c + */ +void dodefine(char*); +void domacro(void); +Sym* getsym(void); +long getnsn(void); +void linehist(char*, int); +void macdef(void); +void macprag(void); +void macend(void); +void macexpand(Sym*, char*); +void macif(int); +void macinc(void); +void maclin(void); +void macund(void); + +/* + * dcl.c + */ +Node* doinit(Sym*, Type*, long, Node*); +Type* tcopy(Type*); +Node* init1(Sym*, Type*, long, int); +Node* newlist(Node*, Node*); +void adecl(int, Type*, Sym*); +int anyproto(Node*); +void argmark(Node*, int); +void dbgdecl(Sym*); +Node* dcllabel(Sym*, int); +Node* dodecl(void(*)(int, Type*, Sym*), int, Type*, Node*); +Sym* mkstatic(Sym*); +void doenum(Sym*, Node*); +void snap(Type*); +Type* dotag(Sym*, int, int); +void edecl(int, Type*, Sym*); +Type* fnproto(Node*); +Type* fnproto1(Node*); +void markdcl(void); +Type* paramconv(Type*, int); +void pdecl(int, Type*, Sym*); +Decl* push(void); +Decl* push1(Sym*); +Node* revertdcl(void); +long xround(long, int); +int rsametype(Type*, Type*, int, int); +int sametype(Type*, Type*); +ulong sign(Sym*); +ulong signature(Type*); +void suallign(Type*); +void tmerge(Type*, Sym*); +void walkparam(Node*, int); +void xdecl(int, Type*, Sym*); +Node* contig(Sym*, Node*, long); + +/* + * com.c + */ +void ccom(Node*); +void complex(Node*); +int tcom(Node*); +int tcoma(Node*, Node*, Type*, int); +int tcomd(Node*); +int tcomo(Node*, int); +int tcomx(Node*); +int tlvalue(Node*); +void constas(Node*, Type*, Type*); + +/* + * con.c + */ +void acom(Node*); +void acom1(vlong, Node*); +void acom2(Node*, Type*); +int acomcmp1(const void*, const void*); +int acomcmp2(const void*, const void*); +int addo(Node*); +void evconst(Node*); + +/* + * funct.c + */ +int isfunct(Node*); +void dclfunct(Type*, Sym*); + +/* + * sub.c + */ +void arith(Node*, int); +int deadheads(Node*); +Type* dotsearch(Sym*, Type*, Node*, long*); +long dotoffset(Type*, Type*, Node*); +void gethunk(void); +Node* invert(Node*); +int bitno(long); +void makedot(Node*, Type*, long); +int mixedasop(Type*, Type*); +Node* new(int, Node*, Node*); +Node* new1(int, Node*, Node*); +int nilcast(Type*, Type*); +int nocast(Type*, Type*); +void prtree(Node*, char*); +void prtree1(Node*, int, int); +void relcon(Node*, Node*); +int relindex(int); +int simpleg(long); +Type* garbt(Type*, long); +int simplec(long); +Type* simplet(long); +int stcompat(Node*, Type*, Type*, long[]); +int tcompat(Node*, Type*, Type*, long[]); +void tinit(void); +Type* typ(int, Type*); +Type* copytyp(Type*); +void typeext(Type*, Node*); +void typeext1(Type*, Node*); +int side(Node*); +int vconst(Node*); +int xlog2(uvlong); +int vlog(Node*); +int topbit(ulong); +void simplifyshift(Node*); +long typebitor(long, long); +void diag(Node*, char*, ...); +void warn(Node*, char*, ...); +void yyerror(char*, ...); +void fatal(Node*, char*, ...); + +/* + * acid.c + */ +void acidtype(Type*); +void acidvar(Sym*); + +/* + * pickle.c + */ +void pickletype(Type*); + +/* + * bits.c + */ +Bits bor(Bits, Bits); +Bits band(Bits, Bits); +Bits bnot(Bits); +int bany(Bits*); +int bnum(Bits); +Bits blsh(uint); +int beq(Bits, Bits); +int bset(Bits, uint); + +/* + * dpchk.c + */ +void dpcheck(Node*); +void arginit(void); +void pragvararg(void); +void pragpack(void); +void pragfpround(void); +void pragprofile(void); +void pragincomplete(void); + +/* + * calls to machine depend part + */ +void codgen(Node*, Node*); +void gclean(void); +void gextern(Sym*, Node*, long, long); +void ginit(void); +long outstring(char*, long); +long outlstring(ushort*, long); +void sextern(Sym*, Node*, long, long); +void xcom(Node*); +long exreg(Type*); +long align(long, Type*, int); +long maxround(long, long); + +extern schar ewidth[]; + +/* + * com64 + */ +int com64(Node*); +void com64init(void); +void bool64(Node*); +double convvtof(vlong); +vlong convftov(double); +double convftox(double, int); +vlong convvtox(vlong, int); + +/* + * machcap + */ +int machcap(Node*); + +#pragma varargck argpos warn 2 +#pragma varargck argpos diag 2 +#pragma varargck argpos yyerror 1 + +#pragma varargck type "F" Node* +#pragma varargck type "L" long +#pragma varargck type "Q" long +#pragma varargck type "O" int +#pragma varargck type "T" Type* +#pragma varargck type "|" int diff --git a/src/cmd/cc/cc.y b/src/cmd/cc/cc.y new file mode 100644 index 000000000..1abcddd43 --- /dev/null +++ b/src/cmd/cc/cc.y @@ -0,0 +1,1205 @@ +// Inferno utils/cc/cc.y +// http://code.google.com/p/inferno-os/source/browse/utils/cc/cc.y +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +%{ +#include "cc.h" +%} +%union { + Node* node; + Sym* sym; + Type* type; + struct + { + Type* t; + uchar c; + } tycl; + struct + { + Type* t1; + Type* t2; + } tyty; + struct + { + char* s; + long l; + } sval; + long lval; + double dval; + vlong vval; +} +%type <sym> ltag +%type <lval> gctname gcname cname gname tname +%type <lval> gctnlist gcnlist zgnlist +%type <type> tlist sbody complex +%type <tycl> types +%type <node> zarglist arglist zcexpr +%type <node> name block stmnt cexpr expr xuexpr pexpr +%type <node> zelist elist adecl slist uexpr string lstring +%type <node> xdecor xdecor2 labels label ulstmnt +%type <node> adlist edecor tag qual qlist +%type <node> abdecor abdecor1 abdecor2 abdecor3 +%type <node> zexpr lexpr init ilist forexpr + +%left ';' +%left ',' +%right '=' LPE LME LMLE LDVE LMDE LRSHE LLSHE LANDE LXORE LORE +%right '?' ':' +%left LOROR +%left LANDAND +%left '|' +%left '^' +%left '&' +%left LEQ LNE +%left '<' '>' LLE LGE +%left LLSH LRSH +%left '+' '-' +%left '*' '/' '%' +%right LMM LPP LMG '.' '[' '(' + +%token <sym> LNAME LTYPE +%token <dval> LFCONST LDCONST +%token <vval> LCONST LLCONST LUCONST LULCONST LVLCONST LUVLCONST +%token <sval> LSTRING LLSTRING +%token LAUTO LBREAK LCASE LCHAR LCONTINUE LDEFAULT LDO +%token LDOUBLE LELSE LEXTERN LFLOAT LFOR LGOTO +%token LIF LINT LLONG LREGISTER LRETURN LSHORT LSIZEOF LUSED +%token LSTATIC LSTRUCT LSWITCH LTYPEDEF LTYPESTR LUNION LUNSIGNED +%token LWHILE LVOID LENUM LSIGNED LCONSTNT LVOLATILE LSET LSIGNOF +%token LRESTRICT LINLINE +%% +prog: +| prog xdecl + +/* + * external declarator + */ +xdecl: + zctlist ';' + { + dodecl(xdecl, lastclass, lasttype, Z); + } +| zctlist xdlist ';' +| zctlist xdecor + { + lastdcl = T; + firstarg = S; + dodecl(xdecl, lastclass, lasttype, $2); + if(lastdcl == T || lastdcl->etype != TFUNC) { + diag($2, "not a function"); + lastdcl = types[TFUNC]; + } + thisfn = lastdcl; + markdcl(); + firstdcl = dclstack; + argmark($2, 0); + } + pdecl + { + argmark($2, 1); + } + block + { + Node *n; + + n = revertdcl(); + if(n) + $6 = new(OLIST, n, $6); + if(!debug['a'] && !debug['Z']) + codgen($6, $2); + } + +xdlist: + xdecor + { + dodecl(xdecl, lastclass, lasttype, $1); + } +| xdecor + { + $1 = dodecl(xdecl, lastclass, lasttype, $1); + } + '=' init + { + doinit($1->sym, $1->type, 0L, $4); + } +| xdlist ',' xdlist + +xdecor: + xdecor2 +| '*' zgnlist xdecor + { + $$ = new(OIND, $3, Z); + $$->garb = simpleg($2); + } + +xdecor2: + tag +| '(' xdecor ')' + { + $$ = $2; + } +| xdecor2 '(' zarglist ')' + { + $$ = new(OFUNC, $1, $3); + } +| xdecor2 '[' zexpr ']' + { + $$ = new(OARRAY, $1, $3); + } + +/* + * automatic declarator + */ +adecl: + ctlist ';' + { + $$ = dodecl(adecl, lastclass, lasttype, Z); + } +| ctlist adlist ';' + { + $$ = $2; + } + +adlist: + xdecor + { + dodecl(adecl, lastclass, lasttype, $1); + $$ = Z; + } +| xdecor + { + $1 = dodecl(adecl, lastclass, lasttype, $1); + } + '=' init + { + long w; + + w = $1->sym->type->width; + $$ = doinit($1->sym, $1->type, 0L, $4); + $$ = contig($1->sym, $$, w); + } +| adlist ',' adlist + { + $$ = $1; + if($3 != Z) { + $$ = $3; + if($1 != Z) + $$ = new(OLIST, $1, $3); + } + } + +/* + * parameter declarator + */ +pdecl: +| pdecl ctlist pdlist ';' + +pdlist: + xdecor + { + dodecl(pdecl, lastclass, lasttype, $1); + } +| pdlist ',' pdlist + +/* + * structure element declarator + */ +edecl: + tlist + { + lasttype = $1; + } + zedlist ';' +| edecl tlist + { + lasttype = $2; + } + zedlist ';' + +zedlist: /* extension */ + { + lastfield = 0; + edecl(CXXX, lasttype, S); + } +| edlist + +edlist: + edecor + { + dodecl(edecl, CXXX, lasttype, $1); + } +| edlist ',' edlist + +edecor: + xdecor + { + lastbit = 0; + firstbit = 1; + } +| tag ':' lexpr + { + $$ = new(OBIT, $1, $3); + } +| ':' lexpr + { + $$ = new(OBIT, Z, $2); + } + +/* + * abstract declarator + */ +abdecor: + { + $$ = (Z); + } +| abdecor1 + +abdecor1: + '*' zgnlist + { + $$ = new(OIND, (Z), Z); + $$->garb = simpleg($2); + } +| '*' zgnlist abdecor1 + { + $$ = new(OIND, $3, Z); + $$->garb = simpleg($2); + } +| abdecor2 + +abdecor2: + abdecor3 +| abdecor2 '(' zarglist ')' + { + $$ = new(OFUNC, $1, $3); + } +| abdecor2 '[' zexpr ']' + { + $$ = new(OARRAY, $1, $3); + } + +abdecor3: + '(' ')' + { + $$ = new(OFUNC, (Z), Z); + } +| '[' zexpr ']' + { + $$ = new(OARRAY, (Z), $2); + } +| '(' abdecor1 ')' + { + $$ = $2; + } + +init: + expr +| '{' ilist '}' + { + $$ = new(OINIT, invert($2), Z); + } + +qual: + '[' lexpr ']' + { + $$ = new(OARRAY, $2, Z); + } +| '.' ltag + { + $$ = new(OELEM, Z, Z); + $$->sym = $2; + } +| qual '=' + +qlist: + init ',' +| qlist init ',' + { + $$ = new(OLIST, $1, $2); + } +| qual +| qlist qual + { + $$ = new(OLIST, $1, $2); + } + +ilist: + qlist +| init +| qlist init + { + $$ = new(OLIST, $1, $2); + } + +zarglist: + { + $$ = Z; + } +| arglist + { + $$ = invert($1); + } + + +arglist: + name +| tlist abdecor + { + $$ = new(OPROTO, $2, Z); + $$->type = $1; + } +| tlist xdecor + { + $$ = new(OPROTO, $2, Z); + $$->type = $1; + } +| '.' '.' '.' + { + $$ = new(ODOTDOT, Z, Z); + } +| arglist ',' arglist + { + $$ = new(OLIST, $1, $3); + } + +block: + '{' slist '}' + { + $$ = invert($2); + // if($2 != Z) + // $$ = new(OLIST, $2, $$); + if($$ == Z) + $$ = new(OLIST, Z, Z); + } + +slist: + { + $$ = Z; + } +| slist adecl + { + $$ = new(OLIST, $1, $2); + } +| slist stmnt + { + $$ = new(OLIST, $1, $2); + } + +labels: + label +| labels label + { + $$ = new(OLIST, $1, $2); + } + +label: + LCASE expr ':' + { + $$ = new(OCASE, $2, Z); + } +| LDEFAULT ':' + { + $$ = new(OCASE, Z, Z); + } +| LNAME ':' + { + $$ = new(OLABEL, dcllabel($1, 1), Z); + } + +stmnt: + error ';' + { + $$ = Z; + } +| ulstmnt +| labels ulstmnt + { + $$ = new(OLIST, $1, $2); + } + +forexpr: + zcexpr +| ctlist adlist + { + $$ = $2; + } + +ulstmnt: + zcexpr ';' +| { + markdcl(); + } + block + { + $$ = revertdcl(); + if($$) + $$ = new(OLIST, $$, $2); + else + $$ = $2; + } +| LIF '(' cexpr ')' stmnt + { + $$ = new(OIF, $3, new(OLIST, $5, Z)); + if($5 == Z) + warn($3, "empty if body"); + } +| LIF '(' cexpr ')' stmnt LELSE stmnt + { + $$ = new(OIF, $3, new(OLIST, $5, $7)); + if($5 == Z) + warn($3, "empty if body"); + if($7 == Z) + warn($3, "empty else body"); + } +| { markdcl(); } LFOR '(' forexpr ';' zcexpr ';' zcexpr ')' stmnt + { + $$ = revertdcl(); + if($$){ + if($4) + $4 = new(OLIST, $$, $4); + else + $4 = $$; + } + $$ = new(OFOR, new(OLIST, $6, new(OLIST, $4, $8)), $10); + } +| LWHILE '(' cexpr ')' stmnt + { + $$ = new(OWHILE, $3, $5); + } +| LDO stmnt LWHILE '(' cexpr ')' ';' + { + $$ = new(ODWHILE, $5, $2); + } +| LRETURN zcexpr ';' + { + $$ = new(ORETURN, $2, Z); + $$->type = thisfn->link; + } +| LSWITCH '(' cexpr ')' stmnt + { + $$ = new(OCONST, Z, Z); + $$->vconst = 0; + $$->type = types[TINT]; + $3 = new(OSUB, $$, $3); + + $$ = new(OCONST, Z, Z); + $$->vconst = 0; + $$->type = types[TINT]; + $3 = new(OSUB, $$, $3); + + $$ = new(OSWITCH, $3, $5); + } +| LBREAK ';' + { + $$ = new(OBREAK, Z, Z); + } +| LCONTINUE ';' + { + $$ = new(OCONTINUE, Z, Z); + } +| LGOTO ltag ';' + { + $$ = new(OGOTO, dcllabel($2, 0), Z); + } +| LUSED '(' zelist ')' ';' + { + $$ = new(OUSED, $3, Z); + } +| LSET '(' zelist ')' ';' + { + $$ = new(OSET, $3, Z); + } + +zcexpr: + { + $$ = Z; + } +| cexpr + +zexpr: + { + $$ = Z; + } +| lexpr + +lexpr: + expr + { + $$ = new(OCAST, $1, Z); + $$->type = types[TLONG]; + } + +cexpr: + expr +| cexpr ',' cexpr + { + $$ = new(OCOMMA, $1, $3); + } + +expr: + xuexpr +| expr '*' expr + { + $$ = new(OMUL, $1, $3); + } +| expr '/' expr + { + $$ = new(ODIV, $1, $3); + } +| expr '%' expr + { + $$ = new(OMOD, $1, $3); + } +| expr '+' expr + { + $$ = new(OADD, $1, $3); + } +| expr '-' expr + { + $$ = new(OSUB, $1, $3); + } +| expr LRSH expr + { + $$ = new(OASHR, $1, $3); + } +| expr LLSH expr + { + $$ = new(OASHL, $1, $3); + } +| expr '<' expr + { + $$ = new(OLT, $1, $3); + } +| expr '>' expr + { + $$ = new(OGT, $1, $3); + } +| expr LLE expr + { + $$ = new(OLE, $1, $3); + } +| expr LGE expr + { + $$ = new(OGE, $1, $3); + } +| expr LEQ expr + { + $$ = new(OEQ, $1, $3); + } +| expr LNE expr + { + $$ = new(ONE, $1, $3); + } +| expr '&' expr + { + $$ = new(OAND, $1, $3); + } +| expr '^' expr + { + $$ = new(OXOR, $1, $3); + } +| expr '|' expr + { + $$ = new(OOR, $1, $3); + } +| expr LANDAND expr + { + $$ = new(OANDAND, $1, $3); + } +| expr LOROR expr + { + $$ = new(OOROR, $1, $3); + } +| expr '?' cexpr ':' expr + { + $$ = new(OCOND, $1, new(OLIST, $3, $5)); + } +| expr '=' expr + { + $$ = new(OAS, $1, $3); + } +| expr LPE expr + { + $$ = new(OASADD, $1, $3); + } +| expr LME expr + { + $$ = new(OASSUB, $1, $3); + } +| expr LMLE expr + { + $$ = new(OASMUL, $1, $3); + } +| expr LDVE expr + { + $$ = new(OASDIV, $1, $3); + } +| expr LMDE expr + { + $$ = new(OASMOD, $1, $3); + } +| expr LLSHE expr + { + $$ = new(OASASHL, $1, $3); + } +| expr LRSHE expr + { + $$ = new(OASASHR, $1, $3); + } +| expr LANDE expr + { + $$ = new(OASAND, $1, $3); + } +| expr LXORE expr + { + $$ = new(OASXOR, $1, $3); + } +| expr LORE expr + { + $$ = new(OASOR, $1, $3); + } + +xuexpr: + uexpr +| '(' tlist abdecor ')' xuexpr + { + $$ = new(OCAST, $5, Z); + dodecl(NODECL, CXXX, $2, $3); + $$->type = lastdcl; + $$->xcast = 1; + } +| '(' tlist abdecor ')' '{' ilist '}' /* extension */ + { + $$ = new(OSTRUCT, $6, Z); + dodecl(NODECL, CXXX, $2, $3); + $$->type = lastdcl; + } + +uexpr: + pexpr +| '*' xuexpr + { + $$ = new(OIND, $2, Z); + } +| '&' xuexpr + { + $$ = new(OADDR, $2, Z); + } +| '+' xuexpr + { + $$ = new(OPOS, $2, Z); + } +| '-' xuexpr + { + $$ = new(ONEG, $2, Z); + } +| '!' xuexpr + { + $$ = new(ONOT, $2, Z); + } +| '~' xuexpr + { + $$ = new(OCOM, $2, Z); + } +| LPP xuexpr + { + $$ = new(OPREINC, $2, Z); + } +| LMM xuexpr + { + $$ = new(OPREDEC, $2, Z); + } +| LSIZEOF uexpr + { + $$ = new(OSIZE, $2, Z); + } +| LSIGNOF uexpr + { + $$ = new(OSIGN, $2, Z); + } + +pexpr: + '(' cexpr ')' + { + $$ = $2; + } +| LSIZEOF '(' tlist abdecor ')' + { + $$ = new(OSIZE, Z, Z); + dodecl(NODECL, CXXX, $3, $4); + $$->type = lastdcl; + } +| LSIGNOF '(' tlist abdecor ')' + { + $$ = new(OSIGN, Z, Z); + dodecl(NODECL, CXXX, $3, $4); + $$->type = lastdcl; + } +| pexpr '(' zelist ')' + { + $$ = new(OFUNC, $1, Z); + if($1->op == ONAME) + if($1->type == T) + dodecl(xdecl, CXXX, types[TINT], $$); + $$->right = invert($3); + } +| pexpr '[' cexpr ']' + { + $$ = new(OIND, new(OADD, $1, $3), Z); + } +| pexpr LMG ltag + { + $$ = new(ODOT, new(OIND, $1, Z), Z); + $$->sym = $3; + } +| pexpr '.' ltag + { + $$ = new(ODOT, $1, Z); + $$->sym = $3; + } +| pexpr LPP + { + $$ = new(OPOSTINC, $1, Z); + } +| pexpr LMM + { + $$ = new(OPOSTDEC, $1, Z); + } +| name +| LCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TINT]; + $$->vconst = $1; + $$->cstring = strdup(symb); + } +| LLCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TLONG]; + $$->vconst = $1; + $$->cstring = strdup(symb); + } +| LUCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TUINT]; + $$->vconst = $1; + $$->cstring = strdup(symb); + } +| LULCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TULONG]; + $$->vconst = $1; + $$->cstring = strdup(symb); + } +| LDCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TDOUBLE]; + $$->fconst = $1; + $$->cstring = strdup(symb); + } +| LFCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TFLOAT]; + $$->fconst = $1; + $$->cstring = strdup(symb); + } +| LVLCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TVLONG]; + $$->vconst = $1; + $$->cstring = strdup(symb); + } +| LUVLCONST + { + $$ = new(OCONST, Z, Z); + $$->type = types[TUVLONG]; + $$->vconst = $1; + $$->cstring = strdup(symb); + } +| string +| lstring + +string: + LSTRING + { + $$ = new(OSTRING, Z, Z); + $$->type = typ(TARRAY, types[TCHAR]); + $$->type->width = $1.l + 1; + $$->cstring = $1.s; + $$->sym = symstring; + $$->etype = TARRAY; + $$->class = CSTATIC; + } +| string LSTRING + { + char *s; + int n; + + n = $1->type->width - 1; + s = alloc(n+$2.l+MAXALIGN); + + memcpy(s, $1->cstring, n); + memcpy(s+n, $2.s, $2.l); + s[n+$2.l] = 0; + + $$ = $1; + $$->type->width += $2.l; + $$->cstring = s; + } + +lstring: + LLSTRING + { + $$ = new(OLSTRING, Z, Z); + $$->type = typ(TARRAY, types[TUSHORT]); + $$->type->width = $1.l + sizeof(ushort); + $$->rstring = (ushort*)$1.s; + $$->sym = symstring; + $$->etype = TARRAY; + $$->class = CSTATIC; + } +| lstring LLSTRING + { + char *s; + int n; + + n = $1->type->width - sizeof(ushort); + s = alloc(n+$2.l+MAXALIGN); + + memcpy(s, $1->rstring, n); + memcpy(s+n, $2.s, $2.l); + *(ushort*)(s+n+$2.l) = 0; + + $$ = $1; + $$->type->width += $2.l; + $$->rstring = (ushort*)s; + } + +zelist: + { + $$ = Z; + } +| elist + +elist: + expr +| elist ',' elist + { + $$ = new(OLIST, $1, $3); + } + +sbody: + '{' + { + $<tyty>$.t1 = strf; + $<tyty>$.t2 = strl; + strf = T; + strl = T; + lastbit = 0; + firstbit = 1; + } + edecl '}' + { + $$ = strf; + strf = $<tyty>2.t1; + strl = $<tyty>2.t2; + } + +zctlist: + { + lastclass = CXXX; + lasttype = types[TINT]; + } +| ctlist + +types: + complex + { + $$.t = $1; + $$.c = CXXX; + } +| tname + { + $$.t = simplet($1); + $$.c = CXXX; + } +| gcnlist + { + $$.t = simplet($1); + $$.c = simplec($1); + $$.t = garbt($$.t, $1); + } +| complex gctnlist + { + $$.t = $1; + $$.c = simplec($2); + $$.t = garbt($$.t, $2); + if($2 & ~BCLASS & ~BGARB) + diag(Z, "duplicate types given: %T and %Q", $1, $2); + } +| tname gctnlist + { + $$.t = simplet(typebitor($1, $2)); + $$.c = simplec($2); + $$.t = garbt($$.t, $2); + } +| gcnlist complex zgnlist + { + $$.t = $2; + $$.c = simplec($1); + $$.t = garbt($$.t, $1|$3); + } +| gcnlist tname + { + $$.t = simplet($2); + $$.c = simplec($1); + $$.t = garbt($$.t, $1); + } +| gcnlist tname gctnlist + { + $$.t = simplet(typebitor($2, $3)); + $$.c = simplec($1|$3); + $$.t = garbt($$.t, $1|$3); + } + +tlist: + types + { + $$ = $1.t; + if($1.c != CXXX) + diag(Z, "illegal combination of class 4: %s", cnames[$1.c]); + } + +ctlist: + types + { + lasttype = $1.t; + lastclass = $1.c; + } + +complex: + LSTRUCT ltag + { + dotag($2, TSTRUCT, 0); + $$ = $2->suetag; + } +| LSTRUCT ltag + { + dotag($2, TSTRUCT, autobn); + } + sbody + { + $$ = $2->suetag; + if($$->link != T) + diag(Z, "redeclare tag: %s", $2->name); + $$->link = $4; + suallign($$); + } +| LSTRUCT sbody + { + taggen++; + sprint(symb, "_%d_", taggen); + $$ = dotag(lookup(), TSTRUCT, autobn); + $$->link = $2; + suallign($$); + } +| LUNION ltag + { + dotag($2, TUNION, 0); + $$ = $2->suetag; + } +| LUNION ltag + { + dotag($2, TUNION, autobn); + } + sbody + { + $$ = $2->suetag; + if($$->link != T) + diag(Z, "redeclare tag: %s", $2->name); + $$->link = $4; + suallign($$); + } +| LUNION sbody + { + taggen++; + sprint(symb, "_%d_", taggen); + $$ = dotag(lookup(), TUNION, autobn); + $$->link = $2; + suallign($$); + } +| LENUM ltag + { + dotag($2, TENUM, 0); + $$ = $2->suetag; + if($$->link == T) + $$->link = types[TINT]; + $$ = $$->link; + } +| LENUM ltag + { + dotag($2, TENUM, autobn); + } + '{' + { + en.tenum = T; + en.cenum = T; + } + enum '}' + { + $$ = $2->suetag; + if($$->link != T) + diag(Z, "redeclare tag: %s", $2->name); + if(en.tenum == T) { + diag(Z, "enum type ambiguous: %s", $2->name); + en.tenum = types[TINT]; + } + $$->link = en.tenum; + $$ = en.tenum; + } +| LENUM '{' + { + en.tenum = T; + en.cenum = T; + } + enum '}' + { + $$ = en.tenum; + } +| LTYPE + { + $$ = tcopy($1->type); + } + +gctnlist: + gctname +| gctnlist gctname + { + $$ = typebitor($1, $2); + } + +zgnlist: + { + $$ = 0; + } +| zgnlist gname + { + $$ = typebitor($1, $2); + } + +gctname: + tname +| gname +| cname + +gcnlist: + gcname +| gcnlist gcname + { + $$ = typebitor($1, $2); + } + +gcname: + gname +| cname + +enum: + LNAME + { + doenum($1, Z); + } +| LNAME '=' expr + { + doenum($1, $3); + } +| enum ',' +| enum ',' enum + +tname: /* type words */ + LCHAR { $$ = BCHAR; } +| LSHORT { $$ = BSHORT; } +| LINT { $$ = BINT; } +| LLONG { $$ = BLONG; } +| LSIGNED { $$ = BSIGNED; } +| LUNSIGNED { $$ = BUNSIGNED; } +| LFLOAT { $$ = BFLOAT; } +| LDOUBLE { $$ = BDOUBLE; } +| LVOID { $$ = BVOID; } + +cname: /* class words */ + LAUTO { $$ = BAUTO; } +| LSTATIC { $$ = BSTATIC; } +| LEXTERN { $$ = BEXTERN; } +| LTYPEDEF { $$ = BTYPEDEF; } +| LTYPESTR { $$ = BTYPESTR; } +| LREGISTER { $$ = BREGISTER; } +| LINLINE { $$ = 0; } + +gname: /* garbage words */ + LCONSTNT { $$ = BCONSTNT; } +| LVOLATILE { $$ = BVOLATILE; } +| LRESTRICT { $$ = 0; } + +name: + LNAME + { + $$ = new(ONAME, Z, Z); + if($1->class == CLOCAL) + $1 = mkstatic($1); + $$->sym = $1; + $$->type = $1->type; + $$->etype = TVOID; + if($$->type != T) + $$->etype = $$->type->etype; + $$->xoffset = $1->offset; + $$->class = $1->class; + $1->aused = 1; + } +tag: + ltag + { + $$ = new(ONAME, Z, Z); + $$->sym = $1; + $$->type = $1->type; + $$->etype = TVOID; + if($$->type != T) + $$->etype = $$->type->etype; + $$->xoffset = $1->offset; + $$->class = $1->class; + } +ltag: + LNAME +| LTYPE +%% diff --git a/src/cmd/cc/com.c b/src/cmd/cc/com.c new file mode 100644 index 000000000..b0b1620ce --- /dev/null +++ b/src/cmd/cc/com.c @@ -0,0 +1,1378 @@ +// Inferno utils/cc/com.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/com.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "cc.h" + +int compar(Node*, int); + +void +complex(Node *n) +{ + + if(n == Z) + return; + + nearln = n->lineno; + if(debug['t']) + if(n->op != OCONST) + prtree(n, "pre complex"); + if(tcom(n)) + return; + if(debug['t']) + if(n->op != OCONST) + prtree(n, "t complex"); + ccom(n); + if(debug['t']) + if(n->op != OCONST) + prtree(n, "c complex"); + acom(n); + if(debug['t']) + if(n->op != OCONST) + prtree(n, "a complex"); + xcom(n); + if(debug['t']) + if(n->op != OCONST) + prtree(n, "x complex"); +} + +/* + * evaluate types + * evaluate lvalues (addable == 1) + */ +enum +{ + ADDROF = 1<<0, + CASTOF = 1<<1, + ADDROP = 1<<2, +}; + +int +tcom(Node *n) +{ + + return tcomo(n, ADDROF); +} + +int +tcomo(Node *n, int f) +{ + Node *l, *r; + Type *t; + int o; + + if(n == Z) { + diag(Z, "Z in tcom"); + errorexit(); + } + n->addable = 0; + l = n->left; + r = n->right; + + switch(n->op) { + default: + diag(n, "unknown op in type complex: %O", n->op); + goto bad; + + case ODOTDOT: + /* + * tcom has already been called on this subtree + */ + *n = *n->left; + if(n->type == T) + goto bad; + break; + + case OCAST: + if(n->type == T) + break; + if(n->type->width == types[TLONG]->width) { + if(tcomo(l, ADDROF|CASTOF)) + goto bad; + } else + if(tcom(l)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, n->type, tcast)) + goto bad; + break; + + case ORETURN: + if(l == Z) { + if(n->type->etype != TVOID) + warn(n, "null return of a typed function"); + break; + } + if(tcom(l)) + goto bad; + typeext(n->type, l); + if(tcompat(n, n->type, l->type, tasign)) + break; + constas(n, n->type, l->type); + if(!sametype(n->type, l->type)) { + l = new1(OCAST, l, Z); + l->type = n->type; + n->left = l; + } + break; + + case OASI: /* same as as, but no test for const */ + n->op = OAS; + o = tcom(l); + if(o | tcom(r)) + goto bad; + + typeext(l->type, r); + if(tlvalue(l) || tcompat(n, l->type, r->type, tasign)) + goto bad; + if(!sametype(l->type, r->type)) { + r = new1(OCAST, r, Z); + r->type = l->type; + n->right = r; + } + n->type = l->type; + break; + + case OAS: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(tlvalue(l)) + goto bad; + if(isfunct(n)) + break; + typeext(l->type, r); + if(tcompat(n, l->type, r->type, tasign)) + goto bad; + constas(n, l->type, r->type); + if(!sametype(l->type, r->type)) { + r = new1(OCAST, r, Z); + r->type = l->type; + n->right = r; + } + n->type = l->type; + break; + + case OASADD: + case OASSUB: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(tlvalue(l)) + goto bad; + if(isfunct(n)) + break; + typeext1(l->type, r); + if(tcompat(n, l->type, r->type, tasadd)) + goto bad; + constas(n, l->type, r->type); + t = l->type; + arith(n, 0); + while(n->left->op == OCAST) + n->left = n->left->left; + if(!sametype(t, n->type) && !mixedasop(t, n->type)) { + r = new1(OCAST, n->right, Z); + r->type = t; + n->right = r; + n->type = t; + } + break; + + case OASMUL: + case OASLMUL: + case OASDIV: + case OASLDIV: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(tlvalue(l)) + goto bad; + if(isfunct(n)) + break; + typeext1(l->type, r); + if(tcompat(n, l->type, r->type, tmul)) + goto bad; + constas(n, l->type, r->type); + t = l->type; + arith(n, 0); + while(n->left->op == OCAST) + n->left = n->left->left; + if(!sametype(t, n->type) && !mixedasop(t, n->type)) { + r = new1(OCAST, n->right, Z); + r->type = t; + n->right = r; + n->type = t; + } + if(typeu[n->type->etype]) { + if(n->op == OASDIV) + n->op = OASLDIV; + if(n->op == OASMUL) + n->op = OASLMUL; + } + break; + + case OASLSHR: + case OASASHR: + case OASASHL: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(tlvalue(l)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, r->type, tand)) + goto bad; + n->type = l->type; + if(typeu[n->type->etype]) { + if(n->op == OASASHR) + n->op = OASLSHR; + } + break; + + case OASMOD: + case OASLMOD: + case OASOR: + case OASAND: + case OASXOR: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(tlvalue(l)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, r->type, tand)) + goto bad; + t = l->type; + arith(n, 0); + while(n->left->op == OCAST) + n->left = n->left->left; + if(!sametype(t, n->type) && !mixedasop(t, n->type)) { + r = new1(OCAST, n->right, Z); + r->type = t; + n->right = r; + n->type = t; + } + if(typeu[n->type->etype]) { + if(n->op == OASMOD) + n->op = OASLMOD; + } + break; + + case OPREINC: + case OPREDEC: + case OPOSTINC: + case OPOSTDEC: + if(tcom(l)) + goto bad; + if(tlvalue(l)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, types[TINT], tadd)) + goto bad; + n->type = l->type; + if(n->type->etype == TIND) + if(n->type->link->width < 1) + diag(n, "inc/dec of a void pointer"); + break; + + case OEQ: + case ONE: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(isfunct(n)) + break; + typeext(l->type, r); + typeext(r->type, l); + if(tcompat(n, l->type, r->type, trel)) + goto bad; + arith(n, 0); + n->type = types[TINT]; + break; + + case OLT: + case OGE: + case OGT: + case OLE: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(isfunct(n)) + break; + typeext1(l->type, r); + typeext1(r->type, l); + if(tcompat(n, l->type, r->type, trel)) + goto bad; + arith(n, 0); + if(typeu[n->type->etype]) + n->op = logrel[relindex(n->op)]; + n->type = types[TINT]; + break; + + case OCOND: + o = tcom(l); + o |= tcom(r->left); + if(o | tcom(r->right)) + goto bad; + if(r->right->type->etype == TIND && vconst(r->left) == 0) { + r->left->type = r->right->type; + r->left->vconst = 0; + } + if(r->left->type->etype == TIND && vconst(r->right) == 0) { + r->right->type = r->left->type; + r->right->vconst = 0; + } + if(sametype(r->right->type, r->left->type)) { + r->type = r->right->type; + n->type = r->type; + break; + } + if(tcompat(r, r->left->type, r->right->type, trel)) + goto bad; + arith(r, 0); + n->type = r->type; + break; + + case OADD: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, r->type, tadd)) + goto bad; + arith(n, 1); + break; + + case OSUB: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, r->type, tsub)) + goto bad; + arith(n, 1); + break; + + case OMUL: + case OLMUL: + case ODIV: + case OLDIV: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, r->type, tmul)) + goto bad; + arith(n, 1); + if(typeu[n->type->etype]) { + if(n->op == ODIV) + n->op = OLDIV; + if(n->op == OMUL) + n->op = OLMUL; + } + break; + + case OLSHR: + case OASHL: + case OASHR: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, r->type, tand)) + goto bad; + n->right = Z; + arith(n, 1); + n->right = new1(OCAST, r, Z); + n->right->type = types[TINT]; + if(typeu[n->type->etype]) + if(n->op == OASHR) + n->op = OLSHR; + break; + + case OAND: + case OOR: + case OXOR: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, r->type, tand)) + goto bad; + arith(n, 1); + break; + + case OMOD: + case OLMOD: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, l->type, r->type, tand)) + goto bad; + arith(n, 1); + if(typeu[n->type->etype]) + n->op = OLMOD; + break; + + case OPOS: + if(tcom(l)) + goto bad; + if(isfunct(n)) + break; + + r = l; + l = new(OCONST, Z, Z); + l->vconst = 0; + l->type = types[TINT]; + n->op = OADD; + n->right = r; + n->left = l; + + if(tcom(l)) + goto bad; + if(tcompat(n, l->type, r->type, tsub)) + goto bad; + arith(n, 1); + break; + + case ONEG: + if(tcom(l)) + goto bad; + if(isfunct(n)) + break; + + if(!machcap(n)) { + r = l; + l = new(OCONST, Z, Z); + l->vconst = 0; + l->type = types[TINT]; + n->op = OSUB; + n->right = r; + n->left = l; + + if(tcom(l)) + goto bad; + if(tcompat(n, l->type, r->type, tsub)) + goto bad; + } + arith(n, 1); + break; + + case OCOM: + if(tcom(l)) + goto bad; + if(isfunct(n)) + break; + + if(!machcap(n)) { + r = l; + l = new(OCONST, Z, Z); + l->vconst = -1; + l->type = types[TINT]; + n->op = OXOR; + n->right = r; + n->left = l; + + if(tcom(l)) + goto bad; + if(tcompat(n, l->type, r->type, tand)) + goto bad; + } + arith(n, 1); + break; + + case ONOT: + if(tcom(l)) + goto bad; + if(isfunct(n)) + break; + if(tcompat(n, T, l->type, tnot)) + goto bad; + n->type = types[TINT]; + break; + + case OANDAND: + case OOROR: + o = tcom(l); + if(o | tcom(r)) + goto bad; + if(tcompat(n, T, l->type, tnot) | + tcompat(n, T, r->type, tnot)) + goto bad; + n->type = types[TINT]; + break; + + case OCOMMA: + o = tcom(l); + if(o | tcom(r)) + goto bad; + n->type = r->type; + break; + + + case OSIGN: /* extension signof(type) returns a hash */ + if(l != Z) { + if(l->op != OSTRING && l->op != OLSTRING) + if(tcomo(l, 0)) + goto bad; + if(l->op == OBIT) { + diag(n, "signof bitfield"); + goto bad; + } + n->type = l->type; + } + if(n->type == T) + goto bad; + if(n->type->width < 0) { + diag(n, "signof undefined type"); + goto bad; + } + n->op = OCONST; + n->left = Z; + n->right = Z; + n->vconst = convvtox(signature(n->type), TULONG); + n->type = types[TULONG]; + break; + + case OSIZE: + if(l != Z) { + if(l->op != OSTRING && l->op != OLSTRING) + if(tcomo(l, 0)) + goto bad; + if(l->op == OBIT) { + diag(n, "sizeof bitfield"); + goto bad; + } + n->type = l->type; + } + if(n->type == T) + goto bad; + if(n->type->width <= 0) { + diag(n, "sizeof undefined type"); + goto bad; + } + if(n->type->etype == TFUNC) { + diag(n, "sizeof function"); + goto bad; + } + n->op = OCONST; + n->left = Z; + n->right = Z; + n->vconst = convvtox(n->type->width, TINT); + n->type = types[TINT]; + break; + + case OFUNC: + o = tcomo(l, 0); + if(o) + goto bad; + if(l->type->etype == TIND && l->type->link->etype == TFUNC) { + l = new1(OIND, l, Z); + l->type = l->left->type->link; + n->left = l; + } + if(tcompat(n, T, l->type, tfunct)) + goto bad; + if(o | tcoma(l, r, l->type->down, 1)) + goto bad; + n->type = l->type->link; + if(!debug['B']) + if(l->type->down == T || l->type->down->etype == TOLD) { + nerrors--; + diag(n, "function args not checked: %F", l); + } + dpcheck(n); + break; + + case ONAME: + if(n->type == T) { + diag(n, "name not declared: %F", n); + goto bad; + } + if(n->type->etype == TENUM) { + n->op = OCONST; + n->type = n->sym->tenum; + if(!typefd[n->type->etype]) + n->vconst = n->sym->vconst; + else + n->fconst = n->sym->fconst; + break; + } + n->addable = 1; + if(n->class == CEXREG) { + n->op = OREGISTER; + n->reg = n->sym->offset; + n->xoffset = 0; + break; + } + break; + + case OLSTRING: + if(n->type->link != types[TUSHORT]) { + o = outstring(0, 0); + while(o & 3) { + ushort a[1]; + a[0] = 0; + outlstring(a, sizeof(ushort)); + o = outlstring(0, 0); + } + } + n->op = ONAME; + n->xoffset = outlstring(n->rstring, n->type->width); + n->addable = 1; + break; + + case OSTRING: + if(n->type->link != types[TCHAR]) { + o = outstring(0, 0); + while(o & 3) { + outstring("", 1); + o = outstring(0, 0); + } + } + n->op = ONAME; + n->xoffset = outstring(n->cstring, n->type->width); + n->addable = 1; + break; + + case OCONST: + break; + + case ODOT: + if(tcom(l)) + goto bad; + if(tcompat(n, T, l->type, tdot)) + goto bad; + if(tcomd(n)) + goto bad; + break; + + case OADDR: + if(tcomo(l, ADDROP)) + goto bad; + if(tlvalue(l)) + goto bad; + if(l->type->nbits) { + diag(n, "address of a bit field"); + goto bad; + } + if(l->op == OREGISTER) { + diag(n, "address of a register"); + goto bad; + } + n->type = typ(TIND, l->type); + n->type->width = types[TIND]->width; + break; + + case OIND: + if(tcom(l)) + goto bad; + if(tcompat(n, T, l->type, tindir)) + goto bad; + n->type = l->type->link; + n->addable = 1; + break; + + case OSTRUCT: + if(tcomx(n)) + goto bad; + break; + } + t = n->type; + if(t == T) + goto bad; + if(t->width < 0) { + snap(t); + if(t->width < 0) { + if(typesu[t->etype] && t->tag) + diag(n, "structure not fully declared %s", t->tag->name); + else + diag(n, "structure not fully declared"); + goto bad; + } + } + if(typeaf[t->etype]) { + if(f & ADDROF) + goto addaddr; + if(f & ADDROP) + warn(n, "address of array/func ignored"); + } + return 0; + +addaddr: + if(tlvalue(n)) + goto bad; + l = new1(OXXX, Z, Z); + *l = *n; + n->op = OADDR; + if(l->type->etype == TARRAY) + l->type = l->type->link; + n->left = l; + n->right = Z; + n->addable = 0; + n->type = typ(TIND, l->type); + n->type->width = types[TIND]->width; + return 0; + +bad: + n->type = T; + return 1; +} + +int +tcoma(Node *l, Node *n, Type *t, int f) +{ + Node *n1; + int o; + + if(t != T) + if(t->etype == TOLD || t->etype == TDOT) /* .../old in prototype */ + t = T; + if(n == Z) { + if(t != T && !sametype(t, types[TVOID])) { + diag(n, "not enough function arguments: %F", l); + return 1; + } + return 0; + } + if(n->op == OLIST) { + o = tcoma(l, n->left, t, 0); + if(t != T) { + t = t->down; + if(t == T) + t = types[TVOID]; + } + return o | tcoma(l, n->right, t, 1); + } + if(f && t != T) + tcoma(l, Z, t->down, 0); + if(tcom(n) || tcompat(n, T, n->type, targ)) + return 1; + if(sametype(t, types[TVOID])) { + diag(n, "too many function arguments: %F", l); + return 1; + } + if(t != T) { + typeext(t, n); + if(stcompat(nodproto, t, n->type, tasign)) { + diag(l, "argument prototype mismatch \"%T\" for \"%T\": %F", + n->type, t, l); + return 1; + } + switch(t->etype) { + case TCHAR: + case TSHORT: + t = types[TINT]; + break; + + case TUCHAR: + case TUSHORT: + t = types[TUINT]; + break; + } + } else + switch(n->type->etype) + { + case TCHAR: + case TSHORT: + t = types[TINT]; + break; + + case TUCHAR: + case TUSHORT: + t = types[TUINT]; + break; + + case TFLOAT: + t = types[TDOUBLE]; + } + if(t != T && !sametype(t, n->type)) { + n1 = new1(OXXX, Z, Z); + *n1 = *n; + n->op = OCAST; + n->left = n1; + n->right = Z; + n->type = t; + n->addable = 0; + } + return 0; +} + +int +tcomd(Node *n) +{ + Type *t; + long o; + + o = 0; + t = dotsearch(n->sym, n->left->type->link, n, &o); + if(t == T) { + diag(n, "not a member of struct/union: %F", n); + return 1; + } + makedot(n, t, o); + return 0; +} + +int +tcomx(Node *n) +{ + Type *t; + Node *l, *r, **ar, **al; + int e; + + e = 0; + if(n->type->etype != TSTRUCT) { + diag(n, "constructor must be a structure"); + return 1; + } + l = invert(n->left); + n->left = l; + al = &n->left; + for(t = n->type->link; t != T; t = t->down) { + if(l == Z) { + diag(n, "constructor list too short"); + return 1; + } + if(l->op == OLIST) { + r = l->left; + ar = &l->left; + al = &l->right; + l = l->right; + } else { + r = l; + ar = al; + l = Z; + } + if(tcom(r)) + e++; + typeext(t, r); + if(tcompat(n, t, r->type, tasign)) + e++; + constas(n, t, r->type); + if(!e && !sametype(t, r->type)) { + r = new1(OCAST, r, Z); + r->type = t; + *ar = r; + } + } + if(l != Z) { + diag(n, "constructor list too long"); + return 1; + } + return e; +} + +int +tlvalue(Node *n) +{ + + if(!n->addable) { + diag(n, "not an l-value"); + return 1; + } + return 0; +} + +/* + * general rewrite + * (IND(ADDR x)) ==> x + * (ADDR(IND x)) ==> x + * remove some zero operands + * remove no op casts + * evaluate constants + */ +void +ccom(Node *n) +{ + Node *l, *r; + int t; + +loop: + if(n == Z) + return; + l = n->left; + r = n->right; + switch(n->op) { + + case OAS: + case OASXOR: + case OASAND: + case OASOR: + case OASMOD: + case OASLMOD: + case OASLSHR: + case OASASHR: + case OASASHL: + case OASDIV: + case OASLDIV: + case OASMUL: + case OASLMUL: + case OASSUB: + case OASADD: + ccom(l); + ccom(r); + if(n->op == OASLSHR || n->op == OASASHR || n->op == OASASHL) + if(r->op == OCONST) { + t = n->type->width * 8; /* bits per byte */ + if(r->vconst >= t || r->vconst < 0) + warn(n, "stupid shift: %lld", r->vconst); + } + break; + + case OCAST: + ccom(l); + if(l->op == OCONST) { + evconst(n); + if(n->op == OCONST) + break; + } + if(nocast(l->type, n->type)) { + l->type = n->type; + *n = *l; + } + break; + + case OCOND: + ccom(l); + ccom(r); + if(l->op == OCONST) + if(vconst(l) == 0) + *n = *r->right; + else + *n = *r->left; + break; + + case OREGISTER: + case OINDREG: + case OCONST: + case ONAME: + break; + + case OADDR: + ccom(l); + l->etype = TVOID; + if(l->op == OIND) { + l->left->type = n->type; + *n = *l->left; + break; + } + goto common; + + case OIND: + ccom(l); + if(l->op == OADDR) { + l->left->type = n->type; + *n = *l->left; + break; + } + goto common; + + case OEQ: + case ONE: + + case OLE: + case OGE: + case OLT: + case OGT: + + case OLS: + case OHS: + case OLO: + case OHI: + ccom(l); + ccom(r); + if(compar(n, 0) || compar(n, 1)) + break; + relcon(l, r); + relcon(r, l); + goto common; + + case OASHR: + case OASHL: + case OLSHR: + ccom(l); + if(vconst(l) == 0 && !side(r)) { + *n = *l; + break; + } + ccom(r); + if(vconst(r) == 0) { + *n = *l; + break; + } + if(r->op == OCONST) { + t = n->type->width * 8; /* bits per byte */ + if(r->vconst >= t || r->vconst <= -t) + warn(n, "stupid shift: %lld", r->vconst); + } + goto common; + + case OMUL: + case OLMUL: + ccom(l); + t = vconst(l); + if(t == 0 && !side(r)) { + *n = *l; + break; + } + if(t == 1) { + *n = *r; + goto loop; + } + ccom(r); + t = vconst(r); + if(t == 0 && !side(l)) { + *n = *r; + break; + } + if(t == 1) { + *n = *l; + break; + } + goto common; + + case ODIV: + case OLDIV: + ccom(l); + if(vconst(l) == 0 && !side(r)) { + *n = *l; + break; + } + ccom(r); + t = vconst(r); + if(t == 0) { + diag(n, "divide check"); + *n = *r; + break; + } + if(t == 1) { + *n = *l; + break; + } + goto common; + + case OSUB: + ccom(r); + if(r->op == OCONST) { + if(typefd[r->type->etype]) { + n->op = OADD; + r->fconst = -r->fconst; + goto loop; + } else { + n->op = OADD; + r->vconst = -r->vconst; + goto loop; + } + } + ccom(l); + goto common; + + case OXOR: + case OOR: + case OADD: + ccom(l); + if(vconst(l) == 0) { + *n = *r; + goto loop; + } + ccom(r); + if(vconst(r) == 0) { + *n = *l; + break; + } + goto commute; + + case OAND: + ccom(l); + ccom(r); + if(vconst(l) == 0 && !side(r)) { + *n = *l; + break; + } + if(vconst(r) == 0 && !side(l)) { + *n = *r; + break; + } + + commute: + /* look for commutative constant */ + if(r->op == OCONST) { + if(l->op == n->op) { + if(l->left->op == OCONST) { + n->right = l->right; + l->right = r; + goto loop; + } + if(l->right->op == OCONST) { + n->right = l->left; + l->left = r; + goto loop; + } + } + } + if(l->op == OCONST) { + if(r->op == n->op) { + if(r->left->op == OCONST) { + n->left = r->right; + r->right = l; + goto loop; + } + if(r->right->op == OCONST) { + n->left = r->left; + r->left = l; + goto loop; + } + } + } + goto common; + + case OANDAND: + ccom(l); + if(vconst(l) == 0) { + *n = *l; + break; + } + ccom(r); + goto common; + + case OOROR: + ccom(l); + if(l->op == OCONST && l->vconst != 0) { + *n = *l; + n->vconst = 1; + break; + } + ccom(r); + goto common; + + default: + if(l != Z) + ccom(l); + if(r != Z) + ccom(r); + common: + if(l != Z) + if(l->op != OCONST) + break; + if(r != Z) + if(r->op != OCONST) + break; + evconst(n); + } +} + +/* OEQ, ONE, OLE, OLS, OLT, OLO, OGE, OHS, OGT, OHI */ +static char *cmps[12] = +{ + "==", "!=", "<=", "<=", "<", "<", ">=", ">=", ">", ">", +}; + +/* 128-bit numbers */ +typedef struct Big Big; +struct Big +{ + vlong a; + uvlong b; +}; +static int +cmp(Big x, Big y) +{ + if(x.a != y.a){ + if(x.a < y.a) + return -1; + return 1; + } + if(x.b != y.b){ + if(x.b < y.b) + return -1; + return 1; + } + return 0; +} +static Big +add(Big x, int y) +{ + uvlong ob; + + ob = x.b; + x.b += y; + if(y > 0 && x.b < ob) + x.a++; + if(y < 0 && x.b > ob) + x.a--; + return x; +} + +Big +big(vlong a, uvlong b) +{ + Big x; + + x.a = a; + x.b = b; + return x; +} + +int +compar(Node *n, int reverse) +{ + Big lo, hi, x; + int op; + char xbuf[40], cmpbuf[50]; + Node *l, *r; + Type *lt, *rt; + + /* + * The point of this function is to diagnose comparisons + * that can never be true or that look misleading because + * of the `usual arithmetic conversions'. As an example + * of the latter, if x is a ulong, then if(x <= -1) really means + * if(x <= 0xFFFFFFFF), while if(x <= -1LL) really means + * what it says (but 8c compiles it wrong anyway). + */ + + if(reverse){ + r = n->left; + l = n->right; + op = comrel[relindex(n->op)]; + }else{ + l = n->left; + r = n->right; + op = n->op; + } + + /* + * Skip over left casts to find out the original expression range. + */ + while(l->op == OCAST) + l = l->left; + if(l->op == OCONST) + return 0; + lt = l->type; + if(l->op == ONAME && l->sym->type){ + lt = l->sym->type; + if(lt->etype == TARRAY) + lt = lt->link; + } + if(lt == T) + return 0; + if(lt->etype == TXXX || lt->etype > TUVLONG) + return 0; + + /* + * Skip over the right casts to find the on-screen value. + */ + if(r->op != OCONST) + return 0; + while(r->oldop == OCAST && !r->xcast) + r = r->left; + rt = r->type; + if(rt == T) + return 0; + + x.b = r->vconst; + x.a = 0; + if((rt->etype&1) && r->vconst < 0) /* signed negative */ + x.a = ~0ULL; + + if((lt->etype&1)==0){ + /* unsigned */ + lo = big(0, 0); + if(lt->width == 8) + hi = big(0, ~0ULL); + else + hi = big(0, (1LL<<(l->type->width*8))-1); + }else{ + lo = big(~0ULL, -(1LL<<(l->type->width*8-1))); + hi = big(0, (1LL<<(l->type->width*8-1))-1); + } + + switch(op){ + case OLT: + case OLO: + case OGE: + case OHS: + if(cmp(x, lo) <= 0) + goto useless; + if(cmp(x, add(hi, 1)) >= 0) + goto useless; + break; + case OLE: + case OLS: + case OGT: + case OHI: + if(cmp(x, add(lo, -1)) <= 0) + goto useless; + if(cmp(x, hi) >= 0) + goto useless; + break; + case OEQ: + case ONE: + /* + * Don't warn about comparisons if the expression + * is as wide as the value: the compiler-supplied casts + * will make both outcomes possible. + */ + if(lt->width >= rt->width && debug['w'] < 2) + return 0; + if(cmp(x, lo) < 0 || cmp(x, hi) > 0) + goto useless; + break; + } + return 0; + +useless: + if((x.a==0 && x.b<=9) || (x.a==~0LL && x.b >= -9ULL)) + snprint(xbuf, sizeof xbuf, "%lld", x.b); + else if(x.a == 0) + snprint(xbuf, sizeof xbuf, "%#llux", x.b); + else + snprint(xbuf, sizeof xbuf, "%#llx", x.b); + if(reverse) + snprint(cmpbuf, sizeof cmpbuf, "%s %s %T", + xbuf, cmps[relindex(n->op)], lt); + else + snprint(cmpbuf, sizeof cmpbuf, "%T %s %s", + lt, cmps[relindex(n->op)], xbuf); + warn(n, "useless or misleading comparison: %s", cmpbuf); + return 0; +} + diff --git a/src/cmd/cc/com64.c b/src/cmd/cc/com64.c new file mode 100644 index 000000000..8d6e07d1b --- /dev/null +++ b/src/cmd/cc/com64.c @@ -0,0 +1,643 @@ +// Inferno utils/cc/com64.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/com64.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "cc.h" + +/* + * this is machine depend, but it is totally + * common on all of the 64-bit symulating machines. + */ + +#define FNX 100 /* botch -- redefinition */ + +Node* nodaddv; +Node* nodsubv; +Node* nodmulv; +Node* noddivv; +Node* noddivvu; +Node* nodmodv; +Node* nodmodvu; +Node* nodlshv; +Node* nodrshav; +Node* nodrshlv; +Node* nodandv; +Node* nodorv; +Node* nodxorv; +Node* nodnegv; +Node* nodcomv; + +Node* nodtestv; +Node* nodeqv; +Node* nodnev; +Node* nodlev; +Node* nodltv; +Node* nodgev; +Node* nodgtv; +Node* nodhiv; +Node* nodhsv; +Node* nodlov; +Node* nodlsv; + +Node* nodf2v; +Node* nodd2v; +Node* nodp2v; +Node* nodsi2v; +Node* nodui2v; +Node* nodsl2v; +Node* nodul2v; +Node* nodsh2v; +Node* noduh2v; +Node* nodsc2v; +Node* noduc2v; + +Node* nodv2f; +Node* nodv2d; +Node* nodv2ui; +Node* nodv2si; +Node* nodv2ul; +Node* nodv2sl; +Node* nodv2uh; +Node* nodv2sh; +Node* nodv2uc; +Node* nodv2sc; + +Node* nodvpp; +Node* nodppv; +Node* nodvmm; +Node* nodmmv; + +Node* nodvasop; + +char etconv[NTYPE]; /* for _vasop */ +Init initetconv[] = +{ + TCHAR, 1, 0, + TUCHAR, 2, 0, + TSHORT, 3, 0, + TUSHORT, 4, 0, + TLONG, 5, 0, + TULONG, 6, 0, + TVLONG, 7, 0, + TUVLONG, 8, 0, + TINT, 9, 0, + TUINT, 10, 0, + -1, 0, 0, +}; + +Node* +fvn(char *name, int type) +{ + Node *n; + + n = new(ONAME, Z, Z); + n->sym = slookup(name); + n->sym->sig = SIGINTERN; + if(fntypes[type] == 0) + fntypes[type] = typ(TFUNC, types[type]); + n->type = fntypes[type]; + n->etype = type; + n->class = CGLOBL; + n->addable = 10; + n->complex = 0; + return n; +} + +void +com64init(void) +{ + Init *p; + + nodaddv = fvn("_addv", TVLONG); + nodsubv = fvn("_subv", TVLONG); + nodmulv = fvn("_mulv", TVLONG); + noddivv = fvn("_divv", TVLONG); + noddivvu = fvn("_divvu", TVLONG); + nodmodv = fvn("_modv", TVLONG); + nodmodvu = fvn("_modvu", TVLONG); + nodlshv = fvn("_lshv", TVLONG); + nodrshav = fvn("_rshav", TVLONG); + nodrshlv = fvn("_rshlv", TVLONG); + nodandv = fvn("_andv", TVLONG); + nodorv = fvn("_orv", TVLONG); + nodxorv = fvn("_xorv", TVLONG); + nodnegv = fvn("_negv", TVLONG); + nodcomv = fvn("_comv", TVLONG); + + nodtestv = fvn("_testv", TLONG); + nodeqv = fvn("_eqv", TLONG); + nodnev = fvn("_nev", TLONG); + nodlev = fvn("_lev", TLONG); + nodltv = fvn("_ltv", TLONG); + nodgev = fvn("_gev", TLONG); + nodgtv = fvn("_gtv", TLONG); + nodhiv = fvn("_hiv", TLONG); + nodhsv = fvn("_hsv", TLONG); + nodlov = fvn("_lov", TLONG); + nodlsv = fvn("_lsv", TLONG); + + nodf2v = fvn("_f2v", TVLONG); + nodd2v = fvn("_d2v", TVLONG); + nodp2v = fvn("_p2v", TVLONG); + nodsi2v = fvn("_si2v", TVLONG); + nodui2v = fvn("_ui2v", TVLONG); + nodsl2v = fvn("_sl2v", TVLONG); + nodul2v = fvn("_ul2v", TVLONG); + nodsh2v = fvn("_sh2v", TVLONG); + noduh2v = fvn("_uh2v", TVLONG); + nodsc2v = fvn("_sc2v", TVLONG); + noduc2v = fvn("_uc2v", TVLONG); + + nodv2f = fvn("_v2f", TFLOAT); + nodv2d = fvn("_v2d", TDOUBLE); + nodv2sl = fvn("_v2sl", TLONG); + nodv2ul = fvn("_v2ul", TULONG); + nodv2si = fvn("_v2si", TINT); + nodv2ui = fvn("_v2ui", TUINT); + nodv2sh = fvn("_v2sh", TSHORT); + nodv2uh = fvn("_v2ul", TUSHORT); + nodv2sc = fvn("_v2sc", TCHAR); + nodv2uc = fvn("_v2uc", TUCHAR); + + nodvpp = fvn("_vpp", TVLONG); + nodppv = fvn("_ppv", TVLONG); + nodvmm = fvn("_vmm", TVLONG); + nodmmv = fvn("_mmv", TVLONG); + + nodvasop = fvn("_vasop", TVLONG); + + for(p = initetconv; p->code >= 0; p++) + etconv[p->code] = p->value; +} + +int +com64(Node *n) +{ + Node *l, *r, *a, *t; + int lv, rv; + + if(n->type == 0) + return 0; + + l = n->left; + r = n->right; + + lv = 0; + if(l && l->type && typev[l->type->etype]) + lv = 1; + rv = 0; + if(r && r->type && typev[r->type->etype]) + rv = 1; + + if(lv) { + switch(n->op) { + case OEQ: + a = nodeqv; + goto setbool; + case ONE: + a = nodnev; + goto setbool; + case OLE: + a = nodlev; + goto setbool; + case OLT: + a = nodltv; + goto setbool; + case OGE: + a = nodgev; + goto setbool; + case OGT: + a = nodgtv; + goto setbool; + case OHI: + a = nodhiv; + goto setbool; + case OHS: + a = nodhsv; + goto setbool; + case OLO: + a = nodlov; + goto setbool; + case OLS: + a = nodlsv; + goto setbool; + + case OANDAND: + case OOROR: + if(machcap(n)) + return 1; + + if(rv) { + r = new(OFUNC, nodtestv, r); + n->right = r; + r->complex = FNX; + r->op = OFUNC; + r->type = types[TLONG]; + } + + case OCOND: + case ONOT: + if(machcap(n)) + return 1; + + l = new(OFUNC, nodtestv, l); + n->left = l; + l->complex = FNX; + l->op = OFUNC; + l->type = types[TLONG]; + n->complex = FNX; + return 1; + } + } + + if(rv) { + if(machcap(n)) + return 1; + switch(n->op) { + case OANDAND: + case OOROR: + r = new(OFUNC, nodtestv, r); + n->right = r; + r->complex = FNX; + r->op = OFUNC; + r->type = types[TLONG]; + return 1; + } + } + + if(typev[n->type->etype]) { + if(machcap(n)) + return 1; + switch(n->op) { + default: + diag(n, "unknown vlong %O", n->op); + case OFUNC: + n->complex = FNX; + case ORETURN: + case OAS: + case OIND: + return 1; + case OADD: + a = nodaddv; + goto setbop; + case OSUB: + a = nodsubv; + goto setbop; + case OMUL: + case OLMUL: + a = nodmulv; + goto setbop; + case ODIV: + a = noddivv; + goto setbop; + case OLDIV: + a = noddivvu; + goto setbop; + case OMOD: + a = nodmodv; + goto setbop; + case OLMOD: + a = nodmodvu; + goto setbop; + case OASHL: + a = nodlshv; + goto setbop; + case OASHR: + a = nodrshav; + goto setbop; + case OLSHR: + a = nodrshlv; + goto setbop; + case OAND: + a = nodandv; + goto setbop; + case OOR: + a = nodorv; + goto setbop; + case OXOR: + a = nodxorv; + goto setbop; + case OPOSTINC: + a = nodvpp; + goto setvinc; + case OPOSTDEC: + a = nodvmm; + goto setvinc; + case OPREINC: + a = nodppv; + goto setvinc; + case OPREDEC: + a = nodmmv; + goto setvinc; + case ONEG: + a = nodnegv; + goto setfnx; + case OCOM: + a = nodcomv; + goto setfnx; + case OCAST: + switch(l->type->etype) { + case TCHAR: + a = nodsc2v; + goto setfnxl; + case TUCHAR: + a = noduc2v; + goto setfnxl; + case TSHORT: + a = nodsh2v; + goto setfnxl; + case TUSHORT: + a = noduh2v; + goto setfnxl; + case TINT: + a = nodsi2v; + goto setfnx; + case TUINT: + a = nodui2v; + goto setfnx; + case TLONG: + a = nodsl2v; + goto setfnx; + case TULONG: + a = nodul2v; + goto setfnx; + case TFLOAT: + a = nodf2v; + goto setfnx; + case TDOUBLE: + a = nodd2v; + goto setfnx; + case TIND: + a = nodp2v; + goto setfnx; + } + diag(n, "unknown %T->vlong cast", l->type); + return 1; + case OASADD: + a = nodaddv; + goto setasop; + case OASSUB: + a = nodsubv; + goto setasop; + case OASMUL: + case OASLMUL: + a = nodmulv; + goto setasop; + case OASDIV: + a = noddivv; + goto setasop; + case OASLDIV: + a = noddivvu; + goto setasop; + case OASMOD: + a = nodmodv; + goto setasop; + case OASLMOD: + a = nodmodvu; + goto setasop; + case OASASHL: + a = nodlshv; + goto setasop; + case OASASHR: + a = nodrshav; + goto setasop; + case OASLSHR: + a = nodrshlv; + goto setasop; + case OASAND: + a = nodandv; + goto setasop; + case OASOR: + a = nodorv; + goto setasop; + case OASXOR: + a = nodxorv; + goto setasop; + } + } + + if(typefd[n->type->etype] && l && l->op == OFUNC) { + switch(n->op) { + case OASADD: + case OASSUB: + case OASMUL: + case OASLMUL: + case OASDIV: + case OASLDIV: + case OASMOD: + case OASLMOD: + case OASASHL: + case OASASHR: + case OASLSHR: + case OASAND: + case OASOR: + case OASXOR: + if(l->right && typev[l->right->etype]) { + diag(n, "sorry float <asop> vlong not implemented\n"); + } + } + } + + if(n->op == OCAST) { + if(l->type && typev[l->type->etype]) { + if(machcap(n)) + return 1; + switch(n->type->etype) { + case TDOUBLE: + a = nodv2d; + goto setfnx; + case TFLOAT: + a = nodv2f; + goto setfnx; + case TLONG: + a = nodv2sl; + goto setfnx; + case TULONG: + a = nodv2ul; + goto setfnx; + case TINT: + a = nodv2si; + goto setfnx; + case TUINT: + a = nodv2ui; + goto setfnx; + case TSHORT: + a = nodv2sh; + goto setfnx; + case TUSHORT: + a = nodv2uh; + goto setfnx; + case TCHAR: + a = nodv2sc; + goto setfnx; + case TUCHAR: + a = nodv2uc; + goto setfnx; + case TIND: // small pun here + a = nodv2ul; + goto setfnx; + } + diag(n, "unknown vlong->%T cast", n->type); + return 1; + } + } + + return 0; + +setbop: + n->left = a; + n->right = new(OLIST, l, r); + n->complex = FNX; + n->op = OFUNC; + return 1; + +setfnxl: + l = new(OCAST, l, 0); + l->type = types[TLONG]; + l->complex = l->left->complex; + +setfnx: + n->left = a; + n->right = l; + n->complex = FNX; + n->op = OFUNC; + return 1; + +setvinc: + n->left = a; + l = new(OADDR, l, Z); + l->type = typ(TIND, l->left->type); + n->right = new(OLIST, l, r); + n->complex = FNX; + n->op = OFUNC; + return 1; + +setbool: + if(machcap(n)) + return 1; + n->left = a; + n->right = new(OLIST, l, r); + n->complex = FNX; + n->op = OFUNC; + n->type = types[TLONG]; + return 1; + +setasop: + if(l->op == OFUNC) { + l = l->right; + goto setasop; + } + + t = new(OCONST, 0, 0); + t->vconst = etconv[l->type->etype]; + t->type = types[TLONG]; + t->addable = 20; + r = new(OLIST, t, r); + + t = new(OADDR, a, 0); + t->type = typ(TIND, a->type); + r = new(OLIST, t, r); + + t = new(OADDR, l, 0); + t->type = typ(TIND, l->type); + r = new(OLIST, t, r); + + n->left = nodvasop; + n->right = r; + n->complex = FNX; + n->op = OFUNC; + + return 1; +} + +void +bool64(Node *n) +{ + Node *n1; + + if(machcap(Z)) + return; + if(typev[n->type->etype]) { + n1 = new(OXXX, 0, 0); + *n1 = *n; + + n->right = n1; + n->left = nodtestv; + n->complex = FNX; + n->addable = 0; + n->op = OFUNC; + n->type = types[TLONG]; + } +} + +/* + * more machine depend stuff. + * this is common for 8,16,32,64 bit machines. + * this is common for ieee machines. + */ +double +convvtof(vlong v) +{ + double d; + + d = v; /* BOTCH */ + return d; +} + +vlong +convftov(double d) +{ + vlong v; + + + v = d; /* BOTCH */ + return v; +} + +double +convftox(double d, int et) +{ + + if(!typefd[et]) + diag(Z, "bad type in castftox %s", tnames[et]); + return d; +} + +vlong +convvtox(vlong c, int et) +{ + int n; + + n = 8 * ewidth[et]; + c &= MASK(n); + if(!typeu[et]) + if(c & SIGN(n)) + c |= ~MASK(n); + return c; +} diff --git a/src/cmd/cc/dcl.c b/src/cmd/cc/dcl.c new file mode 100644 index 000000000..f44c34007 --- /dev/null +++ b/src/cmd/cc/dcl.c @@ -0,0 +1,1664 @@ +// Inferno utils/cc/dcl.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/dcl.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "cc.h" + +Node* +dodecl(void (*f)(int,Type*,Sym*), int c, Type *t, Node *n) +{ + Sym *s; + Node *n1; + long v; + + nearln = lineno; + lastfield = 0; + +loop: + if(n != Z) + switch(n->op) { + default: + diag(n, "unknown declarator: %O", n->op); + break; + + case OARRAY: + t = typ(TARRAY, t); + t->width = 0; + n1 = n->right; + n = n->left; + if(n1 != Z) { + complex(n1); + v = -1; + if(n1->op == OCONST) + v = n1->vconst; + if(v <= 0) { + diag(n, "array size must be a positive constant"); + v = 1; + } + t->width = v * t->link->width; + } + goto loop; + + case OIND: + t = typ(TIND, t); + t->garb = n->garb; + n = n->left; + goto loop; + + case OFUNC: + t = typ(TFUNC, t); + t->down = fnproto(n); + n = n->left; + goto loop; + + case OBIT: + n1 = n->right; + complex(n1); + lastfield = -1; + if(n1->op == OCONST) + lastfield = n1->vconst; + if(lastfield < 0) { + diag(n, "field width must be non-negative constant"); + lastfield = 1; + } + if(lastfield == 0) { + lastbit = 0; + firstbit = 1; + if(n->left != Z) { + diag(n, "zero width named field"); + lastfield = 1; + } + } + if(!typei[t->etype]) { + diag(n, "field type must be int-like"); + t = types[TINT]; + lastfield = 1; + } + if(lastfield > tfield->width*8) { + diag(n, "field width larger than field unit"); + lastfield = 1; + } + lastbit += lastfield; + if(lastbit > tfield->width*8) { + lastbit = lastfield; + firstbit = 1; + } + n = n->left; + goto loop; + + case ONAME: + if(f == NODECL) + break; + s = n->sym; + (*f)(c, t, s); + if(s->class == CLOCAL) + s = mkstatic(s); + firstbit = 0; + n->sym = s; + n->type = s->type; + n->xoffset = s->offset; + n->class = s->class; + n->etype = TVOID; + if(n->type != T) + n->etype = n->type->etype; + if(debug['d']) + dbgdecl(s); + acidvar(s); + s->varlineno = lineno; + break; + } + lastdcl = t; + return n; +} + +Sym* +mkstatic(Sym *s) +{ + Sym *s1; + + if(s->class != CLOCAL) + return s; + snprint(symb, NSYMB, "%s$%d", s->name, s->block); + s1 = lookup(); + if(s1->class != CSTATIC) { + s1->type = s->type; + s1->offset = s->offset; + s1->block = s->block; + s1->class = CSTATIC; + } + return s1; +} + +/* + * make a copy of a typedef + * the problem is to split out incomplete + * arrays so that it is in the variable + * rather than the typedef. + */ +Type* +tcopy(Type *t) +{ + Type *tl, *tx; + int et; + + if(t == T) + return t; + et = t->etype; + if(typesu[et]) + return t; + tl = tcopy(t->link); + if(tl != t->link || + (et == TARRAY && t->width == 0)) { + tx = copytyp(t); + tx->link = tl; + return tx; + } + return t; +} + +Node* +doinit(Sym *s, Type *t, long o, Node *a) +{ + Node *n; + + if(t == T) + return Z; + if(s->class == CEXTERN) { + s->class = CGLOBL; + if(debug['d']) + dbgdecl(s); + } + if(debug['i']) { + print("t = %T; o = %ld; n = %s\n", t, o, s->name); + prtree(a, "doinit value"); + } + + + n = initlist; + if(a->op == OINIT) + a = a->left; + initlist = a; + + a = init1(s, t, o, 0); + if(initlist != Z) + diag(initlist, "more initializers than structure: %s", + s->name); + initlist = n; + + return a; +} + +/* + * get next major operator, + * dont advance initlist. + */ +Node* +peekinit(void) +{ + Node *a; + + a = initlist; + +loop: + if(a == Z) + return a; + if(a->op == OLIST) { + a = a->left; + goto loop; + } + return a; +} + +/* + * consume and return next element on + * initlist. expand strings. + */ +Node* +nextinit(void) +{ + Node *a, *b, *n; + + a = initlist; + n = Z; + + if(a == Z) + return a; + if(a->op == OLIST) { + n = a->right; + a = a->left; + } + if(a->op == OUSED) { + a = a->left; + b = new(OCONST, Z, Z); + b->type = a->type->link; + if(a->op == OSTRING) { + b->vconst = convvtox(*a->cstring, TCHAR); + a->cstring++; + } + if(a->op == OLSTRING) { + b->vconst = convvtox(*a->rstring, TUSHORT); + a->rstring++; + } + a->type->width -= b->type->width; + if(a->type->width <= 0) + initlist = n; + return b; + } + initlist = n; + return a; +} + +int +isstruct(Node *a, Type *t) +{ + Node *n; + + switch(a->op) { + case ODOTDOT: + n = a->left; + if(n && n->type && sametype(n->type, t)) + return 1; + case OSTRING: + case OLSTRING: + case OCONST: + case OINIT: + case OELEM: + return 0; + } + + n = new(ODOTDOT, Z, Z); + *n = *a; + + /* + * ODOTDOT is a flag for tcom + * a second tcom will not be performed + */ + a->op = ODOTDOT; + a->left = n; + a->right = Z; + + if(tcom(n)) + return 0; + + if(sametype(n->type, t)) + return 1; + return 0; +} + +Node* +init1(Sym *s, Type *t, long o, int exflag) +{ + Node *a, *l, *r, nod; + Type *t1; + long e, w, so, mw; + + a = peekinit(); + if(a == Z) + return Z; + + if(debug['i']) { + print("t = %T; o = %ld; n = %s\n", t, o, s->name); + prtree(a, "init1 value"); + } + + if(exflag && a->op == OINIT) + return doinit(s, t, o, nextinit()); + + switch(t->etype) { + default: + diag(Z, "unknown type in initialization: %T to: %s", t, s->name); + return Z; + + case TCHAR: + case TUCHAR: + case TINT: + case TUINT: + case TSHORT: + case TUSHORT: + case TLONG: + case TULONG: + case TVLONG: + case TUVLONG: + case TFLOAT: + case TDOUBLE: + case TIND: + single: + if(a->op == OARRAY || a->op == OELEM) + return Z; + + a = nextinit(); + if(a == Z) + return Z; + + if(t->nbits) + diag(Z, "cannot initialize bitfields"); + if(s->class == CAUTO) { + l = new(ONAME, Z, Z); + l->sym = s; + l->type = t; + l->etype = TVOID; + if(s->type) + l->etype = s->type->etype; + l->xoffset = s->offset + o; + l->class = s->class; + + l = new(OASI, l, a); + return l; + } + + complex(a); + if(a->type == T) + return Z; + + if(a->op == OCONST) { + if(vconst(a) && t->etype == TIND && a->type && a->type->etype != TIND){ + diag(a, "initialize pointer to an integer: %s", s->name); + return Z; + } + if(!sametype(a->type, t)) { + /* hoop jumping to save malloc */ + if(nodcast == Z) + nodcast = new(OCAST, Z, Z); + nod = *nodcast; + nod.left = a; + nod.type = t; + nod.lineno = a->lineno; + complex(&nod); + if(nod.type) + *a = nod; + } + if(a->op != OCONST) { + diag(a, "initializer is not a constant: %s", + s->name); + return Z; + } + if(vconst(a) == 0) + return Z; + goto gext; + } + if(t->etype == TIND) { + while(a->op == OCAST) { + warn(a, "CAST in initialization ignored"); + a = a->left; + } + if(!sametype(t, a->type)) { + diag(a, "initialization of incompatible pointers: %s\n%T and %T", + s->name, t, a->type); + } + if(a->op == OADDR) + a = a->left; + goto gext; + } + + while(a->op == OCAST) + a = a->left; + if(a->op == OADDR) { + warn(a, "initialize pointer to an integer: %s", s->name); + a = a->left; + goto gext; + } + diag(a, "initializer is not a constant: %s", s->name); + return Z; + + gext: + gextern(s, a, o, t->width); + + return Z; + + case TARRAY: + w = t->link->width; + if(a->op == OSTRING || a->op == OLSTRING) + if(typei[t->link->etype]) { + /* + * get rid of null if sizes match exactly + */ + a = nextinit(); + mw = t->width/w; + so = a->type->width/a->type->link->width; + if(mw && so > mw) { + if(so != mw+1) + diag(a, "string initialization larger than array"); + a->type->width -= a->type->link->width; + } + + /* + * arrange strings to be expanded + * inside OINIT braces. + */ + a = new(OUSED, a, Z); + return doinit(s, t, o, a); + } + + mw = -w; + l = Z; + for(e=0;;) { + /* + * peek ahead for element initializer + */ + a = peekinit(); + if(a == Z) + break; + if(a->op == OELEM && t->link->etype != TSTRUCT) + break; + if(a->op == OARRAY) { + if(e && exflag) + break; + a = nextinit(); + r = a->left; + complex(r); + if(r->op != OCONST) { + diag(r, "initializer subscript must be constant"); + return Z; + } + e = r->vconst; + if(t->width != 0) + if(e < 0 || e*w >= t->width) { + diag(a, "initialization index out of range: %ld", e); + continue; + } + } + + so = e*w; + if(so > mw) + mw = so; + if(t->width != 0) + if(mw >= t->width) + break; + r = init1(s, t->link, o+so, 1); + l = newlist(l, r); + e++; + } + if(t->width == 0) + t->width = mw+w; + return l; + + case TUNION: + case TSTRUCT: + /* + * peek ahead to find type of rhs. + * if its a structure, then treat + * this element as a variable + * rather than an aggregate. + */ + if(isstruct(a, t)) + goto single; + + if(t->width <= 0) { + diag(Z, "incomplete structure: %s", s->name); + return Z; + } + l = Z; + + again: + for(t1 = t->link; t1 != T; t1 = t1->down) { + if(a->op == OARRAY && t1->etype != TARRAY) + break; + if(a->op == OELEM) { + if(t1->sym != a->sym) + continue; + nextinit(); + } + r = init1(s, t1, o+t1->offset, 1); + l = newlist(l, r); + a = peekinit(); + if(a == Z) + break; + if(a->op == OELEM) + goto again; + } + if(a && a->op == OELEM) + diag(a, "structure element not found %F", a); + return l; + } +} + +Node* +newlist(Node *l, Node *r) +{ + if(r == Z) + return l; + if(l == Z) + return r; + return new(OLIST, l, r); +} + +void +suallign(Type *t) +{ + Type *l; + long o, w; + + o = 0; + switch(t->etype) { + + case TSTRUCT: + t->offset = 0; + w = 0; + for(l = t->link; l != T; l = l->down) { + if(l->nbits) { + if(l->shift <= 0) { + l->shift = -l->shift; + w = xround(w, tfield->width); + o = w; + w += tfield->width; + } + l->offset = o; + } else { + if(l->width <= 0) + if(l->down != T) + if(l->sym) + diag(Z, "incomplete structure element: %s", + l->sym->name); + else + diag(Z, "incomplete structure element"); + w = align(w, l, Ael1); + l->offset = w; + w = align(w, l, Ael2); + } + } + w = align(w, t, Asu2); + t->width = w; + acidtype(t); + pickletype(t); + return; + + case TUNION: + t->offset = 0; + w = 0; + for(l = t->link; l != T; l = l->down) { + if(l->width <= 0) + if(l->sym) + diag(Z, "incomplete union element: %s", + l->sym->name); + else + diag(Z, "incomplete union element"); + l->offset = 0; + l->shift = 0; + o = align(align(0, l, Ael1), l, Ael2); + if(o > w) + w = o; + } + w = align(w, t, Asu2); + t->width = w; + acidtype(t); + pickletype(t); + return; + + default: + diag(Z, "unknown type in suallign: %T", t); + break; + } +} + +long +xround(long v, int w) +{ + int r; + + if(w <= 0 || w > 8) { + diag(Z, "rounding by %d", w); + w = 1; + } + r = v%w; + if(r) + v += w-r; + return v; +} + +Type* +ofnproto(Node *n) +{ + Type *tl, *tr, *t; + + if(n == Z) + return T; + switch(n->op) { + case OLIST: + tl = ofnproto(n->left); + tr = ofnproto(n->right); + if(tl == T) + return tr; + tl->down = tr; + return tl; + + case ONAME: + t = copytyp(n->sym->type); + t->down = T; + return t; + } + return T; +} + +#define ANSIPROTO 1 +#define OLDPROTO 2 + +void +argmark(Node *n, int pass) +{ + Type *t; + + autoffset = align(0, thisfn->link, Aarg0); + stkoff = 0; + for(; n->left != Z; n = n->left) { + if(n->op != OFUNC || n->left->op != ONAME) + continue; + walkparam(n->right, pass); + if(pass != 0 && anyproto(n->right) == OLDPROTO) { + t = typ(TFUNC, n->left->sym->type->link); + t->down = typ(TOLD, T); + t->down->down = ofnproto(n->right); + tmerge(t, n->left->sym); + n->left->sym->type = t; + } + break; + } + autoffset = 0; + stkoff = 0; +} + +void +walkparam(Node *n, int pass) +{ + Sym *s; + Node *n1; + + if(n != Z && n->op == OPROTO && n->left == Z && n->type == types[TVOID]) + return; + +loop: + if(n == Z) + return; + switch(n->op) { + default: + diag(n, "argument not a name/prototype: %O", n->op); + break; + + case OLIST: + walkparam(n->left, pass); + n = n->right; + goto loop; + + case OPROTO: + for(n1 = n; n1 != Z; n1=n1->left) + if(n1->op == ONAME) { + if(pass == 0) { + s = n1->sym; + push1(s); + s->offset = -1; + break; + } + dodecl(pdecl, CPARAM, n->type, n->left); + break; + } + if(n1) + break; + if(pass == 0) { + /* + * extension: + * allow no name in argument declaration + diag(Z, "no name in argument declaration"); + */ + break; + } + dodecl(NODECL, CPARAM, n->type, n->left); + pdecl(CPARAM, lastdcl, S); + break; + + case ODOTDOT: + break; + + case ONAME: + s = n->sym; + if(pass == 0) { + push1(s); + s->offset = -1; + break; + } + if(s->offset != -1) { + if(autoffset == 0) { + firstarg = s; + firstargtype = s->type; + } + autoffset = align(autoffset, s->type, Aarg1); + s->offset = autoffset; + autoffset = align(autoffset, s->type, Aarg2); + } else + dodecl(pdecl, CXXX, types[TINT], n); + break; + } +} + +void +markdcl(void) +{ + Decl *d; + + blockno++; + d = push(); + d->val = DMARK; + d->offset = autoffset; + d->block = autobn; + autobn = blockno; +} + +Node* +revertdcl(void) +{ + Decl *d; + Sym *s; + Node *n, *n1; + + n = Z; + for(;;) { + d = dclstack; + if(d == D) { + diag(Z, "pop off dcl stack"); + break; + } + dclstack = d->link; + s = d->sym; + switch(d->val) { + case DMARK: + autoffset = d->offset; + autobn = d->block; + return n; + + case DAUTO: + if(debug['d']) + print("revert1 \"%s\"\n", s->name); + if(s->aused == 0) { + nearln = s->varlineno; + if(s->class == CAUTO) + warn(Z, "auto declared and not used: %s", s->name); + if(s->class == CPARAM) + warn(Z, "param declared and not used: %s", s->name); + } + if(s->type && (s->type->garb & GVOLATILE)) { + n1 = new(ONAME, Z, Z); + n1->sym = s; + n1->type = s->type; + n1->etype = TVOID; + if(n1->type != T) + n1->etype = n1->type->etype; + n1->xoffset = s->offset; + n1->class = s->class; + + n1 = new(OADDR, n1, Z); + n1 = new(OUSED, n1, Z); + if(n == Z) + n = n1; + else + n = new(OLIST, n1, n); + } + s->type = d->type; + s->class = d->class; + s->offset = d->offset; + s->block = d->block; + s->varlineno = d->varlineno; + s->aused = d->aused; + break; + + case DSUE: + if(debug['d']) + print("revert2 \"%s\"\n", s->name); + s->suetag = d->type; + s->sueblock = d->block; + break; + + case DLABEL: + if(debug['d']) + print("revert3 \"%s\"\n", s->name); + if(s->label && s->label->addable == 0) + warn(s->label, "label declared and not used \"%s\"", s->name); + s->label = Z; + break; + } + } + return n; +} + +Type* +fnproto(Node *n) +{ + int r; + + r = anyproto(n->right); + if(r == 0 || (r & OLDPROTO)) { + if(r & ANSIPROTO) + diag(n, "mixed ansi/old function declaration: %F", n->left); + return T; + } + return fnproto1(n->right); +} + +int +anyproto(Node *n) +{ + int r; + + r = 0; + +loop: + if(n == Z) + return r; + switch(n->op) { + case OLIST: + r |= anyproto(n->left); + n = n->right; + goto loop; + + case ODOTDOT: + case OPROTO: + return r | ANSIPROTO; + } + return r | OLDPROTO; +} + +Type* +fnproto1(Node *n) +{ + Type *t; + + if(n == Z) + return T; + switch(n->op) { + case OLIST: + t = fnproto1(n->left); + if(t != T) + t->down = fnproto1(n->right); + return t; + + case OPROTO: + lastdcl = T; + dodecl(NODECL, CXXX, n->type, n->left); + t = typ(TXXX, T); + if(lastdcl != T) + *t = *paramconv(lastdcl, 1); + return t; + + case ONAME: + diag(n, "incomplete argument prototype"); + return typ(TINT, T); + + case ODOTDOT: + return typ(TDOT, T); + } + diag(n, "unknown op in fnproto"); + return T; +} + +void +dbgdecl(Sym *s) +{ + print("decl \"%s\": C=%s [B=%d:O=%ld] T=%T\n", + s->name, cnames[s->class], s->block, s->offset, s->type); +} + +Decl* +push(void) +{ + Decl *d; + + d = alloc(sizeof(*d)); + d->link = dclstack; + dclstack = d; + return d; +} + +Decl* +push1(Sym *s) +{ + Decl *d; + + d = push(); + d->sym = s; + d->val = DAUTO; + d->type = s->type; + d->class = s->class; + d->offset = s->offset; + d->block = s->block; + d->varlineno = s->varlineno; + d->aused = s->aused; + return d; +} + +int +sametype(Type *t1, Type *t2) +{ + + if(t1 == t2) + return 1; + return rsametype(t1, t2, 5, 1); +} + +int +rsametype(Type *t1, Type *t2, int n, int f) +{ + int et; + + n--; + for(;;) { + if(t1 == t2) + return 1; + if(t1 == T || t2 == T) + return 0; + if(n <= 0) + return 1; + et = t1->etype; + if(et != t2->etype) + return 0; + if(et == TFUNC) { + if(!rsametype(t1->link, t2->link, n, 0)) + return 0; + t1 = t1->down; + t2 = t2->down; + while(t1 != T && t2 != T) { + if(t1->etype == TOLD) { + t1 = t1->down; + continue; + } + if(t2->etype == TOLD) { + t2 = t2->down; + continue; + } + while(t1 != T || t2 != T) { + if(!rsametype(t1, t2, n, 0)) + return 0; + t1 = t1->down; + t2 = t2->down; + } + break; + } + return 1; + } + if(et == TARRAY) + if(t1->width != t2->width && t1->width != 0 && t2->width != 0) + return 0; + if(typesu[et]) { + if(t1->link == T) + snap(t1); + if(t2->link == T) + snap(t2); + t1 = t1->link; + t2 = t2->link; + for(;;) { + if(t1 == t2) + return 1; + if(!rsametype(t1, t2, n, 0)) + return 0; + t1 = t1->down; + t2 = t2->down; + } + } + t1 = t1->link; + t2 = t2->link; + if((f || !debug['V']) && et == TIND) { + if(t1 != T && t1->etype == TVOID) + return 1; + if(t2 != T && t2->etype == TVOID) + return 1; + } + } +} + +typedef struct Typetab Typetab; + +struct Typetab{ + int n; + Type **a; +}; + +static int +sigind(Type *t, Typetab *tt) +{ + int n; + Type **a, **na, **p, **e; + + n = tt->n; + a = tt->a; + e = a+n; + /* linear search seems ok */ + for(p = a ; p < e; p++) + if(sametype(*p, t)) + return p-a; + if((n&15) == 0){ + na = malloc((n+16)*sizeof(Type*)); + memmove(na, a, n*sizeof(Type*)); + free(a); + a = tt->a = na; + } + a[tt->n++] = t; + return -1; +} + +static ulong +signat(Type *t, Typetab *tt) +{ + int i; + Type *t1; + long s; + + s = 0; + for(; t; t=t->link) { + s = s*thash1 + thash[t->etype]; + if(t->garb&GINCOMPLETE) + return s; + switch(t->etype) { + default: + return s; + case TARRAY: + s = s*thash2 + 0; /* was t->width */ + break; + case TFUNC: + for(t1=t->down; t1; t1=t1->down) + s = s*thash3 + signat(t1, tt); + break; + case TSTRUCT: + case TUNION: + if((i = sigind(t, tt)) >= 0){ + s = s*thash2 + i; + return s; + } + for(t1=t->link; t1; t1=t1->down) + s = s*thash3 + signat(t1, tt); + return s; + case TIND: + break; + } + } + return s; +} + +ulong +signature(Type *t) +{ + ulong s; + Typetab tt; + + tt.n = 0; + tt.a = nil; + s = signat(t, &tt); + free(tt.a); + return s; +} + +ulong +sign(Sym *s) +{ + ulong v; + Type *t; + + if(s->sig == SIGINTERN) + return SIGNINTERN; + if((t = s->type) == T) + return 0; + v = signature(t); + if(v == 0) + v = SIGNINTERN; + return v; +} + +void +snap(Type *t) +{ + if(typesu[t->etype]) + if(t->link == T && t->tag && t->tag->suetag) { + t->link = t->tag->suetag->link; + t->width = t->tag->suetag->width; + } +} + +Type* +dotag(Sym *s, int et, int bn) +{ + Decl *d; + + if(bn != 0 && bn != s->sueblock) { + d = push(); + d->sym = s; + d->val = DSUE; + d->type = s->suetag; + d->block = s->sueblock; + s->suetag = T; + } + if(s->suetag == T) { + s->suetag = typ(et, T); + s->sueblock = autobn; + } + if(s->suetag->etype != et) + diag(Z, "tag used for more than one type: %s", + s->name); + if(s->suetag->tag == S) + s->suetag->tag = s; + return s->suetag; +} + +Node* +dcllabel(Sym *s, int f) +{ + Decl *d, d1; + Node *n; + + n = s->label; + if(n != Z) { + if(f) { + if(n->complex) + diag(Z, "label reused: %s", s->name); + n->complex = 1; // declared + } else + n->addable = 1; // used + return n; + } + + d = push(); + d->sym = s; + d->val = DLABEL; + dclstack = d->link; + + d1 = *firstdcl; + *firstdcl = *d; + *d = d1; + + firstdcl->link = d; + firstdcl = d; + + n = new(OXXX, Z, Z); + n->sym = s; + n->complex = f; + n->addable = !f; + s->label = n; + + if(debug['d']) + dbgdecl(s); + return n; +} + +Type* +paramconv(Type *t, int f) +{ + + switch(t->etype) { + case TUNION: + case TSTRUCT: + if(t->width <= 0) + diag(Z, "incomplete structure: %s", t->tag->name); + break; + + case TARRAY: + t = typ(TIND, t->link); + t->width = types[TIND]->width; + break; + + case TFUNC: + t = typ(TIND, t); + t->width = types[TIND]->width; + break; + + case TFLOAT: + if(!f) + t = types[TDOUBLE]; + break; + + case TCHAR: + case TSHORT: + if(!f) + t = types[TINT]; + break; + + case TUCHAR: + case TUSHORT: + if(!f) + t = types[TUINT]; + break; + } + return t; +} + +void +adecl(int c, Type *t, Sym *s) +{ + + if(c == CSTATIC) + c = CLOCAL; + if(t->etype == TFUNC) { + if(c == CXXX) + c = CEXTERN; + if(c == CLOCAL) + c = CSTATIC; + if(c == CAUTO || c == CEXREG) + diag(Z, "function cannot be %s %s", cnames[c], s->name); + } + if(c == CXXX) + c = CAUTO; + if(s) { + if(s->class == CSTATIC) + if(c == CEXTERN || c == CGLOBL) { + warn(Z, "just say static: %s", s->name); + c = CSTATIC; + } + if(s->class == CAUTO || s->class == CPARAM || s->class == CLOCAL) + if(s->block == autobn) + diag(Z, "auto redeclaration of: %s", s->name); + if(c != CPARAM) + push1(s); + s->block = autobn; + s->offset = 0; + s->type = t; + s->class = c; + s->aused = 0; + } + switch(c) { + case CAUTO: + autoffset = align(autoffset, t, Aaut3); + stkoff = maxround(stkoff, autoffset); + s->offset = -autoffset; + break; + + case CPARAM: + if(autoffset == 0) { + firstarg = s; + firstargtype = t; + } + autoffset = align(autoffset, t, Aarg1); + if(s) + s->offset = autoffset; + autoffset = align(autoffset, t, Aarg2); + break; + } +} + +void +pdecl(int c, Type *t, Sym *s) +{ + if(s && s->offset != -1) { + diag(Z, "not a parameter: %s", s->name); + return; + } + t = paramconv(t, c==CPARAM); + if(c == CXXX) + c = CPARAM; + if(c != CPARAM) { + diag(Z, "parameter cannot have class: %s", s->name); + c = CPARAM; + } + adecl(c, t, s); +} + +void +xdecl(int c, Type *t, Sym *s) +{ + long o; + + o = 0; + switch(c) { + case CEXREG: + o = exreg(t); + if(o == 0) + c = CEXTERN; + if(s->class == CGLOBL) + c = CGLOBL; + break; + + case CEXTERN: + if(s->class == CGLOBL) + c = CGLOBL; + break; + + case CXXX: + c = CGLOBL; + if(s->class == CEXTERN) + s->class = CGLOBL; + break; + + case CAUTO: + diag(Z, "overspecified class: %s %s %s", s->name, cnames[c], cnames[s->class]); + c = CEXTERN; + break; + + case CTYPESTR: + if(!typesuv[t->etype]) { + diag(Z, "typestr must be struct/union: %s", s->name); + break; + } + dclfunct(t, s); + break; + } + + if(s->class == CSTATIC) + if(c == CEXTERN || c == CGLOBL) { + warn(Z, "overspecified class: %s %s %s", s->name, cnames[c], cnames[s->class]); + c = CSTATIC; + } + if(s->type != T) + if(s->class != c || !sametype(t, s->type) || t->etype == TENUM) { + diag(Z, "external redeclaration of: %s", s->name); + Bprint(&diagbuf, " %s %T %L\n", cnames[c], t, nearln); + Bprint(&diagbuf, " %s %T %L\n", cnames[s->class], s->type, s->varlineno); + } + tmerge(t, s); + s->type = t; + s->class = c; + s->block = 0; + s->offset = o; +} + +void +tmerge(Type *t1, Sym *s) +{ + Type *ta, *tb, *t2; + + t2 = s->type; +/*print("merge %T; %T\n", t1, t2);/**/ + for(;;) { + if(t1 == T || t2 == T || t1 == t2) + break; + if(t1->etype != t2->etype) + break; + switch(t1->etype) { + case TFUNC: + ta = t1->down; + tb = t2->down; + if(ta == T) { + t1->down = tb; + break; + } + if(tb == T) + break; + while(ta != T && tb != T) { + if(ta == tb) + break; + /* ignore old-style flag */ + if(ta->etype == TOLD) { + ta = ta->down; + continue; + } + if(tb->etype == TOLD) { + tb = tb->down; + continue; + } + /* checking terminated by ... */ + if(ta->etype == TDOT && tb->etype == TDOT) { + ta = T; + tb = T; + break; + } + if(!sametype(ta, tb)) + break; + ta = ta->down; + tb = tb->down; + } + if(ta != tb) + diag(Z, "function inconsistently declared: %s", s->name); + + /* take new-style over old-style */ + ta = t1->down; + tb = t2->down; + if(ta != T && ta->etype == TOLD) + if(tb != T && tb->etype != TOLD) + t1->down = tb; + break; + + case TARRAY: + /* should we check array size change? */ + if(t2->width > t1->width) + t1->width = t2->width; + break; + + case TUNION: + case TSTRUCT: + return; + } + t1 = t1->link; + t2 = t2->link; + } +} + +void +edecl(int c, Type *t, Sym *s) +{ + Type *t1; + + if(s == S) { + if(!typesu[t->etype]) + diag(Z, "unnamed structure element must be struct/union"); + if(c != CXXX) + diag(Z, "unnamed structure element cannot have class"); + } else + if(c != CXXX) + diag(Z, "structure element cannot have class: %s", s->name); + t1 = t; + t = copytyp(t1); + t->sym = s; + t->down = T; + if(lastfield) { + t->shift = lastbit - lastfield; + t->nbits = lastfield; + if(firstbit) + t->shift = -t->shift; + if(typeu[t->etype]) + t->etype = tufield->etype; + else + t->etype = tfield->etype; + } + if(strf == T) + strf = t; + else + strl->down = t; + strl = t; +} + +/* + * this routine is very suspect. + * ansi requires the enum type to + * be represented as an 'int' + * this means that 0x81234567 + * would be illegal. this routine + * makes signed and unsigned go + * to unsigned. + */ +Type* +maxtype(Type *t1, Type *t2) +{ + + if(t1 == T) + return t2; + if(t2 == T) + return t1; + if(t1->etype > t2->etype) + return t1; + return t2; +} + +void +doenum(Sym *s, Node *n) +{ + + if(n) { + complex(n); + if(n->op != OCONST) { + diag(n, "enum not a constant: %s", s->name); + return; + } + en.cenum = n->type; + en.tenum = maxtype(en.cenum, en.tenum); + + if(!typefd[en.cenum->etype]) + en.lastenum = n->vconst; + else + en.floatenum = n->fconst; + } + if(dclstack) + push1(s); + xdecl(CXXX, types[TENUM], s); + + if(en.cenum == T) { + en.tenum = types[TINT]; + en.cenum = types[TINT]; + en.lastenum = 0; + } + s->tenum = en.cenum; + + if(!typefd[s->tenum->etype]) { + s->vconst = convvtox(en.lastenum, s->tenum->etype); + en.lastenum++; + } else { + s->fconst = en.floatenum; + en.floatenum++; + } + + if(debug['d']) + dbgdecl(s); + acidvar(s); +} + +void +symadjust(Sym *s, Node *n, long del) +{ + + switch(n->op) { + default: + if(n->left) + symadjust(s, n->left, del); + if(n->right) + symadjust(s, n->right, del); + return; + + case ONAME: + if(n->sym == s) + n->xoffset -= del; + return; + + case OCONST: + case OSTRING: + case OLSTRING: + case OINDREG: + case OREGISTER: + return; + } +} + +Node* +contig(Sym *s, Node *n, long v) +{ + Node *p, *r, *q, *m; + long w; + Type *zt; + + if(debug['i']) { + print("contig v = %ld; s = %s\n", v, s->name); + prtree(n, "doinit value"); + } + + if(n == Z) + goto no; + w = s->type->width; + + /* + * nightmare: an automatic array whose size + * increases when it is initialized + */ + if(v != w) { + if(v != 0) + diag(n, "automatic adjustable array: %s", s->name); + v = s->offset; + autoffset = align(autoffset, s->type, Aaut3); + s->offset = -autoffset; + stkoff = maxround(stkoff, autoffset); + symadjust(s, n, v - s->offset); + } + if(w <= ewidth[TIND]) + goto no; + if(n->op == OAS) + diag(Z, "oops in contig"); +/*ZZZ this appears incorrect +need to check if the list completely covers the data. +if not, bail + */ + if(n->op == OLIST) + goto no; + if(n->op == OASI) + if(n->left->type) + if(n->left->type->width == w) + goto no; + while(w & (ewidth[TIND]-1)) + w++; +/* + * insert the following code, where long becomes vlong if pointers are fat + * + *(long**)&X = (long*)((char*)X + sizeof(X)); + do { + *(long**)&X -= 1; + **(long**)&X = 0; + } while(*(long**)&X); + */ + + for(q=n; q->op != ONAME; q=q->left) + ; + + zt = ewidth[TIND] > ewidth[TLONG]? types[TVLONG]: types[TLONG]; + + p = new(ONAME, Z, Z); + *p = *q; + p->type = typ(TIND, zt); + p->xoffset = s->offset; + + r = new(ONAME, Z, Z); + *r = *p; + r = new(OPOSTDEC, r, Z); + + q = new(ONAME, Z, Z); + *q = *p; + q = new(OIND, q, Z); + + m = new(OCONST, Z, Z); + m->vconst = 0; + m->type = zt; + + q = new(OAS, q, m); + + r = new(OLIST, r, q); + + q = new(ONAME, Z, Z); + *q = *p; + r = new(ODWHILE, q, r); + + q = new(ONAME, Z, Z); + *q = *p; + q->type = q->type->link; + q->xoffset += w; + q = new(OADDR, q, 0); + + q = new(OASI, p, q); + r = new(OLIST, q, r); + + n = new(OLIST, r, n); + +no: + return n; +} diff --git a/src/cmd/cc/dpchk.c b/src/cmd/cc/dpchk.c new file mode 100644 index 000000000..6a8193435 --- /dev/null +++ b/src/cmd/cc/dpchk.c @@ -0,0 +1,524 @@ +// Inferno utils/cc/dpchk.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/dpchk.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "cc.h" +#include "y.tab.h" + +enum +{ + Fnone = 0, + Fl, + Fvl, + Fignor, + Fstar, + Fadj, + + Fverb = 10, +}; + +typedef struct Tprot Tprot; +struct Tprot +{ + Type* type; + Bits flag; + Tprot* link; +}; + +typedef struct Tname Tname; +struct Tname +{ + char* name; + int param; + Tname* link; +}; + +static Type* indchar; +static uchar flagbits[512]; +static char fmtbuf[100]; +static int lastadj; +static int lastverb; +static int nstar; +static Tprot* tprot; +static Tname* tname; + +void +argflag(int c, int v) +{ + + switch(v) { + case Fignor: + case Fstar: + case Fl: + case Fvl: + flagbits[c] = v; + break; + case Fverb: + flagbits[c] = lastverb; +/*print("flag-v %c %d\n", c, lastadj);*/ + lastverb++; + break; + case Fadj: + flagbits[c] = lastadj; +/*print("flag-l %c %d\n", c, lastadj);*/ + lastadj++; + break; + } +} + +Bits +getflag(char *s) +{ + Bits flag; + int f; + char *fmt; + Rune c; + + fmt = fmtbuf; + flag = zbits; + nstar = 0; + for(;;) { + s += chartorune(&c, s); + if(c == 0 || c >= nelem(flagbits)) + break; + fmt += runetochar(fmt, &c); + f = flagbits[c]; + switch(f) { + case Fnone: + argflag(c, Fverb); + f = flagbits[c]; + break; + case Fstar: + nstar++; + case Fignor: + continue; + case Fl: + if(bset(flag, Fl)) + flag = bor(flag, blsh(Fvl)); + } + flag = bor(flag, blsh(f)); + if(f >= Fverb) + break; + } + *fmt = 0; + return flag; +} + +void +newprot(Sym *m, Type *t, char *s) +{ + Bits flag; + Tprot *l; + + if(t == T) { + warn(Z, "%s: newprot: type not defined", m->name); + return; + } + flag = getflag(s); + for(l=tprot; l; l=l->link) + if(beq(flag, l->flag) && sametype(t, l->type)) + return; + l = alloc(sizeof(*l)); + l->type = t; + l->flag = flag; + l->link = tprot; + tprot = l; +} + +void +newname(char *s, int p) +{ + Tname *l; + + for(l=tname; l; l=l->link) + if(strcmp(l->name, s) == 0) { + if(l->param != p) + yyerror("vargck %s already defined\n", s); + return; + } + l = alloc(sizeof(*l)); + l->name = s; + l->param = p; + l->link = tname; + tname = l; +} + +void +arginit(void) +{ + int i; + +/* debug['F'] = 1;*/ +/* debug['w'] = 1;*/ + + lastadj = Fadj; + lastverb = Fverb; + indchar = typ(TIND, types[TCHAR]); + + memset(flagbits, Fnone, sizeof(flagbits)); + + for(i='0'; i<='9'; i++) + argflag(i, Fignor); + argflag('.', Fignor); + argflag('#', Fignor); + argflag('u', Fignor); + argflag('h', Fignor); + argflag('+', Fignor); + argflag('-', Fignor); + + argflag('*', Fstar); + argflag('l', Fl); + + argflag('o', Fverb); + flagbits['x'] = flagbits['o']; + flagbits['X'] = flagbits['o']; +} + +void +pragvararg(void) +{ + Sym *s; + int n, c; + char *t; + Rune r; + Type *ty; + + if(!debug['F']) + goto out; + s = getsym(); + if(s && strcmp(s->name, "argpos") == 0) + goto ckpos; + if(s && strcmp(s->name, "type") == 0) + goto cktype; + if(s && strcmp(s->name, "flag") == 0) + goto ckflag; + yyerror("syntax in #pragma varargck"); + goto out; + +ckpos: +/*#pragma varargck argpos warn 2*/ + s = getsym(); + if(s == S) + goto bad; + n = getnsn(); + if(n < 0) + goto bad; + newname(s->name, n); + goto out; + +ckflag: +/*#pragma varargck flag 'c'*/ + c = getnsc(); + if(c != '\'') + goto bad; + c = getr(); + if(c == '\\') + c = getr(); + else if(c == '\'') + goto bad; + if(c == '\n') + goto bad; + if(getc() != '\'') + goto bad; + argflag(c, Fignor); + goto out; + +cktype: +/*#pragma varargck type O int*/ + c = getnsc(); + if(c != '"') + goto bad; + t = fmtbuf; + for(;;) { + r = getr(); + if(r == ' ' || r == '\n') + goto bad; + if(r == '"') + break; + t += runetochar(t, &r); + } + *t = 0; + t = strdup(fmtbuf); + s = getsym(); + if(s == S) + goto bad; + ty = s->type; + while((c = getnsc()) == '*') + ty = typ(TIND, ty); + unget(c); + newprot(s, ty, t); + goto out; + +bad: + yyerror("syntax in #pragma varargck"); + +out: + while(getnsc() != '\n') + ; +} + +Node* +nextarg(Node *n, Node **a) +{ + if(n == Z) { + *a = Z; + return Z; + } + if(n->op == OLIST) { + *a = n->left; + return n->right; + } + *a = n; + return Z; +} + +void +checkargs(Node *nn, char *s, int pos) +{ + Node *a, *n; + Bits flag; + Tprot *l; + + if(!debug['F']) + return; + n = nn; + for(;;) { + s = strchr(s, '%'); + if(s == 0) { + nextarg(n, &a); + if(a != Z) + warn(nn, "more arguments than format %T", + a->type); + return; + } + s++; + flag = getflag(s); + while(nstar > 0) { + n = nextarg(n, &a); + pos++; + nstar--; + if(a == Z) { + warn(nn, "more format than arguments %s", + fmtbuf); + return; + } + if(a->type == T) + continue; + if(!sametype(types[TINT], a->type) && + !sametype(types[TUINT], a->type)) + warn(nn, "format mismatch '*' in %s %T, arg %d", + fmtbuf, a->type, pos); + } + for(l=tprot; l; l=l->link) + if(sametype(types[TVOID], l->type)) { + if(beq(flag, l->flag)) { + s++; + goto loop; + } + } + + n = nextarg(n, &a); + pos++; + if(a == Z) { + warn(nn, "more format than arguments %s", + fmtbuf); + return; + } + if(a->type == 0) + continue; + for(l=tprot; l; l=l->link) + if(sametype(a->type, l->type)) { +/*print("checking %T/%ulx %T/%ulx\n", a->type, flag.b[0], l->type, l->flag.b[0]);*/ + if(beq(flag, l->flag)) + goto loop; + } + warn(nn, "format mismatch %s %T, arg %d", fmtbuf, a->type, pos); + loop:; + } +} + +void +dpcheck(Node *n) +{ + char *s; + Node *a, *b; + Tname *l; + int i; + + if(n == Z) + return; + b = n->left; + if(b == Z || b->op != ONAME) + return; + s = b->sym->name; + for(l=tname; l; l=l->link) + if(strcmp(s, l->name) == 0) + break; + if(l == 0) + return; + + i = l->param; + b = n->right; + while(i > 0) { + b = nextarg(b, &a); + i--; + } + if(a == Z) { + warn(n, "cant find format arg"); + return; + } + if(!sametype(indchar, a->type)) { + warn(n, "format arg type %T", a->type); + return; + } + if(a->op != OADDR || a->left->op != ONAME || a->left->sym != symstring) { +/* warn(n, "format arg not constant string");*/ + return; + } + s = a->left->cstring; + checkargs(b, s, l->param); +} + +void +pragpack(void) +{ + Sym *s; + + packflg = 0; + s = getsym(); + if(s) { + packflg = atoi(s->name+1); + if(strcmp(s->name, "on") == 0 || + strcmp(s->name, "yes") == 0) + packflg = 1; + } + while(getnsc() != '\n') + ; + if(debug['f']) + if(packflg) + print("%4ld: pack %d\n", lineno, packflg); + else + print("%4ld: pack off\n", lineno); +} + +void +pragfpround(void) +{ + Sym *s; + + fproundflg = 0; + s = getsym(); + if(s) { + fproundflg = atoi(s->name+1); + if(strcmp(s->name, "on") == 0 || + strcmp(s->name, "yes") == 0) + fproundflg = 1; + } + while(getnsc() != '\n') + ; + if(debug['f']) + if(fproundflg) + print("%4ld: fproundflg %d\n", lineno, fproundflg); + else + print("%4ld: fproundflg off\n", lineno); +} + +void +pragprofile(void) +{ + Sym *s; + + profileflg = 0; + s = getsym(); + if(s) { + profileflg = atoi(s->name+1); + if(strcmp(s->name, "on") == 0 || + strcmp(s->name, "yes") == 0) + profileflg = 1; + } + while(getnsc() != '\n') + ; + if(debug['f']) + if(profileflg) + print("%4ld: profileflg %d\n", lineno, profileflg); + else + print("%4ld: profileflg off\n", lineno); +} + +void +pragincomplete(void) +{ + Sym *s; + Type *t; + int istag, w, et; + + istag = 0; + s = getsym(); + if(s == nil) + goto out; + et = 0; + w = s->lexical; + if(w == LSTRUCT) + et = TSTRUCT; + else if(w == LUNION) + et = TUNION; + if(et != 0){ + s = getsym(); + if(s == nil){ + yyerror("missing struct/union tag in pragma incomplete"); + goto out; + } + if(s->lexical != LNAME && s->lexical != LTYPE){ + yyerror("invalid struct/union tag: %s", s->name); + goto out; + } + dotag(s, et, 0); + istag = 1; + }else if(strcmp(s->name, "_off_") == 0){ + debug['T'] = 0; + goto out; + }else if(strcmp(s->name, "_on_") == 0){ + debug['T'] = 1; + goto out; + } + t = s->type; + if(istag) + t = s->suetag; + if(t == T) + yyerror("unknown type %s in pragma incomplete", s->name); + else if(!typesu[t->etype]) + yyerror("not struct/union type in pragma incomplete: %s", s->name); + else + t->garb |= GINCOMPLETE; +out: + while(getnsc() != '\n') + ; + if(debug['f']) + print("%s incomplete\n", s->name); +} diff --git a/src/cmd/cc/funct.c b/src/cmd/cc/funct.c new file mode 100644 index 000000000..21d86258f --- /dev/null +++ b/src/cmd/cc/funct.c @@ -0,0 +1,430 @@ +// Inferno utils/cc/funct.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/funct.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "cc.h" + +typedef struct Ftab Ftab; +struct Ftab +{ + char op; + char* name; + char typ; +}; +typedef struct Gtab Gtab; +struct Gtab +{ + char etype; + char* name; +}; + +Ftab ftabinit[OEND]; +Gtab gtabinit[NTYPE]; + +int +isfunct(Node *n) +{ + Type *t, *t1; + Funct *f; + Node *l; + Sym *s; + int o; + + o = n->op; + if(n->left == Z) + goto no; + t = n->left->type; + if(t == T) + goto no; + f = t->funct; + + switch(o) { + case OAS: // put cast on rhs + case OASI: + case OASADD: + case OASAND: + case OASASHL: + case OASASHR: + case OASDIV: + case OASLDIV: + case OASLMOD: + case OASLMUL: + case OASLSHR: + case OASMOD: + case OASMUL: + case OASOR: + case OASSUB: + case OASXOR: + if(n->right == Z) + goto no; + t1 = n->right->type; + if(t1 == T) + goto no; + if(t1->funct == f) + break; + + l = new(OXXX, Z, Z); + *l = *n->right; + + n->right->left = l; + n->right->right = Z; + n->right->type = t; + n->right->op = OCAST; + + if(!isfunct(n->right)) + prtree(n, "isfunc !"); + break; + + case OCAST: // t f(T) or T f(t) + t1 = n->type; + if(t1 == T) + goto no; + if(f != nil) { + s = f->castfr[t1->etype]; + if(s == S) + goto no; + n->right = n->left; + goto build; + } + f = t1->funct; + if(f != nil) { + s = f->castto[t->etype]; + if(s == S) + goto no; + n->right = n->left; + goto build; + } + goto no; + } + + if(f == nil) + goto no; + s = f->sym[o]; + if(s == S) + goto no; + + /* + * the answer is yes, + * now we rewrite the node + * and give diagnostics + */ + switch(o) { + default: + diag(n, "isfunct op missing %O\n", o); + goto bad; + + case OADD: // T f(T, T) + case OAND: + case OASHL: + case OASHR: + case ODIV: + case OLDIV: + case OLMOD: + case OLMUL: + case OLSHR: + case OMOD: + case OMUL: + case OOR: + case OSUB: + case OXOR: + + case OEQ: // int f(T, T) + case OGE: + case OGT: + case OHI: + case OHS: + case OLE: + case OLO: + case OLS: + case OLT: + case ONE: + if(n->right == Z) + goto bad; + t1 = n->right->type; + if(t1 == T) + goto bad; + if(t1->funct != f) + goto bad; + n->right = new(OLIST, n->left, n->right); + break; + + case OAS: // structure copies done by the compiler + case OASI: + goto no; + + case OASADD: // T f(T*, T) + case OASAND: + case OASASHL: + case OASASHR: + case OASDIV: + case OASLDIV: + case OASLMOD: + case OASLMUL: + case OASLSHR: + case OASMOD: + case OASMUL: + case OASOR: + case OASSUB: + case OASXOR: + if(n->right == Z) + goto bad; + t1 = n->right->type; + if(t1 == T) + goto bad; + if(t1->funct != f) + goto bad; + n->right = new(OLIST, new(OADDR, n->left, Z), n->right); + break; + + case OPOS: // T f(T) + case ONEG: + case ONOT: + case OCOM: + n->right = n->left; + break; + + + } + +build: + l = new(ONAME, Z, Z); + l->sym = s; + l->type = s->type; + l->etype = s->type->etype; + l->xoffset = s->offset; + l->class = s->class; + tcomo(l, 0); + + n->op = OFUNC; + n->left = l; + n->type = l->type->link; + if(tcompat(n, T, l->type, tfunct)) + goto bad; + if(tcoma(n->left, n->right, l->type->down, 1)) + goto bad; + return 1; + +no: + return 0; + +bad: + diag(n, "cant rewrite typestr for op %O\n", o); + prtree(n, "isfunct"); + n->type = T; + return 1; +} + +void +dclfunct(Type *t, Sym *s) +{ + Funct *f; + Node *n; + Type *f1, *f2, *f3, *f4; + int o, i, c; + char str[100]; + + if(t->funct) + return; + + // recognize generated tag of dorm _%d_ + if(t->tag == S) + goto bad; + for(i=0; c = t->tag->name[i]; i++) { + if(c == '_') { + if(i == 0 || t->tag->name[i+1] == 0) + continue; + break; + } + if(c < '0' || c > '9') + break; + } + if(c == 0) + goto bad; + + f = alloc(sizeof(*f)); + for(o=0; o<sizeof(f->sym); o++) + f->sym[o] = S; + + t->funct = f; + + f1 = typ(TFUNC, t); + f1->down = copytyp(t); + f1->down->down = t; + + f2 = typ(TFUNC, types[TINT]); + f2->down = copytyp(t); + f2->down->down = t; + + f3 = typ(TFUNC, t); + f3->down = typ(TIND, t); + f3->down->down = t; + + f4 = typ(TFUNC, t); + f4->down = t; + + for(i=0;; i++) { + o = ftabinit[i].op; + if(o == OXXX) + break; + sprint(str, "%s_%s_", t->tag->name, ftabinit[i].name); + n = new(ONAME, Z, Z); + n->sym = slookup(str); + f->sym[o] = n->sym; + switch(ftabinit[i].typ) { + default: + diag(Z, "dclfunct op missing %d\n", ftabinit[i].typ); + break; + + case 1: // T f(T,T) + + dodecl(xdecl, CEXTERN, f1, n); + break; + + case 2: // int f(T,T) == + dodecl(xdecl, CEXTERN, f2, n); + break; + + case 3: // void f(T*,T) += + dodecl(xdecl, CEXTERN, f3, n); + break; + + case 4: // T f(T) ~ + dodecl(xdecl, CEXTERN, f4, n); + break; + } + } + for(i=0;; i++) { + o = gtabinit[i].etype; + if(o == TXXX) + break; + + /* + * OCAST types T1 _T2_T1_(T2) + */ + sprint(str, "_%s%s_", gtabinit[i].name, t->tag->name); + n = new(ONAME, Z, Z); + n->sym = slookup(str); + f->castto[o] = n->sym; + + f1 = typ(TFUNC, t); + f1->down = types[o]; + dodecl(xdecl, CEXTERN, f1, n); + + sprint(str, "%s_%s_", t->tag->name, gtabinit[i].name); + n = new(ONAME, Z, Z); + n->sym = slookup(str); + f->castfr[o] = n->sym; + + f1 = typ(TFUNC, types[o]); + f1->down = t; + dodecl(xdecl, CEXTERN, f1, n); + } + return; +bad: + diag(Z, "dclfunct bad %T %s\n", t, s->name); +} + +Gtab gtabinit[NTYPE] = +{ + TCHAR, "c", + TUCHAR, "uc", + TSHORT, "h", + TUSHORT, "uh", + TINT, "i", + TUINT, "ui", + TLONG, "l", + TULONG, "ul", + TVLONG, "v", + TUVLONG, "uv", + TFLOAT, "f", + TDOUBLE, "d", + TXXX +}; + +Ftab ftabinit[OEND] = +{ + OADD, "add", 1, + OAND, "and", 1, + OASHL, "ashl", 1, + OASHR, "ashr", 1, + ODIV, "div", 1, + OLDIV, "ldiv", 1, + OLMOD, "lmod", 1, + OLMUL, "lmul", 1, + OLSHR, "lshr", 1, + OMOD, "mod", 1, + OMUL, "mul", 1, + OOR, "or", 1, + OSUB, "sub", 1, + OXOR, "xor", 1, + + OEQ, "eq", 2, + OGE, "ge", 2, + OGT, "gt", 2, + OHI, "hi", 2, + OHS, "hs", 2, + OLE, "le", 2, + OLO, "lo", 2, + OLS, "ls", 2, + OLT, "lt", 2, + ONE, "ne", 2, + + OASADD, "asadd", 3, + OASAND, "asand", 3, + OASASHL, "asashl", 3, + OASASHR, "asashr", 3, + OASDIV, "asdiv", 3, + OASLDIV, "asldiv", 3, + OASLMOD, "aslmod", 3, + OASLMUL, "aslmul", 3, + OASLSHR, "aslshr", 3, + OASMOD, "asmod", 3, + OASMUL, "asmul", 3, + OASOR, "asor", 3, + OASSUB, "assub", 3, + OASXOR, "asxor", 3, + + OPOS, "pos", 4, + ONEG, "neg", 4, + OCOM, "com", 4, + ONOT, "not", 4, + +// OPOSTDEC, +// OPOSTINC, +// OPREDEC, +// OPREINC, + + OXXX, +}; + +// Node* nodtestv; + +// Node* nodvpp; +// Node* nodppv; +// Node* nodvmm; +// Node* nodmmv; diff --git a/src/cmd/cc/lex.c b/src/cmd/cc/lex.c new file mode 100644 index 000000000..e3a8e440d --- /dev/null +++ b/src/cmd/cc/lex.c @@ -0,0 +1,1542 @@ +// Inferno utils/cc/lex.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/lex.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "cc.h" +#include "y.tab.h" + +#ifndef CPP +#define CPP "/bin/cpp" +#endif + +/* + * known debug flags + * -a acid declaration output + * -A !B + * -B non ANSI + * -d print declarations + * -D name define + * -F format specification check + * -i print initialization + * -I path include + * -l generate little-endian code + * -L print every NAME symbol + * -M constant multiplication + * -m print add/sub/mul trees + * -n print acid to file (%.c=%.acid) (with -a or -aa) + * -o file output file + * -p use standard cpp ANSI preprocessor (not on windows) + * -r print registerization + * -s print structure offsets (with -a or -aa) + * -S print assembly + * -t print type trees + * -V enable void* conversion warnings + * -v verbose printing + * -w print warnings + * -X abort on error + * -. Inhibit search for includes in source directory + */ + +void +main(int argc, char *argv[]) +{ + char *defs[50], *p; + int nproc, nout, status, i, c, ndef; + + memset(debug, 0, sizeof(debug)); + tinit(); + cinit(); + ginit(); + arginit(); + + profileflg = 1; /* #pragma can turn it off */ + tufield = simplet((1L<<tfield->etype) | BUNSIGNED); + ndef = 0; + outfile = 0; + include[ninclude++] = "."; + ARGBEGIN { + default: + c = ARGC(); + if(c >= 0 && c < sizeof(debug)) + debug[c]++; + break; + + case 'l': /* for little-endian mips */ + if(thechar != 'v'){ + print("can only use -l with vc"); + errorexit(); + } + thechar = '0'; + thestring = "spim"; + break; + + case 'o': + outfile = ARGF(); + break; + + case 'D': + p = ARGF(); + if(p) { + defs[ndef++] = p; + dodefine(p); + } + break; + + case 'I': + p = ARGF(); + setinclude(p); + break; + } ARGEND + if(argc < 1 && outfile == 0) { + print("usage: %cc [-options] files\n", thechar); + errorexit(); + } + if(argc > 1 && systemtype(Windows)){ + print("can't compile multiple files on windows\n"); + errorexit(); + } + if(argc > 1 && !systemtype(Windows)) { + nproc = 1; + /* + * if we're writing acid to standard output, don't compile + * concurrently, to avoid interleaving output. + */ + if(((!debug['a'] && !debug['Z']) || debug['n']) && + (p = getenv("NPROC")) != nil) + nproc = atol(p); /* */ + c = 0; + nout = 0; + for(;;) { + while(nout < nproc && argc > 0) { + i = myfork(); + if(i < 0) { + i = mywait(&status); + if(i < 0) { + print("cannot create a process\n"); + errorexit(); + } + if(status) + c++; + nout--; + continue; + } + if(i == 0) { + fprint(2, "%s:\n", *argv); + if (compile(*argv, defs, ndef)) + errorexit(); + exits(0); + } + nout++; + argc--; + argv++; + } + i = mywait(&status); + if(i < 0) { + if(c) + errorexit(); + exits(0); + } + if(status) + c++; + nout--; + } + } + + if(argc == 0) + c = compile("stdin", defs, ndef); + else + c = compile(argv[0], defs, ndef); + + if(c) + errorexit(); + exits(0); +} + +int +compile(char *file, char **defs, int ndef) +{ + char ofile[400], incfile[20]; + char *p, *av[100], opt[256]; + int i, c, fd[2]; + static int first = 1; + + strcpy(ofile, file); + p = utfrrune(ofile, pathchar()); + if(p) { + *p++ = 0; + if(!debug['.']) + include[0] = strdup(ofile); + } else + p = ofile; + + if(outfile == 0) { + outfile = p; + if(outfile) { + if(p = utfrrune(outfile, '.')) + if(p[1] == 'c' && p[2] == 0) + p[0] = 0; + p = utfrune(outfile, 0); + if(debug['a'] && debug['n']) + strcat(p, ".acid"); + else if(debug['Z'] && debug['n']) + strcat(p, "_pickle.c"); + else { + p[0] = '.'; + p[1] = thechar; + p[2] = 0; + } + } else + outfile = "/dev/null"; + } + + if(p = getenv("INCLUDE")) { + setinclude(p); + } else { + if(systemtype(Plan9)) { + sprint(incfile, "/%s/include", thestring); + setinclude(strdup(incfile)); + setinclude("/sys/include"); + } + } + if (first) + Binit(&diagbuf, 1, OWRITE); + /* + * if we're writing acid to standard output, don't keep scratching + * outbuf. + */ + if((debug['a'] || debug['Z']) && !debug['n']) { + if (first) { + outfile = 0; + Binit(&outbuf, dup(1, -1), OWRITE); + dup(2, 1); + } + } else { + c = mycreate(outfile, 0664); + if(c < 0) { + diag(Z, "cannot open %s - %r", outfile); + outfile = 0; + errorexit(); + } + Binit(&outbuf, c, OWRITE); + } + newio(); + first = 0; + + /* Use an ANSI preprocessor */ + if(debug['p']) { + if(systemtype(Windows)) { + diag(Z, "-p option not supported on windows"); + errorexit(); + } + if(myaccess(file) < 0) { + diag(Z, "%s does not exist", file); + errorexit(); + } + if(mypipe(fd) < 0) { + diag(Z, "pipe failed"); + errorexit(); + } + switch(myfork()) { + case -1: + diag(Z, "fork failed"); + errorexit(); + case 0: + close(fd[0]); + mydup(fd[1], 1); + close(fd[1]); + av[0] = CPP; + i = 1; + if(debug['.']){ + sprint(opt, "-."); + av[i++] = strdup(opt); + } + if(debug['+']) { + sprint(opt, "-+"); + av[i++] = strdup(opt); + } + for(c = 0; c < ndef; c++) { + sprint(opt, "-D%s", defs[c]); + av[i++] = strdup(opt); + } + for(c = 0; c < ninclude; c++) { + sprint(opt, "-I%s", include[c]); + av[i++] = strdup(opt); + } + if(strcmp(file, "stdin") != 0) + av[i++] = file; + av[i] = 0; + if(debug['p'] > 1) { + for(c = 0; c < i; c++) + fprint(2, "%s ", av[c]); + fprint(2, "\n"); + } + myexec(av[0], av); + fprint(2, "can't exec C preprocessor %s: %r\n", CPP); + errorexit(); + default: + close(fd[1]); + newfile(file, fd[0]); + break; + } + } else { + if(strcmp(file, "stdin") == 0) + newfile(file, 0); + else + newfile(file, -1); + } + yyparse(); + if(!debug['a'] && !debug['Z']) + gclean(); + return nerrors; +} + +void +errorexit(void) +{ + if(outfile) + remove(outfile); + exits("error"); +} + +void +pushio(void) +{ + Io *i; + + i = iostack; + if(i == I) { + yyerror("botch in pushio"); + errorexit(); + } + i->p = fi.p; + i->c = fi.c; +} + +void +newio(void) +{ + Io *i; + static int pushdepth = 0; + + i = iofree; + if(i == I) { + pushdepth++; + if(pushdepth > 1000) { + yyerror("macro/io expansion too deep"); + errorexit(); + } + i = alloc(sizeof(*i)); + } else + iofree = i->link; + i->c = 0; + i->f = -1; + ionext = i; +} + +void +newfile(char *s, int f) +{ + Io *i; + + if(debug['e']) + print("%L: %s\n", lineno, s); + + i = ionext; + i->link = iostack; + iostack = i; + i->f = f; + if(f < 0) + i->f = open(s, 0); + if(i->f < 0) { + yyerror("%cc: %r: %s", thechar, s); + errorexit(); + } + fi.c = 0; + linehist(s, 0); +} + +Sym* +slookup(char *s) +{ + + strcpy(symb, s); + return lookup(); +} + +Sym* +lookup(void) +{ + Sym *s; + ulong h; + char *p; + int c, n; + + h = 0; + for(p=symb; *p;) { + h = h * 3; + h += *p++; + } + n = (p - symb) + 1; + if((long)h < 0) + h = ~h; + h %= NHASH; + c = symb[0]; + for(s = hash[h]; s != S; s = s->link) { + if(s->name[0] != c) + continue; + if(strcmp(s->name, symb) == 0) + return s; + } + s = alloc(sizeof(*s)); + s->name = alloc(n); + memmove(s->name, symb, n); + + strcpy(s->name, symb); + s->link = hash[h]; + hash[h] = s; + syminit(s); + + return s; +} + +void +syminit(Sym *s) +{ + s->lexical = LNAME; + s->block = 0; + s->offset = 0; + s->type = T; + s->suetag = T; + s->class = CXXX; + s->aused = 0; + s->sig = SIGNONE; +} + +#define EOF (-1) +#define IGN (-2) +#define ESC (1<<20) +#define GETC() ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff)) + +enum +{ + Numdec = 1<<0, + Numlong = 1<<1, + Numuns = 1<<2, + Numvlong = 1<<3, + Numflt = 1<<4, +}; + +long +yylex(void) +{ + vlong vv; + long c, c1, t; + char *cp; + Rune rune; + Sym *s; + + if(peekc != IGN) { + c = peekc; + peekc = IGN; + goto l1; + } +l0: + c = GETC(); + +l1: + if(c >= Runeself) { + /* + * extension -- + * all multibyte runes are alpha + */ + cp = symb; + goto talph; + } + if(isspace(c)) { + if(c == '\n') + lineno++; + goto l0; + } + if(isalpha(c)) { + cp = symb; + if(c != 'L') + goto talph; + *cp++ = c; + c = GETC(); + if(c == '\'') { + /* L'x' */ + c = escchar('\'', 1, 0); + if(c == EOF) + c = '\''; + c1 = escchar('\'', 1, 0); + if(c1 != EOF) { + yyerror("missing '"); + peekc = c1; + } + yylval.vval = convvtox(c, TUSHORT); + return LUCONST; + } + if(c == '"') { + goto caselq; + } + goto talph; + } + if(isdigit(c)) + goto tnum; + switch(c) + { + + case EOF: + peekc = EOF; + return -1; + + case '_': + cp = symb; + goto talph; + + case '#': + domacro(); + goto l0; + + case '.': + c1 = GETC(); + if(isdigit(c1)) { + cp = symb; + *cp++ = c; + c = c1; + c1 = 0; + goto casedot; + } + break; + + case '"': + strcpy(symb, "\"<string>\""); + cp = alloc(0); + c1 = 0; + + /* "..." */ + for(;;) { + c = escchar('"', 0, 1); + if(c == EOF) + break; + if(c & ESC) { + cp = allocn(cp, c1, 1); + cp[c1++] = c; + } else { + rune = c; + c = runelen(rune); + cp = allocn(cp, c1, c); + runetochar(cp+c1, &rune); + c1 += c; + } + } + yylval.sval.l = c1; + do { + cp = allocn(cp, c1, 1); + cp[c1++] = 0; + } while(c1 & MAXALIGN); + yylval.sval.s = cp; + return LSTRING; + + caselq: + /* L"..." */ + strcpy(symb, "\"L<string>\""); + cp = alloc(0); + c1 = 0; + for(;;) { + c = escchar('"', 1, 0); + if(c == EOF) + break; + cp = allocn(cp, c1, sizeof(ushort)); + *(ushort*)(cp + c1) = c; + c1 += sizeof(ushort); + } + yylval.sval.l = c1; + do { + cp = allocn(cp, c1, sizeof(ushort)); + *(ushort*)(cp + c1) = 0; + c1 += sizeof(ushort); + } while(c1 & MAXALIGN); + yylval.sval.s = cp; + return LLSTRING; + + case '\'': + /* '.' */ + c = escchar('\'', 0, 0); + if(c == EOF) + c = '\''; + c1 = escchar('\'', 0, 0); + if(c1 != EOF) { + yyerror("missing '"); + peekc = c1; + } + vv = c; + yylval.vval = convvtox(vv, TUCHAR); + if(yylval.vval != vv) + yyerror("overflow in character constant: 0x%lx", c); + else + if(c & 0x80){ + nearln = lineno; + warn(Z, "sign-extended character constant"); + } + yylval.vval = convvtox(vv, TCHAR); + return LCONST; + + 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 == '=') + return LDVE; + break; + + case '*': + c1 = GETC(); + if(c1 == '=') + return LMLE; + break; + + case '%': + c1 = GETC(); + if(c1 == '=') + return LMDE; + break; + + case '+': + c1 = GETC(); + if(c1 == '+') + return LPP; + if(c1 == '=') + return LPE; + break; + + case '-': + c1 = GETC(); + if(c1 == '-') + return LMM; + if(c1 == '=') + return LME; + if(c1 == '>') + return LMG; + break; + + case '>': + c1 = GETC(); + if(c1 == '>') { + c = LRSH; + c1 = GETC(); + if(c1 == '=') + return LRSHE; + break; + } + if(c1 == '=') + return LGE; + break; + + case '<': + c1 = GETC(); + if(c1 == '<') { + c = LLSH; + c1 = GETC(); + if(c1 == '=') + return LLSHE; + break; + } + if(c1 == '=') + return LLE; + break; + + case '=': + c1 = GETC(); + if(c1 == '=') + return LEQ; + break; + + case '!': + c1 = GETC(); + if(c1 == '=') + return LNE; + break; + + case '&': + c1 = GETC(); + if(c1 == '&') + return LANDAND; + if(c1 == '=') + return LANDE; + break; + + case '|': + c1 = GETC(); + if(c1 == '|') + return LOROR; + if(c1 == '=') + return LORE; + break; + + case '^': + c1 = GETC(); + if(c1 == '=') + return LXORE; + break; + + default: + return c; + } + peekc = c1; + return c; + +talph: + /* + * cp is set to symb 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; + if(debug['L']) + print("%L: %s\n", lineno, symb); + peekc = c; + s = lookup(); + if(s->macro) { + newio(); + cp = ionext->b; + macexpand(s, cp); + pushio(); + ionext->link = iostack; + iostack = ionext; + fi.p = cp; + fi.c = strlen(cp); + if(peekc != IGN) { + cp[fi.c++] = peekc; + cp[fi.c] = 0; + peekc = IGN; + } + goto l0; + } + yylval.sym = s; + if(s->class == CTYPEDEF || s->class == CTYPESTR) + return LTYPE; + return s->lexical; + +tnum: + c1 = 0; + cp = symb; + if(c != '0') { + c1 |= Numdec; + 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 == symb+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: + if((c == 'U' || c == 'u') && !(c1 & Numuns)) { + c = GETC(); + c1 |= Numuns; + goto ncu; + } + if((c == 'L' || c == 'l') && !(c1 & Numvlong)) { + c = GETC(); + if(c1 & Numlong) + c1 |= Numvlong; + c1 |= Numlong; + goto ncu; + } + *cp = 0; + peekc = c; + if(mpatov(symb, &yylval.vval)) + yyerror("overflow in constant"); + + vv = yylval.vval; + if(c1 & Numvlong) { + if((c1 & Numuns) || convvtox(vv, TVLONG) < 0) { + c = LUVLCONST; + t = TUVLONG; + goto nret; + } + c = LVLCONST; + t = TVLONG; + goto nret; + } + if(c1 & Numlong) { + if((c1 & Numuns) || convvtox(vv, TLONG) < 0) { + c = LULCONST; + t = TULONG; + goto nret; + } + c = LLCONST; + t = TLONG; + goto nret; + } + if((c1 & Numuns) || convvtox(vv, TINT) < 0) { + c = LUCONST; + t = TUINT; + goto nret; + } + c = LCONST; + t = TINT; + goto nret; + +nret: + yylval.vval = convvtox(vv, t); + if(yylval.vval != vv){ + nearln = lineno; + warn(Z, "truncated constant: %T %s", types[t], symb); + } + return c; + +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: + if(c == 'L' || c == 'l') { + c = GETC(); + c1 |= Numlong; + } else + if(c == 'F' || c == 'f') { + c = GETC(); + c1 |= Numflt; + } + *cp = 0; + peekc = c; + yylval.dval = strtod(symb, nil); + if(isInf(yylval.dval, 1) || isInf(yylval.dval, -1)) { + yyerror("overflow in float constant"); + yylval.dval = 0; + } + if(c1 & Numflt) + return LFCONST; + return LDCONST; +} + +/* + * 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; +} + +int +getc(void) +{ + int c; + + if(peekc != IGN) { + c = peekc; + peekc = IGN; + } else + c = GETC(); + if(c == '\n') + lineno++; + if(c == EOF) { + yyerror("End of file"); + errorexit(); + } + return c; +} + +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) { + nearln = lineno; + diag(Z, "illegal rune in string"); + for(c=0; c<i; c++) + print(" %.2x", *(uchar*)(str+c)); + print("\n"); + } + return rune; +} + +int +getnsc(void) +{ + int c; + + if(peekc != IGN) { + c = peekc; + peekc = IGN; + } else + c = GETC(); + for(;;) { + if(!isspace(c)) + return c; + if(c == '\n') { + lineno++; + return c; + } + c = GETC(); + } +} + +void +unget(int c) +{ + + peekc = c; + if(c == '\n') + lineno--; +} + +long +escchar(long e, int longflg, int escflg) +{ + long c, l; + int i; + +loop: + c = getr(); + if(c == '\n') { + yyerror("newline in string"); + return EOF; + } + if(c != '\\') { + if(c == e) + c = EOF; + return c; + } + c = getr(); + if(c == 'x') { + /* + * note this is not ansi, + * supposed to only accept 2 hex + */ + i = 2; + if(longflg) + i = 4; + 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; + } + unget(c); + break; + } + if(escflg) + l |= ESC; + return l; + } + if(c >= '0' && c <= '7') { + /* + * note this is not ansi, + * supposed to only accept 3 oct + */ + i = 2; + if(longflg) + i = 5; + l = c - '0'; + for(; i>0; i--) { + c = getc(); + if(c >= '0' && c <= '7') { + l = l*8 + c-'0'; + continue; + } + unget(c); + } + if(escflg) + l |= ESC; + return l; + } + switch(c) + { + case '\n': goto loop; + case 'n': return '\n'; + case 't': return '\t'; + case 'b': return '\b'; + case 'r': return '\r'; + case 'f': return '\f'; + case 'a': return '\a'; + case 'v': return '\v'; + } + return c; +} + +struct +{ + char *name; + ushort lexical; + ushort type; +} itab[] = +{ + "auto", LAUTO, 0, + "break", LBREAK, 0, + "case", LCASE, 0, + "char", LCHAR, TCHAR, + "const", LCONSTNT, 0, + "continue", LCONTINUE, 0, + "default", LDEFAULT, 0, + "do", LDO, 0, + "double", LDOUBLE, TDOUBLE, + "else", LELSE, 0, + "enum", LENUM, 0, + "extern", LEXTERN, 0, + "float", LFLOAT, TFLOAT, + "for", LFOR, 0, + "goto", LGOTO, 0, + "if", LIF, 0, + "inline", LINLINE, 0, + "int", LINT, TINT, + "long", LLONG, TLONG, + "register", LREGISTER, 0, + "restrict", LRESTRICT, 0, + "return", LRETURN, 0, + "SET", LSET, 0, + "short", LSHORT, TSHORT, + "signed", LSIGNED, 0, + "signof", LSIGNOF, 0, + "sizeof", LSIZEOF, 0, + "static", LSTATIC, 0, + "struct", LSTRUCT, 0, + "switch", LSWITCH, 0, + "typedef", LTYPEDEF, 0, + "typestr", LTYPESTR, 0, + "union", LUNION, 0, + "unsigned", LUNSIGNED, 0, + "USED", LUSED, 0, + "void", LVOID, TVOID, + "volatile", LVOLATILE, 0, + "while", LWHILE, 0, + 0 +}; + +void +cinit(void) +{ + Sym *s; + int i; + Type *t; + + nerrors = 0; + lineno = 1; + iostack = I; + iofree = I; + peekc = IGN; + nhunk = 0; + + types[TXXX] = T; + types[TCHAR] = typ(TCHAR, T); + types[TUCHAR] = typ(TUCHAR, T); + types[TSHORT] = typ(TSHORT, T); + types[TUSHORT] = typ(TUSHORT, T); + types[TINT] = typ(TINT, T); + types[TUINT] = typ(TUINT, T); + types[TLONG] = typ(TLONG, T); + types[TULONG] = typ(TULONG, T); + types[TVLONG] = typ(TVLONG, T); + types[TUVLONG] = typ(TUVLONG, T); + types[TFLOAT] = typ(TFLOAT, T); + types[TDOUBLE] = typ(TDOUBLE, T); + types[TVOID] = typ(TVOID, T); + types[TENUM] = typ(TENUM, T); + types[TFUNC] = typ(TFUNC, types[TINT]); + types[TIND] = typ(TIND, types[TVOID]); + + for(i=0; i<NHASH; i++) + hash[i] = S; + for(i=0; itab[i].name; i++) { + s = slookup(itab[i].name); + s->lexical = itab[i].lexical; + if(itab[i].type != 0) + s->type = types[itab[i].type]; + } + blockno = 0; + autobn = 0; + autoffset = 0; + + t = typ(TARRAY, types[TCHAR]); + t->width = 0; + symstring = slookup(".string"); + symstring->class = CSTATIC; + symstring->type = t; + + t = typ(TARRAY, types[TCHAR]); + t->width = 0; + + nodproto = new(OPROTO, Z, Z); + dclstack = D; + + pathname = allocn(pathname, 0, 100); + if(mygetwd(pathname, 99) == 0) { + pathname = allocn(pathname, 100, 900); + if(mygetwd(pathname, 999) == 0) + strcpy(pathname, "/???"); + } + + fmtinstall('O', Oconv); + fmtinstall('T', Tconv); + fmtinstall('F', FNconv); + fmtinstall('L', Lconv); + fmtinstall('Q', Qconv); + fmtinstall('|', VBconv); +} + +int +filbuf(void) +{ + Io *i; + +loop: + i = iostack; + if(i == I) + return EOF; + if(i->f < 0) + goto pop; + fi.c = read(i->f, i->b, BUFSIZ) - 1; + if(fi.c < 0) { + close(i->f); + linehist(0, 0); + goto pop; + } + fi.p = i->b + 1; + return i->b[0] & 0xff; + +pop: + iostack = i->link; + i->link = iofree; + iofree = i; + i = iostack; + if(i == I) + return EOF; + fi.p = i->p; + fi.c = i->c; + if(--fi.c < 0) + goto loop; + return *fi.p++ & 0xff; +} + +int +Oconv(Fmt *fp) +{ + int a; + + a = va_arg(fp->args, int); + if(a < OXXX || a > OEND) + return fmtprint(fp, "***badO %d***", a); + + return fmtstrcpy(fp, onames[a]); +} + +int +Lconv(Fmt *fp) +{ + char str[STRINGSZ], s[STRINGSZ]; + Hist *h; + struct + { + Hist* incl; /* start of this include file */ + long idel; /* delta line number to apply to include */ + Hist* line; /* start of this #line directive */ + long ldel; /* delta line number to apply to #line */ + } a[HISTSZ]; + long l, d; + int i, n; + + l = va_arg(fp->args, long); + n = 0; + for(h = hist; h != H; h = h->link) { + if(l < h->line) + break; + if(h->name) { + if(h->offset != 0) { /* #line directive, not #pragma */ + if(n > 0 && n < HISTSZ && h->offset >= 0) { + a[n-1].line = h; + a[n-1].ldel = h->line - h->offset + 1; + } + } else { + if(n < HISTSZ) { /* beginning of file */ + a[n].incl = h; + a[n].idel = h->line; + a[n].line = 0; + } + n++; + } + continue; + } + n--; + if(n > 0 && n < HISTSZ) { + d = h->line - a[n].incl->line; + a[n-1].ldel += d; + a[n-1].idel += d; + } + } + if(n > HISTSZ) + n = HISTSZ; + str[0] = 0; + for(i=n-1; i>=0; i--) { + if(i != n-1) { + if(fp->flags & ~(FmtWidth|FmtPrec)) /* BUG ROB - was f3 */ + break; + strcat(str, " "); + } + if(a[i].line) + snprint(s, STRINGSZ, "%s:%ld[%s:%ld]", + a[i].line->name, l-a[i].ldel+1, + a[i].incl->name, l-a[i].idel+1); + else + snprint(s, STRINGSZ, "%s:%ld", + a[i].incl->name, l-a[i].idel+1); + if(strlen(s)+strlen(str) >= STRINGSZ-10) + break; + strcat(str, s); + l = a[i].incl->line - 1; /* now print out start of this file */ + } + if(n == 0) + strcat(str, "<eof>"); + return fmtstrcpy(fp, str); +} + +int +Tconv(Fmt *fp) +{ + char str[STRINGSZ+20], s[STRINGSZ+20]; + Type *t, *t1; + int et; + long n; + + str[0] = 0; + for(t = va_arg(fp->args, Type*); t != T; t = t->link) { + et = t->etype; + if(str[0]) + strcat(str, " "); + if(t->garb&~GINCOMPLETE) { + sprint(s, "%s ", gnames[t->garb&~GINCOMPLETE]); + if(strlen(str) + strlen(s) < STRINGSZ) + strcat(str, s); + } + sprint(s, "%s", tnames[et]); + if(strlen(str) + strlen(s) < STRINGSZ) + strcat(str, s); + if(et == TFUNC && (t1 = t->down)) { + sprint(s, "(%T", t1); + if(strlen(str) + strlen(s) < STRINGSZ) + strcat(str, s); + while(t1 = t1->down) { + sprint(s, ", %T", t1); + if(strlen(str) + strlen(s) < STRINGSZ) + strcat(str, s); + } + if(strlen(str) + strlen(s) < STRINGSZ) + strcat(str, ")"); + } + if(et == TARRAY) { + n = t->width; + if(t->link && t->link->width) + n /= t->link->width; + sprint(s, "[%ld]", n); + if(strlen(str) + strlen(s) < STRINGSZ) + strcat(str, s); + } + if(t->nbits) { + sprint(s, " %d:%d", t->shift, t->nbits); + if(strlen(str) + strlen(s) < STRINGSZ) + strcat(str, s); + } + if(typesu[et]) { + if(t->tag) { + strcat(str, " "); + if(strlen(str) + strlen(t->tag->name) < STRINGSZ) + strcat(str, t->tag->name); + } else + strcat(str, " {}"); + break; + } + } + return fmtstrcpy(fp, str); +} + +int +FNconv(Fmt *fp) +{ + char *str; + Node *n; + + n = va_arg(fp->args, Node*); + str = "<indirect>"; + if(n != Z && (n->op == ONAME || n->op == ODOT || n->op == OELEM)) + str = n->sym->name; + return fmtstrcpy(fp, str); +} + +int +Qconv(Fmt *fp) +{ + char str[STRINGSZ+20], *s; + long b; + int i; + + str[0] = 0; + for(b = va_arg(fp->args, long); b;) { + i = bitno(b); + if(str[0]) + strcat(str, " "); + s = qnames[i]; + if(strlen(str) + strlen(s) >= STRINGSZ) + break; + strcat(str, s); + b &= ~(1L << i); + } + return fmtstrcpy(fp, str); +} + +int +VBconv(Fmt *fp) +{ + char str[STRINGSZ]; + int i, n, t, pc; + + n = va_arg(fp->args, int); + pc = 0; /* BUG: was printcol */ + i = 0; + while(pc < n) { + t = (pc+4) & ~3; + if(t <= n) { + str[i++] = '\t'; + pc = t; + continue; + } + str[i++] = ' '; + pc++; + } + str[i] = 0; + + return fmtstrcpy(fp, str); +} + +void +setinclude(char *p) +{ + int i; + char *e; + + while(*p != 0) { + e = strchr(p, ' '); + if(e != 0) + *e = '\0'; + + for(i=1; i < ninclude; i++) + if(strcmp(p, include[i]) == 0) + break; + + if(i >= ninclude) + include[ninclude++] = p; + + if(ninclude > nelem(include)) { + diag(Z, "ninclude too small %d", nelem(include)); + exits("ninclude"); + } + + if(e == 0) + break; + p = e+1; + } +} diff --git a/src/cmd/cc/lexbody b/src/cmd/cc/lexbody new file mode 100644 index 000000000..f7ba6d0fc --- /dev/null +++ b/src/cmd/cc/lexbody @@ -0,0 +1,723 @@ +// Inferno utils/cc/lexbody +// http://code.google.com/p/inferno-os/source/browse/utils/cc/lexbody +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +/* + * common code for all the assemblers + */ + +void +pragpack(void) +{ + while(getnsc() != '\n') + ; +} + +void +pragvararg(void) +{ + while(getnsc() != '\n') + ; +} + +void +pragfpround(void) +{ + while(getnsc() != '\n') + ; +} + +void +pragprofile(void) +{ + while(getnsc() != '\n') + ; +} + +void +pragincomplete(void) +{ + while(getnsc() != '\n') + ; +} + +void +gethunk(void) +{ + hunk = malloc(NHUNK); + memset(hunk, 0, NHUNK); + nhunk = NHUNK; +} + +void* +alloc(long n) +{ + void *p; + + while((uintptr)hunk & MAXALIGN) { + hunk++; + nhunk--; + } + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void* +allocn(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; +} + +void +setinclude(char *p) +{ + int i; + + if(p == 0) + return; + for(i=1; i < ninclude; i++) + if(strcmp(p, include[i]) == 0) + return; + + if(ninclude >= nelem(include)) { + yyerror("ninclude too small %d", nelem(include)); + exits("ninclude"); + } + include[ninclude++] = p; +} + +void +errorexit(void) +{ + + if(outfile) + remove(outfile); + exits("error"); +} + +void +pushio(void) +{ + Io *i; + + i = iostack; + if(i == I) { + yyerror("botch in pushio"); + errorexit(); + } + i->p = fi.p; + i->c = fi.c; +} + +void +newio(void) +{ + Io *i; + static int pushdepth = 0; + + i = iofree; + if(i == I) { + pushdepth++; + if(pushdepth > 1000) { + yyerror("macro/io expansion too deep"); + errorexit(); + } + i = alloc(sizeof(*i)); + } else + iofree = i->link; + i->c = 0; + i->f = -1; + ionext = i; +} + +void +newfile(char *s, int f) +{ + Io *i; + + i = ionext; + i->link = iostack; + iostack = i; + i->f = f; + if(f < 0) + i->f = open(s, 0); + if(i->f < 0) { + yyerror("%ca: %r: %s", thechar, s); + errorexit(); + } + fi.c = 0; + linehist(s, 0); +} + +Sym* +slookup(char *s) +{ + + strcpy(symb, s); + return lookup(); +} + +Sym* +lookup(void) +{ + Sym *s; + long h; + char *p; + int c, l; + + h = 0; + for(p=symb; c = *p; p++) + h = h+h+h + c; + l = (p - symb) + 1; + if(h < 0) + h = ~h; + h %= NHASH; + c = symb[0]; + for(s = hash[h]; s != S; s = s->link) { + if(s->name[0] != c) + continue; + if(memcmp(s->name, symb, l) == 0) + return s; + } + s = alloc(sizeof(*s)); + s->name = alloc(l); + memmove(s->name, symb, l); + + s->link = hash[h]; + hash[h] = s; + syminit(s); + return s; +} + +long +yylex(void) +{ + int c, c1; + char *cp; + Sym *s; + + c = peekc; + if(c != IGN) { + peekc = IGN; + goto l1; + } +l0: + c = GETC(); + +l1: + if(c == EOF) { + peekc = EOF; + return -1; + } + if(isspace(c)) { + if(c == '\n') { + lineno++; + return ';'; + } + goto l0; + } + if(isalpha(c)) + goto talph; + if(isdigit(c)) + goto tnum; + switch(c) + { + case '\n': + lineno++; + return ';'; + + case '#': + domacro(); + goto l0; + + case '.': + c = GETC(); + if(isalpha(c)) { + cp = symb; + *cp++ = '.'; + goto aloop; + } + if(isdigit(c)) { + cp = symb; + *cp++ = '.'; + goto casedot; + } + peekc = c; + return '.'; + + talph: + case '_': + case '@': + cp = symb; + + aloop: + *cp++ = c; + c = GETC(); + if(isalpha(c) || isdigit(c) || c == '_' || c == '$') + goto aloop; + *cp = 0; + peekc = c; + s = lookup(); + if(s->macro) { + newio(); + cp = ionext->b; + macexpand(s, cp); + pushio(); + ionext->link = iostack; + iostack = ionext; + fi.p = cp; + fi.c = strlen(cp); + if(peekc != IGN) { + cp[fi.c++] = peekc; + cp[fi.c] = 0; + peekc = IGN; + } + goto l0; + } + if(s->type == 0) + s->type = LNAME; + if(s->type == LNAME || + s->type == LVAR || + s->type == LLAB) { + yylval.sym = s; + return s->type; + } + yylval.lval = s->value; + return s->type; + + tnum: + cp = symb; + if(c != '0') + goto dc; + *cp++ = c; + c = GETC(); + c1 = 3; + if(c == 'x' || c == 'X') { + c1 = 4; + c = GETC(); + } else + if(c < '0' || c > '7') + goto dc; + yylval.lval = 0; + for(;;) { + if(c >= '0' && c <= '9') { + if(c > '7' && c1 == 3) + break; + yylval.lval <<= c1; + yylval.lval += c - '0'; + c = GETC(); + continue; + } + if(c1 == 3) + break; + if(c >= 'A' && c <= 'F') + c += 'a' - 'A'; + if(c >= 'a' && c <= 'f') { + yylval.lval <<= c1; + yylval.lval += c - 'a' + 10; + c = GETC(); + continue; + } + break; + } + goto ncu; + + dc: + for(;;) { + if(!isdigit(c)) + break; + *cp++ = c; + c = GETC(); + } + if(c == '.') + goto casedot; + if(c == 'e' || c == 'E') + goto casee; + *cp = 0; + if(sizeof(yylval.lval) == sizeof(vlong)) + yylval.lval = strtoll(symb, nil, 10); + else + yylval.lval = strtol(symb, nil, 10); + + ncu: + while(c == 'U' || c == 'u' || c == 'l' || c == 'L') + c = GETC(); + peekc = c; + return LCONST; + + casedot: + for(;;) { + *cp++ = c; + c = GETC(); + if(!isdigit(c)) + break; + } + if(c == 'e' || c == 'E') + goto casee; + goto caseout; + + casee: + *cp++ = 'e'; + c = GETC(); + if(c == '+' || c == '-') { + *cp++ = c; + c = GETC(); + } + while(isdigit(c)) { + *cp++ = c; + c = GETC(); + } + + caseout: + *cp = 0; + peekc = c; + if(FPCHIP) { + yylval.dval = atof(symb); + return LFCONST; + } + yyerror("assembler cannot interpret fp constants"); + yylval.lval = 1L; + return LCONST; + + case '"': + memcpy(yylval.sval, nullgen.sval, sizeof(yylval.sval)); + cp = yylval.sval; + c1 = 0; + for(;;) { + c = escchar('"'); + if(c == EOF) + break; + if(c1 < sizeof(yylval.sval)) + *cp++ = c; + c1++; + } + if(c1 > sizeof(yylval.sval)) + yyerror("string constant too long"); + return LSCONST; + + case '\'': + c = escchar('\''); + if(c == EOF) + c = '\''; + if(escchar('\'') != EOF) + yyerror("missing '"); + yylval.lval = c; + return LCONST; + + case '/': + c1 = GETC(); + if(c1 == '/') { + for(;;) { + c = GETC(); + if(c == '\n') { + lineno++; + goto l1; + } + if(c == EOF) { + yyerror("eof in comment"); + errorexit(); + } + } + } + if(c1 == '*') { + for(;;) { + c = GETC(); + while(c == '*') { + c = GETC(); + if(c == '/') + goto l0; + } + if(c == EOF) { + yyerror("eof in comment"); + errorexit(); + } + if(c == '\n') + lineno++; + } + } + break; + + default: + return c; + } + peekc = c1; + return c; +} + +int +getc(void) +{ + int c; + + c = peekc; + if(c != IGN) { + peekc = IGN; + return c; + } + c = GETC(); + if(c == '\n') + lineno++; + if(c == EOF) { + yyerror("End of file"); + errorexit(); + } + return c; +} + +int +getnsc(void) +{ + int c; + + for(;;) { + c = getc(); + if(!isspace(c) || c == '\n') + return c; + } +} + +void +unget(int c) +{ + + peekc = c; + if(c == '\n') + lineno--; +} + +int +escchar(int e) +{ + int c, l; + +loop: + c = getc(); + if(c == '\n') { + yyerror("newline in string"); + return EOF; + } + if(c != '\\') { + if(c == e) + return EOF; + return c; + } + c = getc(); + if(c >= '0' && c <= '7') { + l = c - '0'; + c = getc(); + if(c >= '0' && c <= '7') { + l = l*8 + c-'0'; + c = getc(); + if(c >= '0' && c <= '7') { + l = l*8 + c-'0'; + return l; + } + } + peekc = c; + return l; + } + switch(c) + { + case '\n': goto loop; + case 'n': return '\n'; + case 't': return '\t'; + case 'b': return '\b'; + case 'r': return '\r'; + case 'f': return '\f'; + case 'a': return 0x07; + case 'v': return 0x0b; + case 'z': return 0x00; + } + return c; +} + +void +pinit(char *f) +{ + int i; + Sym *s; + + lineno = 1; + newio(); + newfile(f, -1); + pc = 0; + peekc = IGN; + sym = 1; + for(i=0; i<NSYM; i++) { + h[i].type = 0; + h[i].sym = S; + } + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->link) + s->macro = 0; +} + +int +filbuf(void) +{ + Io *i; + +loop: + i = iostack; + if(i == I) + return EOF; + if(i->f < 0) + goto pop; + fi.c = read(i->f, i->b, BUFSIZ) - 1; + if(fi.c < 0) { + close(i->f); + linehist(0, 0); + goto pop; + } + fi.p = i->b + 1; + return i->b[0]; + +pop: + iostack = i->link; + i->link = iofree; + iofree = i; + i = iostack; + if(i == I) + return EOF; + fi.p = i->p; + fi.c = i->c; + if(--fi.c < 0) + goto loop; + return *fi.p++; +} + +void +yyerror(char *a, ...) +{ + char buf[200]; + va_list arg; + + /* + * hack to intercept message from yaccpar + */ + if(strcmp(a, "syntax error") == 0) { + yyerror("syntax error, last name: %s", symb); + return; + } + prfile(lineno); + va_start(arg, a); + vseprint(buf, buf+sizeof(buf), a, arg); + va_end(arg); + print("%s\n", buf); + nerrors++; + if(nerrors > 10) { + print("too many errors\n"); + errorexit(); + } +} + +void +prfile(long l) +{ + int i, n; + Hist a[HISTSZ], *h; + long d; + + n = 0; + for(h = hist; h != H; h = h->link) { + if(l < h->line) + break; + if(h->name) { + if(h->offset == 0) { + if(n >= 0 && n < HISTSZ) + a[n] = *h; + n++; + continue; + } + if(n > 0 && n < HISTSZ) + if(a[n-1].offset == 0) { + a[n] = *h; + n++; + } else + a[n-1] = *h; + continue; + } + n--; + if(n >= 0 && n < HISTSZ) { + d = h->line - a[n].line; + for(i=0; i<n; i++) + a[i].line += d; + } + } + if(n > HISTSZ) + n = HISTSZ; + for(i=0; i<n; i++) + print("%s:%ld ", a[i].name, (long)(l-a[i].line+a[i].offset+1)); +} + +void +ieeedtod(Ieee *ieee, double native) +{ + double fr, ho, f; + int exp; + + if(native < 0) { + ieeedtod(ieee, -native); + ieee->h |= 0x80000000L; + return; + } + if(native == 0) { + ieee->l = 0; + ieee->h = 0; + return; + } + fr = frexp(native, &exp); + f = 2097152L; /* shouldnt use fp constants here */ + fr = modf(fr*f, &ho); + ieee->h = ho; + ieee->h &= 0xfffffL; + ieee->h |= (exp+1022L) << 20; + f = 65536L; + fr = modf(fr*f, &ho); + ieee->l = ho; + ieee->l <<= 16; + ieee->l |= (long)(fr*f); +} diff --git a/src/cmd/cc/mac.c b/src/cmd/cc/mac.c new file mode 100644 index 000000000..c08cd9c97 --- /dev/null +++ b/src/cmd/cc/mac.c @@ -0,0 +1,33 @@ +// Inferno utils/cc/mac.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/mac.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "cc.h" + +#include "macbody" diff --git a/src/cmd/cc/macbody b/src/cmd/cc/macbody new file mode 100644 index 000000000..9d309c10d --- /dev/null +++ b/src/cmd/cc/macbody @@ -0,0 +1,842 @@ +// Inferno utils/cc/macbody +// http://code.google.com/p/inferno-os/source/browse/utils/cc/macbody +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#define VARMAC 0x80 + +long +getnsn(void) +{ + long n; + int c; + + c = getnsc(); + if(c < '0' || c > '9') + return -1; + n = 0; + while(c >= '0' && c <= '9') { + n = n*10 + c-'0'; + c = getc(); + } + unget(c); + return n; +} + +Sym* +getsym(void) +{ + int c; + char *cp; + + c = getnsc(); + if(!isalpha(c) && c != '_') { + unget(c); + return S; + } + for(cp = symb;;) { + if(cp <= symb+NSYMB-4) + *cp++ = c; + c = getc(); + if(isalnum(c) || c == '_') + continue; + unget(c); + break; + } + *cp = 0; + if(cp > symb+NSYMB-4) + yyerror("symbol too large: %s", symb); + return lookup(); +} + +Sym* +getsymdots(int *dots) +{ + int c; + Sym *s; + + s = getsym(); + if(s != S) + return s; + + c = getnsc(); + if(c != '.'){ + unget(c); + return S; + } + if(getc() != '.' || getc() != '.') + yyerror("bad dots in macro"); + *dots = 1; + return slookup("__VA_ARGS__"); +} + +int +getcom(void) +{ + int c; + + for(;;) { + c = getnsc(); + if(c != '/') + break; + c = getc(); + if(c == '/') { + while(c != '\n') + c = getc(); + break; + } + if(c != '*') + break; + c = getc(); + for(;;) { + if(c == '*') { + c = getc(); + if(c != '/') + continue; + c = getc(); + break; + } + if(c == '\n') { + yyerror("comment across newline"); + break; + } + c = getc(); + } + if(c == '\n') + break; + } + return c; +} + +void +dodefine(char *cp) +{ + Sym *s; + char *p; + long l; + + strcpy(symb, cp); + p = strchr(symb, '='); + if(p) { + *p++ = 0; + s = lookup(); + l = strlen(p) + 2; /* +1 null, +1 nargs */ + s->macro = alloc(l); + strcpy(s->macro+1, p); + } else { + s = lookup(); + s->macro = "\0001"; /* \000 is nargs */ + } + if(debug['m']) + print("#define (-D) %s %s\n", s->name, s->macro+1); +} + +struct +{ + char *macname; + void (*macf)(void); +} mactab[] = +{ + "ifdef", 0, /* macif(0) */ + "ifndef", 0, /* macif(1) */ + "else", 0, /* macif(2) */ + + "line", maclin, + "define", macdef, + "include", macinc, + "undef", macund, + + "pragma", macprag, + "endif", macend, + 0 +}; + +void +domacro(void) +{ + int i; + Sym *s; + + s = getsym(); + if(s == S) + s = slookup("endif"); + for(i=0; mactab[i].macname; i++) + if(strcmp(s->name, mactab[i].macname) == 0) { + if(mactab[i].macf) + (*mactab[i].macf)(); + else + macif(i); + return; + } + yyerror("unknown #: %s", s->name); + macend(); +} + +void +macund(void) +{ + Sym *s; + + s = getsym(); + macend(); + if(s == S) { + yyerror("syntax in #undef"); + return; + } + s->macro = 0; +} + +#define NARG 25 +void +macdef(void) +{ + Sym *s, *a; + char *args[NARG], *np, *base; + int n, i, c, len, dots; + int ischr; + + s = getsym(); + if(s == S) + goto bad; + if(s->macro) + yyerror("macro redefined: %s", s->name); + c = getc(); + n = -1; + dots = 0; + if(c == '(') { + n++; + c = getnsc(); + if(c != ')') { + unget(c); + for(;;) { + a = getsymdots(&dots); + if(a == S) + goto bad; + if(n >= NARG) { + yyerror("too many arguments in #define: %s", s->name); + goto bad; + } + args[n++] = a->name; + c = getnsc(); + if(c == ')') + break; + if(c != ',' || dots) + goto bad; + } + } + c = getc(); + } + if(isspace(c)) + if(c != '\n') + c = getnsc(); + base = hunk; + len = 1; + ischr = 0; + for(;;) { + if(isalpha(c) || c == '_') { + np = symb; + *np++ = c; + c = getc(); + while(isalnum(c) || c == '_') { + *np++ = c; + c = getc(); + } + *np = 0; + for(i=0; i<n; i++) + if(strcmp(symb, args[i]) == 0) + break; + if(i >= n) { + i = strlen(symb); + base = allocn(base, len, i); + memcpy(base+len, symb, i); + len += i; + continue; + } + base = allocn(base, len, 2); + base[len++] = '#'; + base[len++] = 'a' + i; + continue; + } + if(ischr){ + if(c == '\\'){ + base = allocn(base, len, 1); + base[len++] = c; + c = getc(); + }else if(c == ischr) + ischr = 0; + }else{ + if(c == '"' || c == '\''){ + base = allocn(base, len, 1); + base[len++] = c; + ischr = c; + c = getc(); + continue; + } + if(c == '/') { + c = getc(); + if(c == '/'){ + c = getc(); + for(;;) { + if(c == '\n') + break; + c = getc(); + } + continue; + } + if(c == '*'){ + c = getc(); + for(;;) { + if(c == '*') { + c = getc(); + if(c != '/') + continue; + c = getc(); + break; + } + if(c == '\n') { + yyerror("comment and newline in define: %s", s->name); + break; + } + c = getc(); + } + continue; + } + base = allocn(base, len, 1); + base[len++] = '/'; + continue; + } + } + if(c == '\\') { + c = getc(); + if(c == '\n') { + c = getc(); + continue; + } + else if(c == '\r') { + c = getc(); + if(c == '\n') { + c = getc(); + continue; + } + } + base = allocn(base, len, 1); + base[len++] = '\\'; + continue; + } + if(c == '\n') + break; + if(c == '#') + if(n > 0) { + base = allocn(base, len, 1); + base[len++] = c; + } + base = allocn(base, len, 1); + base[len++] = c; + c = ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff)); + if(c == '\n') + lineno++; + if(c == -1) { + yyerror("eof in a macro: %s", s->name); + break; + } + } + do { + base = allocn(base, len, 1); + base[len++] = 0; + } while(len & 3); + + *base = n+1; + if(dots) + *base |= VARMAC; + s->macro = base; + if(debug['m']) + print("#define %s %s\n", s->name, s->macro+1); + return; + +bad: + if(s == S) + yyerror("syntax in #define"); + else + yyerror("syntax in #define: %s", s->name); + macend(); +} + +void +macexpand(Sym *s, char *b) +{ + char buf[2000]; + int n, l, c, nargs; + char *arg[NARG], *cp, *ob, *ecp, dots; + + ob = b; + if(*s->macro == 0) { + strcpy(b, s->macro+1); + if(debug['m']) + print("#expand %s %s\n", s->name, ob); + return; + } + + nargs = (char)(*s->macro & ~VARMAC) - 1; + dots = *s->macro & VARMAC; + + c = getnsc(); + if(c != '(') + goto bad; + n = 0; + c = getc(); + if(c != ')') { + unget(c); + l = 0; + cp = buf; + ecp = cp + sizeof(buf)-4; + arg[n++] = cp; + for(;;) { + if(cp >= ecp) + goto toobig; + c = getc(); + if(c == '"') + for(;;) { + if(cp >= ecp) + goto toobig; + *cp++ = c; + c = getc(); + if(c == '\\') { + *cp++ = c; + c = getc(); + continue; + } + if(c == '\n') + goto bad; + if(c == '"') + break; + } + if(c == '\'') + for(;;) { + if(cp >= ecp) + goto toobig; + *cp++ = c; + c = getc(); + if(c == '\\') { + *cp++ = c; + c = getc(); + continue; + } + if(c == '\n') + goto bad; + if(c == '\'') + break; + } + if(c == '/') { + c = getc(); + switch(c) { + case '*': + for(;;) { + c = getc(); + if(c == '*') { + c = getc(); + if(c == '/') + break; + } + } + *cp++ = ' '; + continue; + case '/': + while((c = getc()) != '\n') + ; + break; + default: + unget(c); + c = '/'; + } + } + if(l == 0) { + if(c == ',') { + if(n == nargs && dots) { + *cp++ = ','; + continue; + } + *cp++ = 0; + arg[n++] = cp; + if(n > nargs) + break; + continue; + } + if(c == ')') + break; + } + if(c == '\n') + c = ' '; + *cp++ = c; + if(c == '(') + l++; + if(c == ')') + l--; + } + *cp = 0; + } + if(n != nargs) { + yyerror("argument mismatch expanding: %s", s->name); + *b = 0; + return; + } + cp = s->macro+1; + for(;;) { + c = *cp++; + if(c == '\n') + c = ' '; + if(c != '#') { + *b++ = c; + if(c == 0) + break; + continue; + } + c = *cp++; + if(c == 0) + goto bad; + if(c == '#') { + *b++ = c; + continue; + } + c -= 'a'; + if(c < 0 || c >= n) + continue; + strcpy(b, arg[c]); + b += strlen(arg[c]); + } + *b = 0; + if(debug['m']) + print("#expand %s %s\n", s->name, ob); + return; + +bad: + yyerror("syntax in macro expansion: %s", s->name); + *b = 0; + return; + +toobig: + yyerror("too much text in macro expansion: %s", s->name); + *b = 0; +} + +void +macinc(void) +{ + int c0, c, i, f; + char str[STRINGSZ], *hp; + + c0 = getnsc(); + if(c0 != '"') { + c = c0; + if(c0 != '<') + goto bad; + c0 = '>'; + } + for(hp = str;;) { + c = getc(); + if(c == c0) + break; + if(c == '\n') + goto bad; + *hp++ = c; + } + *hp = 0; + + c = getcom(); + if(c != '\n') + goto bad; + + f = -1; + for(i=0; i<ninclude; i++) { + if(i == 0 && c0 == '>') + continue; + strcpy(symb, include[i]); + strcat(symb, "/"); + if(strcmp(symb, "./") == 0) + symb[0] = 0; + strcat(symb, str); + f = myopen(symb); + if(f >= 0) + break; + } + if(f < 0) + strcpy(symb, str); + c = strlen(symb) + 1; + hp = alloc(c); + memcpy(hp, symb, c); + newio(); + pushio(); + newfile(hp, f); + return; + +bad: + unget(c); + yyerror("syntax in #include"); + macend(); +} + +void +maclin(void) +{ + char *cp; + int c; + long n; + + n = getnsn(); + c = getc(); + if(n < 0) + goto bad; + + for(;;) { + if(c == ' ' || c == '\t') { + c = getc(); + continue; + } + if(c == '"') + break; + if(c == '\n') { + strcpy(symb, "<noname>"); + goto nn; + } + goto bad; + } + cp = symb; + for(;;) { + c = getc(); + if(c == '"') + break; + *cp++ = c; + } + *cp = 0; + c = getcom(); + if(c != '\n') + goto bad; + +nn: + c = strlen(symb) + 1; + cp = alloc(c); + memcpy(cp, symb, c); + linehist(cp, n); + return; + +bad: + unget(c); + yyerror("syntax in #line"); + macend(); +} + +void +macif(int f) +{ + int c, l, bol; + Sym *s; + + if(f == 2) + goto skip; + s = getsym(); + if(s == S) + goto bad; + if(getcom() != '\n') + goto bad; + if((s->macro != 0) ^ f) + return; + +skip: + bol = 1; + l = 0; + for(;;) { + c = getc(); + if(c != '#') { + if(!isspace(c)) + bol = 0; + if(c == '\n') + bol = 1; + continue; + } + if(!bol) + continue; + s = getsym(); + if(s == S) + continue; + if(strcmp(s->name, "endif") == 0) { + if(l) { + l--; + continue; + } + macend(); + return; + } + if(strcmp(s->name, "ifdef") == 0 || strcmp(s->name, "ifndef") == 0) { + l++; + continue; + } + if(l == 0 && f != 2 && strcmp(s->name, "else") == 0) { + macend(); + return; + } + } + +bad: + yyerror("syntax in #if(n)def"); + macend(); +} + +void +macprag(void) +{ + Sym *s; + int c0, c; + char *hp; + Hist *h; + + s = getsym(); + + if(s && strcmp(s->name, "lib") == 0) + goto praglib; + if(s && strcmp(s->name, "pack") == 0) { + pragpack(); + return; + } + if(s && strcmp(s->name, "fpround") == 0) { + pragfpround(); + return; + } + if(s && strcmp(s->name, "profile") == 0) { + pragprofile(); + return; + } + if(s && strcmp(s->name, "varargck") == 0) { + pragvararg(); + return; + } + if(s && strcmp(s->name, "incomplete") == 0) { + pragincomplete(); + return; + } + while(getnsc() != '\n') + ; + return; + +praglib: + c0 = getnsc(); + if(c0 != '"') { + c = c0; + if(c0 != '<') + goto bad; + c0 = '>'; + } + for(hp = symb;;) { + c = getc(); + if(c == c0) + break; + if(c == '\n') + goto bad; + *hp++ = c; + } + *hp = 0; + c = getcom(); + if(c != '\n') + goto bad; + + /* + * put pragma-line in as a funny history + */ + c = strlen(symb) + 1; + hp = alloc(c); + memcpy(hp, symb, c); + + h = alloc(sizeof(Hist)); + h->name = hp; + h->line = lineno; + h->offset = -1; + h->link = H; + if(ehist == H) { + hist = h; + ehist = h; + return; + } + ehist->link = h; + ehist = h; + return; + +bad: + unget(c); + yyerror("syntax in #pragma lib"); + macend(); +} + +void +macend(void) +{ + int c; + + for(;;) { + c = getnsc(); + if(c < 0 || c == '\n') + return; + } +} + +void +linehist(char *f, int offset) +{ + Hist *h; + + /* + * overwrite the last #line directive if + * no alloc has happened since the last one + */ + if(newflag == 0 && ehist != H && offset != 0 && ehist->offset != 0) + if(f && ehist->name && strcmp(f, ehist->name) == 0) { + ehist->line = lineno; + ehist->offset = offset; + return; + } + + if(debug['f']) + if(f) { + if(offset) + print("%4ld: %s (#line %d)\n", lineno, f, offset); + else + print("%4ld: %s\n", lineno, f); + } else + print("%4ld: <pop>\n", lineno); + newflag = 0; + + h = alloc(sizeof(Hist)); + h->name = f; + h->line = lineno; + h->offset = offset; + h->link = H; + if(ehist == H) { + hist = h; + ehist = h; + return; + } + ehist->link = h; + ehist = h; +} diff --git a/src/cmd/cc/omachcap.c b/src/cmd/cc/omachcap.c new file mode 100644 index 000000000..ec5aa86e9 --- /dev/null +++ b/src/cmd/cc/omachcap.c @@ -0,0 +1,38 @@ +// Inferno utils/cc/machcap.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/machcap.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "cc.h" + +/* default, like old cc */ +int +machcap(Node *n) +{ + return 0; +} diff --git a/src/cmd/cc/pgen.c b/src/cmd/cc/pgen.c new file mode 100644 index 000000000..ae0b1b40c --- /dev/null +++ b/src/cmd/cc/pgen.c @@ -0,0 +1,550 @@ +// Inferno utils/6c/sgen.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/sgen.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "gc.h" + +void +codgen(Node *n, Node *nn) +{ + Prog *sp; + Node *n1, nod, nod1; + + cursafe = 0; + curarg = 0; + maxargsafe = 0; + + /* + * isolate name + */ + for(n1 = nn;; n1 = n1->left) { + if(n1 == Z) { + diag(nn, "cant find function name"); + return; + } + if(n1->op == ONAME) + break; + } + nearln = nn->lineno; + gpseudo(ATEXT, n1->sym, nodconst(stkoff)); + sp = p; + + /* + * isolate first argument + */ + if(REGARG) { + if(typecmplx[thisfn->link->etype]) { + nod1 = *nodret->left; + nodreg(&nod, &nod1, REGARG); + gmove(&nod, &nod1); + } else + if(firstarg && typeword[firstargtype->etype]) { + nod1 = *nodret->left; + nod1.sym = firstarg; + nod1.type = firstargtype; + nod1.xoffset = align(0, firstargtype, Aarg1); + nod1.etype = firstargtype->etype; + nodreg(&nod, &nod1, REGARG); + gmove(&nod, &nod1); + } + } + + canreach = 1; + warnreach = 1; + gen(n); + if(canreach && thisfn->link->etype != TVOID) + warn(Z, "no return at end of function: %s", n1->sym->name); + noretval(3); + gbranch(ORETURN); + + if(!debug['N'] || debug['R'] || debug['P']) + regopt(sp); + + if(thechar=='6' || thechar=='7') /* [sic] */ + maxargsafe = xround(maxargsafe, 8); + sp->to.offset += maxargsafe; +} + +void +supgen(Node *n) +{ + int owarn; + long spc; + Prog *sp; + + if(n == Z) + return; + suppress++; + owarn = warnreach; + warnreach = 0; + spc = pc; + sp = lastp; + gen(n); + lastp = sp; + pc = spc; + sp->link = nil; + suppress--; + warnreach = owarn; +} + +void +gen(Node *n) +{ + Node *l, nod; + Prog *sp, *spc, *spb; + Case *cn; + long sbc, scc; + int snbreak, sncontin; + int f, o, oldreach; + +loop: + if(n == Z) + return; + nearln = n->lineno; + o = n->op; + if(debug['G']) + if(o != OLIST) + print("%L %O\n", nearln, o); + + if(!canreach) { + switch(o) { + case OLABEL: + case OCASE: + case OLIST: + case OBREAK: + case OFOR: + case OWHILE: + case ODWHILE: + /* all handled specially - see switch body below */ + break; + default: + if(warnreach) { + warn(n, "unreachable code %O", o); + warnreach = 0; + } + } + } + + switch(o) { + + default: + complex(n); + cgen(n, Z); + break; + + case OLIST: + gen(n->left); + + rloop: + n = n->right; + goto loop; + + case ORETURN: + canreach = 0; + warnreach = !suppress; + complex(n); + if(n->type == T) + break; + l = n->left; + if(l == Z) { + noretval(3); + gbranch(ORETURN); + break; + } + if(typecmplx[n->type->etype]) { + sugen(l, nodret, n->type->width); + noretval(3); + gbranch(ORETURN); + break; + } + regret(&nod, n); + cgen(l, &nod); + regfree(&nod); + if(typefd[n->type->etype]) + noretval(1); + else + noretval(2); + gbranch(ORETURN); + break; + + case OLABEL: + canreach = 1; + l = n->left; + if(l) { + l->pc = pc; + if(l->label) + patch(l->label, pc); + } + gbranch(OGOTO); /* prevent self reference in reg */ + patch(p, pc); + goto rloop; + + case OGOTO: + canreach = 0; + warnreach = !suppress; + n = n->left; + if(n == Z) + return; + if(n->complex == 0) { + diag(Z, "label undefined: %s", n->sym->name); + return; + } + if(suppress) + return; + gbranch(OGOTO); + if(n->pc) { + patch(p, n->pc); + return; + } + if(n->label) + patch(n->label, pc-1); + n->label = p; + return; + + case OCASE: + canreach = 1; + l = n->left; + if(cases == C) + diag(n, "case/default outside a switch"); + if(l == Z) { + cas(); + cases->val = 0; + cases->def = 1; + cases->label = pc; + cases->isv = 0; + goto rloop; + } + complex(l); + if(l->type == T) + goto rloop; + if(l->op == OCONST) + if(typeword[l->type->etype] && l->type->etype != TIND) { + cas(); + cases->val = l->vconst; + cases->def = 0; + cases->label = pc; + cases->isv = typev[l->type->etype]; + goto rloop; + } + diag(n, "case expression must be integer constant"); + goto rloop; + + case OSWITCH: + l = n->left; + complex(l); + if(l->type == T) + break; + if(!typeword[l->type->etype] || l->type->etype == TIND) { + diag(n, "switch expression must be integer"); + break; + } + + gbranch(OGOTO); /* entry */ + sp = p; + + cn = cases; + cases = C; + cas(); + + sbc = breakpc; + breakpc = pc; + snbreak = nbreak; + nbreak = 0; + gbranch(OGOTO); + spb = p; + + gen(n->right); /* body */ + if(canreach){ + gbranch(OGOTO); + patch(p, breakpc); + nbreak++; + } + + patch(sp, pc); + regalloc(&nod, l, Z); + /* always signed */ + if(typev[l->type->etype]) + nod.type = types[TVLONG]; + else + nod.type = types[TLONG]; + cgen(l, &nod); + doswit(&nod); + regfree(&nod); + patch(spb, pc); + + cases = cn; + breakpc = sbc; + canreach = nbreak!=0; + if(canreach == 0) + warnreach = !suppress; + nbreak = snbreak; + break; + + case OWHILE: + case ODWHILE: + l = n->left; + gbranch(OGOTO); /* entry */ + sp = p; + + scc = continpc; + continpc = pc; + gbranch(OGOTO); + spc = p; + + sbc = breakpc; + breakpc = pc; + snbreak = nbreak; + nbreak = 0; + gbranch(OGOTO); + spb = p; + + patch(spc, pc); + if(n->op == OWHILE) + patch(sp, pc); + bcomplex(l, Z); /* test */ + patch(p, breakpc); + if(l->op != OCONST || vconst(l) == 0) + nbreak++; + + if(n->op == ODWHILE) + patch(sp, pc); + gen(n->right); /* body */ + gbranch(OGOTO); + patch(p, continpc); + + patch(spb, pc); + continpc = scc; + breakpc = sbc; + canreach = nbreak!=0; + if(canreach == 0) + warnreach = !suppress; + nbreak = snbreak; + break; + + case OFOR: + l = n->left; + if(!canreach && l->right->left && warnreach) { + warn(n, "unreachable code FOR"); + warnreach = 0; + } + gen(l->right->left); /* init */ + gbranch(OGOTO); /* entry */ + sp = p; + + /* + * if there are no incoming labels in the + * body and the top's not reachable, warn + */ + if(!canreach && warnreach && deadheads(n)) { + warn(n, "unreachable code %O", o); + warnreach = 0; + } + + scc = continpc; + continpc = pc; + gbranch(OGOTO); + spc = p; + + sbc = breakpc; + breakpc = pc; + snbreak = nbreak; + nbreak = 0; + sncontin = ncontin; + ncontin = 0; + gbranch(OGOTO); + spb = p; + + patch(spc, pc); + gen(l->right->right); /* inc */ + patch(sp, pc); + if(l->left != Z) { /* test */ + bcomplex(l->left, Z); + patch(p, breakpc); + if(l->left->op != OCONST || vconst(l->left) == 0) + nbreak++; + } + canreach = 1; + gen(n->right); /* body */ + if(canreach){ + gbranch(OGOTO); + patch(p, continpc); + ncontin++; + } + if(!ncontin && l->right->right && warnreach) { + warn(l->right->right, "unreachable FOR inc"); + warnreach = 0; + } + + patch(spb, pc); + continpc = scc; + breakpc = sbc; + canreach = nbreak!=0; + if(canreach == 0) + warnreach = !suppress; + nbreak = snbreak; + ncontin = sncontin; + break; + + case OCONTINUE: + if(continpc < 0) { + diag(n, "continue not in a loop"); + break; + } + gbranch(OGOTO); + patch(p, continpc); + ncontin++; + canreach = 0; + warnreach = !suppress; + break; + + case OBREAK: + if(breakpc < 0) { + diag(n, "break not in a loop"); + break; + } + /* + * Don't complain about unreachable break statements. + * There are breaks hidden in yacc's output and some people + * write return; break; in their switch statements out of habit. + * However, don't confuse the analysis by inserting an + * unreachable reference to breakpc either. + */ + if(!canreach) + break; + gbranch(OGOTO); + patch(p, breakpc); + nbreak++; + canreach = 0; + warnreach = !suppress; + break; + + case OIF: + l = n->left; + if(bcomplex(l, n->right)) { + if(typefd[l->type->etype]) + f = !l->fconst; + else + f = !l->vconst; + if(debug['c']) + print("%L const if %s\n", nearln, f ? "false" : "true"); + if(f) { + canreach = 1; + supgen(n->right->left); + oldreach = canreach; + canreach = 1; + gen(n->right->right); + /* + * treat constant ifs as regular ifs for + * reachability warnings. + */ + if(!canreach && oldreach && debug['w'] < 2) + warnreach = 0; + } + else { + canreach = 1; + gen(n->right->left); + oldreach = canreach; + canreach = 1; + supgen(n->right->right); + /* + * treat constant ifs as regular ifs for + * reachability warnings. + */ + if(!oldreach && canreach && debug['w'] < 2) + warnreach = 0; + canreach = oldreach; + } + } + else { + sp = p; + canreach = 1; + if(n->right->left != Z) + gen(n->right->left); + oldreach = canreach; + canreach = 1; + if(n->right->right != Z) { + gbranch(OGOTO); + patch(sp, pc); + sp = p; + gen(n->right->right); + } + patch(sp, pc); + canreach = canreach || oldreach; + if(canreach == 0) + warnreach = !suppress; + } + break; + + case OSET: + case OUSED: + usedset(n->left, o); + break; + } +} + +void +usedset(Node *n, int o) +{ + if(n->op == OLIST) { + usedset(n->left, o); + usedset(n->right, o); + return; + } + complex(n); + switch(n->op) { + case OADDR: /* volatile */ + gins(ANOP, n, Z); + break; + case ONAME: + if(o == OSET) + gins(ANOP, Z, n); + else + gins(ANOP, n, Z); + break; + } +} + +int +bcomplex(Node *n, Node *c) +{ + + complex(n); + if(n->type != T) + if(tcompat(n, T, n->type, tnot)) + n->type = T; + if(n->type == T) { + gbranch(OGOTO); + return 0; + } + if(c != Z && n->op == OCONST && deadheads(c)) + return 1; + bool64(n); + boolgen(n, 1, Z); + return 0; +} diff --git a/src/cmd/cc/pickle.c b/src/cmd/cc/pickle.c new file mode 100644 index 000000000..3626e4ad7 --- /dev/null +++ b/src/cmd/cc/pickle.c @@ -0,0 +1,298 @@ +// Inferno utils/cc/pickle.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/pickle.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "cc.h" + +static char *kwd[] = +{ + "$adt", "$aggr", "$append", "$complex", "$defn", + "$delete", "$do", "$else", "$eval", "$head", "$if", + "$local", "$loop", "$return", "$tail", "$then", + "$union", "$whatis", "$while", +}; +static char picklestr[] = "\tbp = pickle(bp, ep, un, "; + +static char* +pmap(char *s) +{ + int i, bot, top, new; + + bot = 0; + top = bot + nelem(kwd) - 1; + while(bot <= top){ + new = bot + (top - bot)/2; + i = strcmp(kwd[new]+1, s); + if(i == 0) + return kwd[new]; + + if(i < 0) + bot = new + 1; + else + top = new - 1; + } + return s; +} + +Sym* +picklesue(Type *t) +{ + int h; + Sym *s; + + if(t != T) + for(h=0; h<nelem(hash); h++) + for(s = hash[h]; s != S; s = s->link) + if(s->suetag && s->suetag->link == t) + return s; + return 0; +} + +Sym* +picklefun(Type *t) +{ + int h; + Sym *s; + + for(h=0; h<nelem(hash); h++) + for(s = hash[h]; s != S; s = s->link) + if(s->type == t) + return s; + return 0; +} + +char picklechar[NTYPE]; +Init picklecinit[] = +{ + TCHAR, 'C', 0, + TUCHAR, 'b', 0, + TSHORT, 'd', 0, + TUSHORT, 'u', 0, + TLONG, 'D', 0, + TULONG, 'U', 0, + TVLONG, 'V', 0, + TUVLONG, 'W', 0, + TFLOAT, 'f', 0, + TDOUBLE, 'F', 0, + TARRAY, 'a', 0, + TIND, 'X', 0, + -1, 0, 0, +}; + +static void +pickleinit(void) +{ + Init *p; + + for(p=picklecinit; p->code >= 0; p++) + picklechar[p->code] = p->value; + + picklechar[TINT] = picklechar[TLONG]; + picklechar[TUINT] = picklechar[TULONG]; + if(types[TINT]->width != types[TLONG]->width) { + picklechar[TINT] = picklechar[TSHORT]; + picklechar[TUINT] = picklechar[TUSHORT]; + if(types[TINT]->width != types[TSHORT]->width) + warn(Z, "picklemember int not long or short"); + } + +} + +void +picklemember(Type *t, long off) +{ + Sym *s, *s1; + static int picklecharinit = 0; + + if(picklecharinit == 0) { + pickleinit(); + picklecharinit = 1; + } + s = t->sym; + switch(t->etype) { + default: + Bprint(&outbuf, " T%d\n", t->etype); + break; + + case TIND: + if(s == S) + Bprint(&outbuf, + "%s\"p\", (char*)addr+%ld+_i*%ld);\n", + picklestr, t->offset+off, t->width); + else + Bprint(&outbuf, + "%s\"p\", &addr->%s);\n", + picklestr, pmap(s->name)); + break; + + case TINT: + case TUINT: + case TCHAR: + case TUCHAR: + case TSHORT: + case TUSHORT: + case TLONG: + case TULONG: + case TVLONG: + case TUVLONG: + case TFLOAT: + case TDOUBLE: + if(s == S) + Bprint(&outbuf, "%s\"%c\", (char*)addr+%ld+_i*%ld);\n", + picklestr, picklechar[t->etype], t->offset+off, t->width); + else + Bprint(&outbuf, "%s\"%c\", &addr->%s);\n", + picklestr, picklechar[t->etype], pmap(s->name)); + break; + case TARRAY: + Bprint(&outbuf, "\tfor(_i = 0; _i < %ld; _i++) {\n\t", + t->width/t->link->width); + picklemember(t->link, t->offset+off); + Bprint(&outbuf, "\t}\n\t_i = 0;\n\tUSED(_i);\n"); + break; + + case TSTRUCT: + case TUNION: + s1 = picklesue(t->link); + if(s1 == S) + break; + if(s == S) { + Bprint(&outbuf, "\tbp = pickle_%s(bp, ep, un, (%s*)((char*)addr+%ld+_i*%ld));\n", + pmap(s1->name), pmap(s1->name), t->offset+off, t->width); + } else { + Bprint(&outbuf, "\tbp = pickle_%s(bp, ep, un, &addr->%s);\n", + pmap(s1->name), pmap(s->name)); + } + break; + } +} + +void +pickletype(Type *t) +{ + Sym *s; + Type *l; + Io *i; + int n; + char *an; + + if(!debug['P']) + return; + if(debug['P'] > 1) { + n = 0; + for(i=iostack; i; i=i->link) + n++; + if(n > 1) + return; + } + s = picklesue(t->link); + if(s == S) + return; + switch(t->etype) { + default: + Bprint(&outbuf, "T%d\n", t->etype); + return; + + case TUNION: + case TSTRUCT: + if(debug['s']) + goto asmstr; + an = pmap(s->name); + + Bprint(&outbuf, "char *\npickle_%s(char *bp, char *ep, int un, %s *addr)\n{\n\tint _i = 0;\n\n\tUSED(_i);\n", an, an); + for(l = t->link; l != T; l = l->down) + picklemember(l, 0); + Bprint(&outbuf, "\treturn bp;\n}\n\n"); + break; + asmstr: + if(s == S) + break; + for(l = t->link; l != T; l = l->down) + if(l->sym != S) + Bprint(&outbuf, "#define\t%s.%s\t%ld\n", + s->name, + l->sym->name, + l->offset); + break; + } +} + +void +picklevar(Sym *s) +{ + int n; + Io *i; + Type *t; + Sym *s1, *s2; + + if(!debug['P'] || debug['s']) + return; + if(debug['P'] > 1) { + n = 0; + for(i=iostack; i; i=i->link) + n++; + if(n > 1) + return; + } + t = s->type; + while(t && t->etype == TIND) + t = t->link; + if(t == T) + return; + if(t->etype == TENUM) { + Bprint(&outbuf, "%s = ", pmap(s->name)); + if(!typefd[t->etype]) + Bprint(&outbuf, "%lld;\n", s->vconst); + else + Bprint(&outbuf, "%f\n;", s->fconst); + return; + } + if(!typesu[t->etype]) + return; + s1 = picklesue(t->link); + if(s1 == S) + return; + switch(s->class) { + case CAUTO: + case CPARAM: + s2 = picklefun(thisfn); + if(s2) + Bprint(&outbuf, "complex %s %s:%s;\n", + pmap(s1->name), pmap(s2->name), pmap(s->name)); + break; + + case CSTATIC: + case CEXTERN: + case CGLOBL: + case CLOCAL: + Bprint(&outbuf, "complex %s %s;\n", + pmap(s1->name), pmap(s->name)); + break; + } +} diff --git a/src/cmd/cc/pswt.c b/src/cmd/cc/pswt.c new file mode 100644 index 000000000..f4149f17b --- /dev/null +++ b/src/cmd/cc/pswt.c @@ -0,0 +1,168 @@ +// Inferno utils/6c/swt.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "gc.h" + +int +swcmp(const void *a1, const void *a2) +{ + C1 *p1, *p2; + + p1 = (C1*)a1; + p2 = (C1*)a2; + if(p1->val < p2->val) + return -1; + return p1->val > p2->val; +} + +void +doswit(Node *n) +{ + Case *c; + C1 *q, *iq; + long def, nc, i, isv; + + def = 0; + nc = 0; + isv = 0; + for(c = cases; c->link != C; c = c->link) { + if(c->def) { + if(def) + diag(n, "more than one default in switch"); + def = c->label; + continue; + } + isv |= c->isv; + nc++; + } + if(isv && !typev[n->type->etype]) + warn(n, "32-bit switch expression with 64-bit case constant"); + + iq = alloc(nc*sizeof(C1)); + q = iq; + for(c = cases; c->link != C; c = c->link) { + if(c->def) + continue; + q->label = c->label; + if(isv) + q->val = c->val; + else + q->val = (long)c->val; /* cast ensures correct value for 32-bit switch on 64-bit architecture */ + q++; + } + qsort(iq, nc, sizeof(C1), swcmp); + if(debug['W']) + for(i=0; i<nc; i++) + print("case %2ld: = %.8llux\n", i, (vlong)iq[i].val); + for(i=0; i<nc-1; i++) + if(iq[i].val == iq[i+1].val) + diag(n, "duplicate cases in switch %lld", (vlong)iq[i].val); + if(def == 0) { + def = breakpc; + nbreak++; + } + swit1(iq, nc, def, n); +} + +void +cas(void) +{ + Case *c; + + c = alloc(sizeof(*c)); + c->link = cases; + cases = c; +} + +long +outlstring(ushort *s, long n) +{ + char buf[2]; + int c; + long r; + + if(suppress) + return nstring; + while(nstring & 1) + outstring("", 1); + r = nstring; + while(n > 0) { + c = *s++; + if(align(0, types[TCHAR], Aarg1)) { + buf[0] = c>>8; + buf[1] = c; + } else { + buf[0] = c; + buf[1] = c>>8; + } + outstring(buf, 2); + n -= sizeof(ushort); + } + return r; +} + +void +nullwarn(Node *l, Node *r) +{ + warn(Z, "result of operation not used"); + if(l != Z) + cgen(l, Z); + if(r != Z) + cgen(r, Z); +} + +void +ieeedtod(Ieee *ieee, double native) +{ + double fr, ho, f; + int exp; + + if(native < 0) { + ieeedtod(ieee, -native); + ieee->h |= 0x80000000L; + return; + } + if(native == 0) { + ieee->l = 0; + ieee->h = 0; + return; + } + fr = frexp(native, &exp); + f = 2097152L; /* shouldnt use fp constants here */ + fr = modf(fr*f, &ho); + ieee->h = ho; + ieee->h &= 0xfffffL; + ieee->h |= (exp+1022L) << 20; + f = 65536L; + fr = modf(fr*f, &ho); + ieee->l = ho; + ieee->l <<= 16; + ieee->l |= (long)(fr*f); +} diff --git a/src/cmd/cc/scon.c b/src/cmd/cc/scon.c new file mode 100644 index 000000000..3047ca44f --- /dev/null +++ b/src/cmd/cc/scon.c @@ -0,0 +1,636 @@ +// Inferno utils/cc/scon.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/scon.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "cc.h" + +static Node* +acast(Type *t, Node *n) +{ + if(n->type->etype != t->etype || n->op == OBIT) { + n = new1(OCAST, n, Z); + if(nocast(n->left->type, t)) + *n = *n->left; + n->type = t; + } + return n; +} + + +void +evconst(Node *n) +{ + Node *l, *r; + int et, isf; + vlong v; + double d; + + if(n == Z || n->type == T) + return; + + et = n->type->etype; + isf = typefd[et]; + + l = n->left; + r = n->right; + + d = 0; + v = 0; + + switch(n->op) { + default: + return; + + case ONEG: + if(isf) + d = -l->fconst; + else + v = -l->vconst; + break; + + case OCOM: + v = ~l->vconst; + break; + + case OCAST: + if(et == TVOID) + return; + et = l->type->etype; + if(isf) { + if(typefd[et]) + d = l->fconst; + else + d = l->vconst; + } else { + if(typefd[et]) + v = l->fconst; + else + v = convvtox(l->vconst, n->type->etype); + } + break; + + case OCONST: + break; + + case OADD: + if(isf) + d = l->fconst + r->fconst; + else { + v = l->vconst + r->vconst; + } + break; + + case OSUB: + if(isf) + d = l->fconst - r->fconst; + else + v = l->vconst - r->vconst; + break; + + case OMUL: + if(isf) + d = l->fconst * r->fconst; + else { + v = l->vconst * r->vconst; + } + break; + + case OLMUL: + v = (uvlong)l->vconst * (uvlong)r->vconst; + break; + + + case ODIV: + if(vconst(r) == 0) { + warn(n, "divide by zero"); + return; + } + if(isf) + d = l->fconst / r->fconst; + else + v = l->vconst / r->vconst; + break; + + case OLDIV: + if(vconst(r) == 0) { + warn(n, "divide by zero"); + return; + } + v = (uvlong)l->vconst / (uvlong)r->vconst; + break; + + case OMOD: + if(vconst(r) == 0) { + warn(n, "modulo by zero"); + return; + } + v = l->vconst % r->vconst; + break; + + case OLMOD: + if(vconst(r) == 0) { + warn(n, "modulo by zero"); + return; + } + v = (uvlong)l->vconst % (uvlong)r->vconst; + break; + + case OAND: + v = l->vconst & r->vconst; + break; + + case OOR: + v = l->vconst | r->vconst; + break; + + case OXOR: + v = l->vconst ^ r->vconst; + break; + + case OLSHR: + v = (uvlong)l->vconst >> r->vconst; + break; + + case OASHR: + v = l->vconst >> r->vconst; + break; + + case OASHL: + v = l->vconst << r->vconst; + break; + + case OLO: + v = (uvlong)l->vconst < (uvlong)r->vconst; + break; + + case OLT: + if(typefd[l->type->etype]) + v = l->fconst < r->fconst; + else + v = l->vconst < r->vconst; + break; + + case OHI: + v = (uvlong)l->vconst > (uvlong)r->vconst; + break; + + case OGT: + if(typefd[l->type->etype]) + v = l->fconst > r->fconst; + else + v = l->vconst > r->vconst; + break; + + case OLS: + v = (uvlong)l->vconst <= (uvlong)r->vconst; + break; + + case OLE: + if(typefd[l->type->etype]) + v = l->fconst <= r->fconst; + else + v = l->vconst <= r->vconst; + break; + + case OHS: + v = (uvlong)l->vconst >= (uvlong)r->vconst; + break; + + case OGE: + if(typefd[l->type->etype]) + v = l->fconst >= r->fconst; + else + v = l->vconst >= r->vconst; + break; + + case OEQ: + if(typefd[l->type->etype]) + v = l->fconst == r->fconst; + else + v = l->vconst == r->vconst; + break; + + case ONE: + if(typefd[l->type->etype]) + v = l->fconst != r->fconst; + else + v = l->vconst != r->vconst; + break; + + case ONOT: + if(typefd[l->type->etype]) + v = !l->fconst; + else + v = !l->vconst; + break; + + case OANDAND: + if(typefd[l->type->etype]) + v = l->fconst && r->fconst; + else + v = l->vconst && r->vconst; + break; + + case OOROR: + if(typefd[l->type->etype]) + v = l->fconst || r->fconst; + else + v = l->vconst || r->vconst; + break; + } + if(isf) { + n->fconst = d; + } else { + n->vconst = convvtox(v, n->type->etype); + } + n->oldop = n->op; + n->op = OCONST; +} + +void +acom(Node *n) +{ + Type *t; + Node *l, *r; + int i; + + switch(n->op) + { + + case ONAME: + case OCONST: + case OSTRING: + case OINDREG: + case OREGISTER: + return; + + case ONEG: + l = n->left; + if(addo(n) && addo(l)) + break; + acom(l); + return; + + case OADD: + case OSUB: + case OMUL: + l = n->left; + r = n->right; + if(addo(n)) { + if(addo(r)) + break; + if(addo(l)) + break; + } + acom(l); + acom(r); + return; + + default: + l = n->left; + r = n->right; + if(l != Z) + acom(l); + if(r != Z) + acom(r); + return; + } + + /* bust terms out */ + t = n->type; + term[0].mult = 0; + term[0].node = Z; + nterm = 1; + acom1(1, n); + if(debug['m']) + for(i=0; i<nterm; i++) { + print("%d %3lld ", i, term[i].mult); + prtree1(term[i].node, 1, 0); + } + if(nterm < NTERM) + acom2(n, t); + n->type = t; +} + +int +acomcmp1(const void *a1, const void *a2) +{ + vlong c1, c2; + Term *t1, *t2; + + t1 = (Term*)a1; + t2 = (Term*)a2; + c1 = t1->mult; + if(c1 < 0) + c1 = -c1; + c2 = t2->mult; + if(c2 < 0) + c2 = -c2; + if(c1 > c2) + return 1; + if(c1 < c2) + return -1; + c1 = 1; + if(t1->mult < 0) + c1 = 0; + c2 = 1; + if(t2->mult < 0) + c2 = 0; + if(c2 -= c1) + return c2; + if(t2 > t1) + return 1; + return -1; +} + +int +acomcmp2(const void *a1, const void *a2) +{ + vlong c1, c2; + Term *t1, *t2; + + t1 = (Term*)a1; + t2 = (Term*)a2; + c1 = t1->mult; + c2 = t2->mult; + if(c1 > c2) + return 1; + if(c1 < c2) + return -1; + if(t2 > t1) + return 1; + return -1; +} + +void +acom2(Node *n, Type *t) +{ + Node *l, *r; + Term trm[NTERM]; + int et, nt, i, j; + vlong c1, c2; + + /* + * copy into automatic + */ + c2 = 0; + nt = nterm; + for(i=0; i<nt; i++) + trm[i] = term[i]; + /* + * recur on subtrees + */ + j = 0; + for(i=1; i<nt; i++) { + c1 = trm[i].mult; + if(c1 == 0) + continue; + l = trm[i].node; + if(l != Z) { + j = 1; + acom(l); + } + } + c1 = trm[0].mult; + if(j == 0) { + n->oldop = n->op; + n->op = OCONST; + n->vconst = c1; + return; + } + et = t->etype; + + /* + * prepare constant term, + * combine it with an addressing term + */ + if(c1 != 0) { + l = new1(OCONST, Z, Z); + l->type = t; + l->vconst = c1; + trm[0].mult = 1; + for(i=1; i<nt; i++) { + if(trm[i].mult != 1) + continue; + r = trm[i].node; + if(r->op != OADDR) + continue; + r->type = t; + l = new1(OADD, r, l); + l->type = t; + trm[i].mult = 0; + break; + } + trm[0].node = l; + } + /* + * look for factorable terms + * c1*i + c1*c2*j -> c1*(i + c2*j) + */ + qsort(trm+1, nt-1, sizeof(trm[0]), acomcmp1); + for(i=nt-1; i>=0; i--) { + c1 = trm[i].mult; + if(c1 < 0) + c1 = -c1; + if(c1 <= 1) + continue; + for(j=i+1; j<nt; j++) { + c2 = trm[j].mult; + if(c2 < 0) + c2 = -c2; + if(c2 <= 1) + continue; + if(c2 % c1) + continue; + r = trm[j].node; + if(r->type->etype != et) + r = acast(t, r); + c2 = trm[j].mult/trm[i].mult; + if(c2 != 1 && c2 != -1) { + r = new1(OMUL, r, new(OCONST, Z, Z)); + r->type = t; + r->right->type = t; + r->right->vconst = c2; + } + l = trm[i].node; + if(l->type->etype != et) + l = acast(t, l); + r = new1(OADD, l, r); + r->type = t; + if(c2 == -1) + r->op = OSUB; + trm[i].node = r; + trm[j].mult = 0; + } + } + if(debug['m']) { + print("\n"); + for(i=0; i<nt; i++) { + print("%d %3lld ", i, trm[i].mult); + prtree1(trm[i].node, 1, 0); + } + } + + /* + * put it all back together + */ + qsort(trm+1, nt-1, sizeof(trm[0]), acomcmp2); + l = Z; + for(i=nt-1; i>=0; i--) { + c1 = trm[i].mult; + if(c1 == 0) + continue; + r = trm[i].node; + if(r->type->etype != et || r->op == OBIT) + r = acast(t, r); + if(c1 != 1 && c1 != -1) { + r = new1(OMUL, r, new(OCONST, Z, Z)); + r->type = t; + r->right->type = t; + if(c1 < 0) { + r->right->vconst = -c1; + c1 = -1; + } else { + r->right->vconst = c1; + c1 = 1; + } + } + if(l == Z) { + l = r; + c2 = c1; + continue; + } + if(c1 < 0) + if(c2 < 0) + l = new1(OADD, l, r); + else + l = new1(OSUB, l, r); + else + if(c2 < 0) { + l = new1(OSUB, r, l); + c2 = 1; + } else + l = new1(OADD, l, r); + l->type = t; + } + if(c2 < 0) { + r = new1(OCONST, 0, 0); + r->vconst = 0; + r->type = t; + l = new1(OSUB, r, l); + l->type = t; + } + *n = *l; +} + +void +acom1(vlong v, Node *n) +{ + Node *l, *r; + + if(v == 0 || nterm >= NTERM) + return; + if(!addo(n)) { + if(n->op == OCONST) + if(!typefd[n->type->etype]) { + term[0].mult += v*n->vconst; + return; + } + term[nterm].mult = v; + term[nterm].node = n; + nterm++; + return; + } + switch(n->op) { + + case OCAST: + acom1(v, n->left); + break; + + case ONEG: + acom1(-v, n->left); + break; + + case OADD: + acom1(v, n->left); + acom1(v, n->right); + break; + + case OSUB: + acom1(v, n->left); + acom1(-v, n->right); + break; + + case OMUL: + l = n->left; + r = n->right; + if(l->op == OCONST) + if(!typefd[n->type->etype]) { + acom1(v*l->vconst, r); + break; + } + if(r->op == OCONST) + if(!typefd[n->type->etype]) { + acom1(v*r->vconst, l); + break; + } + break; + + default: + diag(n, "not addo"); + } +} + +int +addo(Node *n) +{ + + if(n != Z) + if(!typefd[n->type->etype]) + if(!typev[n->type->etype] || ewidth[TVLONG] == ewidth[TIND]) + switch(n->op) { + + case OCAST: + if(nilcast(n->left->type, n->type)) + return 1; + break; + + case ONEG: + case OADD: + case OSUB: + return 1; + + case OMUL: + if(n->left->op == OCONST) + return 1; + if(n->right->op == OCONST) + return 1; + } + return 0; +} diff --git a/src/cmd/cc/sub.c b/src/cmd/cc/sub.c new file mode 100644 index 000000000..fcf915cb8 --- /dev/null +++ b/src/cmd/cc/sub.c @@ -0,0 +1,2054 @@ +// Inferno utils/cc/sub.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/sub.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "cc.h" + +Node* +new(int t, Node *l, Node *r) +{ + Node *n; + + n = alloc(sizeof(*n)); + n->op = t; + n->left = l; + n->right = r; + if(l && t != OGOTO) + n->lineno = l->lineno; + else if(r) + n->lineno = r->lineno; + else + n->lineno = lineno; + newflag = 1; + return n; +} + +Node* +new1(int o, Node *l, Node *r) +{ + Node *n; + + n = new(o, l, r); + n->lineno = nearln; + return n; +} + +void +prtree(Node *n, char *s) +{ + + print(" == %s ==\n", s); + prtree1(n, 0, 0); + print("\n"); +} + +void +prtree1(Node *n, int d, int f) +{ + int i; + + if(f) + for(i=0; i<d; i++) + print(" "); + if(n == Z) { + print("Z\n"); + return; + } + if(n->op == OLIST) { + prtree1(n->left, d, 0); + prtree1(n->right, d, 1); + return; + } + d++; + print("%O", n->op); + i = 3; + switch(n->op) + { + case ONAME: + print(" \"%F\"", n); + print(" %ld", n->xoffset); + i = 0; + break; + + case OINDREG: + print(" %ld(R%d)", n->xoffset, n->reg); + i = 0; + break; + + case OREGISTER: + if(n->xoffset) + print(" %ld+R%d", n->xoffset, n->reg); + else + print(" R%d", n->reg); + i = 0; + break; + + case OSTRING: + print(" \"%s\"", n->cstring); + i = 0; + break; + + case OLSTRING: + print(" \"%S\"", n->rstring); + i = 0; + break; + + case ODOT: + case OELEM: + print(" \"%F\"", n); + break; + + case OCONST: + if(typefd[n->type->etype]) + print(" \"%.8e\"", n->fconst); + else + print(" \"%lld\"", n->vconst); + i = 0; + break; + } + if(n->addable != 0) + print(" <%d>", n->addable); + if(n->type != T) + print(" %T", n->type); + if(n->complex != 0) + print(" (%d)", n->complex); + print(" %L\n", n->lineno); + if(i & 2) + prtree1(n->left, d, 1); + if(i & 1) + prtree1(n->right, d, 1); +} + +Type* +typ(int et, Type *d) +{ + Type *t; + + t = alloc(sizeof(*t)); + t->etype = et; + t->link = d; + t->down = T; + t->sym = S; + t->width = ewidth[et]; + t->offset = 0; + t->shift = 0; + t->nbits = 0; + t->garb = 0; + return t; +} + +Type* +copytyp(Type *t) +{ + Type *nt; + + nt = typ(TXXX, T); + *nt = *t; + return nt; +} + +Type* +garbt(Type *t, long b) +{ + Type *t1; + + if(b & BGARB) { + t1 = copytyp(t); + t1->garb = simpleg(b); + return t1; + } + return t; +} + +int +simpleg(long b) +{ + + b &= BGARB; + switch(b) { + case BCONSTNT: + return GCONSTNT; + case BVOLATILE: + return GVOLATILE; + case BVOLATILE|BCONSTNT: + return GCONSTNT|GVOLATILE; + } + return GXXX; +} + +int +simplec(long b) +{ + + b &= BCLASS; + switch(b) { + case 0: + case BREGISTER: + return CXXX; + case BAUTO: + case BAUTO|BREGISTER: + return CAUTO; + case BEXTERN: + return CEXTERN; + case BEXTERN|BREGISTER: + return CEXREG; + case BSTATIC: + return CSTATIC; + case BTYPEDEF: + return CTYPEDEF; + case BTYPESTR: + return CTYPESTR; + } + diag(Z, "illegal combination of classes %Q", b); + return CXXX; +} + +Type* +simplet(long b) +{ + + b &= ~BCLASS & ~BGARB; + switch(b) { + case BCHAR: + case BCHAR|BSIGNED: + return types[TCHAR]; + + case BCHAR|BUNSIGNED: + return types[TUCHAR]; + + case BSHORT: + case BSHORT|BINT: + case BSHORT|BSIGNED: + case BSHORT|BINT|BSIGNED: + return types[TSHORT]; + + case BUNSIGNED|BSHORT: + case BUNSIGNED|BSHORT|BINT: + return types[TUSHORT]; + + case 0: + case BINT: + case BINT|BSIGNED: + case BSIGNED: + return types[TINT]; + + case BUNSIGNED: + case BUNSIGNED|BINT: + return types[TUINT]; + + case BLONG: + case BLONG|BINT: + case BLONG|BSIGNED: + case BLONG|BINT|BSIGNED: + return types[TLONG]; + + case BUNSIGNED|BLONG: + case BUNSIGNED|BLONG|BINT: + return types[TULONG]; + + case BVLONG|BLONG: + case BVLONG|BLONG|BINT: + case BVLONG|BLONG|BSIGNED: + case BVLONG|BLONG|BINT|BSIGNED: + return types[TVLONG]; + + case BVLONG|BLONG|BUNSIGNED: + case BVLONG|BLONG|BINT|BUNSIGNED: + return types[TUVLONG]; + + case BFLOAT: + return types[TFLOAT]; + + case BDOUBLE: + case BDOUBLE|BLONG: + case BFLOAT|BLONG: + return types[TDOUBLE]; + + case BVOID: + return types[TVOID]; + } + + diag(Z, "illegal combination of types %Q", b); + return types[TINT]; +} + +int +stcompat(Node *n, Type *t1, Type *t2, long ttab[]) +{ + int i; + ulong b; + + i = 0; + if(t2 != T) + i = t2->etype; + b = 1L << i; + i = 0; + if(t1 != T) + i = t1->etype; + if(b & ttab[i]) { + if(ttab == tasign) + if(b == BSTRUCT || b == BUNION) + if(!sametype(t1, t2)) + return 1; + if(n->op != OCAST) + if(b == BIND && i == TIND) + if(!sametype(t1, t2)) + return 1; + return 0; + } + return 1; +} + +int +tcompat(Node *n, Type *t1, Type *t2, long ttab[]) +{ + + if(stcompat(n, t1, t2, ttab)) { + if(t1 == T) + diag(n, "incompatible type: \"%T\" for op \"%O\"", + t2, n->op); + else + diag(n, "incompatible types: \"%T\" and \"%T\" for op \"%O\"", + t1, t2, n->op); + return 1; + } + return 0; +} + +void +makedot(Node *n, Type *t, long o) +{ + Node *n1, *n2; + + if(t->nbits) { + n1 = new(OXXX, Z, Z); + *n1 = *n; + n->op = OBIT; + n->left = n1; + n->right = Z; + n->type = t; + n->addable = n1->left->addable; + n = n1; + } + n->addable = n->left->addable; + if(n->addable == 0) { + n1 = new1(OCONST, Z, Z); + n1->vconst = o; + n1->type = types[TLONG]; + n->right = n1; + n->type = t; + return; + } + n->left->type = t; + if(o == 0) { + *n = *n->left; + return; + } + n->type = t; + n1 = new1(OCONST, Z, Z); + n1->vconst = o; + t = typ(TIND, t); + t->width = types[TIND]->width; + n1->type = t; + + n2 = new1(OADDR, n->left, Z); + n2->type = t; + + n1 = new1(OADD, n1, n2); + n1->type = t; + + n->op = OIND; + n->left = n1; + n->right = Z; +} + +Type* +dotsearch(Sym *s, Type *t, Node *n, long *off) +{ + Type *t1, *xt, *rt; + + xt = T; + + /* + * look it up by name + */ + for(t1 = t; t1 != T; t1 = t1->down) + if(t1->sym == s) { + if(xt != T) + goto ambig; + xt = t1; + } + + /* + * look it up by type + */ + if(s->class == CTYPEDEF || s->class == CTYPESTR) + for(t1 = t; t1 != T; t1 = t1->down) + if(t1->sym == S && typesu[t1->etype]) + if(sametype(s->type, t1)) { + if(xt != T) + goto ambig; + xt = t1; + } + if(xt != T) { + *off = xt->offset; + return xt; + } + + /* + * look it up in unnamed substructures + */ + for(t1 = t; t1 != T; t1 = t1->down) + if(t1->sym == S && typesu[t1->etype]){ + rt = dotsearch(s, t1->link, n, off); + if(rt != T) { + if(xt != T) + goto ambig; + xt = rt; + *off += t1->offset; + } + } + return xt; + +ambig: + diag(n, "ambiguous structure element: %s", s->name); + return xt; +} + +long +dotoffset(Type *st, Type *lt, Node *n) +{ + Type *t; + Sym *g; + long o, o1; + + o = -1; + /* + * first try matching at the top level + * for matching tag names + */ + g = st->tag; + if(g != S) + for(t=lt->link; t!=T; t=t->down) + if(t->sym == S) + if(g == t->tag) { + if(o >= 0) + goto ambig; + o = t->offset; + } + if(o >= 0) + return o; + + /* + * second try matching at the top level + * for similar types + */ + for(t=lt->link; t!=T; t=t->down) + if(t->sym == S) + if(sametype(st, t)) { + if(o >= 0) + goto ambig; + o = t->offset; + } + if(o >= 0) + return o; + + /* + * last try matching sub-levels + */ + for(t=lt->link; t!=T; t=t->down) + if(t->sym == S) + if(typesu[t->etype]) { + o1 = dotoffset(st, t, n); + if(o1 >= 0) { + if(o >= 0) + goto ambig; + o = o1 + t->offset; + } + } + return o; + +ambig: + diag(n, "ambiguous unnamed structure element"); + return o; +} + +/* + * look into tree for floating point constant expressions + */ +int +allfloat(Node *n, int flag) +{ + + if(n != Z) { + if(n->type->etype != TDOUBLE) + return 1; + switch(n->op) { + case OCONST: + if(flag) + n->type = types[TFLOAT]; + return 1; + case OADD: /* no need to get more exotic than this */ + case OSUB: + case OMUL: + case ODIV: + if(!allfloat(n->right, flag)) + break; + case OCAST: + if(!allfloat(n->left, flag)) + break; + if(flag) + n->type = types[TFLOAT]; + return 1; + } + } + return 0; +} + +void +constas(Node *n, Type *il, Type *ir) +{ + Type *l, *r; + + l = il; + r = ir; + + if(l == T) + return; + if(l->garb & GCONSTNT) { + warn(n, "assignment to a constant type (%T)", il); + return; + } + if(r == T) + return; + for(;;) { + if(l->etype != TIND || r->etype != TIND) + break; + l = l->link; + r = r->link; + if(l == T || r == T) + break; + if(r->garb & GCONSTNT) + if(!(l->garb & GCONSTNT)) { + warn(n, "assignment of a constant pointer type (%T)", ir); + break; + } + } +} + +void +typeext1(Type *st, Node *l) +{ + if(st->etype == TFLOAT && allfloat(l, 0)) + allfloat(l, 1); +} + +void +typeext(Type *st, Node *l) +{ + Type *lt; + Node *n1, *n2; + long o; + + lt = l->type; + if(lt == T) + return; + if(st->etype == TIND && vconst(l) == 0) { + l->type = st; + l->vconst = 0; + return; + } + typeext1(st, l); + + /* + * extension of C + * if assign of struct containing unnamed sub-struct + * to type of sub-struct, insert the DOT. + * if assign of *struct containing unnamed substruct + * to type of *sub-struct, insert the add-offset + */ + if(typesu[st->etype] && typesu[lt->etype]) { + o = dotoffset(st, lt, l); + if(o >= 0) { + n1 = new1(OXXX, Z, Z); + *n1 = *l; + l->op = ODOT; + l->left = n1; + l->right = Z; + makedot(l, st, o); + } + return; + } + if(st->etype == TIND && typesu[st->link->etype]) + if(lt->etype == TIND && typesu[lt->link->etype]) { + o = dotoffset(st->link, lt->link, l); + if(o >= 0) { + l->type = st; + if(o == 0) + return; + n1 = new1(OXXX, Z, Z); + *n1 = *l; + n2 = new1(OCONST, Z, Z); + n2->vconst = o; + n2->type = st; + l->op = OADD; + l->left = n1; + l->right = n2; + } + return; + } +} + +/* + * a cast that generates no code + * (same size move) + */ +int +nocast(Type *t1, Type *t2) +{ + int i, b; + + if(t1->nbits) + return 0; + i = 0; + if(t2 != T) + i = t2->etype; + b = 1<<i; + i = 0; + if(t1 != T) + i = t1->etype; + if(b & ncast[i]) + return 1; + return 0; +} + +/* + * a cast that has a noop semantic + * (small to large, convert) + */ +int +nilcast(Type *t1, Type *t2) +{ + int et1, et2; + + if(t1 == T) + return 0; + if(t1->nbits) + return 0; + if(t2 == T) + return 0; + et1 = t1->etype; + et2 = t2->etype; + if(et1 == et2) + return 1; + if(typefd[et1] && typefd[et2]) { + if(ewidth[et1] < ewidth[et2]) + return 1; + return 0; + } + if(typechlp[et1] && typechlp[et2]) { + if(ewidth[et1] < ewidth[et2]) + return 1; + return 0; + } + return 0; +} + +/* + * "the usual arithmetic conversions are performed" + */ +void +arith(Node *n, int f) +{ + Type *t1, *t2; + int i, j, k; + Node *n1; + long w; + + t1 = n->left->type; + if(n->right == Z) + t2 = t1; + else + t2 = n->right->type; + i = TXXX; + if(t1 != T) + i = t1->etype; + j = TXXX; + if(t2 != T) + j = t2->etype; + k = tab[i][j]; + if(k == TIND) { + if(i == TIND) + n->type = t1; + else + if(j == TIND) + n->type = t2; + } else { + /* convert up to at least int */ + if(f == 1) + while(k < TINT) + k += 2; + n->type = types[k]; + } + if(n->op == OSUB) + if(i == TIND && j == TIND) { + w = n->right->type->link->width; + if(w < 1 || n->left->type->link == T || n->left->type->link->width < 1) + goto bad; + n->type = types[ewidth[TIND] <= ewidth[TLONG]? TLONG: TVLONG]; + if(1 && ewidth[TIND] > ewidth[TLONG]){ + n1 = new1(OXXX, Z, Z); + *n1 = *n; + n->op = OCAST; + n->left = n1; + n->right = Z; + n->type = types[TLONG]; + } + if(w > 1) { + n1 = new1(OXXX, Z, Z); + *n1 = *n; + n->op = ODIV; + n->left = n1; + n1 = new1(OCONST, Z, Z); + n1->vconst = w; + n1->type = n->type; + n->right = n1; + w = vlog(n1); + if(w >= 0) { + n->op = OASHR; + n1->vconst = w; + } + } + return; + } + if(!sametype(n->type, n->left->type)) { + n->left = new1(OCAST, n->left, Z); + n->left->type = n->type; + if(n->type->etype == TIND) { + w = n->type->link->width; + if(w < 1) { + snap(n->type->link); + w = n->type->link->width; + if(w < 1) + goto bad; + } + if(w > 1) { + n1 = new1(OCONST, Z, Z); + n1->vconst = w; + n1->type = n->type; + n->left = new1(OMUL, n->left, n1); + n->left->type = n->type; + } + } + } + if(n->right != Z) + if(!sametype(n->type, n->right->type)) { + n->right = new1(OCAST, n->right, Z); + n->right->type = n->type; + if(n->type->etype == TIND) { + w = n->type->link->width; + if(w < 1) { + snap(n->type->link); + w = n->type->link->width; + if(w < 1) + goto bad; + } + if(w != 1) { + n1 = new1(OCONST, Z, Z); + n1->vconst = w; + n1->type = n->type; + n->right = new1(OMUL, n->right, n1); + n->right->type = n->type; + } + } + } + return; +bad: + diag(n, "pointer addition not fully declared: %T", n->type->link); +} + +/* + * try to rewrite shift & mask + */ +void +simplifyshift(Node *n) +{ + ulong c3; + int o, s1, s2, c1, c2; + + if(!typechlp[n->type->etype]) + return; + switch(n->op) { + default: + return; + case OASHL: + s1 = 0; + break; + case OLSHR: + s1 = 1; + break; + case OASHR: + s1 = 2; + break; + } + if(n->right->op != OCONST) + return; + if(n->left->op != OAND) + return; + if(n->left->right->op != OCONST) + return; + switch(n->left->left->op) { + default: + return; + case OASHL: + s2 = 0; + break; + case OLSHR: + s2 = 1; + break; + case OASHR: + s2 = 2; + break; + } + if(n->left->left->right->op != OCONST) + return; + + c1 = n->right->vconst; + c2 = n->left->left->right->vconst; + c3 = n->left->right->vconst; + +/* + if(debug['h']) + print("%.3o %ld %ld %d #%.lux\n", + (s1<<3)|s2, c1, c2, topbit(c3), c3); +*/ + + o = n->op; + switch((s1<<3)|s2) { + case 000: /* (((e <<u c2) & c3) <<u c1) */ + c3 >>= c2; + c1 += c2; + if(c1 >= 32) + break; + goto rewrite1; + + case 002: /* (((e >>s c2) & c3) <<u c1) */ + if(topbit(c3) >= (32-c2)) + break; + case 001: /* (((e >>u c2) & c3) <<u c1) */ + if(c1 > c2) { + c3 <<= c2; + c1 -= c2; + o = OASHL; + goto rewrite1; + } + c3 <<= c1; + if(c1 == c2) + goto rewrite0; + c1 = c2-c1; + o = OLSHR; + goto rewrite2; + + case 022: /* (((e >>s c2) & c3) >>s c1) */ + if(c2 <= 0) + break; + case 012: /* (((e >>s c2) & c3) >>u c1) */ + if(topbit(c3) >= (32-c2)) + break; + goto s11; + case 021: /* (((e >>u c2) & c3) >>s c1) */ + if(topbit(c3) >= 31 && c2 <= 0) + break; + goto s11; + case 011: /* (((e >>u c2) & c3) >>u c1) */ + s11: + c3 <<= c2; + c1 += c2; + if(c1 >= 32) + break; + o = OLSHR; + goto rewrite1; + + case 020: /* (((e <<u c2) & c3) >>s c1) */ + if(topbit(c3) >= 31) + break; + case 010: /* (((e <<u c2) & c3) >>u c1) */ + c3 >>= c1; + if(c1 == c2) + goto rewrite0; + if(c1 > c2) { + c1 -= c2; + goto rewrite2; + } + c1 = c2 - c1; + o = OASHL; + goto rewrite2; + } + return; + +rewrite0: /* get rid of both shifts */ +if(debug['<'])prtree(n, "rewrite0"); + *n = *n->left; + n->left = n->left->left; + n->right->vconst = c3; + return; +rewrite1: /* get rid of lower shift */ +if(debug['<'])prtree(n, "rewrite1"); + n->left->left = n->left->left->left; + n->left->right->vconst = c3; + n->right->vconst = c1; + n->op = o; + return; +rewrite2: /* get rid of upper shift */ +if(debug['<'])prtree(n, "rewrite2"); + *n = *n->left; + n->right->vconst = c3; + n->left->right->vconst = c1; + n->left->op = o; +} + +int +side(Node *n) +{ + +loop: + if(n != Z) + switch(n->op) { + case OCAST: + case ONOT: + case OADDR: + case OIND: + n = n->left; + goto loop; + + case OCOND: + if(side(n->left)) + break; + n = n->right; + + case OEQ: + case ONE: + case OLT: + case OGE: + case OGT: + case OLE: + case OADD: + case OSUB: + case OMUL: + case OLMUL: + case ODIV: + case OLDIV: + case OLSHR: + case OASHL: + case OASHR: + case OAND: + case OOR: + case OXOR: + case OMOD: + case OLMOD: + case OANDAND: + case OOROR: + case OCOMMA: + case ODOT: + if(side(n->left)) + break; + n = n->right; + goto loop; + + case OSIGN: + case OSIZE: + case OCONST: + case OSTRING: + case OLSTRING: + case ONAME: + return 0; + } + return 1; +} + +int +vconst(Node *n) +{ + int i; + + if(n == Z) + goto no; + if(n->op != OCONST) + goto no; + if(n->type == T) + goto no; + switch(n->type->etype) + { + case TFLOAT: + case TDOUBLE: + i = 100; + if(n->fconst > i || n->fconst < -i) + goto no; + i = n->fconst; + if(i != n->fconst) + goto no; + return i; + + case TVLONG: + case TUVLONG: + i = n->vconst; + if(i != n->vconst) + goto no; + return i; + + case TCHAR: + case TUCHAR: + case TSHORT: + case TUSHORT: + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + i = n->vconst; + if(i != n->vconst) + goto no; + return i; + } +no: + return -159; /* first uninteresting constant */ +} + +/* + * return log(n) if n is a power of 2 constant + */ +int +xlog2(uvlong v) +{ + int s, i; + uvlong m; + + s = 0; + m = MASK(8*sizeof(uvlong)); + for(i=32; i; i>>=1) { + m >>= i; + if(!(v & m)) { + v >>= i; + s += i; + } + } + if(v == 1) + return s; + return -1; +} + +int +vlog(Node *n) +{ + if(n->op != OCONST) + goto bad; + if(typefd[n->type->etype]) + goto bad; + + return xlog2(n->vconst); + +bad: + return -1; +} + +int +topbit(ulong v) +{ + int i; + + for(i = -1; v; i++) + v >>= 1; + return i; +} + +/* + * try to cast a constant down + * rather than cast a variable up + * example: + * if(c == 'a') + */ +void +relcon(Node *l, Node *r) +{ + vlong v; + + if(l->op != OCONST) + return; + if(r->op != OCAST) + return; + if(!nilcast(r->left->type, r->type)) + return; + switch(r->type->etype) { + default: + return; + case TCHAR: + case TUCHAR: + case TSHORT: + case TUSHORT: + v = convvtox(l->vconst, r->type->etype); + if(v != l->vconst) + return; + break; + } + l->type = r->left->type; + *r = *r->left; +} + +int +relindex(int o) +{ + + switch(o) { + default: + diag(Z, "bad in relindex: %O", o); + case OEQ: return 0; + case ONE: return 1; + case OLE: return 2; + case OLS: return 3; + case OLT: return 4; + case OLO: return 5; + case OGE: return 6; + case OHS: return 7; + case OGT: return 8; + case OHI: return 9; + } +} + +Node* +invert(Node *n) +{ + Node *i; + + if(n == Z || n->op != OLIST) + return n; + i = n; + for(n = n->left; n != Z; n = n->left) { + if(n->op != OLIST) + break; + i->left = n->right; + n->right = i; + i = n; + } + i->left = n; + return i; +} + +int +bitno(long b) +{ + int i; + + for(i=0; i<32; i++) + if(b & (1L<<i)) + return i; + diag(Z, "bad in bitno"); + return 0; +} + +long +typebitor(long a, long b) +{ + long c; + + c = a | b; + if(a & b) + if((a & b) == BLONG) + c |= BVLONG; /* long long => vlong */ + else + warn(Z, "once is enough: %Q", a & b); + return c; +} + +void +diag(Node *n, char *fmt, ...) +{ + char buf[STRINGSZ]; + va_list arg; + + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf); + + if(debug['X']){ + Bflush(&diagbuf); + abort(); + } + if(n != Z) + if(debug['v']) + prtree(n, "diagnostic"); + + nerrors++; + if(nerrors > 10) { + Bprint(&diagbuf, "too many errors\n"); + errorexit(); + } +} + +void +warn(Node *n, char *fmt, ...) +{ + char buf[STRINGSZ]; + va_list arg; + + if(debug['w']) { + Bprint(&diagbuf, "warning: "); + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf); + + if(n != Z) + if(debug['v']) + prtree(n, "warning"); + } +} + +void +yyerror(char *fmt, ...) +{ + char buf[STRINGSZ]; + va_list arg; + + /* + * hack to intercept message from yaccpar + */ + if(strcmp(fmt, "syntax error") == 0) { + yyerror("syntax error, last name: %s", symb); + return; + } + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + Bprint(&diagbuf, "%L %s\n", lineno, buf); + nerrors++; + if(nerrors > 10) { + Bprint(&diagbuf, "too many errors\n"); + errorexit(); + } +} + +void +fatal(Node *n, char *fmt, ...) +{ + char buf[STRINGSZ]; + va_list arg; + + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf); + + if(debug['X']){ + Bflush(&diagbuf); + abort(); + } + if(n != Z) + if(debug['v']) + prtree(n, "diagnostic"); + + nerrors++; + errorexit(); +} + +ulong thash1 = 0x2edab8c9; +ulong thash2 = 0x1dc74fb8; +ulong thash3 = 0x1f241331; +ulong thash[NALLTYPES]; +Init thashinit[] = +{ + TXXX, 0x17527bbd, 0, + TCHAR, 0x5cedd32b, 0, + TUCHAR, 0x552c4454, 0, + TSHORT, 0x63040b4b, 0, + TUSHORT, 0x32a45878, 0, + TINT, 0x4151d5bd, 0, + TUINT, 0x5ae707d6, 0, + TLONG, 0x5ef20f47, 0, + TULONG, 0x36d8eb8f, 0, + TVLONG, 0x6e5e9590, 0, + TUVLONG, 0x75910105, 0, + TFLOAT, 0x25fd7af1, 0, + TDOUBLE, 0x7c40a1b2, 0, + TIND, 0x1b832357, 0, + TFUNC, 0x6babc9cb, 0, + TARRAY, 0x7c50986d, 0, + TVOID, 0x44112eff, 0, + TSTRUCT, 0x7c2da3bf, 0, + TUNION, 0x3eb25e98, 0, + TENUM, 0x44b54f61, 0, + TFILE, 0x19242ac3, 0, + TOLD, 0x22b15988, 0, + TDOT, 0x0204f6b3, 0, + -1, 0, 0, +}; + +char* bnames[NALIGN]; +Init bnamesinit[] = +{ + Axxx, 0, "Axxx", + Ael1, 0, "el1", + Ael2, 0, "el2", + Asu2, 0, "su2", + Aarg0, 0, "arg0", + Aarg1, 0, "arg1", + Aarg2, 0, "arg2", + Aaut3, 0, "aut3", + -1, 0, 0, +}; + +char* tnames[NALLTYPES]; +Init tnamesinit[] = +{ + TXXX, 0, "TXXX", + TCHAR, 0, "CHAR", + TUCHAR, 0, "UCHAR", + TSHORT, 0, "SHORT", + TUSHORT, 0, "USHORT", + TINT, 0, "INT", + TUINT, 0, "UINT", + TLONG, 0, "LONG", + TULONG, 0, "ULONG", + TVLONG, 0, "VLONG", + TUVLONG, 0, "UVLONG", + TFLOAT, 0, "FLOAT", + TDOUBLE, 0, "DOUBLE", + TIND, 0, "IND", + TFUNC, 0, "FUNC", + TARRAY, 0, "ARRAY", + TVOID, 0, "VOID", + TSTRUCT, 0, "STRUCT", + TUNION, 0, "UNION", + TENUM, 0, "ENUM", + TFILE, 0, "FILE", + TOLD, 0, "OLD", + TDOT, 0, "DOT", + -1, 0, 0, +}; + +char* gnames[NGTYPES]; +Init gnamesinit[] = +{ + GXXX, 0, "GXXX", + GCONSTNT, 0, "CONST", + GVOLATILE, 0, "VOLATILE", + GVOLATILE|GCONSTNT, 0, "CONST-VOLATILE", + -1, 0, 0, +}; + +char* qnames[NALLTYPES]; +Init qnamesinit[] = +{ + TXXX, 0, "TXXX", + TCHAR, 0, "CHAR", + TUCHAR, 0, "UCHAR", + TSHORT, 0, "SHORT", + TUSHORT, 0, "USHORT", + TINT, 0, "INT", + TUINT, 0, "UINT", + TLONG, 0, "LONG", + TULONG, 0, "ULONG", + TVLONG, 0, "VLONG", + TUVLONG, 0, "UVLONG", + TFLOAT, 0, "FLOAT", + TDOUBLE, 0, "DOUBLE", + TIND, 0, "IND", + TFUNC, 0, "FUNC", + TARRAY, 0, "ARRAY", + TVOID, 0, "VOID", + TSTRUCT, 0, "STRUCT", + TUNION, 0, "UNION", + TENUM, 0, "ENUM", + + TAUTO, 0, "AUTO", + TEXTERN, 0, "EXTERN", + TSTATIC, 0, "STATIC", + TTYPEDEF, 0, "TYPEDEF", + TTYPESTR, 0, "TYPESTR", + TREGISTER, 0, "REGISTER", + TCONSTNT, 0, "CONSTNT", + TVOLATILE, 0, "VOLATILE", + TUNSIGNED, 0, "UNSIGNED", + TSIGNED, 0, "SIGNED", + TDOT, 0, "DOT", + TFILE, 0, "FILE", + TOLD, 0, "OLD", + -1, 0, 0, +}; +char* cnames[NCTYPES]; +Init cnamesinit[] = +{ + CXXX, 0, "CXXX", + CAUTO, 0, "AUTO", + CEXTERN, 0, "EXTERN", + CGLOBL, 0, "GLOBL", + CSTATIC, 0, "STATIC", + CLOCAL, 0, "LOCAL", + CTYPEDEF, 0, "TYPEDEF", + CTYPESTR, 0, "TYPESTR", + CPARAM, 0, "PARAM", + CSELEM, 0, "SELEM", + CLABEL, 0, "LABEL", + CEXREG, 0, "EXREG", + -1, 0, 0, +}; + +char* onames[OEND+1]; +Init onamesinit[] = +{ + OXXX, 0, "OXXX", + OADD, 0, "ADD", + OADDR, 0, "ADDR", + OAND, 0, "AND", + OANDAND, 0, "ANDAND", + OARRAY, 0, "ARRAY", + OAS, 0, "AS", + OASI, 0, "ASI", + OASADD, 0, "ASADD", + OASAND, 0, "ASAND", + OASASHL, 0, "ASASHL", + OASASHR, 0, "ASASHR", + OASDIV, 0, "ASDIV", + OASHL, 0, "ASHL", + OASHR, 0, "ASHR", + OASLDIV, 0, "ASLDIV", + OASLMOD, 0, "ASLMOD", + OASLMUL, 0, "ASLMUL", + OASLSHR, 0, "ASLSHR", + OASMOD, 0, "ASMOD", + OASMUL, 0, "ASMUL", + OASOR, 0, "ASOR", + OASSUB, 0, "ASSUB", + OASXOR, 0, "ASXOR", + OBIT, 0, "BIT", + OBREAK, 0, "BREAK", + OCASE, 0, "CASE", + OCAST, 0, "CAST", + OCOMMA, 0, "COMMA", + OCOND, 0, "COND", + OCONST, 0, "CONST", + OCONTINUE, 0, "CONTINUE", + ODIV, 0, "DIV", + ODOT, 0, "DOT", + ODOTDOT, 0, "DOTDOT", + ODWHILE, 0, "DWHILE", + OENUM, 0, "ENUM", + OEQ, 0, "EQ", + OFOR, 0, "FOR", + OFUNC, 0, "FUNC", + OGE, 0, "GE", + OGOTO, 0, "GOTO", + OGT, 0, "GT", + OHI, 0, "HI", + OHS, 0, "HS", + OIF, 0, "IF", + OIND, 0, "IND", + OINDREG, 0, "INDREG", + OINIT, 0, "INIT", + OLABEL, 0, "LABEL", + OLDIV, 0, "LDIV", + OLE, 0, "LE", + OLIST, 0, "LIST", + OLMOD, 0, "LMOD", + OLMUL, 0, "LMUL", + OLO, 0, "LO", + OLS, 0, "LS", + OLSHR, 0, "LSHR", + OLT, 0, "LT", + OMOD, 0, "MOD", + OMUL, 0, "MUL", + ONAME, 0, "NAME", + ONE, 0, "NE", + ONOT, 0, "NOT", + OOR, 0, "OR", + OOROR, 0, "OROR", + OPOSTDEC, 0, "POSTDEC", + OPOSTINC, 0, "POSTINC", + OPREDEC, 0, "PREDEC", + OPREINC, 0, "PREINC", + OPROTO, 0, "PROTO", + OREGISTER, 0, "REGISTER", + ORETURN, 0, "RETURN", + OSET, 0, "SET", + OSIGN, 0, "SIGN", + OSIZE, 0, "SIZE", + OSTRING, 0, "STRING", + OLSTRING, 0, "LSTRING", + OSTRUCT, 0, "STRUCT", + OSUB, 0, "SUB", + OSWITCH, 0, "SWITCH", + OUNION, 0, "UNION", + OUSED, 0, "USED", + OWHILE, 0, "WHILE", + OXOR, 0, "XOR", + OPOS, 0, "POS", + ONEG, 0, "NEG", + OCOM, 0, "COM", + OELEM, 0, "ELEM", + OTST, 0, "TST", + OINDEX, 0, "INDEX", + OFAS, 0, "FAS", + OREGPAIR, 0, "REGPAIR", + OEND, 0, "END", + -1, 0, 0, +}; + +/* OEQ, ONE, OLE, OLS, OLT, OLO, OGE, OHS, OGT, OHI */ +uchar comrel[12] = +{ + ONE, OEQ, OGT, OHI, OGE, OHS, OLT, OLO, OLE, OLS, +}; +uchar invrel[12] = +{ + OEQ, ONE, OGE, OHS, OGT, OHI, OLE, OLS, OLT, OLO, +}; +uchar logrel[12] = +{ + OEQ, ONE, OLS, OLS, OLO, OLO, OHS, OHS, OHI, OHI, +}; + +uchar typei[NTYPE]; +int typeiinit[] = +{ + TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TVLONG, TUVLONG, -1, +}; +uchar typeu[NTYPE]; +int typeuinit[] = +{ + TUCHAR, TUSHORT, TUINT, TULONG, TUVLONG, TIND, -1, +}; + +uchar typesuv[NTYPE]; +int typesuvinit[] = +{ + TVLONG, TUVLONG, TSTRUCT, TUNION, -1, +}; + +uchar typeilp[NTYPE]; +int typeilpinit[] = +{ + TINT, TUINT, TLONG, TULONG, TIND, -1 +}; + +uchar typechl[NTYPE]; +uchar typechlv[NTYPE]; +uchar typechlvp[NTYPE]; +int typechlinit[] = +{ + TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, -1, +}; + +uchar typechlp[NTYPE]; +int typechlpinit[] = +{ + TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TIND, -1, +}; + +uchar typechlpfd[NTYPE]; +int typechlpfdinit[] = +{ + TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TFLOAT, TDOUBLE, TIND, -1, +}; + +uchar typec[NTYPE]; +int typecinit[] = +{ + TCHAR, TUCHAR, -1 +}; + +uchar typeh[NTYPE]; +int typehinit[] = +{ + TSHORT, TUSHORT, -1, +}; + +uchar typeil[NTYPE]; +int typeilinit[] = +{ + TINT, TUINT, TLONG, TULONG, -1, +}; + +uchar typev[NTYPE]; +int typevinit[] = +{ + TVLONG, TUVLONG, -1, +}; + +uchar typefd[NTYPE]; +int typefdinit[] = +{ + TFLOAT, TDOUBLE, -1, +}; + +uchar typeaf[NTYPE]; +int typeafinit[] = +{ + TFUNC, TARRAY, -1, +}; + +uchar typesu[NTYPE]; +int typesuinit[] = +{ + TSTRUCT, TUNION, -1, +}; + +long tasign[NTYPE]; +Init tasigninit[] = +{ + TCHAR, BNUMBER, 0, + TUCHAR, BNUMBER, 0, + TSHORT, BNUMBER, 0, + TUSHORT, BNUMBER, 0, + TINT, BNUMBER, 0, + TUINT, BNUMBER, 0, + TLONG, BNUMBER, 0, + TULONG, BNUMBER, 0, + TVLONG, BNUMBER, 0, + TUVLONG, BNUMBER, 0, + TFLOAT, BNUMBER, 0, + TDOUBLE, BNUMBER, 0, + TIND, BIND, 0, + TSTRUCT, BSTRUCT, 0, + TUNION, BUNION, 0, + -1, 0, 0, +}; + +long tasadd[NTYPE]; +Init tasaddinit[] = +{ + TCHAR, BNUMBER, 0, + TUCHAR, BNUMBER, 0, + TSHORT, BNUMBER, 0, + TUSHORT, BNUMBER, 0, + TINT, BNUMBER, 0, + TUINT, BNUMBER, 0, + TLONG, BNUMBER, 0, + TULONG, BNUMBER, 0, + TVLONG, BNUMBER, 0, + TUVLONG, BNUMBER, 0, + TFLOAT, BNUMBER, 0, + TDOUBLE, BNUMBER, 0, + TIND, BINTEGER, 0, + -1, 0, 0, +}; + +long tcast[NTYPE]; +Init tcastinit[] = +{ + TCHAR, BNUMBER|BIND|BVOID, 0, + TUCHAR, BNUMBER|BIND|BVOID, 0, + TSHORT, BNUMBER|BIND|BVOID, 0, + TUSHORT, BNUMBER|BIND|BVOID, 0, + TINT, BNUMBER|BIND|BVOID, 0, + TUINT, BNUMBER|BIND|BVOID, 0, + TLONG, BNUMBER|BIND|BVOID, 0, + TULONG, BNUMBER|BIND|BVOID, 0, + TVLONG, BNUMBER|BIND|BVOID, 0, + TUVLONG, BNUMBER|BIND|BVOID, 0, + TFLOAT, BNUMBER|BVOID, 0, + TDOUBLE, BNUMBER|BVOID, 0, + TIND, BINTEGER|BIND|BVOID, 0, + TVOID, BVOID, 0, + TSTRUCT, BSTRUCT|BVOID, 0, + TUNION, BUNION|BVOID, 0, + -1, 0, 0, +}; + +long tadd[NTYPE]; +Init taddinit[] = +{ + TCHAR, BNUMBER|BIND, 0, + TUCHAR, BNUMBER|BIND, 0, + TSHORT, BNUMBER|BIND, 0, + TUSHORT, BNUMBER|BIND, 0, + TINT, BNUMBER|BIND, 0, + TUINT, BNUMBER|BIND, 0, + TLONG, BNUMBER|BIND, 0, + TULONG, BNUMBER|BIND, 0, + TVLONG, BNUMBER|BIND, 0, + TUVLONG, BNUMBER|BIND, 0, + TFLOAT, BNUMBER, 0, + TDOUBLE, BNUMBER, 0, + TIND, BINTEGER, 0, + -1, 0, 0, +}; + +long tsub[NTYPE]; +Init tsubinit[] = +{ + TCHAR, BNUMBER, 0, + TUCHAR, BNUMBER, 0, + TSHORT, BNUMBER, 0, + TUSHORT, BNUMBER, 0, + TINT, BNUMBER, 0, + TUINT, BNUMBER, 0, + TLONG, BNUMBER, 0, + TULONG, BNUMBER, 0, + TVLONG, BNUMBER, 0, + TUVLONG, BNUMBER, 0, + TFLOAT, BNUMBER, 0, + TDOUBLE, BNUMBER, 0, + TIND, BINTEGER|BIND, 0, + -1, 0, 0, +}; + +long tmul[NTYPE]; +Init tmulinit[] = +{ + TCHAR, BNUMBER, 0, + TUCHAR, BNUMBER, 0, + TSHORT, BNUMBER, 0, + TUSHORT, BNUMBER, 0, + TINT, BNUMBER, 0, + TUINT, BNUMBER, 0, + TLONG, BNUMBER, 0, + TULONG, BNUMBER, 0, + TVLONG, BNUMBER, 0, + TUVLONG, BNUMBER, 0, + TFLOAT, BNUMBER, 0, + TDOUBLE, BNUMBER, 0, + -1, 0, 0, +}; + +long tand[NTYPE]; +Init tandinit[] = +{ + TCHAR, BINTEGER, 0, + TUCHAR, BINTEGER, 0, + TSHORT, BINTEGER, 0, + TUSHORT, BINTEGER, 0, + TINT, BNUMBER, 0, + TUINT, BNUMBER, 0, + TLONG, BINTEGER, 0, + TULONG, BINTEGER, 0, + TVLONG, BINTEGER, 0, + TUVLONG, BINTEGER, 0, + -1, 0, 0, +}; + +long trel[NTYPE]; +Init trelinit[] = +{ + TCHAR, BNUMBER, 0, + TUCHAR, BNUMBER, 0, + TSHORT, BNUMBER, 0, + TUSHORT, BNUMBER, 0, + TINT, BNUMBER, 0, + TUINT, BNUMBER, 0, + TLONG, BNUMBER, 0, + TULONG, BNUMBER, 0, + TVLONG, BNUMBER, 0, + TUVLONG, BNUMBER, 0, + TFLOAT, BNUMBER, 0, + TDOUBLE, BNUMBER, 0, + TIND, BIND, 0, + -1, 0, 0, +}; + +long tfunct[1] = +{ + BFUNC, +}; + +long tindir[1] = +{ + BIND, +}; + +long tdot[1] = +{ + BSTRUCT|BUNION, +}; + +long tnot[1] = +{ + BNUMBER|BIND, +}; + +long targ[1] = +{ + BNUMBER|BIND|BSTRUCT|BUNION, +}; + +uchar tab[NTYPE][NTYPE] = +{ +/*TXXX*/ { 0, + }, + +/*TCHAR*/ { 0, TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, + TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TUCHAR*/ { 0, TUCHAR, TUCHAR, TUSHORT, TUSHORT, TUINT, TUINT, TULONG, + TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TSHORT*/ { 0, TSHORT, TUSHORT, TSHORT, TUSHORT, TINT, TUINT, TLONG, + TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TUSHORT*/ { 0, TUSHORT, TUSHORT, TUSHORT, TUSHORT, TUINT, TUINT, TULONG, + TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TINT*/ { 0, TINT, TUINT, TINT, TUINT, TINT, TUINT, TLONG, + TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TUINT*/ { 0, TUINT, TUINT, TUINT, TUINT, TUINT, TUINT, TULONG, + TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TLONG*/ { 0, TLONG, TULONG, TLONG, TULONG, TLONG, TULONG, TLONG, + TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TULONG*/ { 0, TULONG, TULONG, TULONG, TULONG, TULONG, TULONG, TULONG, + TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TVLONG*/ { 0, TVLONG, TUVLONG, TVLONG, TUVLONG, TVLONG, TUVLONG, TVLONG, + TUVLONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TUVLONG*/ { 0, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, + TUVLONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND, + }, +/*TFLOAT*/ { 0, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, + TFLOAT, TFLOAT, TFLOAT, TFLOAT, TDOUBLE, TIND, + }, +/*TDOUBLE*/ { 0, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, + TDOUBLE, TDOUBLE, TDOUBLE, TFLOAT, TDOUBLE, TIND, + }, +/*TIND*/ { 0, TIND, TIND, TIND, TIND, TIND, TIND, TIND, + TIND, TIND, TIND, TIND, TIND, TIND, + }, +}; + +void +urk(char *name, int max, int i) +{ + if(i >= max) { + fprint(2, "bad tinit: %s %d>=%d\n", name, i, max); + exits("init"); + } +} + +void +tinit(void) +{ + int *ip; + Init *p; + + for(p=thashinit; p->code >= 0; p++) { + urk("thash", nelem(thash), p->code); + thash[p->code] = p->value; + } + for(p=bnamesinit; p->code >= 0; p++) { + urk("bnames", nelem(bnames), p->code); + bnames[p->code] = p->s; + } + for(p=tnamesinit; p->code >= 0; p++) { + urk("tnames", nelem(tnames), p->code); + tnames[p->code] = p->s; + } + for(p=gnamesinit; p->code >= 0; p++) { + urk("gnames", nelem(gnames), p->code); + gnames[p->code] = p->s; + } + for(p=qnamesinit; p->code >= 0; p++) { + urk("qnames", nelem(qnames), p->code); + qnames[p->code] = p->s; + } + for(p=cnamesinit; p->code >= 0; p++) { + urk("cnames", nelem(cnames), p->code); + cnames[p->code] = p->s; + } + for(p=onamesinit; p->code >= 0; p++) { + urk("onames", nelem(onames), p->code); + onames[p->code] = p->s; + } + for(ip=typeiinit; *ip>=0; ip++) { + urk("typei", nelem(typei), *ip); + typei[*ip] = 1; + } + for(ip=typeuinit; *ip>=0; ip++) { + urk("typeu", nelem(typeu), *ip); + typeu[*ip] = 1; + } + for(ip=typesuvinit; *ip>=0; ip++) { + urk("typesuv", nelem(typesuv), *ip); + typesuv[*ip] = 1; + } + for(ip=typeilpinit; *ip>=0; ip++) { + urk("typeilp", nelem(typeilp), *ip); + typeilp[*ip] = 1; + } + for(ip=typechlinit; *ip>=0; ip++) { + urk("typechl", nelem(typechl), *ip); + typechl[*ip] = 1; + typechlv[*ip] = 1; + typechlvp[*ip] = 1; + } + for(ip=typechlpinit; *ip>=0; ip++) { + urk("typechlp", nelem(typechlp), *ip); + typechlp[*ip] = 1; + typechlvp[*ip] = 1; + } + for(ip=typechlpfdinit; *ip>=0; ip++) { + urk("typechlpfd", nelem(typechlpfd), *ip); + typechlpfd[*ip] = 1; + } + for(ip=typecinit; *ip>=0; ip++) { + urk("typec", nelem(typec), *ip); + typec[*ip] = 1; + } + for(ip=typehinit; *ip>=0; ip++) { + urk("typeh", nelem(typeh), *ip); + typeh[*ip] = 1; + } + for(ip=typeilinit; *ip>=0; ip++) { + urk("typeil", nelem(typeil), *ip); + typeil[*ip] = 1; + } + for(ip=typevinit; *ip>=0; ip++) { + urk("typev", nelem(typev), *ip); + typev[*ip] = 1; + typechlv[*ip] = 1; + typechlvp[*ip] = 1; + } + for(ip=typefdinit; *ip>=0; ip++) { + urk("typefd", nelem(typefd), *ip); + typefd[*ip] = 1; + } + for(ip=typeafinit; *ip>=0; ip++) { + urk("typeaf", nelem(typeaf), *ip); + typeaf[*ip] = 1; + } + for(ip=typesuinit; *ip >= 0; ip++) { + urk("typesu", nelem(typesu), *ip); + typesu[*ip] = 1; + } + for(p=tasigninit; p->code >= 0; p++) { + urk("tasign", nelem(tasign), p->code); + tasign[p->code] = p->value; + } + for(p=tasaddinit; p->code >= 0; p++) { + urk("tasadd", nelem(tasadd), p->code); + tasadd[p->code] = p->value; + } + for(p=tcastinit; p->code >= 0; p++) { + urk("tcast", nelem(tcast), p->code); + tcast[p->code] = p->value; + } + for(p=taddinit; p->code >= 0; p++) { + urk("tadd", nelem(tadd), p->code); + tadd[p->code] = p->value; + } + for(p=tsubinit; p->code >= 0; p++) { + urk("tsub", nelem(tsub), p->code); + tsub[p->code] = p->value; + } + for(p=tmulinit; p->code >= 0; p++) { + urk("tmul", nelem(tmul), p->code); + tmul[p->code] = p->value; + } + for(p=tandinit; p->code >= 0; p++) { + urk("tand", nelem(tand), p->code); + tand[p->code] = p->value; + } + for(p=trelinit; p->code >= 0; p++) { + urk("trel", nelem(trel), p->code); + trel[p->code] = p->value; + } + + /* 32-bit defaults */ + typeword = typechlp; + typecmplx = typesuv; +} + +/* + * return 1 if it is impossible to jump into the middle of n. + */ +static int +deadhead(Node *n, int caseok) +{ +loop: + if(n == Z) + return 1; + switch(n->op) { + case OLIST: + if(!deadhead(n->left, caseok)) + return 0; + rloop: + n = n->right; + goto loop; + + case ORETURN: + break; + + case OLABEL: + return 0; + + case OGOTO: + break; + + case OCASE: + if(!caseok) + return 0; + goto rloop; + + case OSWITCH: + return deadhead(n->right, 1); + + case OWHILE: + case ODWHILE: + goto rloop; + + case OFOR: + goto rloop; + + case OCONTINUE: + break; + + case OBREAK: + break; + + case OIF: + return deadhead(n->right->left, caseok) && deadhead(n->right->right, caseok); + + case OSET: + case OUSED: + break; + } + return 1; +} + +int +deadheads(Node *c) +{ + return deadhead(c->left, 0) && deadhead(c->right, 0); +} + +int +mixedasop(Type *l, Type *r) +{ + return !typefd[l->etype] && typefd[r->etype]; +} |