summaryrefslogtreecommitdiff
path: root/utils/c2l/c2l.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/c2l/c2l.c')
-rw-r--r--utils/c2l/c2l.c5118
1 files changed, 5118 insertions, 0 deletions
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));
+ }
+}