diff options
Diffstat (limited to 'utils/c2l/c2l.c')
| -rw-r--r-- | utils/c2l/c2l.c | 5118 |
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)); + } +} |
