// may later need to add base, offset (or parent) to each of these?  See how it goes...

int mktag(char *tag)
{
  return mkmonop(AST_TAG, mkliteral(tag));
}

int TypeArrayOf(int child, int index, int lower, int upper)
{
  int T[6];
  T[1] = child;
  T[2] = index;
  T[3] = 0; // always 0, in C
  T[4] = upper;
  T[5] = -1; // array element size (includes alignment padding)
  return mk(AST_TYPE_ArrayOf, 5, T);
}

int TypeStructMember(int NextMember, int MemberNameTag, int ThisMemberType)
{
  int T[5];
  T[1] = NextMember;
  T[2] = MemberNameTag;
  T[3] = ThisMemberType;
  T[4] = -1; // offset of this member relative to start of struct
  return mk(AST_TYPE_StructMember, 4, T);
}

int TypeStruct(int StructNameTag, int StructMemberList)
{
  int T[4];
  T[1] = StructNameTag;
  T[2] = StructMemberList;
  T[3] = -1; // size of struct object (includes alignment padding)
  return mk(AST_TYPE_Struct, 3, T);
}

int get_member_offset_inner(int Struct, int MemberTag, char *filename, int lineno)
#define get_member_offset(s, m) get_member_offset_inner(s,m,__FILE__,__LINE__)
{
  // Too messy.  Surely should only be one type of parameter?
  if ((astop(Struct) == AST_AddressOf) && (astop(leftchild(Struct)) == AST_TYPE_Struct)) {
    // if tag is good, go for it    
    Struct = leftchild(Struct);
  } else if ((astop(Struct) == AST_AddressOf) && (astop(leftchild(Struct)) == AST_TAG)) {
    if (astop(TYPEINFO(leftchild(Struct))) == -1) {
      fprintf(stdout, "! %s, Line %d: get_member_offset: typeinfo (@%d)\n", filename, lineno, TYPEINFO(leftchild(Struct)));
      exit(1);
    } else if (astop(TYPEINFO(leftchild(Struct))) != AST_TYPE_Struct) {
      fprintf(stdout, "! %s, Line %d: get_member_offset: typeinfo (@%d) is %d\n", filename, lineno, TYPEINFO(leftchild(Struct)), astop(TYPEINFO(leftchild(Struct))));
      exit(1);
    }
    Struct = TYPEINFO(leftchild(Struct));
  } else if (astop(Struct) == AST_TYPE_Struct) {
    // good struct, use it
  } else {
    fprintf(stdout, "! %s, Line %d: get_member_offset: Struct type (@%d) is %d\n", filename, lineno, Struct, astop(Struct));
    if (astop(Struct) == AST_AddressOf) {
      fprintf(stdout, "                   Points to a %d (@%d)\n", astop(leftchild(Struct)), leftchild(Struct));
    }
    exit(1);
  }
  if (astop(MemberTag) != AST_TAG) {
    fprintf(stdout, "! %s, Line %d: get_member_offset: tag field (@%d) contains %d\n", filename, lineno, MemberTag, astop(MemberTag));
    exit(1);
  }
  assert(astop(Struct) == AST_TYPE_Struct);
  {int member = rightchild(Struct);
    if (member == -1) {
      fprintf(stderr, "Struct at %d\n", Struct); show_one_ast(Struct,-1,-1);
      // it appears to be a duplicate that shhould have already been pointed to the first occurrance.
      exit(1);
    }
    for (;;) {
      if (astop(member) != AST_TYPE_StructMember) {
        fprintf(stderr, "AST[%d] = %d\n", member, astop(member));
        assert(astop(member) == AST_TYPE_StructMember);
      }
      //fprintf(stderr, "comparing %s to %s\n", c[leftchild(MemberTag)].s, c[leftchild(rightchild(member))].s);
      if (c[leftchild(MemberTag)].s == c[leftchild(rightchild(member))].s) {
        int offset = nthchild(member, 3);
	//fprintf(stderr, "returning offset %d\n", offset);
        return offset;
      }
      member = leftchild(member);
      if (member == -1) break;
    }
  }
  fprintf(stderr, "! %s, Line %d: get_member_offset - no result\n", filename, lineno);
  exit(1);
  /* NOT REACHED */ return -1;
}

int TypePointerTo(int child)
{
  return mkmonop(AST_TYPE_PointerTo, child);
}

int TypeAtom(char *signedness, char *size) // eg TypeAtom("signed" "long")
{
  int T[4];
  T[1] = 0;
  if (strcmp(size, "int") == 0) {
    T[2] = 4;
  } else if (strcmp(size, "long") == 0) { 
    T[2] = 4;
  } else if (strcmp(size, "long long") == 0) { 
    T[2] = 8;
  } else if (strcmp(size, "short") == 0) { 
    T[2] = 2;
  } else if (strcmp(size, "char") == 0) { 
    T[2] = 1;
  } else {
    T[2] = 0;
  }
  return mk(AST_TYPE_Atom, 2, T);
}

int ConstructType(char *what, int scope, int qualifier, int type, int pointers, int arrays) {
  int result;

  result = type;

  if ((astop(type) != AST_TYPE_Atom) && (astop(type) != AST_TYPE_Struct)) { // should probably apply scope/qual here?
    fprintf(stderr, "! Warning (Internal): basic type = %d\n", astop(type)); // probably a tag?
  }

  if ((pointers == -1) && (arrays == -1)) return result; // FOR NOW.  TO DO!

  if (pointers != -1) {
    int chain = pointers;
    int chainlen = 0;
    for (;;) {
      assert(astop(chain) == AST_TYPE_PointerTo);
      if (leftchild(chain) == -1) break;
      chain = leftchild(chain); chainlen += 1;
      if (chainlen == 5) exit(1); // arbitrary limit used when debugging a loop.  remove later.
    }
    leftchild(chain) = result;
    result = pointers;
  }

  if (arrays != -1) {
    int chain = arrays;
    int chainlen = 0;
    for (;;) {
      assert(astop(chain) == AST_TYPE_ArrayOf);
      if (leftchild(chain) == -1) break;
      chain = leftchild(chain); chainlen += 1;
      if (chainlen == 5) exit(1);
    }
    leftchild(chain) = result;
    result = arrays;
  }

  return result;
}
