char *makelower(char *s)
{
  char *copy;
  char *p;
  copy = p = strdup(s); /* heap lossage */
  while (*p != '\0') {
    if (isalpha(*p) && isupper(*p)) *p = tolower(*p);
    p += 1;
  }
  return copy;
}

void localtag(char *result, int tagnum, char *name)
{
  if (name == NULL) {
    sprintf(result+strlen(result), "V_%04x_ERROR", tagnum);
    return;
  }
  if (opt_safenames) {
    sprintf(result+strlen(result), "V_%04x_%s", tagnum, name);
  } else {
    sprintf(result+strlen(result), "%s", makelower(name)); /* HEAP LOSSAGE */
                   /* better to make lower in the DEF call! */
  }
}



/* RAWTAG is the debug version that fully decodes a tag.  (But *only* a tag) */
char *rawtag(int tagnum)
{
  int a, b, c, t, f, u, i, s, x;
  char *name;
  static char result[1024]; /* hacky */

  if (tagnum < 0) {
    return "{**COMPLEX OP**}"; /* for now */
  }

  /* See http://www.gtoal.com/athome/edinburgh/imp/imp77/icode.html#define */

  name = (char *)tag[tagnum].data; /* Don't know if this is valid yet */
  a = tag[tagnum].a;
  b = tag[tagnum].b;
  c = tag[tagnum].c;

  *result = '\0';

  t = a>>4; f = a&15;
  x = c&7;  c >>= 3;
  s = c&1; c >>= 1;
  i = c&1;  c >>= 1;
  u = c&1;

  sprintf(result, "/*t=%d f=%d x=%d s=%d i=%d u=%d*/",t,f,x,s,i,u);


  switch(x) {
  case 0: break;
  case 1: strcat(result, "%own "); break;
  case 2: strcat(result, "%constant "); break;
  case 3: strcat(result, "%external "); break;
  case 4: strcat(result, "%system "); break;
  case 5: strcat(result, "%dynamic "); break;
  case 6: strcat(result, "%prim "); break;
  case 7: strcat(result, "%perm "); break;
  }
  switch (t&15) {
  case 0:  break;
  case 1:  
           switch (b) {
           case 1: break;
           case 2: strcat(result, "%byte "); break;
           case 3: strcat(result, "%short/*A*/ "); break;
           default: strcat(result, "{error} "); break;
           }
           strcat(result, "%integer ");
           break;
  case 2:  
           switch (b) {
           case 1: break;
           case 4: strcat(result, "%long "); break;
           default: strcat(result, "{error} "); break;
           }
           strcat(result, "%real ");
           break;
  case 3:  sprintf(result+strlen(result), "%%string (%d) ", b); break;
  case 4:  sprintf(result+strlen(result), "%%record {%s} ", (char *)tag[b].data); break;
  case 5:  strcat(result, "%boolean "); break;
  case 6:  strcat(result, "set\n"); break;
  case 7:  sprintf(result+strlen(result), "8-bit-enumerated format <tag=%d>\n", b); break;
  case 8:  sprintf(result+strlen(result), "16-bit-enumerated format <tag=%d>\n", b); break;
  case 9:  strcat(result, "%name "); break;
  case 10: strcat(result, "%char "); break;
  default: strcat(result, "{undefined} "); break;
  }
  switch (f) {
  case 0: strcat(result, "{void} "); break;
  case 1: break;
  case 2: strcat(result, "%name "); break;
  case 3: strcat(result, "%label "); break;
  case 4: strcat(result, "%format "); break;
  case 5: strcat(result, "{undefined} "); break;
  case 6: strcat(result, "%switch/*a*/ "); break;
  case 7: strcat(result, "%routine "); break;
  case 8: strcat(result, "%function "); break;
  case 9: strcat(result, "%map "); break;
  case 10: strcat(result, "%predicate "); break;
  case 11: strcat(result, "%array "); break;
  case 12: strcat(result, "%arrayname "); break;
  case 13: strcat(result, "%namearray "); break;
  case 14: strcat(result, "%namearrayname "); break;

  case 15: strcat(result, "{undefined} "); break;
  }
  switch (s) {
  case 0: break;
  case 1: strcat(result, "%spec "); break;  
  }

  if ((x == 2) && (f == 1)) {
    sprintf(result+strlen(result), "%d {tag %04x} ", tag[tagnum].data, tagnum);
  } else {
    sprintf(result+strlen(result), "%s {tag %04x} ", name, tagnum);
  }

  switch (i) {
    /* An indirect object (I=1) differs  from  F=2  in
       that F=2 implies that the actual object created
       will  be  a  pointer  and  will be dereferenced
       whenever used unless explicit action  is  taken
       (e.g.  use  of  Assign-Reference).   If  I=1  a
       pointer will be created (usually as an integer)
       and will be treated as an integer (or  address)
       with no automatic dereferencing taking place.
    */
  case 0: break;
  case 1: /*strcat(result, "{ind obj} "); */ break;  
  }
/*
  switch (u) {
  case 0: memprintf("{no unass check} "); break;
  case 1: memprintf("{unass check} "); break;
  }
 */
result[1023] = '\0';
  return strdup(result); /* SHOULD BE: caller copies if needed */
}

char *rawcell(int celltag) /* para must be positive */
{
  char result[1024];
  int op, opdcount;
  if (celltag < 0) {
    memprintf("/*be careful with the signs there buddy -rawcell(%d)*/\n", celltag);
    celltag = -celltag;
  }
  op = code[celltag].op;
  opdcount = code[celltag].opdcount_or_tag;
  sprintf(result, "{code[%d].op=%c,.count/tag=%d}", celltag, op, opdcount);
  return strdup(result);
}

/* cdecl generates a C version of declarations */

char *cdecl(int tagnum)
{
  int a, b, c, t, f, u, i, s, x;
  char *name;
  static char result[1024]; /* hacky */

  if (tagnum < 0) {
    return "{**COMPLEX OP**}"; /* for now */
  }

  /* See http://www.gtoal.com/athome/edinburgh/imp/imp77/icode.html#define */

  name = (char *)tag[tagnum].data; /* Don't know if this is valid yet */
  a = tag[tagnum].a;
  b = tag[tagnum].b;
  c = tag[tagnum].c;

  *result = '\0';

  t = a>>4; f = a&15;
  x = c&7;  c >>= 3;
  s = c&1; c >>= 1;
  i = c&1;  c >>= 1;
  u = c&1;

//if (debug_input) memprintf("/*t=%d f=%d x=%d s=%d i=%d u=%d b=%d c=%d*/",t,f,x,s,i,u,b,c);

  switch(x) {
  case 0: break;
  case 1: strcat(result, "static "); break;
  case 2: strcat(result, "const "); break;
  case 3: {
            /* TODO - if s == 1, then this is a forward declaration
               and should be followed by ';' after the parameter list,
               otherwise should be followed by "{" preceding the actual
               code */
            strcat(result, "extern "); break;
          }
  case 4: strcat(result, "%system "); break;
  case 5: strcat(result, "%dynamic "); break;
  case 6: strcat(result, "extern "); break; /* prim */
  case 7: strcat(result, "extern "); break; /* perm */
  }
  switch (t&15) {
  case 0: if (f == 2) sprintf(result+strlen(result), "int typeof_%s, void ", name); /*HACK*/
          break;
  case 1:  
           switch (b) {
           case 1: strcat(result, "int "); break;
           case 2: strcat(result, "char "); break;
           case 3: strcat(result, "short "); break;
           default: strcat(result, "{error} "); break;
           }
           break;
  case 2:  
           switch (b) {
           case 1: break;
           case 4: strcat(result, "long "); break;
           default: strcat(result, "{error} "); break;
           }
           strcat(result, "real ");
           break;
  case 3:  sprintf(result+strlen(result), "char *"/* maxlen =  b+1*/); break;
  case 4:  {
             if (f == 4) {
               strcat(result, "typedef ");/* and append type after the members */
               RECORDFORMAT = TRUE;
             }
             sprintf(result+strlen(result),
               "struct %s ", (char *)tag[b].data);
             if (f == 2) {
               if ((t&15) == 4 /* pointer */) {
                 sprintf(result+strlen(result), "*");
               }
             } else if (f == 11) {
               /* only if array */
               sprintf(result+strlen(result), "*"); /* array mapped to pointer */
             } else {
               /* YYY3 */
             }
             if ((x == 2) && (t == 1) && (f == 1)) {
               sprintf(result+strlen(result), "%d {ERROR?}", tag[tagnum].data);
             } else {
               /* ***NOT*** if external etc.  only for locals */
               localtag(result, tagnum, name);
             }
             /* for the momeny include all of the 'f' code.  remove once tested */
             switch (f) {
             case 0: strcat(result, "/*void1*/ "); break;
             case 1: break;
             case 2: 
                     if ((t&15) != 4) strcat(result, " * /*QQQ*/ ");
                     break; /* eg %integername fred -> int *fred */
             case 3: strcat(result, "label "); break;
             case 4: strcat(result, ""); break; /* moved to before the name above */
             case 5: strcat(result, "{undefined} "); break;
             case 6: strcat(result, "%switch/*0*/ "); break;
             case 7: strcat(result, "void "); break;
             case 8: strcat(result, " "); break;
             case 9: strcat(result, " "); break;
             case 10: strcat(result, "int "); break;
             case 11: if ((t&15) != 4) strcat(result, " * /*WWW*/ "); break; /* int array decl */
             case 12: strcat(result, "* /*12*/ "); break;
             case 13: strcat(result, "*[] /*13*/ "); break;
             case 14: strcat(result, "**[] /*14*/ "); break;
             case 15: strcat(result, "{undefined} "); break;
             }
//             sprintf(result+strlen(result),
//               " %s ", (char *)tag[b].data);
             return(strdup(result));
           }
  case 5:  strcat(result, "%boolean "); break;
  case 6:  strcat(result, "set\n"); break;
  case 7:  sprintf(result+strlen(result), "8-bit-enumerated format <tag=%d>\n", b); break;
  case 8:  sprintf(result+strlen(result), "16-bit-enumerated format <tag=%d>\n", b); break;
  case 9:  strcat(result, "* /*%name2*/"); break;
  case 10: strcat(result, "%char "); break;
  default: strcat(result, "{undefined} "); break;
  }
  switch (f) {
  case 0: strcat(result, "/*void1*/ "); break;
  case 1: break;
  case 2: strcat(result, " *"); break; /* eg %integername fred -> int *fred */
  case 3: strcat(result, "label "); break;
  case 4: strcat(result, "%format "); break;
  case 5: strcat(result, "{undefined} "); break;
  /* http://docs.freebsd.org/info/gcc/gcc.info.Labels_as_Values.html */
  case 6: strcat(result, "/*todo: gcc jump table extension*/ void **"); break;
  case 7: strcat(result, "void "); break;
  case 8: strcat(result, " "); break;
  case 9: strcat(result, " *"); break; /* %map */
  case 10: strcat(result, "int "); break;
  case 11: sprintf(result+strlen(result), " *"); break;  /* array mapped to pointer */
  case 12: strcat(result, "* /*12*/ "); break;
  case 13: strcat(result, "*[] /*13*/ "); break;
  case 14: strcat(result, "**[] /*14*/ "); break;
  case 15: strcat(result, "{undefined} "); break;
  }

  if (f < 7 || f > 10) switch (s) {
  case 0: break;
  case 1: {
            strcat(result, "/*spec*/ "); break;  
          }
  } else if (s == 1) SPEC = TRUE;


  if ((x == 2) && (t == 1) && (f == 1)) {
    sprintf(result+strlen(result), "%d {ERROR?}", tag[tagnum].data);
  } else {
    /* ***NOT*** if external etc.  only for locals */
    localtag(result, tagnum, name);
  }

  switch (i) {
    /* An indirect object (I=1) differs  from  F=2  in
       that F=2 implies that the actual object created
       will  be  a  pointer  and  will be dereferenced
       whenever used unless explicit action  is  taken
       (e.g.  use  of  Assign-Reference).   If  I=1  a
       pointer will be created (usually as an integer)
       and will be treated as an integer (or  address)
       with no automatic dereferencing taking place.
    */
  case 0: break;
  case 1: /*strcat(result, "{ind obj} "); */ break;  
  }
/*
  switch (u) {
  case 0: memprintf("{no unass check} "); break;
  case 1: memprintf("{unass check} "); break;
  }
 */
  return strdup(result); /* heap lossage */ /* SHOULD BE: caller copies if needed */
}

/* this is meant to be the short version that gets the value of a tag
   into a string; however any cases not yet handled still have the
   full debugging text present, so that I don't overlook them if they're
   invoked.  Final code should throw most of this away */
void appendchar(char *s, int c)
{
  int l = strlen(s);
  s[l] = c; s[l+1] = '\0';
}

char *tag_rhs_value(int tagnum)
{
  int a, b, c, t, f, u, i, s, x;
  char *name;
  static char result[1024]; /* hacky */

  /* See http://www.gtoal.com/athome/edinburgh/imp/imp77/icode.html#define */
  *result = '\0';

  name = (char *)tag[tagnum].data; /* Don't know if this is valid yet */
  a = tag[tagnum].a;
  b = tag[tagnum].b;
  c = tag[tagnum].c;

  t = a>>4; f = a&15;
  x = c&7;  c >>= 3;
  s = c&1; c >>= 1;
  i = c&1;  c >>= 1;
  u = c&1;

  if (tagnum < 0) {
    sprintf(result, "%s", evalexpr(tagnum));
    return strdup(result); /* heap lossage */
  }

  switch (t&15) {
  case 3:  if ((x == 2) && (b < 0 /* length=-1 for internal consts */)) {
             int i;
             char *s = (char *)tag[tagnum].data;
             /* ONLY IF CONST??? */
             assert(s != NULL);
             appendchar(result, '"');
             for (i = 1; i <= *s; i++) {
               if (s[i] == '"') appendchar(result, '\\');
               if (s[i] == '\\') appendchar(result, '\\');
               appendchar(result, s[i]);
             }
             appendchar(result, '"');
             /*break;*/
             return strdup(result); /* no more to do? */
           } else {
             localtag(result, tagnum, name);
//             sprintf(result, "***STRING VAR t=%d f=%d x=%d s=%d ***",
//                              t,f,x,s);
             return(strdup(result));
           }
  case 4:  /* record format */; break;
  default: break;
  }
  switch (f) {
  case 0: strcat(result, "{void} "); break;
  case 1: break;
  case 2: {
            /* TODO: if we have a recordname parameter and we access
               a field of the record in a procedure, this code currently
               generates *v.f rather than v->f  - this is bad C although
               I suspect probably allowed under the gcc extensions */
            strcat(result, "*"); /* imp's auto deref of pointers */
            break;
          }
  case 3: strcat(result, "%label "); break;
  case 4: strcat(result, "%format "); break;
  case 5: strcat(result, "{undefined} "); break;
  case 6: break; /* %switch */
  case 7: break;
  case 8: break;
  case 9: strcat(result, "*"); break; /* map */
  case 10: break;
  case 11: break;
  case 12: break;
  case 13: strcat(result, "%namearray "); break;
  case 14: strcat(result, "%namearrayname "); break;
  case 15: strcat(result, "{undefined} "); break;
  }

  if ((x == 2) && (f == 1)) {
    sprintf(result+strlen(result), "%d", tag[tagnum].data);
  } else {
    /* ***NOT*** if external etc.  only for locals */
    localtag(result, tagnum, name);
  }

  return strdup(result); /* heap lossage */  /* SHOULD BE: caller copies if needed */
}

char *tag_lhs_value(int tagnum)
{
  int a, b, c, t, f, u, i, s, x;
  char *name;
  static char result[1024]; /* hacky */

  *result = '\0';

  if (tagnum < 0) {
    sprintf(result, "%s", evalexpr(tagnum));
    return strdup(result);
  }

  /* See http://www.gtoal.com/athome/edinburgh/imp/imp77/icode.html#define */

  name = (char *)tag[tagnum].data; /* Don't know if this is valid yet */
  a = tag[tagnum].a;
  b = tag[tagnum].b;
  c = tag[tagnum].c;

  t = a>>4; f = a&15;
  x = c&7;  c >>= 3;
  s = c&1; c >>= 1;
  i = c&1;  c >>= 1;
  u = c&1;

  switch (t&15) {
  case 3:  // sprintf(result+strlen(result), "%%string/*1*/ (%d) ", b);
    sprintf(result+strlen(result), "?S%d;", b);
           break;
  case 4:  
//          sprintf(result+strlen(result), "/*LHSval*/%%record {%s} ", (char *)tag[b].data);
          sprintf(result+strlen(result),
            "?Rsizeof struct %s;", (char *)tag[b].data);
        break;
  default: break;
  }
  switch (f) {
  case 0: strcat(result, "{void} "); break;
  case 1: break;
  case 2: strcat(result, "*"); break; /* Imp's auto de-ref on storing to a ptr */
  case 3: strcat(result, "%label "); break;
  case 4: strcat(result, "%format "); break;
  case 5: strcat(result, "{undefined} "); break;
  case 6: strcat(result, "%switch/*c*/ "); break;
  case 7: strcat(result, "%routine "); break;
  case 8: strcat(result, "%function "); break;
  case 9: strcat(result, "%map "); break;
  case 10: strcat(result, "%predicate "); break;
  case 11: strcat(result, "%array "); break;
  case 12: strcat(result, "%arrayname "); break;
  case 13: strcat(result, "%namearray "); break;
  case 14: strcat(result, "%namearrayname "); break;
  case 15: strcat(result, "{undefined} "); break;
  }
  switch (s) {
  case 0: break;
  case 1: strcat(result, "%spec "); break;  
  }

  if ((x == 2) && (f == 1)) {
    sprintf(result+strlen(result), "%d", tag[tagnum].data);
  } else {
    /* ***NOT*** if external etc.  only for locals */
    localtag(result, tagnum, name);
  }

  switch (i) {
    /* An indirect object (I=1) differs  from  F=2  in
       that F=2 implies that the actual object created
       will  be  a  pointer  and  will be dereferenced
       whenever used unless explicit action  is  taken
       (e.g.  use  of  Assign-Reference).   If  I=1  a
       pointer will be created (usually as an integer)
       and will be treated as an integer (or  address)
       with no automatic dereferencing taking place.
    */
  case 0: break;
  case 1: /*strcat(result, "{ind obj} "); */ break;  
  }
/*
  switch (u) {
  case 0: memprintf("{no unass check} "); break;
  case 1: memprintf("{unass check} "); break;
  }
 */
  return strdup(result); /* heap lossage */  /* SHOULD BE: caller copies if needed */
}

char *tag_rhs_addr(int tagnum)
{
  int a, b, c, t, f, u, i, s, x;
  char *name;
  static char result[1024]; /* hacky */

  *result = '\0';

  if (tagnum < 0) {
    /* does this need "&" prepended to the result??? */
    sprintf(result, "&%s", evalexpr(tagnum));
    return strdup(result);
  }

  /* See http://www.gtoal.com/athome/edinburgh/imp/imp77/icode.html#define */

  name = (char *)tag[tagnum].data; /* Don't know if this is valid yet */
  a = tag[tagnum].a;
  b = tag[tagnum].b;
  c = tag[tagnum].c;

  result[0] = '&';
  result[1] = '\0';

  t = a>>4; f = a&15;
  x = c&7;  c >>= 3;
  s = c&1; c >>= 1;
  i = c&1;  c >>= 1;
  u = c&1;
  switch(x) {
  case 0: break; /* auto */
  case 1: break; /* %own */
  case 2: break; /* %constant */
  case 3: break; /* %external */
  case 4: break; /* %system */
  case 5: break; /* %dynamic */
  case 6: break; /* %prim */
  case 7: break; /* %perm */
   }
  switch (t&15) {
  case 0:  break;
  case 1:  
           switch (b) {
           case 1: break;
           case 2: /*strcat(result, "%byte ");*/ break;
           case 3: /*strcat(result, "%short ");*/ break;
           default: strcat(result, "{error} "); break;
           }
           break;
  case 2:  
           switch (b) {
           case 1: break;
           case 4: strcat(result, "%long "); break;
           default: strcat(result, "{error} "); break;
           }
           strcat(result, "%real ");
           break;
  case 3:  /*sprintf(result+strlen(result), "%%string (%d) ", b); */ break;
  case 4:  {
//              sprintf(result+strlen(result),
//                "%%record {%s} ", (char *)tag[b].data);
              break;
           }
  case 5:  strcat(result, "%boolean "); break;
  case 6:  strcat(result, "set\n"); break;
  case 7:  sprintf(result+strlen(result), "8-bit-enumerated format <tag=%d>\n", b); break;
  case 8:  sprintf(result+strlen(result), "16-bit-enumerated format <tag=%d>\n", b); break;
  case 9:  strcat(result, "%name{Y} "); break;
  case 10: strcat(result, "%char "); break;
  default: strcat(result, "{undefined} "); break;
  }
  switch (f) {
  case 0: strcat(result, "{void} "); break;
  case 1: break;
  case 2: {
            /* undo the '&' which took the address of what follows */
            *result = '\0';
          }
          break;
  case 3: strcat(result, "%label "); break;
  case 4: strcat(result, "%format "); break;
  case 5: strcat(result, "{undefined} "); break;
  case 6: strcat(result, "%switch/*d*/ "); break;
  case 7: strcat(result, "%routine "); break;
  case 8: strcat(result, "%function "); break;
  case 9: strcat(result, "%map "); break;
  case 10: strcat(result, "%predicate "); break;
  case 11: strcat(result, "%array "); break;
  case 12: strcat(result, "%arrayname "); break;
  case 13: strcat(result, "%namearray "); break;
  case 14: strcat(result, "%namearrayname "); break;
  case 15: strcat(result, "{undefined} "); break;
  }
  switch (s) {
  case 0: break;
  case 1: strcat(result, "%spec "); break;  
  }

  if ((x == 2) && (f == 1)) {
    sprintf(result+strlen(result), "%d", tag[tagnum].data);
  } else {
    /* ***NOT*** if external etc.  only for locals */
    localtag(result, tagnum, name);
  }

  switch (i) {
    /* An indirect object (I=1) differs  from  F=2  in
       that F=2 implies that the actual object created
       will  be  a  pointer  and  will be dereferenced
       whenever used unless explicit action  is  taken
       (e.g.  use  of  Assign-Reference).   If  I=1  a
       pointer will be created (usually as an integer)
       and will be treated as an integer (or  address)
       with no automatic dereferencing taking place.
    */
  case 0: break;
  case 1: /*strcat(result, "{ind obj} "); */ break;  
  }
/*
  switch (u) {
  case 0: memprintf("{no unass check} "); break;
  case 1: memprintf("{unass check} "); break;
  }
 */
  return strdup(result); /* SHOULD BE: caller copies if needed */
}

char *tag_lhs_addr(int tagnum)
{
  int a, b, c, t, f, u, i, s, x;
  char *name;
  static char result[1024]; /* hacky */

  *result = '\0';

  if (tagnum < 0) {

    /* it may not be wise to use evalexpr here.
       the only complex case should be a map call, and it needs
       to be handled specially anyway.  Also, still have to do stuff
       like:  byteinteger(cp) = 1   =>   *(char *)cp = 1;
     */
    return evalexpr(tagnum);
  }

  /* See http://www.gtoal.com/athome/edinburgh/imp/imp77/icode.html#define */

  name = (char *)tag[tagnum].data; /* Don't know if this is valid yet */
  a = tag[tagnum].a;
  b = tag[tagnum].b;
  c = tag[tagnum].c;

  t = a>>4; f = a&15;
  x = c&7;  c >>= 3;
  s = c&1; c >>= 1;
  i = c&1;  c >>= 1;
  u = c&1;

  switch (t&15) {
  case 3:  sprintf(result+strlen(result), "%%string/*3*/ (%d) ", b); break;
  case 4:  /*sprintf(result+strlen(result), "..LHSaddr..%%record {%s} ",
             (char *)tag[b].data);*/
           break;
  default: break;
  }

  switch (f) {
  case 0: strcat(result, "{void} "); break;
  case 1: break;
  case 2: strcat(result, ""); break; /* %name */
  case 3: strcat(result, "%label "); break;
  case 4: strcat(result, "%format "); break;
  case 5: strcat(result, "{undefined} "); break;
  case 6: strcat(result, "%switch/*d*/ "); break;
  case 7: strcat(result, "%routine "); break;
  case 8: strcat(result, "%function "); break;
  case 9: strcat(result, "%map "); break;
  case 10: strcat(result, "%predicate "); break;
  case 11: strcat(result, "%array "); break;
  case 12: strcat(result, "%arrayname "); break;
  case 13: strcat(result, "%namearray "); break;
  case 14: strcat(result, "%namearrayname "); break;
  case 15: strcat(result, "{undefined} "); break;
  }
  switch (s) {
  case 0: break;
  case 1: strcat(result, "%spec "); break;  
  }

  if ((x == 2) && (f == 1)) {
    sprintf(result+strlen(result), "%d", tag[tagnum].data);
  } else {
    /* ***NOT*** if external etc.  only for locals */
    localtag(result, tagnum, name);
  }

  switch (i) {
    /* An indirect object (I=1) differs  from  F=2  in
       that F=2 implies that the actual object created
       will  be  a  pointer  and  will be dereferenced
       whenever used unless explicit action  is  taken
       (e.g.  use  of  Assign-Reference).   If  I=1  a
       pointer will be created (usually as an integer)
       and will be treated as an integer (or  address)
       with no automatic dereferencing taking place.
    */
  case 0: break;
  case 1: /*strcat(result, "{ind obj} "); */ break;  
  }
/*
  switch (u) {
  case 0: memprintf("{no unass check} "); break;
  case 1: memprintf("{unass check} "); break;
  }
 */
  return strdup(result); /* SHOULD BE: caller copies if needed */
}