]> git.sur5r.net Git - cc65/blob - src/dbginfo/dbginfo.c
Changed most "backticks" (grave accents) into apostrophes.
[cc65] / src / dbginfo / dbginfo.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 dbginfo.c                                 */
4 /*                                                                           */
5 /*                         cc65 debug info handling                          */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2010-2011, Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 52                                           */
11 /*                D-70794 Filderstadt                                        */
12 /* EMail:         uz@cc65.org                                                */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <stdarg.h>
39 #include <string.h>
40 #include <ctype.h>
41 #include <limits.h>
42 #include <assert.h>
43 #include <errno.h>
44
45 #include "dbginfo.h"
46
47
48
49 /*****************************************************************************/
50 /*                                   Data                                    */
51 /*****************************************************************************/
52
53
54
55 /* Use this for debugging - beware, lots of output */
56 #define DEBUG           0
57
58 /* Version numbers of the debug format we understand */
59 #define VER_MAJOR       2U
60 #define VER_MINOR       0U
61
62 /* Dynamic strings */
63 typedef struct StrBuf StrBuf;
64 struct StrBuf {
65     char*       Buf;                    /* Pointer to buffer */
66     unsigned    Len;                    /* Length of the string */
67     unsigned    Allocated;              /* Size of allocated memory */
68 };
69
70 /* Initializer for a string buffer */
71 #define STRBUF_INITIALIZER      { 0, 0, 0 }
72
73 /* An array of unsigneds/pointers that grows if needed. C guarantees that a
74 ** pointer to a union correctly converted points to each of its members.
75 ** So what we do here is using union entries that contain an unsigned
76 ** (used to store ids until they're resolved) and pointers to actual items
77 ** in storage.
78 */
79 typedef union CollEntry CollEntry;
80 union CollEntry {
81     void*               Ptr;
82     unsigned            Id;
83 };
84
85 typedef struct Collection Collection;
86 struct Collection {
87     unsigned            Count;          /* Number of items in the list */
88     unsigned            Size;           /* Size of allocated array */
89     CollEntry*          Items;          /* Array with dynamic size */
90 };
91
92 /* Initializer for static collections */
93 #define COLLECTION_INITIALIZER  { 0, 0, 0 }
94
95 /* Span info management. The following table has as many entries as there
96 ** are addresses active in spans. Each entry lists the spans for this address.
97 */
98 typedef struct SpanInfoListEntry SpanInfoListEntry;
99 struct SpanInfoListEntry {
100     cc65_addr           Addr;           /* Unique address */
101     unsigned            Count;          /* Number of SpanInfos for this address */
102     void*               Data;           /* Either SpanInfo* or SpanInfo** */
103 };
104
105 typedef struct SpanInfoList SpanInfoList;
106 struct SpanInfoList {
107     unsigned            Count;          /* Number of entries */
108     SpanInfoListEntry*  List;           /* Dynamic array with entries */
109 };
110
111 /* Input tokens */
112 typedef enum {
113
114     TOK_INVALID,                        /* Invalid token */
115     TOK_EOF,                            /* End of file reached */
116
117     TOK_INTCON,                         /* Integer constant */
118     TOK_STRCON,                         /* String constant */
119
120     TOK_EQUAL,                          /* = */
121     TOK_COMMA,                          /* , */
122     TOK_MINUS,                          /* - */
123     TOK_PLUS,                           /* + */
124     TOK_EOL,                            /* \n */
125
126     TOK_FIRST_KEYWORD,
127     TOK_ABSOLUTE = TOK_FIRST_KEYWORD,   /* ABSOLUTE keyword */
128     TOK_ADDRSIZE,                       /* ADDRSIZE keyword */
129     TOK_AUTO,                           /* AUTO keyword */
130     TOK_COUNT,                          /* COUNT keyword */
131     TOK_CSYM,                           /* CSYM keyword */
132     TOK_DEF,                            /* DEF keyword */
133     TOK_ENUM,                           /* ENUM keyword */
134     TOK_EQUATE,                         /* EQUATE keyword */
135     TOK_EXPORT,                         /* EXPORT keyword */
136     TOK_EXTERN,                         /* EXTERN keyword */
137     TOK_FILE,                           /* FILE keyword */
138     TOK_FUNC,                           /* FUNC keyword */
139     TOK_GLOBAL,                         /* GLOBAL keyword */
140     TOK_ID,                             /* ID keyword */
141     TOK_IMPORT,                         /* IMPORT keyword */
142     TOK_INFO,                           /* INFO keyword */
143     TOK_LABEL,                          /* LABEL keyword */
144     TOK_LIBRARY,                        /* LIBRARY keyword */
145     TOK_LINE,                           /* LINE keyword */
146     TOK_LONG,                           /* LONG_keyword */
147     TOK_MAJOR,                          /* MAJOR keyword */
148     TOK_MINOR,                          /* MINOR keyword */
149     TOK_MODULE,                         /* MODULE keyword */
150     TOK_MTIME,                          /* MTIME keyword */
151     TOK_NAME,                           /* NAME keyword */
152     TOK_OFFS,                           /* OFFS keyword */
153     TOK_OUTPUTNAME,                     /* OUTPUTNAME keyword */
154     TOK_OUTPUTOFFS,                     /* OUTPUTOFFS keyword */
155     TOK_PARENT,                         /* PARENT keyword */
156     TOK_REF,                            /* REF keyword */
157     TOK_REGISTER,                       /* REGISTER keyword */
158     TOK_RO,                             /* RO keyword */
159     TOK_RW,                             /* RW keyword */
160     TOK_SC,                             /* SC keyword */
161     TOK_SCOPE,                          /* SCOPE keyword */
162     TOK_SEGMENT,                        /* SEGMENT keyword */
163     TOK_SIZE,                           /* SIZE keyword */
164     TOK_SPAN,                           /* SPAN keyword */
165     TOK_START,                          /* START keyword */
166     TOK_STATIC,                         /* STATIC keyword */
167     TOK_STRUCT,                         /* STRUCT keyword */
168     TOK_SYM,                            /* SYM keyword */
169     TOK_TYPE,                           /* TYPE keyword */
170     TOK_VALUE,                          /* VALUE keyword */
171     TOK_VAR,                            /* VAR keyword */
172     TOK_VERSION,                        /* VERSION keyword */
173     TOK_ZEROPAGE,                       /* ZEROPAGE keyword */
174     TOK_LAST_KEYWORD = TOK_ZEROPAGE,
175
176     TOK_IDENT,                          /* To catch unknown keywords */
177 } Token;
178
179 /* Data structure containing information from the debug info file. A pointer
180 ** to this structure is passed as handle to callers from the outside.
181 */
182 typedef struct DbgInfo DbgInfo;
183 struct DbgInfo {
184
185     /* First we have all items in collections sorted by id. The ids are
186     ** continous, so an access by id is almost as cheap as an array access.
187     ** The collections are also used when the objects are deleted, so they're
188     ** actually the ones that "own" the items.
189     */
190     Collection          CSymInfoById;   /* C symbol infos sorted by id */
191     Collection          FileInfoById;   /* File infos sorted by id */
192     Collection          LibInfoById;    /* Library infos sorted by id */
193     Collection          LineInfoById;   /* Line infos sorted by id */
194     Collection          ModInfoById;    /* Module infos sorted by id */
195     Collection          ScopeInfoById;  /* Scope infos sorted by id */
196     Collection          SegInfoById;    /* Segment infos sorted by id */
197     Collection          SpanInfoById;   /* Span infos sorted by id */
198     Collection          SymInfoById;    /* Symbol infos sorted by id */
199     Collection          TypeInfoById;   /* Type infos sorted by id */
200
201     /* Collections with other sort criteria */
202     Collection          CSymFuncByName; /* C functions sorted by name */
203     Collection          FileInfoByName; /* File infos sorted by name */
204     Collection          ModInfoByName;  /* Module info sorted by name */
205     Collection          ScopeInfoByName;/* Scope infos sorted by name */
206     Collection          SegInfoByName;  /* Segment infos sorted by name */
207     Collection          SymInfoByName;  /* Symbol infos sorted by name */
208     Collection          SymInfoByVal;   /* Symbol infos sorted by value */
209
210     /* Other stuff */
211     SpanInfoList        SpanInfoByAddr; /* Span infos sorted by unique address */
212
213     /* Info data */
214     unsigned long       MemUsage;       /* Memory usage for the data */
215     unsigned            MajorVersion;   /* Major version number of loaded file */
216     unsigned            MinorVersion;   /* Minor version number of loaded file */
217     char                FileName[1];    /* Name of input file */
218 };
219
220 /* Data used when parsing the debug info file */
221 typedef struct InputData InputData;
222 struct InputData {
223     const char*         FileName;       /* Name of input file */
224     cc65_line           Line;           /* Current line number */
225     unsigned            Col;            /* Current column number */
226     cc65_line           SLine;          /* Line number at start of token */
227     unsigned            SCol;           /* Column number at start of token */
228     unsigned            Errors;         /* Number of errors */
229     FILE*               F;              /* Input file */
230     int                 C;              /* Input character */
231     Token               Tok;            /* Token from input stream */
232     unsigned long       IVal;           /* Integer constant */
233     StrBuf              SVal;           /* String constant */
234     cc65_errorfunc      Error;          /* Function called in case of errors */
235     DbgInfo*            Info;           /* Pointer to debug info */
236 };
237
238 /* Typedefs for the item structures. Do also serve as forwards */
239 typedef struct CSymInfo CSymInfo;
240 typedef struct FileInfo FileInfo;
241 typedef struct LibInfo LibInfo;
242 typedef struct LineInfo LineInfo;
243 typedef struct ModInfo ModInfo;
244 typedef struct ScopeInfo ScopeInfo;
245 typedef struct SegInfo SegInfo;
246 typedef struct SpanInfo SpanInfo;
247 typedef struct SymInfo SymInfo;
248 typedef struct TypeInfo TypeInfo;
249
250 /* Internally used c symbol info struct */
251 struct CSymInfo {
252     unsigned            Id;             /* Id of file */
253     unsigned short      Kind;           /* Kind of C symbol */
254     unsigned short      SC;             /* Storage class of C symbol */
255     int                 Offs;           /* Offset */
256     union {
257         unsigned        Id;             /* Id of attached asm symbol */
258         SymInfo*        Info;           /* Pointer to attached asm symbol */
259     } Sym;
260     union {
261         unsigned        Id;             /* Id of type */
262         TypeInfo*       Info;           /* Pointer to type */
263     } Type;
264     union {
265         unsigned        Id;             /* Id of scope */
266         ScopeInfo*      Info;           /* Pointer to scope */
267     } Scope;
268     char                Name[1];        /* Name of file with full path */
269 };
270
271 /* Internally used file info struct */
272 struct FileInfo {
273     unsigned            Id;             /* Id of file */
274     unsigned long       Size;           /* Size of file */
275     unsigned long       MTime;          /* Modification time */
276     Collection          ModInfoByName;  /* Modules in which this file is used */
277     Collection          LineInfoByLine; /* Line infos sorted by line */
278     char                Name[1];        /* Name of file with full path */
279 };
280
281 /* Internally used library info struct */
282 struct LibInfo {
283     unsigned            Id;             /* Id of library */
284     char                Name[1];        /* Name of library with path */
285 };
286
287 /* Internally used line info struct */
288 struct LineInfo {
289     unsigned            Id;             /* Id of line info */
290     cc65_line           Line;           /* Line number */
291     union {
292         unsigned        Id;             /* Id of file */
293         FileInfo*       Info;           /* Pointer to file info */
294     } File;
295     cc65_line_type      Type;           /* Type of line */
296     unsigned            Count;          /* Nesting counter for macros */
297     Collection          SpanInfoList;   /* List of spans for this line */
298 };
299
300 /* Internally used module info struct */
301 struct ModInfo {
302     unsigned            Id;             /* Id of library */
303     union {
304         unsigned        Id;             /* Id of main source file */
305         FileInfo*       Info;           /* Pointer to file info */
306     } File;
307     union {
308         unsigned        Id;             /* Id of library if any */
309         LibInfo*        Info;           /* Pointer to library info */
310     } Lib;
311     ScopeInfo*          MainScope;      /* Pointer to main scope */
312     Collection          CSymFuncByName; /* C functions by name */
313     Collection          FileInfoByName; /* Files for this module */
314     Collection          ScopeInfoByName;/* Scopes for this module */
315     char                Name[1];        /* Name of module with path */
316 };
317
318 /* Internally used scope info struct */
319 struct ScopeInfo {
320     unsigned            Id;             /* Id of scope */
321     cc65_scope_type     Type;           /* Type of scope */
322     cc65_size           Size;           /* Size of scope */
323     union {
324         unsigned        Id;             /* Id of module */
325         ModInfo*        Info;           /* Pointer to module info */
326     } Mod;
327     union {
328         unsigned        Id;             /* Id of parent scope */
329         ScopeInfo*      Info;           /* Pointer to parent scope */
330     } Parent;
331     union {
332         unsigned        Id;             /* Id of label symbol */
333         SymInfo*        Info;           /* Pointer to label symbol */
334     } Label;
335     CSymInfo*           CSymFunc;       /* C function for this scope */
336     Collection          SpanInfoList;   /* List of spans for this scope */
337     Collection          SymInfoByName;  /* Symbols in this scope */
338     Collection*         CSymInfoByName; /* C symbols for this scope */
339     Collection*         ChildScopeList; /* Child scopes of this scope */
340     char                Name[1];        /* Name of scope */
341 };
342
343 /* Internally used segment info struct */
344 struct SegInfo {
345     unsigned            Id;             /* Id of segment */
346     cc65_addr           Start;          /* Start address of segment */
347     cc65_size           Size;           /* Size of segment */
348     char*               OutputName;     /* Name of output file */
349     unsigned long       OutputOffs;     /* Offset in output file */
350     char                Name[1];        /* Name of segment */
351 };
352
353 /* Internally used span info struct */
354 struct SpanInfo {
355     unsigned            Id;             /* Id of span */
356     cc65_addr           Start;          /* Start of span */
357     cc65_addr           End;            /* End of span */
358     union {
359         unsigned        Id;             /* Id of segment */
360         SegInfo*        Info;           /* Pointer to segment */
361     } Seg;
362     union {
363         unsigned        Id;             /* Id of type */
364         TypeInfo*       Info;           /* Pointer to type */
365     } Type;
366     Collection*         ScopeInfoList;  /* Scopes for this span */
367     Collection*         LineInfoList;   /* Lines for this span */
368 };
369
370 /* Internally used symbol info struct */
371 struct SymInfo {
372     unsigned            Id;             /* Id of symbol */
373     cc65_symbol_type    Type;           /* Type of symbol */
374     long                Value;          /* Value of symbol */
375     cc65_size           Size;           /* Size of symbol */
376     union {
377         unsigned        Id;             /* Id of export if any */
378         SymInfo*        Info;           /* Pointer to export if any */
379     } Exp;
380     union {
381         unsigned        Id;             /* Id of segment if any */
382         SegInfo*        Info;           /* Pointer to segment if any */
383     } Seg;
384     union {
385         unsigned        Id;             /* Id of symbol scope */
386         ScopeInfo*      Info;           /* Pointer to symbol scope */
387     } Scope;
388     union {
389         unsigned        Id;             /* Parent symbol if any */
390         SymInfo*        Info;           /* Pointer to parent symbol if any */
391     } Parent;
392     CSymInfo*           CSym;           /* Corresponding C symbol */
393     Collection*         ImportList;     /* List of imports if this is an export */
394     Collection*         CheapLocals;    /* List of cheap local symbols */
395     Collection          DefLineInfoList;/* Line info of symbol definition */
396     Collection          RefLineInfoList;/* Line info of symbol references */
397     char                Name[1];        /* Name of symbol */
398 };
399
400 /* Internally used type info struct */
401 struct TypeInfo {
402     unsigned            Id;             /* Id of type */
403     cc65_typedata       Data[1];        /* Data, dynamically allocated */
404 };
405
406 /* A structure used when parsing a type string into a set of cc65_typedata
407 ** structures.
408 */
409 typedef struct TypeParseData TypeParseData;
410 struct TypeParseData {
411     TypeInfo*           Info;
412     unsigned            ItemCount;
413     unsigned            ItemIndex;
414     cc65_typedata*      ItemData;
415     const StrBuf*       Type;
416     unsigned            Pos;
417     unsigned            Error;
418 };
419
420
421
422 /*****************************************************************************/
423 /*                                 Forwards                                  */
424 /*****************************************************************************/
425
426
427
428 static void NextToken (InputData* D);
429 /* Read the next token from the input stream */
430
431
432
433 /*****************************************************************************/
434 /*                             Memory allocation                             */
435 /*****************************************************************************/
436
437
438
439 static void* xmalloc (size_t Size)
440 /* Allocate memory, check for out of memory condition. Do some debugging */
441 {
442     void* P = 0;
443
444     /* Allow zero sized requests and return NULL in this case */
445     if (Size) {
446
447         /* Allocate memory */
448         P = malloc (Size);
449
450         /* Check for errors */
451         assert (P != 0);
452     }
453
454     /* Return a pointer to the block */
455     return P;
456 }
457
458
459
460 static void* xrealloc (void* P, size_t Size)
461 /* Reallocate a memory block, check for out of memory */
462 {
463     /* Reallocate the block */
464     void* N = realloc (P, Size);
465
466     /* Check for errors */
467     assert (N != 0 || Size == 0);
468
469     /* Return the pointer to the new block */
470     return N;
471 }
472
473
474
475 static void xfree (void* Block)
476 /* Free the block, do some debugging */
477 {
478     free (Block);
479 }
480
481
482
483 /*****************************************************************************/
484 /*                              Dynamic strings                              */
485 /*****************************************************************************/
486
487
488
489 static void SB_Done (StrBuf* B)
490 /* Free the data of a string buffer (but not the struct itself) */
491 {
492     if (B->Allocated) {
493         xfree (B->Buf);
494     }
495 }
496
497
498
499 static void SB_Realloc (StrBuf* B, unsigned NewSize)
500 /* Reallocate the string buffer space, make sure at least NewSize bytes are
501 ** available.
502 */
503 {
504     /* Get the current size, use a minimum of 8 bytes */
505     unsigned NewAllocated = B->Allocated;
506     if (NewAllocated == 0) {
507         NewAllocated = 8;
508     }
509
510     /* Round up to the next power of two */
511     while (NewAllocated < NewSize) {
512         NewAllocated *= 2;
513     }
514
515     /* Reallocate the buffer. Beware: The allocated size may be zero while the
516     ** length is not. This means that we have a buffer that wasn't allocated
517     ** on the heap.
518     */
519     if (B->Allocated) {
520         /* Just reallocate the block */
521         B->Buf = xrealloc (B->Buf, NewAllocated);
522     } else {
523         /* Allocate a new block and copy */
524         B->Buf = memcpy (xmalloc (NewAllocated), B->Buf, B->Len);
525     }
526
527     /* Remember the new block size */
528     B->Allocated = NewAllocated;
529 }
530
531
532
533 static void SB_CheapRealloc (StrBuf* B, unsigned NewSize)
534 /* Reallocate the string buffer space, make sure at least NewSize bytes are
535 ** available. This function won't copy the old buffer contents over to the new
536 ** buffer and may be used if the old contents are overwritten later.
537 */
538 {
539     /* Get the current size, use a minimum of 8 bytes */
540     unsigned NewAllocated = B->Allocated;
541     if (NewAllocated == 0) {
542         NewAllocated = 8;
543     }
544
545     /* Round up to the next power of two */
546     while (NewAllocated < NewSize) {
547         NewAllocated *= 2;
548     }
549
550     /* Free the old buffer if there is one */
551     if (B->Allocated) {
552         xfree (B->Buf);
553     }
554
555     /* Allocate a fresh block */
556     B->Buf = xmalloc (NewAllocated);
557
558     /* Remember the new block size */
559     B->Allocated = NewAllocated;
560 }
561
562
563
564 static unsigned SB_GetLen (const StrBuf* B)
565 /* Return the length of the buffer contents */
566 {
567     return B->Len;
568 }
569
570
571
572 static char* SB_GetBuf (StrBuf* B)
573 /* Return a buffer pointer */
574 {
575     return B->Buf;
576 }
577
578
579
580 static const char* SB_GetConstBuf (const StrBuf* B)
581 /* Return a buffer pointer */
582 {
583     return B->Buf;
584 }
585
586
587
588 static char SB_At (const StrBuf* B, unsigned Pos)
589 /* Return the character from a specific position */
590 {
591     assert (Pos <= B->Len);
592     return B->Buf[Pos];
593 }
594
595
596
597 static void SB_Terminate (StrBuf* B)
598 /* Zero terminate the given string buffer. NOTE: The terminating zero is not
599 ** accounted for in B->Len, if you want that, you have to use AppendChar!
600 */
601 {
602     unsigned NewLen = B->Len + 1;
603     if (NewLen > B->Allocated) {
604         SB_Realloc (B, NewLen);
605     }
606     B->Buf[B->Len] = '\0';
607 }
608
609
610
611 static void SB_Clear (StrBuf* B)
612 /* Clear the string buffer (make it empty) */
613 {
614     B->Len = 0;
615 }
616
617
618
619 static void SB_CopyBuf (StrBuf* Target, const char* Buf, unsigned Size)
620 /* Copy Buf to Target, discarding the old contents of Target */
621 {
622     if (Size) {
623         if (Target->Allocated < Size) {
624             SB_CheapRealloc (Target, Size);
625         }
626         memcpy (Target->Buf, Buf, Size);
627     }
628     Target->Len = Size;
629 }
630
631
632
633 static void SB_Copy (StrBuf* Target, const StrBuf* Source)
634 /* Copy Source to Target, discarding the old contents of Target */
635 {
636     SB_CopyBuf (Target, Source->Buf, Source->Len);
637 }
638
639
640
641 static void SB_AppendChar (StrBuf* B, int C)
642 /* Append a character to a string buffer */
643 {
644     unsigned NewLen = B->Len + 1;
645     if (NewLen > B->Allocated) {
646         SB_Realloc (B, NewLen);
647     }
648     B->Buf[B->Len] = (char) C;
649     B->Len = NewLen;
650 }
651
652
653
654 static char* SB_StrDup (const StrBuf* B)
655 /* Return the contents of B as a dynamically allocated string. The string
656 ** will always be NUL terminated.
657 */
658 {
659     /* Allocate memory */
660     char* S = xmalloc (B->Len + 1);
661
662     /* Copy the string */
663     memcpy (S, B->Buf, B->Len);
664
665     /* Terminate it */
666     S[B->Len] = '\0';
667
668     /* And return the result */
669     return S;
670 }
671
672
673
674 /*****************************************************************************/
675 /*                                Collections                                */
676 /*****************************************************************************/
677
678
679
680 static Collection* CollInit (Collection* C)
681 /* Initialize a collection and return it. */
682 {
683     /* Intialize the fields. */
684     C->Count = 0;
685     C->Size  = 0;
686     C->Items = 0;
687
688     /* Return the new struct */
689     return C;
690 }
691
692
693
694 static Collection* CollNew (void)
695 /* Allocate a new collection, initialize and return it */
696 {
697     return CollInit (xmalloc (sizeof (Collection)));
698 }
699
700
701
702 static void CollDone (Collection* C)
703 /* Free the data for a collection. This will not free the data contained in
704 ** the collection.
705 */
706 {
707     /* Free the pointer array */
708     xfree (C->Items);
709
710     /* Clear the fields, so the collection may be reused (or CollDone called)
711     ** again
712     */
713     C->Count = 0;
714     C->Size  = 0;
715     C->Items = 0;
716 }
717
718
719
720 static void CollFree (Collection* C)
721 /* Free a dynamically allocated collection */
722 {
723     /* Accept NULL pointers */
724     if (C) {
725         xfree (C->Items);
726         xfree (C);
727     }
728 }
729
730
731
732 static unsigned CollCount (const Collection* C)
733 /* Return the number of items in the collection. Return 0 if C is NULL. */
734 {
735     return C? C->Count : 0;
736 }
737
738
739
740 static void CollMove (Collection* Source, Collection* Target)
741 /* Move all data from one collection to another. This function will first free
742 ** the data in the target collection, and - after the move - clear the data
743 ** from the source collection.
744 */
745 {
746     /* Free the target collection data */
747     xfree (Target->Items);
748
749     /* Now copy the whole bunch over */
750     *Target = *Source;
751
752     /* Empty Source */
753     Source->Count = 0;
754     Source->Size  = 0;
755     Source->Items = 0;
756 }
757
758
759
760 static void CollGrow (Collection* C, unsigned Size)
761 /* Grow the collection C so it is able to hold Size items without a resize
762 ** being necessary. This can be called for performance reasons if the number
763 ** of items to be placed in the collection is known in advance.
764 */
765 {
766     CollEntry* NewItems;
767
768     /* Ignore the call if the collection is already large enough */
769     if (Size <= C->Size) {
770         return;
771     }
772
773     /* Grow the collection */
774     C->Size = Size;
775     NewItems = xmalloc (C->Size * sizeof (CollEntry));
776     memcpy (NewItems, C->Items, C->Count * sizeof (CollEntry));
777     xfree (C->Items);
778     C->Items = NewItems;
779 }
780
781
782
783 static void CollPrepareInsert (Collection* C, unsigned Index)
784 /* Prepare for insertion of the data at a given position in the collection */
785 {
786     /* Check for invalid indices */
787     assert (Index <= C->Count);
788
789     /* Grow the array if necessary */
790     if (C->Count >= C->Size) {
791         /* Must grow */
792         CollGrow (C, (C->Size == 0)? 1 : C->Size * 2);
793     }
794
795     /* Move the existing elements if needed */
796     if (C->Count != Index) {
797         memmove (C->Items+Index+1, C->Items+Index, (C->Count-Index) * sizeof (void*));
798     }
799     ++C->Count;
800 }
801
802
803
804 static void CollInsert (Collection* C, void* Item, unsigned Index)
805 /* Insert the data at the given position in the collection */
806 {
807     /* Prepare for insertion (free the given slot) */
808     CollPrepareInsert (C, Index);
809
810     /* Store the new item */
811     C->Items[Index].Ptr = Item;
812 }
813
814
815
816 static void CollInsertId (Collection* C, unsigned Id, unsigned Index)
817 /* Insert the data at the given position in the collection */
818 {
819     /* Prepare for insertion (free the given slot) */
820     CollPrepareInsert (C, Index);
821
822     /* Store the new item */
823     C->Items[Index].Id = Id;
824 }
825
826
827
828 static void CollReplace (Collection* C, void* Item, unsigned Index)
829 /* Replace the item at the given position by a new one */
830 {
831     /* Check the index */
832     assert (Index < C->Count);
833
834     /* Replace the element */
835     C->Items[Index].Ptr = Item;
836 }
837
838
839
840 static void CollReplaceExpand (Collection* C, void* Item, unsigned Index)
841 /* If Index is a valid index for the collection, replace the item at this
842 ** position by the one passed. If the collection is too small, expand it,
843 ** filling unused pointers with NULL, then add the new item at the given
844 ** position.
845 */
846 {
847     if (Index < C->Count) {
848         /* Collection is already large enough */
849         C->Items[Index].Ptr = Item;
850     } else {
851         /* Must expand the collection */
852         unsigned Size = C->Size;
853         if (Size == 0) {
854             Size = 2;
855         }
856         while (Index >= Size) {
857             Size *= 2;
858         }
859         CollGrow (C, Size);
860
861         /* Fill up unused slots with NULL */
862         while (C->Count < Index) {
863             C->Items[C->Count++].Ptr = 0;
864         }
865
866         /* Fill in the item */
867         C->Items[C->Count++].Ptr = Item;
868     }
869 }
870
871
872
873 static void CollAppend (Collection* C, void* Item)
874 /* Append an item to the end of the collection */
875 {
876     /* Insert the item at the end of the current list */
877     CollInsert (C, Item, C->Count);
878 }
879
880
881
882 static void CollAppendId (Collection* C, unsigned Id)
883 /* Append an id to the end of the collection */
884 {
885     /* Insert the id at the end of the current list */
886     CollInsertId (C, Id, C->Count);
887 }
888
889
890
891 static void* CollAt (const Collection* C, unsigned Index)
892 /* Return the item at the given index */
893 {
894     /* Check the index */
895     assert (Index < C->Count);
896
897     /* Return the element */
898     return C->Items[Index].Ptr;
899 }
900
901
902
903 static unsigned CollIdAt (const Collection* C, unsigned Index)
904 /* Return the id at the given index */
905 {
906     /* Check the index */
907     assert (Index < C->Count);
908
909     /* Return the element */
910     return C->Items[Index].Id;
911 }
912
913
914
915 static void CollQuickSort (Collection* C, int Lo, int Hi,
916                            int (*Compare) (const void*, const void*))
917 /* Internal recursive sort function. */
918 {
919     /* Get a pointer to the items */
920     CollEntry* Items = C->Items;
921
922     /* Quicksort */
923     while (Hi > Lo) {
924         int I = Lo + 1;
925         int J = Hi;
926         while (I <= J) {
927             while (I <= J && Compare (Items[Lo].Ptr, Items[I].Ptr) >= 0) {
928                 ++I;
929             }
930             while (I <= J && Compare (Items[Lo].Ptr, Items[J].Ptr) < 0) {
931                 --J;
932             }
933             if (I <= J) {
934                 /* Swap I and J */
935                 CollEntry Tmp = Items[I];
936                 Items[I]  = Items[J];
937                 Items[J]  = Tmp;
938                 ++I;
939                 --J;
940             }
941         }
942         if (J != Lo) {
943             /* Swap J and Lo */
944             CollEntry Tmp = Items[J];
945             Items[J]  = Items[Lo];
946             Items[Lo] = Tmp;
947         }
948         if (J > (Hi + Lo) / 2) {
949             CollQuickSort (C, J + 1, Hi, Compare);
950             Hi = J - 1;
951         } else {
952             CollQuickSort (C, Lo, J - 1, Compare);
953             Lo = J + 1;
954         }
955     }
956 }
957
958
959
960 static void CollSort (Collection* C, int (*Compare) (const void*, const void*))
961 /* Sort the collection using the given compare function. */
962 {
963     if (C->Count > 1) {
964         CollQuickSort (C, 0, C->Count-1, Compare);
965     }
966 }
967
968
969
970 /*****************************************************************************/
971 /*                              Debugging stuff                              */
972 /*****************************************************************************/
973
974
975
976 #if DEBUG
977
978 /* Output */
979 #define DBGPRINT(format, ...)   printf ((format), __VA_ARGS__)
980
981
982
983 static void DumpFileInfo (Collection* FileInfos)
984 /* Dump a list of file infos */
985 {
986     unsigned I;
987
988     /* File info */
989     for (I = 0; I < CollCount (FileInfos); ++I) {
990         const FileInfo* FI = CollAt (FileInfos, I);
991         printf ("File info %u:\n"
992                 "  Name:   %s\n"
993                 "  Size:   %lu\n"
994                 "  MTime:  %lu\n",
995                 FI->Id,
996                 FI->Name,
997                 (unsigned long) FI->Size,
998                 (unsigned long) FI->MTime);
999     }
1000 }
1001
1002
1003
1004 static void DumpOneLineInfo (unsigned Num, LineInfo* LI)
1005 /* Dump one line info entry */
1006 {
1007     printf ("  Index:  %u\n"
1008             "    File:   %s\n"
1009             "    Line:   %lu\n"
1010             "    Range:  0x%06lX-0x%06lX\n"
1011             "    Type:   %u\n"
1012             "    Count:  %u\n",
1013             Num,
1014             LI->File.Info->Name,
1015             (unsigned long) LI->Line,
1016             (unsigned long) LI->Start,
1017             (unsigned long) LI->End,
1018             LI->Type,
1019             LI->Count);
1020 }
1021
1022
1023
1024 static void DumpSpanInfo (SpanInfoList* L)
1025 /* Dump a list of span infos */
1026 {
1027     unsigned I, J;
1028
1029     /* Line info */
1030     for (I = 0; I < L->Count; ++I) {
1031         const SpanInfoListEntry* E = &L->List[I];
1032         printf ("Addr:   %lu\n", (unsigned long) E->Addr);
1033         if (E->Count == 1) {
1034             DumpOneLineInfo (0, E->Data);
1035         } else {
1036             for (J = 0; J < E->Count; ++J) {
1037                 DumpOneLineInfo (J, ((LineInfo**) E->Data)[J]);
1038             }
1039         }
1040     }
1041 }
1042
1043
1044
1045 static void DumpData (InputData* D)
1046 /* Dump internal data to stdout for debugging */
1047 {
1048     /* Dump data */
1049     DumpFileInfo (&D->Info->FileInfoById);
1050     DumpLineInfo (&D->Info->LineInfoByAddr);
1051 }
1052 #else
1053
1054 /* No output */
1055 #ifdef __WATCOMC__
1056 static void DBGPRINT(const char* format, ...) {}
1057 #else
1058 #define DBGPRINT(format, ...)
1059 #endif
1060
1061 #endif
1062
1063
1064
1065 /*****************************************************************************/
1066 /*                             Helper functions                              */
1067 /*****************************************************************************/
1068
1069
1070
1071 static unsigned GetId (const void* Data)
1072 /* Return the id of one of the info structures. All structures have the Id
1073 ** field as first member, and the C standard allows converting a union pointer
1074 ** to the data type of the first member, so this is safe and portable.
1075 */
1076 {
1077     if (Data) {
1078         return *(const unsigned*)Data;
1079     } else {
1080         return CC65_INV_ID;
1081     }
1082 }
1083
1084
1085
1086 static unsigned HexValue (char C)
1087 /* Convert the ascii representation of a hex nibble into the hex nibble */
1088 {
1089     if (isdigit (C)) {
1090         return C - '0';
1091     } else if (islower (C)) {
1092         return C - 'a' + 10;
1093     } else {
1094         return C - 'A' + 10;
1095     }
1096 }
1097
1098
1099
1100 static void ParseError (InputData* D, cc65_error_severity Type, const char* Msg, ...)
1101 /* Call the user supplied parse error function */
1102 {
1103     va_list             ap;
1104     int                 MsgSize;
1105     cc65_parseerror*    E;
1106
1107     /* Test-format the error message so we know how much space to allocate */
1108     va_start (ap, Msg);
1109     MsgSize = vsnprintf (0, 0, Msg, ap);
1110     va_end (ap);
1111
1112     /* Allocate memory */
1113     E = xmalloc (sizeof (*E) + MsgSize);
1114
1115     /* Write data to E */
1116     E->type   = Type;
1117     E->name   = D->FileName;
1118     E->line   = D->SLine;
1119     E->column = D->SCol;
1120     va_start (ap, Msg);
1121     vsnprintf (E->errormsg, MsgSize+1, Msg, ap);
1122     va_end (ap);
1123
1124     /* Call the caller:-) */
1125     D->Error (E);
1126
1127     /* Free the data structure */
1128     xfree (E);
1129
1130     /* Count errors */
1131     if (Type == CC65_ERROR) {
1132         ++D->Errors;
1133     }
1134 }
1135
1136
1137
1138 static void SkipLine (InputData* D)
1139 /* Error recovery routine. Skip tokens until EOL or EOF is reached */
1140 {
1141     while (D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
1142         NextToken (D);
1143     }
1144 }
1145
1146
1147
1148 static void UnexpectedToken (InputData* D)
1149 /* Call ParseError with a message about an unexpected input token */
1150 {
1151     ParseError (D, CC65_ERROR, "Unexpected input token %d", D->Tok);
1152     SkipLine (D);
1153 }
1154
1155
1156
1157 static void UnknownKeyword (InputData* D)
1158 /* Print a warning about an unknown keyword in the file. Try to do smart
1159 ** recovery, so if later versions of the debug information add additional
1160 ** keywords, this code may be able to at least ignore them.
1161 */
1162 {
1163     /* Output a warning */
1164     ParseError (D, CC65_WARNING, "Unknown keyword \"%s\" - skipping",
1165                 SB_GetConstBuf (&D->SVal));
1166
1167     /* Skip the identifier */
1168     NextToken (D);
1169
1170     /* If an equal sign follows, ignore anything up to the next line end
1171     ** or comma. If a comma or line end follows, we're already done. If
1172     ** we have none of both, we ignore the remainder of the line.
1173     */
1174     if (D->Tok == TOK_EQUAL) {
1175         NextToken (D);
1176         while (D->Tok != TOK_COMMA && D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
1177             NextToken (D);
1178         }
1179     } else if (D->Tok != TOK_COMMA && D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
1180         SkipLine (D);
1181     }
1182 }
1183
1184
1185
1186 /*****************************************************************************/
1187 /*                               C symbol info                               */
1188 /*****************************************************************************/
1189
1190
1191
1192 static CSymInfo* NewCSymInfo (const StrBuf* Name)
1193 /* Create a new CSymInfo struct and return it */
1194 {
1195     /* Allocate memory */
1196     CSymInfo* S = xmalloc (sizeof (CSymInfo) + SB_GetLen (Name));
1197
1198     /* Initialize it */
1199     memcpy (S->Name, SB_GetConstBuf (Name), SB_GetLen (Name) + 1);
1200
1201     /* Return it */
1202     return S;
1203 }
1204
1205
1206
1207 static void FreeCSymInfo (CSymInfo* S)
1208 /* Free a CSymInfo struct */
1209 {
1210     /* Free the structure itself */
1211     xfree (S);
1212 }
1213
1214
1215
1216 static cc65_csyminfo* new_cc65_csyminfo (unsigned Count)
1217 /* Allocate and return a cc65_csyminfo struct that is able to hold Count
1218 ** entries. Initialize the count field of the returned struct.
1219 */
1220 {
1221     cc65_csyminfo* S = xmalloc (sizeof (*S) - sizeof (S->data[0]) +
1222                                 Count * sizeof (S->data[0]));
1223     S->count = Count;
1224     return S;
1225 }
1226
1227
1228
1229 static void CopyCSymInfo (cc65_csymdata* D, const CSymInfo* S)
1230 /* Copy data from a CSymInfo struct to a cc65_csymdata struct */
1231 {
1232     D->csym_id      = S->Id;
1233     D->csym_kind    = S->Kind;
1234     D->csym_sc      = S->SC;
1235     D->csym_offs    = S->Offs;
1236     D->type_id      = GetId (S->Type.Info);
1237     D->symbol_id    = GetId (S->Sym.Info);
1238     D->scope_id     = GetId (S->Scope.Info);
1239     D->csym_name    = S->Name;
1240 }
1241
1242
1243
1244 static int CompareCSymInfoByName (const void* L, const void* R)
1245 /* Helper function to sort c symbol infos in a collection by name */
1246 {
1247     /* Sort by symbol name, then by id */
1248     int Res = strcmp (((const CSymInfo*) L)->Name, ((const CSymInfo*) R)->Name);
1249     if (Res == 0) {
1250         Res = (int)((const CSymInfo*) L)->Id - (int)((const CSymInfo*) R)->Id;
1251     }
1252     return Res;
1253 }
1254
1255
1256
1257 /*****************************************************************************/
1258 /*                                 File info                                 */
1259 /*****************************************************************************/
1260
1261
1262
1263 static FileInfo* NewFileInfo (const StrBuf* Name)
1264 /* Create a new FileInfo struct and return it */
1265 {
1266     /* Allocate memory */
1267     FileInfo* F = xmalloc (sizeof (FileInfo) + SB_GetLen (Name));
1268
1269     /* Initialize it */
1270     CollInit (&F->ModInfoByName);
1271     CollInit (&F->LineInfoByLine);
1272     memcpy (F->Name, SB_GetConstBuf (Name), SB_GetLen (Name) + 1);
1273
1274     /* Return it */
1275     return F;
1276 }
1277
1278
1279
1280 static void FreeFileInfo (FileInfo* F)
1281 /* Free a FileInfo struct */
1282 {
1283     /* Delete the collections */
1284     CollDone (&F->ModInfoByName);
1285     CollDone (&F->LineInfoByLine);
1286
1287     /* Free the file info structure itself */
1288     xfree (F);
1289 }
1290
1291
1292
1293 static cc65_sourceinfo* new_cc65_sourceinfo (unsigned Count)
1294 /* Allocate and return a cc65_sourceinfo struct that is able to hold Count
1295 ** entries. Initialize the count field of the returned struct.
1296 */
1297 {
1298     cc65_sourceinfo* S = xmalloc (sizeof (*S) - sizeof (S->data[0]) +
1299                                   Count * sizeof (S->data[0]));
1300     S->count = Count;
1301     return S;
1302 }
1303
1304
1305
1306 static void CopyFileInfo (cc65_sourcedata* D, const FileInfo* F)
1307 /* Copy data from a FileInfo struct to a cc65_sourcedata struct */
1308 {
1309     D->source_id    = F->Id;
1310     D->source_name  = F->Name;
1311     D->source_size  = F->Size;
1312     D->source_mtime = F->MTime;
1313 }
1314
1315
1316
1317 static int CompareFileInfoByName (const void* L, const void* R)
1318 /* Helper function to sort file infos in a collection by name */
1319 {
1320     /* Sort by file name. If names are equal, sort by timestamp,
1321     ** then sort by size. Which means, identical files will go
1322     ** together.
1323     */
1324     int Res = strcmp (((const FileInfo*) L)->Name,
1325                       ((const FileInfo*) R)->Name);
1326     if (Res != 0) {
1327         return Res;
1328     }
1329     if (((const FileInfo*) L)->MTime > ((const FileInfo*) R)->MTime) {
1330         return 1;
1331     } else if (((const FileInfo*) L)->MTime < ((const FileInfo*) R)->MTime) {
1332         return -1;
1333     }
1334     if (((const FileInfo*) L)->Size > ((const FileInfo*) R)->Size) {
1335         return 1;
1336     } else if (((const FileInfo*) L)->Size < ((const FileInfo*) R)->Size) {
1337         return -1;
1338     } else {
1339         return 0;
1340     }
1341 }
1342
1343
1344
1345 /*****************************************************************************/
1346 /*                               Library info                                */
1347 /*****************************************************************************/
1348
1349
1350
1351 static LibInfo* NewLibInfo (const StrBuf* Name)
1352 /* Create a new LibInfo struct, intialize and return it */
1353 {
1354     /* Allocate memory */
1355     LibInfo* L = xmalloc (sizeof (LibInfo) + SB_GetLen (Name));
1356
1357     /* Initialize the name */
1358     memcpy (L->Name, SB_GetConstBuf (Name), SB_GetLen (Name) + 1);
1359
1360     /* Return it */
1361     return L;
1362 }
1363
1364
1365
1366 static void FreeLibInfo (LibInfo* L)
1367 /* Free a LibInfo struct */
1368 {
1369     xfree (L);
1370 }
1371
1372
1373
1374 static cc65_libraryinfo* new_cc65_libraryinfo (unsigned Count)
1375 /* Allocate and return a cc65_libraryinfo struct that is able to hold Count
1376 ** entries. Initialize the count field of the returned struct.
1377 */
1378 {
1379     cc65_libraryinfo* L = xmalloc (sizeof (*L) - sizeof (L->data[0]) +
1380                                    Count * sizeof (L->data[0]));
1381     L->count = Count;
1382     return L;
1383 }
1384
1385
1386
1387 static void CopyLibInfo (cc65_librarydata* D, const LibInfo* L)
1388 /* Copy data from a LibInfo struct to a cc65_librarydata struct */
1389 {
1390     D->library_id   = L->Id;
1391     D->library_name = L->Name;
1392 }
1393
1394
1395
1396 /*****************************************************************************/
1397 /*                                 Line info                                 */
1398 /*****************************************************************************/
1399
1400
1401
1402 static LineInfo* NewLineInfo (void)
1403 /* Create a new LineInfo struct and return it */
1404 {
1405     /* Allocate memory */
1406     LineInfo* L = xmalloc (sizeof (LineInfo));
1407
1408     /* Initialize and return it */
1409     CollInit (&L->SpanInfoList);
1410     return L;
1411 }
1412
1413
1414
1415 static void FreeLineInfo (LineInfo* L)
1416 /* Free a LineInfo struct */
1417 {
1418     CollDone (&L->SpanInfoList);
1419     xfree (L);
1420 }
1421
1422
1423
1424 static cc65_lineinfo* new_cc65_lineinfo (unsigned Count)
1425 /* Allocate and return a cc65_lineinfo struct that is able to hold Count
1426 ** entries. Initialize the count field of the returned struct.
1427 */
1428 {
1429     cc65_lineinfo* L = xmalloc (sizeof (*L) - sizeof (L->data[0]) +
1430                                 Count * sizeof (L->data[0]));
1431     L->count = Count;
1432     return L;
1433 }
1434
1435
1436
1437 static void CopyLineInfo (cc65_linedata* D, const LineInfo* L)
1438 /* Copy data from a LineInfo struct to a cc65_linedata struct */
1439 {
1440     D->line_id          = L->Id;
1441     D->source_id        = L->File.Info->Id;
1442     D->source_line      = L->Line;
1443     D->line_type        = L->Type;
1444     D->count            = L->Count;
1445 }
1446
1447
1448
1449 static int CompareLineInfoByLine (const void* L, const void* R)
1450 /* Helper function to sort line infos in a collection by line. */
1451 {
1452     int Left  = ((const LineInfo*) L)->Line;
1453     int Right = ((const LineInfo*) R)->Line;
1454     return Left - Right;
1455 }
1456
1457
1458
1459 /*****************************************************************************/
1460 /*                                Module info                                */
1461 /*****************************************************************************/
1462
1463
1464
1465 static ModInfo* NewModInfo (const StrBuf* Name)
1466 /* Create a new ModInfo struct, intialize and return it */
1467 {
1468     /* Allocate memory */
1469     ModInfo* M = xmalloc (sizeof (ModInfo) + SB_GetLen (Name));
1470
1471     /* Initialize it */
1472     M->MainScope = 0;
1473     CollInit (&M->CSymFuncByName);
1474     CollInit (&M->FileInfoByName);
1475     CollInit (&M->ScopeInfoByName);
1476     memcpy (M->Name, SB_GetConstBuf (Name), SB_GetLen (Name) + 1);
1477
1478     /* Return it */
1479     return M;
1480 }
1481
1482
1483
1484 static void FreeModInfo (ModInfo* M)
1485 /* Free a ModInfo struct */
1486 {
1487     /* Free the collections */
1488     CollDone (&M->CSymFuncByName);
1489     CollDone (&M->FileInfoByName);
1490     CollDone (&M->ScopeInfoByName);
1491
1492     /* Free the structure itself */
1493     xfree (M);
1494 }
1495
1496
1497
1498 static cc65_moduleinfo* new_cc65_moduleinfo (unsigned Count)
1499 /* Allocate and return a cc65_moduleinfo struct that is able to hold Count
1500 ** entries. Initialize the count field of the returned struct.
1501 */
1502 {
1503     cc65_moduleinfo* M = xmalloc (sizeof (*M) - sizeof (M->data[0]) +
1504                                   Count * sizeof (M->data[0]));
1505     M->count = Count;
1506     return M;
1507 }
1508
1509
1510
1511 static void CopyModInfo (cc65_moduledata* D, const ModInfo* M)
1512 /* Copy data from a ModInfo struct to a cc65_moduledata struct */
1513 {
1514     D->module_id    = M->Id;
1515     D->module_name  = M->Name;
1516     D->source_id    = M->File.Info->Id;
1517     D->library_id   = GetId (M->Lib.Info);
1518     D->scope_id     = GetId (M->MainScope);
1519 }
1520
1521
1522
1523 static int CompareModInfoByName (const void* L, const void* R)
1524 /* Helper function to sort module infos in a collection by name */
1525 {
1526     /* Compare module name */
1527     return strcmp (((const ModInfo*) L)->Name, ((const ModInfo*) R)->Name);
1528 }
1529
1530
1531
1532 /*****************************************************************************/
1533 /*                                Scope info                                 */
1534 /*****************************************************************************/
1535
1536
1537
1538 static ScopeInfo* NewScopeInfo (const StrBuf* Name)
1539 /* Create a new ScopeInfo struct, intialize and return it */
1540 {
1541     /* Allocate memory */
1542     ScopeInfo* S = xmalloc (sizeof (ScopeInfo) + SB_GetLen (Name));
1543
1544     /* Initialize the fields as necessary */
1545     S->CSymFunc = 0;
1546     CollInit (&S->SpanInfoList);
1547     CollInit (&S->SymInfoByName);
1548     S->CSymInfoByName = 0;
1549     S->ChildScopeList = 0;
1550     memcpy (S->Name, SB_GetConstBuf (Name), SB_GetLen (Name) + 1);
1551
1552     /* Return it */
1553     return S;
1554 }
1555
1556
1557
1558 static void FreeScopeInfo (ScopeInfo* S)
1559 /* Free a ScopeInfo struct */
1560 {
1561     CollDone (&S->SpanInfoList);
1562     CollDone (&S->SymInfoByName);
1563     CollFree (S->CSymInfoByName);
1564     CollFree (S->ChildScopeList);
1565     xfree (S);
1566 }
1567
1568
1569
1570 static cc65_scopeinfo* new_cc65_scopeinfo (unsigned Count)
1571 /* Allocate and return a cc65_scopeinfo struct that is able to hold Count
1572 ** entries. Initialize the count field of the returned struct.
1573 */
1574 {
1575     cc65_scopeinfo* S = xmalloc (sizeof (*S) - sizeof (S->data[0]) +
1576                                  Count * sizeof (S->data[0]));
1577     S->count = Count;
1578     return S;
1579 }
1580
1581
1582
1583 static void CopyScopeInfo (cc65_scopedata* D, const ScopeInfo* S)
1584 /* Copy data from a ScopeInfo struct to a cc65_scopedata struct */
1585 {
1586     D->scope_id     = S->Id;
1587     D->scope_name   = S->Name;
1588     D->scope_type   = S->Type;
1589     D->scope_size   = S->Size;
1590     D->parent_id    = GetId (S->Parent.Info);
1591     D->symbol_id    = GetId (S->Label.Info);
1592     D->module_id    = S->Mod.Info->Id;
1593 }
1594
1595
1596
1597 static int CompareScopeInfoByName (const void* L, const void* R)
1598 /* Helper function to sort scope infos in a collection by name */
1599 {
1600     const ScopeInfo* Left  = L;
1601     const ScopeInfo* Right = R;
1602
1603     /* Compare scope name, then id */
1604     int Res = strcmp (Left->Name, Right->Name);
1605     if (Res == 0) {
1606         Res = (int)Left->Id - (int)Right->Id;
1607     }
1608     return Res;
1609 }
1610
1611
1612
1613 /*****************************************************************************/
1614 /*                               Segment info                                */
1615 /*****************************************************************************/
1616
1617
1618
1619 static SegInfo* NewSegInfo (const StrBuf* Name, unsigned Id,
1620                             cc65_addr Start, cc65_addr Size,
1621                             const StrBuf* OutputName, unsigned long OutputOffs)
1622 /* Create a new SegInfo struct and return it */
1623 {
1624     /* Allocate memory */
1625     SegInfo* S = xmalloc (sizeof (SegInfo) + SB_GetLen (Name));
1626
1627     /* Initialize it */
1628     S->Id         = Id;
1629     S->Start      = Start;
1630     S->Size       = Size;
1631     if (SB_GetLen (OutputName) > 0) {
1632         /* Output file given */
1633         S->OutputName = SB_StrDup (OutputName);
1634         S->OutputOffs = OutputOffs;
1635     } else {
1636         /* No output file given */
1637         S->OutputName = 0;
1638         S->OutputOffs = 0;
1639     }
1640     memcpy (S->Name, SB_GetConstBuf (Name), SB_GetLen (Name) + 1);
1641
1642     /* Return it */
1643     return S;
1644 }
1645
1646
1647
1648 static void FreeSegInfo (SegInfo* S)
1649 /* Free a SegInfo struct */
1650 {
1651     xfree (S->OutputName);
1652     xfree (S);
1653 }
1654
1655
1656
1657 static cc65_segmentinfo* new_cc65_segmentinfo (unsigned Count)
1658 /* Allocate and return a cc65_segmentinfo struct that is able to hold Count
1659 ** entries. Initialize the count field of the returned struct.
1660 */
1661 {
1662     cc65_segmentinfo* S = xmalloc (sizeof (*S) - sizeof (S->data[0]) +
1663                                    Count * sizeof (S->data[0]));
1664     S->count = Count;
1665     return S;
1666 }
1667
1668
1669
1670 static void CopySegInfo (cc65_segmentdata* D, const SegInfo* S)
1671 /* Copy data from a SegInfo struct to a cc65_segmentdata struct */
1672 {
1673     D->segment_id    = S->Id;
1674     D->segment_name  = S->Name;
1675     D->segment_start = S->Start;
1676     D->segment_size  = S->Size;
1677     D->output_name   = S->OutputName;
1678     D->output_offs   = S->OutputOffs;
1679 }
1680
1681
1682
1683 static int CompareSegInfoByName (const void* L, const void* R)
1684 /* Helper function to sort segment infos in a collection by name */
1685 {
1686     /* Sort by file name */
1687     return strcmp (((const SegInfo*) L)->Name,
1688                    ((const SegInfo*) R)->Name);
1689 }
1690
1691
1692
1693 /*****************************************************************************/
1694 /*                                 Span info                                 */
1695 /*****************************************************************************/
1696
1697
1698
1699 static SpanInfo* NewSpanInfo (void)
1700 /* Create a new SpanInfo struct, intialize and return it */
1701 {
1702     /* Allocate memory */
1703     SpanInfo* S = xmalloc (sizeof (SpanInfo));
1704
1705     /* Initialize and return it */
1706     S->ScopeInfoList = 0;
1707     S->LineInfoList = 0;
1708     return S;
1709 }
1710
1711
1712
1713 static void FreeSpanInfo (SpanInfo* S)
1714 /* Free a SpanInfo struct */
1715 {
1716     CollFree (S->ScopeInfoList);
1717     CollFree (S->LineInfoList);
1718     xfree (S);
1719 }
1720
1721
1722
1723 static cc65_spaninfo* new_cc65_spaninfo (unsigned Count)
1724 /* Allocate and return a cc65_spaninfo struct that is able to hold Count
1725 ** entries. Initialize the count field of the returned struct.
1726 */
1727 {
1728     cc65_spaninfo* S = xmalloc (sizeof (*S) - sizeof (S->data[0]) +
1729                                 Count * sizeof (S->data[0]));
1730     S->count = Count;
1731     return S;
1732 }
1733
1734
1735
1736 static void CopySpanInfo (cc65_spandata* D, const SpanInfo* S)
1737 /* Copy data from a SpanInfo struct to a cc65_spandata struct */
1738 {
1739     D->span_id      = S->Id;
1740     D->span_start   = S->Start;
1741     D->span_end     = S->End;
1742     D->segment_id   = S->Seg.Info->Id;
1743     D->type_id      = GetId (S->Type.Info);
1744     D->scope_count  = CollCount (S->ScopeInfoList);
1745     D->line_count   = CollCount (S->LineInfoList);
1746 }
1747
1748
1749
1750 static int CompareSpanInfoByAddr (const void* L, const void* R)
1751 /* Helper function to sort span infos in a collection by address. Span infos
1752 ** with smaller start address are considered smaller. If start addresses are
1753 ** equal, line spans with smaller end address are considered smaller. This
1754 ** means, that when CompareSpanInfoByAddr is used for sorting, a range with
1755 ** identical start addresses will have smaller spans first, followed by
1756 ** larger spans.
1757 */
1758 {
1759     /* Sort by start of span */
1760     if (((const SpanInfo*) L)->Start > ((const SpanInfo*) R)->Start) {
1761         return 1;
1762     } else if (((const SpanInfo*) L)->Start < ((const SpanInfo*) R)->Start) {
1763         return -1;
1764     } else if (((const SpanInfo*) L)->End > ((const SpanInfo*) R)->End) {
1765         return 1;
1766     } else if (((const SpanInfo*) L)->End < ((const SpanInfo*) R)->End) {
1767         return -1;
1768     } else {
1769         return 0;
1770     }
1771 }
1772
1773
1774
1775 /*****************************************************************************/
1776 /*                                Symbol info                                */
1777 /*****************************************************************************/
1778
1779
1780
1781 static SymInfo* NewSymInfo (const StrBuf* Name)
1782 /* Create a new SymInfo struct, intialize and return it */
1783 {
1784     /* Allocate memory */
1785     SymInfo* S = xmalloc (sizeof (SymInfo) + SB_GetLen (Name));
1786
1787     /* Initialize it as necessary */
1788     S->CSym        = 0;
1789     S->ImportList  = 0;
1790     S->CheapLocals = 0;
1791     CollInit (&S->DefLineInfoList);
1792     CollInit (&S->RefLineInfoList);
1793     memcpy (S->Name, SB_GetConstBuf (Name), SB_GetLen (Name) + 1);
1794
1795     /* Return it */
1796     return S;
1797 }
1798
1799
1800
1801 static void FreeSymInfo (SymInfo* S)
1802 /* Free a SymInfo struct */
1803 {
1804     CollFree (S->ImportList);
1805     CollFree (S->CheapLocals);
1806     CollDone (&S->DefLineInfoList);
1807     CollDone (&S->RefLineInfoList);
1808     xfree (S);
1809 }
1810
1811
1812
1813 static cc65_symbolinfo* new_cc65_symbolinfo (unsigned Count)
1814 /* Allocate and return a cc65_symbolinfo struct that is able to hold Count
1815 ** entries. Initialize the count field of the returned struct.
1816 */
1817 {
1818     cc65_symbolinfo* S = xmalloc (sizeof (*S) - sizeof (S->data[0]) +
1819                                   Count * sizeof (S->data[0]));
1820     S->count = Count;
1821     return S;
1822 }
1823
1824
1825
1826 static void CopySymInfo (cc65_symboldata* D, const SymInfo* S)
1827 /* Copy data from a SymInfo struct to a cc65_symboldata struct */
1828 {
1829     SegInfo* Seg;
1830
1831     D->symbol_id        = S->Id;
1832     D->symbol_name      = S->Name;
1833     D->symbol_type      = S->Type;
1834     D->symbol_size      = S->Size;
1835
1836     /* If this is an import, it doesn't have a value or segment. Use the data
1837     ** from the matching export instead.
1838     */
1839     if (S->Exp.Info) {
1840         /* This is an import, because it has a matching export */
1841         D->export_id    = S->Exp.Info->Id;
1842         D->symbol_value = S->Exp.Info->Value;
1843         Seg             = S->Exp.Info->Seg.Info;
1844     } else {
1845         D->export_id    = CC65_INV_ID;
1846         D->symbol_value = S->Value;
1847         Seg             = S->Seg.Info;
1848     }
1849     if (Seg) {
1850         D->segment_id   = Seg->Id;
1851     } else {
1852         D->segment_id   = CC65_INV_ID;
1853     }
1854     D->scope_id         = S->Scope.Info->Id;
1855     if (S->Parent.Info) {
1856         D->parent_id    = S->Parent.Info->Id;
1857     } else {
1858         D->parent_id    = CC65_INV_ID;
1859     }
1860 }
1861
1862
1863
1864 static int CompareSymInfoByName (const void* L, const void* R)
1865 /* Helper function to sort symbol infos in a collection by name */
1866 {
1867     /* Sort by symbol name */
1868     return strcmp (((const SymInfo*) L)->Name,
1869                    ((const SymInfo*) R)->Name);
1870 }
1871
1872
1873
1874 static int CompareSymInfoByVal (const void* L, const void* R)
1875 /* Helper function to sort symbol infos in a collection by value */
1876 {
1877     /* Sort by symbol value. If both are equal, sort by symbol name so it
1878     ** looks nice when such a list is returned.
1879     */
1880     if (((const SymInfo*) L)->Value > ((const SymInfo*) R)->Value) {
1881         return 1;
1882     } else if (((const SymInfo*) L)->Value < ((const SymInfo*) R)->Value) {
1883         return -1;
1884     } else {
1885         return CompareSymInfoByName (L, R);
1886     }
1887 }
1888
1889
1890
1891 /*****************************************************************************/
1892 /*                                 Type info                                 */
1893 /*****************************************************************************/
1894
1895
1896
1897 /* The following definitions are actually just taken from gentype.h */
1898
1899 /* Size of a data type */
1900 #define GT_SIZE_1               0x00U
1901 #define GT_SIZE_2               0x01U
1902 #define GT_SIZE_3               0x02U
1903 #define GT_SIZE_4               0x03U
1904 #define GT_SIZE_MASK            0x07U
1905
1906 #define GT_GET_SIZE(x)          (((x) & GT_SIZE_MASK) + 1U)
1907
1908 /* Sign of the data type */
1909 #define GT_UNSIGNED             0x00U
1910 #define GT_SIGNED               0x08U
1911 #define GT_SIGN_MASK            0x08U
1912
1913 #define GT_HAS_SIGN(x)          (((x) & GT_SIZE_MASK) == GT_SIGNED)
1914
1915 /* Byte order */
1916 #define GT_LITTLE_ENDIAN        0x00U
1917 #define GT_BIG_ENDIAN           0x10U
1918 #define GT_BYTEORDER_MASK       0x10U
1919
1920 #define GT_IS_LITTLE_ENDIAN(x)  (((x) & GT_BYTEORDER_MASK) == GT_LITTLE_ENDIAN)
1921 #define GT_IS_BIG_ENDIAN(x)     (((x) & GT_BYTEORDER_MASK) == GT_BIG_ENDIAN)
1922
1923 /* Type of the data. */
1924 #define GT_TYPE_VOID            0x00U
1925 #define GT_TYPE_INT             0x20U
1926 #define GT_TYPE_PTR             0x40U
1927 #define GT_TYPE_FLOAT           0x60U
1928 #define GT_TYPE_ARRAY           0x80U
1929 #define GT_TYPE_FUNC            0xA0U
1930 #define GT_TYPE_STRUCT          0xC0U
1931 #define GT_TYPE_UNION           0xE0U
1932 #define GT_TYPE_MASK            0xE0U
1933
1934 #define GT_GET_TYPE(x)          ((x) & GT_TYPE_MASK)
1935 #define GT_IS_INTEGER(x)        (GT_GET_TYPE(x) == GT_TYPE_INTEGER)
1936 #define GT_IS_POINTER(x)        (GT_GET_TYPE(x) == GT_TYPE_POINTER)
1937 #define GT_IS_FLOAT(x)          (GT_GET_TYPE(x) == GT_TYPE_FLOAT)
1938 #define GT_IS_ARRAY(x)          (GT_GET_TYPE(x) == GT_TYPE_ARRAY)
1939 #define GT_IS_FUNCTION(x)       (GT_GET_TYPE(x) == GT_TYPE_FUNCTION)
1940 #define GT_IS_STRUCT(x)         (GT_GET_TYPE(x) == GT_TYPE_STRUCT)
1941 #define GT_IS_UNION(x)          (GT_GET_TYPE(x) == GT_TYPE_UNION)
1942
1943 /* Combined values for the 6502 family */
1944 #define GT_VOID         (GT_TYPE_VOID)
1945 #define GT_BYTE         (GT_TYPE_INT | GT_LITTLE_ENDIAN | GT_UNSIGNED | GT_SIZE_1)
1946 #define GT_WORD         (GT_TYPE_INT | GT_LITTLE_ENDIAN | GT_UNSIGNED | GT_SIZE_2)
1947 #define GT_DWORD        (GT_TYPE_INT | GT_LITTLE_ENDIAN | GT_UNSIGNED | GT_SIZE_4)
1948 #define GT_DBYTE        (GT_TYPE_PTR | GT_BIG_ENDIAN    | GT_UNSIGNED | GT_SIZE_2)
1949 #define GT_PTR          (GT_TYPE_PTR | GT_LITTLE_ENDIAN | GT_UNSIGNED | GT_SIZE_2)
1950 #define GT_FAR_PTR      (GT_TYPE_PTR | GT_LITTLE_ENDIAN | GT_UNSIGNED | GT_SIZE_3)
1951 #define GT_ARRAY(size)  (GT_TYPE_ARRAY | ((size) - 1))
1952
1953
1954
1955 static void FreeTypeInfo (TypeInfo* T)
1956 /* Free a TypeInfo struct */
1957 {
1958     xfree (T);
1959 }
1960
1961
1962
1963 static void InitTypeParseData (TypeParseData* P, const StrBuf* Type,
1964                                unsigned ItemCount)
1965 /* Initialize a TypeParseData structure */
1966 {
1967     P->Info      = xmalloc (sizeof (*P->Info) - sizeof (P->Info->Data[0]) +
1968                             ItemCount * sizeof (P->Info->Data[0]));
1969     P->ItemCount = ItemCount;
1970     P->ItemIndex = 0;
1971     P->ItemData  = P->Info->Data;
1972     P->Type      = Type;
1973     P->Pos       = 0;
1974     P->Error     = 0;
1975 }
1976
1977
1978
1979 static cc65_typedata* TypeFromString (TypeParseData* P)
1980 /* Parse a type string and return a set of typedata structures. Will be called
1981 ** recursively. Will set P->Error and return NULL in case of problems.
1982 */
1983 {
1984     cc65_typedata*  Data;
1985     unsigned char   B;
1986     unsigned        I;
1987     unsigned        Count;
1988
1989     /* Allocate a new entry */
1990     if (P->ItemIndex >= P->ItemCount) {
1991         P->Error = 1;
1992         return 0;
1993     }
1994     Data = &P->ItemData[P->ItemIndex++];
1995
1996     /* Assume no following node */
1997     Data->next = 0;
1998
1999     /* Get the next char, then skip it */
2000     if (P->Pos >= SB_GetLen (P->Type)) {
2001         P->Error = 1;
2002         return 0;
2003     }
2004     B = SB_At (P->Type, P->Pos++);
2005
2006     switch (B) {
2007
2008         /* We only handle those that are currently in use */
2009         case GT_VOID:
2010             Data->what = CC65_TYPE_VOID;
2011             Data->size = 0;
2012             break;
2013
2014         case GT_BYTE:
2015             Data->what = CC65_TYPE_BYTE;
2016             Data->size = GT_GET_SIZE (B);
2017             break;
2018
2019         case GT_WORD:
2020             Data->what = CC65_TYPE_WORD;
2021             Data->size = GT_GET_SIZE (B);
2022             break;
2023
2024         case GT_DWORD:
2025             Data->what = CC65_TYPE_DWORD;
2026             Data->size = GT_GET_SIZE (B);
2027             break;
2028
2029         case GT_DBYTE:
2030             Data->what = CC65_TYPE_DBYTE;
2031             Data->size = GT_GET_SIZE (B);
2032             break;
2033
2034         case GT_PTR:
2035             Data->what = CC65_TYPE_PTR;
2036             Data->data.ptr.ind_type = TypeFromString (P);
2037             Data->size = GT_GET_SIZE (B);
2038             break;
2039
2040         case GT_FAR_PTR:
2041             Data->what = CC65_TYPE_FARPTR;
2042             Data->data.ptr.ind_type = TypeFromString (P);
2043             Data->size = GT_GET_SIZE (B);
2044             break;
2045
2046         default:
2047             if (GT_GET_TYPE (B) == GT_TYPE_ARRAY) {
2048                 Count = 0;
2049                 I = GT_GET_SIZE (B);
2050                 if (I == 0 || I > 4) {
2051                     P->Error = 1;
2052                     break;
2053                 }
2054                 P->Pos += I;
2055                 if (P->Pos > SB_GetLen (P->Type)) {
2056                     P->Error = 1;
2057                     break;
2058                 }
2059                 while (I) {
2060                     Count <<= 8;
2061                     Count |= (unsigned char)  SB_At (P->Type, P->Pos - I);
2062                     --I;
2063                 }
2064                 Data->what = CC65_TYPE_ARRAY;
2065                 Data->data.array.ele_count = Count;
2066                 Data->data.array.ele_type = TypeFromString (P);
2067                 if (!P->Error) {
2068                     Data->size = Data->data.array.ele_count *
2069                                  Data->data.array.ele_type->size;
2070                 }
2071             } else {
2072                 /* OOPS! */
2073                 P->Error = 1;
2074             }
2075             break;
2076     }
2077
2078     /* Return our structure or NULL in case of errors */
2079     return P->Error? 0 : Data;
2080 }
2081
2082
2083
2084
2085 static TypeInfo* ParseTypeString (InputData* D, StrBuf* Type)
2086 /* Check if the string T contains a valid type string. Convert it from readable
2087 ** to binary. Calculate how many cc65_typedata structures are necessary when it
2088 ** is converted. Convert the string into a set of cc65_typedata structures and
2089 ** return them.
2090 */
2091 {
2092     unsigned        I;
2093     unsigned        Count;
2094     const char*     A;
2095     char*           B;
2096     TypeParseData   P;
2097
2098
2099     /* The length must not be zero and divideable by two */
2100     unsigned Length = SB_GetLen (Type);
2101     if (Length < 2 || (Length & 0x01) != 0) {
2102         ParseError (D, CC65_ERROR, "Type value has invalid length");
2103         return 0;
2104     }
2105
2106     /* The string must consist completely of hex digit chars */
2107     A = SB_GetConstBuf (Type);
2108     for (I = 0; I < Length; ++I) {
2109         if (!isxdigit (A[I])) {
2110             ParseError (D, CC65_ERROR, "Type value contains invalid characters");
2111             return 0;
2112         }
2113     }
2114
2115     /* Convert the type to binary */
2116     B = SB_GetBuf (Type);
2117     while (A < SB_GetConstBuf (Type) + Length) {
2118         /* Since we know, there are only hex digits, there can't be any errors */
2119         *B++ = (HexValue (A[0]) << 4) | HexValue (A[1]);
2120         A += 2;
2121     }
2122     Type->Len = (Length /= 2);
2123
2124     /* Get a pointer to the type data, then count the number of cc65_typedata
2125     ** items needed.
2126     */
2127     A = SB_GetConstBuf (Type);
2128     Count = 0;
2129     I = 0;
2130     while (I < Length) {
2131         switch (A[I]) {
2132             /* We only handle those that are currently in use */
2133             case GT_VOID:
2134             case GT_BYTE:
2135             case GT_WORD:
2136             case GT_DWORD:
2137             case GT_DBYTE:
2138             case GT_PTR:
2139             case GT_FAR_PTR:
2140                 ++Count;
2141                 ++I;
2142                 break;
2143
2144             default:
2145                 if (GT_GET_TYPE (A[I]) == GT_TYPE_ARRAY) {
2146                     ++Count;
2147                     I += GT_GET_SIZE (A[I]) + 1;
2148                 } else {
2149                     /* Unknown type in type string */
2150                     ParseError (D, CC65_ERROR, "Unkown type in type value");
2151                     return 0;
2152                 }
2153                 break;
2154         }
2155     }
2156
2157     /* Check that we're even */
2158     if (I != Length) {
2159         ParseError (D, CC65_ERROR, "Syntax error in type in type value");
2160         return 0;
2161     }
2162
2163     /* Initialize the data structure for parsing the type string */
2164     InitTypeParseData (&P, Type, Count);
2165
2166     /* Parse the type string and check for errors */
2167     if (TypeFromString (&P) == 0 || P.ItemCount != P.ItemIndex) {
2168         ParseError (D, CC65_ERROR, "Error parsing the type value");
2169         FreeTypeInfo (P.Info);
2170         return 0;
2171     }
2172
2173     /* Return the result of the parse operation */
2174     return P.Info;
2175 }
2176
2177
2178
2179 /*****************************************************************************/
2180 /*                               SpanInfoList                                */
2181 /*****************************************************************************/
2182
2183
2184
2185 static void InitSpanInfoList (SpanInfoList* L)
2186 /* Initialize a span info list */
2187 {
2188     L->Count = 0;
2189     L->List  = 0;
2190 }
2191
2192
2193
2194 static void CreateSpanInfoList (SpanInfoList* L, Collection* SpanInfos)
2195 /* Create a SpanInfoList from a Collection with span infos. The collection
2196 ** must be sorted by ascending start addresses.
2197 */
2198 {
2199     unsigned I, J;
2200     SpanInfo* S;
2201     SpanInfoListEntry* List;
2202     unsigned StartIndex;
2203     cc65_addr Start;
2204     cc65_addr Addr;
2205     cc65_addr End;
2206
2207     /* Initialize and check if there's something to do */
2208     L->Count = 0;
2209     L->List  = 0;
2210     if (CollCount (SpanInfos) == 0) {
2211         /* No entries */
2212         return;
2213     }
2214
2215     /* Step 1: Determine the number of unique address entries needed */
2216     S = CollAt (SpanInfos, 0);
2217     L->Count += (S->End - S->Start) + 1;
2218     End = S->End;
2219     for (I = 1; I < CollCount (SpanInfos); ++I) {
2220
2221         /* Get next entry */
2222         S = CollAt (SpanInfos, I);
2223
2224         /* Check for additional unique addresses in this span info */
2225         if (S->Start > End) {
2226             L->Count += (S->End - S->Start) + 1;
2227             End = S->End;
2228         } else if (S->End > End) {
2229             L->Count += (S->End - End);
2230             End = S->End;
2231         }
2232
2233     }
2234
2235     /* Step 2: Allocate memory and initialize it */
2236     L->List = List = xmalloc (L->Count * sizeof (*List));
2237     for (I = 0; I < L->Count; ++I) {
2238         List[I].Count = 0;
2239         List[I].Data  = 0;
2240     }
2241
2242     /* Step 3: Determine the number of entries per unique address */
2243     List = L->List;
2244     S = CollAt (SpanInfos, 0);
2245     StartIndex = 0;
2246     Start = S->Start;
2247     End = S->End;
2248     for (J = StartIndex, Addr = S->Start; Addr <= S->End; ++J, ++Addr) {
2249         List[J].Addr = Addr;
2250         ++List[J].Count;
2251     }
2252     for (I = 1; I < CollCount (SpanInfos); ++I) {
2253
2254         /* Get next entry */
2255         S = CollAt (SpanInfos, I);
2256
2257         /* Determine the start index of the next range. Line infos are sorted
2258         ** by ascending start address, so the start address of the next entry
2259         ** is always larger than the previous one - we don't need to check
2260         ** that.
2261         */
2262         if (S->Start <= End) {
2263             /* Range starts within out already known linear range */
2264             StartIndex += (unsigned) (S->Start - Start);
2265             Start = S->Start;
2266             if (S->End > End) {
2267                 End = S->End;
2268             }
2269         } else {
2270             /* Range starts after the already known */
2271             StartIndex += (unsigned) (End - Start) + 1;
2272             Start = S->Start;
2273             End = S->End;
2274         }
2275         for (J = StartIndex, Addr = S->Start; Addr <= S->End; ++J, ++Addr) {
2276             List[J].Addr = Addr;
2277             ++List[J].Count;
2278         }
2279     }
2280
2281     /* Step 4: Allocate memory for the indirect tables */
2282     for (I = 0, List = L->List; I < L->Count; ++I, ++List) {
2283
2284         /* For a count of 1, we store the pointer to the lineinfo for this
2285         ** address in the Data pointer directly. For counts > 1, we allocate
2286         ** an array of pointers and reset the counter, so we can use it as
2287         ** an index later. This is dangerous programming since it disables
2288         ** all possible checks!
2289         */
2290         if (List->Count > 1) {
2291             List->Data = xmalloc (List->Count * sizeof (SpanInfo*));
2292             List->Count = 0;
2293         }
2294     }
2295
2296     /* Step 5: Enter the data into the table */
2297     List = L->List;
2298     S = CollAt (SpanInfos, 0);
2299     StartIndex = 0;
2300     Start = S->Start;
2301     End = S->End;
2302     for (J = StartIndex, Addr = S->Start; Addr <= S->End; ++J, ++Addr) {
2303         assert (List[J].Addr == Addr);
2304         if (List[J].Count == 1 && List[J].Data == 0) {
2305             List[J].Data = S;
2306         } else {
2307             ((SpanInfo**) List[J].Data)[List[J].Count++] = S;
2308         }
2309     }
2310     for (I = 1; I < CollCount (SpanInfos); ++I) {
2311
2312         /* Get next entry */
2313         S = CollAt (SpanInfos, I);
2314
2315         /* Determine the start index of the next range. Line infos are sorted
2316         ** by ascending start address, so the start address of the next entry
2317         ** is always larger than the previous one - we don't need to check
2318         ** that.
2319         */
2320         if (S->Start <= End) {
2321             /* Range starts within out already known linear range */
2322             StartIndex += (unsigned) (S->Start - Start);
2323             Start = S->Start;
2324             if (S->End > End) {
2325                 End = S->End;
2326             }
2327         } else {
2328             /* Range starts after the already known */
2329             StartIndex += (unsigned) (End - Start) + 1;
2330             Start = S->Start;
2331             End = S->End;
2332         }
2333         for (J = StartIndex, Addr = S->Start; Addr <= S->End; ++J, ++Addr) {
2334             assert (List[J].Addr == Addr);
2335             if (List[J].Count == 1 && List[J].Data == 0) {
2336                 List[J].Data = S;
2337             } else {
2338                 ((SpanInfo**) List[J].Data)[List[J].Count++] = S;
2339             }
2340         }
2341     }
2342 }
2343
2344
2345
2346 static void DoneSpanInfoList (SpanInfoList* L)
2347 /* Delete the contents of a span info list */
2348 {
2349     unsigned I;
2350
2351     /* Delete the span info and the indirect data */
2352     for (I = 0; I < L->Count; ++I) {
2353
2354         /* Get a pointer to the entry */
2355         SpanInfoListEntry* E = &L->List[I];
2356
2357         /* Check for indirect memory */
2358         if (E->Count > 1) {
2359             /* SpanInfo addressed indirectly */
2360             xfree (E->Data);
2361         }
2362     }
2363
2364     /* Delete the list */
2365     xfree (L->List);
2366 }
2367
2368
2369
2370 /*****************************************************************************/
2371 /*                                Debug info                                 */
2372 /*****************************************************************************/
2373
2374
2375
2376 static DbgInfo* NewDbgInfo (const char* FileName)
2377 /* Create a new DbgInfo struct and return it */
2378 {
2379     /* Get the length of the name */
2380     unsigned Len = strlen (FileName);
2381
2382     /* Allocate memory */
2383     DbgInfo* Info = xmalloc (sizeof (DbgInfo) + Len);
2384
2385     /* Initialize it */
2386     CollInit (&Info->CSymInfoById);
2387     CollInit (&Info->FileInfoById);
2388     CollInit (&Info->LibInfoById);
2389     CollInit (&Info->LineInfoById);
2390     CollInit (&Info->ModInfoById);
2391     CollInit (&Info->ScopeInfoById);
2392     CollInit (&Info->SegInfoById);
2393     CollInit (&Info->SpanInfoById);
2394     CollInit (&Info->SymInfoById);
2395     CollInit (&Info->TypeInfoById);
2396
2397     CollInit (&Info->CSymFuncByName);
2398     CollInit (&Info->FileInfoByName);
2399     CollInit (&Info->ModInfoByName);
2400     CollInit (&Info->ScopeInfoByName);
2401     CollInit (&Info->SegInfoByName);
2402     CollInit (&Info->SymInfoByName);
2403     CollInit (&Info->SymInfoByVal);
2404
2405     InitSpanInfoList (&Info->SpanInfoByAddr);
2406
2407     Info->MemUsage     = 0;
2408     Info->MajorVersion = 0;
2409     Info->MinorVersion = 0;
2410     memcpy (&Info->FileName, FileName, Len+1);
2411
2412     /* Return it */
2413     return Info;
2414 }
2415
2416
2417
2418 static void FreeDbgInfo (DbgInfo* Info)
2419 /* Free a DbgInfo struct */
2420 {
2421     unsigned I;
2422
2423     /* First, free the items in the collections */
2424     for (I = 0; I < CollCount (&Info->CSymInfoById); ++I) {
2425         FreeCSymInfo (CollAt (&Info->CSymInfoById, I));
2426     }
2427     for (I = 0; I < CollCount (&Info->FileInfoById); ++I) {
2428         FreeFileInfo (CollAt (&Info->FileInfoById, I));
2429     }
2430     for (I = 0; I < CollCount (&Info->LibInfoById); ++I) {
2431         FreeLibInfo (CollAt (&Info->LibInfoById, I));
2432     }
2433     for (I = 0; I < CollCount (&Info->LineInfoById); ++I) {
2434         FreeLineInfo (CollAt (&Info->LineInfoById, I));
2435     }
2436     for (I = 0; I < CollCount (&Info->ModInfoById); ++I) {
2437         FreeModInfo (CollAt (&Info->ModInfoById, I));
2438     }
2439     for (I = 0; I < CollCount (&Info->ScopeInfoById); ++I) {
2440         FreeScopeInfo (CollAt (&Info->ScopeInfoById, I));
2441     }
2442     for (I = 0; I < CollCount (&Info->SegInfoById); ++I) {
2443         FreeSegInfo (CollAt (&Info->SegInfoById, I));
2444     }
2445     for (I = 0; I < CollCount (&Info->SpanInfoById); ++I) {
2446         FreeSpanInfo (CollAt (&Info->SpanInfoById, I));
2447     }
2448     for (I = 0; I < CollCount (&Info->SymInfoById); ++I) {
2449         FreeSymInfo (CollAt (&Info->SymInfoById, I));
2450     }
2451     for (I = 0; I < CollCount (&Info->TypeInfoById); ++I) {
2452         FreeTypeInfo (CollAt (&Info->TypeInfoById, I));
2453     }
2454
2455     /* Free the memory used by the id collections */
2456     CollDone (&Info->CSymInfoById);
2457     CollDone (&Info->FileInfoById);
2458     CollDone (&Info->LibInfoById);
2459     CollDone (&Info->LineInfoById);
2460     CollDone (&Info->ModInfoById);
2461     CollDone (&Info->ScopeInfoById);
2462     CollDone (&Info->SegInfoById);
2463     CollDone (&Info->SpanInfoById);
2464     CollDone (&Info->SymInfoById);
2465     CollDone (&Info->TypeInfoById);
2466
2467     /* Free the memory used by the other collections */
2468     CollDone (&Info->CSymFuncByName);
2469     CollDone (&Info->FileInfoByName);
2470     CollDone (&Info->ModInfoByName);
2471     CollDone (&Info->ScopeInfoByName);
2472     CollDone (&Info->SegInfoByName);
2473     CollDone (&Info->SymInfoByName);
2474     CollDone (&Info->SymInfoByVal);
2475
2476     /* Free span info */
2477     DoneSpanInfoList (&Info->SpanInfoByAddr);
2478
2479     /* Free the structure itself */
2480     xfree (Info);
2481 }
2482
2483
2484
2485 /*****************************************************************************/
2486 /*                            Scanner and parser                             */
2487 /*****************************************************************************/
2488
2489
2490
2491 static int DigitVal (int C)
2492 /* Return the value for a numeric digit. Return -1 if C is invalid */
2493 {
2494     if (isdigit (C)) {
2495         return C - '0';
2496     } else if (isxdigit (C)) {
2497         return toupper (C) - 'A' + 10;
2498     } else {
2499         return -1;
2500     }
2501 }
2502
2503
2504
2505 static void NextChar (InputData* D)
2506 /* Read the next character from the input. Count lines and columns */
2507 {
2508     /* Check if we've encountered EOF before */
2509     if (D->C >= 0) {
2510         if (D->C == '\n') {
2511             ++D->Line;
2512             D->Col = 0;
2513         }
2514         D->C = fgetc (D->F);
2515         ++D->Col;
2516     }
2517 }
2518
2519
2520
2521 static void NextToken (InputData* D)
2522 /* Read the next token from the input stream */
2523 {
2524     static const struct KeywordEntry  {
2525         const char      Keyword[12];
2526         Token           Tok;
2527     } KeywordTable[] = {
2528         { "abs",        TOK_ABSOLUTE    },
2529         { "addrsize",   TOK_ADDRSIZE    },
2530         { "auto",       TOK_AUTO        },
2531         { "count",      TOK_COUNT       },
2532         { "csym",       TOK_CSYM        },
2533         { "def",        TOK_DEF         },
2534         { "enum",       TOK_ENUM        },
2535         { "equ",        TOK_EQUATE      },
2536         { "exp",        TOK_EXPORT      },
2537         { "ext",        TOK_EXTERN      },
2538         { "file",       TOK_FILE        },
2539         { "func",       TOK_FUNC        },
2540         { "global",     TOK_GLOBAL      },
2541         { "id",         TOK_ID          },
2542         { "imp",        TOK_IMPORT      },
2543         { "info",       TOK_INFO        },
2544         { "lab",        TOK_LABEL       },
2545         { "lib",        TOK_LIBRARY     },
2546         { "line",       TOK_LINE        },
2547         { "long",       TOK_LONG        },
2548         { "major",      TOK_MAJOR       },
2549         { "minor",      TOK_MINOR       },
2550         { "mod",        TOK_MODULE      },
2551         { "mtime",      TOK_MTIME       },
2552         { "name",       TOK_NAME        },
2553         { "offs",       TOK_OFFS        },
2554         { "oname",      TOK_OUTPUTNAME  },
2555         { "ooffs",      TOK_OUTPUTOFFS  },
2556         { "parent",     TOK_PARENT      },
2557         { "ref",        TOK_REF         },
2558         { "reg",        TOK_REGISTER    },
2559         { "ro",         TOK_RO          },
2560         { "rw",         TOK_RW          },
2561         { "sc",         TOK_SC          },
2562         { "scope",      TOK_SCOPE       },
2563         { "seg",        TOK_SEGMENT     },
2564         { "size",       TOK_SIZE        },
2565         { "span",       TOK_SPAN        },
2566         { "start",      TOK_START       },
2567         { "static",     TOK_STATIC      },
2568         { "struct",     TOK_STRUCT      },
2569         { "sym",        TOK_SYM         },
2570         { "type",       TOK_TYPE        },
2571         { "val",        TOK_VALUE       },
2572         { "var",        TOK_VAR         },
2573         { "version",    TOK_VERSION     },
2574         { "zp",         TOK_ZEROPAGE    },
2575     };
2576
2577
2578     /* Skip whitespace */
2579     while (D->C == ' ' || D->C == '\t' || D->C == '\r') {
2580         NextChar (D);
2581     }
2582
2583     /* Remember the current position as start of the next token */
2584     D->SLine = D->Line;
2585     D->SCol  = D->Col;
2586
2587     /* Identifier? */
2588     if (D->C == '_' || isalpha (D->C)) {
2589
2590         const struct KeywordEntry* Entry;
2591
2592         /* Read the identifier */
2593         SB_Clear (&D->SVal);
2594         while (D->C == '_' || isalnum (D->C)) {
2595             SB_AppendChar (&D->SVal, D->C);
2596             NextChar (D);
2597         }
2598         SB_Terminate (&D->SVal);
2599
2600         /* Search the identifier in the keyword table */
2601         Entry = bsearch (SB_GetConstBuf (&D->SVal),
2602                          KeywordTable,
2603                          sizeof (KeywordTable) / sizeof (KeywordTable[0]),
2604                          sizeof (KeywordTable[0]),
2605                          (int (*)(const void*, const void*)) strcmp);
2606         if (Entry == 0) {
2607             D->Tok = TOK_IDENT;
2608         } else {
2609             D->Tok = Entry->Tok;
2610         }
2611         return;
2612     }
2613
2614     /* Number? */
2615     if (isdigit (D->C)) {
2616         int Base = 10;
2617         int Val;
2618         if (D->C == '0') {
2619             NextChar (D);
2620             if (toupper (D->C) == 'X') {
2621                 NextChar (D);
2622                 Base = 16;
2623             } else {
2624                 Base = 8;
2625             }
2626         } else {
2627             Base = 10;
2628         }
2629         D->IVal = 0;
2630         while ((Val = DigitVal (D->C)) >= 0 && Val < Base) {
2631             D->IVal = D->IVal * Base + Val;
2632             NextChar (D);
2633         }
2634         D->Tok = TOK_INTCON;
2635         return;
2636     }
2637
2638     /* Other characters */
2639     switch (D->C) {
2640
2641         case '-':
2642             NextChar (D);
2643             D->Tok = TOK_MINUS;
2644             break;
2645
2646         case '+':
2647             NextChar (D);
2648             D->Tok = TOK_PLUS;
2649             break;
2650
2651         case ',':
2652             NextChar (D);
2653             D->Tok = TOK_COMMA;
2654             break;
2655
2656         case '=':
2657             NextChar (D);
2658             D->Tok = TOK_EQUAL;
2659             break;
2660
2661         case '\"':
2662             SB_Clear (&D->SVal);
2663             NextChar (D);
2664             while (1) {
2665                 if (D->C == '\n' || D->C == EOF) {
2666                     ParseError (D, CC65_ERROR, "Unterminated string constant");
2667                     break;
2668                 }
2669                 if (D->C == '\"') {
2670                     NextChar (D);
2671                     break;
2672                 }
2673                 SB_AppendChar (&D->SVal, D->C);
2674                 NextChar (D);
2675             }
2676             SB_Terminate (&D->SVal);
2677             D->Tok = TOK_STRCON;
2678             break;
2679
2680         case '\n':
2681             NextChar (D);
2682             D->Tok = TOK_EOL;
2683             break;
2684
2685         case EOF:
2686             D->Tok = TOK_EOF;
2687             break;
2688
2689         default:
2690             ParseError (D, CC65_ERROR, "Invalid input character '%c'", D->C);
2691
2692     }
2693 }
2694
2695
2696
2697 static int TokenIsKeyword (Token Tok)
2698 /* Return true if the given token is a keyword */
2699 {
2700     return (Tok >= TOK_FIRST_KEYWORD && Tok <= TOK_LAST_KEYWORD);
2701 }
2702
2703
2704
2705 static int TokenFollows (InputData* D, Token Tok, const char* Name)
2706 /* Check for a specific token that follows. */
2707 {
2708     if (D->Tok != Tok) {
2709         ParseError (D, CC65_ERROR, "%s expected", Name);
2710         SkipLine (D);
2711         return 0;
2712     } else {
2713         return 1;
2714     }
2715 }
2716
2717
2718
2719 static int IntConstFollows (InputData* D)
2720 /* Check for an integer constant */
2721 {
2722     return TokenFollows (D, TOK_INTCON, "Integer constant");
2723 }
2724
2725
2726
2727 static int StrConstFollows (InputData* D)
2728 /* Check for a string literal */
2729 {
2730     return TokenFollows (D, TOK_STRCON, "String literal");
2731 }
2732
2733
2734
2735 static int Consume (InputData* D, Token Tok, const char* Name)
2736 /* Check for a token and consume it. Return true if the token was comsumed,
2737 ** return false otherwise.
2738 */
2739 {
2740     if (TokenFollows (D, Tok, Name)) {
2741         NextToken (D);
2742         return 1;
2743     } else {
2744         return 0;
2745     }
2746 }
2747
2748
2749
2750 static int ConsumeEqual (InputData* D)
2751 /* Consume an equal sign */
2752 {
2753     return Consume (D, TOK_EQUAL, "'='");
2754 }
2755
2756
2757
2758 static void ConsumeEOL (InputData* D)
2759 /* Consume an end-of-line token, if we aren't at end-of-file */
2760 {
2761     if (D->Tok != TOK_EOF) {
2762         if (D->Tok != TOK_EOL) {
2763             ParseError (D, CC65_ERROR, "Extra tokens in line");
2764             SkipLine (D);
2765         }
2766         NextToken (D);
2767     }
2768 }
2769
2770
2771
2772 static void ParseCSym (InputData* D)
2773 /* Parse a CSYM line */
2774 {
2775     /* Most of the following variables are initialized with a value that is
2776     ** overwritten later. This is just to avoid compiler warnings.
2777     */
2778     unsigned            Id = 0;
2779     StrBuf              Name = STRBUF_INITIALIZER;
2780     int                 Offs = 0;
2781     cc65_csym_sc        SC = CC65_CSYM_AUTO;
2782     unsigned            ScopeId = 0;
2783     unsigned            SymId = CC65_INV_ID;
2784     unsigned            TypeId = CC65_INV_ID;
2785     CSymInfo*           S;
2786     enum {
2787         ibNone          = 0x0000,
2788
2789         ibId            = 0x0001,
2790         ibOffs          = 0x0002,
2791         ibName          = 0x0004,
2792         ibSC            = 0x0008,
2793         ibScopeId       = 0x0010,
2794         ibSymId         = 0x0020,
2795         ibType          = 0x0040,
2796
2797         ibRequired      = ibId | ibName | ibSC | ibScopeId | ibType,
2798     } InfoBits = ibNone;
2799
2800     /* Skip the CSYM token */
2801     NextToken (D);
2802
2803     /* More stuff follows */
2804     while (1) {
2805
2806         Token Tok;
2807
2808         /* Something we know? */
2809         if (D->Tok != TOK_ID            && D->Tok != TOK_NAME           &&
2810             D->Tok != TOK_OFFS          && D->Tok != TOK_SC             &&
2811             D->Tok != TOK_SCOPE         && D->Tok != TOK_SYM            &&
2812             D->Tok != TOK_TYPE) {
2813
2814             /* Try smart error recovery */
2815             if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
2816                 UnknownKeyword (D);
2817                 continue;
2818             }
2819
2820             /* Done */
2821             break;
2822         }
2823
2824         /* Remember the token, skip it, check for equal */
2825         Tok = D->Tok;
2826         NextToken (D);
2827         if (!ConsumeEqual (D)) {
2828             goto ErrorExit;
2829         }
2830
2831         /* Check what the token was */
2832         switch (Tok) {
2833
2834             case TOK_ID:
2835                 if (!IntConstFollows (D)) {
2836                     goto ErrorExit;
2837                 }
2838                 Id = D->IVal;
2839                 NextToken (D);
2840                 InfoBits |= ibId;
2841                 break;
2842
2843             case TOK_NAME:
2844                 if (!StrConstFollows (D)) {
2845                     goto ErrorExit;
2846                 }
2847                 SB_Copy (&Name, &D->SVal);
2848                 SB_Terminate (&Name);
2849                 InfoBits |= ibName;
2850                 NextToken (D);
2851                 break;
2852
2853             case TOK_OFFS:
2854                 Offs = 1;
2855                 if (D->Tok == TOK_MINUS) {
2856                     Offs = -1;
2857                     NextToken (D);
2858                 }
2859                 if (!IntConstFollows (D)) {
2860                     goto ErrorExit;
2861                 }
2862                 Offs *= (int) D->IVal;
2863                 InfoBits |= ibOffs;
2864                 NextToken (D);
2865                 break;
2866
2867             case TOK_SC:
2868                 switch (D->Tok) {
2869                     case TOK_AUTO:      SC = CC65_CSYM_AUTO;    break;
2870                     case TOK_EXTERN:    SC = CC65_CSYM_EXTERN;  break;
2871                     case TOK_REGISTER:  SC = CC65_CSYM_REG;     break;
2872                     case TOK_STATIC:    SC = CC65_CSYM_STATIC;  break;
2873                     default:
2874                         ParseError (D, CC65_ERROR, "Invalid storage class token");
2875                         break;
2876                 }
2877                 InfoBits |= ibSC;
2878                 NextToken (D);
2879                 break;
2880
2881             case TOK_SCOPE:
2882                 if (!IntConstFollows (D)) {
2883                     goto ErrorExit;
2884                 }
2885                 ScopeId = D->IVal;
2886                 NextToken (D);
2887                 InfoBits |= ibScopeId;
2888                 break;
2889
2890             case TOK_SYM:
2891                 if (!IntConstFollows (D)) {
2892                     goto ErrorExit;
2893                 }
2894                 SymId = D->IVal;
2895                 NextToken (D);
2896                 InfoBits |= ibSymId;
2897                 break;
2898
2899             case TOK_TYPE:
2900                 if (!IntConstFollows (D)) {
2901                     goto ErrorExit;
2902                 }
2903                 TypeId = D->IVal;
2904                 NextToken (D);
2905                 InfoBits |= ibType;
2906                 break;
2907
2908             default:
2909                 /* NOTREACHED */
2910                 UnexpectedToken (D);
2911                 goto ErrorExit;
2912
2913         }
2914
2915         /* Comma or done */
2916         if (D->Tok != TOK_COMMA) {
2917             break;
2918         }
2919         NextToken (D);
2920     }
2921
2922     /* Check for end of line */
2923     if (D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
2924         UnexpectedToken (D);
2925         SkipLine (D);
2926         goto ErrorExit;
2927     }
2928
2929     /* Check for required and/or matched information */
2930     if ((InfoBits & ibRequired) != ibRequired) {
2931         ParseError (D, CC65_ERROR, "Required attributes missing");
2932         goto ErrorExit;
2933     }
2934
2935     /* Symbol only valid if storage class not auto */
2936     if (((InfoBits & ibSymId) != 0) && (SC == CC65_CSYM_AUTO)) {
2937         ParseError (D, CC65_ERROR, "Only non auto symbols can have a symbol attached");
2938         goto ErrorExit;
2939     }
2940
2941     /* Create the symbol info */
2942     S = NewCSymInfo (&Name);
2943     S->Id         = Id;
2944     S->Kind       = CC65_CSYM_VAR;
2945     S->SC         = SC;
2946     S->Offs       = Offs;
2947     S->Sym.Id     = SymId;
2948     S->Type.Id    = TypeId;
2949     S->Scope.Id   = ScopeId;
2950
2951     /* Remember it */
2952     CollReplaceExpand (&D->Info->CSymInfoById, S, Id);
2953
2954 ErrorExit:
2955     /* Entry point in case of errors */
2956     SB_Done (&Name);
2957     return;
2958 }
2959
2960
2961
2962 static void ParseFile (InputData* D)
2963 /* Parse a FILE line */
2964 {
2965     unsigned      Id = 0;
2966     unsigned long Size = 0;
2967     unsigned long MTime = 0;
2968     Collection    ModIds = COLLECTION_INITIALIZER;
2969     StrBuf        Name = STRBUF_INITIALIZER;
2970     FileInfo*     F;
2971     enum {
2972         ibNone      = 0x00,
2973         ibId        = 0x01,
2974         ibName      = 0x02,
2975         ibSize      = 0x04,
2976         ibMTime     = 0x08,
2977         ibModId     = 0x10,
2978         ibRequired  = ibId | ibName | ibSize | ibMTime | ibModId,
2979     } InfoBits = ibNone;
2980
2981     /* Skip the FILE token */
2982     NextToken (D);
2983
2984     /* More stuff follows */
2985     while (1) {
2986
2987         Token Tok;
2988
2989         /* Something we know? */
2990         if (D->Tok != TOK_ID            && D->Tok != TOK_MODULE         &&
2991             D->Tok != TOK_MTIME         && D->Tok != TOK_NAME           &&
2992             D->Tok != TOK_SIZE) {
2993
2994             /* Try smart error recovery */
2995             if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
2996                 UnknownKeyword (D);
2997                 continue;
2998             }
2999
3000             /* Done */
3001             break;
3002         }
3003
3004         /* Remember the token, skip it, check for equal */
3005         Tok = D->Tok;
3006         NextToken (D);
3007         if (!ConsumeEqual (D)) {
3008             goto ErrorExit;
3009         }
3010
3011         /* Check what the token was */
3012         switch (Tok) {
3013
3014             case TOK_ID:
3015                 if (!IntConstFollows (D)) {
3016                     goto ErrorExit;
3017                 }
3018                 Id = D->IVal;
3019                 InfoBits |= ibId;
3020                 NextToken (D);
3021                 break;
3022
3023             case TOK_MTIME:
3024                 if (!IntConstFollows (D)) {
3025                     goto ErrorExit;
3026                 }
3027                 MTime = D->IVal;
3028                 NextToken (D);
3029                 InfoBits |= ibMTime;
3030                 break;
3031
3032             case TOK_MODULE:
3033                 while (1) {
3034                     if (!IntConstFollows (D)) {
3035                         goto ErrorExit;
3036                     }
3037                     CollAppendId (&ModIds, (unsigned) D->IVal);
3038                     NextToken (D);
3039                     if (D->Tok != TOK_PLUS) {
3040                         break;
3041                     }
3042                     NextToken (D);
3043                 }
3044                 InfoBits |= ibModId;
3045                 break;
3046
3047             case TOK_NAME:
3048                 if (!StrConstFollows (D)) {
3049                     goto ErrorExit;
3050                 }
3051                 SB_Copy (&Name, &D->SVal);
3052                 SB_Terminate (&Name);
3053                 InfoBits |= ibName;
3054                 NextToken (D);
3055                 break;
3056
3057             case TOK_SIZE:
3058                 if (!IntConstFollows (D)) {
3059                     goto ErrorExit;
3060                 }
3061                 Size = D->IVal;
3062                 NextToken (D);
3063                 InfoBits |= ibSize;
3064                 break;
3065
3066             default:
3067                 /* NOTREACHED */
3068                 UnexpectedToken (D);
3069                 goto ErrorExit;
3070
3071         }
3072
3073         /* Comma or done */
3074         if (D->Tok != TOK_COMMA) {
3075             break;
3076         }
3077         NextToken (D);
3078     }
3079
3080     /* Check for end of line */
3081     if (D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
3082         UnexpectedToken (D);
3083         SkipLine (D);
3084         goto ErrorExit;
3085     }
3086
3087     /* Check for required information */
3088     if ((InfoBits & ibRequired) != ibRequired) {
3089         ParseError (D, CC65_ERROR, "Required attributes missing");
3090         goto ErrorExit;
3091     }
3092
3093     /* Create the file info and remember it */
3094     F = NewFileInfo (&Name);
3095     F->Id       = Id;
3096     F->Size     = Size;
3097     F->MTime    = MTime;
3098     CollMove (&ModIds, &F->ModInfoByName);
3099     CollReplaceExpand (&D->Info->FileInfoById, F, Id);
3100     CollAppend (&D->Info->FileInfoByName, F);
3101
3102 ErrorExit:
3103     /* Entry point in case of errors */
3104     CollDone (&ModIds);
3105     SB_Done (&Name);
3106     return;
3107 }
3108
3109
3110
3111 static void ParseInfo (InputData* D)
3112 /* Parse an INFO line */
3113 {
3114     /* Skip the INFO token */
3115     NextToken (D);
3116
3117     /* More stuff follows */
3118     while (1) {
3119
3120         Token Tok;
3121
3122         /* Something we know? */
3123         if (D->Tok != TOK_CSYM          && D->Tok != TOK_FILE           &&
3124             D->Tok != TOK_LIBRARY       && D->Tok != TOK_LINE           &&
3125             D->Tok != TOK_MODULE        && D->Tok != TOK_SCOPE          &&
3126             D->Tok != TOK_SEGMENT       && D->Tok != TOK_SPAN           &&
3127             D->Tok != TOK_SYM           && D->Tok != TOK_TYPE) {
3128
3129             /* Try smart error recovery */
3130             if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
3131                 UnknownKeyword (D);
3132                 continue;
3133             }
3134
3135             /* Done */
3136             break;
3137         }
3138
3139         /* Remember the token, skip it, check for equal, check for an integer
3140         ** constant.
3141         */
3142         Tok = D->Tok;
3143         NextToken (D);
3144         if (!ConsumeEqual (D)) {
3145             goto ErrorExit;
3146         }
3147         if (!IntConstFollows (D)) {
3148             goto ErrorExit;
3149         }
3150
3151         /* Check what the token was */
3152         switch (Tok) {
3153
3154             case TOK_CSYM:
3155                 CollGrow (&D->Info->CSymInfoById,  D->IVal);
3156                 break;
3157
3158             case TOK_FILE:
3159                 CollGrow (&D->Info->FileInfoById,   D->IVal);
3160                 CollGrow (&D->Info->FileInfoByName, D->IVal);
3161                 break;
3162
3163             case TOK_LIBRARY:
3164                 CollGrow (&D->Info->LibInfoById, D->IVal);
3165                 break;
3166
3167             case TOK_LINE:
3168                 CollGrow (&D->Info->LineInfoById, D->IVal);
3169                 break;
3170
3171             case TOK_MODULE:
3172                 CollGrow (&D->Info->ModInfoById,   D->IVal);
3173                 CollGrow (&D->Info->ModInfoByName, D->IVal);
3174                 break;
3175
3176             case TOK_SCOPE:
3177                 CollGrow (&D->Info->ScopeInfoById, D->IVal);
3178                 CollGrow (&D->Info->ScopeInfoByName, D->IVal);
3179                 break;
3180
3181             case TOK_SEGMENT:
3182                 CollGrow (&D->Info->SegInfoById,   D->IVal);
3183                 CollGrow (&D->Info->SegInfoByName, D->IVal);
3184                 break;
3185
3186             case TOK_SPAN:
3187                 CollGrow (&D->Info->SpanInfoById,  D->IVal);
3188                 break;
3189
3190             case TOK_SYM:
3191                 CollGrow (&D->Info->SymInfoById,   D->IVal);
3192                 CollGrow (&D->Info->SymInfoByName, D->IVal);
3193                 CollGrow (&D->Info->SymInfoByVal,  D->IVal);
3194                 break;
3195
3196             case TOK_TYPE:
3197                 CollGrow (&D->Info->TypeInfoById,  D->IVal);
3198                 break;
3199
3200             default:
3201                 /* NOTREACHED */
3202                 UnexpectedToken (D);
3203                 goto ErrorExit;
3204
3205         }
3206
3207         /* Skip the number */
3208         NextToken (D);
3209
3210         /* Comma or done */
3211         if (D->Tok != TOK_COMMA) {
3212             break;
3213         }
3214         NextToken (D);
3215     }
3216
3217     /* Check for end of line */
3218     if (D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
3219         UnexpectedToken (D);
3220         SkipLine (D);
3221         goto ErrorExit;
3222     }
3223
3224 ErrorExit:
3225     /* Entry point in case of errors */
3226     return;
3227 }
3228
3229
3230
3231 static void ParseLibrary (InputData* D)
3232 /* Parse a LIBRARY line */
3233 {
3234     unsigned      Id = 0;
3235     StrBuf        Name = STRBUF_INITIALIZER;
3236     LibInfo*      L;
3237     enum {
3238         ibNone      = 0x00,
3239         ibId        = 0x01,
3240         ibName      = 0x02,
3241         ibRequired  = ibId | ibName,
3242     } InfoBits = ibNone;
3243
3244     /* Skip the LIBRARY token */
3245     NextToken (D);
3246
3247     /* More stuff follows */
3248     while (1) {
3249
3250         Token Tok;
3251
3252         /* Something we know? */
3253         if (D->Tok != TOK_ID            && D->Tok != TOK_NAME) {
3254
3255             /* Try smart error recovery */
3256             if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
3257                 UnknownKeyword (D);
3258                 continue;
3259             }
3260
3261             /* Done */
3262             break;
3263         }
3264
3265         /* Remember the token, skip it, check for equal */
3266         Tok = D->Tok;
3267         NextToken (D);
3268         if (!ConsumeEqual (D)) {
3269             goto ErrorExit;
3270         }
3271
3272         /* Check what the token was */
3273         switch (Tok) {
3274
3275             case TOK_ID:
3276                 if (!IntConstFollows (D)) {
3277                     goto ErrorExit;
3278                 }
3279                 Id = D->IVal;
3280                 InfoBits |= ibId;
3281                 NextToken (D);
3282                 break;
3283
3284             case TOK_NAME:
3285                 if (!StrConstFollows (D)) {
3286                     goto ErrorExit;
3287                 }
3288                 SB_Copy (&Name, &D->SVal);
3289                 SB_Terminate (&Name);
3290                 InfoBits |= ibName;
3291                 NextToken (D);
3292                 break;
3293
3294             default:
3295                 /* NOTREACHED */
3296                 UnexpectedToken (D);
3297                 goto ErrorExit;
3298
3299         }
3300
3301         /* Comma or done */
3302         if (D->Tok != TOK_COMMA) {
3303             break;
3304         }
3305         NextToken (D);
3306     }
3307
3308     /* Check for end of line */
3309     if (D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
3310         UnexpectedToken (D);
3311         SkipLine (D);
3312         goto ErrorExit;
3313     }
3314
3315     /* Check for required information */
3316     if ((InfoBits & ibRequired) != ibRequired) {
3317         ParseError (D, CC65_ERROR, "Required attributes missing");
3318         goto ErrorExit;
3319     }
3320
3321     /* Create the library info and remember it */
3322     L = NewLibInfo (&Name);
3323     L->Id = Id;
3324     CollReplaceExpand (&D->Info->LibInfoById, L, Id);
3325
3326 ErrorExit:
3327     /* Entry point in case of errors */
3328     SB_Done (&Name);
3329     return;
3330 }
3331
3332
3333
3334 static void ParseLine (InputData* D)
3335 /* Parse a LINE line */
3336 {
3337     unsigned        Id = CC65_INV_ID;
3338     unsigned        FileId = CC65_INV_ID;
3339     Collection      SpanIds = COLLECTION_INITIALIZER;
3340     cc65_line       Line = 0;
3341     cc65_line_type  Type = CC65_LINE_ASM;
3342     unsigned        Count = 0;
3343     LineInfo*       L;
3344     enum {
3345         ibNone      = 0x00,
3346
3347         ibCount     = 0x01,
3348         ibFileId    = 0x02,
3349         ibId        = 0x04,
3350         ibLine      = 0x08,
3351         ibSpanId    = 0x20,
3352         ibType      = 0x40,
3353
3354         ibRequired  = ibFileId | ibId | ibLine,
3355     } InfoBits = ibNone;
3356
3357     /* Skip the LINE token */
3358     NextToken (D);
3359
3360     /* More stuff follows */
3361     while (1) {
3362
3363         Token Tok;
3364
3365         /* Something we know? */
3366         if (D->Tok != TOK_COUNT   && D->Tok != TOK_FILE         &&
3367             D->Tok != TOK_ID      && D->Tok != TOK_LINE         &&
3368             D->Tok != TOK_SPAN    && D->Tok != TOK_TYPE) {
3369
3370             /* Try smart error recovery */
3371             if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
3372                 UnknownKeyword (D);
3373                 continue;
3374             }
3375
3376             /* Done */
3377             break;
3378         }
3379
3380         /* Remember the token, skip it, check for equal */
3381         Tok = D->Tok;
3382         NextToken (D);
3383         if (!ConsumeEqual (D)) {
3384             goto ErrorExit;
3385         }
3386
3387         /* Check what the token was */
3388         switch (Tok) {
3389
3390             case TOK_FILE:
3391                 if (!IntConstFollows (D)) {
3392                     goto ErrorExit;
3393                 }
3394                 FileId = D->IVal;
3395                 InfoBits |= ibFileId;
3396                 NextToken (D);
3397                 break;
3398
3399             case TOK_ID:
3400                 if (!IntConstFollows (D)) {
3401                     goto ErrorExit;
3402                 }
3403                 Id = D->IVal;
3404                 InfoBits |= ibId;
3405                 NextToken (D);
3406                 break;
3407
3408             case TOK_LINE:
3409                 if (!IntConstFollows (D)) {
3410                     goto ErrorExit;
3411                 }
3412                 Line = (cc65_line) D->IVal;
3413                 NextToken (D);
3414                 InfoBits |= ibLine;
3415                 break;
3416
3417             case TOK_SPAN:
3418                 while (1) {
3419                     if (!IntConstFollows (D)) {
3420                         goto ErrorExit;
3421                     }
3422                     CollAppendId (&SpanIds, (unsigned) D->IVal);
3423                     NextToken (D);
3424                     if (D->Tok != TOK_PLUS) {
3425                         break;
3426                     }
3427                     NextToken (D);
3428                 }
3429                 InfoBits |= ibSpanId;
3430                 break;
3431
3432             case TOK_TYPE:
3433                 if (!IntConstFollows (D)) {
3434                     goto ErrorExit;
3435                 }
3436                 Type = (cc65_line_type) D->IVal;
3437                 InfoBits |= ibType;
3438                 NextToken (D);
3439                 break;
3440
3441             case TOK_COUNT:
3442                 if (!IntConstFollows (D)) {
3443                     goto ErrorExit;
3444                 }
3445                 Count = D->IVal;
3446                 InfoBits |= ibCount;
3447                 NextToken (D);
3448                 break;
3449
3450             default:
3451                 /* NOTREACHED */
3452                 UnexpectedToken (D);
3453                 goto ErrorExit;
3454
3455         }
3456
3457         /* Comma or done */
3458         if (D->Tok != TOK_COMMA) {
3459             break;
3460         }
3461         NextToken (D);
3462     }
3463
3464     /* Check for end of line */
3465     if (D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
3466         UnexpectedToken (D);
3467         SkipLine (D);
3468         goto ErrorExit;
3469     }
3470
3471     /* Check for required information */
3472     if ((InfoBits & ibRequired) != ibRequired) {
3473         ParseError (D, CC65_ERROR, "Required attributes missing");
3474         goto ErrorExit;
3475     }
3476
3477     /* Create the line info and remember it */
3478     L = NewLineInfo ();
3479     L->Id       = Id;
3480     L->Line     = Line;
3481     L->File.Id  = FileId;
3482     L->Type     = Type;
3483     L->Count    = Count;
3484     CollMove (&SpanIds, &L->SpanInfoList);
3485     CollReplaceExpand (&D->Info->LineInfoById, L, Id);
3486
3487 ErrorExit:
3488     /* Entry point in case of errors */
3489     CollDone (&SpanIds);
3490     return;
3491 }
3492
3493
3494
3495 static void ParseModule (InputData* D)
3496 /* Parse a MODULE line */
3497 {
3498     /* Most of the following variables are initialized with a value that is
3499     ** overwritten later. This is just to avoid compiler warnings.
3500     */
3501     unsigned            Id = CC65_INV_ID;
3502     StrBuf              Name = STRBUF_INITIALIZER;
3503     unsigned            FileId = CC65_INV_ID;
3504     unsigned            LibId = CC65_INV_ID;
3505     ModInfo*            M;
3506     enum {
3507         ibNone          = 0x000,
3508
3509         ibFileId        = 0x001,
3510         ibId            = 0x002,
3511         ibName          = 0x004,
3512         ibLibId         = 0x008,
3513
3514         ibRequired      = ibId | ibName | ibFileId,
3515     } InfoBits = ibNone;
3516
3517     /* Skip the MODULE token */
3518     NextToken (D);
3519
3520     /* More stuff follows */
3521     while (1) {
3522
3523         Token Tok;
3524
3525         /* Something we know? */
3526         if (D->Tok != TOK_FILE          && D->Tok != TOK_ID             &&
3527             D->Tok != TOK_NAME          && D->Tok != TOK_LIBRARY) {
3528
3529             /* Try smart error recovery */
3530             if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
3531                 UnknownKeyword (D);
3532                 continue;
3533             }
3534
3535             /* Done */
3536             break;
3537         }
3538
3539         /* Remember the token, skip it, check for equal */
3540         Tok = D->Tok;
3541         NextToken (D);
3542         if (!ConsumeEqual (D)) {
3543             goto ErrorExit;
3544         }
3545
3546         /* Check what the token was */
3547         switch (Tok) {
3548
3549             case TOK_FILE:
3550                 if (!IntConstFollows (D)) {
3551                     goto ErrorExit;
3552                 }
3553                 FileId = D->IVal;
3554                 InfoBits |= ibFileId;
3555                 NextToken (D);
3556                 break;
3557
3558             case TOK_ID:
3559                 if (!IntConstFollows (D)) {
3560                     goto ErrorExit;
3561                 }
3562                 Id = D->IVal;
3563                 InfoBits |= ibId;
3564                 NextToken (D);
3565                 break;
3566
3567             case TOK_NAME:
3568                 if (!StrConstFollows (D)) {
3569                     goto ErrorExit;
3570                 }
3571                 SB_Copy (&Name, &D->SVal);
3572                 SB_Terminate (&Name);
3573                 InfoBits |= ibName;
3574                 NextToken (D);
3575                 break;
3576
3577             case TOK_LIBRARY:
3578                 if (!IntConstFollows (D)) {
3579                     goto ErrorExit;
3580                 }
3581                 LibId = D->IVal;
3582                 InfoBits |= ibLibId;
3583                 NextToken (D);
3584                 break;
3585
3586             default:
3587                 /* NOTREACHED */
3588                 UnexpectedToken (D);
3589                 goto ErrorExit;
3590
3591         }
3592
3593         /* Comma or done */
3594         if (D->Tok != TOK_COMMA) {
3595             break;
3596         }
3597         NextToken (D);
3598     }
3599
3600     /* Check for end of line */
3601     if (D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
3602         UnexpectedToken (D);
3603         SkipLine (D);
3604         goto ErrorExit;
3605     }
3606
3607     /* Check for required and/or matched information */
3608     if ((InfoBits & ibRequired) != ibRequired) {
3609         ParseError (D, CC65_ERROR, "Required attributes missing");
3610         goto ErrorExit;
3611     }
3612
3613     /* Create the scope info */
3614     M = NewModInfo (&Name);
3615     M->File.Id = FileId;
3616     M->Id      = Id;
3617     M->Lib.Id  = LibId;
3618
3619     /* ... and remember it */
3620     CollReplaceExpand (&D->Info->ModInfoById, M, Id);
3621     CollAppend (&D->Info->ModInfoByName, M);
3622
3623 ErrorExit:
3624     /* Entry point in case of errors */
3625     SB_Done (&Name);
3626     return;
3627 }
3628
3629
3630
3631 static void ParseScope (InputData* D)
3632 /* Parse a SCOPE line */
3633 {
3634     /* Most of the following variables are initialized with a value that is
3635     ** overwritten later. This is just to avoid compiler warnings.
3636     */
3637     unsigned            Id = CC65_INV_ID;
3638     cc65_scope_type     Type = CC65_SCOPE_MODULE;
3639     cc65_size           Size = 0;
3640     StrBuf              Name = STRBUF_INITIALIZER;
3641     unsigned            ModId = CC65_INV_ID;
3642     unsigned            ParentId = CC65_INV_ID;
3643     Collection          SpanIds = COLLECTION_INITIALIZER;
3644     unsigned            SymId = CC65_INV_ID;
3645     ScopeInfo*          S;
3646     enum {
3647         ibNone          = 0x000,
3648
3649         ibId            = 0x001,
3650         ibModId         = 0x002,
3651         ibName          = 0x004,
3652         ibParentId      = 0x008,
3653         ibSize          = 0x010,
3654         ibSpanId        = 0x020,
3655         ibSymId         = 0x040,
3656         ibType          = 0x080,
3657
3658         ibRequired      = ibId | ibModId | ibName,
3659     } InfoBits = ibNone;
3660
3661     /* Skip the SCOPE token */
3662     NextToken (D);
3663
3664     /* More stuff follows */
3665     while (1) {
3666
3667         Token Tok;
3668
3669         /* Something we know? */
3670         if (D->Tok != TOK_ID            && D->Tok != TOK_MODULE         &&
3671             D->Tok != TOK_NAME          && D->Tok != TOK_PARENT         &&
3672             D->Tok != TOK_SIZE          && D->Tok != TOK_SPAN           &&
3673             D->Tok != TOK_SYM           && D->Tok != TOK_TYPE) {
3674
3675             /* Try smart error recovery */
3676             if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
3677                 UnknownKeyword (D);
3678                 continue;
3679             }
3680
3681             /* Done */
3682             break;
3683         }
3684
3685         /* Remember the token, skip it, check for equal */
3686         Tok = D->Tok;
3687         NextToken (D);
3688         if (!ConsumeEqual (D)) {
3689             goto ErrorExit;
3690         }
3691
3692         /* Check what the token was */
3693         switch (Tok) {
3694
3695             case TOK_ID:
3696                 if (!IntConstFollows (D)) {
3697                     goto ErrorExit;
3698                 }
3699                 Id = D->IVal;
3700                 InfoBits |= ibId;
3701                 NextToken (D);
3702                 break;
3703
3704             case TOK_MODULE:
3705                 if (!IntConstFollows (D)) {
3706                     goto ErrorExit;
3707                 }
3708                 ModId = D->IVal;
3709                 InfoBits |= ibModId;
3710                 NextToken (D);
3711                 break;
3712
3713             case TOK_NAME:
3714                 if (!StrConstFollows (D)) {
3715                     goto ErrorExit;
3716                 }
3717                 SB_Copy (&Name, &D->SVal);
3718                 SB_Terminate (&Name);
3719                 InfoBits |= ibName;
3720                 NextToken (D);
3721                 break;
3722
3723             case TOK_PARENT:
3724                 if (!IntConstFollows (D)) {
3725                     goto ErrorExit;
3726                 }
3727                 ParentId = D->IVal;
3728                 NextToken (D);
3729                 InfoBits |= ibParentId;
3730                 break;
3731
3732             case TOK_SIZE:
3733                 if (!IntConstFollows (D)) {
3734                     goto ErrorExit;
3735                 }
3736                 Size = (cc65_size) D->IVal;
3737                 InfoBits |= ibSize;
3738                 NextToken (D);
3739                 break;
3740
3741             case TOK_SPAN:
3742                 while (1) {
3743                     if (!IntConstFollows (D)) {
3744                         goto ErrorExit;
3745                     }
3746                     CollAppendId (&SpanIds, (unsigned) D->IVal);
3747                     NextToken (D);
3748                     if (D->Tok != TOK_PLUS) {
3749                         break;
3750                     }
3751                     NextToken (D);
3752                 }
3753                 InfoBits |= ibSpanId;
3754                 break;
3755
3756             case TOK_SYM:
3757                 if (!IntConstFollows (D)) {
3758                     goto ErrorExit;
3759                 }
3760                 SymId = D->IVal;
3761                 NextToken (D);
3762                 InfoBits |= ibSymId;
3763                 break;
3764
3765             case TOK_TYPE:
3766                 switch (D->Tok) {
3767                     case TOK_GLOBAL:    Type = CC65_SCOPE_GLOBAL;       break;
3768                     case TOK_FILE:      Type = CC65_SCOPE_MODULE;       break;
3769                     case TOK_SCOPE:     Type = CC65_SCOPE_SCOPE;        break;
3770                     case TOK_STRUCT:    Type = CC65_SCOPE_STRUCT;       break;
3771                     case TOK_ENUM:      Type = CC65_SCOPE_ENUM;         break;
3772                     default:
3773                         ParseError (D, CC65_ERROR,
3774                                     "Unknown value for attribute \"type\"");
3775                         SkipLine (D);
3776                         goto ErrorExit;
3777                 }
3778                 NextToken (D);
3779                 InfoBits |= ibType;
3780                 break;
3781
3782             default:
3783                 /* NOTREACHED */
3784                 UnexpectedToken (D);
3785                 goto ErrorExit;
3786
3787         }
3788
3789         /* Comma or done */
3790         if (D->Tok != TOK_COMMA) {
3791             break;
3792         }
3793         NextToken (D);
3794     }
3795
3796     /* Check for end of line */
3797     if (D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
3798         UnexpectedToken (D);
3799         SkipLine (D);
3800         goto ErrorExit;
3801     }
3802
3803     /* Check for required and/or matched information */
3804     if ((InfoBits & ibRequired) != ibRequired) {
3805         ParseError (D, CC65_ERROR, "Required attributes missing");
3806         goto ErrorExit;
3807     }
3808
3809     /* Create the scope info ... */
3810     S = NewScopeInfo (&Name);
3811     S->Id        = Id;
3812     S->Type      = Type;
3813     S->Size      = Size;
3814     S->Mod.Id    = ModId;
3815     S->Parent.Id = ParentId;
3816     S->Label.Id  = SymId;
3817     CollMove (&SpanIds, &S->SpanInfoList);
3818
3819     /* ... and remember it */
3820     CollReplaceExpand (&D->Info->ScopeInfoById, S, Id);
3821     CollAppend (&D->Info->ScopeInfoByName, S);
3822
3823 ErrorExit:
3824     /* Entry point in case of errors */
3825     CollDone (&SpanIds);
3826     SB_Done (&Name);
3827     return;
3828 }
3829
3830
3831
3832 static void ParseSegment (InputData* D)
3833 /* Parse a SEGMENT line */
3834 {
3835     unsigned        Id = 0;
3836     cc65_addr       Start = 0;
3837     cc65_addr       Size = 0;
3838     StrBuf          Name = STRBUF_INITIALIZER;
3839     StrBuf          OutputName = STRBUF_INITIALIZER;
3840     unsigned long   OutputOffs = 0;
3841     SegInfo*        S;
3842     enum {
3843         ibNone      = 0x000,
3844
3845         ibAddrSize  = 0x001,
3846         ibId        = 0x002,
3847         ibOutputName= 0x004,
3848         ibOutputOffs= 0x008,
3849         ibName      = 0x010,
3850         ibSize      = 0x020,
3851         ibStart     = 0x040,
3852         ibType      = 0x080,
3853
3854         ibRequired  = ibId | ibName | ibStart | ibSize | ibAddrSize | ibType,
3855     } InfoBits = ibNone;
3856
3857     /* Skip the SEGMENT token */
3858     NextToken (D);
3859
3860     /* More stuff follows */
3861     while (1) {
3862
3863         Token Tok;
3864
3865         /* Something we know? */
3866         if (D->Tok != TOK_ADDRSIZE      && D->Tok != TOK_ID         &&
3867             D->Tok != TOK_NAME          && D->Tok != TOK_OUTPUTNAME &&
3868             D->Tok != TOK_OUTPUTOFFS    && D->Tok != TOK_SIZE       &&
3869             D->Tok != TOK_START         && D->Tok != TOK_TYPE) {
3870
3871             /* Try smart error recovery */
3872             if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
3873                 UnknownKeyword (D);
3874                 continue;
3875             }
3876             /* Done */
3877             break;
3878         }
3879
3880         /* Remember the token, skip it, check for equal */
3881         Tok = D->Tok;
3882         NextToken (D);
3883         if (!ConsumeEqual (D)) {
3884             goto ErrorExit;
3885         }
3886
3887         /* Check what the token was */
3888         switch (Tok) {
3889
3890             case TOK_ADDRSIZE:
3891                 NextToken (D);
3892                 InfoBits |= ibAddrSize;
3893                 break;
3894
3895             case TOK_ID:
3896                 if (!IntConstFollows (D)) {
3897                     goto ErrorExit;
3898                 }
3899                 Id = D->IVal;
3900                 InfoBits |= ibId;
3901                 NextToken (D);
3902                 break;
3903
3904             case TOK_NAME:
3905                 if (!StrConstFollows (D)) {
3906                     goto ErrorExit;
3907                 }
3908                 SB_Copy (&Name, &D->SVal);
3909                 SB_Terminate (&Name);
3910                 InfoBits |= ibName;
3911                 NextToken (D);
3912                 break;
3913
3914             case TOK_OUTPUTNAME:
3915                 if (!StrConstFollows (D)) {
3916                     goto ErrorExit;
3917                 }
3918                 SB_Copy (&OutputName, &D->SVal);
3919                 SB_Terminate (&OutputName);
3920                 InfoBits |= ibOutputName;
3921                 NextToken (D);
3922                 break;
3923
3924             case TOK_OUTPUTOFFS:
3925                 if (!IntConstFollows (D)) {
3926                     goto ErrorExit;
3927                 }
3928                 OutputOffs = D->IVal;
3929                 NextToken (D);
3930                 InfoBits |= ibOutputOffs;
3931                 break;
3932
3933             case TOK_SIZE:
3934                 if (!IntConstFollows (D)) {
3935                     goto ErrorExit;
3936                 }
3937                 Size = D->IVal;
3938                 NextToken (D);
3939                 InfoBits |= ibSize;
3940                 break;
3941
3942             case TOK_START:
3943                 if (!IntConstFollows (D)) {
3944                     goto ErrorExit;
3945                 }
3946                 Start = (cc65_addr) D->IVal;
3947                 NextToken (D);
3948                 InfoBits |= ibStart;
3949                 break;
3950
3951             case TOK_TYPE:
3952                 NextToken (D);
3953                 InfoBits |= ibType;
3954                 break;
3955
3956             default:
3957                 /* NOTREACHED */
3958                 UnexpectedToken (D);
3959                 goto ErrorExit;
3960
3961         }
3962
3963         /* Comma or done */
3964         if (D->Tok != TOK_COMMA) {
3965             break;
3966         }
3967         NextToken (D);
3968     }
3969
3970     /* Check for end of line */
3971     if (D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
3972         UnexpectedToken (D);
3973         SkipLine (D);
3974         goto ErrorExit;
3975     }
3976
3977     /* Check for required and/or matched information */
3978     if ((InfoBits & ibRequired) != ibRequired) {
3979         ParseError (D, CC65_ERROR, "Required attributes missing");
3980         goto ErrorExit;
3981     }
3982     InfoBits &= (ibOutputName | ibOutputOffs);
3983     if (InfoBits != ibNone && InfoBits != (ibOutputName | ibOutputOffs)) {
3984         ParseError (D, CC65_ERROR,
3985                     "Attributes \"outputname\" and \"outputoffs\" must be paired");
3986         goto ErrorExit;
3987     }
3988
3989     /* Fix OutputOffs if not given */
3990     if (InfoBits == ibNone) {
3991         OutputOffs = 0;
3992     }
3993
3994     /* Create the segment info and remember it */
3995     S = NewSegInfo (&Name, Id, Start, Size, &OutputName, OutputOffs);
3996     CollReplaceExpand (&D->Info->SegInfoById, S, Id);
3997     CollAppend (&D->Info->SegInfoByName, S);
3998
3999 ErrorExit:
4000     /* Entry point in case of errors */
4001     SB_Done (&Name);
4002     SB_Done (&OutputName);
4003     return;
4004 }
4005
4006
4007
4008 static void ParseSpan (InputData* D)
4009 /* Parse a SPAN line */
4010 {
4011     unsigned        Id = 0;
4012     cc65_addr       Start = 0;
4013     cc65_addr       Size = 0;
4014     unsigned        SegId = CC65_INV_ID;
4015     unsigned        TypeId = CC65_INV_ID;
4016     SpanInfo*       S;
4017     enum {
4018         ibNone      = 0x000,
4019
4020         ibId        = 0x01,
4021         ibSegId     = 0x02,
4022         ibSize      = 0x04,
4023         ibStart     = 0x08,
4024         ibType      = 0x10,
4025
4026         ibRequired  = ibId | ibSegId | ibSize | ibStart,
4027     } InfoBits = ibNone;
4028
4029     /* Skip the SEGMENT token */
4030     NextToken (D);
4031
4032     /* More stuff follows */
4033     while (1) {
4034
4035         Token Tok;
4036
4037         /* Something we know? */
4038         if (D->Tok != TOK_ID    && D->Tok != TOK_SEGMENT        &&
4039             D->Tok != TOK_SIZE  && D->Tok != TOK_START          &&
4040             D->Tok != TOK_TYPE) {
4041
4042             /* Try smart error recovery */
4043             if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
4044                 UnknownKeyword (D);
4045                 continue;
4046             }
4047             /* Done */
4048             break;
4049         }
4050
4051         /* Remember the token, skip it, check for equal */
4052         Tok = D->Tok;
4053         NextToken (D);
4054         if (!ConsumeEqual (D)) {
4055             goto ErrorExit;
4056         }
4057
4058         /* Check what the token was */
4059         switch (Tok) {
4060
4061             case TOK_ID:
4062                 if (!IntConstFollows (D)) {
4063                     goto ErrorExit;
4064                 }
4065                 Id = D->IVal;
4066                 InfoBits |= ibId;
4067                 NextToken (D);
4068                 break;
4069
4070             case TOK_SEGMENT:
4071                 if (!IntConstFollows (D)) {
4072                     goto ErrorExit;
4073                 }
4074                 SegId = D->IVal;
4075                 InfoBits |= ibSegId;
4076                 NextToken (D);
4077                 break;
4078
4079             case TOK_SIZE:
4080                 if (!IntConstFollows (D)) {
4081                     goto ErrorExit;
4082                 }
4083                 Size = D->IVal;
4084                 NextToken (D);
4085                 InfoBits |= ibSize;
4086                 break;
4087
4088             case TOK_START:
4089                 if (!IntConstFollows (D)) {
4090                     goto ErrorExit;
4091                 }
4092                 Start = (cc65_addr) D->IVal;
4093                 NextToken (D);
4094                 InfoBits |= ibStart;
4095                 break;
4096
4097             case TOK_TYPE:
4098                 if (!IntConstFollows (D)) {
4099                     goto ErrorExit;
4100                 }
4101                 TypeId = D->IVal;
4102                 NextToken (D);
4103                 InfoBits |= ibType;
4104                 break;
4105
4106             default:
4107                 /* NOTREACHED */
4108                 UnexpectedToken (D);
4109                 goto ErrorExit;
4110
4111         }
4112
4113         /* Comma or done */
4114         if (D->Tok != TOK_COMMA) {
4115             break;
4116         }
4117         NextToken (D);
4118     }
4119
4120     /* Check for end of line */
4121     if (D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
4122         UnexpectedToken (D);
4123         SkipLine (D);
4124         goto ErrorExit;
4125     }
4126
4127     /* Check for required and/or matched information */
4128     if ((InfoBits & ibRequired) != ibRequired) {
4129         ParseError (D, CC65_ERROR, "Required attributes missing");
4130         goto ErrorExit;
4131     }
4132
4133     /* Create the span info and remember it */
4134     S = NewSpanInfo ();
4135     S->Id       = Id;
4136     S->Start    = Start;
4137     S->End      = Start + Size - 1;
4138     S->Seg.Id   = SegId;
4139     S->Type.Id  = TypeId;
4140     CollReplaceExpand (&D->Info->SpanInfoById, S, Id);
4141
4142 ErrorExit:
4143     /* Entry point in case of errors */
4144     return;
4145 }
4146
4147
4148
4149 static void ParseSym (InputData* D)
4150 /* Parse a SYM line */
4151 {
4152     /* Most of the following variables are initialized with a value that is
4153     ** overwritten later. This is just to avoid compiler warnings.
4154     */
4155     Collection          DefLineIds = COLLECTION_INITIALIZER;
4156     unsigned            ExportId = CC65_INV_ID;
4157     unsigned            FileId = CC65_INV_ID;
4158     unsigned            Id = CC65_INV_ID;
4159     StrBuf              Name = STRBUF_INITIALIZER;
4160     unsigned            ParentId = CC65_INV_ID;
4161     Collection          RefLineIds = COLLECTION_INITIALIZER;
4162     unsigned            ScopeId = CC65_INV_ID;
4163     unsigned            SegId = CC65_INV_ID;
4164     cc65_size           Size = 0;
4165     cc65_symbol_type    Type = CC65_SYM_EQUATE;
4166     long                Value = 0;
4167
4168     SymInfo*            S;
4169     enum {
4170         ibNone          = 0x0000,
4171
4172         ibAddrSize      = 0x0001,
4173         ibDefLineId     = 0x0002,
4174         ibExportId      = 0x0004,
4175         ibFileId        = 0x0008,
4176         ibId            = 0x0010,
4177         ibParentId      = 0x0020,
4178         ibRefLineId     = 0x0040,
4179         ibScopeId       = 0x0080,
4180         ibSegId         = 0x0100,
4181         ibSize          = 0x0200,
4182         ibName          = 0x0400,
4183         ibType          = 0x0800,
4184         ibValue         = 0x1000,
4185
4186         ibRequired      = ibAddrSize | ibId | ibName,
4187     } InfoBits = ibNone;
4188
4189     /* Skip the SYM token */
4190     NextToken (D);
4191
4192     /* More stuff follows */
4193     while (1) {
4194
4195         Token Tok;
4196
4197         /* Something we know? */
4198         if (D->Tok != TOK_ADDRSIZE      && D->Tok != TOK_DEF            &&
4199             D->Tok != TOK_EXPORT        && D->Tok != TOK_FILE           &&
4200             D->Tok != TOK_ID            && D->Tok != TOK_NAME           &&
4201             D->Tok != TOK_PARENT        && D->Tok != TOK_REF            &&
4202             D->Tok != TOK_SCOPE         && D->Tok != TOK_SEGMENT        &&
4203             D->Tok != TOK_SIZE          && D->Tok != TOK_TYPE           &&
4204             D->Tok != TOK_VALUE) {
4205
4206             /* Try smart error recovery */
4207             if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
4208                 UnknownKeyword (D);
4209                 continue;
4210             }
4211
4212             /* Done */
4213             break;
4214         }
4215
4216         /* Remember the token, skip it, check for equal */
4217         Tok = D->Tok;
4218         NextToken (D);
4219         if (!ConsumeEqual (D)) {
4220             goto ErrorExit;
4221         }
4222
4223         /* Check what the token was */
4224         switch (Tok) {
4225
4226             case TOK_ADDRSIZE:
4227                 NextToken (D);
4228                 InfoBits |= ibAddrSize;
4229                 break;
4230
4231             case TOK_DEF:
4232                 while (1) {
4233                     if (!IntConstFollows (D)) {
4234                         goto ErrorExit;
4235                     }
4236                     CollAppendId (&DefLineIds, (unsigned) D->IVal);
4237                     NextToken (D);
4238                     if (D->Tok != TOK_PLUS) {
4239                         break;
4240                     }
4241                     NextToken (D);
4242                 }
4243                 InfoBits |= ibDefLineId;
4244                 break;
4245
4246             case TOK_EXPORT:
4247                 if (!IntConstFollows (D)) {
4248                     goto ErrorExit;
4249                 }
4250                 ExportId = D->IVal;
4251                 InfoBits |= ibExportId;
4252                 NextToken (D);
4253                 break;
4254
4255             case TOK_FILE:
4256                 if (!IntConstFollows (D)) {
4257                     goto ErrorExit;
4258                 }
4259                 FileId = D->IVal;
4260                 InfoBits |= ibFileId;
4261                 NextToken (D);
4262                 break;
4263
4264             case TOK_ID:
4265                 if (!IntConstFollows (D)) {
4266                     goto ErrorExit;
4267                 }
4268                 Id = D->IVal;
4269                 NextToken (D);
4270                 InfoBits |= ibId;
4271                 break;
4272
4273             case TOK_NAME:
4274                 if (!StrConstFollows (D)) {
4275                     goto ErrorExit;
4276                 }
4277                 SB_Copy (&Name, &D->SVal);
4278                 SB_Terminate (&Name);
4279                 InfoBits |= ibName;
4280                 NextToken (D);
4281                 break;
4282
4283             case TOK_PARENT:
4284                 if (!IntConstFollows (D)) {
4285                     goto ErrorExit;
4286                 }
4287                 ParentId = D->IVal;
4288                 NextToken (D);
4289                 InfoBits |= ibParentId;
4290                 break;
4291
4292             case TOK_REF:
4293                 while (1) {
4294                     if (!IntConstFollows (D)) {
4295                         goto ErrorExit;
4296                     }
4297                     CollAppendId (&RefLineIds, (unsigned) D->IVal);
4298                     NextToken (D);
4299                     if (D->Tok != TOK_PLUS) {
4300                         break;
4301                     }
4302                     NextToken (D);
4303                 }
4304                 InfoBits |= ibRefLineId;
4305                 break;
4306
4307             case TOK_SCOPE:
4308                 if (!IntConstFollows (D)) {
4309                     goto ErrorExit;
4310                 }
4311                 ScopeId = D->IVal;
4312                 NextToken (D);
4313                 InfoBits |= ibScopeId;
4314                 break;
4315
4316             case TOK_SEGMENT:
4317                 if (!IntConstFollows (D)) {
4318                     goto ErrorExit;
4319                 }
4320                 SegId = (unsigned) D->IVal;
4321                 InfoBits |= ibSegId;
4322                 NextToken (D);
4323                 break;
4324
4325             case TOK_SIZE:
4326                 if (!IntConstFollows (D)) {
4327                     goto ErrorExit;
4328                 }
4329                 Size = (cc65_size) D->IVal;
4330                 InfoBits |= ibSize;
4331                 NextToken (D);
4332                 break;
4333
4334             case TOK_TYPE:
4335                 switch (D->Tok) {
4336                     case TOK_EQUATE:    Type = CC65_SYM_EQUATE;         break;
4337                     case TOK_IMPORT:    Type = CC65_SYM_IMPORT;         break;
4338                     case TOK_LABEL:     Type = CC65_SYM_LABEL;          break;
4339                     default:
4340                         ParseError (D, CC65_ERROR,
4341                                     "Unknown value for attribute \"type\"");
4342                         SkipLine (D);
4343                         goto ErrorExit;
4344                 }
4345                 NextToken (D);
4346                 InfoBits |= ibType;
4347                 break;
4348
4349             case TOK_VALUE:
4350                 if (!IntConstFollows (D)) {
4351                     goto ErrorExit;
4352                 }
4353                 Value = D->IVal;
4354                 InfoBits |= ibValue;
4355                 NextToken (D);
4356                 break;
4357
4358             default:
4359                 /* NOTREACHED */
4360                 UnexpectedToken (D);
4361                 goto ErrorExit;
4362
4363         }
4364
4365         /* Comma or done */
4366         if (D->Tok != TOK_COMMA) {
4367             break;
4368         }
4369         NextToken (D);
4370     }
4371
4372     /* Check for end of line */
4373     if (D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
4374         UnexpectedToken (D);
4375         SkipLine (D);
4376         goto ErrorExit;
4377     }
4378
4379     /* Check for required and/or matched information */
4380     if ((InfoBits & ibRequired) != ibRequired) {
4381         ParseError (D, CC65_ERROR, "Required attributes missing");
4382         goto ErrorExit;
4383     }
4384     if ((InfoBits & (ibScopeId | ibParentId)) == 0 ||
4385         (InfoBits & (ibScopeId | ibParentId)) == (ibScopeId | ibParentId)) {
4386         ParseError (D, CC65_ERROR, "Only one of \"parent\", \"scope\" must be specified");
4387         goto ErrorExit;
4388     }
4389
4390     /* Create the symbol info */
4391     S = NewSymInfo (&Name);
4392     S->Id         = Id;
4393     S->Type       = Type;
4394     S->Value      = Value;
4395     S->Size       = Size;
4396     S->Exp.Id     = ExportId;
4397     S->Seg.Id     = SegId;
4398     S->Scope.Id   = ScopeId;
4399     S->Parent.Id  = ParentId;
4400     CollMove (&DefLineIds, &S->DefLineInfoList);
4401     CollMove (&RefLineIds, &S->RefLineInfoList);
4402
4403     /* Remember it */
4404     CollReplaceExpand (&D->Info->SymInfoById, S, Id);
4405     CollAppend (&D->Info->SymInfoByName, S);
4406     CollAppend (&D->Info->SymInfoByVal, S);
4407
4408 ErrorExit:
4409     /* Entry point in case of errors */
4410     CollDone (&DefLineIds);
4411     CollDone (&RefLineIds);
4412     SB_Done (&Name);
4413     return;
4414 }
4415
4416
4417
4418 static void ParseType (InputData* D)
4419 /* Parse a TYPE line */
4420 {
4421     /* Most of the following variables are initialized with a value that is
4422     ** overwritten later. This is just to avoid compiler warnings.
4423     */
4424     unsigned            Id = CC65_INV_ID;
4425     StrBuf              Value = STRBUF_INITIALIZER;
4426
4427     TypeInfo*           T;
4428     enum {
4429         ibNone          = 0x0000,
4430
4431         ibId            = 0x01,
4432         ibValue         = 0x02,
4433
4434         ibRequired      = ibId | ibValue,
4435     } InfoBits = ibNone;
4436
4437     /* Skip the SYM token */
4438     NextToken (D);
4439
4440     /* More stuff follows */
4441     while (1) {
4442
4443         Token Tok;
4444
4445         /* Something we know? */
4446         if (D->Tok != TOK_ID    && D->Tok != TOK_VALUE) {
4447
4448             /* Try smart error recovery */
4449             if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
4450                 UnknownKeyword (D);
4451                 continue;
4452             }
4453
4454             /* Done */
4455             break;
4456         }
4457
4458         /* Remember the token, skip it, check for equal */
4459         Tok = D->Tok;
4460         NextToken (D);
4461         if (!ConsumeEqual (D)) {
4462             goto ErrorExit;
4463         }
4464
4465         /* Check what the token was */
4466         switch (Tok) {
4467
4468             case TOK_ID:
4469                 if (!IntConstFollows (D)) {
4470                     goto ErrorExit;
4471                 }
4472                 Id = D->IVal;
4473                 NextToken (D);
4474                 InfoBits |= ibId;
4475                 break;
4476
4477             case TOK_VALUE:
4478                 if (!StrConstFollows (D)) {
4479                     goto ErrorExit;
4480                 }
4481                 SB_Copy (&Value, &D->SVal);
4482                 InfoBits |= ibValue;
4483                 NextToken (D);
4484                 break;
4485
4486             default:
4487                 /* NOTREACHED */
4488                 UnexpectedToken (D);
4489                 goto ErrorExit;
4490
4491         }
4492
4493         /* Comma or done */
4494         if (D->Tok != TOK_COMMA) {
4495             break;
4496         }
4497         NextToken (D);
4498     }
4499
4500     /* Check for end of line */
4501     if (D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
4502         UnexpectedToken (D);
4503         SkipLine (D);
4504         goto ErrorExit;
4505     }
4506
4507     /* Check for required and/or matched information */
4508     if ((InfoBits & ibRequired) != ibRequired) {
4509         ParseError (D, CC65_ERROR, "Required attributes missing");
4510         goto ErrorExit;
4511     }
4512
4513     /* Parse the type string to create the type info */
4514     T = ParseTypeString (D, &Value);
4515     if (T == 0) {
4516         goto ErrorExit;
4517     }
4518     T->Id       = Id;
4519
4520     /* Remember it */
4521     CollReplaceExpand (&D->Info->TypeInfoById, T, Id);
4522
4523 ErrorExit:
4524     /* Entry point in case of errors */
4525     SB_Done (&Value);
4526     return;
4527 }
4528
4529
4530
4531 static void ParseVersion (InputData* D)
4532 /* Parse a VERSION line */
4533 {
4534     enum {
4535         ibNone      = 0x00,
4536         ibMajor     = 0x01,
4537         ibMinor     = 0x02,
4538         ibRequired  = ibMajor | ibMinor,
4539     } InfoBits = ibNone;
4540
4541     /* Skip the VERSION token */
4542     NextToken (D);
4543
4544     /* More stuff follows */
4545     while (D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
4546
4547         switch (D->Tok) {
4548
4549             case TOK_MAJOR:
4550                 NextToken (D);
4551                 if (!ConsumeEqual (D)) {
4552                     goto ErrorExit;
4553                 }
4554                 if (!IntConstFollows (D)) {
4555                     goto ErrorExit;
4556                 }
4557                 D->Info->MajorVersion = D->IVal;
4558                 NextToken (D);
4559                 InfoBits |= ibMajor;
4560                 break;
4561
4562             case TOK_MINOR:
4563                 NextToken (D);
4564                 if (!ConsumeEqual (D)) {
4565                     goto ErrorExit;
4566                 }
4567                 if (!IntConstFollows (D)) {
4568                     goto ErrorExit;
4569                 }
4570                 D->Info->MinorVersion = D->IVal;
4571                 NextToken (D);
4572                 InfoBits |= ibMinor;
4573                 break;
4574
4575             case TOK_IDENT:
4576                 /* Try to skip unknown keywords that may have been added by
4577                 ** a later version.
4578                 */
4579                 UnknownKeyword (D);
4580                 break;
4581
4582             default:
4583                 UnexpectedToken (D);
4584                 SkipLine (D);
4585                 goto ErrorExit;
4586         }
4587
4588         /* Comma follows before next attribute */
4589         if (D->Tok == TOK_COMMA) {
4590             NextToken (D);
4591         } else if (D->Tok == TOK_EOL || D->Tok == TOK_EOF) {
4592             break;
4593         } else {
4594             UnexpectedToken (D);
4595             goto ErrorExit;
4596         }
4597     }
4598
4599     /* Check for required information */
4600     if ((InfoBits & ibRequired) != ibRequired) {
4601         ParseError (D, CC65_ERROR, "Required attributes missing");
4602         goto ErrorExit;
4603     }
4604
4605 ErrorExit:
4606     /* Entry point in case of errors */
4607     return;
4608 }
4609
4610
4611
4612 /*****************************************************************************/
4613 /*                              Data processing                              */
4614 /*****************************************************************************/
4615
4616
4617
4618 static int FindCSymInfoByName (const Collection* CSymInfos, const char* Name,
4619                                unsigned* Index)
4620 /* Find the C symbol info with a given file name. The function returns true if
4621 ** the name was found. In this case, Index contains the index of the first item
4622 ** that matches. If the item wasn't found, the function returns false and
4623 ** Index contains the insert position for Name.
4624 */
4625 {
4626     /* Do a binary search */
4627     int Lo = 0;
4628     int Hi = (int) CollCount (CSymInfos) - 1;
4629     int Found = 0;
4630     while (Lo <= Hi) {
4631
4632         /* Mid of range */
4633         int Cur = (Lo + Hi) / 2;
4634
4635         /* Get item */
4636         const CSymInfo* CurItem = CollAt (CSymInfos, Cur);
4637
4638         /* Compare */
4639         int Res = strcmp (CurItem->Name, Name);
4640
4641         /* Found? */
4642         if (Res < 0) {
4643             Lo = Cur + 1;
4644         } else {
4645             Hi = Cur - 1;
4646             /* Since we may have duplicates, repeat the search until we've
4647             ** the first item that has a match.
4648             */
4649             if (Res == 0) {
4650                 Found = 1;
4651             }
4652         }
4653     }
4654
4655     /* Pass back the index. This is also the insert position */
4656     *Index = Lo;
4657     return Found;
4658 }
4659
4660
4661
4662 static int FindFileInfoByName (const Collection* FileInfos, const char* Name,
4663                                unsigned* Index)
4664 /* Find the FileInfo for a given file name. The function returns true if the
4665 ** name was found. In this case, Index contains the index of the first item
4666 ** that matches. If the item wasn't found, the function returns false and
4667 ** Index contains the insert position for Name.
4668 */
4669 {
4670     /* Do a binary search */
4671     int Lo = 0;
4672     int Hi = (int) CollCount (FileInfos) - 1;
4673     int Found = 0;
4674     while (Lo <= Hi) {
4675
4676         /* Mid of range */
4677         int Cur = (Lo + Hi) / 2;
4678
4679         /* Get item */
4680         const FileInfo* CurItem = CollAt (FileInfos, Cur);
4681
4682         /* Compare */
4683         int Res = strcmp (CurItem->Name, Name);
4684
4685         /* Found? */
4686         if (Res < 0) {
4687             Lo = Cur + 1;
4688         } else {
4689             Hi = Cur - 1;
4690             /* Since we may have duplicates, repeat the search until we've
4691             ** the first item that has a match.
4692             */
4693             if (Res == 0) {
4694                 Found = 1;
4695             }
4696         }
4697     }
4698
4699     /* Pass back the index. This is also the insert position */
4700     *Index = Lo;
4701     return Found;
4702 }
4703
4704
4705
4706 static SpanInfoListEntry* FindSpanInfoByAddr (const SpanInfoList* L, cc65_addr Addr)
4707 /* Find the index of a SpanInfo for a given address. Returns 0 if no such
4708 ** SpanInfo was found.
4709 */
4710 {
4711     /* Do a binary search */
4712     int Lo = 0;
4713     int Hi = (int) L->Count - 1;
4714     while (Lo <= Hi) {
4715
4716         /* Mid of range */
4717         int Cur = (Lo + Hi) / 2;
4718
4719         /* Get item */
4720         SpanInfoListEntry* CurItem = &L->List[Cur];
4721
4722         /* Found? */
4723         if (CurItem->Addr > Addr) {
4724             Hi = Cur - 1;
4725         } else if (CurItem->Addr < Addr) {
4726             Lo = Cur + 1;
4727         } else {
4728             /* Found */
4729             return CurItem;
4730         }
4731     }
4732
4733     /* Not found */
4734     return 0;
4735 }
4736
4737
4738
4739 static LineInfo* FindLineInfoByLine (const Collection* LineInfos, cc65_line Line)
4740 /* Find the LineInfo for a given line number. The function returns the line
4741 ** info or NULL if none was found.
4742 */
4743 {
4744     /* Do a binary search */
4745     int Lo = 0;
4746     int Hi = (int) CollCount (LineInfos) - 1;
4747     while (Lo <= Hi) {
4748
4749         /* Mid of range */
4750         int Cur = (Lo + Hi) / 2;
4751
4752         /* Get item */
4753         LineInfo* CurItem = CollAt (LineInfos, Cur);
4754
4755         /* Found? */
4756         if (Line > CurItem->Line) {
4757             Lo = Cur + 1;
4758         } else if (Line < CurItem->Line) {
4759             Hi = Cur - 1;
4760         } else {
4761             /* Found */
4762             return CurItem;
4763         }
4764     }
4765
4766     /* Not found */
4767     return 0;
4768 }
4769
4770
4771
4772 static SegInfo* FindSegInfoByName (const Collection* SegInfos, const char* Name)
4773 /* Find the SegInfo for a given segment name. The function returns the segment
4774 ** info or NULL if none was found.
4775 */
4776 {
4777     /* Do a binary search */
4778     int Lo = 0;
4779     int Hi = (int) CollCount (SegInfos) - 1;
4780     while (Lo <= Hi) {
4781
4782         /* Mid of range */
4783         int Cur = (Lo + Hi) / 2;
4784
4785         /* Get item */
4786         SegInfo* CurItem = CollAt (SegInfos, Cur);
4787
4788         /* Compare */
4789         int Res = strcmp (CurItem->Name, Name);
4790
4791         /* Found? */
4792         if (Res < 0) {
4793             Lo = Cur + 1;
4794         } else if (Res > 0) {
4795             Hi = Cur - 1;
4796         } else {
4797             /* Found */
4798             return CurItem;
4799         }
4800     }
4801
4802     /* Not found */
4803     return 0;
4804 }
4805
4806
4807
4808 static int FindScopeInfoByName (const Collection* ScopeInfos, const char* Name,
4809                                 unsigned* Index)
4810 /* Find the ScopeInfo for a given scope name. The function returns true if the
4811 ** name was found. In this case, Index contains the index of the first item
4812 ** that matches. If the item wasn't found, the function returns false and
4813 ** Index contains the insert position for Name.
4814 */
4815 {
4816     /* Do a binary search */
4817     int Lo = 0;
4818     int Hi = (int) CollCount (ScopeInfos) - 1;
4819     int Found = 0;
4820     while (Lo <= Hi) {
4821
4822         /* Mid of range */
4823         int Cur = (Lo + Hi) / 2;
4824
4825         /* Get item */
4826         const ScopeInfo* CurItem = CollAt (ScopeInfos, Cur);
4827
4828         /* Compare */
4829         int Res = strcmp (CurItem->Name, Name);
4830
4831         /* Found? */
4832         if (Res < 0) {
4833             Lo = Cur + 1;
4834         } else {
4835             Hi = Cur - 1;
4836             /* Since we may have duplicates, repeat the search until we've
4837             ** the first item that has a match.
4838             */
4839             if (Res == 0) {
4840                 Found = 1;
4841             }
4842         }
4843     }
4844
4845     /* Pass back the index. This is also the insert position */
4846     *Index = Lo;
4847     return Found;
4848 }
4849
4850
4851
4852 static int FindSymInfoByName (const Collection* SymInfos, const char* Name,
4853                               unsigned* Index)
4854 /* Find the SymInfo for a given file name. The function returns true if the
4855 ** name was found. In this case, Index contains the index of the first item
4856 ** that matches. If the item wasn't found, the function returns false and
4857 ** Index contains the insert position for Name.
4858 */
4859 {
4860     /* Do a binary search */
4861     int Lo = 0;
4862     int Hi = (int) CollCount (SymInfos) - 1;
4863     int Found = 0;
4864     while (Lo <= Hi) {
4865
4866         /* Mid of range */
4867         int Cur = (Lo + Hi) / 2;
4868
4869         /* Get item */
4870         const SymInfo* CurItem = CollAt (SymInfos, Cur);
4871
4872         /* Compare */
4873         int Res = strcmp (CurItem->Name, Name);
4874
4875         /* Found? */
4876         if (Res < 0) {
4877             Lo = Cur + 1;
4878         } else {
4879             Hi = Cur - 1;
4880             /* Since we may have duplicates, repeat the search until we've
4881             ** the first item that has a match.
4882             */
4883             if (Res == 0) {
4884                 Found = 1;
4885             }
4886         }
4887     }
4888
4889     /* Pass back the index. This is also the insert position */
4890     *Index = Lo;
4891     return Found;
4892 }
4893
4894
4895
4896 static int FindSymInfoByValue (const Collection* SymInfos, long Value,
4897                                unsigned* Index)
4898 /* Find the SymInfo for a given value. The function returns true if the
4899 ** value was found. In this case, Index contains the index of the first item
4900 ** that matches. If the item wasn't found, the function returns false and
4901 ** Index contains the insert position for the given value.
4902 */
4903 {
4904     /* Do a binary search */
4905     int Lo = 0;
4906     int Hi = (int) CollCount (SymInfos) - 1;
4907     int Found = 0;
4908     while (Lo <= Hi) {
4909
4910         /* Mid of range */
4911         int Cur = (Lo + Hi) / 2;
4912
4913         /* Get item */
4914         SymInfo* CurItem = CollAt (SymInfos, Cur);
4915
4916         /* Found? */
4917         if (Value > CurItem->Value) {
4918             Lo = Cur + 1;
4919         } else {
4920             Hi = Cur - 1;
4921             /* Since we may have duplicates, repeat the search until we've
4922             ** the first item that has a match.
4923             */
4924             if (Value == CurItem->Value) {
4925                 Found = 1;
4926             }
4927         }
4928     }
4929
4930     /* Pass back the index. This is also the insert position */
4931     *Index = Lo;
4932     return Found;
4933 }
4934
4935
4936
4937 static void ProcessCSymInfo (InputData* D)
4938 /* Postprocess c symbol infos */
4939 {
4940     unsigned I;
4941
4942     /* Walk over all c symbols. Resolve the ids and add the c symbols to the
4943     ** corresponding asm symbols.
4944     */
4945     for (I = 0; I < CollCount (&D->Info->CSymInfoById); ++I) {
4946
4947         /* Get this c symbol info */
4948         CSymInfo* S = CollAt (&D->Info->CSymInfoById, I);
4949
4950         /* Resolve the asm symbol */
4951         if (S->Sym.Id == CC65_INV_ID) {
4952             S->Sym.Info = 0;
4953         } else if (S->Sym.Id >= CollCount (&D->Info->SymInfoById)) {
4954             ParseError (D,
4955                         CC65_ERROR,
4956                         "Invalid symbol id %u for c symbol with id %u",
4957                         S->Sym.Id, S->Id);
4958             S->Sym.Info = 0;
4959         } else {
4960             S->Sym.Info = CollAt (&D->Info->SymInfoById, S->Sym.Id);
4961
4962             /* For normal (=static) symbols, add a backlink to the symbol but
4963             ** check that there is not more than one.
4964             */
4965             if (S->SC != CC65_CSYM_AUTO && S->SC != CC65_CSYM_REG) {
4966                 if (S->Sym.Info->CSym) {
4967                     ParseError (D,
4968                                 CC65_ERROR,
4969                                 "Asm symbol id %u has more than one C symbol attached",
4970                                 S->Sym.Info->Id);
4971                     S->Sym.Info = 0;
4972                 } else {
4973                     S->Sym.Info->CSym = S;
4974                 }
4975             }
4976         }
4977
4978         /* Resolve the type */
4979         if (S->Type.Id >= CollCount (&D->Info->TypeInfoById)) {
4980             ParseError (D,
4981                         CC65_ERROR,
4982                         "Invalid type id %u for c symbol with id %u",
4983                         S->Type.Id, S->Id);
4984             S->Type.Info = 0;
4985         } else {
4986             S->Type.Info = CollAt (&D->Info->TypeInfoById, S->Type.Id);
4987         }
4988
4989         /* Resolve the scope */
4990         if (S->Scope.Id >= CollCount (&D->Info->ScopeInfoById)) {
4991             ParseError (D,
4992                         CC65_ERROR,
4993                         "Invalid scope id %u for c symbol with id %u",
4994                         S->Scope.Id, S->Id);
4995             S->Scope.Info = 0;
4996         } else {
4997             S->Scope.Info = CollAt (&D->Info->ScopeInfoById, S->Scope.Id);
4998
4999             /* Add the c symbol to the list of all c symbols for this scope */
5000             if (S->Scope.Info->CSymInfoByName == 0) {
5001                 S->Scope.Info->CSymInfoByName = CollNew ();
5002             }
5003             CollAppend (S->Scope.Info->CSymInfoByName, S);
5004
5005             /* If the scope has an owner symbol, it's a .PROC scope. If this
5006             ** symbol is identical to the one attached to the C symbol, this
5007             ** is actuallay a C function and the scope is the matching scope.
5008             ** Remember the C symbol in the scope in this case.
5009             ** Beware: Scopes haven't been postprocessed, so we don't have a
5010             ** pointer but just an id.
5011             */
5012             if (S->Sym.Info && S->Scope.Info->Label.Id == S->Sym.Info->Id) {
5013                 /* This scope is our function scope */
5014                 S->Scope.Info->CSymFunc = S;
5015                 /* Add it to the list of all c functions */
5016                 CollAppend (&D->Info->CSymFuncByName, S);
5017             }
5018
5019         }
5020     }
5021
5022     /* Walk over all scopes and sort the c symbols by name. */
5023     for (I = 0; I < CollCount (&D->Info->ScopeInfoById); ++I) {
5024
5025         /* Get this scope */
5026         ScopeInfo* S = CollAt (&D->Info->ScopeInfoById, I);
5027
5028         /* Ignore scopes without C symbols */
5029         if (CollCount (S->CSymInfoByName) > 1) {
5030             /* Sort the c symbols for this scope by name */
5031             CollSort (S->CSymInfoByName, CompareCSymInfoByName);
5032         }
5033     }
5034
5035     /* Sort the main list of all C functions by name */
5036     CollSort (&D->Info->CSymFuncByName, CompareCSymInfoByName);
5037 }
5038
5039
5040
5041 static void ProcessFileInfo (InputData* D)
5042 /* Postprocess file infos */
5043 {
5044     /* Walk over all file infos and resolve the module ids */
5045     unsigned I;
5046     for (I = 0; I < CollCount (&D->Info->FileInfoById); ++I) {
5047
5048         /* Get this file info */
5049         FileInfo* F = CollAt (&D->Info->FileInfoById, I);
5050
5051         /* Resolve the module ids */
5052         unsigned J;
5053         for (J = 0; J < CollCount (&F->ModInfoByName); ++J) {
5054
5055             /* Get the id of this module */
5056             unsigned ModId = CollIdAt (&F->ModInfoByName, J);
5057             if (ModId >= CollCount (&D->Info->ModInfoById)) {
5058                 ParseError (D,
5059                             CC65_ERROR,
5060                             "Invalid module id %u for file with id %u",
5061                             ModId, F->Id);
5062                 CollReplace (&F->ModInfoByName, 0, J);
5063             } else {
5064
5065                 /* Get a pointer to the module */
5066                 ModInfo* M = CollAt (&D->Info->ModInfoById, ModId);
5067
5068                 /* Replace the id by the pointer */
5069                 CollReplace (&F->ModInfoByName, M, J);
5070
5071                 /* Insert a backpointer into the module */
5072                 CollAppend (&M->FileInfoByName, F);
5073             }
5074         }
5075
5076         /* If we didn't have any errors, sort the modules by name */
5077         if (D->Errors == 0) {
5078             CollSort (&F->ModInfoByName, CompareModInfoByName);
5079         }
5080     }
5081
5082     /* Now walk over all modules and sort the file infos by name */
5083     for (I = 0; I < CollCount (&D->Info->ModInfoById); ++I) {
5084
5085         /* Get this module info */
5086         ModInfo* M = CollAt (&D->Info->ModInfoById, I);
5087
5088         /* Sort the files by name */
5089         CollSort (&M->FileInfoByName, CompareFileInfoByName);
5090     }
5091
5092     /* Sort the file infos by name, so we can do a binary search */
5093     CollSort (&D->Info->FileInfoByName, CompareFileInfoByName);
5094 }
5095
5096
5097
5098 static void ProcessLineInfo (InputData* D)
5099 /* Postprocess line infos */
5100 {
5101     unsigned I, J;
5102
5103     /* Get pointers to the collections */
5104     Collection* LineInfos = &D->Info->LineInfoById;
5105     Collection* FileInfos = &D->Info->FileInfoById;
5106
5107     /* Walk over the line infos and replace the id numbers of file and segment
5108     ** with pointers to the actual structs. Add the line info to each file
5109     ** where it is defined. Resolve the spans and add backpointers to the
5110     ** spans.
5111     */
5112     for (I = 0; I < CollCount (LineInfos); ++I) {
5113
5114         /* Get LineInfo struct */
5115         LineInfo* L = CollAt (LineInfos, I);
5116
5117         /* Replace the file id by a pointer to the FileInfo. Add a back
5118         ** pointer
5119         */
5120         if (L->File.Id >= CollCount (FileInfos)) {
5121             ParseError (D,
5122                         CC65_ERROR,
5123                         "Invalid file id %u for line with id %u",
5124                         L->File.Id, L->Id);
5125             L->File.Info = 0;
5126         } else {
5127             L->File.Info = CollAt (FileInfos, L->File.Id);
5128             CollAppend (&L->File.Info->LineInfoByLine, L);
5129         }
5130
5131         /* Resolve the spans ids */
5132         for (J = 0; J < CollCount (&L->SpanInfoList); ++J) {
5133
5134             /* Get the id of this span */
5135             unsigned SpanId = CollIdAt (&L->SpanInfoList, J);
5136             if (SpanId >= CollCount (&D->Info->SpanInfoById)) {
5137                 ParseError (D,
5138                             CC65_ERROR,
5139                             "Invalid span id %u for line with id %u",
5140                             SpanId, L->Id);
5141                 CollReplace (&L->SpanInfoList, 0, J);
5142             } else {
5143
5144                 /* Get a pointer to the span */
5145                 SpanInfo* SP = CollAt (&D->Info->SpanInfoById, SpanId);
5146
5147                 /* Replace the id by the pointer */
5148                 CollReplace (&L->SpanInfoList, SP, J);
5149
5150                 /* Insert a backpointer into the span */
5151                 if (SP->LineInfoList == 0) {
5152                     SP->LineInfoList = CollNew ();
5153                 }
5154                 CollAppend (SP->LineInfoList, L);
5155             }
5156         }
5157     }
5158
5159     /* Walk over all files and sort the line infos for each file so we can
5160     ** do a binary search later.
5161     */
5162     for (I = 0; I < CollCount (FileInfos); ++I) {
5163
5164         /* Get a pointer to this file info */
5165         FileInfo* F = CollAt (FileInfos, I);
5166
5167         /* Sort the line infos for this file */
5168         CollSort (&F->LineInfoByLine, CompareLineInfoByLine);
5169     }
5170 }
5171
5172
5173
5174 static void ProcessModInfo (InputData* D)
5175 /* Postprocess module infos */
5176 {
5177     unsigned I;
5178
5179     /* Walk over all scopes and resolve the ids */
5180     for (I = 0; I < CollCount (&D->Info->ModInfoById); ++I) {
5181
5182         /* Get this module info */
5183         ModInfo* M = CollAt (&D->Info->ModInfoById, I);
5184
5185         /* Resolve the main file */
5186         if (M->File.Id >= CollCount (&D->Info->FileInfoById)) {
5187             ParseError (D,
5188                         CC65_ERROR,
5189                         "Invalid file id %u for module with id %u",
5190                         M->File.Id, M->Id);
5191             M->File.Info = 0;
5192         } else {
5193             M->File.Info = CollAt (&D->Info->FileInfoById, M->File.Id);
5194         }
5195
5196         /* Resolve the library */
5197         if (M->Lib.Id == CC65_INV_ID) {
5198             M->Lib.Info = 0;
5199         } else if (M->Lib.Id >= CollCount (&D->Info->LibInfoById)) {
5200             ParseError (D,
5201                         CC65_ERROR,
5202                         "Invalid library id %u for module with id %u",
5203                         M->Lib.Id, M->Id);
5204             M->Lib.Info = 0;
5205         } else {
5206             M->Lib.Info = CollAt (&D->Info->LibInfoById, M->Lib.Id);
5207         }
5208     }
5209
5210     /* Sort the collection that contains the module info by name */
5211     CollSort (&D->Info->ModInfoByName, CompareModInfoByName);
5212 }
5213
5214
5215
5216 static void ProcessScopeInfo (InputData* D)
5217 /* Postprocess scope infos */
5218 {
5219     unsigned I, J;
5220
5221     /* Walk over all scopes. Resolve the ids and add the scopes to the list
5222     ** of scopes for a module.
5223     */
5224     for (I = 0; I < CollCount (&D->Info->ScopeInfoById); ++I) {
5225
5226         /* Get this scope info */
5227         ScopeInfo* S = CollAt (&D->Info->ScopeInfoById, I);
5228
5229         /* Resolve the module */
5230         if (S->Mod.Id >= CollCount (&D->Info->ModInfoById)) {
5231             ParseError (D,
5232                         CC65_ERROR,
5233                         "Invalid module id %u for scope with id %u",
5234                         S->Mod.Id, S->Id);
5235             S->Mod.Info = 0;
5236         } else {
5237             S->Mod.Info = CollAt (&D->Info->ModInfoById, S->Mod.Id);
5238
5239             /* Add the scope to the list of scopes for this module */
5240             CollAppend (&S->Mod.Info->ScopeInfoByName, S);
5241
5242             /* If this is a main scope, add a pointer to the corresponding
5243             ** module.
5244             */
5245             if (S->Parent.Id == CC65_INV_ID) {
5246                 /* No parent means main scope */
5247                 S->Mod.Info->MainScope = S;
5248             }
5249
5250             /* If this is the scope that implements a C function, add the
5251             ** function to the list of all functions in this module.
5252             */
5253             if (S->CSymFunc) {
5254                 CollAppend (&S->Mod.Info->CSymFuncByName, S->CSymFunc);
5255             }
5256         }
5257
5258         /* Resolve the parent scope */
5259         if (S->Parent.Id == CC65_INV_ID) {
5260             S->Parent.Info = 0;
5261         } else if (S->Parent.Id >= CollCount (&D->Info->ScopeInfoById)) {
5262             ParseError (D,
5263                         CC65_ERROR,
5264                         "Invalid parent scope id %u for scope with id %u",
5265                         S->Parent.Id, S->Id);
5266             S->Parent.Info = 0;
5267         } else {
5268             S->Parent.Info = CollAt (&D->Info->ScopeInfoById, S->Parent.Id);
5269
5270             /* Set a backpointer in the parent */
5271             if (S->Parent.Info->ChildScopeList == 0) {
5272                 S->Parent.Info->ChildScopeList = CollNew ();
5273             }
5274             CollAppend (S->Parent.Info->ChildScopeList, S);
5275         }
5276
5277         /* Resolve the label */
5278         if (S->Label.Id == CC65_INV_ID) {
5279             S->Label.Info = 0;
5280         } else if (S->Label.Id >= CollCount (&D->Info->SymInfoById)) {
5281             ParseError (D,
5282                         CC65_ERROR,
5283                         "Invalid label id %u for scope with id %u",
5284                         S->Label.Id, S->Id);
5285             S->Label.Info = 0;
5286         } else {
5287             S->Label.Info = CollAt (&D->Info->SymInfoById, S->Label.Id);
5288         }
5289
5290         /* Resolve the spans ids */
5291         for (J = 0; J < CollCount (&S->SpanInfoList); ++J) {
5292
5293             /* Get the id of this span */
5294             unsigned SpanId = CollIdAt (&S->SpanInfoList, J);
5295             if (SpanId >= CollCount (&D->Info->SpanInfoById)) {
5296                 ParseError (D,
5297                             CC65_ERROR,
5298                             "Invalid span id %u for scope with id %u",
5299                             SpanId, S->Id);
5300                 CollReplace (&S->SpanInfoList, 0, J);
5301             } else {
5302
5303                 /* Get a pointer to the span */
5304                 SpanInfo* SP = CollAt (&D->Info->SpanInfoById, SpanId);
5305
5306                 /* Replace the id by the pointer */
5307                 CollReplace (&S->SpanInfoList, SP, J);
5308
5309                 /* Insert a backpointer into the span */
5310                 if (SP->ScopeInfoList == 0) {
5311                     SP->ScopeInfoList = CollNew ();
5312                 }
5313                 CollAppend (SP->ScopeInfoList, S);
5314             }
5315         }
5316     }
5317
5318     /* Walk over all modules. If a module doesn't have scopes, it wasn't
5319     ** compiled with debug info which is ok. If it has debug info, it must
5320     ** also have a main scope. If there are scopes, sort them by name. Do
5321     ** also sort C functions in this module by name.
5322     */
5323     for (I = 0; I < CollCount (&D->Info->ModInfoById); ++I) {
5324
5325         /* Get this module */
5326         ModInfo* M = CollAt (&D->Info->ModInfoById, I);
5327
5328         /* Ignore modules without any scopes (no debug info) */
5329         if (CollCount (&M->ScopeInfoByName) == 0) {
5330             continue;
5331         }
5332
5333         /* Must have a main scope */
5334         if (M->MainScope == 0) {
5335             ParseError (D,
5336                         CC65_ERROR,
5337                         "Module with id %u has no main scope",
5338                         M->Id);
5339         }
5340
5341         /* Sort the scopes for this module by name */
5342         CollSort (&M->ScopeInfoByName, CompareScopeInfoByName);
5343
5344         /* Sort the C functions in this module by name */
5345         CollSort (&M->CSymFuncByName, CompareCSymInfoByName);
5346     }
5347
5348     /* Sort the scope infos */
5349     CollSort (&D->Info->ScopeInfoByName, CompareScopeInfoByName);
5350 }
5351
5352
5353
5354 static void ProcessSegInfo (InputData* D)
5355 /* Postprocess segment infos */
5356 {
5357     /* Sort the segment infos by name */
5358     CollSort (&D->Info->SegInfoByName, CompareSegInfoByName);
5359 }
5360
5361
5362
5363 static void ProcessSpanInfo (InputData* D)
5364 /* Postprocess span infos */
5365 {
5366     unsigned I;
5367
5368     /* Temporary collection with span infos sorted by address */
5369     Collection SpanInfoByAddr = COLLECTION_INITIALIZER;
5370
5371     /* Resize the temporary collection */
5372     CollGrow (&SpanInfoByAddr, CollCount (&D->Info->SpanInfoById));
5373
5374     /* Walk over all spans and resolve the ids */
5375     for (I = 0; I < CollCount (&D->Info->SpanInfoById); ++I) {
5376
5377         /* Get this span info */
5378         SpanInfo* S = CollAt (&D->Info->SpanInfoById, I);
5379
5380         /* Resolve the segment and relocate the span */
5381         if (S->Seg.Id >= CollCount (&D->Info->SegInfoById)) {
5382             ParseError (D,
5383                         CC65_ERROR,
5384                         "Invalid segment id %u for span with id %u",
5385                         S->Seg.Id, S->Id);
5386             S->Seg.Info = 0;
5387         } else {
5388             S->Seg.Info = CollAt (&D->Info->SegInfoById, S->Seg.Id);
5389             S->Start += S->Seg.Info->Start;
5390             S->End   += S->Seg.Info->Start;
5391         }
5392
5393         /* Resolve the type if we have it */
5394         if (S->Type.Id == CC65_INV_ID) {
5395             S->Type.Info = 0;
5396         } else if (S->Type.Id >= CollCount (&D->Info->TypeInfoById)) {
5397             ParseError (D,
5398                         CC65_ERROR,
5399                         "Invalid type id %u for span with id %u",
5400                         S->Type.Id, S->Id);
5401             S->Type.Info = 0;
5402         } else {
5403             S->Type.Info = CollAt (&D->Info->TypeInfoById, S->Type.Id);
5404         }
5405
5406         /* Append this span info to the temporary collection that is later
5407         ** sorted by address.
5408         */
5409         CollAppend (&SpanInfoByAddr, S);
5410     }
5411
5412     /* Sort the collection with all span infos by address */
5413     CollSort (&SpanInfoByAddr, CompareSpanInfoByAddr);
5414
5415     /* Create the span info list from the span info collection */
5416     CreateSpanInfoList (&D->Info->SpanInfoByAddr, &SpanInfoByAddr);
5417
5418     /* Remove the temporary collection */
5419     CollDone (&SpanInfoByAddr);
5420 }
5421
5422
5423
5424 static void ProcessSymInfo (InputData* D)
5425 /* Postprocess symbol infos */
5426 {
5427     unsigned I, J;
5428
5429     /* Walk over the symbols and resolve the references */
5430     for (I = 0; I < CollCount (&D->Info->SymInfoById); ++I) {
5431
5432         /* Get the symbol info */
5433         SymInfo* S = CollAt (&D->Info->SymInfoById, I);
5434
5435         /* Resolve export */
5436         if (S->Exp.Id == CC65_INV_ID) {
5437             S->Exp.Info = 0;
5438         } else if (S->Exp.Id >= CollCount (&D->Info->SymInfoById)) {
5439             ParseError (D,
5440                         CC65_ERROR,
5441                         "Invalid export id %u for symbol with id %u",
5442                         S->Exp.Id, S->Id);
5443             S->Exp.Info = 0;
5444         } else {
5445             S->Exp.Info = CollAt (&D->Info->SymInfoById, S->Exp.Id);
5446
5447             /* Add a backpointer, so the export knows its imports */
5448             if (S->Exp.Info->ImportList == 0) {
5449                 S->Exp.Info->ImportList = CollNew ();
5450             }
5451             CollAppend (S->Exp.Info->ImportList, S);
5452         }
5453
5454         /* Resolve segment */
5455         if (S->Seg.Id == CC65_INV_ID) {
5456             S->Seg.Info = 0;
5457         } else if (S->Seg.Id >= CollCount (&D->Info->SegInfoById)) {
5458             ParseError (D,
5459                         CC65_ERROR,
5460                         "Invalid segment id %u for symbol with id %u",
5461                         S->Seg.Id, S->Id);
5462             S->Seg.Info = 0;
5463         } else {
5464             S->Seg.Info = CollAt (&D->Info->SegInfoById, S->Seg.Id);
5465         }
5466
5467         /* Resolve the scope */
5468         if (S->Scope.Id == CC65_INV_ID) {
5469             S->Scope.Info = 0;
5470         } else if (S->Scope.Id >= CollCount (&D->Info->ScopeInfoById)) {
5471             ParseError (D,
5472                         CC65_ERROR,
5473                         "Invalid scope id %u for symbol with id %u",
5474                         S->Scope.Id, S->Id);
5475             S->Scope.Info = 0;
5476         } else {
5477             S->Scope.Info = CollAt (&D->Info->ScopeInfoById, S->Scope.Id);
5478
5479             /* Place a backpointer to the symbol in the scope */
5480             CollAppend (&S->Scope.Info->SymInfoByName, S);
5481         }
5482
5483         /* Resolve the parent for cheap locals */
5484         if (S->Parent.Id == CC65_INV_ID) {
5485             S->Parent.Info = 0;
5486         } else if (S->Parent.Id >= CollCount (&D->Info->SymInfoById)) {
5487             ParseError (D,
5488                         CC65_ERROR,
5489                         "Invalid parent id %u for symbol with id %u",
5490                         S->Parent.Id, S->Id);
5491             S->Parent.Info = 0;
5492         } else {
5493             S->Parent.Info = CollAt (&D->Info->SymInfoById, S->Parent.Id);
5494
5495             /* Place a backpointer to the cheap local into the parent */
5496             if (S->Parent.Info->CheapLocals == 0) {
5497                 S->Parent.Info->CheapLocals = CollNew ();
5498             }
5499             CollAppend (S->Parent.Info->CheapLocals, S);
5500         }
5501
5502         /* Resolve the line infos for the symbol definition */
5503         for (J = 0; J < CollCount (&S->DefLineInfoList); ++J) {
5504
5505             /* Get the id of this line info */
5506             unsigned LineId = CollIdAt (&S->DefLineInfoList, J);
5507             if (LineId >= CollCount (&D->Info->LineInfoById)) {
5508                 ParseError (D,
5509                             CC65_ERROR,
5510                             "Invalid line id %u for symbol with id %u",
5511                             LineId, S->Id);
5512                 CollReplace (&S->DefLineInfoList, 0, J);
5513             } else {
5514                 /* Get a pointer to the line info */
5515                 LineInfo* LI = CollAt (&D->Info->LineInfoById, LineId);
5516
5517                 /* Replace the id by the pointer */
5518                 CollReplace (&S->DefLineInfoList, LI, J);
5519             }
5520         }
5521
5522         /* Resolve the line infos for symbol references */
5523         for (J = 0; J < CollCount (&S->RefLineInfoList); ++J) {
5524
5525             /* Get the id of this line info */
5526             unsigned LineId = CollIdAt (&S->RefLineInfoList, J);
5527             if (LineId >= CollCount (&D->Info->LineInfoById)) {
5528                 ParseError (D,
5529                             CC65_ERROR,
5530                             "Invalid line id %u for symbol with id %u",
5531                             LineId, S->Id);
5532                 CollReplace (&S->RefLineInfoList, 0, J);
5533             } else {
5534                 /* Get a pointer to the line info */
5535                 LineInfo* LI = CollAt (&D->Info->LineInfoById, LineId);
5536
5537                 /* Replace the id by the pointer */
5538                 CollReplace (&S->RefLineInfoList, LI, J);
5539             }
5540         }
5541
5542     }
5543
5544     /* Second run. Resolve scopes for cheap locals */
5545     for (I = 0; I < CollCount (&D->Info->SymInfoById); ++I) {
5546
5547         /* Get the symbol info */
5548         SymInfo* S = CollAt (&D->Info->SymInfoById, I);
5549
5550         /* Resolve the scope */
5551         if (S->Scope.Info == 0) {
5552             /* No scope - must have a parent */
5553             if (S->Parent.Info == 0) {
5554                 ParseError (D,
5555                             CC65_ERROR,
5556                             "Symbol with id %u has no parent and no scope",
5557                             S->Id);
5558             } else if (S->Parent.Info->Scope.Info == 0) {
5559                 ParseError (D,
5560                             CC65_ERROR,
5561                             "Symbol with id %u has parent %u without a scope",
5562                             S->Id, S->Parent.Info->Id);
5563             } else {
5564                 S->Scope.Info = S->Parent.Info->Scope.Info;
5565             }
5566         }
5567     }
5568
5569     /* Walk over the scopes and sort the symbols in the scope by name */
5570     for (I = 0; I < CollCount (&D->Info->ScopeInfoById); ++I) {
5571
5572         /* Get the scope info */
5573         ScopeInfo* S = CollAt (&D->Info->ScopeInfoById, I);
5574
5575         /* Sort the symbols in this scope by name */
5576         CollSort (&S->SymInfoByName, CompareSymInfoByName);
5577     }
5578
5579     /* Sort the symbol infos */
5580     CollSort (&D->Info->SymInfoByName, CompareSymInfoByName);
5581     CollSort (&D->Info->SymInfoByVal,  CompareSymInfoByVal);
5582 }
5583
5584
5585
5586 /*****************************************************************************/
5587 /*                             Debug info files                              */
5588 /*****************************************************************************/
5589
5590
5591
5592 cc65_dbginfo cc65_read_dbginfo (const char* FileName, cc65_errorfunc ErrFunc)
5593 /* Parse the debug info file with the given name. On success, the function
5594 ** will return a pointer to an opaque cc65_dbginfo structure, that must be
5595 ** passed to the other functions in this module to retrieve information.
5596 ** errorfunc is called in case of warnings and errors. If the file cannot be
5597 ** read successfully, NULL is returned.
5598 */
5599 {
5600     /* Data structure used to control scanning and parsing */
5601     InputData D = {
5602         0,                      /* Name of input file */
5603         1,                      /* Line number */
5604         0,                      /* Input file */
5605         0,                      /* Line at start of current token */
5606         0,                      /* Column at start of current token */
5607         0,                      /* Number of errors */
5608         0,                      /* Input file */
5609         ' ',                    /* Input character */
5610         TOK_INVALID,            /* Input token */
5611         0,                      /* Integer constant */
5612         STRBUF_INITIALIZER,     /* String constant */
5613         0,                      /* Function called in case of errors */
5614         0,                      /* Pointer to debug info */
5615     };
5616     D.FileName = FileName;
5617     D.Error    = ErrFunc;
5618
5619     /* Open the input file */
5620     D.F = fopen (FileName, "rt");
5621     if (D.F == 0) {
5622         /* Cannot open */
5623         ParseError (&D, CC65_ERROR,
5624                     "Cannot open input file \"%s\": %s",
5625                      FileName, strerror (errno));
5626         return 0;
5627     }
5628
5629     /* Create a new debug info struct */
5630     D.Info = NewDbgInfo (FileName);
5631
5632     /* Prime the pump */
5633     NextToken (&D);
5634
5635     /* The first line in the file must specify version information */
5636     if (D.Tok != TOK_VERSION) {
5637         ParseError (&D, CC65_ERROR,
5638                     "\"version\" keyword missing in first line - this is not "
5639                     "a valid debug info file");
5640         goto CloseAndExit;
5641     }
5642
5643     /* Parse the version directive */
5644     ParseVersion (&D);
5645
5646     /* Do several checks on the version number */
5647     if (D.Info->MajorVersion < VER_MAJOR) {
5648         ParseError (
5649             &D, CC65_ERROR,
5650             "This is an old version of the debug info format that is no "
5651             "longer supported. Version found = %u.%u, version supported "
5652             "= %u.%u",
5653             D.Info->MajorVersion, D.Info->MinorVersion,
5654             VER_MAJOR, VER_MINOR
5655         );
5656         goto CloseAndExit;
5657     } else if (D.Info->MajorVersion == VER_MAJOR &&
5658                D.Info->MinorVersion > VER_MINOR) {
5659         ParseError (
5660             &D, CC65_ERROR,
5661             "This is a slightly newer version of the debug info format. "
5662             "It might work, but you may get errors about unknown keywords "
5663             "and similar. Version found = %u.%u, version supported = %u.%u",
5664             D.Info->MajorVersion, D.Info->MinorVersion,
5665             VER_MAJOR, VER_MINOR
5666         );
5667     } else if (D.Info->MajorVersion > VER_MAJOR) {
5668         ParseError (
5669             &D, CC65_WARNING,
5670             "The format of this debug info file is newer than what we "
5671             "know. Will proceed but probably fail. Version found = %u.%u, "
5672             "version supported = %u.%u",
5673             D.Info->MajorVersion, D.Info->MinorVersion,
5674             VER_MAJOR, VER_MINOR
5675         );
5676     }
5677     ConsumeEOL (&D);
5678
5679     /* Parse lines */
5680     while (D.Tok != TOK_EOF) {
5681
5682         switch (D.Tok) {
5683
5684             case TOK_CSYM:
5685                 ParseCSym (&D);
5686                 break;
5687
5688             case TOK_FILE:
5689                 ParseFile (&D);
5690                 break;
5691
5692             case TOK_INFO:
5693                 ParseInfo (&D);
5694                 break;
5695
5696             case TOK_LIBRARY:
5697                 ParseLibrary (&D);
5698                 break;
5699
5700             case TOK_LINE:
5701                 ParseLine (&D);
5702                 break;
5703
5704             case TOK_MODULE:
5705                 ParseModule (&D);
5706                 break;
5707
5708             case TOK_SCOPE:
5709                 ParseScope (&D);
5710                 break;
5711
5712             case TOK_SEGMENT:
5713                 ParseSegment (&D);
5714                 break;
5715
5716             case TOK_SPAN:
5717                 ParseSpan (&D);
5718                 break;
5719
5720             case TOK_SYM:
5721                 ParseSym (&D);
5722                 break;
5723
5724             case TOK_TYPE:
5725                 ParseType (&D);
5726                 break;
5727
5728             case TOK_IDENT:
5729                 /* Output a warning, then skip the line with the unknown
5730                 ** keyword that may have been added by a later version.
5731                 */
5732                 ParseError (&D, CC65_WARNING,
5733                             "Unknown keyword \"%s\" - skipping",
5734                             SB_GetConstBuf (&D.SVal));
5735
5736                 SkipLine (&D);
5737                 break;
5738
5739             default:
5740                 UnexpectedToken (&D);
5741
5742         }
5743
5744         /* EOL or EOF must follow */
5745         ConsumeEOL (&D);
5746     }
5747
5748 CloseAndExit:
5749     /* Close the file */
5750     fclose (D.F);
5751
5752     /* Free memory allocated for SVal */
5753     SB_Done (&D.SVal);
5754
5755     /* In case of errors, delete the debug info already allocated and
5756     ** return NULL
5757     */
5758     if (D.Errors > 0) {
5759         /* Free allocated stuff */
5760         FreeDbgInfo (D.Info);
5761         return 0;
5762     }
5763
5764     /* We do now have all the information from the input file. Do
5765     ** postprocessing. Beware: Some of the following postprocessing
5766     ** depends on the order of the calls.
5767     */
5768     ProcessCSymInfo (&D);
5769     ProcessFileInfo (&D);
5770     ProcessLineInfo (&D);
5771     ProcessModInfo (&D);
5772     ProcessScopeInfo (&D);
5773     ProcessSegInfo (&D);
5774     ProcessSpanInfo (&D);
5775     ProcessSymInfo (&D);
5776
5777 #if DEBUG
5778     /* Debug output */
5779     DumpData (&D);
5780 #endif
5781
5782     /* Return the debug info struct that was created */
5783     return D.Info;
5784 }
5785
5786
5787
5788 void cc65_free_dbginfo (cc65_dbginfo Handle)
5789 /* Free debug information read from a file */
5790 {
5791     if (Handle) {
5792         FreeDbgInfo ((DbgInfo*) Handle);
5793     }
5794 }
5795
5796
5797
5798 /*****************************************************************************/
5799 /*                                 C symbols                                 */
5800 /*****************************************************************************/
5801
5802
5803
5804 const cc65_csyminfo* cc65_get_csymlist (cc65_dbginfo Handle)
5805 /* Return a list of all c symbols */
5806 {
5807     const DbgInfo*      Info;
5808     cc65_csyminfo*      S;
5809     unsigned            I;
5810
5811     /* Check the parameter */
5812     assert (Handle != 0);
5813
5814     /* The handle is actually a pointer to a debug info struct */
5815     Info = Handle;
5816
5817     /* Allocate memory for the data structure returned to the caller */
5818     S = new_cc65_csyminfo (CollCount (&Info->CSymInfoById));
5819
5820     /* Fill in the data */
5821     for (I = 0; I < CollCount (&Info->CSymInfoById); ++I) {
5822         /* Copy the data */
5823         CopyCSymInfo (S->data + I, CollAt (&Info->CSymInfoById, I));
5824     }
5825
5826     /* Return the result */
5827     return S;
5828 }
5829
5830
5831
5832 const cc65_csyminfo* cc65_csym_byid (cc65_dbginfo Handle, unsigned Id)
5833 /* Return information about a c symbol with a specific id. The function
5834 ** returns NULL if the id is invalid (no such c symbol) and otherwise a
5835 ** cc65_csyminfo structure with one entry that contains the requested
5836 ** symbol information.
5837 */
5838 {
5839     const DbgInfo*      Info;
5840     cc65_csyminfo*      S;
5841
5842     /* Check the parameter */
5843     assert (Handle != 0);
5844
5845     /* The handle is actually a pointer to a debug info struct */
5846     Info = Handle;
5847
5848     /* Check if the id is valid */
5849     if (Id >= CollCount (&Info->CSymInfoById)) {
5850         return 0;
5851     }
5852
5853     /* Allocate memory for the data structure returned to the caller */
5854     S = new_cc65_csyminfo (1);
5855
5856     /* Fill in the data */
5857     CopyCSymInfo (S->data, CollAt (&Info->CSymInfoById, Id));
5858
5859     /* Return the result */
5860     return S;
5861 }
5862
5863
5864
5865 const cc65_csyminfo* cc65_cfunc_bymodule (cc65_dbginfo Handle, unsigned ModId)
5866 /* Return the list of C functions (not symbols!) for a specific module. If
5867 ** the module id is invalid, the function will return NULL, otherwise a
5868 ** (possibly empty) c symbol list.
5869 */
5870 {
5871     const DbgInfo*      Info;
5872     const ModInfo*      M;
5873     cc65_csyminfo*      D;
5874     unsigned            I;
5875
5876
5877     /* Check the parameter */
5878     assert (Handle != 0);
5879
5880     /* The handle is actually a pointer to a debug info struct */
5881     Info = Handle;
5882
5883     /* Check if the module id is valid */
5884     if (ModId >= CollCount (&Info->ModInfoById)) {
5885         return 0;
5886     }
5887
5888     /* Get a pointer to the module info */
5889     M = CollAt (&Info->ModInfoById, ModId);
5890
5891     /* Allocate memory for the data structure returned to the caller */
5892     D = new_cc65_csyminfo (CollCount (&M->CSymFuncByName));
5893
5894     /* Fill in the data */
5895     for (I = 0; I < CollCount (&M->CSymFuncByName); ++I) {
5896         CopyCSymInfo (D->data + I, CollAt (&M->CSymFuncByName, I));
5897     }
5898
5899     /* Return the result */
5900     return D;
5901 }
5902
5903
5904
5905 const cc65_csyminfo* cc65_cfunc_byname (cc65_dbginfo Handle, const char* Name)
5906 /* Return a list of all C functions with the given name that have a
5907 ** definition.
5908 */
5909 {
5910     const DbgInfo*      Info;
5911     unsigned            Index;
5912     unsigned            Count;
5913     const CSymInfo*     S;
5914     cc65_csyminfo*      D;
5915     unsigned            I;
5916
5917
5918     /* Check the parameter */
5919     assert (Handle != 0);
5920
5921     /* The handle is actually a pointer to a debug info struct */
5922     Info = Handle;
5923
5924     /* Search for a function with the given name */
5925     if (!FindCSymInfoByName (&Info->CSymFuncByName, Name, &Index)) {
5926         return 0;
5927     }
5928
5929     /* Count functions with this name */
5930     Count = 1;
5931     I = Index;
5932     while (1) {
5933         if (++I >= CollCount (&Info->CSymFuncByName)) {
5934             break;
5935         }
5936         S = CollAt (&Info->CSymFuncByName, I);
5937         if (strcmp (S->Name, Name) != 0) {
5938             /* Next symbol has another name */
5939             break;
5940         }
5941         ++Count;
5942     }
5943
5944     /* Allocate memory for the data structure returned to the caller */
5945     D = new_cc65_csyminfo (Count);
5946
5947     /* Fill in the data */
5948     for (I = 0; I < Count; ++I, ++Index) {
5949         CopyCSymInfo (D->data + I, CollAt (&Info->CSymFuncByName, Index));
5950     }
5951
5952     /* Return the result */
5953     return D;
5954 }
5955
5956
5957
5958 const cc65_csyminfo* cc65_csym_byscope (cc65_dbginfo Handle, unsigned ScopeId)
5959 /* Return all C symbols for a scope. The function will return NULL if the
5960 ** given id is invalid.
5961 */
5962 {
5963     const DbgInfo*      Info;
5964     const ScopeInfo*    S;
5965     cc65_csyminfo*      D;
5966     unsigned            I;
5967
5968
5969     /* Check the parameter */
5970     assert (Handle != 0);
5971
5972     /* The handle is actually a pointer to a debug info struct */
5973     Info = Handle;
5974
5975     /* Check if the scope id is valid */
5976     if (ScopeId >= CollCount (&Info->ScopeInfoById)) {
5977         return 0;
5978     }
5979
5980     /* Get a pointer to the scope */
5981     S = CollAt (&Info->ScopeInfoById, ScopeId);
5982
5983     /* Allocate memory for the data structure returned to the caller */
5984     D = new_cc65_csyminfo (CollCount (S->CSymInfoByName));
5985
5986     /* Fill in the data */
5987     for (I = 0; I < CollCount (S->CSymInfoByName); ++I) {
5988         CopyCSymInfo (D->data + I, CollAt (S->CSymInfoByName, I));
5989     }
5990
5991     /* Return the result */
5992     return D;
5993 }
5994
5995
5996
5997 void cc65_free_csyminfo (cc65_dbginfo Handle, const cc65_csyminfo* Info)
5998 /* Free a c symbol info record */
5999 {
6000     /* Just for completeness, check the handle */
6001     assert (Handle != 0);
6002
6003     /* Just free the memory */
6004     xfree ((cc65_csyminfo*) Info);
6005 }
6006
6007
6008
6009 /*****************************************************************************/
6010 /*                                 Libraries                                 */
6011 /*****************************************************************************/
6012
6013
6014
6015 const cc65_libraryinfo* cc65_get_librarylist (cc65_dbginfo Handle)
6016 /* Return a list of all libraries */
6017 {
6018     const DbgInfo*      Info;
6019     cc65_libraryinfo*   D;
6020     unsigned            I;
6021
6022     /* Check the parameter */
6023     assert (Handle != 0);
6024
6025     /* The handle is actually a pointer to a debug info struct */
6026     Info = Handle;
6027
6028     /* Allocate memory for the data structure returned to the caller */
6029     D = new_cc65_libraryinfo (CollCount (&Info->LibInfoById));
6030
6031     /* Fill in the data */
6032     for (I = 0; I < CollCount (&Info->LibInfoById); ++I) {
6033         /* Copy the data */
6034         CopyLibInfo (D->data + I, CollAt (&Info->LibInfoById, I));
6035     }
6036
6037     /* Return the result */
6038     return D;
6039 }
6040
6041
6042
6043 const cc65_libraryinfo* cc65_library_byid (cc65_dbginfo Handle, unsigned Id)
6044 /* Return information about a library with a specific id. The function
6045 ** returns NULL if the id is invalid (no such library) and otherwise a
6046 ** cc65_libraryinfo structure with one entry that contains the requested
6047 ** library information.
6048 */
6049 {
6050     const DbgInfo*      Info;
6051     cc65_libraryinfo*   D;
6052
6053     /* Check the parameter */
6054     assert (Handle != 0);
6055
6056     /* The handle is actually a pointer to a debug info struct */
6057     Info = Handle;
6058
6059     /* Check if the id is valid */
6060     if (Id >= CollCount (&Info->LibInfoById)) {
6061         return 0;
6062     }
6063
6064     /* Allocate memory for the data structure returned to the caller */
6065     D = new_cc65_libraryinfo (1);
6066
6067     /* Fill in the data */
6068     CopyLibInfo (D->data, CollAt (&Info->LibInfoById, Id));
6069
6070     /* Return the result */
6071     return D;
6072 }
6073
6074
6075
6076 void cc65_free_libraryinfo (cc65_dbginfo Handle, const cc65_libraryinfo* Info)
6077 /* Free a library info record */
6078 {
6079     /* Just for completeness, check the handle */
6080     assert (Handle != 0);
6081
6082     /* Just free the memory */
6083     xfree ((cc65_libraryinfo*) Info);
6084 }
6085
6086
6087
6088 /*****************************************************************************/
6089 /*                                 Line info                                 */
6090 /*****************************************************************************/
6091
6092
6093
6094 const cc65_lineinfo* cc65_line_byid (cc65_dbginfo Handle, unsigned Id)
6095 /* Return information about a line with a specific id. The function
6096 ** returns NULL if the id is invalid (no such line) and otherwise a
6097 ** cc65_lineinfo structure with one entry that contains the requested
6098 ** module information.
6099 */
6100 {
6101     const DbgInfo*      Info;
6102     cc65_lineinfo*      D;
6103
6104     /* Check the parameter */
6105     assert (Handle != 0);
6106
6107     /* The handle is actually a pointer to a debug info struct */
6108     Info = Handle;
6109
6110     /* Check if the id is valid */
6111     if (Id >= CollCount (&Info->LineInfoById)) {
6112         return 0;
6113     }
6114
6115     /* Allocate memory for the data structure returned to the caller */
6116     D = new_cc65_lineinfo (1);
6117
6118     /* Fill in the data */
6119     CopyLineInfo (D->data, CollAt (&Info->LineInfoById, Id));
6120
6121     /* Return the result */
6122     return D;
6123 }
6124
6125
6126
6127 const cc65_lineinfo* cc65_line_bynumber (cc65_dbginfo Handle, unsigned FileId,
6128                                          cc65_line Line)
6129 /* Return line information for a source file/line number combination. The
6130 ** function returns NULL if no line information was found.
6131 */
6132 {
6133     const DbgInfo*  Info;
6134     const FileInfo* F;
6135     cc65_lineinfo*  D;
6136     LineInfo*       L = 0;
6137
6138     /* Check the parameter */
6139     assert (Handle != 0);
6140
6141     /* The handle is actually a pointer to a debug info struct */
6142     Info = Handle;
6143
6144     /* Check if the source file id is valid */
6145     if (FileId >= CollCount (&Info->FileInfoById)) {
6146         return 0;
6147     }
6148
6149     /* Get the file */
6150     F = CollAt (&Info->FileInfoById, FileId);
6151
6152     /* Search in the file for the given line */
6153     L = FindLineInfoByLine (&F->LineInfoByLine, Line);
6154
6155     /* Bail out if we didn't find the line */
6156     if (L == 0) {
6157         return 0;
6158     }
6159
6160     /* Prepare the struct we will return to the caller */
6161     D = new_cc65_lineinfo (1);
6162
6163     /* Copy the data */
6164     CopyLineInfo (D->data, L);
6165
6166     /* Return the allocated struct */
6167     return D;
6168 }
6169
6170
6171
6172 const cc65_lineinfo* cc65_line_bysource (cc65_dbginfo Handle, unsigned FileId)
6173 /* Return line information for a source file. The function returns NULL if the
6174 ** file id is invalid.
6175 */
6176 {
6177     const DbgInfo*  Info;
6178     const FileInfo* F;
6179     cc65_lineinfo*  D;
6180     unsigned        I;
6181
6182     /* Check the parameter */
6183     assert (Handle != 0);
6184
6185     /* The handle is actually a pointer to a debug info struct */
6186     Info = Handle;
6187
6188     /* Check if the source file id is valid */
6189     if (FileId >= CollCount (&Info->FileInfoById)) {
6190         return 0;
6191     }
6192
6193     /* Get the file */
6194     F = CollAt (&Info->FileInfoById, FileId);
6195
6196     /* Prepare the struct we will return to the caller */
6197     D = new_cc65_lineinfo (CollCount (&F->LineInfoByLine));
6198
6199     /* Fill in the data */
6200     for (I = 0; I < CollCount (&F->LineInfoByLine); ++I) {
6201         /* Copy the data */
6202         CopyLineInfo (D->data + I, CollAt (&F->LineInfoByLine, I));
6203     }
6204
6205     /* Return the allocated struct */
6206     return D;
6207 }
6208
6209
6210
6211 const cc65_lineinfo* cc65_line_bysymdef (cc65_dbginfo Handle, unsigned SymId)
6212 /* Return line information for the definition of a symbol. The function
6213 ** returns NULL if the symbol id is invalid, otherwise a list of line infos.
6214 */
6215 {
6216     const DbgInfo*  Info;
6217     const SymInfo*  S;
6218     cc65_lineinfo*  D;
6219     unsigned        I;
6220
6221     /* Check the parameter */
6222     assert (Handle != 0);
6223
6224     /* The handle is actually a pointer to a debug info struct */
6225     Info = Handle;
6226
6227     /* Check if the symbol id is valid */
6228     if (SymId >= CollCount (&Info->SymInfoById)) {
6229         return 0;
6230     }
6231
6232     /* Get the symbol */
6233     S = CollAt (&Info->SymInfoById, SymId);
6234
6235     /* Prepare the struct we will return to the caller */
6236     D = new_cc65_lineinfo (CollCount (&S->DefLineInfoList));
6237
6238     /* Fill in the data */
6239     for (I = 0; I < CollCount (&S->DefLineInfoList); ++I) {
6240         /* Copy the data */
6241         CopyLineInfo (D->data + I, CollAt (&S->DefLineInfoList, I));
6242     }
6243
6244     /* Return the allocated struct */
6245     return D;
6246 }
6247
6248
6249
6250 const cc65_lineinfo* cc65_line_bysymref (cc65_dbginfo Handle, unsigned SymId)
6251 /* Return line information for all references of a symbol. The function
6252 ** returns NULL if the symbol id is invalid, otherwise a list of line infos.
6253 */
6254 {
6255     const DbgInfo*  Info;
6256     const SymInfo*  S;
6257     cc65_lineinfo*  D;
6258     unsigned        I;
6259
6260     /* Check the parameter */
6261     assert (Handle != 0);
6262
6263     /* The handle is actually a pointer to a debug info struct */
6264     Info = Handle;
6265
6266     /* Check if the symbol id is valid */
6267     if (SymId >= CollCount (&Info->SymInfoById)) {
6268         return 0;
6269     }
6270
6271     /* Get the symbol */
6272     S = CollAt (&Info->SymInfoById, SymId);
6273
6274     /* Prepare the struct we will return to the caller */
6275     D = new_cc65_lineinfo (CollCount (&S->RefLineInfoList));
6276
6277     /* Fill in the data */
6278     for (I = 0; I < CollCount (&S->RefLineInfoList); ++I) {
6279         /* Copy the data */
6280         CopyLineInfo (D->data + I, CollAt (&S->RefLineInfoList, I));
6281     }
6282
6283     /* Return the allocated struct */
6284     return D;
6285 }
6286
6287
6288
6289 const cc65_lineinfo* cc65_line_byspan (cc65_dbginfo Handle, unsigned SpanId)
6290 /* Return line information for a a span. The function returns NULL if the
6291 ** span id is invalid, otherwise a list of line infos.
6292 */
6293 {
6294     const DbgInfo*  Info;
6295     const SpanInfo* S;
6296     cc65_lineinfo*  D;
6297     unsigned        I;
6298
6299     /* Check the parameter */
6300     assert (Handle != 0);
6301
6302     /* The handle is actually a pointer to a debug info struct */
6303     Info = Handle;
6304
6305     /* Check if the span id is valid */
6306     if (SpanId >= CollCount (&Info->SpanInfoById)) {
6307         return 0;
6308     }
6309
6310     /* Get the span */
6311     S = CollAt (&Info->SpanInfoById, SpanId);
6312
6313     /* Prepare the struct we will return to the caller */
6314     D = new_cc65_lineinfo (CollCount (S->LineInfoList));
6315
6316     /* Fill in the data. Since S->LineInfoList may be NULL, we will use the
6317     ** count field of the returned data struct instead.
6318     */
6319     for (I = 0; I < D->count; ++I) {
6320         /* Copy the data */
6321         CopyLineInfo (D->data + I, CollAt (S->LineInfoList, I));
6322     }
6323
6324     /* Return the allocated struct */
6325     return D;
6326 }
6327
6328
6329
6330 void cc65_free_lineinfo (cc65_dbginfo Handle, const cc65_lineinfo* Info)
6331 /* Free line info returned by one of the other functions */
6332 {
6333     /* Just for completeness, check the handle */
6334     assert (Handle != 0);
6335
6336     /* Just free the memory */
6337     xfree ((cc65_lineinfo*) Info);
6338 }
6339
6340
6341
6342 /*****************************************************************************/
6343 /*                                  Modules                                  */
6344 /*****************************************************************************/
6345
6346
6347
6348 const cc65_moduleinfo* cc65_get_modulelist (cc65_dbginfo Handle)
6349 /* Return a list of all modules */
6350 {
6351     const DbgInfo*      Info;
6352     cc65_moduleinfo*    D;
6353     unsigned            I;
6354
6355     /* Check the parameter */
6356     assert (Handle != 0);
6357
6358     /* The handle is actually a pointer to a debug info struct */
6359     Info = Handle;
6360
6361     /* Allocate memory for the data structure returned to the caller */
6362     D = new_cc65_moduleinfo (CollCount (&Info->ModInfoById));
6363
6364     /* Fill in the data */
6365     for (I = 0; I < CollCount (&Info->ModInfoById); ++I) {
6366         /* Copy the data */
6367         CopyModInfo (D->data + I, CollAt (&Info->ModInfoById, I));
6368     }
6369
6370     /* Return the result */
6371     return D;
6372 }
6373
6374
6375
6376 const cc65_moduleinfo* cc65_module_byid (cc65_dbginfo Handle, unsigned Id)
6377 /* Return information about a module with a specific id. The function
6378 ** returns NULL if the id is invalid (no such module) and otherwise a
6379 ** cc65_moduleinfo structure with one entry that contains the requested
6380 ** module information.
6381 */
6382 {
6383     const DbgInfo*      Info;
6384     cc65_moduleinfo*    D;
6385
6386     /* Check the parameter */
6387     assert (Handle != 0);
6388
6389     /* The handle is actually a pointer to a debug info struct */
6390     Info = Handle;
6391
6392     /* Check if the id is valid */
6393     if (Id >= CollCount (&Info->ModInfoById)) {
6394         return 0;
6395     }
6396
6397     /* Allocate memory for the data structure returned to the caller */
6398     D = new_cc65_moduleinfo (1);
6399
6400     /* Fill in the data */
6401     CopyModInfo (D->data, CollAt (&Info->ModInfoById, Id));
6402
6403     /* Return the result */
6404     return D;
6405 }
6406
6407
6408
6409 void cc65_free_moduleinfo (cc65_dbginfo Handle, const cc65_moduleinfo* Info)
6410 /* Free a module info record */
6411 {
6412     /* Just for completeness, check the handle */
6413     assert (Handle != 0);
6414
6415     /* Just free the memory */
6416     xfree ((cc65_moduleinfo*) Info);
6417 }
6418
6419
6420
6421 /*****************************************************************************/
6422 /*                                   Spans                                   */
6423 /*****************************************************************************/
6424
6425
6426
6427 const cc65_spaninfo* cc65_get_spanlist (cc65_dbginfo Handle)
6428 /* Return a list of all spans */
6429 {
6430     const DbgInfo*      Info;
6431     cc65_spaninfo*      D;
6432     unsigned            I;
6433
6434     /* Check the parameter */
6435     assert (Handle != 0);
6436
6437     /* The handle is actually a pointer to a debug info struct */
6438     Info = Handle;
6439
6440     /* Allocate memory for the data structure returned to the caller */
6441     D = new_cc65_spaninfo (CollCount (&Info->SpanInfoById));
6442
6443     /* Fill in the data */
6444     for (I = 0; I < CollCount (&Info->SpanInfoById); ++I) {
6445         /* Copy the data */
6446         CopySpanInfo (D->data + I, CollAt (&Info->SpanInfoById, I));
6447     }
6448
6449     /* Return the result */
6450     return D;
6451 }
6452
6453
6454
6455 const cc65_spaninfo* cc65_span_byid (cc65_dbginfo Handle, unsigned Id)
6456 /* Return information about a span with a specific id. The function
6457 ** returns NULL if the id is invalid (no such span) and otherwise a
6458 ** cc65_spaninfo structure with one entry that contains the requested
6459 ** span information.
6460 */
6461 {
6462     const DbgInfo*      Info;
6463     cc65_spaninfo*      D;
6464
6465     /* Check the parameter */
6466     assert (Handle != 0);
6467
6468     /* The handle is actually a pointer to a debug info struct */
6469     Info = Handle;
6470
6471     /* Check if the id is valid */
6472     if (Id >= CollCount (&Info->SpanInfoById)) {
6473         return 0;
6474     }
6475
6476     /* Allocate memory for the data structure returned to the caller */
6477     D = new_cc65_spaninfo (1);
6478
6479     /* Fill in the data */
6480     CopySpanInfo (D->data, CollAt (&Info->SpanInfoById, Id));
6481
6482     /* Return the result */
6483     return D;
6484 }
6485
6486
6487
6488 const cc65_spaninfo* cc65_span_byaddr (cc65_dbginfo Handle, unsigned long Addr)
6489 /* Return span information for the given address. The function returns NULL
6490 ** if no spans were found for this address.
6491 */
6492 {
6493     const DbgInfo*      Info;
6494     SpanInfoListEntry* E;
6495     cc65_spaninfo*  D = 0;
6496
6497     /* Check the parameter */
6498     assert (Handle != 0);
6499
6500     /* The handle is actually a pointer to a debug info struct */
6501     Info = Handle;
6502
6503     /* Search for spans that cover this address */
6504     E = FindSpanInfoByAddr (&Info->SpanInfoByAddr, Addr);
6505
6506     /* Do we have spans? */
6507     if (E != 0) {
6508
6509         unsigned I;
6510
6511         /* Prepare the struct we will return to the caller */
6512         D = new_cc65_spaninfo (E->Count);
6513         if (E->Count == 1) {
6514             CopySpanInfo (D->data, E->Data);
6515         } else {
6516             for (I = 0; I < D->count; ++I) {
6517                 /* Copy data */
6518                 CopySpanInfo (D->data + I, ((SpanInfo**) E->Data)[I]);
6519             }
6520         }
6521     }
6522
6523     /* Return the struct we've created */
6524     return D;
6525 }
6526
6527
6528
6529 const cc65_spaninfo* cc65_span_byline (cc65_dbginfo Handle, unsigned LineId)
6530 /* Return span information for the given source line. The function returns NULL
6531 ** if the line id is invalid, otherwise the spans for this line (possibly zero).
6532 */
6533 {
6534     const DbgInfo*      Info;
6535     const LineInfo*     L;
6536     cc65_spaninfo*      D;
6537     unsigned            I;
6538
6539     /* Check the parameter */
6540     assert (Handle != 0);
6541
6542     /* The handle is actually a pointer to a debug info struct */
6543     Info = Handle;
6544
6545     /* Check if the line id is valid */
6546     if (LineId >= CollCount (&Info->LineInfoById)) {
6547         return 0;
6548     }
6549
6550     /* Get the line with this id */
6551     L = CollAt (&Info->LineInfoById, LineId);
6552
6553     /* Allocate memory for the data structure returned to the caller */
6554     D = new_cc65_spaninfo (CollCount (&L->SpanInfoList));
6555
6556     /* Fill in the data */
6557     for (I = 0; I < CollCount (&L->SpanInfoList); ++I) {
6558         /* Copy the data */
6559         CopySpanInfo (D->data + I, CollAt (&L->SpanInfoList, I));
6560     }
6561
6562     /* Return the result */
6563     return D;
6564 }
6565
6566
6567
6568 const cc65_spaninfo* cc65_span_byscope (cc65_dbginfo Handle, unsigned ScopeId)
6569 /* Return span information for the given scope. The function returns NULL if
6570 ** the scope id is invalid, otherwise the spans for this scope (possibly zero).
6571 */
6572 {
6573     const DbgInfo*      Info;
6574     const ScopeInfo*    S;
6575     cc65_spaninfo*      D;
6576     unsigned            I;
6577
6578     /* Check the parameter */
6579     assert (Handle != 0);
6580
6581     /* The handle is actually a pointer to a debug info struct */
6582     Info = Handle;
6583
6584     /* Check if the scope id is valid */
6585     if (ScopeId >= CollCount (&Info->ScopeInfoById)) {
6586         return 0;
6587     }
6588
6589     /* Get the scope with this id */
6590     S = CollAt (&Info->ScopeInfoById, ScopeId);
6591
6592     /* Allocate memory for the data structure returned to the caller */
6593     D = new_cc65_spaninfo (CollCount (&S->SpanInfoList));
6594
6595     /* Fill in the data */
6596     for (I = 0; I < CollCount (&S->SpanInfoList); ++I) {
6597         /* Copy the data */
6598         CopySpanInfo (D->data + I, CollAt (&S->SpanInfoList, I));
6599     }
6600
6601     /* Return the result */
6602     return D;
6603 }
6604
6605
6606
6607 void cc65_free_spaninfo (cc65_dbginfo Handle, const cc65_spaninfo* Info)
6608 /* Free a span info record */
6609 {
6610     /* Just for completeness, check the handle */
6611     assert (Handle != 0);
6612
6613     /* Just free the memory */
6614     xfree ((cc65_spaninfo*) Info);
6615 }
6616
6617
6618
6619 /*****************************************************************************/
6620 /*                               Source files                                */
6621 /*****************************************************************************/
6622
6623
6624
6625 const cc65_sourceinfo* cc65_get_sourcelist (cc65_dbginfo Handle)
6626 /* Return a list of all source files */
6627 {
6628     const DbgInfo*      Info;
6629     cc65_sourceinfo*    D;
6630     unsigned            I;
6631
6632     /* Check the parameter */
6633     assert (Handle != 0);
6634
6635     /* The handle is actually a pointer to a debug info struct */
6636     Info = Handle;
6637
6638     /* Allocate memory for the data structure returned to the caller. */
6639     D = new_cc65_sourceinfo (CollCount (&Info->FileInfoById));
6640
6641     /* Fill in the data */
6642     for (I = 0; I < CollCount (&Info->FileInfoById); ++I) {
6643         /* Copy the data */
6644         CopyFileInfo (D->data + I, CollAt (&Info->FileInfoById, I));
6645     }
6646
6647     /* Return the result */
6648     return D;
6649 }
6650
6651
6652
6653 const cc65_sourceinfo* cc65_source_byid (cc65_dbginfo Handle, unsigned Id)
6654 /* Return information about a source file with a specific id. The function
6655 ** returns NULL if the id is invalid (no such source file) and otherwise a
6656 ** cc65_sourceinfo structure with one entry that contains the requested
6657 ** source file information.
6658 */
6659 {
6660     const DbgInfo*      Info;
6661     cc65_sourceinfo*    D;
6662
6663     /* Check the parameter */
6664     assert (Handle != 0);
6665
6666     /* The handle is actually a pointer to a debug info struct */
6667     Info = Handle;
6668
6669     /* Check if the id is valid */
6670     if (Id >= CollCount (&Info->FileInfoById)) {
6671         return 0;
6672     }
6673
6674     /* Allocate memory for the data structure returned to the caller */
6675     D = new_cc65_sourceinfo (1);
6676
6677     /* Fill in the data */
6678     CopyFileInfo (D->data, CollAt (&Info->FileInfoById, Id));
6679
6680     /* Return the result */
6681     return D;
6682 }
6683
6684
6685
6686
6687 const cc65_sourceinfo* cc65_source_bymodule (cc65_dbginfo Handle, unsigned Id)
6688 /* Return information about the source files used to build a module. The
6689 ** function returns NULL if the module id is invalid (no such module) and
6690 ** otherwise a cc65_sourceinfo structure with one entry per source file.
6691 */
6692 {
6693     const DbgInfo*      Info;
6694     const ModInfo*      M;
6695     cc65_sourceinfo*    D;
6696     unsigned            I;
6697
6698     /* Check the parameter */
6699     assert (Handle != 0);
6700
6701     /* The handle is actually a pointer to a debug info struct */
6702     Info = Handle;
6703
6704     /* Check if the module id is valid */
6705     if (Id >= CollCount (&Info->ModInfoById)) {
6706         return 0;
6707     }
6708
6709     /* Get a pointer to the module info */
6710     M = CollAt (&Info->ModInfoById, Id);
6711
6712     /* Allocate memory for the data structure returned to the caller */
6713     D = new_cc65_sourceinfo (CollCount (&M->FileInfoByName));
6714
6715     /* Fill in the data */
6716     for (I = 0; I < CollCount (&M->FileInfoByName); ++I) {
6717         CopyFileInfo (D->data + I, CollAt (&M->FileInfoByName, I));
6718     }
6719
6720     /* Return the result */
6721     return D;
6722 }
6723
6724
6725
6726 void cc65_free_sourceinfo (cc65_dbginfo Handle, const cc65_sourceinfo* Info)
6727 /* Free a source info record */
6728 {
6729     /* Just for completeness, check the handle */
6730     assert (Handle != 0);
6731
6732     /* Free the memory */
6733     xfree ((cc65_sourceinfo*) Info);
6734 }
6735
6736
6737
6738 /*****************************************************************************/
6739 /*                                  Scopes                                   */
6740 /*****************************************************************************/
6741
6742
6743
6744 const cc65_scopeinfo* cc65_get_scopelist (cc65_dbginfo Handle)
6745 /* Return a list of all scopes in the debug information */
6746 {
6747     const DbgInfo*      Info;
6748     cc65_scopeinfo*     D;
6749     unsigned            I;
6750
6751     /* Check the parameter */
6752     assert (Handle != 0);
6753
6754     /* The handle is actually a pointer to a debug info struct */
6755     Info = Handle;
6756
6757     /* Allocate memory for the data structure returned to the caller */
6758     D = new_cc65_scopeinfo (CollCount (&Info->ScopeInfoById));
6759
6760     /* Fill in the data */
6761     for (I = 0; I < CollCount (&Info->ScopeInfoById); ++I) {
6762         /* Copy the data */
6763         CopyScopeInfo (D->data + I, CollAt (&Info->ScopeInfoById, I));
6764     }
6765
6766     /* Return the result */
6767     return D;
6768 }
6769
6770
6771
6772 const cc65_scopeinfo* cc65_scope_byid (cc65_dbginfo Handle, unsigned Id)
6773 /* Return the scope with a given id. The function returns NULL if no scope
6774 ** with this id was found.
6775 */
6776 {
6777     const DbgInfo*      Info;
6778     cc65_scopeinfo*     D;
6779
6780     /* Check the parameter */
6781     assert (Handle != 0);
6782
6783     /* The handle is actually a pointer to a debug info struct */
6784     Info = Handle;
6785
6786     /* Check if the id is valid */
6787     if (Id >= CollCount (&Info->ScopeInfoById)) {
6788         return 0;
6789     }
6790
6791     /* Allocate memory for the data structure returned to the caller */
6792     D = new_cc65_scopeinfo (1);
6793
6794     /* Fill in the data */
6795     CopyScopeInfo (D->data, CollAt (&Info->ScopeInfoById, Id));
6796
6797     /* Return the result */
6798     return D;
6799 }
6800
6801
6802
6803 const cc65_scopeinfo* cc65_scope_bymodule (cc65_dbginfo Handle, unsigned ModId)
6804 /* Return the list of scopes for one module. The function returns NULL if no
6805 ** scope with the given id was found.
6806 */
6807 {
6808     const DbgInfo*      Info;
6809     const ModInfo*      M;
6810     cc65_scopeinfo*     D;
6811     unsigned            I;
6812
6813     /* Check the parameter */
6814     assert (Handle != 0);
6815
6816     /* The handle is actually a pointer to a debug info struct */
6817     Info = Handle;
6818
6819     /* Check if the module id is valid */
6820     if (ModId >= CollCount (&Info->ModInfoById)) {
6821         return 0;
6822     }
6823
6824     /* Get a pointer to the module info */
6825     M = CollAt (&Info->ModInfoById, ModId);
6826
6827     /* Allocate memory for the data structure returned to the caller */
6828     D = new_cc65_scopeinfo (CollCount (&M->ScopeInfoByName));
6829
6830     /* Fill in the data */
6831     for (I = 0; I < CollCount (&M->ScopeInfoByName); ++I) {
6832         CopyScopeInfo (D->data + I, CollAt (&M->ScopeInfoByName, I));
6833     }
6834
6835     /* Return the result */
6836     return D;
6837 }
6838
6839
6840
6841 const cc65_scopeinfo* cc65_scope_byname (cc65_dbginfo Handle, const char* Name)
6842 /* Return the list of scopes with a given name. Returns NULL if no scope with
6843 ** the given name was found, otherwise a non empty scope list.
6844 */
6845 {
6846     const DbgInfo*      Info;
6847     unsigned            Index;
6848     const ScopeInfo*    S;
6849     cc65_scopeinfo*     D;
6850     unsigned            Count;
6851     unsigned            I;
6852
6853
6854     /* Check the parameter */
6855     assert (Handle != 0);
6856
6857     /* The handle is actually a pointer to a debug info struct */
6858     Info = Handle;
6859
6860     /* Search for the first item with the given name */
6861     if (!FindScopeInfoByName (&Info->ScopeInfoByName, Name, &Index)) {
6862         /* Not found */
6863         return 0;
6864     }
6865
6866     /* Count scopes with this name */
6867     Count = 1;
6868     I = Index;
6869     while (1) {
6870         if (++I >= CollCount (&Info->ScopeInfoByName)) {
6871             break;
6872         }
6873         S = CollAt (&Info->ScopeInfoByName, I);
6874         if (strcmp (S->Name, Name) != 0) {
6875             /* Next symbol has another name */
6876             break;
6877         }
6878         ++Count;
6879     }
6880
6881     /* Allocate memory for the data structure returned to the caller */
6882     D = new_cc65_scopeinfo (Count);
6883
6884     /* Fill in the data */
6885     for (I = 0; I < Count; ++I, ++Index) {
6886         CopyScopeInfo (D->data + I, CollAt (&Info->ScopeInfoByName, Index));
6887     }
6888
6889     /* Return the result */
6890     return D;
6891 }
6892
6893
6894
6895 const cc65_scopeinfo* cc65_scope_byspan (cc65_dbginfo Handle, unsigned SpanId)
6896 /* Return scope information for a a span. The function returns NULL if the
6897 ** span id is invalid, otherwise a list of line scopes.
6898 */
6899 {
6900     const DbgInfo*      Info;
6901     const SpanInfo*     S;
6902     cc65_scopeinfo*     D;
6903     unsigned            I;
6904
6905     /* Check the parameter */
6906     assert (Handle != 0);
6907
6908     /* The handle is actually a pointer to a debug info struct */
6909     Info = Handle;
6910
6911     /* Check if the span id is valid */
6912     if (SpanId >= CollCount (&Info->SpanInfoById)) {
6913         return 0;
6914     }
6915
6916     /* Get the span */
6917     S = CollAt (&Info->SpanInfoById, SpanId);
6918
6919     /* Prepare the struct we will return to the caller */
6920     D = new_cc65_scopeinfo (CollCount (S->ScopeInfoList));
6921
6922     /* Fill in the data. Since D->ScopeInfoList may be NULL, we will use the
6923     ** count field of the returned data struct instead.
6924     */
6925     for (I = 0; I < D->count; ++I) {
6926         /* Copy the data */
6927         CopyScopeInfo (D->data + I, CollAt (S->ScopeInfoList, I));
6928     }
6929
6930     /* Return the allocated struct */
6931     return D;
6932 }
6933
6934
6935
6936 const cc65_scopeinfo* cc65_childscopes_byid (cc65_dbginfo Handle, unsigned Id)
6937 /* Return the direct child scopes of a scope with a given id. The function
6938 ** returns NULL if no scope with this id was found, otherwise a list of the
6939 ** direct childs.
6940 */
6941 {
6942     const DbgInfo*      Info;
6943     cc65_scopeinfo*     D;
6944     const ScopeInfo*    S;
6945     unsigned            I;
6946
6947     /* Check the parameter */
6948     assert (Handle != 0);
6949
6950     /* The handle is actually a pointer to a debug info struct */
6951     Info = Handle;
6952
6953     /* Check if the id is valid */
6954     if (Id >= CollCount (&Info->ScopeInfoById)) {
6955         return 0;
6956     }
6957
6958     /* Get the scope */
6959     S = CollAt (&Info->ScopeInfoById, Id);
6960
6961     /* Allocate memory for the data structure returned to the caller */
6962     D = new_cc65_scopeinfo (CollCount (S->ChildScopeList));
6963
6964     /* Fill in the data */
6965     for (I = 0; I < D->count; ++I) {
6966         CopyScopeInfo (D->data + I, CollAt (S->ChildScopeList, I));
6967     }
6968
6969     /* Return the result */
6970     return D;
6971 }
6972
6973
6974
6975 void cc65_free_scopeinfo (cc65_dbginfo Handle, const cc65_scopeinfo* Info)
6976 /* Free a scope info record */
6977 {
6978     /* Just for completeness, check the handle */
6979     assert (Handle != 0);
6980
6981     /* Free the memory */
6982     xfree ((cc65_scopeinfo*) Info);
6983 }
6984
6985
6986
6987 /*****************************************************************************/
6988 /*                                 Segments                                  */
6989 /*****************************************************************************/
6990
6991
6992
6993 const cc65_segmentinfo* cc65_get_segmentlist (cc65_dbginfo Handle)
6994 /* Return a list of all segments referenced in the debug information */
6995 {
6996     const DbgInfo*      Info;
6997     cc65_segmentinfo*   D;
6998     unsigned            I;
6999
7000     /* Check the parameter */
7001     assert (Handle != 0);
7002
7003     /* The handle is actually a pointer to a debug info struct */
7004     Info = Handle;
7005
7006     /* Allocate memory for the data structure returned to the caller */
7007     D = new_cc65_segmentinfo (CollCount (&Info->SegInfoById));
7008
7009     /* Fill in the data */
7010     for (I = 0; I < CollCount (&Info->SegInfoById); ++I) {
7011         /* Copy the data */
7012         CopySegInfo (D->data + I, CollAt (&Info->SegInfoById, I));
7013     }
7014
7015     /* Return the result */
7016     return D;
7017 }
7018
7019
7020
7021 const cc65_segmentinfo* cc65_segment_byid (cc65_dbginfo Handle, unsigned Id)
7022 /* Return information about a segment with a specific id. The function returns
7023 ** NULL if the id is invalid (no such segment) and otherwise a segmentinfo
7024 ** structure with one entry that contains the requested segment information.
7025 */
7026 {
7027     const DbgInfo*      Info;
7028     cc65_segmentinfo*   D;
7029
7030     /* Check the parameter */
7031     assert (Handle != 0);
7032
7033     /* The handle is actually a pointer to a debug info struct */
7034     Info = Handle;
7035
7036     /* Check if the id is valid */
7037     if (Id >= CollCount (&Info->SegInfoById)) {
7038         return 0;
7039     }
7040
7041     /* Allocate memory for the data structure returned to the caller */
7042     D = new_cc65_segmentinfo (1);
7043
7044     /* Fill in the data */
7045     CopySegInfo (D->data, CollAt (&Info->SegInfoById, Id));
7046
7047     /* Return the result */
7048     return D;
7049 }
7050
7051
7052
7053 const cc65_segmentinfo* cc65_segment_byname (cc65_dbginfo Handle,
7054                                              const char* Name)
7055 /* Return information about a segment with a specific name. The function
7056 ** returns NULL if no segment with this name exists and otherwise a
7057 ** cc65_segmentinfo structure with one entry that contains the requested
7058 ** information.
7059 */
7060 {
7061     const DbgInfo*      Info;
7062     const SegInfo*      S;
7063     cc65_segmentinfo*   D;
7064
7065     /* Check the parameter */
7066     assert (Handle != 0);
7067
7068     /* The handle is actually a pointer to a debug info struct */
7069     Info = Handle;
7070
7071     /* Search for the segment */
7072     S = FindSegInfoByName (&Info->SegInfoByName, Name);
7073     if (S == 0) {
7074         return 0;
7075     }
7076
7077     /* Allocate memory for the data structure returned to the caller */
7078     D = new_cc65_segmentinfo (1);
7079
7080     /* Fill in the data */
7081     CopySegInfo (D->data, S);
7082
7083     /* Return the result */
7084     return D;
7085 }
7086
7087
7088
7089 void cc65_free_segmentinfo (cc65_dbginfo Handle, const cc65_segmentinfo* Info)
7090 /* Free a segment info record */
7091 {
7092     /* Just for completeness, check the handle */
7093     assert (Handle != 0);
7094
7095     /* Free the memory */
7096     xfree ((cc65_segmentinfo*) Info);
7097 }
7098
7099
7100
7101 /*****************************************************************************/
7102 /*                                  Symbols                                  */
7103 /*****************************************************************************/
7104
7105
7106
7107 const cc65_symbolinfo* cc65_symbol_byid (cc65_dbginfo Handle, unsigned Id)
7108 /* Return the symbol with a given id. The function returns NULL if no symbol
7109 ** with this id was found.
7110 */
7111 {
7112     const DbgInfo*      Info;
7113     cc65_symbolinfo*    D;
7114
7115     /* Check the parameter */
7116     assert (Handle != 0);
7117
7118     /* The handle is actually a pointer to a debug info struct */
7119     Info = Handle;
7120
7121     /* Check if the id is valid */
7122     if (Id >= CollCount (&Info->SymInfoById)) {
7123         return 0;
7124     }
7125
7126     /* Allocate memory for the data structure returned to the caller */
7127     D = new_cc65_symbolinfo (1);
7128
7129     /* Fill in the data */
7130     CopySymInfo (D->data, CollAt (&Info->SymInfoById, Id));
7131
7132     /* Return the result */
7133     return D;
7134 }
7135
7136
7137
7138 const cc65_symbolinfo* cc65_symbol_byname (cc65_dbginfo Handle, const char* Name)
7139 /* Return a list of symbols with a given name. The function returns NULL if
7140 ** no symbol with this name was found.
7141 */
7142 {
7143     const DbgInfo*      Info;
7144     cc65_symbolinfo*    D;
7145     unsigned            I;
7146     unsigned            Index;
7147     unsigned            Count;
7148
7149     /* Check the parameter */
7150     assert (Handle != 0);
7151
7152     /* The handle is actually a pointer to a debug info struct */
7153     Info = Handle;
7154
7155     /* Search for the symbol */
7156     if (!FindSymInfoByName (&Info->SymInfoByName, Name, &Index)) {
7157         /* Not found */
7158         return 0;
7159     }
7160
7161     /* Index contains the position. Count how many symbols with this name
7162     ** we have. Skip the first one, since we have at least one.
7163     */
7164     Count = 1;
7165     while ((unsigned) Index + Count < CollCount (&Info->SymInfoByName)) {
7166         const SymInfo* S = CollAt (&Info->SymInfoByName, (unsigned) Index + Count);
7167         if (strcmp (S->Name, Name) != 0) {
7168             break;
7169         }
7170         ++Count;
7171     }
7172
7173     /* Allocate memory for the data structure returned to the caller */
7174     D = new_cc65_symbolinfo (Count);
7175
7176     /* Fill in the data */
7177     for (I = 0; I < Count; ++I) {
7178         /* Copy the data */
7179         CopySymInfo (D->data + I, CollAt (&Info->SymInfoByName, Index++));
7180     }
7181
7182     /* Return the result */
7183     return D;
7184 }
7185
7186
7187
7188 const cc65_symbolinfo* cc65_symbol_byscope (cc65_dbginfo Handle, unsigned ScopeId)
7189 /* Return a list of symbols in the given scope. This includes cheap local
7190 ** symbols, but not symbols in subscopes. The function returns NULL if the
7191 ** scope id is invalid (no such scope) and otherwise a - possibly empty -
7192 ** symbol list.
7193 */
7194 {
7195     const DbgInfo*      Info;
7196     cc65_symbolinfo*    D;
7197     const ScopeInfo*    S;
7198     unsigned            I;
7199
7200
7201     /* Check the parameter */
7202     assert (Handle != 0);
7203
7204     /* The handle is actually a pointer to a debug info struct */
7205     Info = Handle;
7206
7207     /* Check if the id is valid */
7208     if (ScopeId >= CollCount (&Info->ScopeInfoById)) {
7209         return 0;
7210     }
7211
7212     /* Get the scope */
7213     S = CollAt (&Info->ScopeInfoById, ScopeId);
7214
7215     /* Allocate memory for the data structure returned to the caller */
7216     D = new_cc65_symbolinfo (CollCount (&S->SymInfoByName));
7217
7218     /* Fill in the data */
7219     for (I = 0; I < CollCount (&S->SymInfoByName); ++I) {
7220         /* Copy the data */
7221         CopySymInfo (D->data + I, CollAt (&S->SymInfoByName, I));
7222     }
7223
7224     /* Return the result */
7225     return D;
7226 }
7227
7228
7229
7230 const cc65_symbolinfo* cc65_symbol_inrange (cc65_dbginfo Handle, cc65_addr Start,
7231                                             cc65_addr End)
7232 /* Return a list of labels in the given range. End is inclusive. The function
7233 ** return NULL if no symbols within the given range are found. Non label
7234 ** symbols are ignored and not returned.
7235 */
7236 {
7237     const DbgInfo*      Info;
7238     Collection          SymInfoList = COLLECTION_INITIALIZER;
7239     cc65_symbolinfo*    D;
7240     unsigned            I;
7241     unsigned            Index;
7242
7243     /* Check the parameter */
7244     assert (Handle != 0);
7245
7246     /* The handle is actually a pointer to a debug info struct */
7247     Info = Handle;
7248
7249     /* Search for the symbol. Because we're searching for a range, we cannot
7250     ** make use of the function result.
7251     */
7252     FindSymInfoByValue (&Info->SymInfoByVal, Start, &Index);
7253
7254     /* Start from the given index, check all symbols until the end address is
7255     ** reached. Place all symbols into SymInfoList for later.
7256     */
7257     for (I = Index; I < CollCount (&Info->SymInfoByVal); ++I) {
7258
7259         /* Get the item */
7260         SymInfo* Item = CollAt (&Info->SymInfoByVal, I);
7261
7262         /* The collection is sorted by address, so if we get a value larger
7263         ** than the end address, we're done.
7264         */
7265         if (Item->Value > (long) End) {
7266             break;
7267         }
7268
7269         /* Ignore non-labels (this will also ignore imports) */
7270         if (Item->Type != CC65_SYM_LABEL) {
7271             continue;
7272         }
7273
7274         /* Ok, remember this one */
7275         CollAppend (&SymInfoList, Item);
7276     }
7277
7278     /* If we don't have any labels within the range, bail out. No memory has
7279     ** been allocated for SymInfoList.
7280     */
7281     if (CollCount (&SymInfoList) == 0) {
7282         return 0;
7283     }
7284
7285     /* Allocate memory for the data structure returned to the caller */
7286     D = new_cc65_symbolinfo (CollCount (&SymInfoList));
7287
7288     /* Fill in the data */
7289     for (I = 0; I < CollCount (&SymInfoList); ++I) {
7290         /* Copy the data */
7291         CopySymInfo (D->data + I, CollAt (&SymInfoList, I));
7292     }
7293
7294     /* Free the collection */
7295     CollDone (&SymInfoList);
7296
7297     /* Return the result */
7298     return D;
7299 }
7300
7301
7302
7303 void cc65_free_symbolinfo (cc65_dbginfo Handle, const cc65_symbolinfo* Info)
7304 /* Free a symbol info record */
7305 {
7306     /* Just for completeness, check the handle */
7307     assert (Handle != 0);
7308
7309     /* Free the memory */
7310     xfree ((cc65_symbolinfo*) Info);
7311 }
7312
7313
7314
7315 /*****************************************************************************/
7316 /*                                   Types                                   */
7317 /*****************************************************************************/
7318
7319
7320
7321 const cc65_typedata* cc65_type_byid (cc65_dbginfo Handle, unsigned Id)
7322 /* Return the data for the type with the given id. The function returns NULL
7323 ** if no type with this id was found.
7324 */
7325 {
7326     const DbgInfo*        Info;
7327     const TypeInfo*       T;
7328
7329     /* Check the parameter */
7330     assert (Handle != 0);
7331
7332     /* The handle is actually a pointer to a debug info struct */
7333     Info = Handle;
7334
7335     /* Check if the id is valid */
7336     if (Id >= CollCount (&Info->TypeInfoById)) {
7337         return 0;
7338     }
7339
7340     /* Get the type info with the given id */
7341     T = CollAt (&Info->TypeInfoById, Id);
7342
7343     /* We do already have the type data. Return it. */
7344     return T->Data;
7345 }
7346
7347
7348
7349 void cc65_free_typedata (cc65_dbginfo Handle, const cc65_typedata* data)
7350 /* Free a symbol info record */
7351 {
7352     /* Just for completeness, check the handle and the data*/
7353     assert (Handle != 0 && data != 0);
7354
7355     /* Nothing to do */
7356 }
7357
7358
7359