/*
typedef struct operation {
  int AST_Code;
  int Children;
  char *Diag_Name;
  char *C_Name;
  int Display_Children;
} operation;
 */

static char so_temp[1024];
void show_object(int p)
{
  switch (astop(p)) {
  case AST_TAG: strcat(so_temp, c[leftchild(p)].s); return;
  case AST_Idx: show_object(leftchild(p)); strcat(so_temp, "["); show_object(rightchild(p)); strcat(so_temp, "]"); return;
  case AST_Ptr: show_object(leftchild(p)); strcat(so_temp, "->"); show_object(rightchild(p)); return;
  case AST_Member: show_object(leftchild(p)); strcat(so_temp, "."); show_object(rightchild(p)); return;
  default: strcat(so_temp, "???"); return;  // for now - TO DO
  }
}

char *so(int p) {
  so_temp[0] = '\0';
  show_object(p);
  return so_temp;
}

int get_lineno(int p) {
  int l;
  int disp;
  int this;
  int i;

  switch (astop(p)) {
  case AST_TAG: return c[leftchild(p)].l;
  case AST_Idx: 
  case AST_Ptr: 
  case AST_Member:
    l = get_lineno(leftchild(p));
    if (l == -1) return get_lineno(rightchild(p)); 
  default:

     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)) {
	 l = get_lineno(nthchild(p, i));
         if (l != -1) return l;
       }
       this = this>>1;
     }
     return -1;
  }
}

void print_all_trips(void)
{
  // breaks when we shorten a trip using AST_REDIRECT :-(
  int ap = RESERVE_FOR_TYPE_INFO;
  for (;;) {
    int oper = AST[ap];
    int count = AST[ap+1];
    int child = ap+2;
    int disp = op[oper-AST_BASE].Display_Children;
    int this;
    if ((oper >= AST_BASE) && (oper <= AST_TOP)) {
      fprintf(stdout, "%4d: %s", ap, op[oper-AST_BASE].Diag_Name);
    } else {
      fprintf(stdout, "%4d: %d", ap, oper/*op[oper-AST_BASE].Diag_Name*/);
    }
    if (oper == AST_TAG) {
      if (AST[child] != -1) {
        fprintf(stdout, " \"%s\" (c[%d].s)", c[AST[child]].s, AST[child]);
      } else {
        fprintf(stdout, " %d", AST[child]);
      }
    } else {
      this = 1<<(count-1);
      for (;;) {
        if (child == ap+2+count) break;
        if ((AST_BASE <= AST[child]) && (AST[child] <= AST_TOP) && (astop(AST[child]) == AST_TAG)) {
          fprintf(stdout, " \"%s\"", c[leftchild(AST[child])].s);
        } else {
          if (disp&this) {
            fprintf(stdout, " [%d]", AST[child]);
          } else {
            fprintf(stdout, " %d", AST[child]);
          }
        }
        this = this >> 1;
        child += 1;
      }
    }
    if (TYPEINFO(ap) != -1) {
      fprintf(stdout, "  [[typeinfo=%d]]\n", TYPEINFO(ap));
    } else {
      fprintf(stdout, "\n");
    }  
    ap = ap + 2 + AST[ap+1] + RESERVE_FOR_TYPE_INFO;
    if (ap >= nexttrip) break;
  }
  fprintf(stdout, "-----------------\n");
}

void show_ast(int ap, int depth, int comefrom)
{
  int oper = AST[ap];
  int count = AST[ap+1];
  int child = ap+2;
  int disp;
  int this;

  if (ap == -1) {
    /*fprintf(stdout, "show_ast(-1);\n");*/ return;
  }

  if ((oper < AST_BASE) || (oper > AST_TOP)) {
    fprintf(stderr, "%4d: oper = %d,  count = %d,  Children = %d (came from %4d:)\n",
	    ap, oper, count, op[oper-AST_BASE].Children, comefrom);
    exit(1);
  }

#ifdef NEVER
  while (astop(ap) == AST_REDIRECT) {
    fprintf(stderr, "Redirect from %d to %d\n", ap, leftchild(ap));
    ap = leftchild(ap);
  }
  oper = AST[ap];
  count = AST[ap+1];
  child = ap+2;
#endif

  if ((oper != AST_REDIRECT) && (count != op[oper-AST_BASE].Children)) {
    fprintf(stderr, "%4d: oper = %d (%s),  count = %d,  Children = %d (came from %4d:)\n",
	    ap, oper, op[oper-AST_BASE].Diag_Name, count, op[oper-AST_BASE].Children, comefrom);
    fflush(stderr);
    assert(count == op[oper-AST_BASE].Children);
  }

  switch (oper) {
  case AST_REDIRECT:
    fprintf(stdout, "%4d: %s %d\n", ap, op[oper-AST_BASE].Diag_Name, AST[ap+2]);
    break;

  case AST_TAG:
    fprintf(stdout, "%4d: %s \"%s\"  [[typeinfo=%d]]\n", ap, op[oper-AST_BASE].Diag_Name, c[AST[ap+2]].s, TYPEINFO(ap));
    //if (TYPEINFO(ap) != -1) {
    //  show_ast(TYPEINFO(ap),depth+1,comefrom);
    //}
    break;

  case AST_Var:
    fprintf(stdout, "%4d: %s %s %d\n", ap, op[oper-AST_BASE].Diag_Name, c[AST[ap+2]].s, AST[ap+3]);
    break;

  case AST_Const:
    fprintf(stdout, "%4d: %s %s\n", ap, op[oper-AST_BASE].Diag_Name, escape(c[AST[ap+2]].s, c[AST[ap+2]].t));
    break;

  default:
    if ((oper < AST_BASE) || (oper > AST_TOP)) {
      fprintf(stderr, "* WARNING: show_ast oper=%d branched via 'default:' - add a case for it.\n", oper);
    } else {
      fprintf(stderr, "* WARNING: show_ast oper=%s branched via 'default:' - add a case for it.\n", op[oper-AST_BASE].Diag_Name);
    }    
    exit(0);

  case AST_Add: ;
  case AST_Sub: ;
  case AST_Mul: ;
  case AST_Div: ;
  case AST_Mod: ;
  case AST_AddAss: ;
  case AST_SubAss: ;
  case AST_MulAss: ;
  case AST_DivAss: ;
  case AST_ModAss: ;
  case AST_Post_Inc: ;
  case AST_Pre_Inc: ;
  case AST_Post_Dec: ;
  case AST_Pre_Dec: ;
  case AST_Idx: ;
  case AST_Member: ;
  case AST_Ptr: ;
  case AST_Call: ;
  case AST_Cond: ;
  case AST_Type: ;
  case AST_Return: ;
  case AST_ReturnResult: ;
  case AST_LE: ;
  case AST_GT: ;
  case AST_LT: ;
  case AST_GE: ;
  case AST_EQ: ;
  case AST_NE: ;
  case AST_IFTHENELSE: ;
  case AST_IFTHEN: ;
  case AST_Switch: ;
  case AST_UNeg: ;
  case AST_UPos: ;
  case AST_UBitNot: ;
  case AST_UBoolNot: ;
  case AST_BoolAnd: ;
  case AST_BoolOr: ;
  case AST_ShortcutBoolAnd: ;
  case AST_ShortcutBoolOr: ;
  case AST_BitAnd: ;
  case AST_BitOr: ;
  case AST_BitAndAss: ;
  case AST_BitOrAss: ;
  case AST_BitXor: ;
  case AST_BitXorAss: ;
  case AST_BitLsh: ;
  case AST_BitRsh: ;
  case AST_BitLshAss: ;
  case AST_BitRshAss: ;
  case AST_AssignTo: ;
  case AST_Declare: ;
  case AST_DefProc: ;
  case AST_DefParam: ;
  case AST_ReceiveParam: ;
  case AST_UseParam: ;
  case AST_AddressOf: ;
  case AST_IndirectThrough: ;
  case AST_C_ForLoop: ;
  case AST_C_While: ;
  case AST_C_DoWhile: ;
  case AST_C_Break: ;
  case AST_C_Continue: ;
  case AST_Cast: ;
  case AST_SizeOf: ;
  case AST_Case: ;
  case AST_DefaultCase: ;
  case AST_Label: ;
  case AST_Goto: ;
  case AST_Sourceline: ;
  case AST_LINENO: ;
  case AST_LINEAR_BLOB: ;
  case AST_SEQ: ;
  case AST_CommaSEQ: ;
  case AST_TYPE_ArrayOf: ; // child index lower upper
  case AST_TYPE_Struct: ; // structtypename childlinks structsize
  case AST_TYPE_PointerTo: ; // child
  case AST_TYPE_Atom: ; // signed bytesize
  case AST_TYPE_StructMember: ; // next_member this_element
  case AST_Scope: ;
  case AST_SHOWTREE: ;

    // May or may not need to include the AST_TYPE_* entries here?

    disp = op[oper-AST_BASE].Display_Children;
    fprintf(stdout, "%4d: %s", ap, op[oper-AST_BASE].Diag_Name);
    if (disp == 0) {
      fprintf(stdout, "\n");
      return;
    }
    this = 1<<(count-1);
    for (;;) {
      if (child == ap+2+count) break;
      //if (disp&this) fprintf(stdout, " %s", op[AST[AST[child]]-AST_BASE]);
      if (disp&this) fprintf(stdout, " [%d]", AST[child]); else fprintf(stdout, " %d", AST[child]);
      this = this >> 1;
      child += 1;
    }
    if (TYPEINFO(ap) != -1) {
      fprintf(stdout, "  [[typeinfo=%d]]\n", TYPEINFO(ap));
    } else {
      fprintf(stdout, "\n");
    }  
    this = 1<<(count-1);
    {
      child = ap+2;
      for (;;) {
        if (child == ap+2+count) break;
        if (disp&this)
	  if (astop(AST[child]) != AST_TYPE_Struct)
            show_ast(AST[child], depth+1, ap);
        this = this >> 1;
        child += 1;
      }
    }

    break;

  }
  fflush(stdout);
  return;
}

void show_one_ast(int ap, int depth, int comefrom)
{
  int oper = AST[ap];
  int count = AST[ap+1];
  int child = ap+2;
  int disp;
  int this;

  if (ap == -1) {
    /*fprintf(stdout, "show_ast(-1);\n");*/ return;
  }

  if ((oper < AST_BASE) || (oper > AST_TOP)) {
    fprintf(stderr, "%4d: oper = %d,  count = %d,  Children = %d (came from %4d:)\n",
	    ap, oper, count, op[oper-AST_BASE].Children, comefrom);
    exit(1);
  }

#ifdef NEVER
  while (astop(ap) == AST_REDIRECT) {
    fprintf(stderr, "Redirect from %d to %d\n", ap, leftchild(ap));
    ap = leftchild(ap);
  }
  oper = AST[ap];
  count = AST[ap+1];
  child = ap+2;
#endif

  if (count != op[oper-AST_BASE].Children) {
    fprintf(stderr, "%4d: oper = %d (%s),  count = %d,  Children = %d (came from %4d:)\n",
	    ap, oper, op[oper-AST_BASE].Diag_Name, count, op[oper-AST_BASE].Children, comefrom);
    fflush(stderr);
    assert(count == op[oper-AST_BASE].Children);
  }

  switch (oper) {
  case AST_TAG:
    fprintf(stdout, "%4d: %s \"%s\"  [[typeinfo=%d]]\n", ap, op[oper-AST_BASE].Diag_Name, c[AST[ap+2]].s, TYPEINFO(ap));
    break;

  case AST_Var:
    fprintf(stdout, "%4d: %s %s %d\n", ap, op[oper-AST_BASE].Diag_Name, c[AST[ap+2]].s, AST[ap+3]);
    break;

  case AST_Const:
    fprintf(stdout, "%4d: %s %s\n", ap, op[oper-AST_BASE].Diag_Name, escape(c[AST[ap+2]].s, c[AST[ap+2]].t));
    break;

  default:
    if ((oper < AST_BASE) || (oper > AST_TOP)) {
      fprintf(stderr, "* WARNING: show_one_ast oper=%d branched via 'default:' - add a case for it.\n", oper);
    } else {
      fprintf(stderr, "* WARNING: show_one_ast oper=%s branched via 'default:' - add a case for it.\n", op[oper-AST_BASE].Diag_Name);
    }    
    exit(0);

  case AST_Add: ;
  case AST_Sub: ;
  case AST_Mul: ;
  case AST_Div: ;
  case AST_Mod: ;
  case AST_AddAss: ;
  case AST_SubAss: ;
  case AST_MulAss: ;
  case AST_DivAss: ;
  case AST_ModAss: ;
  case AST_Post_Inc: ;
  case AST_Pre_Inc: ;
  case AST_Post_Dec: ;
  case AST_Pre_Dec: ;
  case AST_Idx: ;
  case AST_Member: ;
  case AST_Ptr: ;
  case AST_Call: ;
  case AST_Cond: ;
  case AST_Type: ;
  case AST_Return: ;
  case AST_ReturnResult: ;
  case AST_LE: ;
  case AST_GT: ;
  case AST_LT: ;
  case AST_GE: ;
  case AST_EQ: ;
  case AST_NE: ;
  case AST_IFTHENELSE: ;
  case AST_IFTHEN: ;
  case AST_Switch: ;
  case AST_UNeg: ;
  case AST_UPos: ;
  case AST_UBitNot: ;
  case AST_UBoolNot: ;
  case AST_BoolAnd: ;
  case AST_BoolOr: ;
  case AST_ShortcutBoolAnd: ;
  case AST_ShortcutBoolOr: ;
  case AST_BitAnd: ;
  case AST_BitOr: ;
  case AST_BitAndAss: ;
  case AST_BitOrAss: ;
  case AST_BitXor: ;
  case AST_BitXorAss: ;
  case AST_BitLsh: ;
  case AST_BitRsh: ;
  case AST_BitLshAss: ;
  case AST_BitRshAss: ;
  case AST_AssignTo: ;
  case AST_Declare: ;
  case AST_DefProc: ;
  case AST_DefParam: ;
  case AST_ReceiveParam: ;
  case AST_UseParam: ;
  case AST_AddressOf: ;
  case AST_IndirectThrough: ;
  case AST_C_ForLoop: ;
  case AST_C_While: ;
  case AST_C_DoWhile: ;
  case AST_C_Break: ;
  case AST_C_Continue: ;
  case AST_Cast: ;
  case AST_SizeOf: ;
  case AST_Case: ;
  case AST_DefaultCase: ;
  case AST_Label: ;
  case AST_Goto: ;
  case AST_Sourceline: ;
  case AST_LINENO: ;
  case AST_REDIRECT: ;
  case AST_LINEAR_BLOB: ;
  case AST_SEQ: ;
  case AST_CommaSEQ: ;
  case AST_TYPE_ArrayOf: ; // child index lower upper
  case AST_TYPE_Struct: ; // structtypename childlinks structsize
  case AST_TYPE_PointerTo: ; // child
  case AST_TYPE_Atom: ; // signed bytesize
  case AST_TYPE_StructMember: ; // next_member this_element
  case AST_Scope: ;

    // May or may not need to include the AST_TYPE_* entries here?

    disp = op[oper-AST_BASE].Display_Children;
    fprintf(stdout, "%4d: %s", ap, op[oper-AST_BASE].Diag_Name);
    if (disp == 0) {
      fprintf(stdout, "\n");
      return;
    }
    this = 1<<(count-1);
    for (;;) {
      if (child == ap+2+count) break;
      //if (disp&this) fprintf(stdout, " %s", op[AST[AST[child]]-AST_BASE]);
      if (disp&this) fprintf(stdout, " [%d]", AST[child]); else fprintf(stdout, " %d", AST[child]);
      this = this >> 1;
      child += 1;
    }
    if (TYPEINFO(ap) != -1) {
      fprintf(stdout, "  [[typeinfo=%d]]\n", TYPEINFO(ap));
    } else {
      fprintf(stdout, "\n");
    }  

    break;

  }
  fflush(stdout);
  return;
}
