// http://citeseer.ist.psu.edu/cache/papers/cs/16951/ftp:zSzzSzftp.cso.uiuc.eduzSzpubzSzlangzSzsmalltalkzSzpaperszSzcompilerszSztree-based-opt.prelim.pdf/mcconnell92treebased.pdf

static int nexttrip = 0;
static int AST[256*1024];


#define leftchild(t) AST[(t)+2]
#define rightchild(t) AST[(t)+3]
#define nthchild(t,n) AST[(t)+2+(n)]

#define RESERVE_FOR_TYPE_INFO 1
#define TYPEINFO(p) AST[(p)-1]

#define astop(p) AST[p]
#define children(p) AST[p+1]

static int latest_line = -1;

void semantic_error(char *s, char *p)
{
  fprintf(stderr, s, p);
  fprintf(stderr, "Text cells used = %d, Code cells used = %d\n\n", nextfree, nexttrip);
  fflush(stderr);
  exit(2);
}

int mk(int AST_op, int count, int *T) {
  int trip;
  int parm;

  trip = nexttrip+RESERVE_FOR_TYPE_INFO;
  AST[trip-1] = -1; // initialise TYPEINFO
  AST[trip] = AST_op;
  AST[trip+1] = count;
  if ((AST_op != AST_Dummy) && (count != op[AST_op-AST_BASE].Children)) fprintf(stderr, "? Internal warning: size mismatch in mk(%d, %d)\n", AST_op, count);
  for (parm = 0; parm < count; parm++) {
    AST[trip+parm+2] = T[parm+1];
  }
  nexttrip += 2+count+RESERVE_FOR_TYPE_INFO;
  return trip;
}

// the next 3 wrappers are just for convenience. All could be replaced by calls to the above

int mkmonop(int AST_op, int child) {
  int trip;

  trip = nexttrip+RESERVE_FOR_TYPE_INFO;
  AST[trip-1] = -1; // initialise TYPEINFO
  AST[trip] = AST_op;
  AST[trip+1] = 1;
  if (1 != op[AST_op-AST_BASE].Children) fprintf(stderr, "? Internal warning: size mismatch in mkmonop(%d)\n", AST_op);
  AST[trip+2] = child;
  nexttrip += 3+RESERVE_FOR_TYPE_INFO;
  return trip;
}

int mkbinop(int AST_op, int leftchild, int rightchild) {
  int trip;

  trip = nexttrip+RESERVE_FOR_TYPE_INFO;
  AST[trip-1] = -1; // initialise TYPEINFO
  AST[trip] = AST_op;
  AST[trip+1] = 2;
  if (2 != op[AST_op-AST_BASE].Children) fprintf(stderr, "? Internal warning: size mismatch in mkbinop(%d)\n", AST_op);
  AST[trip+2] = leftchild;
  AST[trip+3] = rightchild;
  nexttrip += 4+RESERVE_FOR_TYPE_INFO;
  return trip;
}

int mkterop(int AST_op, int leftchild, int rightchild, int extrachild) {
  int trip;

  trip = nexttrip+RESERVE_FOR_TYPE_INFO;
  AST[trip-1] = -1; // initialise TYPEINFO
  AST[trip] = AST_op;
  AST[trip+1] = 3;
  if (3 != op[AST_op-AST_BASE].Children) fprintf(stderr, "? Internal warning: size mismatch in mkterop(%d)\n", AST_op);
  AST[trip+2] = leftchild;
  AST[trip+3] = rightchild;
  AST[trip+4] = extrachild;
  nexttrip += 5+RESERVE_FOR_TYPE_INFO;
  return trip;
}

int mkconst(int n)
{
  char s[128];
  int trip = nexttrip+RESERVE_FOR_TYPE_INFO;
  sprintf(s, "%d", n);
  AST[trip] = AST_Const;
  AST[trip+1] = 2;
  if (2 != op[AST_Const-AST_BASE].Children) fprintf(stderr, "? Internal warning: size mismatch in mkconst(%d)\n", n);
  AST[trip+2] = mkliteral(s);
  AST[trip+3] = n;
  nexttrip += 4+RESERVE_FOR_TYPE_INFO;
  TYPEINFO(trip) = TypeAtom("signed", "int"); // initialise TYPEINFO
  return trip;
}

void replace_with_int_const(int p, int val) // AHA BUG FOUND.  SOME replace's are not with constants!
{
  AST[p] = AST_REDIRECT; // REDIRECT is a monop and therefore must always fit in the old slot.
  // preserving AST[p+1] allows us to skip these nodes safely by counting
  AST[p+2] = mkconst(val); // derived constant, literal is generated and stored in c[].s
  TYPEINFO(p) = -1;
}

void replace_with_trip(int p, int trip) // AHA BUG FOUND.  SOME replace's are not with constants!
{
fprintf(stderr, "replace_with_trip: references to %d should be replaced by references to %d\n", p, trip);
  AST[p] = AST_REDIRECT; // REDIRECT is a monop and therefore must always fit in the old slot.
  // preserving AST[p+1] allows us to skip these nodes safely by counting
  AST[p+2] = trip;
  TYPEINFO(p) = -1;
}

void replace_struct_pointer(int p, int badstruct, int goodstruct)
{
  int i;
  int disp;
  int this;

  rightchild(badstruct) = rightchild(goodstruct);
  nthchild(badstruct,2) = nthchild(goodstruct, 2);
  return;

  fprintf(stderr,
     "%d: replace_struct_pointer: every reference to %d in an AST_TYPE_Struct should be replaced by %d\n",
	  p, rightchild(badstruct), rightchild(goodstruct));

  if (astop(p) == AST_TYPE_Struct) { // StructName StructMemberList structsize
    if (rightchild(p) == badstruct) {
      fprintf(stderr, "replace_struct_pointer: replaced AST[%d]\n", p);
      rightchild(p) = goodstruct;
      fprintf(stdout, "Replaced %d with %d in struct at %d\n", badstruct, goodstruct, p);
    }
  }

  disp = op[astop(p)-AST_BASE].Display_Children;
  this = 1<<(children(p)-1);
  for (i = 0; i < children(p); i++) {
    if ((nthchild(p, i) != -1) && (disp&this)) {
      replace_struct_pointer(nthchild(p, i), badstruct, goodstruct);
    }
    this = this>>1;
  }

}

int clone(int p) {
  int i = mk(AST[p], AST[p+1], AST+p+1);  
  TYPEINFO(i) = TYPEINFO(p);
  return i;
}

int DefToReceive(int p)
{
  int T[4];
  // *copy* a chain of DefParams to a chain of ReceiveParams (don't just tweak the types in situ)
  if (p == -1) return -1;
  T[1] = leftchild(p);//name
  T[2] = rightchild(p);//type
  T[3] = DefToReceive(nthchild(p, 2));//link
  T[0] = mk(AST_ReceiveParam, 3, T);
  TYPEINFO(T[0]) = TYPEINFO(p);
  return T[0];
}

int character_constant(int ap)
{
  int i = mkbinop(AST_Const, A[ap+4], c[A[ap+4]].s[0]);
  TYPEINFO(i) = TypeAtom("signed", "char"); // initialise TYPEINFO
  return i;
}
int integer_constant(int ap)
{
  int i = mkbinop(AST_Const, A[ap+4], atoi(c[A[ap+4]].s));
  TYPEINFO(i) = TypeAtom("signed", "int"); // initialise TYPEINFO
  return i;
}
int string_constant(int ap)
{
  int i = mkbinop(AST_Const, A[ap+4], A[ap+4]);
  return i; // TO DO: array of char
}

