/*
** 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);
static struct type *getTypeFromTypeNo(int typeNo);


/*
** 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;

			case TAG_TYPEDEF:
				return getTypeSize(getTypeFromTypeNo(t->spec.typedefinfo.type));
		}
	}
	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 struct string *getStringFromString(char *s)
{
	struct string *walk;
	int i;
	for(i=0; walk = (struct string*)array_GetElement(&stringArray, i); i++)
	{
		if(strcmp(s, walk->str) == 0)
			return walk;
	}
	return NULL;
}


static struct type *getTypeFromTypeString(struct string *strs)
{
	struct type *walk;
	int i, stri;

	stri = getStringIndex(strs);

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


static struct type *getTypeFromTypeName(char *name)
{
	struct string *strs;

	strs = getStringFromString(name);
	if(strs)
		return getTypeFromTypeString(strs);
	return NULL;
}


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 = getTypeFromTypeString(tn);
				if(!t)
				{
					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 = getTypeFromTypeString(tn);
				if(!t)
				{
					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 = getTypeFromTypeString(typeName);
				if(!t)
				{
					t = (struct type*)xmalloc(sizeof(struct type));
					array_AddElement(&typeArray, t);
				}
				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;

				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 amiga_symbol *asym;
    struct sec *sec;

	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;
				}
				asym = (struct amiga_symbol*)ptr->bsym;
				//fprintf(stderr, "symbol %s, hunk %d, offset %d\n", name->str, asym->hunk_number, asym->index);

				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 type   *stypp;
	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 0:
        		fprintf(stderr, "0:%s\n", S_GET_NAME(ptr));
        		break;
        	case 1:
        		fprintf(stderr, "1:%s, %d\n", S_GET_NAME(ptr), S_GET_VALUE(ptr));
        		break;
        	case 2:
        		fprintf(stderr, "2:%s\n", S_GET_NAME(ptr));
        		break;
        	case 3:
        		fprintf(stderr, "3:%s\n", S_GET_NAME(ptr));
        		break;
        	case 4:
        		fprintf(stderr, "4:%s\n", S_GET_NAME(ptr));
        		break;
        	case 5:
        		fprintf(stderr, "5:%s\n", S_GET_NAME(ptr));
        		break;
        	case 6:
        		fprintf(stderr, "6:%s\n", S_GET_NAME(ptr));
        		break;
        	case 7:
        		fprintf(stderr, "7:%s\n", S_GET_NAME(ptr));
        		break;
        	case 8:
        		fprintf(stderr, "8:%s\n", S_GET_NAME(ptr));
        		break;*/

        	case 0x21:
        		/* this is the very special handling of a stab, that was created
        		** through #pragma libbase. We've to look for a type with the
        		** given name and create a symbol with the length of this type. */
                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);
                }

                stypp = getTypeFromTypeName(stringbuffer);
                if(!stypp)
                {
                	as_warn("unknown type `%s' in #pragma libbase.", stringbuffer);
                }
                else
                {
                	unsigned int v;
                	char *symname = "__THISSHAREDLIBRARYBASESIZE\0\0\0\0";

                	v = HUNK_DATA;
                	bfd_write(&v, sizeof(v), 1, stdoutput);
                	v = 0;
                	bfd_write(&v, sizeof(v), 1, stdoutput);
                	v = HUNK_EXT;
                	bfd_write(&v, sizeof(v), 1, stdoutput);
                	v = (EXT_ABS << 24) + ((strlen(symname) + 3) / 4);
                	bfd_write(&v, sizeof(v), 1, stdoutput);
					bfd_write(symname, 4, (v & 0x00ffffff), stdoutput);
					v = getTypeSize(stypp);
					if(v == 0)
	                	as_warn("type `%s' in #pragma libbase is incomplete.", stringbuffer);
					else if(v < 34)
	                	as_warn("size of type `%s' in #pragma libbase is smaller\nthan size of struct Library.", stringbuffer);
                	bfd_write(&v, sizeof(v), 1, stdoutput);
					v = 0;
                	bfd_write(&v, sizeof(v), 1, stdoutput);
					v = HUNK_END;
                	bfd_write(&v, sizeof(v), 1, stdoutput);
                }
				break;

            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);
}


