// cc -c skimpes.c -I /home/gtoal/src/compilers101/new-parser/imps

/*
gtoal@linux:~/src/skimp/new/mark2$ fgrep \>\> skimp*.c|fgrep 28
skimpbs.c:      if ((unsigned)Nametag >> 28 == 4) {
skimpbs.c:      if ((unsigned)Nametag >> 28 >= 2) {
skimpbs.c:        if ((unsigned)Nametag >> 28 == 1) {
skimpbs.c:    } else if ((unsigned)Nametag >> 28 == 4 &&

skimpds.c:    if ((unsigned)Nametag >> 28 == 4) {
skimpds.c:      if (!((unsigned)Ptag >> 28))
skimpds.c:            if ((unsigned)Pnametag >> 28 == 4)
skimpds.c:              if ((unsigned)Ptag >> 28 == 1)
skimpds.c:                if ((unsigned)Pnametag >> 28 >= 2)
skimpds.c:                  if ((unsigned)Pnametag >> 28 == 1)

skimpes.c:          if ((unsigned)Nametag >> 28 <= 1)
skimpes.c:          else if ((unsigned)Nametag >> 28 <= 3)
skimpes.c:        if ((unsigned)Datum >> 28 == 1) {
*/

#include <perms.h>

#ifndef NDEBUG
// Although gcc supports array bounds checking for arrays based at 0, it
// does not handle arrays with non-zero lower bounds.  Indeed neither does C,
// so the non-stanard macro processor below is a hack to add Imp-style lower
// and upper bounds to C arrays.  With bounds checking!
extern int _C(int x, char *name, int lower, int upper, char *filename, int line);
#define _C(x, name, lower, upper) _C((x), name, (lower), (upper), __FILE__, __LINE__)
#else
// No array bound checking
#define _C(x, name, lower, upper) (x)
#endif

extern int A[500 /*1:500*/];
$define A[x] A[(x)-1]
extern int Taglink[256 /*0:255*/];
extern int Tag[512 /*1:512*/];
$define Tag[x] Tag[(x)-1]
_imp_string Display[16 /*0:15*/];
extern int Level;
extern int Condflag;
extern int Expropt;
_imp_string Strint(int N, int P);
_imp_string Strhex(int N);
void Fault(_imp_string S);
_imp_string Name(int Ident);
void Dump(_imp_string Opn, _imp_string Reg, _imp_string Base, int Disp);
int Getwork(void);
void Returnwork(int Work);
void Proc(int Ap);
void Array(int Ap);
int Getcoti(int Const);
void Expr(int Exprp) {
  auto int Totree(int Exprp);
  auto void Evaluate(int Nodep);
  int Tree[64 /*1:64*/];
$define Tree[x] Tree[(x)-1]
  int Treep;
  int Treenode;
  int Treenode1;
  int Treenode2;
  int Testp;
  int Expr1p;
  int Expr2p;
  int Compp;
  int I;
  int J;
  int L;
  static const int Reversecomp[6 /*1:6*/] = {1, 2, 5, 6, 3, 4};
$define Reversecomp[x] Reversecomp[(x)-1]
  Treep = 1;
  if (!Condflag)
    Treenode = Totree(Exprp);
  else {
    Condflag = 0;
    Testp = Exprp;
    Expr1p = A[Testp + 1];
    Compp = A[Testp + 2];
    Expr2p = A[Testp + 3];
    Treenode1 = Totree(Expr1p);
    Treenode2 = Totree(Expr2p);
    if (Tree[Treenode1] == -4 && Tree[Treenode1 + 1] == 0) {
      A[Compp] = Reversecomp[A[Compp]];
      Treenode = Treenode2;
    } else if (Tree[Treenode2] == -4 && Tree[Treenode2 + 1] == 0)
      Treenode = Treenode1;
    else {
      Tree[Treep] = 10;
      Tree[Treep + 1] = Treenode1;
      Tree[Treep + 2] = Treenode2;
      Treenode = Treep;
    }
  }
  if (Expropt == 1) {
    Newline();
    if (0 < Tree[Treenode] && Tree[Treenode] <= 10)
      L = Treenode + 2;
    else
      L = Treenode + 1;
    J = 0;
    for (I = 1; I <= L; I++) {
      Write(Tree[I], 4);
      J += 5;
      if (I == Treenode) Printstring(_imp_str_literal("*"));
      if (Tree[I] == -3) {
        I++;
        Printstring(_imp_join(_imp_str_literal("  "), Strhex(Tree[I])));
        J += 10;
      }
      if (J > 70) {
        Newline();
        J = 0;
      }
    }
    Newlines(2);
  }
  Evaluate(Treenode);
  return;
  int Totree(int Exprp) {
    auto void Pseval(int Type, int Datum);
    int Os[4 /*1:4*/];
$define Os[x] Os[(x)-1]
    int Ps[5 /*1:5*/];
$define Ps[x] Ps[(x)-1]
    int Osp;
    int Psp;
    int Unaryp;
    int Operandp;
    int Exprrestp;
    int Opp;
    int Namep;
    int Actualp;
    int Ident;
    int Nametag;
    static const int Prec[12 /*1:12*/] = {3, 3, 2, 1, 1, 3, 2, 2, 1, 1, 1, 4};
$define Prec[x] Prec[(x)-1]
    // <UNARY><OPERAND><EXPRREST>
    Unaryp = A[Exprp + 1];
    Operandp = A[Exprp + 2];
    Exprrestp = A[Exprp + 3];
    if (A[Unaryp] <= 2) {    // <UNARY>='-','\','+',;
      Os[1] = A[Unaryp] + 10; // 10: '-', 11: '\', 12: '+'
      Osp = 1;
    } else
      Osp = 0;
    Psp = 0;
    for (;;) {
      if (A[Operandp] == 1) {
        Namep = A[Operandp + 1];
        Actualp = A[Operandp + 2];
        Ident = A[Namep + 1];
        if (!Taglink[Ident]) {
          Fault(_imp_join(Name(Ident), _imp_str_literal(" NOT DECLARED")));
          Pseval(-3, 0);
        } else {
          Nametag = Tag[Taglink[Ident]];
          if ((((unsigned)Nametag >> 28)&7) <= 1)
            if (A[Actualp] == 1) {
              Fault(_imp_join(
                  _imp_str_literal("SCALAR "),
                  _imp_join(Name(Ident), _imp_str_literal(" HAS PARAMETER"))));
              Pseval(-3, 0);
            } else
              Pseval(-3, Nametag);
          else if ((((unsigned)Nametag >> 28)&7) <= 3)
            Pseval(-2, Operandp);
          else if (!((unsigned)Nametag >> 24 & 0xF)) {
            Fault(_imp_join(
                _imp_str_literal("ROUTINE NAME "),
                _imp_join(Name(Ident), _imp_str_literal(" IN EXPRESSION"))));
            Pseval(-3, 0);
          } else
            Pseval(-1, Operandp);
        }
      } else if (A[Operandp] == 2)
        Pseval(-4, A[A[Operandp + 1] + 1]);
      else {
        Psp++;
        Ps[Psp] = Totree(A[Operandp + 1]);
      }
      if (A[Exprrestp] == 2) break;
      Opp = A[Exprrestp + 1];
      Operandp = A[Exprrestp + 2];
      Exprrestp = A[Exprrestp + 3];
      while (Osp > 0 && Prec[A[Opp]] <= Prec[Os[Osp]]) {
        Pseval(Os[Osp], 0);
        Osp--;
      }
      Osp++;
      Os[Osp] = A[Opp];
    }
    while (Osp > 0) {
      Pseval(Os[Osp], 0);
      Osp--;
    }
    return (Ps[1]);
    void Pseval(int Type, int Datum) {
      auto void Store(int T);
      int Nodep;
      Nodep = Treep;
      Store(Type);
      if (Type > 0)
        if (Type > 10)  // unary?  10: '-', 11: '\', 12: '+'
          Store(Ps[Psp]);
        else {
          Store(Ps[Psp - 1]);
          Store(Ps[Psp]);
          Psp--;
        }
      else {
        Store(Datum);
        Psp++;
      }
      Ps[Psp] = Nodep;
      void Store(int T) {
        if (Treep > 64) {
          Fault(_imp_str_literal("EXPRESSION TOO LONG"));
          exit(0);
        }
        Tree[Treep] = T;
        Treep++;
      }
    }
  }
  void Evaluate(int Nodep) {
    auto void Opn(int Op, int P);
    static const _imp_string Strop[13 /*0:12*/] = {
        _imp_str_literal("LOAD"), _imp_str_literal("SHL"),
        _imp_str_literal("SHR"),  _imp_str_literal("AND"),
        _imp_str_literal("XOR"),  _imp_str_literal("OR"),
        _imp_str_literal("EXP"),  _imp_str_literal("DIV"),
        _imp_str_literal("MLT"),  _imp_str_literal("ADD"),
        _imp_str_literal("SUB"),  _imp_str_literal("NEG"),
        _imp_str_literal("NOT")};
    static const int Commut[10 /*1:10*/] = {0, 0, 1, 1, 1, 0, 0, 1, 1, 0};
$define Commut[x] Commut[(x)-1]
    int Op;
    int Opd1p;
    int Opd2p;
    int Work;
    if (Tree[Nodep] < 0) {
      Opn(0, Nodep);
      return;
    }
    Op = Tree[Nodep];
    Opd1p = Tree[Nodep + 1];
    if (Op > 10) {
      if (Tree[Opd1p] >= -2)
        Evaluate(Opd1p);
      else
        Opn(0, Opd1p);
      Dump(Strop[Op], _imp_str_literal("ACC"), _imp_str_literal(""), 0);
      return;
    }
    Opd2p = Tree[Nodep + 2];
    if (Tree[Opd1p] >= -2)
      if (Tree[Opd2p] >= -2) {
        Evaluate(Opd2p);
        Work = Getwork();
        Dump(_imp_str_literal("STR"), _imp_str_literal("ACC"), Display[Level],
             Work);
        Evaluate(Opd1p);
        Dump(Strop[Op], _imp_str_literal("ACC"), Display[Level], Work);
        Returnwork(Work);
      } else {
        Evaluate(Opd1p);
        Opn(Op, Opd2p);
      }
    else if (Tree[Opd2p] >= -2) {
      Evaluate(Opd2p);
      if (Commut[Op]) {
        Opn(Op, Opd1p);
        return;
      }
      Work = Getwork();
      Dump(_imp_str_literal("STR"), _imp_str_literal("ACC"), Display[Level],
           Work);
      Opn(0, Opd1p);
      Dump(Strop[Op], _imp_str_literal("ACC"), Display[Level], Work);
      Returnwork(Work);
    } else {
      Opn(0, Opd1p);
      Opn(Op, Opd2p);
    }
    return;
    void Opn(int Op, int P) {
      _imp_string Base;
      int Type;
      int Datum;
      int Disp;
      Type = Tree[P];
      Datum = Tree[P + 1];
      if (Type == -1)
        Proc(Datum);
      else if (Type == -2) {
        Array(Datum);
        Dump(_imp_str_literal("LOAD"), _imp_str_literal("ACC"),
             _imp_str_literal("ACC"), 0);
      } else if (Type == -3) {
        Base = Display[(unsigned)Datum >> 16 & 0xF];
        Disp = Datum & 0xFFFF;
        if ((unsigned)Datum >> 28 == 1) {
          Dump(_imp_str_literal("LOAD"), _imp_str_literal("WK"), Base, Disp);
          Dump(Strop[Op], _imp_str_literal("ACC"), _imp_str_literal("WK"), 0);
        } else
          Dump(Strop[Op], _imp_str_literal("ACC"), Base, Disp);
      } else if (Op > 0 || Datum > 0xFFFF)
        Dump(Strop[Op], _imp_str_literal("ACC"), _imp_str_literal("COT"),
             Getcoti(Datum));
      else
        Dump(_imp_str_literal("LDA"), _imp_str_literal("ACC"),
             _imp_str_literal(""), Datum);
    }
  }
}
