+build(op) {
+ extern cp[], cvtab, opdope[], maprel[];
+ auto p1[], t1, d1, p2[], t2, d2, p3[], t3, d3, t;
+ auto d, dope, leftc, cvn, pcvn;
+ char cvtab[];
+
+ if (op==4) { /* [] */
+ build(40); /* + */
+ op = 36; /* * */
+ }
+ dope = opdope[op];
+ if ((dope&01)!=0) { /* binary */
+ p2 = disarray(*--cp);
+ t2 = p2[1];
+ chkfun(p2);
+ d2 = p2[2];
+ if (*p2==20)
+ d2 = 0;
+ }
+ p1 = disarray(*--cp);
+ if (op!=100 & op!=35) /* call, * */
+ chkfun(p1);
+ t1 = p1[1];
+ d1 = p1[2];
+ if (*p1==20)
+ d1 = 0;
+ pcvn = 0;
+ switch (op) {
+
+ /* : */
+ case 8:
+ if (t1!=t2)
+ error("Type clash in conditional");
+ t = t1;
+ goto nocv;
+
+ /* , */
+ case 9:
+ *cp++ = block(2, 9, 0, 0, p1, p2);
+ return;
+
+ /* ? */
+ case 90:
+ if (*p2!=8)
+ error("Illegal conditional");
+ t = t2;
+ goto nocv;
+
+ /* call */
+ case 100:
+ if ((t1&030) != 020)
+ error("Call of non-function");
+ *cp++ = block(2,100,decref(t1),24,p1,p2);
+ return;
+
+ /* * */
+ case 36:
+ if (*p1==35 | *p1==29) { /* & unary */
+ *cp++ = p1[3];
+ return;
+ }
+ if (*p1!=20 & d1==0)
+ d1 = 1;
+ if ((t1&030) == 020) /* function */
+ error("Illegal indirection");
+ *cp++ = block(1,36,decref(t1),d1,p1);
+ return;
+
+ /* & unary */
+ case 35:
+ if (*p1==36) { /* * */
+ *cp++ = p1[3];
+ return;
+ }
+ if (*p1==20) {
+ *cp++ = block(1,p1[3]==5?29:35,incref(t1),1,p1);
+ return;
+ }
+ error("Illegal lvalue");
+ break;
+
+ case 43: /* / */
+ case 44: /* % */
+ case 73: /* =/ */
+ case 74: /* =% */
+ d1++;
+ d2++;
+
+ case 42: /* * */
+ case 72: /* =* */
+ d1++;
+ d2++;
+ break;
+
+ case 30: /* ++ -- pre and post */
+ case 31:
+ case 32:
+ case 33:
+ chklval(p1);
+ *cp++ = block(2,op,t1,max(d1,1),p1,plength(p1));
+ return;
+
+ case 39: /* . (structure ref) */
+ case 50: /* -> (indirect structure ref) */
+ if (p2[0]!=20 | p2[3]!=4) /* not mos */
+ error("Illegal structure ref");
+ *cp++ = p1;
+ t = t2;
+ if ((t&030) == 030) /* array */
+ t = decref(t);
+ setype(p1, t);
+ if (op==39) /* is "." */
+ build(35); /* unary & */
+ *cp++ = block(1,21,7,0,p2[5]);
+ build(40); /* + */
+ if ((t2&030) != 030) /* not array */
+ build(36); /* unary * */
+ return;
+ }
+ if ((dope&02)!=0) /* lvalue needed on left? */
+ chklval(p1);
+ if ((dope&020)!=0) /* word operand on left? */
+ chkw(p1);
+ if ((dope&040)!=0) /* word operand on right? */
+ chkw(p2);
+ if ((dope&01)==0) { /* unary op? */
+ *cp++ = block(1,op,t1,max(d1,1),p1);
+ return;
+ }
+ if (t2==7) {
+ t = t1;
+ p2[1] = 0; /* no int cv for struct */
+ t2 = 0;
+ goto nocv;
+ }
+ cvn = cvtab[11*lintyp(t1)+lintyp(t2)];
+ leftc = cvn&0100;
+ t = leftc? t2:t1;
+ if (op==80 & t1!=4 & t2!=4) { /* = */
+ t = t1;
+ if (leftc | cvn!=1)
+ goto nocv;
+ }
+ if (cvn =& 077) {
+ if (cvn==077) {
+ illcv:
+ error("Illegal conversion");
+ goto nocv;
+ }
+ if (cvn>4 & cvn<10) { /* ptr conv */
+ t = 0; /* integer result */
+ cvn = 0;
+ if ((dope&04)!=0) /* relational? */
+ goto nocv;
+ if (op!=41) /* - */
+ goto illcv;
+ pcvn = cvn;
+ goto nocv;
+ }
+ if (leftc) {
+ if ((dope&010) != 0) { /* =op */
+ if (cvn == 1) {
+ leftc = 0;
+ cvn = 8;
+ t = t1;
+ goto rcvt;
+ } else
+ goto illcv;
+ }
+ d1 = (p1=convert(p1, t, d1, cvn, plength(p2)))[2];
+ } else {
+ rcvt:
+ d2 = (p2=convert(p2, t, d2, cvn, plength(p1)))[2];
+ }
+nocv:; }
+ if (d1==d2)
+ d = d1+1; else
+ d = max(d1,d2);
+ if ((dope&04)!=0) { /* relational? */
+ if (op>61 & t>=010)
+ op =+ 4; /* ptr relation */
+ t = 0; /* relational is integer */
+ }
+ *cp++ = optim(block(2,op,t,d,p1,p2));
+ if (pcvn) {
+ p1 = *--cp;
+ *cp++ = block(1,50+pcvn,0,d,p1);
+ }
+ return;
+ *cp++ = block(1,op,t1,d1==0?1:d1,p1);
+}
+
+setype(p, t)
+int p[];
+{
+ int p1[];
+
+ if ((p[1]&07) != 4) /* not structure */
+ return;
+ p[1] = t;
+ switch(*p) {
+
+ case 29: /* & */
+ case 35:
+ setype(p[3], decref(t));
+ return;
+
+ case 36: /* * */
+ setype(p[3], incref(t));
+ return;
+
+ case 40: /* + */
+ setype(p[4], t);
+ }
+}
+
+chkfun(p)
+int p[];
+{
+ if ((p[1]&030)==020) /* func */
+ error("Illegal use of function");
+}
+
+optim(p)
+int p[];
+{
+ int p1[], p2[], t;
+
+ if (*p != 40) /* + */
+ return(p);
+ p1 = p[3];
+ p2 = p[4];
+ if (*p1==21) { /* const */
+ t = p1;
+ p1 = p2;
+ p2 = t;
+ }
+ if (*p2 != 21) /* const */
+ return(p);
+ if ((t=p2[3]) == 0) /* const 0 */
+ return(p1);
+ if (*p1!=35 & *p1!=29) /* not & */
+ return(p);
+ p2 = p1[3];
+ if (*p2!=20) { /* name? */
+ error("C error (optim)");
+ return(p);
+ }
+ p2[4] =+ t;
+ return(p1);
+}
+
+disarray(p)
+int p[];
+{
+ extern cp;
+ int t, cp[];
+
+ if (((t = p[1]) & 030)!=030 | p[0]==20&p[3]==4) /* array & not MOS */
+ return(p);
+ p[1] = decref(t);
+ *cp++ = p;
+ build(35); /* add & */
+ return(*--cp);
+}
+
+convert(p, t, d, cvn, len)
+int p[];
+{
+ int c, p1[];
+
+ if (*p==21) { /* constant */
+ c = p[3];
+ switch(cvn) {
+
+ case 4: /* int -> double[] */
+ c =<< 1;
+
+ case 3: /* int -> float[] */
+ c =<< 1;
+
+ case 2: /* int -> int[] */
+ c =<< 1;
+ p[3] = c;
+ return(p);
+
+ case 10: /* i -> s[] */
+ p[3] = c*len;
+ return(p);
+ }
+ }
+ if (cvn==10) /* i -> s[]; retrun i*len */
+ return(block(2,42,t,d+2,p,block(1,21,0,0,len)));
+ return(block(1, 50+cvn, t, max(1,d), p));
+}
+
+chkw(p)
+int p[]; {
+ extern error;
+ auto t;
+
+ if ((t=p[1])>1 & t<=07)
+ error("Integer operand required");
+ return;
+}
+
+lintyp(t)
+{
+ if (t<=07)
+ return(t);
+ if ((t&037)==t)
+ return((t&07)+5);
+ return(10);
+}
+
+error(s, p1, p2, p3, p4, p5, p6) {
+ extern line, fout, nerror;
+ int f;
+
+ nerror++;
+ flush();
+ f = fout;
+ fout = 1;
+ printf("%d: ", line);
+ printf(s, p1, p2, p3, p4, p5, p6);
+ putchar('\n');
+ fout = f;
+}
+
+block(n, op, t, d, p1,p2,p3)
+int p1[],p2[],p3[]; {
+ int p[], ap[], space[];
+ extern space;
+
+ ap = &op;
+ n =+ 3;
+ p = space;
+ while(n--)
+ pblock(*ap++);
+ return(p);
+}
+
+pblock(p)
+{
+ extern space, osleft;
+ int space[];
+
+ *space++ = p;
+ if (--osleft<=0) {
+ error("Expression overflow");
+ exit(1);
+ }
+}
+
+chklval(p)
+int p[]; {
+ extern error;
+
+ if (*p!=20 & *p !=36)
+ error("Lvalue required");
+}
+
+max(a, b)
+{
+ if (a>b)
+ return(a);
+ return(b);
+}
+