/*
** create debugfiles for StormC
*/

#include "stab.h"
#include "stormdebug.h"
#include <clib/alib_protos.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/iffparse.h>
#include <libraries/iffparse.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>

#define ID_SDBG 0x53444247
#define ID_STRG 0x53545247
#define ID_TYPE 0x54595045
#define ID_ILST 0x494c5354
#define ID_ENUM 0x454e554d
#define ID_SCOP 0x53434f50
#define ID_SRCS 0x53524353
#define ID_POSN 0x504f534e

#define FIRSTSTRINGINDEX 16
#define FIRSTSOURCEINDEX 1
#define FIRSTPOSITIONINDEX 1
#define FIRSTSCOPEINDEX 1
#define FIRSTSNODEINDEX 1
#define FIRSTSENUMINDEX 1
#define FIRSTTYPEINDEX 128

#define TAG_VOID                     1
#define TAG_UBYTE                    2
#define TAG_BYTE                     3
#define TAG_UWORD                    4
#define TAG_WORD                     5
#define TAG_ULONG                    6
#define TAG_LONG                     7
#define TAG_ULONGLONG                8
#define TAG_LONGLONG                 9
#define TAG_FLOAT                   10 /* FFP in C unbekannt */
#define TAG_SINGLE                  11 /* 32 IEEE */
#define TAG_DOUBLE                  12 /* 64 IEEE */
#define TAG_EXTENDED                13 /* 96 IEEE (von StormC nicht benutzt) */
#define TAG_CHAR                    16
#define TAG_WCHAR                   17 /* 16 bit char in C unbekannt */
#define TAG_LCHAR                   18 /* 32 bit char in C unbekannt */
#define TAG_SBOOL                   19 /*  8 bit BOOL in C ubekannt */
#define TAG_BOOL                    20 /* 16 bit BOOL in C unbekannt */
#define TAG_LBOOL                   21 /* 32 bit BOOL in C unbekannt */
#define TAG_ELLIPSE                 31 /* ... */
#define TAG_POINTER                 32
#define TAG_REFERENCE               33
#define TAG_BPTR                    34 /* BCPL Pointer in C unbekannt */
#define TAG_ENUM                    40
#define TAG_ARRAY                   41
#define TAG_SUBRANGE                42
#define TAG_SET                     43 /* Mengen in C unbekannt */
#define TAG_PASCALSTR               44 /* Pascal String in C unbekannt */
#define TAG_FUNCTION                45
#define TAG_CLASS                   50
#define TAG_STRUCT                  50
#define TAG_STRUCTORUNION           50
#define TAG_UNION                   50
#define TAG_RECORD                  50
#define TAG_VMT                     51
#define TAG_VOLATILECONST           70 /* qualifiziert volatile und const */
#define TAG_TYPEDEF                 80

struct string
{
    char str[1];  /* dynamically extended to fit for the string. */
};

struct source
{
    UWORD pathIndex;
    UWORD nameIndex;
    ULONG lastChange;          /* unused, set to 0 */
    UBYTE sourceLanguageIndex; /* unused, set to 0 */
    UBYTE compilerNameIndex;   /* unused, set to 0 */
};

struct position
{
    int sourceIndex;
    int lineNo;
    int hunkNo; /* currently 0? */
    unsigned int hunkOffset;
};

struct type
{
    int typeNo;
    int nameIndex;
    union {
        UBYTE tag;    /* Die Typnummer TAG_BYTE, TAG_WORD etc */
        struct {       /* Pointer */
            UBYTE tag;
            UBYTE zero;
            UWORD type; /* Der Index des Typs auf den der Pointer zeigt. */
        } pointer;
        struct {       /* Referenz (identisch zu Pointer) */
            UBYTE tag;
            UBYTE zero;
            UWORD type; /* Der Index des Typs auf den die Referenz zeigt. */
        } reference;
        struct {       /* BPTR wird nicht benutzt. */
            UBYTE tag;
            UBYTE zero;
            UWORD type; /* der Index des Typs auf den der BCPL Pointer zeigt. */
        } bptr;
        struct {          /* Qualifier volatile und const */
            UBYTE tag;
            UBYTE what;    /* Bit 0: const, Bit 1: volatile */
            UWORD type;    /* Der Index des Typs der const oder volatile ist */
        } volatileconst;
        struct {          /* Aufzähltyp */
            UBYTE tag;
            UBYTE type;    /* Der Index des Basistyps, z.B. TAG_BYTE, TAG_LONG etc */
            UWORD name;    /* Index des Namens des Aufzähltyps */
        } enumeration;
        struct {          /* Pointer auf die Virtual Member Table */
            UBYTE tag;
            UBYTE zero;
            UWORD count;  /* Anzahl der Einträge */
        } vmt;
        struct {            /* Arraytyp */
            UBYTE tag;
            UBYTE zero;
            UWORD indexType; /* der Index des IndexTyps, z.B. TAG_BYTE oder TAG_SUBRANGE */
            UWORD elemType;  /* der Index des Typs der Feldelemente */
            ULONG elemSize;  /* Größe eines Eintrags (kann größer als Feldelementgröße sein) */
                             /* 0: entspricht Größe des elemType */
        } array;
        struct {            /* Teilbereichstyp */
            UBYTE tag;
            UBYTE type;      /* Index des Basistyps des Bereichs, z.B. TAG_BYTE, TAG_LONG etc */
            LONG low;        /* untere Grenze (kleinster Wert) */
            ULONG high;      /* obere Grenze (größter Wert) */
        } subrange;
        struct {            /* Mengentyp (nicht benutzt) */
            UBYTE tag;
            UBYTE zero;
            UWORD indexType;
            LONG low;
            UWORD count;
        } set;
        struct {            /* Pascalstring (nicht benutzt) */
            UBYTE tag;
            UBYTE size;
        } pascalstr;
        struct {               /* Funktionstyp */
            UBYTE tag;
            UBYTE resultPlace;  /* Ergebnisort: 0: void, 1: d0, 2: a0, 3: fp0, */
                                /*              4: $8(a5) enthält Pointer auf Ergebnis, */
                                /*              254: Konstruktor, 255: Destruktor */
            UWORD resultType;   /* Ergebnistyp */
            UWORD argList;      /* Index der Argumentenliste */
            UWORD classType;    /* Der Index des Klassentyps, falls eine Memberfunktion vorliegt */
            UBYTE stack;        /* Stackbenutzung (unused): */
            UBYTE what;         /* Sichtbarkeit (unused): Bit 0: virtual, */
                                /*               Bit 1: protected, Bit 2: private */
        } function;
        struct {               /* Klassen-/Struktur-/Unionstyp */
            UBYTE tag;
            UBYTE what;         /* Art: 0: struct, 1: class, 2: union */
            UWORD name;         /* Index des Namens */
            ULONG size;         /* Größe in Bytes */
            UWORD memberList;   /* Index der Memberliste */
        } classinfo;
        struct {
            UBYTE tag;
            UBYTE zero;
            UWORD type;          /* Typ, mit dem der Typedef-Name belegt ist */
            UWORD name;          /* Stringnummer des Typedef-Namens */
        } typedefinfo;
    } spec;
};

struct snode
{
    UWORD nextIndex;    /* Index des nächsten Elements */
    UWORD nameIndex;    /* Index des Namens des Elements */
    UWORD typeIndex;    /* Index des Typs des Elements */
    ULONG codeStart;    /* Codeposition des Elements */
    ULONG sourceStart;  /* Sourceposition des Elements */
    union {
        struct {
            UWORD codeLen;  /* Sichtbarkeit der Var, 0 = bis Scopeende, sonst */
                            /* Abstand zu CodeStart */
        } var;
        struct {
            UWORD scope;        /* Index des Scopes des Element */
            UWORD posnIndex;    /* Index in das Positionsarray für schnelle Zugriffe */
            UWORD codeSize;     /* Größe des Elements (nur bei Funktionen) */
        } func;
    } spec;
};

struct senum
{
    UWORD nameIndex;    /* Index des Namens der Konstante */
    UWORD typeIndex;    /* Index des Enum-Typs, der zu dieser Konstante gehört */
    LONG value;         /* Wert der Konstante */
};

struct scope
{
    UWORD parentIndex;  /* Der übergeordenete Scope (0 im Filescope) */
    UWORD objectsIndex; /* Der Index der Liste aller Objekte im Scope */
    ULONG sourceStart;  /* Sourceposition des Starts des Scopes */
    ULONG sourceEnd;    /* Sourceposition des Endes des Scopes */
};

#define NOSCOPE 0xffff


/*
** Dynamic Array
*/
struct Array
{
  void **elements;
  int next2last;
  int total;
};



void array_Init(struct Array *a)
{
  a->elements = NULL;
  a->next2last = 0;
  a->total = 0;
}


void array_Exit(struct Array *a)
{
  if(a->elements)
  {
    xfree(a->elements);
    a->elements = NULL;
  }
}


int array_GetNumElements(struct Array *a)
{
  return a->next2last;
}


void array_AddElement(struct Array *a, void *e)
{
  if(a->next2last >= a->total)
  {
    int nt = (a->total ? (a->total * 2) : 50);
    void **ne = (void**) xmalloc(nt * sizeof(void*));
    if (a->elements)
    {
      memcpy(ne, a->elements, a->total * sizeof(void*));
      xfree(a->elements);
    }
    a->elements = ne;
    a->total = nt;
  }

  a->elements[a->next2last] = e;
  a->next2last ++;
}


int array_GetIndex(struct Array *a, void *e)
{
  if(a->elements)
  {
    int i;
    for(i=0; i<a->next2last; i++)
    {
      if(a->elements[i] == e)  return i;
    }
  }
  return -1;
}


void *array_GetElement(struct Array *a, int index)
{
  if(a->elements  &&  index >= 0  &&  index < a->next2last)
    return a->elements[index];
  return NULL;
}




/*
** needed Data
*/
static char *stringbuffer = NULL;
static int strLen = 0;
static int bufLen = 0;

static struct Array stringArray;
static struct Array sourceArray;
static struct Array positionArray;
static struct Array scopeArray;
static struct Array snodeArray;
static struct Array senumArray;
static struct Array typeArray;
static int currentPathStringIndex = 0;
static int currentSourceIndex = 0;

static struct string *parseName(char **input);
static struct type *parseType(int typeNo, struct string *typeName, char **input);
static symbolS *createLists(symbolS *start_symbol, struct scope *currentScope, struct type **currentFunction);
static struct type *getTypeFromTypeIndex(int typeIndex);


/*
** get...()
*/
static int getTypeSize(struct type *t)
{
  struct type *t2;
  if(t)
  {
    switch(t->spec.tag)
    {
      case TAG_UBYTE:
      case TAG_BYTE:
      case TAG_CHAR:
      case TAG_SBOOL:
        return 1;

      case TAG_UWORD:
      case TAG_WORD:
      case TAG_WCHAR:
      case TAG_BOOL:
        return 2;

      case TAG_ULONG:
      case TAG_LONG:
      case TAG_FLOAT:
      case TAG_SINGLE:
      case TAG_LCHAR:
      case TAG_LBOOL:
      case TAG_POINTER:
      case TAG_BPTR:
        return 4;

      case TAG_ULONGLONG:
      case TAG_LONGLONG:
      case TAG_DOUBLE:
      case TAG_EXTENDED:
        return 8;

      case TAG_ARRAY:
        t2 = getTypeFromTypeIndex(t->spec.array.indexType);
        if(t2  &&  t2->spec.tag == TAG_SUBRANGE)
        {
          return ((t2->spec.subrange.high - t2->spec.subrange.low + 1) * t->spec.array.elemSize);
        }
        break;

      case TAG_STRUCT:
        return t->spec.classinfo.size;
    }
  }
  return 0;
}


static int getTypeIndexFromTypeNo(int typeNo)
{
  struct type *walk;
  int i;

  for(i=0; i<array_GetNumElements(&typeArray); i++)
  {
    walk = (struct type*) array_GetElement(&typeArray, i);
        if(walk->typeNo == typeNo)
          return i + FIRSTTYPEINDEX;
    }
  return 0;
}


static struct type *getTypeFromTypeNo(int typeNo)
{
  struct type *walk;
  int i;

  for(i=0; i<array_GetNumElements(&typeArray); i++)
  {
    walk = (struct type*) array_GetElement(&typeArray, i);
        if(walk->typeNo == typeNo) return walk;
    }
    return NULL;
}


static struct type *getTypeFromTypeIndex(int typeIndex)
{
  return (struct type*) array_GetElement(&typeArray, typeIndex - FIRSTTYPEINDEX);
}


static int getTypeIndex(struct type *t)
{
    return FIRSTTYPEINDEX + array_GetIndex(&typeArray, t);
}


static int getStringIndex(struct string *s)
{
    return FIRSTSTRINGINDEX + array_GetIndex(&stringArray, s);
}


static int getScopeIndex(struct scope *s)
{
    return FIRSTSCOPEINDEX + array_GetIndex(&scopeArray, s);
}


static struct scope *getScopeFromScopeIndex(int scopeIndex)
{
  return (struct scope*) array_GetElement(&scopeArray, scopeIndex - FIRSTSCOPEINDEX);
}


static int getSnodeIndex(struct snode *n)
{
    return FIRSTSNODEINDEX + array_GetIndex(&snodeArray, n);
}


static struct snode *getSnodeFromIndex(int index)
{
  return (struct snode*)array_GetElement(&snodeArray, index - FIRSTSNODEINDEX);
}


static struct position *getLatestPosition(void)
{
    return (struct position*)
      array_GetElement(&positionArray, array_GetNumElements(&positionArray) - 1);
}


static struct scope *getGlobalScope(void)
{
    return (struct scope*)array_GetElement(&scopeArray, 0);
}


/*
** new...()
*/
static struct string *newString(char *str)
{
    struct string *s;
    int i;

    for(i=0; i<array_GetNumElements(&stringArray); i++)
    {
      s = (struct string*) array_GetElement(&stringArray, i);
      if(strcmp(str, s->str) == 0)
        return s;
    }

  s = xmalloc(sizeof(struct string) + strlen(str));
  strcpy(s->str, str);
  array_AddElement(&stringArray, s);
    return s;
}

static struct source *newSource(int pathIndex, int nameIndex)
{
    struct source *s;
  int i;

  for(i=0; i<array_GetNumElements(&sourceArray); i++)
  {
    s = (struct source*) array_GetElement(&sourceArray, i);
        if(s->pathIndex == pathIndex
        && s->nameIndex == nameIndex)
          return s;
  }

    s = xmalloc(sizeof(struct source));
    s->pathIndex = pathIndex;
    s->nameIndex = nameIndex;
    s->lastChange = 0;
    s->sourceLanguageIndex = 0;
    s->compilerNameIndex = 0;
    array_AddElement(&sourceArray, s);
    return s;
}

static struct senum *newSenum(int nameIndex, int typeIndex, long value)
{
    struct senum *s = xmalloc(sizeof(struct senum));
    s->nameIndex = nameIndex;
    s->typeIndex = typeIndex;
    s->value     = value;
    array_AddElement(&senumArray, s);
    return s;
}

static struct position *newPosition(int sourceIndex, int lineNo, int hunkNumber, unsigned int hunkOffset)
{
    struct position *p = xmalloc(sizeof(struct position));
    p->sourceIndex = sourceIndex;
    p->lineNo      = lineNo;
    p->hunkNo      = hunkNumber < 0 ? 0 : hunkNumber;
    p->hunkOffset  = hunkOffset;
    array_AddElement(&positionArray, p);
    return p;
}

static struct type *newTypeBasic(int typeNo, struct string *sstrp, int tag)
{
    struct type *t = xmalloc(sizeof(struct type));
    t->typeNo    = typeNo;
    t->nameIndex = (sstrp ? getStringIndex(sstrp) : 0);
    t->spec.tag  = tag;
    array_AddElement(&typeArray, t);
    return t;
}

static struct type *newTypeTypedef(int typeNo, struct string *name, int refTypeNo)
{
    struct type *t = xmalloc(sizeof(struct type));
    t->typeNo    = typeNo;
    t->nameIndex = (name ? getStringIndex(name) : 0);
    t->spec.typedefinfo.tag  = TAG_TYPEDEF;
    t->spec.typedefinfo.zero = 0;
    t->spec.typedefinfo.type = getTypeIndexFromTypeNo(refTypeNo);
    t->spec.typedefinfo.name = (name ? getStringIndex(name) : 0);
    array_AddElement(&typeArray, t);
    return t;
}

static struct type *newTypePointer(int typeNo, int refTypeNo)
{
    struct type *t = xmalloc(sizeof(struct type));
    t->typeNo    = typeNo;
    t->nameIndex = 0;
    t->spec.pointer.tag  = TAG_POINTER;
    t->spec.pointer.zero = 0;
    t->spec.pointer.type = getTypeIndexFromTypeNo(refTypeNo);
    array_AddElement(&typeArray, t);
    return t;
}

static struct type *newTypeReference(int typeNo, int refTypeNo)
{
    struct type *t = xmalloc(sizeof(struct type));
    t->typeNo    = typeNo;
    t->nameIndex = 0;
    t->spec.reference.tag  = TAG_REFERENCE;
    t->spec.reference.zero = 0;
    t->spec.reference.type = getTypeIndexFromTypeNo(refTypeNo);
    array_AddElement(&typeArray, t);
    return t;
}


/*
** append...()
*/
static void appendMemberToClassInfo(struct type *t, struct snode *n)
{
  n->nextIndex = 0;
  if (!t->spec.classinfo.memberList)
  {
    t->spec.classinfo.memberList = getSnodeIndex(n);
  }
  else
  {
    struct snode *s;
    int i = t->spec.classinfo.memberList;
    while(1)
    {
      s = getSnodeFromIndex(i);
      if (!s)
      {
        printf("appendMemberToClassInfo(): index is out of snode-list.\n");
        return;
      }
      i = s->nextIndex;
      if (i == 0)
      {
        s->nextIndex = getSnodeIndex(n);
        return;
      }
    }
  }
}


static void appendArgToFunction(struct type *t, struct snode *n)
{
  n->nextIndex = 0;
  if (!t->spec.function.argList)
  {
    t->spec.function.argList = getSnodeIndex(n);
  }
  else
  {
    struct snode *s;
    int i = t->spec.function.argList;
    while(1)
    {
      s = getSnodeFromIndex(i);
      if (!s)
      {
        printf("appendArgToFunction(): index is out of snode-list.\n");
        return;
      }
      i = s->nextIndex;
      if (i == 0)
      {
        s->nextIndex = getSnodeIndex(n);
        return;
      }
    }
  }
}


static void appendSnodeToScope(struct scope *t, struct snode *n)
{
  if (!t->objectsIndex)
  {
    t->objectsIndex = getSnodeIndex(n);
  }
  else
  {
    struct snode *s;
    int i = t->objectsIndex;
    while(1)
    {
      s = getSnodeFromIndex(i);
      if (!s)
      {
        printf("appendSnodeToScope(): index is out of snode-list.\n");
        return;
      }
      i = s->nextIndex;
      if (i == 0)
      {
        s->nextIndex = getSnodeIndex(n);
        return;
      }
    }
  }
}




/*
** parse...()
*/
static struct string *parseName(char **input)
{
  int i = 0;
  char c, str [256];

  while (1)
  {
    c = **input;
    if (c == ':')
    {
      if(*((*input) + 1) == ':'  &&  isalpha(*((*input) + 2)))
      {
        str[i++] = c;
        (*input)++;
        c = **input;
        str[i++] = c;
        (*input)++;
        c = **input;
      }
      else
        break;
    }
    else if (c == ';'  ||  c == 0)
      break;

    str[i++] = c;
    (*input)++;
  }
  str[i] = 0;
  return newString(str);
}


static struct type *parseMethod(int typeNo, struct string *typeName, struct type *fromClass, char **input)
{
  /* typeNo is the number, this method should be assigned to.
  ** typeName holds the name for this new method. This maybe NULL.
  ** fromClass is the class this method belongs to.
  ** input is the pointer description-string after the type number. */
  struct type *ts, *t2 = NULL;
  int v, w, cr;

  if (**input != '=')
  {
    ts = getTypeFromTypeNo(typeNo);

    t2 = (struct type*)xmalloc(sizeof(struct type));
    t2->typeNo    = typeNo;
    t2->nameIndex = typeName ? getStringIndex(typeName) : 0;
    t2->spec.function.tag         = TAG_FUNCTION;
    t2->spec.function.resultPlace = ts ? ts->spec.function.resultPlace : 0;
    t2->spec.function.resultType  = ts ? ts->spec.function.resultType  : 0;
    t2->spec.function.argList     = ts ? ts->spec.function.argList     : 0;
    t2->spec.function.classType   = getTypeIndex(fromClass);
    t2->spec.function.stack       = 0;
    t2->spec.function.what        = 0;
    array_AddElement(&typeArray, t2);
  }
  else if (*((*input) + 1) == '#'  &&  *((*input) + 2) != '#')
  {
    /* uhäääääää. Let's try to make a somehow working skip */
    /* until we know what's happening here. */
    (*input) += 2;

    while (**input != ';')
    {
      if (sscanf(*input, "%d%n", &v, &cr) < 1)
      {
        fprintf(stderr, "parseMethod(): error(a1) during parsing method of struct, union or class\non '%s'.\n", *input);
        return NULL;
      }
      (*input) ++;

      if (**input == '=')
      {
        (*input) ++;
        if (!parseType(v, NULL, input))
          return NULL;
      }
      if (**input == ',')
      {
        (*input) ++;
      }
    }
    (*input) ++;

    t2 = (struct type*)xmalloc(sizeof(struct type));
    t2->typeNo    = typeNo;
    t2->nameIndex = typeName ? getStringIndex(typeName) : 0;
    t2->spec.function.tag         = TAG_FUNCTION;
    t2->spec.function.resultPlace = 0;
    t2->spec.function.resultType  = 0;
    t2->spec.function.argList     = 0;
    t2->spec.function.classType   = getTypeIndex(fromClass);
    t2->spec.function.stack       = 0;
    t2->spec.function.what        = 0;
    array_AddElement(&typeArray, t2);
  }
  else
  {
    (*input) ++;
    t2 = parseType(typeNo, typeName, input);
    if (!t2  ||  t2->spec.tag != TAG_FUNCTION)
      return NULL;
    t2->spec.function.classType = getTypeIndex(fromClass);
  }

  if (**input != ':')
  {
    fprintf(stderr, "parseMethod(): error during parsing method of struct, union or class\non '%s'.\n", *input);
    return NULL;
  }
  (*input) ++;

  /* skip arguments */
  while(*(*input)++ != ';')  ;

  /* visibility */
  switch(**input)
  {
    case '0': /* private */
      t2->spec.function.what |= (1 << 2);
      break;
    case '1': /* protected */
      t2->spec.function.what |= (1 << 1);
      break;
    case '2': /* public */
      break;
  }
  (*input) ++;

  /* method qualifier */
  (*input) ++;

  /* virtual? */
  if (*(*input)++ == '*')
  {
    t2->spec.function.what |= 1;
    if (sscanf(*input, "%d;%d%n", &v, &w, &cr) != 2)
    {
      fprintf(stderr, "parseMethod(): error(v1) during parsing method of struct, union or class!\n");
      return NULL;
    }
    (*input) += cr;
    if (**input == '=')
    {
      (*input) ++;
      if (!parseType(w, NULL, input))
        return NULL;
    }
    if (**input != ';')
    {
      fprintf(stderr, "parseMethod(): error(v2) during parsing method of struct, union or class!\n");
      return NULL;
    }
    (*input) ++;
  }

  /* is there something more to come? */
  if (**input != ';')
  {
    if (sscanf(*input, "%d%n", &v, &cr) != 1)
    {
      fprintf(stderr, "parseMethod(): error(3) during parsing method of struct, union or class!\n");
      return NULL;
    }
    (*input) += cr;
    if (!parseMethod(v, NULL, fromClass, input))
      return NULL;
  }
  else
  {
    (*input) ++;
  }

  return t2;
}


static struct type *parseType(int typeNo, struct string *typeName, char **input)
{
  /* typeNo is the number, this type should be assigned to.
  ** typeName holds the name for this new type. This maybe NULL.
  ** input is the pointer description-string after the '='. */
  int cr;
  int value, x, y, z, protection;
  char tdstr[128];
  struct type *t, *t2;
  struct string *name;
  struct snode *n;
  int attr_bitsize = -1;

  /* read type attributes */
  while(**input == '@')
  {
    char c = *((*input) + 1);
    if(isdigit(c)  ||  c == '('  ||  c == '-')
      break;  /* this is not an attribute but an C++ member. */
    if(c == 's')
      sscanf((*input) + 2, "%d", &attr_bitsize);
    while(*((*input)++) != ';') ;
  }

  /* continue with description */
  if(**input == 'x')
  {
    /* cross reference */
    struct string *tn;
    (*input) ++;
    switch(**input)
    {
      case 's':
        (*input) ++;
        tn = parseName(input);
        t = (struct type*)xmalloc(sizeof(struct type));
        t->typeNo    = typeNo;
        t->nameIndex = tn ? getStringIndex(tn) : 0;
        t->spec.classinfo.tag  = TAG_STRUCTORUNION;
        t->spec.classinfo.what = 0;
        t->spec.classinfo.name = t->nameIndex;
        t->spec.classinfo.size = 0;
        t->spec.classinfo.memberList = 0;
        array_AddElement(&typeArray, t);
        if (**input != ':')
        {
          fprintf(stderr, "parseType(): error during parsing cross-reference to struct.\n");
          return NULL;
        }
        (*input) ++;
        return t;

      case 'u':
        (*input) ++;
        tn = parseName(input);
        t = (struct type*)xmalloc(sizeof(struct type));
        t->typeNo    = typeNo;
        t->nameIndex = tn ? getStringIndex(tn) : 0;
        t->spec.classinfo.tag  = TAG_STRUCTORUNION;
        t->spec.classinfo.what = 2;
        t->spec.classinfo.name = t->nameIndex;
        t->spec.classinfo.size = 0;
        t->spec.classinfo.memberList = 0;
        array_AddElement(&typeArray, t);
        return t;

      case 'e':
        (*input) ++;
        tn = parseName(input);
        t = (struct type*)xmalloc(sizeof(struct type));
        t->typeNo    = typeNo;
        t->nameIndex = tn ? getStringIndex(tn) : 0;
        t->spec.enumeration.tag  = TAG_ENUM;
        t->spec.enumeration.type = TAG_LONG;
        t->spec.enumeration.name = t->nameIndex;
        array_AddElement(&typeArray, t);
        return t;
    }
  }
  else if(**input == 'e')
  {
    /* enumeration */
    (*input) ++;
    t = (struct type*)xmalloc(sizeof(struct type));
    t->typeNo    = typeNo;
    t->nameIndex = typeName ? getStringIndex(typeName) : 0;
    t->spec.enumeration.tag  = TAG_ENUM;
    t->spec.enumeration.type = TAG_LONG;
    t->spec.enumeration.name = t->nameIndex;
    array_AddElement(&typeArray, t);
    while(**input != ';')
    {
      if(sscanf(*input, "%[^:]:%d,%n", tdstr, &value, &cr) < 2)
      {
        fprintf(stderr, "parseType(): error during parsing enumeration!\n");
        return NULL;
      }
      (*input) += cr;
      newSenum(getStringIndex(newString(tdstr)), getTypeIndex(t), value);
    }
    (*input) ++;
    return t;
  }
  else if(sscanf(*input, "%[^0123456789:;-]%d%n", tdstr, &value, &cr) == 2)
  {
    (*input) += cr;
    switch(tdstr[0])
    {
      case '*': /* pointer */
        if (**input == '=')
        {
          (*input) ++;
          if (!parseType(value, NULL, input))
            return NULL;
        }
        return newTypePointer(typeNo, value);

      case '&': /* reference */
        if (**input == '=')
        {
          (*input) ++;
          if (!parseType(value, NULL, input))
            return NULL;
        }
        return newTypeReference(typeNo, value);

      case 'r': /* subrange */
        if(sscanf(*input, ";%i;%i;%n", &x, &y, &cr) < 2)
        {
          fprintf(stderr, "parseType(), case 'r': range-data expected.\n");
          return NULL;
        }
        (*input) += cr;
        t = (struct type*)xmalloc(sizeof(struct type));
        t->typeNo = typeNo;
        t->nameIndex = typeName ? getStringIndex(typeName) : 0;
        t->spec.subrange.tag  = TAG_SUBRANGE;
        t->spec.subrange.type = TAG_LONG;
        t->spec.subrange.low  = x;
        t->spec.subrange.high = y;
        array_AddElement(&typeArray, t);
        return t;

      case 'a': /* array */
      case 'P': /* packed array (no padding) */
        if (tdstr[1] != 'r')
        {
          fprintf(stderr, "parseType(): unknown array-specifier '%s'.\n", tdstr);
          return NULL;
        }
        if (sscanf(*input, ";%i;%i;%i%n", &x, &y, &z, &cr) < 3)
        {
          fprintf(stderr, "parseType(), array-data expected.\n");
          return NULL;
        }
        (*input) += cr;
        if (**input == '=')
        {
          (*input) ++;
          if (!parseType(z, NULL, input))
            return NULL;
        }
        t2 = (struct type*)xmalloc(sizeof(struct type));
        t2->typeNo = 0;
        t2->nameIndex = 0;
        t2->spec.subrange.tag  = TAG_SUBRANGE;
        t2->spec.subrange.type = getTypeIndexFromTypeNo(value);
        t2->spec.subrange.low  = x;
        t2->spec.subrange.high = y;
        array_AddElement(&typeArray, t2);

        t = (struct type*)xmalloc(sizeof(struct type));
        t->typeNo    = typeNo;
        t->nameIndex = typeName ? getStringIndex(typeName) : 0;
        t->spec.array.tag       = TAG_ARRAY;
        t->spec.array.zero      = 0;
        t->spec.array.indexType = getTypeIndex(t2);
        t->spec.array.elemType  = getTypeIndexFromTypeNo(z);
        t->spec.array.elemSize  = getTypeSize(getTypeFromTypeNo(z));
        array_AddElement(&typeArray, t);
        return t;

      case 'f': /* function */
        t = (struct type*)xmalloc(sizeof(struct type));
        t->typeNo    = typeNo;
        t->nameIndex = typeName ? getStringIndex(typeName) : 0;
        t->spec.function.tag         = TAG_FUNCTION;
        t->spec.function.resultPlace = 0;
        t->spec.function.resultType  = getTypeIndexFromTypeNo(value);
        t->spec.function.argList     = 0;
        t->spec.function.classType   = 0;
        t->spec.function.stack       = 0;
        t->spec.function.what        = 0;
        array_AddElement(&typeArray, t);
        return t;

      case '#': /* method */
        if(tdstr[1] != '#')
        {
          fprintf(stderr, "parseType(): '#' after '#' expected.\n");
          return NULL;
        }
        if (**input == '=')
        {
          (*input) ++;
          if (!parseType(value, NULL, input))
            return NULL;
        }
        t = (struct type*)xmalloc(sizeof(struct type));
        t->typeNo    = typeNo;
        t->nameIndex = typeName ? getStringIndex(typeName) : 0;
        t->spec.function.tag         = TAG_FUNCTION;
        t->spec.function.resultPlace = 0;
        t->spec.function.resultType  = getTypeIndexFromTypeNo(value);
        t->spec.function.argList     = 0;
        t->spec.function.classType   = 0;
        t->spec.function.stack       = 0;
        t->spec.function.what        = 0;
        array_AddElement(&typeArray, t);
        if (**input != ';')
        {
          fprintf(stderr, "parseType(): ';' after method-description expected.\n");
          return NULL;
        }
        (*input) ++;
        return t;

      case 's': /* struct */
      case 'u': /* union */
        t = (struct type*)xmalloc(sizeof(struct type));
        t->typeNo    = typeNo;
        t->nameIndex = typeName ? getStringIndex(typeName) : 0;
        t->spec.classinfo.tag  = TAG_STRUCTORUNION;
        t->spec.classinfo.what = (tdstr[0] == 's' ? 0 : 2);
        t->spec.classinfo.name = t->nameIndex;
        t->spec.classinfo.size = value;
        t->spec.classinfo.memberList = 0;
        array_AddElement(&typeArray, t);

        if (**input == '!')
        {
          /* virtual base classes */
          (*input) ++;
          if (sscanf(*input, "%i,%n", &x, &cr) != 1)
          {
            fprintf(stderr, "parseType(): error(v1) during parsing struct, union or class\non '%s'.\n", *input);
            return NULL;
          }
          (*input) += cr;

          for(y=0; y<x; y++)
          {
            if (sscanf(*input, "%d,%d%n", &z, &value, &cr) != 2)
            {
              fprintf(stderr, "parseType(): error(v2) during parsing struct, union or class\non '%s'.\n", *input);
              return NULL;
            }
            (*input) += cr;
            if (**input == '=')
            {
              (*input) ++;
              if (!parseType(value, NULL, input))
                return NULL;
            }
            if (**input != ';')
            {
              fprintf(stderr, "parseType(): error(v3) during parsing struct, union or class\non '%s'.\n", *input);
              return NULL;
            }
            (*input) ++;
          }
        }
        while (**input != ';')
        {
          name = parseName(input);
          if (*((*input) + 1) == ':')
          {
            /* methode */
            (*input) += 2;
            if (sscanf(*input, "%d%n", &value, &cr) < 1)
            {
              fprintf(stderr, "parseType(): error during parsing method of struct, union or class!\n");
              return NULL;
            }
            (*input) += cr;

            if (!parseMethod(value, name, t, input))
              return NULL;
          }
          else
          {
            /* attribut */
            (*input) += 1;
            protection = 8;
            if (**input == '/')
            {
              /* visibility */
              (*input) ++;
              switch (**input)
              {
                case '0': /* private */
                  protection = 13;
                  break;
                case '1': /* protected */
                  protection = 12;
                  break;
                case '2': /* public */
                  break;
              }
              (*input) ++;
            }

            if (sscanf(*input, "%d%n", &value, &cr) < 1)
            {
              fprintf(stderr, "parseType(): error(1) during parsing struct, union or class\non '%s'.\n", *input);
              return NULL;
            }
            (*input) += cr;

            if (**input == '=')
            {
              (*input) ++;
              if (!parseType(value, NULL, input))
                return NULL;
            }

            if (**input == ':')
            {
              /* static member */
              /* we're skipping static members for now. */
              (*input) ++;
              parseName(input);
              if (**input != ';')
              {
                fprintf(stderr, "parseType(): error during parsing static member of a struct, union or class!\n");
                return NULL;
              }
              (*input) ++;
            }
            else if (sscanf(*input, ",%d,%d;%n", &x, &y, &cr) == 2)
            {
              (*input) += cr;
              n = xmalloc(sizeof(struct snode));
              n->nameIndex = getStringIndex(name);
              n->typeIndex = getTypeIndexFromTypeNo(value);
              if((x & 7) || (y & 7))
                n->codeStart = 0x0b000000 | (y << 16) | x;
              else
                n->codeStart = (protection << 24) | (x / 8);
              n->sourceStart = 0;
              n->spec.var.codeLen = 0;
              array_AddElement(&snodeArray, n);
              appendMemberToClassInfo(t, n);
            }
            else if (sscanf(*input, ",%d;%n", &x, &cr) == 1)
            {
              /* the number of bits in the field was omitted. */
              /* seems to be a v-table or -pointer. */
              (*input) += cr;
              n = xmalloc(sizeof(struct snode));
              n->nameIndex = getStringIndex(name);
              n->typeIndex = getTypeIndexFromTypeNo(value);
              n->codeStart = (protection << 24) | (x / 8);
              n->sourceStart = 0;
              n->spec.var.codeLen = 0;
              array_AddElement(&snodeArray, n);
              appendMemberToClassInfo(t, n);
            }
            else
            {
              fprintf(stderr, "parseType(): error(2) during parsing struct, union or class\non '%s'.\n", *input);
              return NULL;
            }
          }
        }
        (*input) ++;
        return t;

      case 'A':
      case 'b':
      case 'B':
      case 'c':
      case 'C':
      case 'd':
      case 'D':
      case 'E':
      case 'F':
      case 'g':
      case 'G':
      case 'i':
      case 'k':
      case 'K':
      case 'M':
      case 'o':
      case 'p':
      case 'R':
      case 'S':
      case 'v':
      case 'w':
      case 'x':
      case 'Y':
      case '@':
      case 'n':
      case 'N':
      case 'z':
      default:
        fprintf(stderr, "parseType(): unsupported type descriptor '%s'.\n", tdstr);
        return NULL;
    }
  }
  else if(sscanf(*input, "%d%n", &value, &cr) == 1)
  {
    (*input) += cr;
    /* type reference (typedef) */
    if(value < 0)
    {
      /* builtin type */
      int typetag = TAG_VOID;
      switch(value)
      {
        case -1:
        case -4:
        case -15:
        case -29:
          typetag = TAG_LONG;
          break;

        case -2:
          typetag = TAG_CHAR;
          break;

        case -3:
        case -28:
          typetag = TAG_WORD;
          break;

        case -5:
        case -20:
        case -21:
          typetag = TAG_UBYTE;
          break;

        case -6:
        case -27:
          typetag = TAG_BYTE;
          break;

        case -7:
        case -22:
          typetag = TAG_UWORD;
          break;

        case -8:
        case -9:
        case -10:
        case -23:
        case -24:
          typetag = TAG_ULONG;
          break;

        case -11:
          typetag = TAG_VOID;
          break;

        case -12:
        case -17:
          typetag = TAG_SINGLE;
          break;

        case -13:
        case -18:
          typetag = TAG_DOUBLE;
          break;

        case -14:
          typetag = TAG_EXTENDED;
          break;

        case -16:
          if(attr_bitsize == 8)
            typetag = TAG_SBOOL;
          else if(attr_bitsize == 16)
            typetag = TAG_BOOL;
          else
            typetag = TAG_LBOOL;
          break;

        case -19:
          typetag = TAG_PASCALSTR;
          break;

        case -30:
          typetag = TAG_WCHAR;
          break;

        case -31:
        case -34:
          typetag = TAG_LONGLONG;
          break;

        case -32:
        case -33:
          typetag = TAG_ULONGLONG;
          break;


        case -25:
        case -26:
        default:
          fprintf(stderr, "parseType(): unsupported builtin type %d.\n", value);
      }
      return newTypeBasic(typeNo, typeName, typetag);
    }
    else
    {
      if (**input == '=')
      {
        (*input) ++;
        if (!parseType(value, NULL, input))
          return NULL;
      }
      return newTypeTypedef(typeNo, typeName, value);
    }
  }

  fprintf(stderr, "parseType(): parse error on '%s'.\n", *input);
  return NULL;
}


symbolS *parseStab(symbolS *ptr, char *input, int hunkNo, unsigned int symbol_value, unsigned int symbol_desc, struct scope *currentScope, struct type **currentFunction)
{
  int value, cr;
  char sdstr [32];
  struct snode *snodp;
    struct scope *sscop;
    struct type  *stypp;
  struct string *name = parseName(&input);
  if(!name)
    return 0;

  if(sscanf(input, ":%[^0123456789;:-]%d%n", sdstr, &value, &cr) == 2)
  {
    input += cr;
    switch(sdstr[0])
    {
      case 'r': /* register variable */
        if (*input == '=')
        {
          input ++;
          if (!parseType(value, NULL, &input))
            return NULL;
        }
        snodp = (struct snode*) xmalloc(sizeof(struct snode));
        snodp->nameIndex = getStringIndex(name);
        snodp->typeIndex = getTypeIndexFromTypeNo(value);
        snodp->codeStart = 0x03000000 + (symbol_value & 0x00ffffff);
        snodp->sourceStart = (1 << 31) | (currentSourceIndex << 20) | symbol_desc;
        snodp->spec.var.codeLen = 0;
        array_AddElement(&snodeArray, snodp);
        snodp->nextIndex = NOSCOPE; /* this is the flag, that this node has no scope, yet. */
        break;

      case 'R':
      case 'P':   /* parameter in register */
      case 'a': /* parameter in register passed by reference */
        if (*input == '=')
        {
          input ++;
          if (!parseType(value, NULL, &input))
            return NULL;
        }
        snodp = (struct snode*)xmalloc(sizeof(struct snode));
        snodp->nameIndex = getStringIndex(name);
        snodp->typeIndex = getTypeIndexFromTypeNo(value);
        snodp->codeStart = 0x03000000 + (symbol_value & 0x00ffffff);
        snodp->sourceStart = (1 << 31) | (currentSourceIndex << 20) | symbol_desc;
        snodp->spec.var.codeLen = 0;
        array_AddElement(&snodeArray, snodp);
        appendArgToFunction(*currentFunction, snodp);
        break;

      case 'p': /* parameter on stack */
      case 'v': /* parameter on stack passed by reference */
        if (*input == '=')
        {
          input ++;
          if (!parseType(value, NULL, &input))
            return NULL;
        }
        snodp = (struct snode*)xmalloc(sizeof(struct snode));
        snodp->nameIndex = getStringIndex(name);
        snodp->typeIndex = getTypeIndexFromTypeNo(value);
        snodp->codeStart = 0x06000000 + (symbol_value & 0x00ffffff);
        snodp->sourceStart = (1 << 31) | (currentSourceIndex << 20) | symbol_desc;
        snodp->spec.var.codeLen = 0;
        array_AddElement(&snodeArray, snodp);
        appendArgToFunction(*currentFunction, snodp);
        break;

      case 'G':   /* global variable */
        if (*input == '=')
        {
          input ++;
          if (!parseType(value, NULL, &input))
            return NULL;
        }
        snodp = (struct snode*)xmalloc(sizeof(struct snode));
        snodp->nameIndex = getStringIndex(name);
        snodp->typeIndex = getTypeIndexFromTypeNo(value);
        /*printf("%s, segment=%d,%d, offset=%d\n", name->str, S_GET_TYPE(ptr), N_DATA, 0); */
        snodp->codeStart = 0x0a000000;
        snodp->sourceStart = (1 << 31) | (currentSourceIndex << 20) | symbol_desc;
        snodp->spec.var.codeLen = 0;
        array_AddElement(&snodeArray, snodp);
        snodp->nextIndex = getGlobalScope()->objectsIndex;
        getGlobalScope()->objectsIndex = getSnodeIndex(snodp);
        break;

      case 'S': /* file-scope static variable */
      case 'V': /* func-scope static variable */
        if (*input == '=')
        {
          input ++;
          if (!parseType(value, NULL, &input))
            return NULL;
        }
        snodp = (struct snode*)xmalloc(sizeof(struct snode));
        snodp->nameIndex = getStringIndex(name);
        snodp->typeIndex = getTypeIndexFromTypeNo(value);
        if (hunkNo >= 0)
          snodp->codeStart = ((~hunkNo << 24) & 0xff000000) | (symbol_value & 0x00ffffff);
        else
          snodp->codeStart = 0xfe000000 | (symbol_value & 0x00ffffff);
        snodp->sourceStart = (1 << 31) | (currentSourceIndex << 20) | symbol_desc;
        snodp->spec.var.codeLen = 0;
        array_AddElement(&snodeArray, snodp);
        if(sdstr[0] == 'S')
        {
          snodp->nextIndex = getGlobalScope()->objectsIndex;
          getGlobalScope()->objectsIndex = getSnodeIndex(snodp);
        }
        else
        {
          snodp->nextIndex = NOSCOPE; /* this is the flag, that this node has no scope, yet. */
        }
        break;

      case 'F': /* global function */
      case 'f': /* static function */
        if (*input == '=')
        {
          input ++;
          if (!parseType(value, NULL, &input))
            return NULL;
        }
        if (*input == ',')
        {
          /* nested functions */
          fprintf(stderr, "parseStab(): nested functions are currently not implemented!\n");
          return NULL;
        }
        /* the type of a function is the type of its return-value */
        stypp = (struct type*)xmalloc(sizeof(struct type));
        stypp->typeNo = 0;
        stypp->nameIndex = getStringIndex(name);
        stypp->spec.function.tag  = TAG_FUNCTION;
        stypp->spec.function.resultPlace = 0;
        stypp->spec.function.resultType  = getTypeIndexFromTypeNo(value);
        stypp->spec.function.argList     = 0;
        stypp->spec.function.classType   = 0;
        stypp->spec.function.stack       = 0;
        stypp->spec.function.what        = 0;
        array_AddElement(&typeArray, stypp);

        snodp = (struct snode*)xmalloc(sizeof(struct snode));
        snodp->nameIndex = getStringIndex(name);
        snodp->typeIndex = getTypeIndex(stypp);
        if (hunkNo >= 0)
          snodp->codeStart = ((~hunkNo << 24) & 0xff000000) | (symbol_value & 0x00ffffff);
        else
          snodp->codeStart = 0xff000000 | (symbol_value & 0x00ffffff);
        snodp->sourceStart = (1 << 31) | (currentSourceIndex << 20) | symbol_desc;
        snodp->spec.func.scope     = 0;
        snodp->spec.func.posnIndex = 0;
        snodp->spec.func.codeSize  = getLatestPosition()->hunkOffset - symbol_value;
        array_AddElement(&snodeArray, snodp);
        snodp->nextIndex = currentScope->objectsIndex;
        currentScope->objectsIndex = getSnodeIndex(snodp);
        *currentFunction = stypp;
        break;

      case 't':
      case 'T': /* name for a type */
        if(strcmp(name->str, "int") == 0
        || strcmp(name->str, "long int") == 0)
        {
            newTypeBasic(value, name, TAG_LONG);
        }
        else if(strcmp(name->str, "unsigned int") == 0
        || strcmp(name->str, "long unsigned int") == 0)
        {
            newTypeBasic(value, name, TAG_ULONG);
        }
        else if(strcmp(name->str, "long long int") == 0)
        {
            newTypeBasic(value, name, TAG_LONGLONG);
        }
        else if(strcmp(name->str, "long long unsigned int") == 0)
        {
            newTypeBasic(value, name, TAG_ULONGLONG);
        }
        else if(strcmp(name->str, "short int") == 0)
        {
            newTypeBasic(value, name, TAG_WORD);
        }
        else if(strcmp(name->str, "short unsigned int") == 0)
        {
            newTypeBasic(value, name, TAG_UWORD);
        }
        else if(strcmp(name->str, "char") == 0
        || strcmp(name->str, "signed char") == 0)
        {
            newTypeBasic(value, name, TAG_BYTE);
        }
        else if(strcmp(name->str, "unsigned char") == 0)
        {
            newTypeBasic(value, name, TAG_UBYTE);
        }
        else if(strcmp(name->str, "float") == 0)
        {
            newTypeBasic(value, name, TAG_SINGLE);
        }
        else if(strcmp(name->str, "double") == 0
             || strcmp(name->str, "long double") == 0)
        {
            newTypeBasic(value, name, TAG_DOUBLE);
        }
        else if(strcmp(name->str, "void") == 0)
        {
            newTypeBasic(value, name, TAG_VOID);
        }
        else if(strcmp(name->str, "complex int") == 0
             || strcmp(name->str, "complex float") == 0
             || strcmp(name->str, "complex double") == 0
             || strcmp(name->str, "complex long double") == 0)
        {
            break;
        }
        else if (*input == '=')
        {
          input ++;
          if (!parseType(value, name, &input))
            return NULL;
        }
        break;

      case 'c':
        fprintf(stderr, "parseStab(): constants are currently not implemented!\n");
        return NULL;

      case 'b':
      case 'C':
      case 'd':
      case 'D':
      case 'i':
      case 'L':
      case 'm':
      case 'I':
      case 'J':
      case 'Q':
      case 's':
      case 'X':
      case 'x':
      default:
        fprintf(stderr, "parseStab(): unsupported symbol descriptor '%s'.\n", sdstr);
        return NULL;
    }
  }
  else if (sscanf(input, ":%d%n", &value, &cr) == 1)
  {
    input += cr;
    /* variable on the stack */
    if (*input == '=')
    {
      input ++;
      if (!parseType(value, NULL, &input))
        return NULL;
    }
    snodp = (struct snode*) xmalloc(sizeof(struct snode));
    snodp->nameIndex = getStringIndex(name);
    snodp->typeIndex = getTypeIndexFromTypeNo(value);
    snodp->codeStart = 0x06000000 + (symbol_value & 0x00ffffff);
    snodp->sourceStart = (1 << 31) | (currentSourceIndex << 20) | symbol_desc;
    snodp->spec.var.codeLen = 0;
    array_AddElement(&snodeArray, snodp);
    snodp->nextIndex = NOSCOPE; /* this is the flag, that this node has no scope, yet. */
  }
  else
    return NULL;
  return ptr;
}



/*
** createLists()
*/
static symbolS *createLists(symbolS *start_symbol, struct scope *currentScope, struct type **currentFunction)
{
    symbolS *ptr;
    struct string *sstrp;
    struct source *ssrcp;
    struct scope  *sscop;
  struct snode  *snodp;
  struct Node *next;
  int fi, si, i;

  if (stringbuffer == NULL)
  {
    strLen = 0;
    bufLen = 4096;
    stringbuffer = (char*) xmalloc(bufLen);
    stringbuffer[0] = 0;
  }

  ptr = start_symbol;
  while(ptr)
  {
        switch(S_GET_TYPE_FULL(ptr))
        {
            case N_GSYM:
            case N_FUN:
            case N_STSYM:
            case N_LCSYM:
            case N_RSYM:
            case N_SSYM:
            case N_LSYM:
            case N_PSYM:
                strcpy(stringbuffer, S_GET_NAME(ptr));
                strLen = strlen(stringbuffer);

                while((stringbuffer[strLen - 1] == '\\')  &&  symbol_next(ptr))
                {
          int nbl = bufLen;
          ptr = symbol_next(ptr);
          while (strLen + strlen(S_GET_NAME(ptr)) >= nbl)
          {
            nbl *= 2;
          }
          if (nbl > bufLen)
          {
            char *nsb = xmalloc(nbl);
            bufLen = nbl;
            memcpy(nsb, stringbuffer, strLen + 1);
            xfree(stringbuffer);
            stringbuffer = nsb;
          }
          strcpy(stringbuffer + strLen - 1, S_GET_NAME(ptr));
          strLen = strlen(stringbuffer);
                }
                /*printf("SYM: '%s'.\n", stringbuffer); */
        ptr = parseStab(ptr, stringbuffer, S_GET_HUNKNO(ptr), S_GET_VALUE(ptr), S_GET_DESC(ptr), currentScope, currentFunction);
        break;

            case N_SO:
                strcpy(stringbuffer, S_GET_NAME(ptr));
                /*printf("SO: '%s'.\n", stringbuffer); */
                sstrp = newString(stringbuffer);
                if(stringbuffer[strlen(stringbuffer) - 1] == '/')
                {
                    currentPathStringIndex = getStringIndex(sstrp);
                }
                else
                {
                    ssrcp = newSource(currentPathStringIndex, getStringIndex(sstrp));
                    currentSourceIndex = FIRSTSOURCEINDEX + array_GetIndex(&sourceArray, ssrcp);
                }
                break;

            case N_SOL:
                strcpy(stringbuffer, S_GET_NAME(ptr));
                /*printf("SOL: '%s'.\n", stringbuffer); */
                sstrp = newString(stringbuffer);
                ssrcp = newSource(currentPathStringIndex, getStringIndex(sstrp));
        currentSourceIndex = FIRSTSOURCEINDEX + array_GetIndex(&sourceArray, ssrcp);
                break;

            case N_SLINE:
                /*printf("SLINE:\n"); */
                newPosition(currentSourceIndex, S_GET_DESC(ptr), S_GET_HUNKNO(ptr), S_GET_VALUE(ptr));
                break;

            case N_LBRAC:
                /*printf("LBRAC:\n"); */
        sscop = (struct scope*)xmalloc(sizeof(struct scope));
        sscop->parentIndex  = getScopeIndex(currentScope);
        sscop->objectsIndex = 0;
        sscop->sourceStart  = 0;
        sscop->sourceEnd    = 0;
        array_AddElement(&scopeArray, sscop);

        if (*currentFunction)
          fi = getTypeIndex(*currentFunction);
        else
          fi = ~0;

        for(i=0; i<array_GetNumElements(&snodeArray); i++)
        {
          snodp = (struct snode*) array_GetElement(&snodeArray, i);
          if (snodp->nextIndex == NOSCOPE)
          {
            snodp->nextIndex = sscop->objectsIndex;
            sscop->objectsIndex = getSnodeIndex(snodp);
          }
          else if (snodp->typeIndex == fi  &&  snodp->spec.func.scope == 0)
          {
            snodp->spec.func.scope = getScopeIndex(sscop);
          }
        }

                ptr = createLists(symbol_next(ptr), sscop, currentFunction);
                break;

            case N_RBRAC:
                /*printf("RBRAC:\n"); */
                return ptr;
                break;
        }
      if(ptr)
        ptr = symbol_next(ptr);
    }
    return NULL;
}


/*
** We need a second pass where we give every function without a scope
** a new empty scope.
** After this, we can add the parameters of a function to its scope.
*/
static void paras2scope(void)
{
  struct snode *walk;
  struct type *styp;
  struct scope *sscop;
  int i;

  for(i=0; i<array_GetNumElements(&snodeArray); i++)
  {
    walk = (struct snode*) array_GetElement(&snodeArray, i);
    styp = getTypeFromTypeIndex(walk->typeIndex);

    if (styp  &&  styp->spec.tag == TAG_FUNCTION)
    {
      if (walk->spec.func.scope == 0)
      {
        sscop = (struct scope*)xmalloc(sizeof(struct scope));
        sscop->parentIndex  = getScopeIndex(getGlobalScope());
        sscop->objectsIndex = 0;
        sscop->sourceStart  = 0;
        sscop->sourceEnd    = 0;
        array_AddElement(&scopeArray, sscop);
        walk->spec.func.scope = getScopeIndex(sscop);
      }
      else
      {
        sscop = getScopeFromScopeIndex(walk->spec.func.scope);
      }
      if (styp->spec.function.argList)
      {
        appendSnodeToScope(sscop, getSnodeFromIndex(styp->spec.function.argList));
      }
    }
  }
}


/*
** write...()
*/
static void writeSTRG(struct IFFHandle *handle)
{
    struct string *walk;
    UWORD s;
    int i;

    PushChunk(handle, ID_SDBG, ID_STRG, IFFSIZE_UNKNOWN);

    s = FIRSTSTRINGINDEX;
    WriteChunkBytes(handle, &s, sizeof(s));
  s = array_GetNumElements(&stringArray);
    WriteChunkBytes(handle, &s, sizeof(s));

  for(i=0; i<array_GetNumElements(&stringArray); i++)
  {
    walk = (struct string*) array_GetElement(&stringArray, i);
        WriteChunkBytes(handle, walk->str, strlen(walk->str) + 1);
    }

    PopChunk(handle);
}


static void writeTYPE(struct IFFHandle *handle)
{
    struct type *walk;
    UWORD s;
    int i;

    PushChunk(handle, ID_SDBG, ID_TYPE, IFFSIZE_UNKNOWN);

    s = FIRSTTYPEINDEX;
    WriteChunkBytes(handle, &s, sizeof(s));
    s = sizeof(walk->spec);
    WriteChunkBytes(handle, &s, sizeof(s));

  for(i=0; i<array_GetNumElements(&typeArray); i++)
  {
    walk = (struct type*) array_GetElement(&typeArray, i);
        WriteChunkBytes(handle, &walk->spec, sizeof(walk->spec));
    }

    PopChunk(handle);
}


static void writeILST(struct IFFHandle *handle)
{
    struct snode *walk;
    UWORD s;
    int i;

    PushChunk(handle, ID_SDBG, ID_ILST, IFFSIZE_UNKNOWN);

    s = FIRSTSNODEINDEX;
    WriteChunkBytes(handle, &s, sizeof(s));
    s = 20;
    WriteChunkBytes(handle, &s, sizeof(s));

  for(i=0; i<array_GetNumElements(&snodeArray); i++)
  {
    walk = (struct snode*) array_GetElement(&snodeArray, i);
      if (walk->nextIndex == NOSCOPE)
      {
        printf("writeILST(): here is a node without a scope!\n");
      }
      else
      {
      WriteChunkBytes(handle, &walk->nextIndex, sizeof(walk->nextIndex));
      WriteChunkBytes(handle, &walk->nameIndex, sizeof(walk->nameIndex));
      WriteChunkBytes(handle, &walk->typeIndex, sizeof(walk->typeIndex));
      WriteChunkBytes(handle, &walk->codeStart, sizeof(walk->codeStart));
      WriteChunkBytes(handle, &walk->sourceStart, sizeof(walk->sourceStart));
      WriteChunkBytes(handle, &walk->spec, sizeof(walk->spec));
    }
    }

    PopChunk(handle);
}


static void writeENUM(struct IFFHandle *handle)
{
    struct senum *walk;
    UWORD s;
  int i, n;

  if(n = array_GetNumElements(&senumArray))
    {
        PushChunk(handle, ID_SDBG, ID_ENUM, IFFSIZE_UNKNOWN);

        s = FIRSTSENUMINDEX;
        WriteChunkBytes(handle, &s, sizeof(s));
        s = 8;
        WriteChunkBytes(handle, &s, sizeof(s));

    for(i=0; i<n; i++)
    {
      walk = (struct senum*) array_GetElement(&senumArray,  i);
            WriteChunkBytes(handle, &walk->nameIndex, sizeof(walk->nameIndex));
            WriteChunkBytes(handle, &walk->typeIndex, sizeof(walk->typeIndex));
            WriteChunkBytes(handle, &walk->value, sizeof(walk->value));
        }

        PopChunk(handle);
    }
}


static void writeSCOP(struct IFFHandle *handle)
{
    struct scope *walk;
    UWORD s;
    int i;

    PushChunk(handle, ID_SDBG, ID_SCOP, IFFSIZE_UNKNOWN);

    s = FIRSTSCOPEINDEX;
    WriteChunkBytes(handle, &s, sizeof(s));
    s = 12;
    WriteChunkBytes(handle, &s, sizeof(s));

  for(i=0; i<array_GetNumElements(&scopeArray); i++)
  {
    walk = (struct scope*) array_GetElement(&scopeArray, i);
        WriteChunkBytes(handle, &walk->parentIndex,  sizeof(walk->parentIndex));
        WriteChunkBytes(handle, &walk->objectsIndex, sizeof(walk->objectsIndex));
        WriteChunkBytes(handle, &walk->sourceStart,  sizeof(walk->sourceStart));
        WriteChunkBytes(handle, &walk->sourceEnd,    sizeof(walk->sourceEnd));
    }

    PopChunk(handle);
}


static void writeSRCS(struct IFFHandle *handle)
{
    struct source *walk;
    UWORD s;
    int i;

    PushChunk(handle, ID_SDBG, ID_SRCS, IFFSIZE_UNKNOWN);

    s = FIRSTSOURCEINDEX;
    WriteChunkBytes(handle, &s, sizeof(s));
    s = 10;
    WriteChunkBytes(handle, &s, sizeof(s));

  for(i=0; i<array_GetNumElements(&sourceArray); i++)
  {
    walk = (struct source*) array_GetElement(&sourceArray, i);
        WriteChunkBytes(handle, &walk->pathIndex,  sizeof(walk->pathIndex));
        WriteChunkBytes(handle, &walk->nameIndex,  sizeof(walk->nameIndex));
        WriteChunkBytes(handle, &walk->lastChange, sizeof(walk->lastChange));
        WriteChunkBytes(handle, &walk->sourceLanguageIndex, sizeof(walk->sourceLanguageIndex));
        WriteChunkBytes(handle, &walk->compilerNameIndex,   sizeof(walk->compilerNameIndex));
    }

    PopChunk(handle);
}


static void writePOSN(struct IFFHandle *handle)
{
    struct position *prev, *walk;
    UBYTE b;
    UWORD w;
    ULONG l;
  int i;

    PushChunk(handle, ID_SDBG, ID_POSN, IFFSIZE_UNKNOWN);

    prev = NULL;
  for(i=0; i<array_GetNumElements(&positionArray); i++)
  {
    walk = (struct position*) array_GetElement(&positionArray, i);

        /* code */
        if((prev == NULL)  ||  (prev->hunkNo != walk->hunkNo)  ||  (walk->hunkOffset - prev->hunkOffset > 65534))
        {
            b = 251;
            WriteChunkBytes(handle, &b, sizeof(b));
            l = ((~walk->hunkNo) << 24) | (walk->hunkOffset);
            WriteChunkBytes(handle, &l, sizeof(l));
        }
        else if(walk->hunkOffset - prev->hunkOffset > 250)
        {
            b = 255;
            WriteChunkBytes(handle, &b, sizeof(b));
            w = walk->hunkOffset - prev->hunkOffset;
            WriteChunkBytes(handle, &w, sizeof(w));
        }
        else
        {
            b = walk->hunkOffset - prev->hunkOffset;
            WriteChunkBytes(handle, &b, sizeof(b));
        }

        /* source */
        b = 254;
        WriteChunkBytes(handle, &b, sizeof(b));
        l = (1 << 31) | (walk->sourceIndex << 20) | (walk->lineNo);
        WriteChunkBytes(handle, &l, sizeof(l));

        prev = walk;
    }

    PopChunk(handle);
}



/*
** main entry.
** called from as.c/main()
*/
void debug_output(char *fname, symbolS *first)
{
    struct IFFHandle *handle;
    struct scope *sscop;
    struct type *cF = NULL;

  array_Init(&stringArray);
  array_Init(&sourceArray);
  array_Init(&positionArray);
  array_Init(&scopeArray);
  array_Init(&snodeArray);
  array_Init(&senumArray);
  array_Init(&typeArray);

    handle = AllocIFF();
    if(!handle)
    {
    }
    else
    {
        handle->iff_Stream = Open(fname, MODE_NEWFILE);
        if(!handle->iff_Stream)
        {
        }
        else
        {
            InitIFFasDOS(handle);
            if(OpenIFF(handle, IFFF_WRITE) != 0)
            {
            }
            else
            {
                PushChunk(handle, ID_SDBG, ID_FORM, IFFSIZE_UNKNOWN);

                sscop = (struct scope*)xmalloc(sizeof(struct scope));
                sscop->parentIndex  = 0;
                sscop->objectsIndex = 0;
                sscop->sourceStart  = 0;
                sscop->sourceEnd    = 0;
                array_AddElement(&scopeArray, sscop);

        printf("debug_output: going to do createLists()...\n");
                createLists(first, sscop, &cF);
                paras2scope();
        printf("debug_output: done createLists().\n");
                writeSTRG(handle);
                writeSRCS(handle);
                writeTYPE(handle);
                writeILST(handle);
                writeENUM(handle);
                writeSCOP(handle);
                writePOSN(handle);

                PopChunk(handle);
                CloseIFF(handle);
            }
            Close(handle->iff_Stream);
        }
        FreeIFF(handle);
    }

  array_Exit(&stringArray);
  array_Exit(&sourceArray);
  array_Exit(&positionArray);
  array_Exit(&scopeArray);
  array_Exit(&snodeArray);
  array_Exit(&senumArray);
  array_Exit(&typeArray);
}


