summaryrefslogtreecommitdiff
path: root/utils/c2l
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
commit74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a (patch)
treec6e220ba61db3a6ea4052e6841296d829654e664 /utils/c2l
parent46439007cf417cbd9ac8049bb4122c890097a0fa (diff)
20060303
Diffstat (limited to 'utils/c2l')
-rw-r--r--utils/c2l/Nt.c131
-rw-r--r--utils/c2l/Plan9.c108
-rw-r--r--utils/c2l/Posix.c91
-rw-r--r--utils/c2l/acid.c13
-rw-r--r--utils/c2l/bits.c89
-rw-r--r--utils/c2l/c2l.c5118
-rw-r--r--utils/c2l/cc.h849
-rw-r--r--utils/c2l/cc.y1239
-rw-r--r--utils/c2l/com.c918
-rw-r--r--utils/c2l/com64.c52
-rw-r--r--utils/c2l/dcl.c1387
-rw-r--r--utils/c2l/dpchk.c392
-rw-r--r--utils/c2l/lex.c1675
-rw-r--r--utils/c2l/lexbody650
-rw-r--r--utils/c2l/mac.c3
-rw-r--r--utils/c2l/macbody773
-rw-r--r--utils/c2l/mkfile38
-rw-r--r--utils/c2l/mpatof.c337
-rw-r--r--utils/c2l/out.c825
-rw-r--r--utils/c2l/scon.c250
-rw-r--r--utils/c2l/sub.c1694
21 files changed, 16632 insertions, 0 deletions
diff --git a/utils/c2l/Nt.c b/utils/c2l/Nt.c
new file mode 100644
index 00000000..bf36e0dd
--- /dev/null
+++ b/utils/c2l/Nt.c
@@ -0,0 +1,131 @@
+#include <windows.h>
+#include <lib9.h>
+
+#define Windows (1<<2) /* hack - can't include cc.h because of clashes */
+#define Chunk (1*1024*1024)
+
+void*
+mysbrk(ulong size)
+{
+ void *v;
+ static int chunk;
+ static uchar *brk;
+
+ if(chunk < size) {
+ chunk = Chunk;
+ if(chunk < size)
+ chunk = Chunk + size;
+ brk = VirtualAlloc(NULL, chunk, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ if(brk == 0)
+ return (void*)-1;
+ }
+ v = brk;
+ chunk -= size;
+ brk += size;
+ return v;
+}
+
+int
+mycreat(char *n, int p)
+{
+
+ return create(n, 1, p);
+}
+
+int
+mywait(int *s)
+{
+ fprint(2, "mywait called\n");
+ abort();
+ return 0;
+}
+
+int
+mydup(int f1, int f2)
+{
+ int ok;
+
+ ok = _dup2(f1, f2);
+ if(ok < 0)
+ return -1;
+ return f2;
+/*
+ fprint(2, "mydup called\n");
+ abort();
+ return 0;
+*/
+}
+
+int
+mypipe(int *fd)
+{
+ fprint(2, "mypipe called\n");
+ abort();
+ return 0;
+}
+
+int
+systemtype(int sys)
+{
+
+ return sys&Windows;
+}
+
+int
+pathchar(void)
+{
+ return '/';
+}
+
+char*
+mygetwd(char *path, int len)
+{
+ return getcwd(path, len);
+}
+
+int
+myexec(char *path, char *argv[])
+{
+ fprint(2, "myexec called\n");
+ abort();
+ return 0;
+}
+
+int
+myfork(void)
+{
+ fprint(2, "myfork called\n");
+ abort();
+ return 0;
+}
+
+/*
+ * fake mallocs
+ */
+void*
+malloc(uint n)
+{
+ return mysbrk(n);
+}
+
+void*
+calloc(uint m, uint n)
+{
+ return mysbrk(m*n);
+}
+
+void*
+realloc(void *p, uint n)
+{
+ void *new;
+
+ new = malloc(n);
+ if(new && p)
+ memmove(new, p, n);
+ return new;
+}
+
+void
+free(void *p)
+{
+}
diff --git a/utils/c2l/Plan9.c b/utils/c2l/Plan9.c
new file mode 100644
index 00000000..853df40b
--- /dev/null
+++ b/utils/c2l/Plan9.c
@@ -0,0 +1,108 @@
+#include "cc.h"
+
+void*
+mysbrk(ulong size)
+{
+ return sbrk(size);
+}
+
+int
+mycreat(char *n, int p)
+{
+
+ return create(n, 1, p);
+}
+
+int
+mywait(int *s)
+{
+ int p;
+ Waitmsg *w;
+
+ if((w = wait()) == nil)
+ return -1;
+ else{
+ p = w->pid;
+ *s = 0;
+ if(w->msg[0])
+ *s = 1;
+ free(w);
+ return p;
+ }
+}
+
+int
+mydup(int f1, int f2)
+{
+ return dup(f1,f2);
+}
+
+int
+mypipe(int *fd)
+{
+ return pipe(fd);
+}
+
+int
+systemtype(int sys)
+{
+
+ return sys&Plan9;
+}
+
+int
+pathchar(void)
+{
+ return '/';
+}
+
+char*
+mygetwd(char *path, int len)
+{
+ return getwd(path, len);
+}
+
+int
+myexec(char *path, char *argv[])
+{
+ return exec(path, argv);
+}
+
+/*
+ * fake mallocs
+ */
+void*
+malloc(ulong n)
+{
+ return alloc(n);
+}
+
+void*
+calloc(ulong m, ulong n)
+{
+ return alloc(m*n);
+}
+
+void*
+realloc(void*, ulong)
+{
+ fprint(2, "realloc called\n");
+ abort();
+ return 0;
+}
+
+void
+free(void*)
+{
+}
+
+int
+myfork(void)
+{
+ return fork();
+}
+
+void
+setmalloctag(void*, ulong)
+{
+}
diff --git a/utils/c2l/Posix.c b/utils/c2l/Posix.c
new file mode 100644
index 00000000..065f1e20
--- /dev/null
+++ b/utils/c2l/Posix.c
@@ -0,0 +1,91 @@
+#include "cc.h"
+
+void*
+mysbrk(ulong size)
+{
+ return (void*)sbrk(size);
+}
+
+int
+mycreat(char *n, int p)
+{
+
+ return create(n, 1, p);
+}
+
+int
+mywait(int *s)
+{
+ return wait(s);
+}
+
+int
+mydup(int f1, int f2)
+{
+ return dup2(f1,f2);
+}
+
+int
+mypipe(int *fd)
+{
+ return pipe(fd);
+}
+
+int
+systemtype(int sys)
+{
+
+ return sys&Unix;
+}
+
+int
+pathchar(void)
+{
+ return '/';
+}
+
+char*
+mygetwd(char *path, int len)
+{
+ return (char*)getcwd(path, len);
+}
+
+int
+myexec(char *path, char *argv[])
+{
+ return execvp(path, argv);
+}
+
+/*
+ * fake mallocs
+ */
+void*
+malloc(size_t n)
+{
+ return alloc(n);
+}
+
+void*
+calloc(size_t m, size_t n)
+{
+ return alloc(m*n);
+}
+
+void*
+realloc(void *p, size_t n)
+{
+ fprint(2, "realloc called\n");
+ abort();
+ return 0;
+}
+
+void
+free(void *p)
+{
+}
+
+int
+myfork(void)
+{
+ return fork();
+}
diff --git a/utils/c2l/acid.c b/utils/c2l/acid.c
new file mode 100644
index 00000000..c31e600f
--- /dev/null
+++ b/utils/c2l/acid.c
@@ -0,0 +1,13 @@
+#include "cc.h"
+
+void
+acidtype(Type *t)
+{
+ USED(t);
+}
+
+void
+acidvar(Sym *s)
+{
+ USED(s);
+}
diff --git a/utils/c2l/bits.c b/utils/c2l/bits.c
new file mode 100644
index 00000000..a22ba512
--- /dev/null
+++ b/utils/c2l/bits.c
@@ -0,0 +1,89 @@
+#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/utils/c2l/c2l.c b/utils/c2l/c2l.c
new file mode 100644
index 00000000..f870d640
--- /dev/null
+++ b/utils/c2l/c2l.c
@@ -0,0 +1,5118 @@
+#define EXTERN
+
+#include "cc.h"
+
+/*
+ * locals, parameters, globals etc of the same name should work ok without having
+ * to duplicate Syms because the details are on the containing Nodes
+ */
+
+#define SZ_CHAR 1
+#define SZ_SHORT 2
+#define SZ_INT 4
+#define SZ_LONG 4
+#define SZ_FLOAT 4
+#define SZ_IND 4
+#define SZ_VLONG 8
+#define SZ_DOUBLE 8
+
+char buf[128], mbuf[128];
+static Sym *sysop, *bioop, *libcop;
+static int again;
+
+#define INFINITY 0x7fffffff
+#define STAR 0x80
+#define RET 0x80
+
+#define LARR (-1729)
+
+static void swalk(void);
+static int isdec(Node*);
+static int isconst(Node*, vlong);
+static int cktype(Node*, Node*, int, int);
+static void addnode(int, Node*);
+static int argpos(Node*, Node*);
+static void setdec(Sym*, Type*);
+static Type* tcp(Type*);
+static int isadt(Type*);
+static void aargs(Node*);
+static int iteq(Type*, Type*);
+static Node* arg(Node*, int);
+static void etgen2(Sym*);
+static Node* ckneg(Node*);
+static Sym* suename(Type*);
+static int isnil(Node*);
+static void sliceasgn(Node*);
+static Node* lastn(Node*);
+static char* hasm(void);
+static void prn(Node*, int);
+static int isfn(Type*);
+
+schar ewidth[NTYPE] =
+{
+ -1, /* [TXXX] */
+ SZ_CHAR, /* [TCHAR] */
+ SZ_CHAR, /* [TUCHAR] */
+ SZ_SHORT, /* [TSHORT] */
+ SZ_SHORT, /* [TUSHORT] */
+ SZ_INT, /* [TINT] */
+ SZ_INT, /* [TUINT] */
+ SZ_LONG, /* [TLONG] */
+ SZ_LONG, /* [TULONG] */
+ SZ_VLONG, /* [TVLONG] */
+ SZ_VLONG, /* [TUVLONG] */
+ SZ_FLOAT, /* [TFLOAT] */
+ SZ_DOUBLE, /* [TDOUBLE] */
+ SZ_IND, /* [TIND] */
+ 0, /* [TFUNC] */
+ -1, /* [TARRAY] */
+ 0, /* [TVOID] */
+ -1, /* [TSTRUCT] */
+ -1, /* [TUNION] */
+ SZ_INT, /* [TENUM] */
+};
+
+long ncast[NTYPE] =
+{
+ 0, /* [TXXX] */
+ BCHAR|BUCHAR, /* [TCHAR] */
+ BCHAR|BUCHAR, /* [TUCHAR] */
+ BSHORT|BUSHORT, /* [TSHORT] */
+ BSHORT|BUSHORT, /* [TUSHORT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TINT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TUINT] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TLONG] */
+ BINT|BUINT|BLONG|BULONG|BIND, /* [TULONG] */
+ BVLONG|BUVLONG, /* [TVLONG] */
+ BVLONG|BUVLONG, /* [TUVLONG] */
+ BFLOAT, /* [TFLOAT] */
+ BDOUBLE, /* [TDOUBLE] */
+ BLONG|BULONG|BIND, /* [TIND] */
+ 0, /* [TFUNC] */
+ 0, /* [TARRAY] */
+ 0, /* [TVOID] */
+ BSTRUCT, /* [TSTRUCT] */
+ BUNION, /* [TUNION] */
+ 0, /* [TENUM] */
+};
+
+enum{
+ TCFD = 1,
+ TCFC = 2,
+ TCPC = 4,
+ TCAR = 8,
+ TCIN = 16,
+ TCGEN = TCFD|TCFC|TCPC|TCAR,
+ TCALL = TCFD|TCFC|TCPC|TCAR|TCIN,
+};
+
+enum{
+ SGLOB,
+ SPARM,
+ SAUTO,
+};
+
+typedef struct Scope Scope;
+
+struct Scope{
+ Node *n;
+ int k;
+ Scope *nxt;
+};
+
+static void
+prtyp(Type *t, char *s, int nl)
+{
+ print("%s: ", s);
+ if(t == T){
+ print("nil");
+ if(nl)
+ print("\n");
+ return;
+ }
+ while(t != T){
+ print("%d(%d)[%x] ", t->etype, t->mark, (int)t);
+ if(isadt(t))
+ break;
+ t = t->link;
+ }
+ if(nl)
+ print("\n");
+}
+
+static Node*
+func(Node *n)
+{
+ while(n != Z && n->op != OFUNC)
+ n = n->left;
+ return n;
+}
+
+static void
+setmain(Node *n)
+{
+ inmain |= n->left->op == ONAME && strcmp(n->left->sym->name, "main") == 0;
+}
+
+static Node*
+protoname(Node *n)
+{
+ do
+ n = n->left;
+ while(n != Z && n->op != ONAME && n->op != ODOTDOT);
+ return n;
+}
+
+static Type*
+prototype(Node *n, Type *t)
+{
+ for( ; n != Z ; n = n->left){
+ switch(n->op){
+ case OARRAY:
+ t = typ(TARRAY, t);
+ t->width = 0;
+ break;
+ case OIND:
+ t = typ(TIND, t);
+ break;
+ case OFUNC:
+ t = typ(TFUNC, t);
+ t->down = fnproto(n);
+ break;
+ }
+ }
+ return t;
+}
+
+static Scope *scopes, *freescopes;
+
+static void
+pushdcl(Node *n, int c)
+{
+ Sym *s;
+
+ if(passes){
+ s = n->sym;
+ push1(s);
+ if(c != CAUTO || s->class != CSTATIC)
+ s->class = c;
+ s->type = n->type;
+ }
+}
+
+static void
+pushparams(Node *n)
+{
+ if(n == Z)
+ return;
+ if(passes){
+ if(n->op == OLIST){
+ pushparams(n->left);
+ pushparams(n->right);
+ }
+ else if(n->op == OPROTO){
+ n = protoname(n);
+ if(n != Z && n->op == ONAME)
+ pushdcl(n, CPARAM);
+ }
+ else if(n->op == ONAME){
+ addnode(OPROTO, n);
+ pushdcl(n, CPARAM);
+ }
+ else if(n->op != ODOTDOT)
+ diag(Z, "bad op in pushparams");
+ }
+}
+
+static void
+pushscope(Node *n, int k)
+{
+ Scope *s;
+
+ if(freescopes != nil){
+ s = freescopes;
+ freescopes = freescopes->nxt;
+ }
+ else
+ s = (Scope*)malloc(sizeof(Scope));
+ s->n = n;
+ s->k = k;
+ s->nxt = scopes;
+ scopes = s;
+ if(passes && (k == SPARM || k == SAUTO))
+ markdcl();
+ if(k == SPARM)
+ pushparams(n->right);
+}
+
+static void
+popscope(void)
+{
+ int k;
+ Scope *s;
+
+ s = scopes;
+ k = s->k;
+ scopes = scopes->nxt;
+ s->nxt = freescopes;
+ freescopes = s;
+ if(passes && (k == SPARM || k == SAUTO))
+ revertdcl();
+}
+
+static Node*
+curfn(void)
+{
+ Scope *s;
+
+ for(s = scopes; s != nil; s = s->nxt)
+ if(s->k == SPARM)
+ return s->n;
+ return Z;
+}
+
+static void
+marktype(Type *t, int tc)
+{
+ t->mark = tc;
+}
+
+static int
+marked(Type *t)
+{
+ return t == T ? 0 : t->mark;
+}
+
+static Sym*
+decsym(Node *n)
+{
+ if(n == Z)
+ return S;
+ if(n->op == OFUNC){
+ if(n->left->op == ONAME)
+ return n->left->sym;
+ return S;
+ }
+ if(n->op == ODAS)
+ return n->left->sym;
+ return n->sym;
+}
+
+static void
+trep(Type *t1, Type *t)
+{
+ int l;
+ Sym *s;
+ Type *t2;
+
+ if(t1 != T){
+ l = t1->lineno;
+ s = t1->sym;
+ t2 = t1->down;
+ *t1 = *t;
+ t1->down = t2;
+ t1->sym = s;
+ t1->lineno = l;
+ }
+}
+
+static void
+tind(Node *n)
+{
+ if(n == Z)
+ return;
+ n = protoname(n);
+ if(n != Z && n->type != T){
+ n->type = tcp(n->type->link);
+ marktype(n->type, TCIN);
+ }
+}
+
+static void
+tcon(Node *n, Type *t)
+{
+ Type *tt;
+
+ if(n->garb)
+ return;
+ n->garb = 1;
+ again = 1;
+ switch(n->op){
+ case OCONST:
+ if(t->mark == TCFD && !isnil(n))
+ addnode(OFILDES, n);
+ n->type = t;
+ break;
+ case OCAST:
+ tcon(n->left, t);
+ *n = *n->left;
+ n->type = t;
+ break;
+ case ONAME:
+ n->sym->type = t;
+ n->type = t;
+ setdec(n->sym, t);
+ break;
+ case ODOT:
+ case ODOTIND:
+ trep(n->type, t);
+ n->type = t;
+ break;
+ case OARRIND:
+ tt = n->left->type;
+ if(tt != T)
+ tt->link = t;
+ n->type = t;
+ break;
+ case OFUNC:
+ n->left->type->link = t;
+ if(n->left->op == ONAME)
+ n->left->sym->type->link = t;
+ n->type = t;
+ break;
+ }
+}
+
+static Node*
+retval(Node *n)
+{
+ int i;
+ Type *t;
+ Node *a, *l, *cf;
+
+ cf = curfn();
+ t = cf->left->type->link;
+ if(t->mark&(TCPC|TCFC) && (n == Z || !(n->type->mark&(TCPC|TCFC)))){
+ if(n == Z)
+ n = new1(ORETURN, Z, Z);
+ l = n->left;
+ for(i = 0; ; i++){
+ a = arg(cf->right, i);
+ if(a == Z)
+ break;
+ a = protoname(a);
+ if(a == Z || a->op != ONAME)
+ break;
+ if(a->type->mark == TCIN){
+ if(l == Z)
+ l = ncopy(a);
+ else
+ l = new1(OTUPLE, l, ncopy(a));
+ }
+ }
+ n->left = l;
+ n->type = l->type = t;
+ }
+ return n;
+}
+
+static void
+sube(Node *n)
+{
+ Node *l, *r, *nn;
+ Type *tt;
+ static Node *gn;
+ int p;
+
+ if(n == Z)
+ return;
+ l = n->left;
+ r = n->right;
+ switch(n->op){
+ default:
+ sube(l);
+ sube(r);
+ break;
+ case OIND:
+ if(l == Z)
+ return;
+ tt = l->type;
+ sube(l);
+ if(cktype(l, n, TCIN, 0) && iteq(tt, l->type))
+ *n = *n->left;
+ break;
+ case OARRIND:
+ tt = l->type;
+ sube(l);
+ sube(r);
+ if(!isconst(r, 0))
+ break;
+ if(cktype(l, n, TCIN, 0) && iteq(tt, l->type))
+ *n = *n->left;
+ break;
+ case ONAME:
+ if(cktype(n, n, TCALL, 0))
+ setdec(n->sym, n->type);
+ break;
+ case OCAST:
+ sube(l);
+ if(cktype(l, n, TCALL, 0))
+ n->type = l->type;
+ break;
+ case OPROTO:
+ sube(l);
+ sube(r);
+ nn = protoname(n);
+ if(nn != Z && cktype(nn, n, TCALL, 0)){
+ n->type = nn->type;
+ p = argpos(n, gn->right);
+ for(tt = gn->left->type->down; tt != T && p >= 0; tt = tt->down){
+ if(p == 0){
+ trep(tt, nn->type);
+ break;
+ }
+ --p;
+ }
+ }
+ break;
+ case OFUNC:
+ if(n->kind == KEXP)
+ aargs(n);
+ if(n->left->op == ONAME)
+ gn = n;
+ sube(l);
+ sube(r);
+ if(l != Z && cktype(n, n, TCGEN, 0))
+ l->type->link = n->type;
+ break;
+ case OAS:
+ sube(l);
+ sube(r);
+ if(r->op == ORETV){
+ n->left = new1(OTUPLE, l, r->right);
+ n->right = r->left;
+ n->left->type = n->type;
+ break;
+ }
+ if(cktype(r, n, TCGEN, 0)){
+ tcon(l, r->type);
+ n->type = r->type;
+ }
+ if(cktype(l, n, TCGEN, 1)){
+ tcon(r, l->type);
+ n->type = l->type;
+ }
+ break;
+ case OLT:
+ case OGE:
+ sube(l);
+ sube(r);
+ if(cktype(l, n, TCFD, 0) && isconst(r, 0)){
+ n->op = n->op == OLT ? OEQ : ONE;
+ r->op = ONIL;
+ r->type = l->type;
+ }
+ break;
+ case OGT:
+ case OLE:
+ sube(l);
+ sube(r);
+ if(cktype(r, n, TCFD, 0) && isconst(l, 0)){
+ n->op = n->op == OGT ? OEQ : ONE;
+ l->op = ONIL;
+ l->type = r->type;
+ }
+ break;
+ }
+}
+
+static void
+subs(Node *n, int blk, int aut)
+{
+ Node *l, *r;
+
+ if(n == Z)
+ return;
+ if(blk)
+ pushscope(n, SAUTO);
+ nearln = n->lineno;
+ l = n->left;
+ r = n->right;
+ switch(n->op){
+ default:
+ sube(n);
+ break;
+ case ONAME:
+ if(aut && n->kind != KEXP)
+ pushdcl(n, CAUTO);
+ if(cktype(n, n, TCALL, 0))
+ setdec(n->sym, n->type);
+ break;
+ case ODAS:
+ if(aut)
+ pushdcl(l, CAUTO);
+ subs(l, 0, aut);
+ if(cktype(l, n, TCALL, 0))
+ tcon(r, l->type);
+ break;
+ case OSBREAK:
+ case ONUL:
+ case OLABEL:
+ case OGOTO:
+ case OCONTINUE:
+ case OBREAK:
+ case OSET:
+ case OUSED:
+ break;
+ case OBLK:
+ subs(l, 1, aut);
+ break;
+ case OCASE:
+ subs(r, 1, aut);
+ break;
+ case OLIST:
+ subs(l, 0, aut);
+ subs(r, 0, aut);
+ break;
+ case ORETURN:
+ sube(l);
+ if(l != Z && cktype(l, n, TCGEN, 0)){
+ n->type = l->type;
+ tcon(curfn(), l->type);
+ }
+ retval(n);
+ break;
+ case OSWITCH:
+ case OWHILE:
+ case ODWHILE:
+ sube(l);
+ subs(r, 1, aut);
+ break;
+ case OIF:
+ sube(l);
+ subs(r->left, 1, aut);
+ subs(r->right, 1, aut);
+ break;
+ case OFOR:
+ sube(l->left);
+ sube(l->right->left);
+ sube(l->right->right);
+ subs(r, 1, aut);
+ break;
+ }
+ if(blk)
+ popscope();
+}
+
+static Node*
+finddec0(Sym *s, Node *n)
+{
+ Node *nn;
+
+ if(n == Z)
+ return ZZ;
+ switch(n->op){
+ case OLIST:
+ nn = finddec0(s, n->left);
+ if(nn != Z)
+ return nn;
+ return finddec0(s, n->right);
+ case OFUNC:
+ if(n->op != KEXP){
+ if(s == decsym(n))
+ return n;
+ return finddec0(s, n->right);
+ }
+ else
+ return ZZ;
+ case OPROTO:
+ case OIND:
+ case OARRAY:
+ return finddec0(s, n->left);
+ case ODOTDOT:
+ return ZZ;
+ case ONOOP:
+ case OPUSH:
+ case OPOP:
+ case OCODE:
+ case ODECE:
+ case ODECT:
+ return finddec0(s, n->right);
+ case ODECV:
+ case ODECF:
+ if(s == decsym(n->left) && !isfn(n->left->type))
+ return n->left;
+ return finddec0(s, n->right);
+ }
+ if(isdec(n)){
+ if(s == decsym(n) && !isfn(n->type))
+ return n;
+ return Z;
+ }
+ return ZZ;
+}
+
+static Node*
+finddec(Sym *s, int g)
+{
+ Node *n;
+ Scope *sc;
+
+ for(sc = scopes; sc != nil; sc = sc->nxt){
+ if(!g || sc->k == SGLOB){
+ n = finddec0(s, sc->n);
+ if(n != Z && n != ZZ)
+ return n;
+ }
+ }
+ return Z;
+}
+
+static void
+setdec(Sym *s, Type *t)
+{
+ Node *n;
+
+ if((n = finddec(s, 0)) != Z){
+ n->type = t;
+ if(n->op == ODAS){
+ n = n->left;
+ n->type = t;
+ }
+ n->sym->type = t;
+ }
+}
+
+typedef struct Syml Syml;
+
+struct Syml{
+ Sym *sym;
+ Syml *nxt;
+};
+
+typedef struct Symq Symq;
+
+struct Symq{
+ Syml *f;
+ Syml *r;
+};
+
+typedef struct Modl Modl;
+
+struct Modl{
+ char *mod;
+ int ld;
+ Modl *nxt;
+};
+
+static void
+prn(Node *n, int i)
+{
+ int j;
+
+ for(j = 0; j < i; j++)
+ print("\t");
+ if(n == Z){
+ print("Z\n");
+ return;
+ }
+ print("%s", onames[n->op]);
+ if(n->blk)
+ print(" block");
+ if(n->type == T)
+ print(" T");
+ else
+ print(" %s", tnames[n->type->etype]);
+ if(n->op == OCONST)
+ print(" %d", (int)n->vconst);
+ else if(n->op == OSTRING)
+ print(" %s", n->cstring);
+ else if(n->op == ONAME)
+ print(" %s", n->sym->name);
+ print("\n");
+ if(n->op != OLIST)
+ i++;
+ prn(n->left, i);
+ prn(n->right, i);
+}
+
+static int
+isbigv(vlong v)
+{
+ return v > 0xffffffff;
+}
+
+static int
+islbigv(vlong v)
+{
+ return v > 0x7fffffff || v < -0x7fffffff;
+}
+
+static int
+isuintv(vlong v)
+{
+ return !isbigv(v) && (v&0x80000000) != 0;
+}
+
+static int
+isadt(Type *t)
+{
+ return t != T && (t->etype == TSTRUCT || t->etype == TUNION);
+}
+
+static int
+isreal(Type *t)
+{
+ return t != T && (t->etype == TDOUBLE || t->etype == TFLOAT);
+}
+
+static int
+isbyte(Type *t)
+{
+ return t != T && (t->etype == TCHAR || t->etype == TUCHAR);
+}
+
+static int
+isshort(Type *t)
+{
+ return t != T && (t->etype == TSHORT || t->etype == TUSHORT);
+}
+
+static int
+isint(Type *t)
+{
+ return t != T && (t->etype == TINT || t->etype == TUINT);
+}
+
+static int
+islong(Type *t)
+{
+ return t != T && (t->etype == TLONG || t->etype == TULONG);
+}
+
+static int
+isbig(Type *t)
+{
+ return t != T && (t->etype == TVLONG || t->etype == TUVLONG);
+}
+
+static int
+isinteger(Type *t)
+{
+ return isbyte(t) || isshort(t) || isint(t) || islong(t) || isbig(t);
+}
+
+static int
+isptr(Type *t)
+{
+ return t != T && (t->etype == TIND || t->etype == TARRAY || t->etype == TFUNC);
+}
+
+static int
+isscalar(Type *t)
+{
+ return t != T && !isadt(t) && t->etype != TTUPLE;
+}
+
+static int
+isvoid(Type *t)
+{
+ return t == T || t->etype == TVOID;
+}
+
+static int
+isnum(Type *t)
+{
+ return t != T && isscalar(t) && !isptr(t) && !isvoid(t);
+}
+
+static int
+isarray(Type *t)
+{
+ return t != T && (t->etype == TARRAY || (t->etype == TIND && !isadt(t->link)));
+}
+
+static int
+isstr(Type *t)
+{
+ return t != T && (t->etype == TSTRING || isarray(t) && isbyte(t->link));
+}
+
+static int
+isfn(Type *t)
+{
+ return t != T && t->etype == TFUNC;
+}
+
+static int
+iscastable(Type *t, Type *tt)
+{
+ return t != T && (!isptr(t) || isarray(t) && isbyte(t->link) && isstr(tt));
+}
+
+static int
+isname(Node *n)
+{
+ return n->op == ONAME;
+}
+
+static int
+isstring(Node *n)
+{
+ return n->op == OSTRING || n->op == OLSTRING || n->op == ONAME && n->sym->tenum != T && n->sym->tenum->etype == TIND;
+}
+
+static int
+isnil(Node *n)
+{
+ if(!isptr(n->type))
+ return 0;
+ while(n->op == OCAST)
+ n = n->left;
+ return n->op == OCONST && n->vconst == 0 || n->op == ONIL;
+}
+
+static int
+isconst(Node *n, vlong v)
+{
+ while(n->op == OCAST)
+ n = n->left;
+ return n->op == OCONST && n->vconst == v;
+}
+
+static Node*
+cknil(Node *n)
+{
+ if(isconst(n, 0))
+ n->op = ONIL;
+ return n;
+}
+
+static int
+cktype(Node *n, Node *t, int mask, int lev)
+{
+ int g, m, m0;
+
+ g = t->garb > lev;
+ m = marked(n->type) & mask;
+ if(n->op == ONAME){
+ m0 = marked(n->sym->type) & mask;
+ if(m && !m0){
+ n->sym->type = n->type;
+ if(!g)
+ again = 1;
+ }
+ if(!m && m0){
+ n->type = n->sym->type;
+ if(!g)
+ again = 1;
+ }
+ m |= m0;
+ }
+ if(m && t->garb < 2)
+ t->garb++;
+ return m && !g ? m : 0;
+}
+
+int
+isconsym(Sym *s)
+{
+ switch(s->class){
+ case CXXX:
+ case CTYPEDEF:
+ return 1;
+ case CEXTERN:
+ case CGLOBL:
+ case CSTATIC:
+ case CLOCAL:
+ return s->type != T && s->type->etype == TENUM;
+ }
+ return -1;
+}
+
+static void genstart(void);
+
+static char*
+mprolog[] =
+{
+ "%%: module",
+ "{",
+ "\tPATH: con \"%%%.dis\";",
+ "",
+ nil
+};
+
+static char*
+mepilog[] =
+{
+ "};",
+ nil
+};
+
+static char*
+bprolog[] =
+{
+ "implement %%;",
+ "",
+ "include \"draw.m\";",
+ "",
+ "%%: module",
+ "{",
+ " init: fn(nil: ref Draw->Context, argl: list of string);",
+ "};",
+ "",
+ nil
+};
+
+static char*
+bmprolog[] =
+{
+ "implement %%;",
+ "",
+ "include \"draw.m\";",
+ "",
+ nil
+};
+
+static char*
+bepilog[] =
+{
+ nil
+};
+
+static void
+pgen0(char **txt)
+{
+ int sub;
+ char *b, *s, *t, **p;
+
+ p = txt;
+ for(;;){
+ s = *p++;
+ if(s == nil)
+ break;
+ sub = 0;
+ for(t = s; *t != 0; t++){
+ if(*t == '%' && *(t+1) == '%'){
+ sub = 1;
+ break;
+ }
+ }
+ if(sub){
+ strcpy(buf, s);
+ b = buf;
+ for(t = s; *t != 0; t++){
+ if(*t == '%' && *(t+1) == '%'){
+ if(*(t+2) == '%'){
+ outmod(mbuf, 0);
+ t++;
+ }
+ else
+ outmod(mbuf, 1);
+ strcpy(b, mbuf);
+ b += strlen(mbuf);
+ t++;
+ }
+ else
+ *b++ = *t;
+ }
+ *b = 0;
+ prline(buf);
+ }
+ else
+ prline(s);
+ }
+}
+
+static char*
+hasm()
+{
+ outmod(mbuf, 0);
+ strcat(mbuf, ".m");
+ if(exists(mbuf))
+ return mbuf;
+ else if(domod){
+ outmod(buf, 0);
+ strcat(buf, ".h");
+ if(exists(buf))
+ return mbuf;
+ }
+ return nil;
+}
+
+void
+pgen(int b)
+{
+ char **p;
+
+ if(!dolog())
+ return;
+ if(b)
+ p = hasm() ? bmprolog : bprolog;
+ else
+ p = mprolog;
+ pgen0(p);
+ if(b && passes)
+ genstart();
+ if(!b)
+ incind();
+}
+
+void
+epgen(int b)
+{
+ char **p;
+
+ /* output(INFINITY, 1); */
+ if(!dolog())
+ return;
+ if(b){
+ if(!passes)
+ genstart();
+ p = bepilog;
+ }
+ else
+ p = mepilog;
+ if(!b)
+ decind();
+ pgen0(p);
+}
+
+static int lastsec = 0;
+
+#define ASSOC 1
+#define RASSOC 2
+#define POSTOP 4
+
+#define LEFT 1
+#define RIGHT 2
+#define PRE 4
+#define POST 8
+
+static int space[] = { 0, 0, 2, 0, 4, 5, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+static struct{
+ char *name;
+ int prec;
+ int kind;
+} ops[] = {
+ "", 0, 0, /* ONOOP */
+ "", 16, 0, /* OXXX, */
+ "+", 12, ASSOC, /* OADD, */
+ "&", 14, RASSOC, /* OADDR, */
+ "&", 8, ASSOC, /* OAND, */
+ "&&", 5, ASSOC, /* OANDAND, */
+ "", 16, 0, /* OARRAY, */
+ "=", 2, RASSOC, /* OAS, */
+ "=", 2, RASSOC, /* OASI, */
+ "+=", 2, RASSOC, /* OASADD, */
+ "&=", 2, RASSOC, /* OASAND, */
+ "<<=", 2, RASSOC, /* OASASHL, */
+ ">>=", 2, RASSOC, /* OASASHR, */
+ "/=", 2, RASSOC, /* OASDIV, */
+ "<<", 11, 0, /* OASHL, */
+ ">>", 11, 0, /* OASHR, */
+ "/=", 2, RASSOC, /* OASLDIV, */
+ "%=", 2, RASSOC, /* OASLMOD, */
+ "*=", 2, RASSOC, /* OASLMUL, */
+ ">>=", 2, RASSOC, /* OASLSHR, */
+ "%=", 2, RASSOC, /* OASMOD, */
+ "*=", 2, RASSOC, /* OASMUL, */
+ "|=", 2, RASSOC, /* OASOR, */
+ "-=", 2, RASSOC, /* OASSUB, */
+ "^=", 2, RASSOC, /* OASXOR, */
+ "", -1, 0, /* OBIT, */
+ "", -1, 0, /* OBREAK, */
+ "", -1, 0, /* OCASE, */
+ "", 14, RASSOC, /* OCAST, */
+ "", 1, ASSOC, /* OCOMMA, */
+ "", 3, RASSOC, /* OCOND, */
+ "", 16, 0, /* OCONST, */
+ "", -1, 0, /* OCONTINUE, */
+ "/", 13, 0, /* ODIV, */
+ ".", 15, 0, /* ODOT, */
+ "...", 16, 0, /* ODOTDOT, */
+ "", -1, 0, /* ODWHILE, */
+ "", -1, 0, /* OENUM, */
+ "==", 9, 0, /* OEQ, */
+ "", -1, 0, /* OFOR, */
+ "", 15, 0, /* OFUNC, */
+ ">=", 10, 0, /* OGE, */
+ "", -1, 0, /* OGOTO, */
+ ">", 10, 0, /* OGT, */
+ ">", 10, 0, /* OHI, */
+ ">=", 10, 0, /* OHS, */
+ "", -1, 0, /* OIF, */
+ "*", 14, RASSOC, /* OIND, */
+ "", -1, 0, /* OINDREG, */
+ "", 16, 0, /* OINIT, */
+ "", -1, 0, /* OLABEL, */
+ "/", 13, 0, /* OLDIV, */
+ "<=", 10, 0, /* OLE, */
+ "", 16, 0, /* OLIST, */
+ "%", 13, 0, /* OLMOD, */
+ "*", 13, ASSOC, /* OLMUL, */
+ "<", 10, 0, /* OLO, */
+ "<=", 10, 0, /* OLS, */
+ ">>", 11, 0, /* OLSHR, */
+ "<", 10, 0, /* OLT, */
+ "%", 13, 0, /* OMOD, */
+ "*", 13, ASSOC, /* OMUL, */
+ "", 16, 0, /* ONAME, */
+ "!=", 9, 0, /* ONE, */
+ "!", 14, RASSOC, /* ONOT, */
+ "|", 6, ASSOC, /* OOR, */
+ "||", 4, ASSOC, /* OOROR, */
+ "--", 14, RASSOC|POSTOP, /* OPOSTDEC, */
+ "++", 14, RASSOC|POSTOP, /* OPOSTINC, */
+ "--", 14, RASSOC, /* OPREDEC, */
+ "++", 14, RASSOC, /* OPREINC, */
+ "", 16, 0, /* OPROTO, */
+ "", -1, 0, /* OREGISTER, */
+ "", 0, 0, /* ORETURN, */
+ "SET", -1, 0, /* OSET, */
+ "signof", 14, RASSOC, /* OSIGN, */
+ "sizeof", 14, RASSOC, /* OSIZE, */
+ "", 16, 0, /* OSTRING, */
+ "", 16, 0, /* OLSTRING, */
+ "", 16, 0, /* OSTRUCT, */
+ "-", 12, 0, /* OSUB, */
+ "", -1, 0, /* OSWITCH, */
+ "", 16, 0, /* OUNION, */
+ "USED", -1, 0, /* OUSED, */
+ "", -1, 0, /* OWHILE, */
+ "^", 7, ASSOC, /* OXOR, */
+ "-", 14, RASSOC, /* ONEG, */
+ "~", 14, RASSOC, /* OCOM, */
+ "", 16, 0, /* OELEM, */
+ "", -1, 0, /* OTST, */
+ "", -1, 0, /* OINDEX, */
+ "", -1, 0, /* OFAS, */
+ "", -1, 0, /* OBLK */
+ "+", 14, RASSOC, /* OPOS */
+ "", -1, 0, /* ONUL */
+ ".", 15, 0, /* ODOTIND */
+ "", 15, 0, /* OARRIND */
+ "", -1, 0, /* ODAS */
+ ":=", 2, RASSOC, /* OASD */
+ "", 16, 0, /* OIOTA */
+ "", 14, RASSOC, /* OLEN */
+ "", 17, 0, /* OBRACKET */
+ "", 14, RASSOC, /* OREF */
+ "", 14, RASSOC, /* OARRAYOF */
+ "", 15, 0, /* OSLICE */
+ "&", 14, RASSOC, /* OSADDR, */
+ "", 16, 0, /* ONIL */
+ "", 16, 0, /* OS2AB */
+ "", 16, 0, /* OAB2S */
+ "", 16, 0, /* OFILDES */
+ ".", 15, 0, /* OFD */
+ "", 16, 0, /* OTUPLE */
+ ".", 15, 0, /* OT0 */
+ "", 15, 0, /* ORETV */
+ "+", 12, ASSOC, /* OCAT */
+ "", -1, 0, /* OSBREAK, */
+ ".", 15, 0, /* OLDOT */
+ "->", 15, 0, /* OMDOT */
+ nil, -1, 0, /* OCODE */
+ nil, -1, 0, /* ODECE */
+ nil, -1, 0, /* ODECT */
+ nil, -1, 0, /* ODECV */
+ nil, -1, 0, /* ODECF */
+ nil, -1, 0, /* OPUSH */
+ nil, -1, 0, /* OPOP */
+ "", -1, 0, /* OEND */
+};
+
+#define COMPLEX 32
+
+#define NOBR 2
+#define NOIN 4
+#define YESBR 8
+#define NONL 16
+#define NOENL 32
+
+enum{
+ LNONE,
+ LSTRLEN,
+ LSTRCMP,
+ LSTRCPY,
+ LSTRCAT,
+ LSTRNCMP,
+ LSTRNCPY,
+ LSTRNCAT,
+ LSTRDUP,
+ LMEMMOVE,
+ LMALLOC,
+ LFREE,
+ LEXIT,
+ LCLOSE,
+ LATOI,
+ LATOL,
+ LATOF,
+ LPRINT,
+ LFPRINT,
+ LSPRINT,
+ LSELF,
+};
+
+static int tmp;
+
+static void egen(Node*, int, int);
+static Node* buildcases(Node*);
+static void tdgen(Node *, int);
+static Node* cfind(Node*);
+static Node* cgen(Node*, Node*);
+static void cgen0(Node*, Node*);
+static int lteq(Type*, Type*);
+static Type* ntype(Node*);
+static int rewe(Node*, Type*, int);
+static void rewlc(Node*, int, Type*);
+static Node* con(vlong);
+static void clrbrk(Node*);
+static int hasbrk(Node*);
+static int isgen(char*);
+static int simple(Node*);
+static void pfmt(char*);
+static void lpfmt(ushort*);
+static int lline(Node*);
+static void args(Node*);
+static void addmodn(Sym*);
+static void scomplex(Node*);
+static void mset(Node*);
+
+static Node *lastd;
+
+static int
+rev(int op)
+{
+ switch(op){
+ case OLT: return OGT;
+ case OLE: return OGE;
+ case OGT: return OLT;
+ case OGE: return OLE;
+ }
+ return op;
+}
+
+void
+newsec(int l)
+{
+ if(l != 1 && lastd != Z){
+ tdgen(lastd, 1);
+ lastd = Z;
+ }
+ if(l != 2)
+ etgen2(nil);
+ if(lastsec && l != lastsec)
+ newline();
+ lastsec = l;
+}
+
+static Node*
+defval(Type *t)
+{
+ Node *n;
+
+ if(t == T)
+ t = types[TINT];
+ n = con(0);
+ n->type = types[TINT];
+ n->kind = KDEC;
+ switch(t->etype){
+ case TFLOAT:
+ case TDOUBLE:
+ n->type = types[TDOUBLE];
+ n->fconst = 0.0;
+ n->cstring = "0.0";
+ return n;
+ default:
+ break;
+ case TIND:
+ case TFUNC:
+ case TARRAY:
+ n->type = typ1(TIND, types[TVOID]);
+ return n;
+ case TVOID:
+ case TSTRUCT:
+ case TUNION:
+ free(n);
+ return Z;
+ }
+ if(!lteq(n->type, t)){
+ n = new1(OCAST, n, Z);
+ n->type = t;
+ }
+ return n;
+}
+
+static int
+teq(Type *t1, Type *t2)
+{
+ if(t1 == t2)
+ return 1;
+ return sametype(t1, t2);
+/*
+ if(t1->etype != t2->etype)
+ return 0;
+ switch(t1->etype){
+ case TARRAY:
+ if(t1->width != t2->width)
+ return 0;
+ break;
+ case TFUNC:
+ if(!teq(t1->down, t2->down))
+ return 0;
+ break;
+ case TSTRUCT:
+ case TUNION:
+ return t1->link == t2->link;
+ case TENUM:
+ return 1;
+ }
+ return teq(t1->link, t2->link);
+*/
+}
+
+static int
+tequiv(Type *t1, Type *t2)
+{
+ if(!teq(t1, t2))
+ return 0;
+ if(t1->etype == TSTRUCT || t1->etype == TUNION)
+ return suename(t1) == suename(t2);
+ return 1;
+}
+
+static int
+iteq(Type *t1, Type *t2)
+{
+ if(t1 == T || t2 == T)
+ return 0;
+ return t1->etype == TIND && (teq(t1->link, t2) || (t1->link->etype == TVOID && isnum(t2)));
+}
+
+static Type *
+ltype(Type *t)
+{
+ switch(t->etype){
+ case TUCHAR:
+ return types[TCHAR];
+ case TSHORT:
+ case TUSHORT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TENUM:
+ return types[TINT];
+ case TUVLONG:
+ return types[TVLONG];
+ case TFLOAT:
+ return types[TDOUBLE];
+ default:
+ return t;
+ }
+ return t;
+}
+
+static int
+lteq(Type *t1, Type *t2)
+{
+ if(t1 == T || t2 == T)
+ return 0;
+ if(t1 == t2)
+ return 1;
+ if(t1->etype == TIND && t2->etype == TIND)
+ return lteq(t1->link, t2->link);
+ return sametype(ltype(t1), ltype(t2));
+}
+
+static Type*
+tcp(Type *t)
+{
+ Type *nt;
+
+ if(t == T)
+ return T;
+ nt = typ1(TXXX, T);
+ *nt = *t;
+ return nt;
+}
+
+static Type*
+tuple(Type *t1, Type *t2)
+{
+ Type *t, **at, *l;
+
+ if(t1 == T || t1->etype == TVOID)
+ return tcp(t2);
+ if(t2 == T || t2->etype == TVOID)
+ return tcp(t1);
+ if(t2->etype == TTUPLE)
+ diag(Z, "bad tuple type");
+ t = typ1(TTUPLE, T);
+ at = &t->link;
+ if(t1->etype == TTUPLE){
+ for(l = t1->link; l != T; l = l->down){
+ *at = tcp(l);
+ at = &(*at)->down;
+ }
+ }
+ else{
+ *at = tcp(t1);
+ at = &(*at)->down;
+ }
+ *at = tcp(t2);
+ return t;
+}
+
+static Sym*
+sue(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 S;
+}
+
+static void
+pranon(int i)
+{
+ prid("anon_");
+ prnum(i+1, KDEC, T);
+}
+
+static int
+dotpath(Sym *s, Type *t, int pr)
+{
+ int i;
+ Type *t1;
+
+ if(t == T)
+ return 0;
+ for(t1 = t->link; t1 != T; t1 = t1->down){
+ if(t1->sym == s){
+ if(pr){
+ prdelim(".");
+ prsym(s, 0);
+ }
+ return 1;
+ }
+ }
+ i = 0;
+ for(t1 = t->link; t1 != T; t1 = t1->down){
+ if(t1->sym == S){
+ i++;
+ if(typesu[t1->etype] && sametype(s->type, t1)){
+ if(pr){
+ prdelim(".");
+ pranon(i-1);
+ }
+ return 1;
+ }
+ }
+ }
+ i = 0;
+ for(t1 = t->link; t1 != T; t1 = t1->down){
+ if(t1->sym == S){
+ i++;
+ if(typesu[t1->etype] && dotpath(s, t1, 0)){
+ if(pr){
+ prdelim(".");
+ pranon(i-1);
+ dotpath(s, t1, 1);
+ }
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static Sym*
+suename(Type *t)
+{
+ Sym *s;
+
+ s = sue(t->link);
+ if(s != S)
+ return s;
+ else if(t->tag != S)
+ return t->tag;
+ else if(t->sym != S)
+ return t->sym;
+ return S;
+}
+
+static int
+cycle(Type *t, Type *base)
+{
+ int r;
+ Type *l;
+
+ if(t->vis){
+ /* sametype() does structural comparison so have to check names */
+ if(t == base || tequiv(t, base))
+ return 1;
+ return 0;
+ }
+ r = 0;
+ t->vis = 1;
+ switch(t->etype){
+ case TIND:
+ case TARRAY:
+ r = cycle(t->link, base);
+ break;
+ case TSTRUCT:
+ case TUNION:
+ case TTUPLE:
+ for(l = t->link; l != T; l = l->down)
+ r |= cycle(l, base);
+ break;
+ }
+ t->vis = 0;
+ return r;
+}
+
+static void
+addnode(int op, Node *n)
+{
+ Node *nn;
+
+ nn = new1(OXXX, Z, Z);
+ *nn = *n;
+ n->op = op;
+ n->left = nn;
+ n->right = Z;
+ n->type = nn->type;
+}
+
+static void
+cast(Node *n, Type *t)
+{
+ addnode(OCAST, n);
+ n->type = t;
+}
+
+static void
+intcast(Node *n)
+{
+ if(isptr(n->type)){
+ addnode(ONE, n);
+ n->right = con(0);
+ n->right->type = n->left->type;
+ n->type = types[TINT];
+ }
+ else
+ cast(n, types[TINT]);
+}
+
+static void
+strcast(Node *n)
+{
+ cast(n, stringtype);
+}
+
+static void
+bptr(Node *n)
+{
+ if(n == Z)
+ return;
+ switch(n->op){
+ default:
+ if(!lteq(n->type, types[TINT]))
+ intcast(n);
+ break;
+ case ONOT:
+ if(!lteq(n->left->type, types[TINT])){
+ intcast(n->left);
+ if(n->left->op == ONE){
+ n->left->op = OEQ;
+ *n = *n->left;
+ }
+ }
+ break;
+ case OANDAND:
+ case OOROR:
+ bptr(n->left);
+ bptr(n->right);
+ break;
+ case OCOND:
+ bptr(n->right->left);
+ bptr(n->right->right);
+ break;
+ }
+}
+
+static void
+bcomplex(Node *n)
+{
+ if(n == Z)
+ return;
+ if(!passes)
+ complex(n);
+ bptr(n);
+}
+
+static void
+ecomplex(Node *n)
+{
+ if(!passes)
+ complex(n);
+ rewe(n, T, 0);
+}
+
+static void
+becomplex(Node *n)
+{
+ bcomplex(n);
+ rewe(n, T, 0);
+}
+
+static void
+tgen(Type *t, int dec, int arinit)
+{
+ Type *l;
+
+ if(t == T)
+ return;
+ switch(t->etype){
+ case TXXX:
+ prid("int");
+ break;
+ case TCHAR:
+ case TUCHAR:
+ prid("byte");
+ break;
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TENUM:
+ prid("int");
+ break;
+ case TVLONG:
+ case TUVLONG:
+ prid("big");
+ break;
+ case TFLOAT:
+ case TDOUBLE:
+ prid("real");
+ break;
+ case TIND:
+ if(strings == 2 && t->link && t->link->etype == TCHAR){
+ prid("string");
+ break;
+ }
+ if(isadt(t->link) || t->link->etype == TFUNC)
+ prid("ref ");
+ else
+ prid("array of ");
+ if(t->link && t->link->etype == TVOID){
+ prid("byte");
+ prcom("was void*", Z);
+ }
+ else
+ tgen(t->link, 1, 0);
+ break;
+ case TFUNC:
+ if(0){
+ prid("int");
+ prcom("was function", Z);
+ break;
+ }
+ prid("fn");
+ prdelim("(");
+ for(l = t->down; l != T; l = l->down){
+ if(l->etype == TVOID && l->down == T)
+ break;
+ if(l->etype == TDOT){
+ prcom("was ...", Z);
+ break;
+ }
+ if(l->sym != S)
+ prsym(l->sym, 0);
+ else
+ prid("nil");
+ prdelim(": ");
+ tgen(l, 1, 0);
+ if(l->down != T && l->down->etype != TDOT)
+ prdelim(", ");
+ }
+ /* tgen(t->down, dec, 0, 0); */
+ prdelim(")");
+ if(!isvoid(t->link)){
+ prdelim(": ");
+ tgen(t->link, dec, 0);
+ }
+ break;
+ case TARRAY:
+ prid("array");
+ if(t->width == LARR)
+ t->width = LARR;
+ else if(dec){
+ if(t->nwidth != Z)
+ prcom("array index was ", t->nwidth);
+ else if(t->width != 0){
+ sprint(buf, "array index was %ld", t->width/t->link->width);
+ prcom(buf, Z);
+ }
+ }
+ else{
+ prdelim("[");
+ if(t->nwidth != Z)
+ egen(t->nwidth, ONOOP, PRE);
+ else if(t->width != 0)
+ prnum(t->width/t->link->width, KDEC, T);
+ prdelim("]");
+ }
+ prdelim(" of ");
+ if(!arinit)
+ tgen(t->link, 1, 0);
+ break;
+ case TVOID:
+ /* prid("void"); */
+ prid("byte");
+ prcom("was void", Z);
+ break;
+ case TSTRUCT:
+ case TUNION:
+ if(t->link != T && t->link->etype == TFD){
+ prid("Sys->FD");
+ usemod(sysop, 0);
+ }
+ else
+ prsym(suename(t), 1);
+ break;
+ case TTUPLE:
+ prdelim("(");
+ for(l = t->link; l != T; l = l->down){
+ tgen(l, dec, 0);
+ if(l->down != T)
+ prdelim(", ");
+ }
+ prdelim(")");
+ break;
+ case TDOT:
+ prdelim("...");
+ break;
+ case TSTRING:
+ prid("string");
+ break;
+ case TFD:
+ prid("fd");
+ break;
+ default:
+ diag(Z, "unknown type");
+ break;
+ }
+}
+
+static Type*
+typn(Type *t, int i)
+{
+ Type *l;
+
+ for(l = t->down; l != T && --i >= 0; l = l->down)
+ ;
+ return l;
+}
+
+void
+ttgen2(Type *t)
+{
+ Type *l;
+ Sym *s;
+ int anon = 0;
+
+ switch(t->etype){
+ case TSTRUCT:
+ case TUNION:
+ newsec(0);
+ output(t->lineno, 1);
+ s = suename(t);
+ if(isgen(s->name))
+ addmodn(s);
+ setmod(s);
+ prsym(s, 0);
+ prdelim(": ");
+ prid("adt");
+ prdelim("{");
+ if(t->etype == TUNION)
+ prcom("was union", Z);
+ newline();
+ incind();
+ t->vis = 1;
+ for(l = t->link; l != T; l = l->down){
+ output(l->lineno, 1);
+ if(l->nbits)
+ prcom("was bit field", Z);
+ if(l->sym != S)
+ prsym(l->sym, 0);
+ else
+ pranon(anon++);
+ prdelim(": ");
+ if(cycle(l, t))
+ prid("cyclic ");
+ tgen(l, 1, 0);
+ prdelim(";");
+ newline();
+ }
+ t->vis = 0;
+ decind();
+ prdelim("};");
+ newline();
+ newline();
+ break;
+ default:
+ break;
+ }
+}
+
+static int
+canjoin(Node *n, Node *nn)
+{
+ return teq(n->type, nn->type) && isname(n) && isname(nn) && n->type->etype != TARRAY;
+}
+
+void
+vtgen2(Node *n)
+{
+ int t, c, comma = 0;
+ Node *nn;
+ Sym *s;
+
+ nn = n;
+ if(n->op == ODAS)
+ nn = n->left;
+ if(nn->type == T || nn->sym == S)
+ return;
+ t = nn->type->etype;
+ c = nn->sym->class;
+ if(0 && c == CTYPEDEF){
+ /* egen(nn, ONOOP, PRE); */
+ /* tdgen(n, 1, 0); */
+ if(isadt(n->type)){
+ s = suename(n->type);
+ if(isgen(s->name)){
+ s->lname = nn->sym->name;
+ ttgen2(n->type);
+ }
+ }
+ }
+ if(c != CGLOBL && c != CSTATIC && c != CLOCAL && c != CEXREG)
+ return;
+ newsec(1);
+ if(lastd != Z){
+ if(t != TFUNC && canjoin(lastd, n))
+ comma = 1;
+ else
+ tdgen(lastd, 1);
+ }
+ output(nn->lineno, 1);
+ if(t == TFUNC){
+ if(ism()){
+ setmod(nn->sym);
+ egen(nn, ONOOP, PRE);
+ tdgen(n, 1);
+ }
+ lastd = Z;
+ return;
+ }
+ if(comma)
+ prdelim(", ");
+ if(nn->op != ONAME)
+ diag(nn, "internal: not name in vtgen");
+ setmod(nn->sym);
+ prsym(nn->sym, 0);
+ /* egen(nn, ONOOP, PRE); */
+ /* tdgen(n, 1, 0); */
+ lastd = n;
+ if(n->op == ODAS)
+ rewe(n->right, T, 1);
+}
+
+static void minseq(Syml*);
+
+static Node*
+con(vlong v)
+{
+ int neg = 0;
+ Node *n;
+
+ if(v < 0){
+ neg = 1;
+ v = -v;
+ }
+ n = new1(OCONST, Z, Z);
+ n->vconst = v;
+ n->kind = KDEC;
+ n->type = types[TINT];
+ if(neg)
+ n = new1(ONEG, n, Z);
+ return n;
+}
+
+/*
+static Node*
+fcon(double v)
+{
+ int neg = 0;
+ Node *n;
+
+ if(v < 0){
+ neg = 1;
+ v = -v;
+ }
+ n = new1(OCONST, Z, Z);
+ n->fconst = v;
+ n->kind = KDEC;
+ n->type = types[TDOUBLE];
+ if(neg)
+ n = new1(ONEG, n, Z);
+ return n;
+}
+*/
+
+static Node*
+add(vlong v, Node *n)
+{
+ if(v == 0)
+ return n;
+ return new1(OADD, con(v), n);
+}
+
+static Node*
+addn(Node *n1, Node *n2)
+{
+ if(n1 == Z || n2 == Z)
+ return Z;
+ if(isconst(n1, 0))
+ return n2;
+ if(isconst(n2, 0))
+ return n1;
+ return new1(OADD, n1, n2);
+}
+
+static Node*
+mul(vlong v, Node *n)
+{
+ if(v == 0)
+ return con(0);
+ else if(v == 1)
+ return n;
+ else if(v == -1)
+ return new1(ONEG, n, Z);
+ return new1(OMUL, con(v), n);
+}
+
+static Node*
+mydiv(Node *n, vlong w)
+{
+ Node *nn;
+
+ if(w == 0)
+ return Z;
+ if(w == 1)
+ return n;
+ else if(w == -1)
+ return new1(ONEG, n, Z);
+ switch(n->op){
+ case OCONST:
+ if(n->vconst % w == 0){
+ n->vconst /= w;
+ if(n->left != Z && mydiv(n->left, w) == Z){
+ n->vconst *= w;
+ break;
+ }
+ return n;
+ }
+ break;
+ case OCAST:
+ return mydiv(n->left, w);
+ case OMUL:
+ nn = mydiv(n->right, w);
+ if(nn != Z){
+ if(isconst(nn, 1))
+ *n = *n->left;
+ return n;
+ }
+ nn = mydiv(n->left, w);
+ if(nn != Z){
+ if(isconst(nn, 1))
+ *n = *n->right;
+ return n;
+ }
+ break;
+ default:
+ break;
+ }
+ return Z;
+}
+
+static Node*
+iota(void)
+{
+ return new1(OIOTA, Z, Z);
+}
+
+static Node*
+symcon(Sym *s)
+{
+ Node *n;
+
+ if(s->nconst != Z)
+ return s->nconst;
+ n = con(s->vconst);
+ n->kind = s->kind;
+ return n;
+}
+
+#define ARITH 1
+#define GEOM 2
+
+static Syml*
+newsyml(Sym *s, Syml **frees)
+{
+ Syml *sl, *f;
+
+ if((f = *frees) != nil){
+ sl = f;
+ *frees = f->nxt;
+ }
+ else
+ sl = (Syml*)malloc(sizeof(Syml));
+ sl->sym = s;
+ sl->nxt = nil;
+ return sl;
+}
+
+static Syml*
+etseq(Syml *syml)
+{
+ int e, pio, io, comma;
+ vlong d, dd, v0, v1, v, t, tt;
+ Node *expr;
+ Sym *s;
+ Syml *sl, *lsl;
+
+ lsl = nil;
+ pio = io = ARITH|GEOM;
+ e = 0;
+ dd = 0;
+ for(sl = syml; sl != nil; sl = sl->nxt){
+ s = sl->sym;
+ if(isreal(s->tenum) || s->tenum->etype == TIND)
+ break;
+ if(e == 0)
+ v0 = s->vconst;
+ if(e == 1){
+ v1 = s->vconst;
+ d = v1-v0;
+ }
+ if(e > 0 && (v <= 0 || s->vconst != 2*v))
+ io &= ~GEOM;
+ if(0 && e > 1 && s->vconst-v != d)
+ io &= ~ARITH;
+ if(e > 1){
+ t = s->vconst-v;
+ tt = t-d;
+ if(e > 2 && tt != dd)
+ io &= ~ARITH;
+ else{
+ d = t;
+ dd = tt;
+ }
+ }
+ if(io == 0)
+ break;
+ v = s->vconst;
+ lsl = sl;
+ pio = io;
+ e++;
+ }
+ if(e < 2)
+ pio = 0;
+ if(pio&GEOM){
+ if(e < 3)
+ pio = 0;
+ }
+ else if(pio&ARITH){
+ int n;
+
+ if(d == 0 && dd == 0)
+ n = 2;
+ else if(dd == 0)
+ n = 3;
+ else
+ n = 4;
+ if(e < n || (dd&1) != 0)
+ pio = 0;
+ }
+ if(lsl == nil || pio == 0)
+ lsl = syml;
+ comma = 0;
+ for(sl = syml; sl != nil; sl = sl->nxt){
+ s = sl->sym;
+ nearln = s->lineno;
+ output(s->lineno, 1);
+ if(pio){
+ if(comma)
+ prdelim(", ");
+ setmod(s);
+ prsym(s, 0);
+ comma = 1;
+ }
+ else{
+ setmod(s);
+ prsym(s, 0);
+ prdelim(": ");
+ prid("con ");
+ if(isbyte(s->tenum) || isbig(s->tenum) && !islbigv(s->vconst) || !isbig(s->tenum) && isuintv(s->vconst)){
+ tgen(s->tenum, 1, 0);
+ prdelim(" ");
+ }
+ if(s->nconst != Z)
+ egen(s->nconst, ONOOP, PRE);
+ else if(s->kind == KCHR)
+ prchar(s->vconst);
+ else if(isreal(s->tenum))
+ prreal(s->fconst, s->cstring, s->kind);
+ else
+ prnum(s->vconst, s->kind, s->tenum);
+ prdelim(";");
+ newline();
+ }
+ if(sl == lsl)
+ break;
+ }
+ if(pio){
+ s = syml->sym;
+ prdelim(": ");
+ prid("con ");
+ if(isbyte(s->tenum) || isbig(s->tenum)){
+ tgen(s->tenum, 1, 0);
+ prdelim(" ");
+ }
+ if(pio&GEOM){
+ if(v0 == 0 || v0 == 1 || v0 == -1)
+ expr = mul(v0, new1(OASHL, con(1), iota()));
+ else
+ expr = new1(OMUL, symcon(s), new1(OASHL, con(1), iota()));
+ }
+ else if(d == 0 && dd == 0)
+ expr = symcon(s);
+ else if(dd == 0)
+ expr = add(v0, mul(d, iota()));
+ else
+ expr = add(v0, new1(OADD, mul(v1-dd/2-v0, iota()), mul(dd/2, new1(OMUL, iota(), iota()))));
+ complex(expr);
+ expr = ckneg(expr);
+ egen(expr, ONOOP, PRE);
+ prdelim(";");
+ newline();
+ }
+ return lsl->nxt;
+}
+
+static void
+adde(Syml *sl, Symq *q)
+{
+ if(q->f == nil)
+ q->f = sl;
+ else
+ q->r->nxt = sl;
+ q->r = sl;
+}
+
+static void
+freeq(Symq *q, Syml **frees)
+{
+ if(q->f){
+ q->r->nxt = *frees;
+ *frees = q->f;
+ q->f = q->r = nil;
+ }
+}
+
+static void
+etgen2(Sym *s)
+{
+ Syml *sl;
+ static Syml *frees;
+ static Symq symq, symq1;
+
+ if(s != nil){
+ newsec(2);
+ sl = newsyml(s, &frees);
+ adde(sl, &symq);
+ if(isinteger(s->tenum) && isbigv(s->vconst) && !isbig(s->tenum))
+ s->tenum = types[TVLONG];
+ return;
+ }
+ /* end of enums */
+ if(symq.f && symq.f == symq.r){ /* try to merge with other singletons */
+ adde(symq.f, &symq1);
+ symq.f = symq.r = nil;
+ return;
+ }
+ if(symq1.f){
+ for(sl = symq1.f; sl != nil; sl = etseq(sl))
+ ;
+ freeq(&symq1, &frees);
+ }
+ if(symq.f){
+ for(sl = symq.f; sl != nil; sl = etseq(sl))
+ ;
+ freeq(&symq, &frees);
+ }
+}
+
+static void
+lgen(Node *n, int br, int first)
+{
+ if(br)
+ prdelim("(");
+ if(n == Z){
+ if(br)
+ prdelim(")");
+ return;
+ }
+ if(n->op == OLIST || n->op == OTUPLE){
+ lgen(n->left, 0, first);
+ lgen(n->right, 0, 0);
+ }
+ else if(n->op != ODOTDOT){
+ if(!first)
+ prdelim(", ");
+ egen(n, ONOOP, PRE);
+ }
+ else
+ prcom("was ...", Z);
+ if(br)
+ prdelim(")");
+}
+
+static void
+preced(int op1, int op2, int s, int c)
+{
+ int p1, p2, k1, k2, br;
+ char buf[2];
+
+ br = 0;
+ p1 = ops[op1].prec;
+ p2 = ops[op2].prec;
+ if(p1 < 0 || p2 < 0)
+ diag(Z, "-ve precedence");
+ if(p1 > p2)
+ br = 1;
+ else if(p1 == p2){
+ k1 = ops[op1].kind;
+ k2 = ops[op2].kind;
+ if(op1 == op2){
+ if(k1&RASSOC)
+ br = s == LEFT;
+ else
+ br = s == RIGHT && !(k1&ASSOC);
+ }
+ else{
+ if(k1&RASSOC)
+ br = s == LEFT;
+ else
+ br = s == RIGHT && op1 != OADD;
+
+ if(k1&POSTOP && !(k2&POSTOP))
+ br = 1;
+
+ /* funny case */
+ if(op2 == OMDOT && s == LEFT && (op1 == ODOT || op1 == ODOTIND))
+ br = 1;
+ }
+ }
+ if(br){
+ buf[0] = c;
+ buf[1] = '\0';
+ prdelim(buf);
+ }
+}
+
+static void
+egen(Node *n, int op0, int side)
+{
+ int op, p;
+ Type *t;
+ Node *nn;
+
+ if(n == Z){
+ if(op0 == OBRACKET)
+ prdelim("()");
+ return;
+ }
+ if(n->op == OCONST && n->left != Z){ /* actual node in source */
+ n->left->type = n->type;
+ n = n->left;
+ }
+ if((n->op == OSTRING || n->op == OLSTRING) && n->left != Z) /* actual node in source */
+ n = n->left;
+ if(n->op == OCAST && (lteq(n->type, n->left->type) || isnil(n) || !iscastable(n->type, n->left->type))){
+ if(isnil(n))
+ prid("nil");
+ else
+ egen(n->left, op0, side);
+ return;
+ }
+ if(n->op == ONAME && arrow(n->sym))
+ n->op = OMDOT;
+ if(n->op != OLIST)
+ output(n->lineno, 0);
+ op = n->op;
+ preced(op0, op, side, '(');
+ switch(op){
+ case OLIST:
+ case OTUPLE:
+ lgen(n, 1, 1);
+ break;
+ case OIOTA:
+ prid("iota");
+ break;
+ case OMDOT:
+ case ONAME:
+ case OXXX:
+ prsym(n->sym, 1);
+ break;
+ case OCONST:
+ if(n->kind == KCHR)
+ prchar(n->vconst);
+ else if(isreal(n->type))
+ prreal(n->fconst, n->cstring, n->kind);
+ else if(isnil(n))
+ prid("nil");
+ else
+ prnum(n->vconst, n->kind, n->type);
+ if(n->right != Z)
+ prcom("was ", n->right);
+ break;
+ case OSTRING:
+ prstr(n->cstring);
+ break;
+ case OLSTRING:
+ prlstr(n->rstring);
+ break;
+ case OCOND:
+ egen(n->left, op, POST);
+ prdelim(" ? ");
+ egen(n->right->left, op, PRE|POST);
+ prdelim(" : ");
+ egen(n->right->right, op, PRE);
+ prcom("?", Z);
+ break;
+ case OCOMMA:
+ if(op0 != OCOMMA)
+ prdelim("(");
+ egen(n->left, op, LEFT);
+ prdelim(", ");
+ egen(n->right, op, RIGHT);
+ if(op0 != OCOMMA)
+ prdelim(")");
+ break;
+ case OLDOT:
+ egen(n->left, OMOD, LEFT); /* any precedence 13 operator */
+ prdelim(".");
+ egen(n->right, op, RIGHT);
+ break;
+ default:
+ p = ops[op].prec;
+ egen(n->left, op, LEFT);
+ if(space[p])
+ prdelim(" ");
+ prdelim(ops[op].name);
+ if(space[p])
+ prdelim(" ");
+ egen(n->right, op, RIGHT);
+ break;
+ case OIND: case OADDR: case OSADDR:
+ case OPOS: case ONEG:
+ case ONOT: case OCOM:
+ case OPREINC: case OPREDEC:
+ if(op == OADDR){
+ n->op = OSADDR;
+ if(!isfn(n->left->type))
+ prcom("was ", n);
+ }
+ else
+ prdelim(ops[op].name);
+ egen(n->left, op, PRE);
+ break;
+ case OPOSTINC: case OPOSTDEC:
+ egen(n->left, op, POST);
+ prdelim(ops[op].name);
+ break;
+ case ODOT:
+ egen(n->left, op, LEFT);
+ dotpath(n->sym, n->left->type, 1);
+ /* prdelim(ops[op].name); */
+ /* prsym(n->sym, 0); */
+ break;
+ case ODOTIND:
+ egen(n->left, op, LEFT);
+ if(isadt(n->left->type))
+ dotpath(n->sym, n->left->type, 1); /* type may be demoted arg */
+ else
+ dotpath(n->sym, n->left->type->link, 1);
+ /* prdelim(ops[op].name); */
+ /* prsym(n->sym, 0); */
+ break;
+ case OARRIND:
+ egen(n->left, op, LEFT);
+ prdelim("[");
+ egen(n->right, ONOOP, RIGHT);
+ prdelim("]");
+ if(n->right->op == OCONST && n->right->vconst < 0)
+ prcom("negative array index", Z);
+ break;
+ case OLEN:
+ prid("len ");
+ egen(n->right, op, PRE);
+ break;
+ case OREF:
+ prid("ref ");
+ tgen(n->type->link, 0, 0);
+ break;
+ case OARRAYOF:
+ prid("array");
+ prdelim("[");
+ egen(n->left, ONOOP, LEFT);
+ prdelim("]");
+ prid(" of ");
+ tgen(n->type->link, 0, 0);
+ break;
+ case OSLICE:
+ egen(n->left, op, LEFT);
+ prdelim("[");
+ egen(n->right->left, ONOOP, RIGHT);
+ prdelim(": ");
+ egen(n->right->right, ONOOP, RIGHT);
+ prdelim("]");
+ break;
+ case OFUNC:
+ if(n->kind == KEXP)
+ egen(n->left, op, LEFT);
+ else
+ prsym(n->left->sym, 0);
+ lgen(n->right, 1, 1);
+ if(n->kind != KEXP && !isvoid(n->left->type->link)){
+ prdelim(": ");
+ tgen(n->left->type->link, 0, 0);
+ }
+ break;
+ case ONIL:
+ prid("nil");
+ break;
+ case OCAST:
+ if(isnil(n))
+ prid("nil");
+ else if(iscastable(n->type, n->left->type)){
+ tgen(n->type, 0, 0);
+ prdelim(" ");
+ egen(n->left, op, RIGHT);
+ }
+ else
+ egen(n->left, op0, RIGHT);
+ break;
+ case OARRAY:
+ tgen(n->type, 0, 0);
+ egen(n->left, op, LEFT);
+ prdelim("[");
+ egen(n->right, ONOOP, RIGHT);
+ prdelim("]");
+ break;
+ case OSTRUCT:
+ case OUNION:
+ tgen(n->type, 0, 0);
+ lgen(n->left, 1, 1);
+ break;
+ case OELEM:
+ prdelim(".");
+ /* tgen(n->type, 0, 0, 0); */
+ prsym(n->sym, 0);
+ break;
+ case OSIZE:
+ case OSIGN:
+ prid(ops[op].name);
+ if(n->left != Z)
+ egen(n->left, OBRACKET, RIGHT);
+ else{
+ prdelim(" ");
+ prid(tnames[n->type->etype]);
+ if(typesu[n->type->etype] && n->type->tag){
+ prdelim(" ");
+ prid(n->type->tag->name);
+ }
+ }
+ break;
+ case OPROTO:
+ nn = n;
+ t = n->type;
+ n = protoname(n);
+ if(n != Z)
+ t = n->type;
+ else
+ t = prototype(nn->left, t);
+ if(!isvoid(t) || n != Z){
+ if(n == Z)
+ prid("nil");
+ else if(n->op == ODOTDOT){
+ prcom("was ...", Z);
+ break;
+ }
+ else
+ prsym(n->sym, 0);
+ /* egen(n, ONOOP, PRE); */
+ prdelim(": ");
+ tgen(t, 1, 0);
+ }
+ break;
+ case ODOTDOT:
+ prid("...");
+ break;
+ case OINIT:
+ egen(n->left, ONOOP, PRE);
+ break;
+ case OS2AB:
+ prid("libc0->s2ab");
+ prdelim("(");
+ egen(n->left, ONOOP, PRE);
+ prdelim(")");
+ usemod(libcop, 1);
+ break;
+ case OAB2S:
+ prid("libc0->ab2s");
+ prdelim("(");
+ egen(n->left, ONOOP, PRE);
+ prdelim(")");
+ usemod(libcop, 1);
+ break;
+ case OFILDES:
+ prid("sys->fildes");
+ prdelim("(");
+ egen(n->left, ONOOP, PRE);
+ prdelim(")");
+ usemod(sysop, 1);
+ break;
+ case OFD:
+ egen(n->left, op, LEFT);
+ prdelim(ops[op].name);
+ prid("fd");
+ break;
+ case OT0:
+ egen(n->left, op, LEFT);
+ prdelim(ops[op].name);
+ prid("t0");
+ break;
+ case ORETV:
+ n->op = OAS;
+ nn = n->left;
+ p = isvoid(n->type) || n->type->etype != TTUPLE || n->type->mark == TCPC;
+ if(p)
+ n->left = n->right;
+ else
+ n->left = new1(OTUPLE, new1(ONIL, Z, Z), n->right);
+ n->right = nn;
+ n->left->type = n->type;
+ if(!p && op0 != ONOOP)
+ addnode(OT0, n);
+ egen(n, op0, side);
+ break;
+ case OCAT:
+ egen(n->left, op, LEFT);
+ prdelim(" + ");
+ egen(n->right, op, RIGHT);
+ break;
+ }
+ preced(op0, op, side, ')');
+}
+
+static int
+isexpr(Node *n, Type *t)
+{
+ if(n == Z)
+ return 0;
+ if(n->op == OLIST || n->op == OINIT || n->op == OSTRUCT)
+ return 0;
+ if(teq(t, n->type))
+ return 1;
+ return 0;
+}
+
+static Node *
+nxtval(Node *n, Node **nn)
+{
+ if(n == Z){
+ *nn = Z;
+ return Z;
+ }
+ if(n->op == OLIST){
+ *nn = n->right;
+ return n->left;
+ }
+ *nn = Z;
+ return n;
+}
+
+static Node*
+eagen(Node *n, Type *t, int ar, int *nz, int depth)
+{
+ int i, w, nw, down;
+ Type *t1;
+ Node *nn, *tn;
+
+ if(n != Z){
+ if(n->type == T && t == T){
+ egen(n, ONOOP, PRE);
+ if(ar){
+ prdelim(",");
+ newline();
+ }
+ return Z;
+ }
+ if(ar && n->op == OLIST && n->left->op == OARRAY){
+ egen(n->left->left, ONOOP, PRE);
+ prdelim(" => ");
+ n = n->right;
+ }
+ if(n->op == OLIST && n->left->op == OELEM){
+ prcom("cannot do ", n->left);
+ n = n->right;
+ }
+ if(n->op == OUSED || n->op == ODOTDOT)
+ n = n->left;
+ if(t == T)
+ t = n->type;
+ }
+ switch(t->etype){
+ case TSTRUCT:
+ case TUNION:
+ if(isexpr(n, t))
+ goto Default;
+ down = 0;
+ tn = nxtval(n, &nn);
+ if(tn != Z && (tn->op == OINIT || tn->op == OSTRUCT)){
+ down = 1;
+ n = tn->left;
+ }
+ if(depth > 0){
+ tgen(t, 0, 0);
+ prdelim(" ");
+ }
+ prdelim("(");
+ for(t1 = t->link; t1 != T; t1 = t1->down){
+ if(n == Z)
+ n = defval(t1);
+ n = eagen(n, t1, 0, nil, depth+1);
+ if(t1->down != T){
+ prdelim(",");
+ if(ar)
+ prdelim("\t");
+ else
+ prdelim(" ");
+ }
+ }
+ prdelim(")");
+ if(down)
+ n = nn;
+ break;
+ case TARRAY:
+ if(isexpr(n, t))
+ goto Default;
+ if(depth > 0){
+ tgen(t, 0, 1);
+ prdelim(" ");
+ }
+ prdelim("{");
+ newline();
+ incind();
+ w = t->width/t->link->width;
+ nw = 0;
+ for(i = 0; i < w; i++){
+ down = 0;
+ tn = nxtval(n, &nn);
+ if(tn != Z && (tn->op == OINIT || tn->op == OSTRUCT)){
+ down = 1;
+ n = tn->left;
+ }
+ n = eagen(n, t->link, 1, &nw, depth+1);
+ if(down)
+ n = nn;
+ }
+ if(nw > 0){
+ if(nw > 1)
+ prdelim("* => ");
+ egen(defval(t->link), ONOOP, PRE);
+ newline();
+ }
+ decind();
+ prdelim("}");
+ break;
+ default:
+Default:
+ if(n == Z){
+ if(ar)
+ (*nz)++;
+ else
+ egen(defval(t), ONOOP, PRE);
+ return Z;
+ }
+ n = nxtval(n, &nn);
+ if(ar && isnil(n) && iscastable(t, types[TINT])){
+ tgen(t, 0, 0);
+ prdelim(" ");
+ }
+ egen(n, ONOOP, PRE);
+ n = nn;
+ break;
+ }
+ if(ar){
+ prdelim(",");
+ newline();
+ }
+ return n;
+}
+
+/* better is
+ * array of byte "abcde\0"
+ * but limbo compiler does not accept this as a constant expression
+ */
+static void
+stob(Node *n)
+{
+ int m;
+ char *s = nil, buf[UTFmax];
+ ushort *u = nil;
+
+ while(n->op == ONAME)
+ n = n->sym->nconst;
+ if(n->op == OSTRING)
+ s = n->cstring;
+ else
+ u = n->rstring;
+ prdelim("{ ");
+ if(s){
+ while(*s){
+ prid("byte ");
+ prchar(*s++);
+ prdelim(", ");
+ }
+ }
+ else{
+ while(*u){
+ m = runetochar(buf, u++);
+ s = buf;
+ while(--m >= 0){
+ prid("byte ");
+ prchar(*s++);
+ prdelim(", ");
+ }
+ }
+ }
+ prid("byte ");
+ prchar('\0');
+ prdelim(" }");
+}
+
+static Type *arrayofchar;
+
+static void
+sdgen(Node *n, int glob)
+{
+ int sop = 0;
+
+ prdelim(" := ");
+ if(glob && n->right->op == OS2AB && isstring(n->right->left)){
+ if(arrayofchar == T){
+ arrayofchar = typ1(TARRAY, types[TCHAR]);
+ arrayofchar->width = 0;
+ }
+ n->type = n->right->type = arrayofchar;
+ sop = 1;
+ }
+ else
+ n->type = n->right->type = T;
+ tgen(n->type, 0, 1);
+ if(sop)
+ stob(n->right->left);
+ else
+ eagen(n->right, n->type, 0, nil, 0);
+ prdelim(";");
+ newline();
+}
+
+static void
+tdgen(Node *n, int glob)
+{
+ int ar, arinit;
+
+ if(ism()){
+ prdelim(": ");
+ tgen(n->type, 1, 0);
+ if(n->op == ODAS)
+ prcom("initial value was ", n->right);
+ prdelim(";");
+ newline();
+ return;
+ }
+ if(n->op == ODAS && (isstring(n->right) || n->right->op == OS2AB)){
+ sdgen(n, glob);
+ return;
+ }
+ ar = n->type->etype == TARRAY && n->type->width != LARR;
+ arinit = ar && n->op == ODAS;
+ if(ar)
+ prdelim(" := ");
+ else
+ prdelim(": ");
+ tgen(n->type, 0, arinit);
+ if(n->op == ODAS){
+ if(!arinit)
+ prdelim(" = ");
+ eagen(n->right, n->type, 0, nil, 0);
+ }
+ prdelim(";");
+ newline();
+}
+
+static int
+isdec(Node *n)
+{
+ return isname(n) && n->kind != KEXP || n->op == ODAS;
+}
+
+static void
+sgen(Node *n, int blk, Node **ln)
+{
+ int comma = 0;
+ Node *nn;
+
+ if(n == Z)
+ return;
+ if(blk){
+ pushscope(n, SAUTO);
+ if(n->op == OLIST && !(blk&NOBR) || (blk&YESBR)){
+ prdelim("{");
+ newline();
+ }
+ else if(!(blk&NONL))
+ newline();
+ if(!(blk&NOIN))
+ incind();
+ }
+ if((nn = *ln) != Z && isdec(nn)){
+ if(isdec(n)){
+ if(canjoin(nn, n))
+ comma = 1;
+ else
+ tdgen(nn, 0);
+ }
+ else if(n->op != OLIST){
+ tdgen(nn, 0);
+ newline();
+ }
+ }
+ if(n->op != OLIST){
+ *ln = n;
+ output(n->lineno, 1);
+ }
+ switch(n->op){
+ default:
+ egen(n, ONOOP, PRE);
+ prdelim(";");
+ newline();
+ break;
+ case ODAS:
+ pushdcl(n->left, CAUTO);
+ egen(n->left, ONOOP, PRE);
+ break;
+ case ONAME:
+ if(n->kind == KEXP){
+ egen(n, ONOOP, PRE);
+ prdelim(";");
+ newline();
+ }
+ else{
+ pushdcl(n, CAUTO);
+ if(comma)
+ prdelim(", ");
+ if(n->op != ONAME)
+ diag(n, "internal: not name in sgen");
+ prsym(n->sym, 0);
+ /* egen(n, ONOOP, PRE); */
+/*
+ prdelim(": ");
+ tgen(n->type, 0, 0, 0);
+ prdelim(";");
+ newline();
+*/
+ }
+ break;
+ case OSBREAK:
+ break;
+ case ONUL:
+ prdelim(";");
+ newline();
+ break;
+ case OBLK:
+ sgen(n->left, 1|YESBR, ln);
+ break;
+ case OLIST:
+ sgen(n->left, 0, ln);
+ sgen(n->right, 0, ln);
+ break;
+ case ORETURN:
+ prkeywd("return");
+ if(n->left != Z)
+ prdelim(" ");
+ egen(n->left, ONOOP, PRE);
+ prdelim(";");
+ newline();
+ break;
+ case OLABEL:
+ prcom("was label ", n->left);
+ /* i = zeroind(); */
+ /* egen(n->left, ONOOP, PRE); */
+ /* prdelim(":"); */
+ newline();
+ /* restoreind(i); */
+ break;
+ case OGOTO:
+ prcom("was goto ", n->left);
+ /* prkeywd("goto "); */
+ /* egen(n->left, ONOOP, PRE); */
+ prdelim(";");
+ newline();
+ break;
+ case OCASE:
+ for(nn = n->left; nn != Z; nn = nn->right){
+ if(nn != n->left)
+ prkeywd(" or ");
+ if(nn->left != Z)
+ egen(nn->left, ONOOP, PRE);
+ else
+ prkeywd("*");
+ }
+ prdelim(" =>");
+ clrbrk(n->right);
+ sgen(n->right, 1|NOBR, ln);
+ if(n->kind != KLAST && !hasbrk(n->right)){
+ prcom("fall through", Z);
+ newline();
+ }
+ break;
+ case OSWITCH:
+ prkeywd("case");
+ egen(n->left, OBRACKET, PRE);
+ sgen(n->right, 1|NOIN|YESBR, ln);
+ break;
+ case OWHILE:
+ prkeywd("while");
+ egen(n->left, OBRACKET, PRE);
+ sgen(n->right, 1, ln);
+ break;
+ case ODWHILE:
+ prkeywd("do");
+ sgen(n->right, 1|NOENL, ln);
+ prkeywd("while");
+ egen(n->left, OBRACKET, PRE);
+ prdelim(";");
+ newline();
+ break;
+ case OFOR:
+ prkeywd("for");
+ prdelim("(");
+ egen(n->left->right->left, ONOOP, PRE);
+ prdelim(";");
+ if(n->left->left != Z)
+ prdelim(" ");
+ egen(n->left->left, ONOOP, PRE);
+ prdelim(";");
+ if(n->left->right->right != Z)
+ prdelim(" ");
+ egen(n->left->right->right, ONOOP, PRE);
+ prdelim(")");
+ sgen(n->right, 1, ln);
+ break;
+ case OCONTINUE:
+ prkeywd("continue");
+ prdelim(";");
+ newline();
+ break;
+ case OBREAK:
+ prkeywd("break");
+ prdelim(";");
+ newline();
+ break;
+ case OIF:
+ prkeywd("if");
+ egen(n->left, OBRACKET, PRE);
+ if(n->right->left->op == OIF && n->right->left->right->right == Z && n->right->right != Z) /* avoid dangling else */
+ sgen(n->right->left, 1|YESBR, ln);
+ else
+ sgen(n->right->left, 1, ln);
+ if(n->right->right != Z){
+ prdelim("else");
+ if(n->right->right->op == OIF){ /* merge else and if */
+ prdelim(" ");
+ sgen(n->right->right, 1|NONL|NOIN, ln);
+ }
+ else
+ sgen(n->right->right, 1, ln);
+ }
+ break;
+ case OSET:
+ case OUSED:
+ prkeywd(ops[n->op].name);
+ lgen(n->left, 1, 1);
+ prdelim(";");
+ newline();
+ break;
+ }
+ if(blk){
+ if(!(blk&NOIN))
+ decind();
+ if(n->op == OLIST&& !(blk&NOBR) || (blk&YESBR)){
+ prdelim("}");
+ if(!(blk&NOENL))
+ newline();
+ }
+ popscope();
+ }
+}
+
+static void rew(Node*, int);
+
+static void
+rewc0(Node *n, Node *r)
+{
+ Node *nn;
+
+ if((nn = cfind(n)) != Z){
+ cgen0(nn, n);
+ if(r->op == ORETURN){
+ n->right->left = new1(ORETURN, n->right->left, Z);
+ n->right->right = new1(ORETURN, n->right->right, Z);
+ n->right->left->type = n->right->left->left->type;
+ n->right->right->type = n->right->right->left->type;
+ *r = *n;
+ }
+ }
+}
+
+static void
+rewc1(Node *n)
+{
+ Node *c, *nc;
+
+ if(n == Z || n->op != OCOND || side(n) || !simple(n))
+ return;
+ c = n->left;
+ nc = new1(ONOT, ncopy(c), Z);
+ n->op = OOROR;
+ n->left = new1(OANDAND, c, n->right->left);
+ n->right = new1(OANDAND, nc, n->right->right);
+}
+
+static void
+rewc(Node *n, Node *r)
+{
+ Node *nn, *rr, *i;
+
+ if((nn = cfind(n)) != Z){
+ i = cgen(nn, n);
+ rr = new1(OXXX, Z, Z);
+ if(n == r && nn == n)
+ *rr = *nn;
+ else
+ *rr = *r;
+ r->op = OLIST;
+ r->left = i;
+ r->right = rr;
+ }
+}
+
+static int
+rewe(Node *n, Type *t, int lev)
+{
+ int op, k, k1, k2;
+ int v;
+ Node *nn;
+
+ if(n == Z)
+ return -1;
+ switch(n->op){
+ case OCONST:
+ break;
+ case ONAME:
+ if(strings || !isstring(n))
+ break;
+ case OSTRING:
+ case OLSTRING:
+ if(!strings)
+ addnode(OS2AB, n);
+ break;
+ case OCOND:
+ bptr(n->left);
+ rewe(n->left, T, 1);
+ rewe(n->right, T, 1);
+ break;
+ case OIND:
+ if(isfn(n->type)){
+ *n = *n->left;
+ rewe(n, T, 1);
+ break;
+ }
+ if(!isadt(n->type)){
+ n->op = OARRIND;
+ n->right = con(0);
+ rewe(n, T, 1);
+ break;
+ }
+ rewe(n->left, T, 1);
+ break;
+ case OADDR:
+ if(n->left->op == OARRIND){
+ n->right = n->left;
+ n->left = n->right->left;
+ n->right->left = n->right->right;
+ n->right->right = Z;
+ n->right->op = OLIST;
+ n->op = OSLICE;
+ rewe(n, T, 1);
+ break;
+ }
+ rewe(n->left, T, 1);
+ break;
+ case OSLICE:
+ rewe(n->left, T, 1);
+ rewe(n->right, T, 1);
+ if(n->left->op == OSLICE){
+ n->right->left = addn(n->left->right->left, n->right->left);
+ n->right->right = addn(n->left->right->left, n->right->right);
+ n->left = n->left->left;
+ rewe(n, T, 1);
+ break;
+ }
+ break;
+ case OCOMMA:
+ rewe(n->left, T, 1);
+ rewe(n->right, T, 1);
+ if(n->left->op == OAS && n->right->op == OAS){
+ n->op = OAS;
+ n->left->op = n->right->op = OLIST;
+ nn = n->left->right;
+ n->left->right = n->right->left;
+ n->right->left = nn;
+ rewe(n, T, 1);
+ break;
+ }
+ break;
+ case OFUNC:
+ if(n->left->op == ONAME){
+ if((k = n->left->sym->kind) != LNONE){
+ rewlc(n, k, t);
+ rewe(n->left, T, 1);
+ rewe(n->right, T, 1);
+ args(n);
+ return k;
+ }
+ }
+ else
+ rewe(n->left, T, 1);
+ rewe(n->right, T, 1);
+ args(n);
+ break;
+ case OCAST:
+ rewe(n->left, n->type, 1);
+ break;
+ case OAS:
+ case OASI:
+ case OASD:
+ rewe(n->left, T, 1);
+ rewe(n->right, n->type, 1);
+ break;
+ case ONOT:
+ case OANDAND:
+ case OOROR:
+ bptr(n);
+ rewe(n->left, T, 1);
+ rewe(n->right, T, 1);
+ break;
+ case OPREINC:
+ case OPOSTINC:
+ case OASADD:
+ if(n->op != OPOSTINC || lev == 0){
+ sliceasgn(n);
+ if(n->op == OAS){
+ rewe(n, T, 1);
+ break;
+ }
+ }
+ rewe(n->left, T, 1);
+ rewe(n->right, T, 1);
+ break;
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OLE:
+ case OGT:
+ case OGE:
+ k1 = rewe(n->left, T, 1);
+ k2 = rewe(n->right, T, 1);
+ if(k1 == LSTRCMP && n->right->op == OCONST){
+ op = -1;
+ v = n->right->vconst;
+ switch(v){
+ case -1:
+ if(n->op == OEQ)
+ op = OLT;
+ else if(n->op == ONE)
+ op = OGE;
+ break;
+ case 0:
+ op = n->op;
+ break;
+ case 1:
+ if(n->op == OEQ)
+ op = OGT;
+ else if(n->op == ONE)
+ op = OLE;
+ break;
+ }
+ if(op != -1){
+ *n = *n->left;
+ n->op = op;
+ }
+ }
+ if(k2 == LSTRCMP && n->left->op == OCONST){
+ op = -1;
+ v = n->left->vconst;
+ switch(v){
+ case -1:
+ if(n->op == OEQ)
+ op = OLT;
+ else if(n->op == ONE)
+ op = OGE;
+ break;
+ case 0:
+ op = rev(n->op);
+ break;
+ case 1:
+ if(n->op == OEQ)
+ op = OGT;
+ else if(n->op == ONE)
+ op = OLE;
+ break;
+ }
+ if(op != -1){
+ *n = *n->right;
+ n->op = op;
+ }
+ }
+ break;
+ default:
+ rewe(n->left, T, 1);
+ rewe(n->right, T, 1);
+ break;
+ }
+ return -1;
+}
+
+/*
+static void
+rewf(Node *n)
+{
+ if(n == Z)
+ return;
+ switch(n->op){
+ case OFUNC:
+ if(n->left->op == ONAME)
+ fdargs(n);
+ break;
+ default:
+ rewf(n->left);
+ rewf(n->right);
+ break;
+ }
+}
+*/
+
+static void
+rew(Node *n, int blk)
+{
+ int i;
+ Node *a, *nn;
+
+ if(n == Z)
+ return;
+ if(blk)
+ pushscope(n, SAUTO);
+ nearln = n->lineno;
+ if(n->blk){
+ n->blk = 0;
+ addnode(OBLK, n);
+ }
+ switch(n->op){
+ default:
+ if(simple(n))
+ rewc0(n, n);
+ else
+ rewc(n, n);
+ if(n->op == OLIST || n->op == OIF){
+ rew(n, 0);
+ break;
+ }
+ ecomplex(n);
+ break;
+ case ODAS:
+ pushdcl(n->left, CAUTO);
+ rewe(n->right, T, 1);
+ break;
+ case OSBREAK:
+ case ONUL:
+ break;
+ case ONAME:
+ if(n->kind == KEXP)
+ ecomplex(n);
+ else
+ pushdcl(n, CAUTO);
+ break;
+ case OBLK:
+ rew(n->left, 1);
+ break;
+ case OLIST:
+ rew(n->left, 0);
+ rew(n->right, 0);
+ break;
+ case ORETURN:
+ if(simple(n->left))
+ rewc0(n->left, n);
+ else
+ rewc(n->left, n);
+ if(n->op != ORETURN){
+ rew(n, 0);
+ break;
+ }
+ ecomplex(n);
+ break;
+ case OLABEL:
+ case OGOTO:
+ break;
+ case OCASE:
+ for(nn = n->left; nn != Z; nn = nn->right)
+ if(nn->left != Z)
+ ecomplex(nn->left);
+ rew(n->right, 1);
+ break;
+ case OSWITCH:
+ rewc(n->left, n);
+ if(n->op == OLIST){
+ rew(n, 0);
+ break;
+ }
+ ecomplex(n->left);
+ if(!lteq(n->left->type, types[TINT]))
+ intcast(n->left);
+ n->right = buildcases(n->right);
+ rew(n->right, 1);
+ break;
+ case OWHILE:
+ case ODWHILE:
+ rewc1(n->left);
+ becomplex(n->left);
+ rew(n->right, 1);
+ break;
+ case OFOR:
+ rewc1(n->left->left);
+ rewc(n->left->right->left, n);
+ if(n->op == OLIST){
+ rew(n, 0);
+ break;
+ }
+ becomplex(n->left->left);
+ ecomplex(n->left->right->left);
+ ecomplex(n->left->right->right);
+ rew(n->right, 1);
+ break;
+ case OCONTINUE:
+ break;
+ case OBREAK:
+ break;
+ case OIF:
+ rewc1(n->left);
+ rewc(n->left, n);
+ if(n->op == OLIST){
+ rew(n, 0);
+ break;
+ }
+ becomplex(n->left);
+ rew(n->right->left, 1);
+ rew(n->right->right, 1);
+ break;
+ case OSET:
+ if(n->left == Z){
+ n->op = ONUL;
+ n->left = n->right = Z;
+ break;
+ }
+ if(n->left->op != OLIST){
+ n->op = OAS;
+ n->right = defval(n->left->type);
+ rew(n, 0);
+ break;
+ }
+ i = 0;
+ nn = Z;
+ for(;;){
+ a = arg(n->left, i);
+ if(a == Z)
+ break;
+ a = new1(OAS, a, defval(a->type));
+ if(i == 0)
+ nn = a;
+ else
+ nn = new1(OLIST, nn, a);
+ i++;
+ }
+ *n = *nn;
+ rew(n, 0);
+ break;
+ case OUSED:
+ if(n->left == Z){
+ n->op = ONUL;
+ n->left = n->right = Z;
+ break;
+ }
+ i = 0;
+ nn = Z;
+ for(;;){
+ a = arg(n->left, i);
+ if(a == Z)
+ break;
+ if(i == 0)
+ nn = a;
+ else
+ nn = new1(OOROR, nn, a);
+ i++;
+ }
+ n->op = OIF;
+ n->left = nn;
+ n->right = new1(OLIST, Z, Z);
+ n->right->left = new1(ONUL, Z, Z);
+ rew(n, 0);
+ break;
+ }
+ if(blk)
+ popscope();
+}
+
+void
+codgen2(Node *n, Node *nn, int lastlno, int rw)
+{
+ Node *ln = Z;
+
+ newsec(0);
+ output(nn->lineno, 1);
+ tmp = 0;
+ /* t = types[TVOID]; */
+ nn = func(nn);
+ pushscope(nn, SPARM);
+ if(rw)
+ rew(n, 1);
+ egen(nn, ONOOP, PRE);
+ newline();
+ prdelim("{");
+ newline();
+ incind();
+ /* rewf(n); */
+ pushscope(n, SAUTO);
+ sgen(n, 0, &ln);
+ if(ln != Z && isdec(ln))
+ tdgen(ln, 0);
+ popscope();
+ popscope();
+ if(n != Z)
+ output(lline(n), 1);
+ output(lastlno, 1);
+ decind();
+ prdelim("}");
+ newline();
+ newline();
+ setmain(nn);
+}
+
+void
+rewall(Node *n, Node *nn, int lastlno)
+{
+ USED(lastlno);
+ tmp = 0;
+ nn = func(nn);
+ pushscope(nn, SPARM);
+ rew(n, 1);
+ popscope();
+ setmain(nn);
+}
+
+void
+suball(Node *n, Node *nn)
+{
+ Node *rn;
+
+ nn = func(nn);
+ pushscope(nn, SPARM);
+ subs(nn, 0, 0);
+ subs(n, 1, 1);
+ nn = lastn(n);
+ if(nn != Z && nn->op != ORETURN){
+ rn = retval(Z);
+ if(rn != Z){
+ addnode(OLIST, nn);
+ nn->right = rn;
+ }
+ }
+ popscope();
+}
+
+void
+ginit(void)
+{
+ thechar = 'o';
+ thestring = "386";
+ tfield = types[TLONG];
+}
+
+long
+align(long i, Type *t, int op)
+{
+ long o;
+ Type *v;
+ int w;
+
+ o = i;
+ w = 1;
+ switch(op) {
+ default:
+ diag(Z, "unknown align opcode %d", op);
+ break;
+
+ case Asu2: /* padding at end of a struct */
+ w = SZ_LONG;
+ break;
+
+ case Ael1: /* initial allign of struct element */
+ for(v=t; v->etype==TARRAY; v=v->link)
+ ;
+ w = ewidth[v->etype];
+ if(w <= 0 || w >= SZ_LONG)
+ w = SZ_LONG;
+ break;
+
+ case Ael2: /* width of a struct element */
+ o += t->width;
+ break;
+
+ case Aarg0: /* initial passbyptr argument in arg list */
+ if(typesuv[t->etype]) {
+ o = align(o, types[TIND], Aarg1);
+ o = align(o, types[TIND], Aarg2);
+ }
+ break;
+
+ case Aarg1: /* initial allign of parameter */
+ w = ewidth[t->etype];
+ if(w <= 0 || w >= SZ_LONG) {
+ w = SZ_LONG;
+ break;
+ }
+ w = 1; /* little endian no adjustment */
+ break;
+
+ case Aarg2: /* width of a parameter */
+ o += t->width;
+ w = SZ_LONG;
+ break;
+
+ case Aaut3: /* total allign of automatic */
+ o = align(o, t, Ael2);
+ o = align(o, t, Ael1);
+ w = SZ_LONG; /* because of a pun in cc/dcl.c:contig() */
+ break;
+ }
+ o = round(o, w);
+ if(0)
+ print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
+ return o;
+}
+
+long
+maxround(long max, long v)
+{
+ v = round(v, SZ_LONG);
+ if(v > max)
+ return v;
+ return max;
+}
+
+static int
+nlen(Node *n)
+{
+ if(n == Z)
+ return 0;
+ if(n->op == OLIST)
+ return nlen(n->left)+nlen(n->right);
+ return 1;
+}
+
+static void
+flatten(Node *n, Node **a, int *i)
+{
+ if(n == Z)
+ return;
+ if(n->op == OLIST){
+ flatten(n->left, a, i);
+ flatten(n->right, a, i);
+ free(n);
+ return;
+ }
+ a[(*i)++] = n;
+}
+
+static Node*
+addcase(Node *n, Node **e, Node **s, int k)
+{
+ Node *nn;
+
+ if(*e != Z){
+ nn = new1(OCASE, *e, *s);
+ nn->right->blk = 0;
+ nn->kind = k;
+ }
+ else
+ nn = *s;
+ *e = *s = Z;
+ if(n == Z)
+ return nn;
+ return new1(OLIST, n, nn);
+}
+
+/* collect case code together */
+static Node*
+buildcases(Node *n)
+{
+ int i, m, m0, c;
+ Node *e, *s, *nn, **a, **ep;
+
+ m = nlen(n);
+ a = (Node **)malloc(m*sizeof(Node*));
+ m0 = 0;
+ flatten(n, a, &m0);
+ if(m != m0)
+ diag(Z, "internal: bad buildcases()");
+ c = 1;
+ e = s = nn = Z;
+ ep = &e;
+ for(i = 0; i < m; i++){
+ n = a[i];
+ if(n->op == OCASE){
+ if(!c){
+ nn = addcase(nn, &e, &s, KNIL);
+ ep = &e;
+ }
+ *ep = new1(OLIST, n->left, Z);
+ if(n->left == Z)
+ (*ep)->lineno = n->lineno;
+ ep = &(*ep)->right;
+ c = 1;
+ }
+ else{
+ if(s == Z)
+ s = n;
+ else
+ s = new1(OLIST, s, n);
+ c = 0;
+ }
+ }
+ nn = addcase(nn, &e, &s, KLAST);
+ free(a);
+ return nn;
+}
+
+static Sym *
+tmpgen(Type *t)
+{
+ Sym *s;
+
+ sprint(buf, "tmp_%d", ++tmp);
+ s = slookup(buf);
+ s->type = t;
+ s->class = CAUTO;
+ if(t->etype == TENUM)
+ s->type = types[TINT];
+ return s;
+}
+
+static Node*
+cfind(Node *n)
+{
+ Node *nn;
+
+ if(n == Z)
+ return Z;
+ if(n->op == OCOND)
+ return n;
+ nn = cfind(n->left);
+ if(nn != Z)
+ return nn;
+ return cfind(n->right);
+}
+
+Node*
+ncopy(Node *n)
+{
+ Node *nn;
+
+ if(n == Z)
+ return Z;
+ nn = new1(n->op, Z, Z);
+ *nn = *n;
+ nn->left = ncopy(n->left);
+ nn->right = ncopy(n->right);
+ return nn;
+}
+
+static int
+complexity(Node *n, int *cond)
+{
+ int c;
+
+ if(n == Z)
+ return 0;
+ c = complexity(n->left, cond)+1+complexity(n->right, cond);
+ if(n->op == OCOND)
+ (*cond)++;
+ return c;
+}
+
+static int
+simple(Node *n)
+{
+ int c;
+
+ c = 0;
+ return complexity(n, &c) < COMPLEX && c <= 1;
+}
+
+static Type*
+intype(Node *n)
+{
+ Type *t;
+
+ t = ntype(n);
+ if(t == T)
+ return T;
+ return t->link;
+}
+
+static Type*
+ntype(Node *n)
+{
+ Type *t;
+
+ if(n == Z)
+ return T;
+ t = n->type;
+ if(t != T){
+ if(t->etype == TENUM)
+ return n->sym->tenum;
+ return t;
+ }
+ switch(n->op){
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OLE:
+ case ONOT:
+ case OANDAND:
+ case OOROR:
+ case OIOTA:
+ return types[TINT];
+ case OCOMMA:
+ return ntype(n->right);
+ case OCOND:
+ return maxtype(ntype(n->right->left), ntype(n->right->right));
+ case OFUNC:
+ return intype(n->left);
+ case ODOT:
+ tcomd(n, ntype(n->left));
+ t = n->type;
+ n->type = T;
+ return t;
+ case ODOTIND:
+ tcomd(n, intype(n->left));
+ t = n->type;
+ n->type = T;
+ return t;
+ case OARRIND:
+ return intype(n->left);
+ case OADDR:
+ return typ1(TIND, ntype(n->left));
+ case OIND:
+ return intype(n->left);
+ case OSTRUCT:
+ return T;
+ }
+ return maxtype(ntype(n->left), ntype(n->right));
+}
+
+static Type*
+gettype(Node *n1, Node *n2)
+{
+ Type *t;
+
+ t = maxtype(n1->type, n2->type);
+ if(t != T)
+ return t;
+ return maxtype(ntype(n1), ntype(n2));
+}
+
+static void
+cgen0(Node *n, Node *e)
+{
+ Node *c, *nn, *ed, *ee;
+
+ if(n == e){
+ n->op = OIF;
+ return;
+ }
+ c = n->left;
+ ed = new1(OXXX, Z, Z);
+ *ed = *e;
+ ee = ncopy(e);
+ nn = cfind(ee);
+ *n = *n->right->left;
+ *nn = *nn->right->right;
+ e->op = OIF;
+ e->left = c;
+ e->right = new1(OLIST, ed, ee);
+}
+
+static Node*
+cgen(Node *n, Node *e)
+{
+ Type *t;
+ Node *tn, *i;
+
+ USED(e);
+ tn = new1(ONAME, Z, Z);
+ t = gettype(n->right->left, n->right->right);
+ tn->sym = tmpgen(t);
+ tn->type = tn->sym->type;
+/*
+ if(n == e){
+ n->op = OIF;
+ n->right->left = new1(OASD, tn, n->right->left);
+ n->right->right = new1(OAS, tn, n->right->right);
+ return n;
+ }
+*/
+ i = new1(OIF, n->left, new1(OLIST, new1(OASD, tn, n->right->left), new1(OAS, tn, n->right->right)));
+ *n = *tn;
+ return i;
+}
+
+static struct{
+ char *name;
+ int args;
+ int fd;
+ char *lname;
+} sysops[] = {
+ "create", 1, RET, nil,
+ "dirstat", 1, 0, "stat",
+ "dirfstat", 0, 1, "fstat",
+ "dirwstat", 1, 0, "wstat",
+ "dirfwstat", 0, 1, "fwstat",
+ "dirread", 0, 1, nil,
+ "dup", 0, 0, nil,
+ "fprint", 2|STAR, 1, nil,
+ "fprintf", 2|STAR, 1, "fprint",
+ "open", 1, RET, nil,
+ "print", 1|STAR, 0, nil,
+ "printf", 1|STAR, 0, "print",
+ "read", 0, 1, nil,
+ "remove", 1, 0, nil,
+ "seek", 0, 1, nil,
+ "sleep", 0, 0, nil,
+ "sprint", 1|STAR, 0, nil,
+ "sprintf", 1|STAR, 0, "sprint",
+ "write", 0, 1, nil,
+ 0
+};
+
+/* dummy entry for module */
+#define BIOTMP "__bio__"
+
+static struct{
+ char *name;
+ char *lname;
+} bioops[] = {
+ "Bflush", "flush",
+ "Bgetc", "getc",
+ "Bprint", "puts",
+ "Bputc", "putc",
+ "Bread", "read",
+ "Bseek", "seek",
+ "Bungetc", "ungetc",
+ "Bwrite", "write",
+ BIOTMP, nil,
+ 0
+};
+
+char *libcops[] = {
+ "isalnum",
+ "isalpha",
+ "isascii",
+ "iscntrl",
+ "isdigit",
+ "isgraph",
+ "islower",
+ "isprint",
+ "ispunct",
+ "isspace",
+ "isupper",
+ "isxdigit",
+ "strchr",
+ "strrchr",
+ "toascii",
+ "tolower",
+ "toupper",
+ "abs",
+ "min",
+ "max",
+ 0,
+};
+
+static struct{
+ char *name;
+ int type;
+ int string;
+} xops[] = {
+ "strlen", LSTRLEN, 1,
+ "strcmp", LSTRCMP, 1,
+ "strcpy", LSTRCPY, 1,
+ "strcat", LSTRCAT, 1,
+ "strncmp", LSTRNCMP, 1,
+ "strncpy", LSTRNCPY, 1,
+ "strncat", LSTRNCAT, 1,
+ "strdup", LSTRDUP, 1,
+ "memcpy", LMEMMOVE, 0,
+ "memmove", LMEMMOVE, 0,
+ "malloc", LMALLOC, 0,
+ "free", LFREE, 0,
+ "exit", LEXIT, 0,
+ "exits", LEXIT, 0,
+ "close", LCLOSE, 0,
+ "atoi", LATOI, 0,
+ "atol", LATOI, 0,
+ "atoll", LATOL, 0,
+ "atof", LATOF, 0,
+ "atod", LATOF, 0,
+ "print", LPRINT, 0,
+ "printf", LPRINT, 0,
+ "fprint", LFPRINT, 0,
+ "fprintf", LFPRINT, 0,
+ "sprint", LSPRINT, 0,
+ "sprintf", LSPRINT, 0,
+ 0
+};
+
+char *mathsops[] = {
+ "sin",
+ "cos",
+ "tan",
+ "sinh",
+ "cosh",
+ "tanh",
+ "asin",
+ "acos",
+ "atan",
+ "asinh",
+ "acosh",
+ "atanh",
+ "atan2",
+ "sqrt",
+ "cbrt",
+ "pow",
+ "pow10",
+ "exp",
+ "log",
+ "log10",
+ 0
+};
+
+Node *glob, *globe;
+
+void
+sysinit(void)
+{
+ int i;
+ Sym *s;
+
+ glob = globe = new1(ONOOP, Z, Z);
+ for(i = 0; sysops[i].name; i++){
+ s = slookup(sysops[i].name);
+ s->class = CEXTERN;
+ s->args = sysops[i].args;
+ s->fd = sysops[i].fd;
+ s->mod = "sys";
+ s->lname = sysops[i].lname;
+ s->limbo = 1;
+ sysop = s;
+ }
+ for(i = 0; bioops[i].name; i++){
+ s = slookup(bioops[i].name);
+ s->class = CEXTERN;
+ if(strcmp(bioops[i].name, BIOTMP) == 0){
+ s->mod = "bufio";
+ bioop = s;
+ }
+ s->lname = bioops[i].lname;
+ s->kind = LSELF;
+ s->limbo = 1;
+ }
+ for(i = 0; mathsops[i]; i++){
+ s = slookup(mathsops[i]);
+ s->class = CEXTERN;
+ s->mod = "math";
+ s->limbo = 1;
+ }
+ for(i = 0; libcops[i]; i++){
+ s = slookup(libcops[i]);
+ s->class = CEXTERN;
+ s->mod = strings ? "libc" : "libc0";
+ s->limbo = 1;
+ libcop = s;
+ }
+ for(i = 0; xops[i].name; i++){
+ s = slookup(xops[i].name);
+ s->class = CEXTERN;
+ if(strings || !xops[i].string)
+ s->kind = xops[i].type;
+ else
+ s->mod = "libc0";
+ if(s->kind == LEXIT)
+ s->lname = "exit";
+ s->limbo = 1;
+ }
+ usemod(sysop, 1);
+ if(!strings)
+ usemod(libcop, 1);
+}
+
+void
+clbegin(void)
+{
+ pushscope(glob, SGLOB);
+}
+
+void
+clend(void)
+{
+ if(passes)
+ swalk();
+ popscope();
+}
+
+static Modl *mods;
+
+void
+usemod(Sym *s, int ld)
+{
+ Modl *ml;
+
+ for(ml = mods; ml != nil; ml = ml->nxt)
+ if(strcmp(ml->mod, s->mod) == 0){
+ ml->ld |= ld;
+ return;
+ }
+ ml = (Modl *)malloc(sizeof(Modl));
+ ml->mod = s->mod;
+ ml->ld = ld;
+ ml->nxt = mods;
+ mods = ml;
+}
+
+static void
+ginc(Modl *ml)
+{
+ int c;
+ char *s;
+
+ if(ml == nil)
+ return;
+ if(ml->nxt != nil)
+ ginc(ml->nxt);
+ s = ml->mod;
+ c = toupper(s[0]);
+ sprint(buf, "include \"%s.m\";", s);
+ prline(buf);
+ if(ml->ld){
+ sprint(buf, " %s: %c%s;", s, c, s+1);
+ prline(buf);
+ }
+}
+
+static void
+gload(Modl *ml)
+{
+ int c;
+ char *s;
+
+ if(ml == nil)
+ return;
+ if(ml->nxt != nil)
+ gload(ml->nxt);
+ if(ml->ld){
+ s = ml->mod;
+ c = toupper(s[0]);
+ sprint(buf, " %s = load %c%s %c%s->PATH;", s, c, s+1, c, s+1);
+ prline(buf);
+ }
+}
+
+static void
+callmain(void)
+{
+ if(inmain){
+ if(strings)
+ prline(" main(len argl, argl);");
+ else
+ prline(" main(len argl, libc0->ls2aab(argl));");
+ }
+}
+
+static void
+genstart(void)
+{
+ char *s;
+
+ if(!strings && inmain)
+ usemod(libcop, 1);
+ ginc(mods);
+ s = hasm();
+ if(s){
+ sprint(buf, "include \"%s\";", s);
+ prline(buf);
+ }
+ prline("");
+ prline("init(nil: ref Draw->Context, argl: list of string)");
+ prline("{");
+ gload(mods);
+ callmain();
+ prline("}");
+ prline("");
+}
+
+static int
+argpos0(Node *nn, Node *n, int *p)
+{
+ int pp;
+
+ if(n == Z)
+ return -1;
+ if(n->op == OLIST){
+ pp = argpos0(nn, n->left, p);
+ if(pp >= 0)
+ return pp;
+ return argpos0(nn, n->right, p);
+ }
+ if(n == nn)
+ return *p;
+ (*p)++;
+ return -1;
+}
+
+static int
+argpos(Node *nn, Node *n)
+{
+ int p = 0;
+
+ p = argpos0(nn, n, &p);
+ if(p < 0)
+ diag(Z, "-ve argpos");
+ return p;
+}
+
+static Node*
+arg0(Node *n, int a, int *i)
+{
+ Node *nn;
+
+ if(n == Z)
+ return Z;
+ if(n->op == OLIST){
+ nn = arg0(n->left, a, i);
+ if(nn != Z)
+ return nn;
+ return arg0(n->right, a, i);
+ }
+ if(a == (*i)++)
+ return n;
+ return Z;
+}
+
+static Node*
+arg(Node *n, int a)
+{
+ int i = 0;
+
+ return arg0(n, a, &i);
+}
+
+static Node*
+list(Node *l, Node *r)
+{
+ if(r == Z)
+ return l;
+ if(l == Z)
+ return r;
+ return new1(OLIST, l, r);
+}
+
+static Node*
+droparg(Node *n, int a, int *i)
+{
+ if(n == Z)
+ return Z;
+ if(n->op == OLIST)
+ return list(droparg(n->left, a, i), droparg(n->right, a, i));
+ if(a == (*i)++)
+ return Z;
+ return n;
+}
+
+static void
+sargs(Node *n)
+{
+ int s, f, i, j;
+ Node *a;
+
+ if(strings || (f = n->left->sym->args) == 0)
+ return;
+ s = 0;
+ for(i = 1, j = 0; i < STAR || s; i *= 2, j++){
+ if(f&i || s){
+ a = arg(n->right, j);
+ if(a == Z)
+ break;
+ if(s && !isstr(a->type))
+ continue;
+ if(f&STAR)
+ s++;
+ if(a->op == OS2AB){
+ *a = *a->left;
+ continue;
+ }
+ addnode(OAB2S, a);
+ }
+ }
+}
+
+static void
+fdargs(Node *n)
+{
+ int f, i, j;
+ Node *a;
+
+ if((f = n->left->sym->fd) == 0)
+ return;
+ marktype(pfdtype, TCFD);
+ if(f&RET)
+ tcon(n, pfdtype);
+ for(i = 1, j = 0; i < RET; i *= 2, j++){
+ if(f&i){
+ a = arg(n->right, j);
+ if(a == Z)
+ break;
+ tcon(a, pfdtype);
+ }
+ }
+}
+
+static void
+aargs(Node *n)
+{
+ int i;
+ Node *a, *nn, *fn;
+ Type *t, *t0, *ft, *at, *st;
+
+ if(!doaddr)
+ return;
+ if(n->op != OFUNC || n->left->op != ONAME)
+ return;
+ /* ft = n->left->type; */
+ ft = n->left->sym->type;
+ t = t0 = ft->link;
+ nn = Z;
+ for(i = 0; ; i++){
+ a = arg(n->right, i);
+ if(a == Z)
+ break;
+ at = typn(ft, i);
+ if(at != T && at->etype != TDOT && (a->op == OADDR || iteq(a->type, at) || iteq(at, a->type))){
+ if(iteq(at, a->type))
+ st = at->link;
+ else
+ st = a->type->link;
+ if(doalladdr || isscalar(st)){
+ if(a->op == OADDR)
+ *a = *a->left;
+ else if(iteq(a->type, at))
+ a->type = at;
+ if(t->mark == 0){
+ t = tuple(t, a->type);
+ trep(at, at->link);
+ fn = finddec(n->left->sym, 1);
+ if(fn != Z && fn->op == OFUNC)
+ tind(arg(fn->right, i));
+ }
+ if(nn == Z)
+ nn = cknil(ncopy(a));
+ else{
+ nn = new1(OTUPLE, nn, cknil(ncopy(a)));
+ nn->type = t;
+ }
+ }
+ }
+ }
+ if(nn != Z){
+ if(isvoid(t0) || t->mark == TCPC)
+ marktype(t, TCPC);
+ else
+ marktype(t, TCFC);
+ tcon(n, t);
+ addnode(ORETV, n);
+ n->right = nn;
+ }
+}
+
+static void
+args(Node *n)
+{
+ if(n->op != OFUNC || n->left->op != ONAME)
+ return;
+ sargs(n);
+ if(passes){
+ fdargs(n);
+ aargs(n);
+ }
+}
+
+static Node*
+indir(Node *n)
+{
+ if(n->op == OADDR)
+ return n->left;
+ return new1(OIND, n, Z);
+}
+
+static void
+rewlc(Node *n, int k, Type *t)
+{
+ int i;
+ Type *tt;
+ Node *a0, *a1, *a2, *nn;
+
+ if(t == T)
+ t = n->type;
+ a0 = arg(n->right, 0);
+ a1 = arg(n->right, 1);
+ switch(k){
+ case LSTRLEN:
+ n->op = OLEN;
+ break;
+ case LSTRCMP:
+ n->op = ONE;
+ n->left = a0;
+ n->right = a1;
+ break;
+ case LSTRCPY:
+ n->op = OAS;
+ n->left = a0;
+ n->right = a1;
+ n->type = n->left->type;
+ break;
+ case LSTRCAT:
+ n->op = OASADD;
+ n->left = a0;
+ n->right = a1;
+ n->type = n->left->type;
+ break;
+ case LSTRDUP:
+ *n = *a0;
+ break;
+ case LMEMMOVE:
+ if(!teq(a0->type, a1->type))
+ break;
+ if(a0->type->etype == TIND){
+ tt = a0->type->link;
+ a2 = arg(n->right, 2);
+ if(isadt(tt) && isconst(a2, tt->width)){
+ n->op = OAS;
+ n->left = indir(a0);
+ n->right = indir(a1);
+ n->type = n->left->type = n->right->type = tt;
+ break;
+ }
+ if(mydiv(a2, tt->width) != Z){
+ n->op = OAS;
+ n->left = new1(OSLICE, a0, new1(OLIST, con(0), Z));
+ n->right = new1(OSLICE, a1, new1(OLIST, con(0), a2));
+ n->type = n->left->type = n->right->type = a0->type;
+ }
+ }
+ break;
+ case LMALLOC:
+ if(t->etype == TIND){
+ tt = t->link;
+ if(isadt(tt) && isconst(a0, tt->width)){
+ n->op = OREF;
+ n->left = Z;
+ n->right = Z;
+ n->type = t;
+ break;
+ }
+ if(mydiv(a0, tt->width) != Z){
+ n->op = OARRAYOF;
+ n->left = a0;
+ n->right = Z;
+ n->type = t;
+ if(isadt(tt)){
+ n->type = typ1(TARRAY, tt);
+ n->type->width = LARR; /* limbo array without bounds */
+ marktype(n->type, TCAR);
+ }
+ }
+ }
+ break;
+ case LFREE:
+ n->op = OAS;
+ n->left = a0;
+ n->right = con(0);
+ n->type = n->left->type;
+ n->right->type = n->type;
+ break;
+ case LEXIT:
+ i = n->kind;
+ *n = *n->left;
+ n->kind = i;
+ break;
+ case LCLOSE:
+ n->op = OAS;
+ n->left = a0;
+ n->right = con(0);
+ n->left->type = typ1(TIND, n->left->type);
+ n->type = n->left->type;
+ n->right->type = n->type;
+ break;
+ case LATOI:
+ if(!strings)
+ strcast(a0);
+ n->op = OCAST;
+ n->left = a0;
+ n->right = Z;
+ n->type = types[TINT];
+ break;
+ case LATOL:
+ if(!strings)
+ strcast(a0);
+ n->op = OCAST;
+ n->left = a0;
+ n->right = Z;
+ n->type = types[TVLONG];
+ break;
+ case LATOF:
+ if(!strings)
+ strcast(a0);
+ n->op = OCAST;
+ n->left = a0;
+ n->right = Z;
+ n->type = types[TDOUBLE];
+ break;
+ case LPRINT:
+ if(a0->op == OSTRING)
+ pfmt(a0->cstring);
+ else if(a0->op == OLSTRING)
+ lpfmt(a0->rstring);
+ break;
+ case LFPRINT:
+ if(a1->op == OSTRING)
+ pfmt(a1->cstring);
+ else if(a1->op == OLSTRING)
+ lpfmt(a1->rstring);
+ break;
+ case LSPRINT:
+ if(n->right->kind != KDROP){
+ if(a1->op == OSTRING)
+ pfmt(a1->cstring);
+ else if(a1->op == OLSTRING)
+ lpfmt(a1->rstring);
+ nn = new1(OXXX, Z, Z);
+ *nn = *n;
+ i = 0;
+ nn->right = droparg(nn->right, 0, &i);
+ nn->right->kind = KDROP;
+ n->op = OAS;
+ n->left = a0;
+ n->right = nn;
+ n->type = nn->type;
+ }
+ break;
+ case LSELF:
+ if(n->right != Z && n->right->kind != KDROP){
+ i = 0;
+ n->right = droparg(n->right, 0, &i);
+ if(n->right != Z)
+ n->right->kind = KDROP;
+ addnode(OLDOT, n->left);
+ n->left->right = n->left->left;
+ n->left->left = a0;
+ usemod(bioop, 1);
+ }
+ break;
+ }
+}
+
+void
+expgen(Node *n)
+{
+ egen(n, ONOOP, PRE);
+}
+
+static void
+clrbrk(Node *n)
+{
+ if(n == Z)
+ return;
+ switch(n->op){
+ case OLIST:
+ clrbrk(n->right);
+ break;
+ case OBREAK:
+ n->op = OSBREAK;
+ n->left = n->right = Z;
+ break;
+ }
+}
+
+static int
+hasbrk(Node *n)
+{
+ if(n == Z)
+ return 0;
+ switch(n->op){
+ case OLIST:
+ case OWHILE:
+ case ODWHILE:
+ case OFOR:
+ return hasbrk(n->right);
+ case OIF:
+ if(n->right->right == Z)
+ return 0;
+ return hasbrk(n->right->left) && hasbrk(n->right->right);
+ case ORETURN:
+ case OGOTO:
+ case OCONTINUE:
+ case OBREAK:
+ case OSBREAK:
+ return 1;
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+static int
+isgen(char *s)
+{
+ char *s1, *s2;
+
+ s1 = strchr(s, '_');
+ s2 = strrchr(s, '_');
+ if(s1 == nil || s2-s1 != 4)
+ return 0;
+ return s1[1] == 'a' && s1[2] == 'd' && s1[3] == 't';
+}
+
+static void
+addmodn(Sym *s)
+{
+ char buf[128], *ns;
+
+ if(s->name[0] == '_'){
+ outmod(buf, -1);
+ ns = malloc(strlen(buf)+strlen(s->name)+1);
+ strcpy(ns, buf);
+ strcat(ns, s->name);
+ s->name = ns;
+ }
+}
+
+static void
+pfmt(char *s)
+{
+ char *t = s;
+
+ while(*s != '\0'){
+ if(*s == '%'){
+ *t++ = *s++;
+ if(*s == 'l'){
+ s++;
+ if(*s == 'l')
+ *t++ = 'b';
+ else
+ *t++ = *s;
+ s++;
+ }
+ else if(*s == 'p'){
+ *t++ = 'x';
+ s++;
+ }
+ else
+ *t++ = *s++;
+ }
+ else
+ *t++ = *s++;
+ }
+ *t = '\0';
+}
+
+static void
+lpfmt(ushort *s)
+{
+ ushort*t = s;
+
+ while(*s != '\0'){
+ if(*s == '%'){
+ *t++ = *s++;
+ if(*s == 'l'){
+ s++;
+ if(*s == 'l')
+ *t++ = 'b';
+ else
+ *t++ = *s;
+ s++;
+ }
+ else if(*s == 'p'){
+ *t++ = 'x';
+ s++;
+ }
+ else
+ *t++ = *s++;
+ }
+ else
+ *t++ = *s++;
+ }
+ *t = '\0';
+}
+
+int
+line(Node *n)
+{
+ if(n == Z)
+ return 0;
+ if(n->op == OLIST)
+ return line(n->left);
+ return n->lineno;
+}
+
+static int
+lline(Node *n)
+{
+ if(n == Z)
+ return 0;
+ if(n->op == OLIST)
+ return lline(n->right);
+ return n->lineno+1;
+}
+
+static Node*
+lastn(Node *n)
+{
+ while(n != Z && n->op == OLIST)
+ n = n->right;
+ return n;
+}
+
+static Node*
+newnode(int op, Node *l)
+{
+ Node *n;
+
+ n = new1(op, l, Z);
+ globe->right = n;
+ globe = n;
+ return n;
+}
+
+void
+codgen1(Node *n, Node *nn, int lastlno)
+{
+ Node *nnn;
+
+ scomplex(n);
+ nnn = newnode(OCODE, new1(OLIST, n, nn));
+ nnn->lineno = lastlno;
+ mset(n);
+ mset(nn);
+ nn = func(nn);
+ newnode(ODECF, nn);
+ setmain(nn);
+}
+
+void
+vtgen1(Node *n)
+{
+ int c;
+ Node *nn = n;
+
+ if(n->op == ODAS)
+ nn = n->left;
+ if(nn->type == T || nn->sym == S)
+ return;
+ c = nn->sym->class;
+ if(c == CGLOBL || c == CSTATIC || c == CLOCAL || c == CEXREG){
+ newnode(ODECV, n);
+ if(nn->type->etype != TFUNC || ism())
+ setmod(nn->sym);
+ }
+ mset(n);
+}
+
+void
+etgen1(Sym *s)
+{
+ Node *n;
+
+ n = newnode(ODECE, Z);
+ n->sym = s;
+ if(s != S)
+ setmod(s);
+}
+
+void
+ttgen1(Type *t)
+{
+ Node *n;
+
+ n = newnode(ODECT, Z);
+ n->type = t;
+ if(isadt(t))
+ setmod(suename(t));
+}
+
+void
+outpush1(char *s)
+{
+ Node *n;
+ char *t;
+
+ n = newnode(OPUSH, Z);
+ if(s == nil)
+ t = nil;
+ else{
+ t = malloc(strlen(s)+1);
+ strcpy(t, s);
+ }
+ n->cstring = t;
+ outpush0(s, n);
+}
+
+void
+outpop1(int lno)
+{
+ Node *n;
+
+ n = newnode(OPOP, Z);
+ n->lineno = lno;
+ outpop0(lno);
+}
+
+void
+codgen(Node *n, Node *nn, int lastlno)
+{
+ if(passes)
+ codgen1(n, nn, lastlno);
+ else
+ codgen2(n, nn, lastlno, 1);
+}
+
+void
+vtgen(Node *n)
+{
+ if(passes)
+ vtgen1(n);
+ else
+ vtgen2(n);
+}
+
+void
+etgen(Sym *s)
+{
+ if(passes)
+ etgen1(s);
+ else
+ etgen2(s);
+}
+
+void
+ttgen(Type *t)
+{
+ if(passes)
+ ttgen1(t);
+ else
+ ttgen2(t);
+}
+
+void
+outpush(char *s)
+{
+ if(passes)
+ outpush1(s);
+ else
+ outpush2(s, Z);
+}
+
+void
+outpop(int lno)
+{
+ if(passes)
+ outpop1(lno);
+ else
+ outpop2(lno);
+}
+
+static void
+swalk(void)
+{
+ Node *n, *l;
+
+ for(n = glob; n != Z; n = n->right){
+ l = n->left;
+ switch(n->op){
+ case OCODE:
+ rewall(l->left, l->right, n->lineno);
+ break;
+ default:
+ break;
+ }
+ }
+ while(again){
+ again = 0;
+ for(n = glob; n != Z; n = n->right){
+ l = n->left;
+ switch(n->op){
+ case OCODE:
+ suball(l->left, l->right);
+ break;
+ case ODECV:
+ subs(l, 0, 0);
+ break;
+ case ODECE:
+ case ODECT:
+ case ODECF:
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ for(n = glob; n != Z; n = n->right){
+ l = n->left;
+ switch(n->op){
+ case ONOOP:
+ break;
+ case OPUSH:
+ outpush2(n->cstring, n);
+ break;
+ case OPOP:
+ outpop2(n->lineno);
+ break;
+ case OCODE:
+ codgen2(l->left, l->right, n->lineno, 0);
+ break;
+ case ODECV:
+ vtgen2(l);
+ break;
+ case ODECE:
+ etgen2(n->sym);
+ break;
+ case ODECT:
+ ttgen2(n->type);
+ break;
+ case ODECF:
+ break;
+ }
+ }
+}
+
+static void
+scomplex(Node *n)
+{
+ if(n == Z)
+ return;
+ switch(n->op){
+ default:
+ complex(n);
+ break;
+ case ODAS:
+ case OSBREAK:
+ case ONUL:
+ case OLABEL:
+ case OGOTO:
+ case OCONTINUE:
+ case OBREAK:
+ break;
+ case ONAME:
+ if(n->kind == KEXP)
+ complex(n);
+ break;
+ case OBLK:
+ case OSET:
+ case OUSED:
+ scomplex(n->left);
+ break;
+ case OLIST:
+ scomplex(n->left);
+ scomplex(n->right);
+ break;
+ case ORETURN:
+ complex(n);
+ break;
+ case OCASE:
+ complex(n->left);
+ break;
+ case OSWITCH:
+ case OWHILE:
+ case ODWHILE:
+ complex(n->left);
+ scomplex(n->right);
+ break;
+ case OFOR:
+ complex(n->left->left);
+ complex(n->left->right->left);
+ complex(n->left->right->right);
+ scomplex(n->right);
+ break;
+ case OIF:
+ complex(n->left);
+ scomplex(n->right->left);
+ scomplex(n->right->right);
+ break;
+ }
+}
+
+static void
+mtset(Type *t)
+{
+ if(t == T)
+ return;
+ switch(t->etype){
+ case TIND:
+ case TARRAY:
+ mtset(t->link);
+ break;
+ case TSTRUCT:
+ case TUNION:
+ prsym0(suename(t));
+ /*
+ for(l = t->link; l != T; l = l->down)
+ mtset(l);
+ */
+ break;
+ }
+}
+
+static void
+mset(Node *n)
+{
+ if(n == Z)
+ return;
+ n->garb = 0;
+ if(n->op == ONAME)
+ prsym0(n->sym);
+ mtset(n->type);
+ mset(n->left);
+ mset(n->right);
+}
+
+static int
+sign(Node *n)
+{
+ int s;
+
+ if(n == Z)
+ return 1;
+ switch(n->op){
+ case OCONST:
+ sign(n->left);
+ if(n->vconst < 0){
+ n->vconst = -n->vconst;
+ return -1;
+ }
+ break;
+ case OPOS:
+ s = sign(n->left);
+ *n = *n->left;
+ return s;
+ case ONEG:
+ s = sign(n->left);
+ *n = *n->left;
+ return -s;
+ case OADD:
+ if(sign(n->right) < 0)
+ n->op = OSUB;
+ break;
+ case OSUB:
+ if(sign(n->right) < 0)
+ n->op = OADD;
+ break;
+ case OMUL:
+ case ODIV:
+ return sign(n->left)*sign(n->right);
+ default:
+ break;
+ }
+ return 1;
+}
+
+static Node*
+ckneg(Node *n)
+{
+ if(sign(n) < 0)
+ return new1(ONEG, n, Z);
+ return n;
+}
+
+static void
+sliceasgn(Node *n)
+{
+ Type *t;
+ Node *nn;
+
+ if(side(n->left) || (n->right != Z && side(n->right)))
+ return;
+ t = n->type;
+ if(isarray(t) && (!strings || t->link->etype != TCHAR)){
+ if(n->op == OASADD)
+ nn = n->right;
+ else
+ nn = con(1);
+ n->op = OAS;
+ n->right = new1(OSLICE, ncopy(n->left), new1(OLIST, nn, Z));
+ }
+}
diff --git a/utils/c2l/cc.h b/utils/c2l/cc.h
new file mode 100644
index 00000000..3900506d
--- /dev/null
+++ b/utils/c2l/cc.h
@@ -0,0 +1,849 @@
+#include <lib9.h>
+#include <bio.h>
+#include <ctype.h>
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+typedef struct Node Node;
+typedef struct Sym Sym;
+typedef struct Type Type;
+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];
+};
+
+EXTERN int lastnumbase;
+
+#define KNIL 0
+#define KCHR 1
+#define KOCT 2
+#define KDEC 3
+#define KHEX 4
+#define KEXP 5
+#define KDROP 6
+#define KLAST 7
+
+struct Node
+{
+ Node* left;
+ Node* right;
+ double fconst; /* fp constant */
+ vlong vconst; /* non fp const */
+ char* cstring; /* character string */
+ ushort* rstring; /* rune string */
+
+ Sym* sym;
+ Type* type;
+ long lineno;
+ char op;
+ char garb;
+ char kind;
+ char blk;
+};
+#define Z ((Node*)0)
+#define ZZ ((Node*)-1)
+
+struct Sym
+{
+ Sym* link;
+ Type* type;
+ Type* suetag;
+ Type* tenum;
+ char* macro;
+ long lineno;
+ long offset;
+ vlong vconst;
+ double fconst;
+ Node* nconst;
+ char* cstring;
+ Node* label;
+ char *name;
+ char *lname;
+ char *mod;
+ ushort lexical;
+ ushort block;
+ ushort sueblock;
+ char class;
+ char kind;
+ char lkw;
+ char args;
+ char fd;
+ char limbo;
+};
+#define S ((Sym*)0)
+
+struct Decl
+{
+ Decl* link;
+ Sym* sym;
+ Type* type;
+ long offset;
+ long lineno;
+ short val;
+ ushort block;
+ char class;
+};
+#define D ((Decl*)0)
+
+struct Type
+{
+ Sym* sym;
+ Sym* tag;
+ Type* link;
+ Type* down;
+ Node* nwidth;
+ long width;
+ long offset;
+ long lineno;
+ char shift;
+ char nbits;
+ char etype;
+ char garb;
+ char vis;
+ char mark;
+};
+#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 /* also in ../{8a,0a}.h */
+{
+ Plan9 = 1<<0,
+ Unix = 1<<1,
+ Windows = 1<<2,
+};
+
+enum
+{
+ DMARK,
+ DAUTO,
+ DSUE,
+ DLABEL,
+};
+enum
+{
+ ONOOP,
+ 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,
+ OELEM,
+
+ OTST, /* used in some compilers */
+ OINDEX,
+ OFAS,
+
+ OBLK,
+ OPOS,
+ ONUL,
+ ODOTIND,
+ OARRIND,
+ ODAS,
+ OASD,
+ OIOTA,
+ OLEN,
+ OBRACKET,
+ OREF,
+ OARRAYOF,
+ OSLICE,
+ OSADDR,
+ ONIL,
+ OS2AB,
+ OAB2S,
+ OFILDES,
+ OFD,
+ OTUPLE,
+ OT0,
+ ORETV,
+ OCAT,
+ OSBREAK,
+ OLDOT,
+ OMDOT,
+
+ OCODE,
+ ODECE,
+ ODECT,
+ ODECV,
+ ODECF,
+ OPUSH,
+ OPOP,
+
+ 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,
+ TREGISTER,
+ TCONSTNT,
+ TVOLATILE,
+ TUNSIGNED,
+ TSIGNED,
+ TDOT,
+ TFILE,
+ TOLD,
+
+ TSTRING,
+ TFD,
+ TTUPLE,
+
+ NALLTYPES,
+};
+enum
+{
+ CXXX,
+ CAUTO,
+ CEXTERN,
+ CGLOBL,
+ CSTATIC,
+ CLOCAL,
+ CTYPEDEF,
+ CPARAM,
+ CSELEM,
+ CLABEL,
+ CEXREG,
+ NCTYPES,
+};
+enum
+{
+ GXXX = 0,
+ GCONSTNT = 1<<0,
+ GVOLATILE = 1<<1,
+ NGTYPES = 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,
+ BOLD = 1L<<TOLD,
+ 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,
+ 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|BREGISTER,
+
+ BGARB = BCONSTNT|BVOLATILE,
+};
+
+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 int comm;
+EXTERN Decl* dclstack;
+EXTERN int doaddr;
+EXTERN int doalladdr;
+EXTERN int doinc;
+EXTERN int doloc;
+EXTERN int domod;
+EXTERN Hist* ehist;
+EXTERN long firstbit;
+EXTERN Decl* firstdcl;
+EXTERN int fperror;
+EXTERN Sym* hash[NHASH];
+EXTERN char* hunk;
+EXTERN char* include[20];
+EXTERN Type* fdtype;
+EXTERN int inmain;
+EXTERN Io* iofree;
+EXTERN Io* ionext;
+EXTERN Io* iostack;
+EXTERN int justcode;
+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 int passes;
+EXTERN char* pathname;
+EXTERN int peekc;
+EXTERN Type* pfdtype;
+EXTERN long pline;
+EXTERN long saveline;
+EXTERN Type* strf;
+EXTERN int strings;
+EXTERN Type* stringtype;
+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 Node* initlist;
+EXTERN int nterm;
+EXTERN int hjdickflg;
+EXTERN int fproundflg;
+EXTERN Bits zbits;
+
+extern char *onames[], *tnames[], *gnames[];
+extern char *cnames[], *qnames[], *bnames[];
+extern char tab[NTYPE][NTYPE];
+extern char 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 char typeaf[];
+extern char typefd[];
+extern char typei[];
+extern char typesu[];
+extern char typesuv[];
+extern char typeu[];
+extern char typev[];
+extern char typec[];
+extern char typeh[];
+extern char typeil[];
+extern char typeilp[];
+extern char typechl[];
+extern char typechlp[];
+extern char typechlpfd[];
+
+extern ulong thash1;
+extern ulong thash2;
+extern ulong thash3;
+extern ulong thash[];
+
+/*
+ * Inferno.c/Posix.c/Nt.c
+ */
+int mywait(int*);
+int mycreat(char*, int);
+int systemtype(int);
+int pathchar(void);
+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 mpatof(char*, double*);
+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 outbegin(char *);
+void outend(void);
+void outfun(Node*);
+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*);
+void 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*, int);
+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);
+#define round ccround
+long round(long, int);
+int rsametype(Type*, Type*, int, int);
+int sametype(Type*, Type*);
+ulong signature(Type*, int);
+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*, Type*);
+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*);
+
+/*
+ * sub.c
+ */
+void arith(Node*, int);
+Type* dotsearch(Sym*, Type*, Node*);
+long dotoffset(Type*, Type*, Node*);
+void gethunk(void);
+Node* invert(Node*);
+int bitno(long);
+void makedot(Node*, Type*, long);
+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* typ1(int, Type*);
+void typeext(Type*, Node*);
+void typeext1(Type*, Node*);
+int side(Node*);
+int vconst(Node*);
+int vlog(Node*);
+int topbit(ulong);
+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*);
+
+/*
+ * 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 praghjdicks(void);
+void pragfpround(void);
+
+/*
+ * calls to machine depend part
+ */
+void codgen(Node*, Node*, int);
+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);
+
+#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
+
+/* output routines */
+
+void prline(char*);
+void prstr(char *);
+void prlstr(ushort *);
+void prkeywd(char *);
+void prid(char *);
+void prsym(Sym*, int);
+void prsym0(Sym*);
+void prdelim(char *);
+void prchar(vlong);
+void prreal(double, char*, int);
+void prnum(vlong, int, Type*);
+void prcom(char *, Node*);
+void newline(void);
+void incind(void);
+void decind(void);
+int zeroind(void);
+void restoreind(int);
+void startcom(int);
+void addcom(int);
+void endcom(void);
+int outcom(int);
+int arrow(Sym*);
+
+/* limbo generating routines */
+
+void pgen(int);
+void epgen(int);
+void ttgen(Type*);
+void vtgen(Node*);
+void etgen(Sym*);
+void expgen(Node*);
+
+/* -m routines */
+
+void newsec(int);
+
+void outpush(char*);
+void outpop(int);
+void outpush0(char*, Node*);
+void outpop0(int);
+void outpush2(char*, Node*);
+void outpop2(int);
+char* outmod(char*, int);
+
+/* miscellaneous */
+
+int iscon(char*);
+Node* ncopy(Node*);
+void doasenum(Sym*);
+Type *maxtype(Type*, Type*);
+
+void linit(void);
+void sysinit(void);
+
+int ism(void);
+int isb(void);
+int dolog(void);
+
+int line(Node*);
+
+void output(long, int);
+void usemod(Sym*, int);
+void setmod(Sym*);
+
+int exists(char*);
+int isconsym(Sym *);
+
+void clbegin(void);
+void clend(void);
+
+int gfltconv(Fmt*);
diff --git a/utils/c2l/cc.y b/utils/c2l/cc.y
new file mode 100644
index 00000000..22dc6c0c
--- /dev/null
+++ b/utils/c2l/cc.y
@@ -0,0 +1,1239 @@
+%{
+#include "cc.h"
+%}
+%union {
+ Node* node;
+ Sym* sym;
+ Type* type;
+ struct
+ {
+ Type* t;
+ char 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 cname gname tname
+%type <lval> gctnlist zgnlist tnlist
+%type <type> tlist etlist sbody complex
+%type <tycl> types etypes
+%type <node> zarglist arglist zcexpr
+%type <node> name block stmnt cexpr expr xuexpr pexpr
+%type <node> zelist elist adecl slist uexpr string lstring sstring slstring
+%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
+
+%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 LCTYPE LSTYPE
+%token <dval> LFCONST LDCONST
+%token <vval> LCHARACTER 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 LUNION LUNSIGNED LWHILE
+%token LVOID LENUM LSIGNED LCONSTNT LVOLATILE LSET LSIGNOF LVLONG
+%%
+prog:
+| prog xdecl
+
+/*
+ * external declarator
+ */
+xdecl:
+ zctlist ';'
+ {
+ dodecl(xdecl, lastclass, lasttype, Z, 1);
+ }
+| zctlist xdlist ';'
+| zctlist xdecor
+ {
+ lastdcl = T;
+ dodecl(xdecl, lastclass, lasttype, $2, 0);
+ 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
+ {
+ $6->blk = 0;
+ codgen($6, $2, lineno);
+ revertdcl();
+ }
+
+xdlist:
+ xdecor
+ {
+ dodecl(xdecl, lastclass, lasttype, $1, 1);
+ }
+| xdecor
+ {
+ $1 = dodecl(xdecl, lastclass, lasttype, $1, 0);
+ }
+ '=' init
+ {
+ $4 = doinit($1->sym, $1->type, 0L, $4);
+ $4 = new(ODAS, $1, $4);
+ $4->type = $1->type;
+ $4->lineno = $1->lineno;
+ vtgen($4);
+ }
+| xdlist ',' xdlist
+
+xdecor:
+ xdecor2
+| '*' zgnlist xdecor
+ {
+ $$ = new(OIND, $3, Z);
+ $$->garb = simpleg($2);
+ }
+
+xdecor2:
+ tag
+| '(' xdecor ')'
+ {
+ $$ = $2;
+ }
+| xdecor2 '(' zarglist ')'
+ {
+ $$ = new(OFUNC, $1, $3);
+ /* outfun($$); */
+ }
+| xdecor2 '[' zexpr ']'
+ {
+ $$ = new(OARRAY, $1, $3);
+ }
+
+/*
+ * automatic declarator
+ */
+adecl:
+ {
+ $$ = Z;
+ }
+| adecl ctlist ';'
+ {
+ $$ = dodecl(adecl, lastclass, lasttype, Z, 1);
+ if($1 != Z)
+ if($$ != Z)
+ $$ = new(OLIST, $1, $$);
+ else
+ $$ = $1;
+ }
+| adecl ctlist adlist ';'
+ {
+ $$ = $1;
+ if($3 != Z) {
+ $$ = $3;
+ if($1 != Z)
+ $$ = new(OLIST, $1, $3);
+ }
+ }
+
+adlist:
+ xdecor
+ {
+ $$ = dodecl(adecl, lastclass, lasttype, $1, 1);
+ if($$->sym->class == CSTATIC)
+ $$ = Z;
+ }
+| xdecor
+ {
+ $1 = dodecl(adecl, lastclass, lasttype, $1, 0);
+ }
+ '=' init
+ {
+ /* long w; */
+
+ /* w = $1->sym->type->width; */
+ $$ = doinit($1->sym, $1->type, 0L, $4);
+ /* $$ = contig($1->sym, $$, w); */
+ $$ = new(ODAS, $1, $$);
+ $$->type = $1->type;
+ $$->lineno = $1->lineno;
+ vtgen($$);
+ if($1->sym->class == CSTATIC)
+ $$ = Z;
+ }
+| 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, 1);
+ }
+| pdlist ',' pdlist
+
+/*
+ * structure element declarator
+ */
+edecl:
+ etlist
+ {
+ lasttype = $1;
+ }
+ zedlist ';'
+| edecl etlist
+ {
+ lasttype = $2;
+ }
+ zedlist ';'
+
+zedlist: /* extension */
+ {
+ lastfield = 0;
+ edecl(CXXX, lasttype, S);
+ }
+| edlist
+
+edlist:
+ edecor
+ {
+ dodecl(edecl, CXXX, lasttype, $1, 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:
+ '{' adecl slist '}'
+ {
+ $$ = invert($3);
+ if($2 != Z)
+ $$ = new(OLIST, $2, $$);
+ if($$ == Z)
+ $$ = new(ONUL, Z, Z);
+ $$->blk = 1;
+ }
+
+slist:
+ {
+ $$ = Z;
+ }
+| slist stmnt
+ {
+ if($1 == Z)
+ $$ = $2;
+ else
+ $$ = new(OLIST, $1, $2);
+ }
+
+labels:
+ label
+| labels label
+ {
+ $$ = new(OLIST, $1, $2);
+ }
+
+label:
+ LCASE expr ':'
+ {
+ $$ = new(OCASE, $2, Z);
+ $$->lineno = $2->lineno;
+ }
+| LDEFAULT ':'
+ {
+ $$ = new(OCASE, Z, Z);
+ }
+| LNAME ':'
+ {
+ $$ = new(OLABEL, dcllabel($1, 1), Z);
+ $1->lineno = lineno;
+ }
+
+stmnt:
+ error ';'
+ {
+ $$ = Z;
+ }
+| ulstmnt
+| labels ulstmnt
+ {
+ $$ = new(OLIST, $1, $2);
+ }
+
+ulstmnt:
+ zcexpr ';'
+ {
+ if($$ == Z)
+ $$ = new(ONUL, Z, Z);
+ $$->kind = KEXP;
+ }
+| {
+ markdcl();
+ }
+ block
+ {
+ revertdcl();
+ $$ = $2;
+ }
+| LIF '(' cexpr ')' stmnt
+ {
+ $$ = new(OIF, $3, new(OLIST, $5, Z));
+ $$->lineno = $3->lineno;
+ $5->blk = 0;
+ }
+| LIF '(' cexpr ')' stmnt LELSE stmnt
+ {
+ $$ = new(OIF, $3, new(OLIST, $5, $7));
+ $$->lineno = $3->lineno;
+ $5->blk = $7->blk = 0;
+ }
+| LFOR '(' zcexpr ';' zcexpr ';' zcexpr ')' stmnt
+ {
+ $$ = new(OFOR, new(OLIST, $5, new(OLIST, $3, $7)), $9);
+ if($3 != Z)
+ $$->lineno = $3->lineno;
+ else if($5 != Z)
+ $$->lineno = $5->lineno;
+ else if($7 != Z)
+ $$->lineno = $7->lineno;
+ else
+ $$->lineno = line($9);
+ $9->blk = 0;
+ }
+| LWHILE '(' cexpr ')' stmnt
+ {
+ $$ = new(OWHILE, $3, $5);
+ $$->lineno = $3->lineno;
+ $5->blk = 0;
+ }
+| LDO stmnt LWHILE '(' cexpr ')' ';'
+ {
+ $$ = new(ODWHILE, $5, $2);
+ $$->lineno = line($2);
+ $2->blk = 0;
+ }
+| LRETURN zcexpr ';'
+ {
+ $$ = new(ORETURN, $2, Z);
+ $$->type = thisfn->link;
+ if($2 != Z)
+ $$->lineno = $2->lineno;
+ }
+| LSWITCH '(' cexpr ')' stmnt
+ {
+ $$ = new(OSWITCH, $3, $5);
+ $$->lineno = $3->lineno;
+ $5->blk = 0;
+ }
+| LBREAK ';'
+ {
+ $$ = new(OBREAK, Z, Z);
+ }
+| LCONTINUE ';'
+ {
+ $$ = new(OCONTINUE, Z, Z);
+ }
+| LGOTO LNAME ';'
+ {
+ $$ = new(OGOTO, dcllabel($2, 0), Z);
+ $2->lineno = lineno;
+ }
+| LUSED '(' zelist ')' ';'
+ {
+ $$ = new(OUSED, $3, Z);
+ $$->lineno = line($3);
+ }
+| LSET '(' zelist ')' ';'
+ {
+ $$ = new(OSET, $3, Z);
+ $$->lineno = line($3);
+ }
+
+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, 1);
+ $$->type = lastdcl;
+ }
+| '(' tlist abdecor ')' '{' ilist '}' /* extension */
+ {
+ $$ = new(OSTRUCT, $6, Z);
+ dodecl(NODECL, CXXX, $2, $3, 1);
+ $$->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, 1);
+ $$->type = lastdcl;
+ }
+| LSIGNOF '(' tlist abdecor ')'
+ {
+ $$ = new(OSIGN, Z, Z);
+ dodecl(NODECL, CXXX, $3, $4, 1);
+ $$->type = lastdcl;
+ }
+| pexpr '(' zelist ')'
+ {
+ $$ = new(OFUNC, $1, Z);
+ if($1->op == ONAME)
+ if($1->type == T)
+ dodecl(xdecl, CXXX, types[TINT], $$, 1);
+ $$->right = invert($3);
+ $$->kind = KEXP;
+ }
+| pexpr '[' cexpr ']'
+ {
+ $$ = new(OARRIND, $1, $3);
+ }
+| pexpr LMG ltag
+ {
+ $$ = new(ODOTIND, $1, Z);
+ $$->sym = $3;
+ }
+| pexpr '.' ltag
+ {
+ $$ = new(ODOT, $1, Z);
+ $$->sym = $3;
+ }
+| pexpr LPP
+ {
+ $$ = new(OPOSTINC, $1, Z);
+ }
+| pexpr LMM
+ {
+ $$ = new(OPOSTDEC, $1, Z);
+ }
+| name
+| LCHARACTER
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TINT];
+ $$->vconst = $1;
+ $$->kind = KCHR;
+ }
+| LCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TINT];
+ $$->vconst = $1;
+ $$->kind = lastnumbase;
+ }
+| LLCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TLONG];
+ $$->vconst = $1;
+ $$->kind = lastnumbase;
+ }
+| LUCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TUINT];
+ $$->vconst = $1;
+ $$->kind = lastnumbase;
+ }
+| LULCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TULONG];
+ $$->vconst = $1;
+ $$->kind = lastnumbase;
+ }
+| LDCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TDOUBLE];
+ $$->fconst = $1;
+ $$->cstring = strdup(symb);
+ $$->kind = lastnumbase;
+ }
+| LFCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TFLOAT];
+ $$->fconst = $1;
+ $$->cstring = strdup(symb);
+ $$->kind = lastnumbase;
+ }
+| LVLCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TVLONG];
+ $$->vconst = $1;
+ $$->kind = lastnumbase;
+ }
+| LUVLCONST
+ {
+ $$ = new(OCONST, Z, Z);
+ $$->type = types[TUVLONG];
+ $$->vconst = $1;
+ $$->kind = lastnumbase;
+ }
+| string
+| lstring
+
+sstring:
+ LSTRING
+ {
+ $$ = new(OSTRING, Z, Z);
+ $$->type = typ(TARRAY, types[TCHAR]);
+ $$->type->width = $1.l + 1;
+ $$->cstring = $1.s;
+ $$->sym = symstring;
+ }
+
+string:
+ sstring
+ {
+ $$ = $1;
+ }
+| string sstring
+ {
+ char *s;
+ int n1, n2;
+
+ n1 = $1->type->width - 1;
+ n2 = $2->type->width - 1;
+ s = alloc(n1+n2+MAXALIGN);
+
+ memcpy(s, $1->cstring, n1);
+ memcpy(s+n1, $2->cstring, n2);
+ s[n1+n2] = 0;
+
+ $1->left = new(OCAT, ncopy($1), $2);
+
+ $$ = $1;
+ $$->type->width += n2;
+ $$->cstring = s;
+ }
+
+slstring:
+ LLSTRING
+ {
+ $$ = new(OLSTRING, Z, Z);
+ $$->type = typ(TARRAY, types[TUSHORT]);
+ $$->type->width = $1.l + sizeof(ushort);
+ $$->rstring = (ushort*)$1.s;
+ $$->sym = symstring;
+ }
+
+lstring:
+ slstring
+ {
+ $$ = $1;
+ }
+| lstring slstring
+ {
+ char *s;
+ int n1, n2;
+
+ n1 = $1->type->width - sizeof(ushort);
+ n2 = $2->type->width - sizeof(ushort);
+ s = alloc(n1+n2+MAXALIGN);
+
+ memcpy(s, $1->rstring, n1);
+ memcpy(s+n1, $2->rstring, n2);
+ *(ushort*)(s+n1+n2) = 0;
+
+ $1->left = new(OCAT, ncopy($1), $2);
+
+ $$ = $1;
+ $$->type->width += n2;
+ $$->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
+
+etypes:
+ complex
+ {
+ $$.t = $1;
+ $$.c = CXXX;
+ }
+| tnlist
+ {
+ $$.t = simplet($1);
+ $$.c = simplec($1);
+ }
+
+types:
+ complex
+ {
+ $$.t = $1;
+ $$.c = CXXX;
+ }
+| complex gctnlist
+ {
+ $$.t = $1;
+ $$.c = simplec($2);
+ if($2 & ~BCLASS & ~BGARB)
+ diag(Z, "illegal combination of types 1: %Q/%T", $2, $1);
+ }
+| gctnlist
+ {
+ $$.t = simplet($1);
+ $$.c = simplec($1);
+ $$.t = garbt($$.t, $1);
+ }
+| gctnlist complex
+ {
+ $$.t = $2;
+ $$.c = simplec($1);
+ $$.t = garbt($$.t, $1);
+ if($1 & ~BCLASS & ~BGARB)
+ diag(Z, "illegal combination of types 2: %Q/%T", $1, $2);
+ }
+| gctnlist complex gctnlist
+ {
+ $$.t = $2;
+ $$.c = simplec($1|$3);
+ $$.t = garbt($$.t, $1|$3);
+ if(($1|$3) & ~BCLASS & ~BGARB || $3 & BCLASS)
+ diag(Z, "illegal combination of types 3: %Q/%T/%Q", $1, $2, $3);
+ }
+
+etlist:
+ zgnlist etypes
+ {
+ $$ = $2.t;
+ if($2.c != CXXX)
+ diag(Z, "illegal combination of class 4: %s", cnames[$2.c]);
+ $$ = garbt($$, $1);
+ }
+
+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;
+ $2->lineno = lineno;
+ }
+| LSTRUCT ltag
+ {
+ dotag($2, TSTRUCT, autobn);
+ saveline = $2->lineno = lineno;
+ }
+ sbody
+ {
+ $$ = $2->suetag;
+ if($$->link != T)
+ diag(Z, "redeclare tag: %s", $2->name);
+ $$->link = $4;
+ $$->lineno = saveline;
+ suallign($$);
+ }
+| LSTRUCT
+ {
+ saveline = lineno;
+ }
+ sbody
+ {
+ char buf[128];
+
+ taggen++;
+ sprint(symb, "%s_adt_%d", outmod(buf, -1), taggen);
+ $$ = dotag(lookup(), TSTRUCT, autobn);
+ $$->link = $3;
+ $$->lineno = saveline;
+ lookup()->lineno = saveline;
+ suallign($$);
+ }
+| LUNION ltag
+ {
+ dotag($2, TUNION, 0);
+ $$ = $2->suetag;
+ $2->lineno = lineno;
+ }
+| LUNION ltag
+ {
+ dotag($2, TUNION, autobn);
+ saveline = $2->lineno = lineno;
+ }
+ sbody
+ {
+ $$ = $2->suetag;
+ if($$->link != T)
+ diag(Z, "redeclare tag: %s", $2->name);
+ $$->link = $4;
+ $$->lineno = saveline;
+ suallign($$);
+ }
+| LUNION
+ {
+ saveline = lineno;
+ }
+ sbody
+ {
+ char buf[128];
+
+ taggen++;
+ sprint(symb, "%s_adt_%d", outmod(buf, -1), taggen);
+ $$ = dotag(lookup(), TUNION, autobn);
+ $$->link = $3;
+ $$->lineno = saveline;
+ lookup()->lineno = saveline;
+ suallign($$);
+ }
+| LENUM ltag
+ {
+ dotag($2, TENUM, 0);
+ $$ = $2->suetag;
+ if($$->link == T)
+ $$->link = types[TINT];
+ $$ = $$->link;
+ $2->lineno = lineno;
+ }
+| LENUM ltag
+ {
+ dotag($2, TENUM, autobn);
+ $2->lineno = lineno;
+ }
+ '{'
+ {
+ 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;
+ etgen(nil);
+ }
+| LENUM '{'
+ {
+ en.tenum = T;
+ en.cenum = T;
+ }
+ enum '}'
+ {
+ $$ = en.tenum;
+ etgen(nil);
+ }
+| LCTYPE
+ {
+ $$ = tcopy($1->type);
+ }
+| LSTYPE
+ {
+ $$ = tcopy($1->type);
+ }
+
+tnlist:
+ tname
+| tnlist tname
+ {
+ $$ = typebitor($1, $2);
+ }
+
+gctnlist:
+ gctname
+| gctnlist gctname
+ {
+ $$ = typebitor($1, $2);
+ }
+
+zgnlist:
+ {
+ $$ = 0;
+ }
+| zgnlist gname
+ {
+ $$ = typebitor($1, $2);
+ }
+
+gctname:
+ tname
+| gname
+| cname
+
+enum:
+ LNAME
+ {
+ doenum($1, Z);
+ $1->lineno = lineno;
+ }
+| LNAME '=' expr
+ {
+ doenum($1, $3);
+ $1->lineno = lineno;
+ }
+| enum ','
+| enum ',' enum
+
+tname: /* type words */
+ LCHAR { $$ = BCHAR; }
+| LSHORT { $$ = BSHORT; }
+| LINT { $$ = BINT; }
+| LLONG { $$ = BLONG; }
+| LSIGNED { $$ = BSIGNED; }
+| LUNSIGNED { $$ = BUNSIGNED; }
+| LFLOAT { $$ = BFLOAT; }
+| LDOUBLE { $$ = BDOUBLE; }
+| LVOID { $$ = BVOID; }
+| LVLONG { $$ = BVLONG|BLONG; }
+
+cname: /* class words */
+ LAUTO { $$ = BAUTO; }
+| LSTATIC { $$ = BSTATIC; }
+| LEXTERN { $$ = BEXTERN; }
+| LTYPEDEF { $$ = BTYPEDEF; }
+| LREGISTER { $$ = BREGISTER; }
+
+gname:
+ LCONSTNT { $$ = BCONSTNT; }
+| LVOLATILE { $$ = BVOLATILE; }
+
+name:
+ LNAME
+ {
+ $$ = new(ONAME, Z, Z);
+ if($1->class == CLOCAL)
+ $1 = mkstatic($1);
+ $$->sym = $1;
+ $$->type = $1->type;
+ }
+tag:
+ ltag
+ {
+ $$ = new(ONAME, Z, Z);
+ $$->sym = $1;
+ $$->type = $1->type;
+ }
+ltag:
+ LNAME
+| LCTYPE
+| LSTYPE
+
+%%
diff --git a/utils/c2l/com.c b/utils/c2l/com.c
new file mode 100644
index 00000000..283c2ae9
--- /dev/null
+++ b/utils/c2l/com.c
@@ -0,0 +1,918 @@
+#include "cc.h"
+
+void
+complex(Node *n)
+{
+
+ if(n == Z)
+ return;
+
+ nearln = n->lineno;
+ if(tcom(n))
+ return;
+ ccom(n);
+ acom(n);
+}
+
+/*
+ * 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();
+ }
+ 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(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:
+ case OASD:
+ 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;
+ 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;
+ typeext1(l->type, r);
+ if(tlvalue(l) || 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)) {
+ 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;
+ typeext1(l->type, r);
+ if(tlvalue(l) || 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)) {
+ 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) || 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) || 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)) {
+ 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) || 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;
+ 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;
+ 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(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(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(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(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(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(tcompat(n, l->type, r->type, tand))
+ goto bad;
+ arith(n, 1);
+ if(typeu[n->type->etype])
+ n->op = OLMOD;
+ break;
+
+ case ONOT:
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, T, l->type, tnot))
+ goto bad;
+ n->type = types[TINT];
+ break;
+
+ case OPOS:
+ case ONEG:
+ case OCOM:
+ if(tcom(l))
+ goto bad;
+ n->type = l->type;
+ break;
+
+ case ONUL:
+ break;
+
+ case OIOTA:
+ n->type = types[TINT];
+ break;
+
+ case ODAS:
+ n->type = n->left->type;
+ 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->right = ncopy(n);
+ n->op = OCONST;
+ n->left = Z;
+ /* n->right = Z; */
+ n->vconst = convvtox(signature(n->type, 10), 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->right = ncopy(n);
+ 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(1)
+ 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) {
+ if(n->sym->tenum->etype == TIND){
+ /* n->op = OSTRING; */
+ n->type = n->sym->tenum;
+ /* n->cstring = n->sym->sconst; */
+ break;
+ }
+ n->left = ncopy(n);
+ n->op = OCONST;
+ n->type = n->sym->tenum;
+ if(!typefd[n->type->etype])
+ n->vconst = n->sym->vconst;
+ else{
+ n->fconst = n->sym->fconst;
+ n->cstring = n->sym->cstring;
+ }
+ break;
+ }
+ break;
+
+ case OLSTRING:
+ case OSTRING:
+ case OCONST:
+ break;
+
+ case ODOT:
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, T, l->type, tdot))
+ goto bad;
+ if(tcomd(n, l->type))
+ goto bad;
+ break;
+
+ case ODOTIND:
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, T, l->type, tindir))
+ goto bad;
+ if(tcompat(n, T, l->type->link, tdot))
+ goto bad;
+ if(tcomd(n, l->type->link))
+ goto bad;
+ break;
+
+ case OARRIND:
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, T, l->type, tindir))
+ goto bad;
+ n->type = l->type->link;
+ if(tcom(r))
+ 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 = typ1(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;
+ 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(n->type->etype == TARRAY)
+ n->type = typ1(TIND, n->type->link);
+ return 0;
+ 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->type = typ1(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]; */
+ t = n->type;
+ break;
+
+ case TUCHAR:
+ case TUSHORT:
+ /* t = types[TUINT]; */
+ t = n->type;
+ break;
+
+ case TFLOAT:
+ /* t = types[TDOUBLE]; */
+ t = n->type;
+ }
+ }
+ 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;
+ }
+ return 0;
+}
+
+int
+tcomd(Node *n, Type *t)
+{
+ long o;
+
+ o = 0;
+ /* t = n->left->type; */
+ for(;;) {
+ t = dotsearch(n->sym, t->link, n);
+ if(t == T) {
+ diag(n, "not a member of struct/union: %F", n);
+ return 1;
+ }
+ o += t->offset;
+ if(t->sym == n->sym)
+ break;
+ if(sametype(t, n->sym->type))
+ break;
+ }
+ n->type = t;
+ 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(0) {
+ 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;
+
+ if(n == Z)
+ return;
+ l = n->left;
+ r = n->right;
+ switch(n->op) {
+
+ case OAS:
+ case OASD:
+ 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);
+ 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);
+ relcon(l, r);
+ relcon(r, l);
+ goto common;
+
+ case OASHR:
+ case OASHL:
+ case OLSHR:
+ ccom(l);
+ ccom(r);
+ 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;
+
+ 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);
+ }
+}
diff --git a/utils/c2l/com64.c b/utils/c2l/com64.c
new file mode 100644
index 00000000..9a193ef3
--- /dev/null
+++ b/utils/c2l/com64.c
@@ -0,0 +1,52 @@
+#include "cc.h"
+
+/*
+ * this is machine depend, but it is totally
+ * common on all of the 64-bit symulating machines.
+ */
+
+/*
+ * 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/utils/c2l/dcl.c b/utils/c2l/dcl.c
new file mode 100644
index 00000000..6fb6977a
--- /dev/null
+++ b/utils/c2l/dcl.c
@@ -0,0 +1,1387 @@
+#include "cc.h"
+
+Node*
+dodecl(void (*f)(int,Type*,Sym*), int c, Type *t, Node *n, int gen)
+{
+ 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;
+ t->nwidth = n1->left;
+ }
+ 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;
+ acidvar(s);
+ if(gen)
+ vtgen(n);
+ 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 = typ(TXXX, 0);
+ *tx = *t;
+ tx->link = tl;
+ return tx;
+ }
+ return t;
+}
+
+Node*
+doinit(Sym *s, Type *t, long o, Node *a)
+{
+ Node *n, *reta;
+
+ if(t == T)
+ return Z;
+ if(s->class == CEXTERN)
+ s->class = CGLOBL;
+ if(0) {
+ 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;
+
+ reta = a;
+ init1(s, t, o, 0);
+ if(initlist != Z)
+ diag(initlist, "more initializers than structure: %s",
+ s->name);
+ initlist = n;
+
+ return reta;
+}
+
+/*
+ * 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, *n;
+
+ a = initlist;
+ n = Z;
+
+ if(a == Z)
+ return a;
+ if(a->op == OLIST) {
+ n = a->right;
+ a = a->left;
+ }
+ 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;
+}
+
+void
+init1(Sym *s, Type *t, long o, int exflag)
+{
+ Node *a, *r, nod;
+ Type *t1;
+ long e, w, so, mw;
+
+ a = peekinit();
+ if(a == Z)
+ return;
+
+ if(0) {
+ print("t = %T; o = %ld; n = %s\n", t, o, s->name);
+ prtree(a, "init1 value");
+ }
+
+ if(exflag && a->op == OINIT){
+ doinit(s, t, o, nextinit());
+ return;
+ }
+
+ switch(t->etype) {
+ default:
+ diag(Z, "unknown type in initialization: %T to: %s", t, s->name);
+ return;
+
+ 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;
+
+ a = nextinit();
+ if(a == Z)
+ return;
+
+ if(t->nbits)
+ diag(Z, "cannot initialize bitfields");
+ if(0 && s->class == CAUTO)
+ return;
+
+ complex(a);
+ if(a->type == T)
+ return;
+
+ if(a->op == OCONST) {
+ 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;
+ }
+ if(vconst(a) == 0)
+ return;
+ return;
+ }
+ if(t->etype == TIND) {
+ while(a->op == OCAST) {
+ warn(a, "CAST in initialization ignored");
+ a = a->left;
+ }
+ if(0 && !sametype(t, a->type)) {
+ diag(a, "initialization of incompatible pointers: %s",
+ s->name);
+ print("%T and %T\n", t, a->type);
+ }
+/*
+ if(a->op == OADDR)
+ a = a->left;
+*/
+ return;
+ }
+
+ while(a->op == OCAST)
+ a = a->left;
+ if(a->op == OADDR) {
+ warn(a, "initialize pointer to an integer: %s", s->name);
+ /* a = a->left; */
+ return;
+ }
+ /* diag(a, "initializer is not a constant: %s", s->name); */
+ return;
+
+ 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(t->width <= 0)
+ t->width = w*(so-1);
+ USED(a);
+ return;
+ }
+
+ mw = -w;
+ 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;
+ }
+ 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;
+ init1(s, t->link, o+so, 1);
+ e++;
+ }
+ if(t->width == 0)
+ t->width = mw+w;
+ return;
+
+ 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;
+ }
+
+ 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();
+ }
+ init1(s, t1, o+t1->offset, 1);
+ 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;
+ }
+}
+
+/*
+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 = round(w, tfield->width);
+ o = w;
+ w += tfield->width;
+ }
+ l->offset = o;
+ } else {
+ if(l->width <= 0)
+ 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);
+ ttgen(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);
+ ttgen(t);
+ return;
+
+ default:
+ diag(Z, "unknown type in suallign: %T", t);
+ break;
+ }
+}
+
+long
+round(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:
+ if(n->type == T)
+ n->type = n->sym->type;
+ t = typ(TXXX, T);
+ *t = *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);
+ 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;
+}
+
+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, 1);
+ 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, 1);
+ 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) {
+ autoffset = align(autoffset, s->type, Aarg1);
+ s->offset = autoffset;
+ autoffset = align(autoffset, s->type, Aarg2);
+ } else
+ dodecl(pdecl, CXXX, types[TINT], n, 1);
+ 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;
+
+ 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;
+ free(d);
+ return Z;
+
+ case DAUTO:
+ if(0) {
+ 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);
+ }
+ s->type = d->type;
+ s->class = d->class;
+ s->offset = d->offset;
+ s->block = d->block;
+ s->lineno = d->lineno;
+ break;
+
+ case DSUE:
+ s->suetag = d->type;
+ s->sueblock = d->block;
+ s->lineno = d->lineno;
+ break;
+
+ case DLABEL:
+ if(0 && s->label)
+ warn(s->label, "label declared and not used \"%s\"", s->name);
+ s->label = Z;
+ s->lineno = d->lineno;
+ break;
+ }
+ free(d);
+ }
+ return Z;
+}
+
+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;
+ n = dodecl(NODECL, CXXX, n->type, n->left, 1);
+ t = typ(TXXX, T);
+ if(lastdcl != T)
+ *t = *paramconv(lastdcl, 1);
+ if(n != Z && n->op == ONAME)
+ t->sym = n->sym;
+ 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)
+{
+ static Decl zdecl;
+ Decl *d;
+
+ d = alloc(sizeof(*d));
+ *d = zdecl;
+ 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->lineno = s->lineno;
+ 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] || et == TTUPLE) {
+ 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 || 1) && et == TIND) {
+ if(t1 != T && t1->etype == TVOID)
+ return 1;
+ if(t2 != T && t2->etype == TVOID)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+ulong
+signature(Type *t, int n)
+{
+ Type *t1;
+ long s;
+
+ s = 0;
+ if(n > 0)
+ for(; t; t=t->link) {
+ s = s*thash1 + thash[t->etype];
+ switch(t->etype) {
+ default:
+ return s;
+ case TARRAY:
+ s = s*thash2 + t->width;
+ break;
+ case TFUNC:
+ case TSTRUCT:
+ case TUNION:
+ for(t1=t; t1; t1=t1->down)
+ s = s*thash3 + signature(t1, n-1);
+ case TIND:
+ break;
+ }
+ }
+ return s;
+}
+
+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;
+ d->lineno = s->lineno;
+ 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(0)
+ diag(Z, "label reused: %s", s->name);
+ }
+ return n;
+ }
+
+ d = push();
+ d->sym = s;
+ d->val = DLABEL;
+ d->lineno = s->lineno;
+ dclstack = d->link;
+
+ d1 = *firstdcl;
+ *firstdcl = *d;
+ *d = d1;
+
+ firstdcl->link = d;
+ firstdcl = d;
+
+ n = new(OXXX, Z, Z);
+ n->sym = s;
+ s->label = n;
+ return n;
+}
+
+Type*
+paramconv(Type *t, int f)
+{
+ f = 1;
+ 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;
+ }
+ switch(c) {
+ case CAUTO:
+ autoffset = align(autoffset, t, Aaut3);
+ s->offset = -autoffset;
+ break;
+
+ case CPARAM:
+ autoffset = align(autoffset, t, Aarg1);
+ if(s)
+ s->offset = autoffset;
+ autoffset = align(autoffset, t, Aarg2);
+ break;
+ }
+ if(s)
+ s->lineno = lineno;
+}
+
+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);
+ if(s)
+ s->lineno = lineno;
+}
+
+void
+xdecl(int c, Type *t, Sym *s)
+{
+ long o;
+
+ o = 0;
+ if(c == CEXREG)
+ c = CEXTERN;
+ if(c == CXXX) {
+ c = CGLOBL;
+ if(s->class == CEXTERN)
+ s->class = c;
+ }
+ if(c == CEXTERN)
+ if(s->class == CGLOBL)
+ c = CGLOBL;
+ if(c == CAUTO) {
+ diag(Z, "overspecified class: %s %s %s", s->name, cnames[c], cnames[s->class]);
+ c = CEXTERN;
+ }
+ 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);
+ print(" %s %T; %s %T\n", cnames[c], t, cnames[s->class], s->type);
+ }
+ 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)
+{
+ long l;
+ 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 = typ(TXXX, T);
+ l = t->lineno;
+ *t = *t1;
+ t->lineno = l;
+ 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)
+{
+ int k = KDEC;
+ Node *nc;
+
+ nc = Z;
+ if(n) {
+ k = n->kind;
+ complex(n);
+ if(n->op != OCONST && n->op != OSTRING && n->op != OLSTRING) {
+ diag(n, "enum not a constant: %s", s->name);
+ return;
+ }
+ nc = n->left;
+ 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(s->tenum->etype == TIND){ /* string */
+ nc = n;
+ s->tenum = n->type;
+ }
+ else if(!typefd[s->tenum->etype]) {
+ s->vconst = convvtox(en.lastenum, s->tenum->etype);
+ en.lastenum++;
+ s->tenum = types[TINT];
+ } else {
+ s->fconst = en.floatenum;
+ if(n)
+ s->cstring = n->cstring;
+ else
+ s->cstring = nil;
+ en.floatenum++;
+ s->tenum = types[TDOUBLE];
+ }
+ s->nconst = nc;
+
+ acidvar(s);
+ s->kind = k;
+ etgen(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:
+ return;
+
+ case OCONST:
+ case OSTRING:
+ case OLSTRING:
+ case OINDREG:
+ case OREGISTER:
+ return;
+ }
+}
diff --git a/utils/c2l/dpchk.c b/utils/c2l/dpchk.c
new file mode 100644
index 00000000..78865cb8
--- /dev/null
+++ b/utils/c2l/dpchk.c
@@ -0,0 +1,392 @@
+#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[256];
+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 c, f;
+ char *fmt;
+
+ fmt = fmtbuf;
+ flag = zbits;
+ nstar = 0;
+ while(c = *s++) {
+ *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;
+
+ 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('+', 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;
+
+ if(1)
+ goto out;
+ s = getsym();
+ if(s && strcmp(s->name, "argpos") == 0)
+ goto ckpos;
+ if(s && strcmp(s->name, "type") == 0)
+ goto cktype;
+ 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;
+
+cktype:
+/*#pragma varargck type O int*/
+ c = getnsc();
+ if(c != '"')
+ goto bad;
+ t = fmtbuf;
+ for(;;) {
+ c = getc();
+ if(c == ' ' || c == '\n')
+ goto bad;
+ if(c == '"')
+ break;
+ *t++ = c;
+ }
+ *t = 0;
+ t = strdup(fmtbuf);
+ s = getsym();
+ if(s == S)
+ goto bad;
+ c = getnsc();
+ unget(c);
+ if(c == '*')
+ newprot(s, typ(TIND, s->type), t);
+ else
+ newprot(s, s->type, 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(1)
+ 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))
+ 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
+praghjdicks(void)
+{
+ Sym *s;
+
+ hjdickflg = 0;
+ s = getsym();
+ if(s) {
+ hjdickflg = atoi(s->name+1);
+ if(strcmp(s->name, "on") == 0 ||
+ strcmp(s->name, "yes") == 0 ||
+ strcmp(s->name, "dick") == 0)
+ hjdickflg = 1;
+ }
+ while(getnsc() != '\n')
+ ;
+ if(0)
+ if(hjdickflg)
+ print("%4ld: hjdicks %d\n", lineno, hjdickflg);
+ else
+ print("%4ld: hjdicks off\n", lineno);
+}
+
+void
+pragfpround(void)
+{
+ Sym *s;
+
+ fproundflg = 0;
+ s = getsym();
+ if(s) {
+ hjdickflg = atoi(s->name+1);
+ if(strcmp(s->name, "on") == 0 ||
+ strcmp(s->name, "yes") == 0 ||
+ strcmp(s->name, "dick") == 0)
+ fproundflg = 1;
+ }
+ while(getnsc() != '\n')
+ ;
+ if(0)
+ if(fproundflg)
+ print("%4ld: fproundflg %d\n", lineno, fproundflg);
+ else
+ print("%4ld: fproundflg off\n", lineno);
+}
diff --git a/utils/c2l/lex.c b/utils/c2l/lex.c
new file mode 100644
index 00000000..5701dd99
--- /dev/null
+++ b/utils/c2l/lex.c
@@ -0,0 +1,1675 @@
+#include "cc.h"
+#include "y.tab.h"
+
+#ifndef CPP
+#define CPP "/bin/cpp"
+#endif
+
+static int ansip;
+
+void
+main(int argc, char *argv[])
+{
+ char *defs[50], *p;
+ int nproc, nout, status, i, c, ndef;
+
+ tinit();
+ cinit();
+ ginit();
+ arginit();
+
+ tufield = simplet((1L<<tfield->etype) | BUNSIGNED);
+ ndef = 0;
+ include[ninclude++] = ".";
+ strings = 1;
+ passes = 1;
+
+ ARGBEGIN {
+ default:
+ break;
+
+ case 'p':
+ ansip = 1;
+ break;
+
+ case 'D':
+ p = ARGF();
+ if(p) {
+ defs[ndef++] = p;
+ dodefine(p);
+ }
+ break;
+
+ case 'I':
+ p = ARGF();
+ setinclude(p);
+ break;
+
+ case 'm':
+ domod = 1;
+ break;
+
+ case 'i':
+ doinc = 1;
+ break;
+
+ case 'l':
+ doloc = 1;
+ break;
+
+ case 'c':
+ justcode = 1;
+ break;
+
+ case 'v':
+ comm = 1;
+ break;
+
+ case 's':
+ strings = 0;
+ break;
+
+ case 'S':
+ strings = 2;
+ break;
+
+ case 'M':
+ inmain = 1;
+ break;
+
+ case 'q':
+ passes = 0;
+ break;
+
+ case 'a':
+ doaddr = 1;
+ break;
+
+ case 'A':
+ doaddr = 1;
+ doalladdr = 1;
+ break;
+
+ } ARGEND
+
+ if(doinc)
+ domod = doloc = 0;
+
+ linit();
+
+ if(argc != 1) {
+ print("usage: c2l [-options] file\n");
+ errorexit();
+ }
+ if(argc > 1 && systemtype(Windows)){
+ print("can't compile multiple files on windows\n");
+ errorexit();
+ }
+ if(argc > 1 && !systemtype(Windows)) {
+ nproc = 1;
+ if(p = getenv("NPROC"))
+ 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[200], incfile[20];
+ char *p, *av[100], opt[256];
+ int i, c, fd[2];
+
+ strcpy(ofile, file);
+ p = utfrrune(ofile, pathchar());
+ if(p) {
+ *p++ = 0;
+ include[0] = strdup(ofile);
+ } else
+ p = ofile;
+
+ USED(p);
+ if(p = getenv("INCLUDE")) {
+ setinclude(p);
+ } else {
+ if(systemtype(Plan9)) {
+ sprint(incfile, "/%s/include", thestring);
+ setinclude(strdup(incfile));
+ setinclude("/sys/include");
+ }
+ }
+ newio();
+
+ /* Use an ANSI preprocessor */
+ if(ansip) {
+ if(systemtype(Windows)) {
+ diag(Z, "-p option not supported on windows");
+ 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;
+ 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(0) {
+ for(c = 0; c < i; c++)
+ fprint(2, "%s ", av[c]);
+ print("\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);
+ }
+
+ clbegin();
+ yyparse();
+ clend();
+ newsec(0);
+ return nerrors;
+}
+
+void
+errorexit(void)
+{
+ 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 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(0)
+ 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("c2l: %r: %s", s);
+ errorexit();
+ }
+ fi.c = 0;
+ linehist(s, 0);
+ outpush(s);
+}
+
+Sym*
+slookup(char *s)
+{
+
+ strcpy(symb, s);
+ return lookup();
+}
+
+Sym*
+lookup(void)
+{
+ static Sym zsym;
+ 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 = zsym;
+ 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->type = T;
+ s->suetag = T;
+ s->class = CXXX;
+ s->lname = s->mod = nil;
+ s->lineno = lineno;
+ s->tenum = T;
+}
+
+#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,
+};
+
+static int ypeek = 0;
+
+long
+yylex(void)
+{
+ vlong vv;
+ long c, c1;
+ 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)
+ warn(Z, "sign-extended character constant");
+ yylval.vval = convvtox(vv, TCHAR);
+ return LCHARACTER;
+
+ case '/':
+ c1 = GETC();
+ if(c1 == '*') {
+ startcom(lineno);
+ for(;;) {
+ c = getr();
+ if(c == '*'){
+ while(c == '*') {
+ c = getr();
+ if(c == '/'){
+ endcom();
+ goto l0;
+ }
+ addcom('*');
+ }
+ addcom(c);
+ }
+ else
+ addcom(c);
+ if(c == EOF) {
+ yyerror("eof in comment");
+ errorexit();
+ }
+ }
+ }
+ if(c1 == '/') {
+ startcom(lineno);
+ for(;;) {
+ c = getr();
+ if(c == '\n'){
+ endcom();
+ goto l0;
+ }
+ addcom(c);
+ 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(0)
+ print("%L: %s\n", lineno, symb);
+ peekc = c;
+ s = lookup();
+ if(s->macro && !ypeek) {
+ 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;
+ }
+ /* outpush(nil); */
+ goto l0;
+ }
+ yylval.sym = s;
+ if(s->class == CTYPEDEF) {
+ if(s->type && typesu[s->type->etype])
+ return LCTYPE;
+ return LSTYPE;
+ }
+ return s->lexical;
+
+tnum:
+ lastnumbase = KDEC;
+ 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'){
+ lastnumbase = KHEX;
+ 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;
+ }
+ }
+ else
+ lastnumbase = KOCT;
+ if(c < '0' || c > '7'){
+ lastnumbase = KDEC;
+ 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) {
+ c = LUVLCONST;
+ goto nret;
+ }
+ yylval.vval = convvtox(yylval.vval, TVLONG);
+ if(yylval.vval < 0) {
+ c = LUVLCONST;
+ goto nret;
+ }
+ c = LVLCONST;
+ goto nret;
+ }
+ if(c1 & Numlong) {
+ if(c1 & Numuns) {
+ c = LULCONST;
+ goto nret;
+ }
+ yylval.vval = convvtox(yylval.vval, TLONG);
+ if(yylval.vval < 0) {
+ c = LULCONST;
+ goto nret;
+ }
+ c = LLCONST;
+ goto nret;
+ }
+ if(c1 & Numuns) {
+ c = LUCONST;
+ goto nret;
+ }
+ yylval.vval = convvtox(yylval.vval, TINT);
+ if(yylval.vval < 0) {
+ c = LUCONST;
+ goto nret;
+ }
+ c = LCONST;
+ goto nret;
+
+nret:
+ 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;
+ if(mpatof(symb, &yylval.dval)) {
+ yyerror("overflow in float constant");
+ yylval.dval = 0;
+ }
+ if(c1 & Numflt)
+ return LFCONST;
+ return LDCONST;
+}
+
+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();
+ }
+ return 0;
+}
+
+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,
+ "int", LINT, TINT,
+ "long", LLONG, TLONG,
+ "register", LREGISTER, 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,
+ "union", LUNION, 0,
+ "unsigned", LUNSIGNED, 0,
+ "USED", LUSED, 0,
+ "void", LVOID, TVOID,
+ "volatile", LVOLATILE, 0,
+ "while", LWHILE, 0,
+ "__int64", LVLONG, TVLONG, /* for windows */
+ 0
+};
+
+static char *litab[] =
+{
+ "adt",
+ "alt",
+ "array",
+ "big",
+ "break",
+ "byte",
+ "case",
+ "chan",
+ "con",
+ "continue",
+ "cyclic",
+ "do",
+ "else",
+ "exit",
+ "fn",
+ "for",
+ "hd",
+ "if",
+ "implement",
+ "import",
+ "include",
+ "int",
+ "len",
+ "list",
+ "load",
+ "module",
+ "nil",
+ "of",
+ "or",
+ "pick",
+ "real",
+ "ref",
+ "return",
+ "self",
+ "spawn",
+ "string",
+ "tagof",
+ "tl",
+ "to",
+ "type",
+ "while",
+ 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]);
+ stringtype = typ(TSTRING, T);
+ fdtype = typ(TSTRUCT, typ(TFD, T));
+ fdtype->width = 4;
+ pfdtype = typ(TIND, fdtype);
+
+ 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];
+ }
+ for(i=0; litab[i]; i++){
+ s = slookup(litab[i]);
+ s->lkw = 1;
+ }
+ 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('f', gfltconv);
+ fmtinstall('F', gfltconv);
+ fmtinstall('g', gfltconv);
+ fmtinstall('G', gfltconv);
+ fmtinstall('e', gfltconv);
+ fmtinstall('E', gfltconv);
+
+ 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:
+ if(i->f >= 0)
+ outpop(lineno);
+ 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;
+ char s[STRINGSZ];
+
+ a = va_arg(fp->args, int);
+ if(a < OXXX || a > OEND) {
+ sprint(s, "***badO %d***", a);
+ fmtstrcpy(fp, s);
+ } else
+ fmtstrcpy(fp, onames[a]);
+ return 0;
+}
+
+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>");
+ fmtstrcpy(fp, str);
+ return 0;
+}
+
+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) {
+ sprint(s, "%s ", gnames[t->garb]);
+ 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;
+ }
+ }
+ fmtstrcpy(fp, str);
+ return 0;
+}
+
+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;
+ fmtstrcpy(fp, str);
+ return 0;
+}
+
+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);
+ }
+ fmtstrcpy(fp, str);
+ return 0;
+}
+
+int
+VBconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ int i, n, t, pc;
+
+ n = va_arg(fp->args, int);
+ pc = 0; /*was printcol */
+ i = 0;
+ while(pc < n) {
+ t = (pc+8) & ~7;
+ if(t <= n) {
+ str[i++] = '\t';
+ pc = t;
+ continue;
+ }
+ str[i++] = ' ';
+ pc++;
+ }
+ str[i] = 0;
+ fmtstrcpy(fp, str);
+ return 0;
+}
+
+/*
+ * real allocs
+ */
+void*
+alloc(long n)
+{
+ void *p;
+
+ while((ulong)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;
+ 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;
+ }
+}
+
+static void
+doio(char *s)
+{
+ char *cp;
+
+ newio();
+ cp = ionext->b;
+ strcpy(cp, s);
+ 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;
+ }
+}
+
+static void
+undoio(void)
+{
+ Io *i;
+
+ i = iostack;
+ iostack = i->link;
+ i->link = iofree;
+ iofree = i;
+ i = iostack;
+ fi.p = i->p;
+ fi.c = i->c;
+}
+
+/* rm // comment from a string */
+static void
+slashslash(char *s)
+{
+ for( ; *s != '\0'; s++)
+ if(*s == '/' && s[1] == '/'){
+ *s = '\0';
+ return;
+ }
+}
+
+int
+iscon(char *str)
+{
+ int olineno, opeekc, con, tok, t;
+ Sym *s;
+ char buf[1024];
+
+ if(str == nil || *str == 0 || strlen(str)+16 > 1024)
+ return 0;
+ ypeek = 1;
+ olineno = lineno;
+ opeekc = peekc;
+ peekc = IGN;
+ strcpy(buf, str);
+ slashslash(buf);
+ strcat(buf, " break break");
+ doio(buf);
+ tok = 0;
+ con = 1;
+ while(con){
+ t = yylex();
+ if(t == LBREAK)
+ break;
+ switch(t){
+ case LSTRING:
+ case LLSTRING:
+ tok = 1;
+ free(yylval.sval.s);
+ break;
+ case LNAME:
+ tok = 1;
+ s = yylval.sym;
+ if(s->macro || s->type == T || s->type->etype != TENUM)
+ con = 0;
+ break;
+ case LCHARACTER:
+ case LCONST:
+ case LLCONST:
+ case LUCONST:
+ case LULCONST:
+ case LVLCONST:
+ case LUVLCONST:
+ case LFCONST:
+ case LDCONST:
+ tok = 1;
+ break;
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case '%':
+ case LPP:
+ case LMM:
+ case '<':
+ case '>':
+ case LGE:
+ case LLE:
+ case LEQ:
+ case LNE:
+ case LLSH:
+ case LRSH:
+ case '!':
+ case '~':
+ case '&':
+ case '|':
+ case '^':
+ case '(':
+ case ')':
+ break;
+ default:
+ con = 0;
+ break;
+ }
+ }
+ undoio();
+ peekc = opeekc;
+ lineno = olineno;
+ ypeek = 0;
+ return con && tok;
+}
+
+void
+doasenum(Sym *s)
+{
+ char *b, buf[1024];
+
+ b = s->macro;
+ s->macro = nil;
+ lineno--;
+ slashslash(b+1);
+ sprint(buf, "enum{ %s = %s };\n", s->name, b+1);
+ doio(buf);
+ /* outpush(nil); */
+ free(b);
+}
diff --git a/utils/c2l/lexbody b/utils/c2l/lexbody
new file mode 100644
index 00000000..ab7e2439
--- /dev/null
+++ b/utils/c2l/lexbody
@@ -0,0 +1,650 @@
+/*
+ * common code for all the assemblers
+ */
+
+/*
+ * real allocs
+ */
+void*
+alloc(long n)
+{
+ void *p;
+
+ while((ulong)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 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)
+{
+ static Sym zsym;
+ 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 = zsym;
+ 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;
+ yylval.lval = atol(symb);
+
+ ncu:
+ 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 l0;
+ }
+ 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);
+ doprint(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/utils/c2l/mac.c b/utils/c2l/mac.c
new file mode 100644
index 00000000..7ec6e393
--- /dev/null
+++ b/utils/c2l/mac.c
@@ -0,0 +1,3 @@
+#include "cc.h"
+
+#include "macbody"
diff --git a/utils/c2l/macbody b/utils/c2l/macbody
new file mode 100644
index 00000000..aacb1e6f
--- /dev/null
+++ b/utils/c2l/macbody
@@ -0,0 +1,773 @@
+
+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();
+}
+
+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 */
+ while(l & 3)
+ l++;
+ while(nhunk < l)
+ gethunk();
+ *hunk = 0;
+ strcpy(hunk+1, p);
+ s->macro = hunk;
+ hunk += l;
+ nhunk -= l;
+ } else {
+ s = lookup();
+ s->macro = "\0001"; /* \000 is nargs */
+ }
+ if(0)
+ 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;
+
+ s = getsym();
+ if(s == S)
+ goto bad;
+ if(s->macro)
+ yyerror("macro redefined: %s", s->name);
+ c = getc();
+ n = -1;
+ if(c == '(') {
+ n++;
+ c = getnsc();
+ if(c != ')') {
+ unget(c);
+ for(;;) {
+ a = getsym();
+ 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 != ',')
+ goto bad;
+ }
+ }
+ c = getc();
+ }
+ if(isspace(c))
+ if(c != '\n')
+ c = getnsc();
+ base = hunk;
+ len = 1;
+ 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(c == '/') {
+ c = getc();
+ if(c != '*') {
+ base = allocn(base, len, 1);
+ base[len++] = '/';
+ continue;
+ }
+ 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;
+ }
+ 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;
+ s->macro = base;
+ if(0)
+ print("#define %s %s\n", s->name, s->macro+1);
+ if(n == -1 && iscon(base+1))
+ doasenum(s);
+ 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;
+
+ ob = b;
+ USED(ob);
+ nargs = *s->macro - 1;
+ if(nargs < 0) {
+ strcpy(b, s->macro+1);
+ if(0)
+ print("#expand %s %s\n", s->name, ob);
+ return;
+ }
+ 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(l == 0) {
+ if(c == ',') {
+ *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 != '#') {
+ *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(0)
+ 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 = open(symb, 0);
+ if(f >= 0)
+ break;
+ }
+ if(f < 0)
+ strcpy(symb, str);
+ c = strlen(symb) + 1;
+ while(c & 3)
+ c++;
+ while(nhunk < c)
+ gethunk();
+ hp = hunk;
+ memcpy(hunk, symb, c);
+ nhunk -= c;
+ hunk += 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;
+ while(c & 3)
+ c++;
+ while(nhunk < c)
+ gethunk();
+ cp = hunk;
+ memcpy(hunk, symb, c);
+ nhunk -= c;
+ hunk += 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 && s->type != T && s->type->etype == TENUM){
+ if(!f)
+ return;
+ }
+ else 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, "hjdicks") == 0) {
+ praghjdicks();
+ return;
+ }
+ if(s && strcmp(s->name, "fpround") == 0) {
+ pragfpround();
+ return;
+ }
+ if(s && strcmp(s->name, "varargck") == 0) {
+ pragvararg();
+ 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;
+ while(c & 3)
+ c++;
+ while(nhunk < c)
+ gethunk();
+ hp = hunk;
+ memcpy(hunk, symb, c);
+ nhunk -= c;
+ hunk += 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(0)
+ 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;
+}
+
+void
+gethunk(void)
+{
+ char *h;
+ long nh;
+
+ nh = NHUNK;
+ if(thunk >= 10L*NHUNK)
+ nh = 10L*NHUNK;
+ h = (char*)mysbrk(nh);
+ if(h == (char*)-1) {
+ yyerror("out of memory");
+ errorexit();
+ }
+ hunk = h;
+ nhunk = nh;
+ thunk += nh;
+}
diff --git a/utils/c2l/mkfile b/utils/c2l/mkfile
new file mode 100644
index 00000000..219d36e1
--- /dev/null
+++ b/utils/c2l/mkfile
@@ -0,0 +1,38 @@
+<../../mkconfig
+
+TARG=c2l
+
+OFILES=\
+ acid.$O\
+ bits.$O\
+ com.$O\
+ com64.$O\
+ $TARGMODEL.$O\
+ dcl.$O\
+ dpchk.$O\
+ lex.$O\
+ mac.$O\
+ mpatof.$O\
+ out.$O\
+ scon.$O\
+ sub.$O\
+ y.tab.$O\
+ c2l.$O\
+
+HFILES= cc.h\
+ y.tab.h\
+
+YFILES= cc.y\
+
+LIBS=math bio 9
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+CFLAGS= $CFLAGS -I../include
+
+mac.$O: macbody
+
+lex.$O: lex.c
+ $CC $CFLAGS '-DCPP="/bin/cpp"' lex.c
diff --git a/utils/c2l/mpatof.c b/utils/c2l/mpatof.c
new file mode 100644
index 00000000..d55ddab4
--- /dev/null
+++ b/utils/c2l/mpatof.c
@@ -0,0 +1,337 @@
+#include "cc.h"
+
+enum
+{
+ Mpscale = 29, /* safely smaller than bits in a long */
+ Mpprec = 36, /* Mpscale*Mpprec sb > largest fp exp */
+ Mpbase = 1L<<Mpscale,
+};
+
+typedef
+struct
+{
+ long a[Mpprec];
+ char ovf;
+} Mp;
+
+int mpatof(char*, double*);
+int mpatov(char *s, vlong *v);
+void mpint(Mp*, int);
+void mppow(Mp*, int, int);
+void mpmul(Mp*, int);
+void mpadd(Mp*, Mp*);
+int mptof(Mp*, double*);
+
+/*
+ * convert a string, s, to floating in *d
+ * return conversion overflow.
+ * required syntax is [+-]d*[.]d*[e[+-]d*]
+ */
+int
+mpatof(char *s, double *d)
+{
+ Mp a, b;
+ int dp, c, f, ef, ex, zer;
+ double d1, d2;
+
+ dp = 0; /* digits after decimal point */
+ f = 0; /* sign */
+ ex = 0; /* exponent */
+ zer = 1; /* zero */
+ memset(&a, 0, sizeof(a));
+ for(;;) {
+ switch(c = *s++) {
+ default:
+ goto bad;
+ case '-':
+ f = 1;
+ case ' ':
+ case '\t':
+ case '+':
+ continue;
+ case '.':
+ dp = 1;
+ continue;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ zer = 0;
+ case '0':
+ mpint(&b, c-'0');
+ mpmul(&a, 10);
+ mpadd(&a, &b);
+ if(dp)
+ dp++;
+ continue;
+ case 'E':
+ case 'e':
+ ex = 0;
+ ef = 0;
+ for(;;) {
+ c = *s++;
+ if(c == '+' || c == ' ' || c == '\t')
+ continue;
+ if(c == '-') {
+ ef = 1;
+ continue;
+ }
+ if(c >= '0' && c <= '9') {
+ ex = ex*10 + (c-'0');
+ continue;
+ }
+ break;
+ }
+ if(ef)
+ ex = -ex;
+ case 0:
+ break;
+ }
+ break;
+ }
+ if(a.ovf)
+ goto bad;
+ if(zer) {
+ *d = 0;
+ return 0;
+ }
+ if(dp)
+ dp--;
+ dp -= ex;
+ if(dp > 0) {
+ /*
+ * must divide by 10**dp
+ */
+ if(mptof(&a, &d1))
+ goto bad;
+
+ /*
+ * trial exponent of 8**dp
+ * 8 (being between 5 and 10)
+ * should pick up all underflows
+ * in the division of 5**dp.
+ */
+ d2 = frexp(d1, &ex);
+ d2 = ldexp(d2, ex-3*dp);
+ if(d2 == 0)
+ goto bad;
+
+ /*
+ * decompose each 10 into 5*2.
+ * create 5**dp in fixed point
+ * and then play with the exponent
+ * for the remaining 2**dp.
+ * note that 5**dp will overflow
+ * with as few as 134 input digits.
+ */
+ mpint(&a, 1);
+ mppow(&a, 5, dp);
+ if(mptof(&a, &d2))
+ goto bad;
+ d1 = frexp(d1/d2, &ex);
+ d1 = ldexp(d1, ex-dp);
+ if(d1 == 0)
+ goto bad;
+ } else {
+ /*
+ * must multiply by 10**|dp| --
+ * just do it in fixed point.
+ */
+ mppow(&a, 10, -dp);
+ if(mptof(&a, &d1))
+ goto bad;
+ }
+ if(f)
+ d1 = -d1;
+ *d = d1;
+ return 0;
+
+bad:
+ return 1;
+}
+
+/*
+ * convert a to floating in *d
+ * return conversion overflow
+ */
+int
+mptof(Mp *a, double *d)
+{
+ double f, g;
+ long x, *a1;
+ int i;
+
+ if(a->ovf)
+ return 1;
+ a1 = a->a;
+ f = ldexp(*a1++, 0);
+ for(i=Mpscale; i<Mpprec*Mpscale; i+=Mpscale)
+ if(x = *a1++) {
+ g = ldexp(x, i);
+ /*
+ * NOTE: the test (g==0) is plan9
+ * specific. ansi compliant overflow
+ * is signaled by HUGE and errno==ERANGE.
+ * change this for your particular ldexp.
+ */
+ if(g == 0)
+ return 1;
+ f += g; /* this could bomb! */
+ }
+ *d = f;
+ return 0;
+}
+
+/*
+ * return a += b
+ */
+void
+mpadd(Mp *a, Mp *b)
+{
+ int i, c;
+ long x, *a1, *b1;
+
+ if(b->ovf)
+ a->ovf = 1;
+ if(a->ovf)
+ return;
+ c = 0;
+ a1 = a->a;
+ b1 = b->a;
+ for(i=0; i<Mpprec; i++) {
+ x = *a1 + *b1++ + c;
+ c = 0;
+ if(x >= Mpbase) {
+ x -= Mpbase;
+ c = 1;
+ }
+ *a1++ = x;
+ }
+ a->ovf = c;
+}
+
+/*
+ * return a = c
+ */
+void
+mpint(Mp *a, int c)
+{
+
+ memset(a, 0, sizeof(*a));
+ a->a[0] = c;
+}
+
+/*
+ * return a *= c
+ */
+void
+mpmul(Mp *a, int c)
+{
+ Mp p;
+ int b;
+
+ memmove(&p, a, sizeof(p));
+ if(!(c & 1))
+ memset(a, 0, sizeof(*a));
+ c &= ~1;
+ for(b=2; c; b<<=1) {
+ mpadd(&p, &p);
+ if(c & b) {
+ mpadd(a, &p);
+ c &= ~b;
+ }
+ }
+}
+
+/*
+ * return a *= b**e
+ */
+void
+mppow(Mp *a, int b, int e)
+{
+ int b1;
+
+ b1 = b*b;
+ b1 = b1*b1;
+ while(e >= 4) {
+ mpmul(a, b1);
+ e -= 4;
+ if(a->ovf)
+ return;
+ }
+ while(e > 0) {
+ mpmul(a, b);
+ e--;
+ }
+}
+
+/*
+ * convert a string, s, to vlong in *v
+ * return conversion overflow.
+ * required syntax is [0[x]]d*
+ */
+int
+mpatov(char *s, vlong *v)
+{
+ vlong n, nn;
+ int c;
+ n = 0;
+ c = *s;
+ if(c == '0')
+ goto oct;
+ while(c = *s++) {
+ if(c >= '0' && c <= '9')
+ nn = n*10 + c-'0';
+ else
+ goto bad;
+ if(n < 0 && nn >= 0)
+ goto bad;
+ n = nn;
+ }
+ goto out;
+oct:
+ s++;
+ c = *s;
+ if(c == 'x' || c == 'X')
+ goto hex;
+ while(c = *s++) {
+ if(c >= '0' || c <= '7')
+ nn = n*8 + c-'0';
+ else
+ goto bad;
+ if(n < 0 && nn >= 0)
+ goto bad;
+ n = nn;
+ }
+ goto out;
+hex:
+ s++;
+ while(c = *s++) {
+ if(c >= '0' && c <= '9')
+ c += 0-'0';
+ else
+ if(c >= 'a' && c <= 'f')
+ c += 10-'a';
+ else
+ if(c >= 'A' && c <= 'F')
+ c += 10-'A';
+ else
+ goto bad;
+ nn = n*16 + c;
+ if(n < 0 && nn >= 0)
+ goto bad;
+ n = nn;
+ }
+out:
+ *v = n;
+ return 0;
+
+bad:
+ *v = ~0;
+ return 1;
+}
diff --git a/utils/c2l/out.c b/utils/c2l/out.c
new file mode 100644
index 00000000..ab81a995
--- /dev/null
+++ b/utils/c2l/out.c
@@ -0,0 +1,825 @@
+#include "cc.h"
+
+#define INCREMENT 8
+#define DEVNULL "/dev/null"
+
+static int indent = 0;
+static int fd = -1;
+static int nf = 0;
+static int mylineno = 1;
+
+typedef struct Com{
+ int lno;
+ char *s;
+ Node *n;
+ int tba;
+ struct Com *nxt;
+} Com;
+
+Com *hdc, *curc;
+
+typedef struct File{
+ char *s;
+ char *f;
+ char *m;
+ int b;
+ int loc;
+ int in;
+ int tg;
+ Node *n;
+ Com *c;
+ struct File *nxt;
+} File;
+
+typedef struct Create{
+ char *s;
+ struct Create *nxt;
+} Create;
+
+File *fs;
+Create *cs;
+
+static void genmsg(void);
+static int isloc(void);
+
+static void
+addcreate(char *s)
+{
+ Create *c;
+
+ if(strcmp(s, DEVNULL) == 0)
+ return;
+ c = (Create*)malloc(sizeof(Create));
+ c->s = malloc(strlen(s)+1);
+ strcpy(c->s, s);
+ c->nxt = cs;
+ cs = c;
+}
+
+static int
+created(char *s)
+{
+ Create *c;
+
+ for(c = cs; c != nil; c = c->nxt)
+ if(strcmp(s, c->s) == 0)
+ return 1;
+ return 0;
+}
+
+int
+dolog(void)
+{
+ if(justcode)
+ return 0;
+ return domod || !doinc || inmain;
+}
+
+static char*
+curf(void)
+{
+ File *f;
+
+ for(f = fs; f != nil; f = f->nxt)
+ if(f->f != nil)
+ return f->s;
+ return nil;
+}
+
+static char*
+curm(void)
+{
+ File *f;
+
+ for(f = fs; f != nil; f = f->nxt)
+ if(f->f != nil)
+ return f->m;
+ return nil;
+}
+
+void
+setmod(Sym *s)
+{
+ if(domod && s->mod == nil && ism() && !(doloc && !isloc()))
+ s->mod = curm();
+}
+
+char *
+outmod(char *buf, int up)
+{
+ char *s, *t;
+
+ s = curf();
+ if(s == nil)
+ return "";
+ t = strchr(s, '.');
+ if(t != nil)
+ *t = '\0';
+ strcpy(buf, s);
+ if(t != nil)
+ *t = '.';
+ if(up == 1 || (up < 0 && ism()))
+ buf[0] = toupper(buf[0]);
+ return buf;
+}
+
+int
+ism(void)
+{
+ return !isb();
+}
+
+int
+isb(void)
+{
+ File *f;
+
+ for(f = fs; f != nil; f = f->nxt)
+ if(f->f != nil)
+ return f->b;
+ return 0;
+}
+
+static int
+isloc(void)
+{
+ File *f;
+
+ for(f = fs; f != nil; f = f->nxt)
+ if(f->f != nil)
+ return f->loc;
+ return 0;
+}
+
+static File*
+pushf(void)
+{
+ static File zfile;
+ File *f;
+
+ f = (File*)malloc(sizeof(File));
+ *f = zfile;
+ f->s = nil;
+ f->f = nil;
+ f->m = nil;
+ f->nxt = fs;
+ fs = f;
+ return f;
+}
+
+static void
+popf(void)
+{
+ File *f;
+
+ f = fs;
+ fs = fs->nxt;
+ if(f->s != nil)
+ free(f->s);
+ free(f);
+}
+
+static void
+setf(File *f, char *s)
+{
+ int n;
+ char *t;
+
+ if(s != nil){
+ t = strrchr(s, '/');
+ f->loc = t == nil;
+ if(t != nil)
+ s = t+1;
+ n = strlen(s);
+ f->s = malloc(n+1);
+ strcpy(f->s, s);
+ s = f->s;
+ if(n > 2 && s[n-2] == '.'){
+ f->m = malloc(n-1);
+ strncpy(f->m, s, n-2);
+ if(s[n-1] == 'h')
+ s[n-1] = 'm';
+ else if(s[n-1] == 'c'){
+ s[n-1] = 'b';
+ f->b = 1;
+ }
+ else
+ s = nil;
+ }
+ else
+ s = nil;
+ if(s == nil){
+ free(f->s);
+ if(f->m != nil)
+ free(f->m);
+ f->s = nil;
+ f->m = nil;
+ }
+ }
+ f->f = f->s;
+ if(f->s != nil && nf > 0){
+ if(doinc || doloc && !f->loc)
+ f->f = DEVNULL;
+ else if(!domod)
+ f->f = nil;
+ }
+}
+
+void
+outpush0(char *s, Node *n)
+{
+ File *f;
+
+ f = pushf();
+ setf(f, s);
+ if(f->f != nil){
+ nf++;
+ f->tg = taggen;
+ taggen = 0;
+ f->n = n;
+ f->c = hdc;
+ hdc = nil;
+ }
+}
+
+void
+outpop0(int lno)
+{
+ File *f;
+
+ USED(lno);
+ f = fs;
+ if(f->f != nil){
+ nf--;
+ taggen = f->tg;
+ f->n->left = (void*)hdc;
+ hdc = f->c;
+ }
+ popf();
+}
+
+void
+outpush2(char *s, Node *n)
+{
+ File *f;
+
+ f = pushf();
+ setf(f, s);
+ if(f->f != nil){
+ if(fd >= 0){
+ newsec(0);
+ close(fd);
+ close(1);
+ fd = -1;
+ }
+ if(created(f->f))
+ f->f = DEVNULL; /* don't overwrite original if included again */
+ fd = create(f->f, OWRITE, 0664);
+ if(fd >= 0)
+ addcreate(f->f);
+ mydup(fd, 1);
+ nf++;
+ f->tg = taggen;
+ taggen = 0;
+ f->c = hdc;
+ if(n != Z)
+ hdc = (void*)n->left;
+ else
+ hdc = nil;
+ f->in = indent;
+ indent = 0;
+ genmsg();
+ pgen(f->b);
+ }
+}
+
+void
+outpop2(int lno)
+{
+ File *f, *g;
+
+ f = fs;
+ if(f->f != nil){
+ if(fd >= 0){
+ newsec(0);
+ output(lno, 1);
+ epgen(f->b);
+ close(fd);
+ close(1);
+ fd = -1;
+ }
+ for(g = fs->nxt; g != nil; g = g->nxt){
+ if(g->f != nil){
+ fd = open(g->f, OWRITE);
+ seek(fd, 0, 2);
+ mydup(fd, 1);
+ break;
+ }
+ }
+ nf--;
+ taggen = f->tg;
+ hdc = f->c;
+ indent = f->in;
+ }
+ popf();
+}
+
+static void
+xprint(char *s)
+{
+ if(nerrors == 0)
+ print(s);
+}
+
+static int tot = 0;
+
+static void
+doindent(int d)
+{
+ int i;
+
+ for(i = 0; i < d/8; i++)
+ xprint("\t");
+ for(i = 0; i < d%8; i++)
+ xprint(" ");
+}
+
+void
+incind(void)
+{
+ indent += INCREMENT;
+}
+
+void
+decind(void)
+{
+ indent -= INCREMENT;
+}
+
+int
+zeroind(void)
+{
+ int i = indent;
+
+ indent = 0;
+ return i;
+}
+
+void
+restoreind(int i)
+{
+ indent = i;
+}
+
+void
+newline0(void)
+{
+ xprint("\n");
+ tot = 0;
+ mylineno++;
+}
+
+void
+newline(void)
+{
+ if(!outcom(1)){
+ xprint("\n");
+ mylineno++;
+ }
+ tot = 0;
+}
+
+static void
+lprint(char *s)
+{
+ if(tot == 0) {
+ doindent(indent);
+ tot += indent;
+ }
+ xprint(s);
+ tot += strlen(s);
+}
+
+void
+prline(char *s)
+{
+ xprint(s);
+ xprint("\n");
+ mylineno++;
+}
+
+void
+prdelim(char *s)
+{
+ if(*s == '%'){
+ if(*++s == '=')
+ lprint("%%=");
+ else
+ lprint("%%");
+ return;
+ }
+ lprint(s);
+}
+
+void
+prkeywd(char *kw)
+{
+ lprint(kw);
+}
+
+void
+prid(char *s)
+{
+ lprint(s);
+}
+
+static void
+priddol(char *s, int dol)
+{
+ char *t;
+ char buf[128];
+
+ if(dol){
+ t = strchr(s, '$');
+ if(t != nil)
+ *t = '_';
+ lprint(s);
+ if(t != nil){
+ strcpy(buf, s);
+ while(slookup(buf)->type != T){
+ strcat(buf, "x");
+ lprint("x");
+ }
+ *t = '$';
+ }
+ }
+ else
+ lprint(s);
+}
+
+void
+prsym(Sym *s, int mod)
+{
+ char buf[128];
+ int c;
+
+ if(mod && s->mod && strcmp(s->mod, curm()) != 0 && (!s->limbo || s->class == CEXTERN)){
+ c = isconsym(s);
+ if(c >= 0){
+ if(c){
+ s->mod[0] = toupper(s->mod[0]);
+ lprint(s->mod);
+ s->mod[0] = tolower(s->mod[0]);
+ }
+ else
+ lprint(s->mod);
+ lprint("->");
+ usemod(s, !c);
+ }
+ }
+ if(s->lname)
+ prid(s->lname);
+ else{
+ priddol(s->name, s->class == CSTATIC);
+ if(s->lkw){
+ strcpy(buf, s->name);
+ for(;;){
+ strcat(buf, "x");
+ lprint("x");
+ s = slookup(buf);
+ if(s->type == T)
+ break;
+ }
+ }
+ }
+}
+
+int
+arrow(Sym *s)
+{
+ if(s->mod && strcmp(s->mod, curm()) != 0)
+ return isconsym(s) >= 0;
+ return 0;
+}
+
+void
+prsym0(Sym *s)
+{
+ int c;
+
+ if(s->mod && strcmp(s->mod, curm()) != 0){
+ c = isconsym(s);
+ if(c >= 0)
+ usemod(s, !c);
+ }
+}
+
+static int
+isprintable(int c)
+{
+ if(c >= 0x20 && c <= 0x7e)
+ return 1;
+ return c == '\0' || c == '\n' || c == '\t' || c == '\b' || c == '\r' || c == '\f' || c == '\a' || c == '\v';
+}
+
+static int
+hex(int c)
+{
+ if(c < 10)
+ return c+'0';
+ return c+'a'-10;
+}
+
+void
+prchar0(vlong x, int quote)
+{
+ int c, e, i = 0;
+ static char buf[16];
+
+ if(quote)
+ buf[i++] = '\'';
+ c = x;
+ if(c < 0 || c > 255 || !isprintable(c)){
+ if(c&0xffff0000)
+ diag(Z, "character too big");
+ buf[i++] = '\\';
+ buf[i++] = 'u';
+ buf[i++] = hex((c>>12)&0xf);
+ buf[i++] = hex((c>>8)&0xf);
+ buf[i++] = hex((c>>4)&0xf);
+ buf[i++] = hex((c>>0)&0xf);
+ }
+ else{
+ e = 0;
+ switch(c){
+ case '\n': e = 'n'; break;
+ case '\t': e = 't'; break;
+ case '\b': e = 'b'; break;
+ case '\r': e = 'r'; break;
+ case '\f': e = 'f'; break;
+ case '\a': e = 'a'; break;
+ case '\v': e = 'v'; break;
+ case '"': if(!quote) e = '"'; break;
+ case '\'': if(quote) e = '\''; break;
+ case '\\': e = '\\'; break;
+ case '%': buf[i++] = c; break;
+ case 0: e = '0'; if(strings) prcom("nul byte in string ?", Z); break;
+ }
+ if(e != 0){
+ buf[i++] = '\\';
+ c = e;
+ }
+ buf[i++] = c;
+ }
+ if(quote)
+ buf[i++] = '\'';
+ buf[i] = '\0';
+ lprint(buf);
+}
+
+void
+prchar(vlong x)
+{
+ prchar0(x, 1);
+}
+
+void
+prstr(char *s)
+{
+ uchar *t;
+ Rune r;
+
+ t = (uchar*)s;
+ lprint("\"");
+ while(*t != 0){
+ if(*t & 0x80){
+ t += chartorune(&r, (char*)t);
+ prchar0(r, 0);
+ }
+ else
+ prchar0(*t++, 0);
+ }
+ lprint("\"");
+}
+
+void
+prlstr(ushort *s)
+{
+ lprint("\"");
+ while(*s != 0)
+ prchar0(*s++, 0);
+ lprint("\"");
+}
+
+void
+prreal(double x, char *s, int b)
+{
+ static char buf[128];
+
+ if(b != KDEC)
+ diag(Z, "not base 10 in prreal");
+ if(s != nil)
+ lprint(s);
+ else{
+ sprint(buf, "%f", x);
+ lprint(buf);
+ }
+}
+
+void
+prnum(vlong x, int b, Type *t)
+{
+ static char buf[128];
+ int w;
+ vlong m;
+
+ w = 4;
+ if(t != T)
+ w = ewidth[t->etype];
+ m = MASK(8*w);
+ if(b == KHEX)
+ sprint(buf, "16r%llux", x&m);
+ else if(b == KOCT)
+ sprint(buf, "8r%lluo", x&m);
+ else
+ sprint(buf, "%lld", x);
+ lprint(buf);
+}
+
+char *cb;
+int cn, csz;
+
+static void
+outcom0(Com *c)
+{
+ Node *n;
+ char *s, *t, *u;
+
+ s = c->s;
+ n = c->n;
+ if(comm && c->tba){
+ t = strchr(s, '\n');
+ *t = '\0';
+ fprint(2, "%s:%d: %s", curf(), mylineno, s);
+ *t = '\n';
+ if(n != Z){
+ mydup(2, 1);
+ expgen(n);
+ mydup(fd, 1);
+ }
+ fprint(2, "\n");
+ }
+ while(*s != '\0'){
+ t = strchr(s, '\n');
+ *t = '\0';
+ if(tot != 0)
+ prdelim("\t");
+ prdelim("# ");
+ while((u = strchr(s, '%')) != nil){
+ /* do not let print interpret % ! */
+ *u = 0;
+ lprint(s);
+ *u = '%';
+ lprint("%%");
+ s = u+1;
+ }
+ lprint(s);
+ if(n == Z)
+ newline0();
+ *t = '\n';
+ s = t+1;
+ }
+ if(n != Z){
+ expgen(n);
+ newline0();
+ }
+}
+
+int
+outcom(int f)
+{
+ int lno, nl;
+ Com *c;
+
+ nl = 0;
+ lno = pline+f;
+ c = hdc;
+ while(c != nil && c->lno < lno){
+/* print("outcom: %d < %d (f=%d)\n", c->lno, lno, f); */
+ nl = 1;
+ outcom0(c);
+ hdc = hdc->nxt;
+ free(c->s);
+ free(c);
+ c = hdc;
+ }
+ return nl;
+}
+
+void
+startcom(int lno)
+{
+ Com *c, **ac;
+
+ c = (Com *)malloc(sizeof(Com));
+ c->lno = lno;
+ c->s = nil;
+ c->n = Z;
+ c->tba = 0;
+ c->nxt = nil;
+ for(ac = &hdc; *ac != nil && (*ac)->lno <= lno; ac = &(*ac)->nxt)
+ ;
+ c->nxt = *ac;
+ curc = *ac = c;
+}
+
+void
+addcom(int rr)
+{
+ int i, nb;
+ char *ncb;
+ char s[UTFmax];
+ Rune r[1];
+
+ if(rr >= Runeself){
+ r[0] = rr;
+ nb = runetochar(s, r);
+ }
+ else{
+ nb = 1;
+ s[0] = rr;
+ }
+ if(cn+nb-1 >= csz){
+ csz += 32;
+ ncb = malloc(csz);
+ memcpy(ncb, cb, cn);
+ free(cb);
+ cb = ncb;
+ }
+ for(i = 0; i < nb; i++)
+ cb[cn++] = s[i];
+}
+
+void
+endcom(void)
+{
+ char *s;
+
+ addcom('\n');
+ addcom('\0');
+ s = malloc(strlen(cb)+1);
+ strcpy(s, cb);
+ curc->s = s;
+/* print("com %d %s\n", curc->lno, s); */
+ cn = 0;
+}
+
+void
+linit()
+{
+ csz = 32;
+ cb = malloc(csz);
+ sysinit();
+}
+
+static void
+genmsg(void)
+{
+ prline("#");
+ prline("# initially generated by c2l");
+ prline("#");
+ prline("");
+}
+
+void
+prcom(char *s, Node *n)
+{
+ Com *c;
+
+ startcom(pline);
+ c = curc;
+ sprint(cb, "TBA %s", s);
+ cn = strlen(cb);
+ c->n = n;
+ c->tba = 1;
+ endcom();
+}
+
+void
+output(long lno, int com)
+{
+/* print("output(%ld)\n", lno); */
+ pline = lno;
+ if(com)
+ outcom(0);
+}
+
+int
+exists(char *f)
+{
+ int fd;
+
+ fd = open(f, OREAD);
+ close(fd);
+ return fd >= 0;
+}
diff --git a/utils/c2l/scon.c b/utils/c2l/scon.c
new file mode 100644
index 00000000..89f87332
--- /dev/null
+++ b/utils/c2l/scon.c
@@ -0,0 +1,250 @@
+#include "cc.h"
+
+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 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;
+
+ case OPOS:
+ if(isf)
+ d = l->fconst;
+ else
+ v = l->vconst;
+ break;
+
+ case ONEG:
+ if(isf)
+ d = -l->fconst;
+ else
+ v = -l->vconst;
+ break;
+
+ case OCOM:
+ if(typefd[l->type->etype])
+ v = 0; /* ~l->fconst */
+ else
+ v = ~l->vconst;
+ break;
+ }
+
+ n->left = ncopy(n);
+ n->op = OCONST;
+ /* n->left = Z; */
+ n->right = Z;
+ if(isf) {
+ n->fconst = d;
+ } else {
+ n->vconst = convvtox(v, n->type->etype);
+ }
+}
+
+void
+acom(Node *n)
+{
+ USED(n);
+}
diff --git a/utils/c2l/sub.c b/utils/c2l/sub.c
new file mode 100644
index 00000000..a696cb0f
--- /dev/null
+++ b/utils/c2l/sub.c
@@ -0,0 +1,1694 @@
+#include "cc.h"
+
+Node*
+new(int t, Node *l, Node *r)
+{
+ static Node znode;
+ Node *n;
+
+ n = alloc(sizeof(*n));
+ *n = znode;
+ n->op = t;
+ n->left = l;
+ n->right = r;
+ n->lineno = lineno;
+ n->kind = KNIL;
+ newflag = 1;
+ return n;
+}
+
+Node*
+new1(int o, Node *l, Node *r)
+{
+ Node *n;
+
+ n = new(o, l, r);
+ if(l != Z)
+ n->lineno = l->lineno;
+ else if(r != Z)
+ n->lineno = r->lineno;
+ else
+ 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);
+ i = 0;
+ break;
+
+ case OINDREG:
+ i = 0;
+ break;
+
+ case OREGISTER:
+ 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->type != T)
+ print(" %T", n->type);
+ print("\n");
+ if(i & 2)
+ prtree1(n->left, d, 1);
+ if(i & 1)
+ prtree1(n->right, d, 1);
+}
+
+Type*
+typ(int et, Type *d)
+{
+ static Type ztype;
+ Type *t;
+
+ t = alloc(sizeof(*t));
+ *t = ztype;
+ t->etype = et;
+ t->link = d;
+ t->down = T;
+ t->sym = S;
+ t->width = ewidth[et];
+ t->nwidth = Z;
+ t->lineno = lineno;
+ return t;
+}
+
+Type*
+typ1(int et, Type *d)
+{
+ Type *t;
+
+ t = typ(et, d);
+ t->lineno = nearln;
+ return t;
+}
+
+Type*
+garbt(Type *t, long b)
+{
+ Type *t1;
+
+ if(b & BGARB) {
+ t1 = typ(TXXX, T);
+ *t1 = *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;
+ }
+ 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;
+
+ return 0;
+ 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(0 && 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)
+{
+ USED(n);
+ USED(o);
+ USED(t);
+ return;
+}
+
+Type*
+dotsearch(Sym *s, Type *t, Node *n)
+{
+ Type *t1, *xt;
+
+ 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;
+ }
+ if(xt != T)
+ return xt;
+
+ /*
+ * look it up by type
+ */
+ 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)
+ return xt;
+
+ /*
+ * look it up in unnamed substructures
+ */
+ for(t1 = t; t1 != T; t1 = t1->down)
+ if(t1->sym == S && typesu[t1->etype])
+ if(dotsearch(s, t1->link, n) != T) {
+ if(xt != T)
+ goto ambig;
+ xt = t1;
+ }
+ 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;
+
+ lt = l->type;
+ if(lt == T)
+ return;
+ if(st->etype == TIND && vconst(l) == 0) {
+ l->type = st;
+ l->vconst = 0;
+ return;
+ }
+ typeext1(st, l);
+}
+
+/*
+ * 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;
+ 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)
+ goto bad;
+ n->type = types[TLONG];
+ return;
+ }
+ if(!sametype(n->type, n->left->type)) {
+ n->left = new1(OCAST, n->left, Z);
+ 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;
+ }
+ return;
+bad:
+ diag(n, "pointer addition not fully declared: %T", n->type->link);
+}
+
+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
+vlog(Node *n)
+{
+ int s, i;
+ uvlong m, v;
+
+ if(n->op != OCONST)
+ goto bad;
+ if(typefd[n->type->etype])
+ goto bad;
+
+ v = n->vconst;
+
+ 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;
+
+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;
+ Node *t;
+
+ 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:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TVLONG:
+ case TUVLONG:
+ v = convvtox(l->vconst, r->type->etype);
+ if(v != l->vconst)
+ return;
+ break;
+ }
+ t = new1(OXXX, Z, Z);
+ *t = *l;
+ l->op = OCAST;
+ l->left = t;
+ l->right = Z;
+ 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 || n->blk)
+ return n;
+ i = n;
+ for(n = n->left; n != Z; n = n->left) {
+ if(n->op != OLIST || n->blk)
+ 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);
+ fprint(2, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
+
+ if(0)
+ abort();
+ if(n != Z)
+ if(0)
+ prtree(n, "diagnostic");
+
+ nerrors++;
+ if(nerrors > 10) {
+ fprint(2, "too many errors\n");
+ errorexit();
+ }
+}
+
+void
+warn(Node *n, char *fmt, ...)
+{
+ char buf[STRINGSZ];
+ va_list arg;
+
+ if(0) {
+ fprint(2, "warning: ");
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ fprint(2, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
+
+ if(n != Z)
+ if(0)
+ 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);
+ fprint(2, "%L %s\n", lineno, buf);
+ nerrors++;
+ if(nerrors > 10) {
+ fprint(2, "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);
+ fprint(2, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
+
+ if(0)
+ abort();
+ if(n != Z)
+ if(0)
+ 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, "xxx",
+ 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, "pointer",
+ TFUNC, 0, "function",
+ TARRAY, 0, "array",
+ TVOID, 0, "void",
+ TSTRUCT, 0, "struct",
+ TUNION, 0, "union",
+ TENUM, 0, "enum",
+ TFILE, 0, "file",
+ TOLD, 0, "old",
+ TDOT, 0, "dot",
+ TSTRING, 0, "string",
+ TFD, 0, "fd",
+ TTUPLE, 0, "tuple",
+ -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",
+ 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",
+ CPARAM, 0, "PARAM",
+ CSELEM, 0, "SELEM",
+ CLABEL, 0, "LABEL",
+ CEXREG, 0, "EXREG",
+ -1, 0, 0,
+};
+
+char* onames[OEND+1];
+Init onamesinit[] =
+{
+ ONOOP, 0, "NOOP",
+ 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",
+ ONEG, 0, "NEG",
+ OCOM, 0, "COM",
+ OELEM, 0, "ELEM",
+ OTST, 0, "TST",
+ OINDEX, 0, "INDEX",
+ OFAS, 0, "FAS",
+ OBLK, 0, "BLK",
+ OPOS, 0, "POS",
+ ONUL, 0, "NUL",
+ ODOTIND, 0, "DOTIND",
+ OARRIND, 0, "ARRIND",
+ ODAS, 0, "ODAS",
+ OASD, 0, "OASD",
+ OIOTA, 0, "IOTA",
+ OLEN, 0, "LEN",
+ OBRACKET, 0, "BRACKET",
+ OREF, 0, "REF",
+ OARRAYOF, 0, "ARRAYOF",
+ OSLICE, 0, "SLICE",
+ OSADDR, 0, "SADDR",
+ ONIL, 0, "NIL",
+ OS2AB, 0, "S2AB",
+ OAB2S, 0, "AB2S",
+ OFILDES, 0, "FILDES",
+ OFD, 0, "FD",
+ OTUPLE, 0, "TUPLE",
+ OT0, 0, "T0",
+ ORETV, 0, "RETV",
+ OCAT, 0, "CAT",
+ OSBREAK, 0, "SBREAK",
+ OLDOT, 0, "LDOT",
+ OMDOT, 0, "MDOT",
+ OCODE, 0, "CODE",
+ ODECE, 0, "DECE",
+ ODECT, 0, "DECT",
+ ODECV, 0, "DECV",
+ ODECF, 0, "DECF",
+ OPUSH, 0, "PUSH",
+ OPOP, 0, "POP",
+ OEND, 0, "END",
+ -1, 0, 0,
+};
+
+char comrel[12] =
+{
+ ONE, OEQ, OGT, OHI, OGE, OHS, OLT, OLO, OLE, OLS,
+};
+char invrel[12] =
+{
+ OEQ, ONE, OGE, OHS, OGT, OHI, OLE, OLS, OLT, OLO,
+};
+char logrel[12] =
+{
+ OEQ, ONE, OLS, OLS, OLO, OLO, OHS, OHS, OHI, OHI,
+};
+
+char typei[NTYPE];
+int typeiinit[] =
+{
+ TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TVLONG, TUVLONG, -1,
+};
+char typeu[NTYPE];
+int typeuinit[] =
+{
+ TUCHAR, TUSHORT, TUINT, TULONG, TUVLONG, TIND, -1,
+};
+
+char typesuv[NTYPE];
+int typesuvinit[] =
+{
+ TVLONG, TUVLONG, TSTRUCT, TUNION, -1,
+};
+
+char typeilp[NTYPE];
+int typeilpinit[] =
+{
+ TINT, TUINT, TLONG, TULONG, TIND, -1
+};
+
+char typechl[NTYPE];
+int typechlinit[] =
+{
+ TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, -1,
+};
+
+char typechlp[NTYPE];
+int typechlpinit[] =
+{
+ TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TIND, -1,
+};
+
+char typechlpfd[NTYPE];
+int typechlpfdinit[] =
+{
+ TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TFLOAT, TDOUBLE, TIND, -1,
+};
+
+char typec[NTYPE];
+int typecinit[] =
+{
+ TCHAR, TUCHAR, -1
+};
+
+char typeh[NTYPE];
+int typehinit[] =
+{
+ TSHORT, TUSHORT, -1,
+};
+
+char typeil[NTYPE];
+int typeilinit[] =
+{
+ TINT, TUINT, TLONG, TULONG, -1,
+};
+
+char typev[NTYPE];
+int typevinit[] =
+{
+ TVLONG, TUVLONG, -1,
+};
+
+char typefd[NTYPE];
+int typefdinit[] =
+{
+ TFLOAT, TDOUBLE, -1,
+};
+
+char typeaf[NTYPE];
+int typeafinit[] =
+{
+ TFUNC, TARRAY, -1,
+};
+
+char 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,
+};
+
+char 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 i;
+ 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(i=0; typeiinit[i] >= 0; i++) {
+ urk("typei", nelem(typei), typeiinit[i]);
+ typei[typeiinit[i]] = 1;
+ }
+ for(i=0; typeuinit[i] >= 0; i++) {
+ urk("typeu", nelem(typeu), typeuinit[i]);
+ typeu[typeuinit[i]] = 1;
+ }
+ for(i=0; typesuvinit[i] >= 0; i++) {
+ urk("typesuv", nelem(typesuv), typesuvinit[i]);
+ typesuv[typesuvinit[i]] = 1;
+ }
+ for(i=0; typeilpinit[i] >= 0; i++) {
+ urk("typeilp", nelem(typeilp), typeilpinit[i]);
+ typeilp[typeilpinit[i]] = 1;
+ }
+ for(i=0; typechlinit[i] >= 0; i++) {
+ urk("typechl", nelem(typechl), typechlinit[i]);
+ typechl[typechlinit[i]] = 1;
+ }
+ for(i=0; typechlpinit[i] >= 0; i++) {
+ urk("typechlp", nelem(typechlp), typechlpinit[i]);
+ typechlp[typechlpinit[i]] = 1;
+ }
+ for(i=0; typechlpfdinit[i] >= 0; i++) {
+ urk("typechlpfd", nelem(typechlpfd), typechlpfdinit[i]);
+ typechlpfd[typechlpfdinit[i]] = 1;
+ }
+ for(i=0; typecinit[i] >= 0; i++) {
+ urk("typec", nelem(typec), typecinit[i]);
+ typec[typecinit[i]] = 1;
+ }
+ for(i=0; typehinit[i] >= 0; i++) {
+ urk("typeh", nelem(typeh), typehinit[i]);
+ typeh[typehinit[i]] = 1;
+ }
+ for(i=0; typeilinit[i] >= 0; i++) {
+ urk("typeil", nelem(typeil), typeilinit[i]);
+ typeil[typeilinit[i]] = 1;
+ }
+ for(i=0; typevinit[i] >= 0; i++) {
+ urk("typev", nelem(typev), typevinit[i]);
+ typev[typevinit[i]] = 1;
+ }
+ for(i=0; typefdinit[i] >= 0; i++) {
+ urk("typefd", nelem(typefd), typefdinit[i]);
+ typefd[typefdinit[i]] = 1;
+ }
+ for(i=0; typeafinit[i] >= 0; i++) {
+ urk("typeaf", nelem(typeaf), typeafinit[i]);
+ typeaf[typeafinit[i]] = 1;
+ }
+ for(i=0; typesuinit[i] >= 0; i++) {
+ urk("typesu", nelem(typesu), typesuinit[i]);
+ typesu[typesuinit[i]] = 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;
+ }
+}