
/*
** lval[0] - symbol table address, else 0 for constant
** lval[1] - type of indirect obj to fetch, else 0 for static
** lval[2] - type of pointer or array, else 0 for all other
** lval[3] - true if constant expression
** lval[4] - value of constant expression
** lval[5] - true if secondary register altered
** lval[6] - function address of highest/last binary operator
** lval[7] - stage address of "oper 0" code, else 0
*/

/*
** skim over terms adjoining || and && operators
*/
skim(opstr, testfunc, dropval, endval, heir, lval)
  char *opstr;

#ifdef FULLC
  int (*testfunc)(), dropval, endval, (*heir)(), lval[]; {
#else /* FULLC */
  int testfunc, dropval, endval, heir, lval[]; {
#endif /* FULLC */

  int k, hits, droplab, endlab;
  hits=0;
  while(1) {
    k=plung1(heir, lval);
    if(nextop(opstr)) {
      bump(opsize);
      if(hits==0) {
        hits=1;
        droplab=getlabel();
        }
      dropout(k, testfunc, droplab, lval);
      }
    else if(hits) {
      dropout(k, testfunc, droplab, lval);
      const(endval);
      jump(endlab=getlabel());
      postlabel(droplab);
      const(dropval);
      postlabel(endlab);
      lval[1]=lval[2]=lval[3]=lval[7]=0;
      return 0;
      }
    else return k;
    }
  }

/*
** test for early dropout from || or && evaluations
*/
#ifdef FULLC
dropout(k, testfunc, exit1, lval) int k, (*testfunc)(), exit1, lval[]; {
#else /* FULLC */
dropout(k, testfunc, exit1, lval) int k, testfunc, exit1, lval[]; {
#endif /* FULLC */

  if(k) rvalue(lval);
  else if(lval[3]) const(lval[4]);

#ifdef FULLC
  (*testfunc)(exit1); /* jumps on false */
#else /* FULLC */
  testfunc(exit1); /* jumps on false */
#endif /* FULLC */

  }

/*
** plunge to a lower level
*/
plunge(opstr, opoff, heir, lval)
  char *opstr;

#ifdef FULLC
  int opoff, (*heir)(), lval[]; {
#else /* FULLC */
  int opoff, heir, lval[]; {
#endif /* FULLC */

  int k, lval2[8];
  k=plung1(heir, lval);
  if(nextop(opstr)==0) return k;
  if(k) rvalue(lval);
  while(1) {
    if(nextop(opstr)) {
      bump(opsize);
      opindex=opindex+opoff;
      plung2(op[opindex], op2[opindex], heir, lval, lval2);
      }
    else return 0;
    }
  }

/*
** unary plunge to lower level
** renamed "plung1" (original was "plunge1") to have
** first 6 chars unique for M80 assembler.
*/
#ifdef FULLC
plung1(heir, lval) int (*heir)(), lval[]; {
#else /* FULLC */
plung1(heir, lval) int heir, lval[]; {
#endif /* FULLC */

  char *before, *start;
  int k;
  setstage(&before, &start);

#ifdef FULLC
  k= (*heir)(lval);
#else /* FULLC */
  k= heir(lval);
#endif /* FULLC */

  if(lval[3]) clearstage(before,0); /* load constant later */
  return k;
  }

/*
** binary plunge to lower level
** renamed "plung2" (original was "plunge2") to have
** first 6 chars unique for M80 assembler.
*/
plung2(oper, oper2, heir, lval, lval2)

#ifdef FULLC
  int (*oper)(), (*oper2)(), (*heir)(), lval[], lval2[]; {
#else /* FULLC */
  int oper, oper2, heir, lval[], lval2[]; {
#endif /* FULLC */

  char *before, *start;
  setstage(&before, &start);
  lval[5]=1;          /* flag secondary register used */
  lval[7]=0;          /* flag as not "... oper 0" syntax */
  if(lval[3]) {       /* constant on left side not yet loaded */
    if(plung1(heir, lval2)) rvalue(lval2);
    if(lval[4]==0) lval[7]=stagenext;
    const2(lval[4]<<dbltest(lval2, lval));
    }
  else {              /* non-constant on left side */
    push();
    if(plung1(heir, lval2)) rvalue(lval2);
    if(lval2[3]) {    /* constant on right side */
      if(lval2[4]==0) lval[7]=start;
      if(oper==zzadd) { /* may test other commutative operators */
        csp=csp+2;
        clearstage(before, 0);
        const2(lval2[4]<<dbltest(lval, lval2));   /* load secondary */
        }
      else {
        const(lval2[4]<<dbltest(lval, lval2));    /* load primary */
        smartpop(lval2, start);
        }
      }
    else {            /* non-constants on both sides */
      smartpop(lval2, start);
      if((oper==zzadd)|(oper==zzsub)) {
        if(dbltest(lval,lval2)) doublereg();
        if(dbltest(lval2,lval)) {
          swap();
          doublereg();
          if(oper==zzsub) swap();
          }
        }
      }
    }
  if(oper) {
    if(lval[3]=lval[3]&lval2[3]) {
      lval[4]=calc(lval[4], oper, lval2[4]);
      clearstage(before, 0);  
      lval[5]=0;
      }
    else {
      if((lval[2]==0)&(lval2[2]==0)) {

#ifdef FULLC
        (*oper)();
#else /* FULLC */
        oper();
#endif /* FULLC */

        lval[6]= oper;    /* identify the operator */
        }
      else {

#ifdef FULLC
        (*oper2)();
#else /* FULLC */
        oper2();
#endif /* FULLC */

        lval[6]= oper2;   /* identify the operator */
        }
      }
    if(oper==zzsub) {
      if((lval[2]==CINT)&(lval2[2]==CINT)) {
        swap();
        const(1);
        zzasr();  /** div by 2 **/
        }
      }
    if((oper==zzsub)|(oper==zzadd)) result(lval, lval2);
    }
  }

#ifdef FULLC
calc(left, oper, right) int left, (*oper)(), right; {
#else /* FULLC */
calc(left, oper, right) int left, oper, right; {
#endif /* FULLC */

       if(oper ==  zzor) return (left  |  right);
  else if(oper == zzxor) return (left  ^  right);
  else if(oper == zzand) return (left  &  right);
  else if(oper ==  zzeq) return (left  == right);
  else if(oper ==  zzne) return (left  != right);
  else if(oper ==  zzle) return (left  <= right);
  else if(oper ==  zzge) return (left  >= right);
  else if(oper ==  zzlt) return (left  <  right);
  else if(oper ==  zzgt) return (left  >  right);
  else if(oper == zzasr) return (left  >> right);
  else if(oper == zzasl) return (left  << right);
  else if(oper == zzadd) return (left  +  right);
  else if(oper == zzsub) return (left  -  right);
  else if(oper ==zzmult) return (left  *  right);
  else if(oper == zzdiv) return (left  /  right);
  else if(oper == zzmod) return (left  %  right);
  else return 0;
  }

expression(const, val) int *const, *val;  {
  int lval[8];
  if(heir1(lval)) rvalue(lval);
  if(lval[3]) {
    *const=1;
    *val=lval[4];
    }
  else *const=0;
  }

heir1(lval)  int lval[];  {

#ifdef FULLC
  int k,lval2[8], (*oper)(), heir3();
#else /* FULLC */
  int k,lval2[8], oper, heir3();
#endif /* FULLC */

  k=plung1(heir3, lval);
  if(lval[3]) const(lval[4]);
       if(match("|="))  oper= zzor;
  else if(match("^="))  oper= zzxor;
  else if(match("&="))  oper= zzand;
  else if(match("+="))  oper= zzadd;
  else if(match("-="))  oper= zzsub;
  else if(match("*="))  oper= zzmult;
  else if(match("/="))  oper= zzdiv;
  else if(match("%="))  oper= zzmod;
  else if(match(">>=")) oper= zzasr;
  else if(match("<<=")) oper= zzasl;
  else if(match("="))   oper= 0;
  else return k;
  if(k==0) {
    needlval();
    return 0;
    }
  if(lval[1]) {
    if(oper) {
      push();
      rvalue(lval);
      }
    plung2(oper, oper, heir1, lval, lval2);
    if(oper) pop();
    }
  else {
    if(oper) {
      rvalue(lval);
      plung2(oper, oper, heir1, lval, lval2);
      }
    else {
      if(heir1(lval2)) rvalue(lval2);
      lval[5]=lval2[5];
      }
    }
  store(lval);
  return 0;
  }

heir3(lval)  int lval[]; {
  int heir4();
  return skim("||", eq0, 1, 0, heir4, lval);
  }

heir4(lval)  int lval[]; {
  int heir5();
  return skim("&&", ne0, 0, 1, heir5, lval);
  }

heir5(lval)  int lval[]; {
  int heir6();
  return plunge("|", 0, heir6, lval);
  }

heir6(lval)  int lval[]; {
  int heir7();
  return plunge("^", 1, heir7, lval);
  }

heir7(lval)  int lval[]; {
  int heir8();
  return plunge("&", 2, heir8, lval);
  }

heir8(lval)  int lval[];  {
  int heir9();
  return plunge("== !=", 3, heir9, lval);
  }

heir9(lval)  int lval[];  {
  int heir10();
  return plunge("<= >= < >", 5, heir10, lval);
  }

heir10(lval)  int lval[];  {
  int heir11();
  return plunge(">> <<", 9, heir11, lval);
  }

heir11(lval)  int lval[];  {
  int heir12();
  return plunge("+ -", 11, heir12, lval);
  }

heir12(lval)  int lval[];  {
  int heir13();
  return plunge("* / %", 13, heir13, lval);
  }
                                                                             