]> git.sur5r.net Git - cc65/commitdiff
Preparations for adding scopes.
authoruz <uz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Sun, 31 Jul 2011 21:32:46 +0000 (21:32 +0000)
committeruz <uz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Sun, 31 Jul 2011 21:32:46 +0000 (21:32 +0000)
git-svn-id: svn://svn.cc65.org/cc65/trunk@5100 b7a2c559-68d2-44c3-8de9-860c34a00d81

src/dbginfo/dbginfo.c
src/dbginfo/dbginfo.h

index 80c6600a99aa0df695cc02520f0a333873a6450a..fc212135b9f085f31760c7d6992595f1ef67b8a3 100644 (file)
@@ -57,7 +57,7 @@
 
 /* Version numbers of the debug format we understand */
 #define VER_MAJOR       1U
-#define VER_MINOR       2U
+#define VER_MINOR       3U
 
 /* Dynamic strings */
 typedef struct StrBuf StrBuf;
@@ -108,8 +108,10 @@ struct DbgInfo {
     Collection          FileInfoById;   /* File infos sorted by id */
     Collection          LineInfos;      /* List of all line infos */
     LineInfoList        LineInfoByAddr; /* Line infos sorted by unique address */
+    Collection          SymInfoById;    /* Symbol infos sorted by id */
     Collection          SymInfoByName;  /* Symbol infos sorted by name */
     Collection          SymInfoByVal;   /* Symbol infos sorted by value */
+    Collection          ScopeInfoById;  /* Scope infos sorted by id */
 };
 
 /* Input tokens */
@@ -143,9 +145,11 @@ typedef enum {
     TOK_NAME,                           /* NAME keyword */
     TOK_OUTPUTNAME,                     /* OUTPUTNAME keyword */
     TOK_OUTPUTOFFS,                     /* OUTPUTOFFS keyword */
+    TOK_PARENT,                         /* PARENT keyword */
     TOK_RANGE,                          /* RANGE keyword */
     TOK_RO,                             /* RO keyword */
     TOK_RW,                             /* RW keyword */
+    TOK_SCOPE,                          /* SCOPE keyword */
     TOK_SEGMENT,                        /* SEGMENT keyword */
     TOK_SIZE,                           /* SIZE keyword */
     TOK_START,                          /* START keyword */
@@ -221,13 +225,30 @@ struct LineInfo {
 /* Internally used symbol info struct */
 typedef struct SymInfo SymInfo;
 struct SymInfo {
+    unsigned            Id;             /* Id of symbol */
     cc65_symbol_type    Type;           /* Type of symbol */
     long                Value;          /* Value of symbol */
     cc65_size           Size;           /* Size of symbol */
     unsigned            Segment;        /* Id of segment if any */
+    unsigned            Scope;          /* Id of symbol scope */
+    unsigned            Parent;         /* Parent symbol if any */
     char                SymName[1];     /* Name of symbol */
 };
 
+/* Internally used scope info struct */
+typedef struct ScopeInfo ScopeInfo;
+struct ScopeInfo {
+    unsigned            Id;             /* Id of scope */
+    cc65_scope_type     Type;           /* Type of scope */
+    cc65_size           Size;           /* Size of scope */
+    unsigned            Flags;          /* Scope flags */
+    union {
+        unsigned        Id;             /* Id of parent scope */
+        ScopeInfo*      Scope;          /* Pointer to parent scope */
+    } Parent;
+    char                ScopeName[1];   /* Name of scope */
+};
+
 
 
 /*****************************************************************************/
@@ -343,6 +364,19 @@ static cc65_symbolinfo* new_cc65_symbolinfo (unsigned Count)
 
 
 
+static cc65_scopeinfo* new_cc65_scopeinfo (unsigned Count)
+/* Allocate and return a cc65_scopeinfo struct that is able to hold Count
+ * entries. Initialize the count field of the returned struct.
+ */
+{
+    cc65_scopeinfo* S = xmalloc (sizeof (*S) - sizeof (S->data[0]) +
+                                 Count * sizeof (S->data[0]));
+    S->count = Count;
+    return S;
+}
+
+
+
 /*****************************************************************************/
 /*                              Dynamic strings                              */
 /*****************************************************************************/
@@ -1039,19 +1073,13 @@ static int CompareFileInfoById (const void* L, const void* R)
 
 
 
-static SymInfo* NewSymInfo (const StrBuf* Name, long Val,
-                            cc65_symbol_type Type, cc65_size Size,
-                            unsigned Segment)
+static SymInfo* NewSymInfo (const StrBuf* Name)
 /* Create a new SymInfo struct, intialize and return it */
 {
     /* Allocate memory */
     SymInfo* S = xmalloc (sizeof (SymInfo) + SB_GetLen (Name));
 
-    /* Initialize it */
-    S->Type    = Type;
-    S->Value   = Val;
-    S->Size    = Size;
-    S->Segment = Segment;
+    /* Initialize the name */
     memcpy (S->SymName, SB_GetConstBuf (Name), SB_GetLen (Name) + 1);
 
     /* Return it */
@@ -1068,6 +1096,21 @@ static void FreeSymInfo (SymInfo* S)
 
 
 
+static int CompareSymInfoById (const void* L, const void* R)
+/* Helper function to sort symbol infos in a collection by id */
+{
+    /* Sort by symbol id. */
+    if (((const SymInfo*) L)->Id > ((const SymInfo*) R)->Id) {
+        return 1;
+    } else if (((const SymInfo*) L)->Id < ((const SymInfo*) R)->Id ) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+
+
 static int CompareSymInfoByName (const void* L, const void* R)
 /* Helper function to sort symbol infos in a collection by name */
 {
@@ -1286,6 +1329,60 @@ static void DoneLineInfoList (LineInfoList* L)
 
 
 
+/*****************************************************************************/
+/*                                Scope info                                 */
+/*****************************************************************************/
+
+
+
+static ScopeInfo* NewScopeInfo (const StrBuf* Name)
+/* Create a new ScopeInfo struct, intialize and return it */
+{
+    /* Allocate memory */
+    ScopeInfo* S = xmalloc (sizeof (ScopeInfo) + SB_GetLen (Name));
+
+    /* Initialize the name */
+    memcpy (S->ScopeName, SB_GetConstBuf (Name), SB_GetLen (Name) + 1);
+
+    /* Return it */
+    return S;
+}
+
+
+
+static void FreeScopeInfo (ScopeInfo* S)
+/* Free a ScopeInfo struct */
+{
+    xfree (S);
+}
+
+
+
+static int CompareScopeInfoById (const void* L, const void* R)
+/* Helper function to sort scope infos in a collection by id */
+{
+    /* Sort by symbol id. */
+    if (((const ScopeInfo*) L)->Id > ((const ScopeInfo*) R)->Id) {
+        return 1;
+    } else if (((const ScopeInfo*) L)->Id < ((const ScopeInfo*) R)->Id ) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+
+
+static int CompareScopeInfoByName (const void* L, const void* R)
+/* Helper function to sort scope infos in a collection by name */
+{
+    /* Sort by symbol name */
+    return strcmp (((const ScopeInfo*) L)->ScopeName,
+                   ((const ScopeInfo*) R)->ScopeName);
+}
+
+
+
 /*****************************************************************************/
 /*                                Debug info                                 */
 /*****************************************************************************/
@@ -1305,8 +1402,10 @@ static DbgInfo* NewDbgInfo (void)
     InitCollection (&Info->FileInfoById);
     InitCollection (&Info->LineInfos);
     InitLineInfoList (&Info->LineInfoByAddr);
+    InitCollection (&Info->SymInfoById);
     InitCollection (&Info->SymInfoByName);
     InitCollection (&Info->SymInfoByVal);
+    InitCollection (&Info->ScopeInfoById);
 
     /* Return it */
     return Info;
@@ -1344,9 +1443,16 @@ static void FreeDbgInfo (DbgInfo* Info)
     for (I = 0; I < CollCount (&Info->SymInfoByName); ++I) {
         FreeSymInfo (CollAt (&Info->SymInfoByName, I));
     }
+    DoneCollection (&Info->SymInfoById);
     DoneCollection (&Info->SymInfoByName);
     DoneCollection (&Info->SymInfoByVal);
 
+    /* Free scope info */
+    for (I = 0; I < CollCount (&Info->ScopeInfoById); ++I) {
+        FreeScopeInfo (CollAt (&Info->ScopeInfoById, I));
+    }
+    DoneCollection (&Info->ScopeInfoById);
+
     /* Free the structure itself */
     xfree (Info);
 }
@@ -1384,7 +1490,7 @@ static void CopyLineInfo (cc65_linedata* D, const LineInfo* L)
 static void CopyFileInfo (cc65_sourcedata* D, const FileInfo* F)
 /* Copy data from a FileInfo struct to a cc65_sourcedata struct */
 {
-    D->id           = F->Id;
+    D->source_id    = F->Id;
     D->source_name  = F->FileName;
     D->source_size  = F->Size;
     D->source_mtime = F->MTime;
@@ -1395,7 +1501,7 @@ static void CopyFileInfo (cc65_sourcedata* D, const FileInfo* F)
 static void CopySegInfo (cc65_segmentdata* D, const SegInfo* S)
 /* Copy data from a SegInfo struct to a cc65_segmentdata struct */
 {
-    D->id            = S->Id;
+    D->segment_id    = S->Id;
     D->segment_name  = S->SegName;
     D->segment_start = S->Start;
     D->segment_size  = S->Size;
@@ -1408,11 +1514,25 @@ static void CopySegInfo (cc65_segmentdata* D, const SegInfo* S)
 static void CopySymInfo (cc65_symboldata* D, const SymInfo* S)
 /* Copy data from a SymInfo struct to a cc65_symboldata struct */
 {
+    D->symbol_id      = S->Id;
     D->symbol_name    = S->SymName;
     D->symbol_type    = S->Type;
     D->symbol_size    = S->Size;
     D->symbol_value   = S->Value;
     D->symbol_segment = S->Segment;
+    D->scope_id       = S->Scope;
+}
+
+
+
+static void CopyScopeInfo (cc65_scopedata* D, const ScopeInfo* S)
+/* Copy data from a ScopeInfo struct to a cc65_scopedata struct */
+{
+    D->scope_id       = S->Id;
+    D->scope_name     = S->ScopeName;
+    D->scope_type     = S->Type;
+    D->scope_size     = S->Size;
+    D->scope_parent   = S->Parent.Scope->Id;
 }
 
 
@@ -1562,9 +1682,11 @@ static void NextToken (InputData* D)
         { "name",       TOK_NAME        },
         { "outputname", TOK_OUTPUTNAME  },
         { "outputoffs", TOK_OUTPUTOFFS  },
+        { "parent",     TOK_PARENT      },
         { "range",      TOK_RANGE       },
         { "ro",         TOK_RO          },
         { "rw",         TOK_RW          },
+        { "scope",      TOK_SCOPE       },
         { "seg",        TOK_SEGMENT     },
         { "segment",    TOK_SEGMENT     },
         { "size",       TOK_SIZE        },
@@ -2055,6 +2177,163 @@ ErrorExit:
 
 
 
+static void ParseScope (InputData* D)
+/* Parse a SCOPE line */
+{
+    /* Most of the following variables are initialized with a value that is
+     * overwritten later. This is just to avoid compiler warnings.
+     */
+    unsigned            Id = CC65_INV_ID;
+    cc65_scope_type     Type = CC65_SCOPE_MODULE;
+    cc65_size           Size = 0;
+    StrBuf              Name = STRBUF_INITIALIZER;
+    unsigned            Parent = CC65_INV_ID;
+    ScopeInfo*          S;
+    enum {
+        ibNone          = 0x000,
+
+        ibId            = 0x001,
+        ibName          = 0x002,
+        ibParent        = 0x004,
+        ibSize          = 0x008,
+        ibType          = 0x010,
+
+        ibRequired      = ibId | ibName | ibParent | ibType,
+    } InfoBits = ibNone;
+
+    /* Skip the SCOPE token */
+    NextToken (D);
+
+    /* More stuff follows */
+    while (1) {
+
+        Token Tok;
+
+        /* Something we know? */
+        if (D->Tok != TOK_ID            && D->Tok != TOK_NAME           &&
+            D->Tok != TOK_PARENT        && D->Tok != TOK_SIZE           &&
+            D->Tok != TOK_TYPE) {
+
+            /* Try smart error recovery */
+            if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
+                UnknownKeyword (D);
+                continue;
+            }
+
+            /* Done */
+            break;
+        }
+
+        /* Remember the token, skip it, check for equal */
+        Tok = D->Tok;
+        NextToken (D);
+        if (!ConsumeEqual (D)) {
+            goto ErrorExit;
+        }
+
+        /* Check what the token was */
+        switch (Tok) {
+
+            case TOK_ID:
+                if (!IntConstFollows (D)) {
+                    goto ErrorExit;
+                }
+                Id = D->IVal;
+                InfoBits |= ibId;
+                NextToken (D);
+                break;
+
+            case TOK_NAME:
+                if (!StrConstFollows (D)) {
+                    goto ErrorExit;
+                }
+                SB_Copy (&Name, &D->SVal);
+                SB_Terminate (&Name);
+                InfoBits |= ibName;
+                NextToken (D);
+                break;
+
+            case TOK_PARENT:
+                if (!IntConstFollows (D)) {
+                    goto ErrorExit;
+                }
+                Size = D->IVal;
+                NextToken (D);
+                InfoBits |= ibParent;
+                break;
+
+            case TOK_SIZE:
+                if (!IntConstFollows (D)) {
+                    goto ErrorExit;
+                }
+                Size = (cc65_size) D->IVal;
+                InfoBits |= ibSize;
+                NextToken (D);
+                break;
+
+            case TOK_TYPE:
+                switch (D->Tok) {
+                    case TOK_EQUATE:
+                        Type = CC65_SYM_EQUATE;
+                        break;
+                    case TOK_LABEL:
+                        Type = CC65_SYM_LABEL;
+                        break;
+                    default:
+                        ParseError (D, CC65_ERROR,
+                                    "Unknown value for attribute \"type\"");
+                        SkipLine (D);
+                        goto ErrorExit;
+                }
+                NextToken (D);
+                InfoBits |= ibType;
+                break;
+
+            default:
+                /* NOTREACHED */
+                UnexpectedToken (D);
+                goto ErrorExit;
+
+        }
+
+        /* Comma or done */
+        if (D->Tok != TOK_COMMA) {
+            break;
+        }
+        NextToken (D);
+    }
+
+    /* Check for end of line */
+    if (D->Tok != TOK_EOL && D->Tok != TOK_EOF) {
+        UnexpectedToken (D);
+        SkipLine (D);
+        goto ErrorExit;
+    }
+
+    /* Check for required and/or matched information */
+    if ((InfoBits & ibRequired) != ibRequired) {
+        ParseError (D, CC65_ERROR, "Required attributes missing");
+        goto ErrorExit;
+    }
+
+    /* Create the scope info */
+    S = NewScopeInfo (&Name);
+    S->Id        = Id;
+    S->Type      = Type;
+    S->Size      = Size;
+    S->Parent.Id = Parent;
+
+    /* ... and remember it */
+    CollAppend (&D->Info->ScopeInfoById, S);
+
+ErrorExit:
+    /* Entry point in case of errors */
+    SB_Done (&Name);
+    return;
+}
+
+
+
 static void ParseSegment (InputData* D)
 /* Parse a SEGMENT line */
 {
@@ -2066,15 +2345,17 @@ static void ParseSegment (InputData* D)
     unsigned long   OutputOffs = 0;
     SegInfo*        S;
     enum {
-        ibNone      = 0x00,
-        ibId        = 0x01,
-        ibSegName   = 0x02,
-        ibStart     = 0x04,
-        ibSize      = 0x08,
-        ibAddrSize  = 0x10,
-        ibType      = 0x20,
-        ibOutputName= 0x40,
-        ibOutputOffs= 0x80,
+        ibNone      = 0x000,
+
+        ibAddrSize  = 0x001,
+        ibId        = 0x002,
+        ibOutputName= 0x004,
+        ibOutputOffs= 0x008,
+        ibSegName   = 0x010,
+        ibSize      = 0x020,
+        ibStart     = 0x040,
+        ibType      = 0x080,
+
         ibRequired  = ibId | ibSegName | ibStart | ibSize | ibAddrSize | ibType,
     } InfoBits = ibNone;
 
@@ -2230,26 +2511,37 @@ ErrorExit:
 
 static void ParseSym (InputData* D)
 /* Parse a SYM line */
-{                                                                 
+{
     /* Most of the following variables are initialized with a value that is
      * overwritten later. This is just to avoid compiler warnings.
      */
+    unsigned            File = CC65_INV_ID;
+    unsigned            Id = CC65_INV_ID;
+    StrBuf              Name = STRBUF_INITIALIZER;
+    unsigned            Parent = CC65_INV_ID;
+    unsigned            Scope = CC65_INV_ID;
+    unsigned            Segment = CC65_INV_ID;
+    cc65_size           Size = 0;
     cc65_symbol_type    Type = CC65_SYM_EQUATE;
     long                Value = 0;
-    cc65_size           Size = 0;
-    StrBuf              SymName = STRBUF_INITIALIZER;
-    unsigned            Segment = CC65_INV_ID;
+
     SymInfo*            S;
     enum {
-        ibNone          = 0x00,
-        ibSymName       = 0x01,
-        ibValue         = 0x02,
-        ibAddrSize      = 0x04,
-        ibType          = 0x08,
-        ibSize          = 0x10,
-        ibSegment       = 0x20,
-        ibFile          = 0x40,
-        ibRequired      = ibSymName | ibValue | ibAddrSize | ibType,
+        ibNone          = 0x000,
+
+        ibAddrSize      = 0x001,
+        ibFile          = 0x002,
+        ibId            = 0x004,
+        ibParent        = 0x008,
+        ibScope         = 0x010,
+        ibSegment       = 0x020,
+        ibSize          = 0x040,
+        ibName          = 0x080,
+        ibType          = 0x100,
+        ibValue         = 0x200,
+
+        ibRequired      = ibAddrSize | ibId | ibScope | ibName |
+                          ibType | ibValue,
     } InfoBits = ibNone;
 
     /* Skip the SYM token */
@@ -2262,9 +2554,10 @@ static void ParseSym (InputData* D)
 
         /* Something we know? */
         if (D->Tok != TOK_ADDRSIZE      && D->Tok != TOK_FILE   &&
-            D->Tok != TOK_NAME          && D->Tok != TOK_SEGMENT&&
-            D->Tok != TOK_SIZE          && D->Tok != TOK_TYPE   &&
-            D->Tok != TOK_VALUE) {
+            D->Tok != TOK_ID            && D->Tok != TOK_NAME   &&
+            D->Tok != TOK_PARENT        && D->Tok != TOK_SCOPE  &&
+            D->Tok != TOK_SEGMENT       && D->Tok != TOK_SIZE   &&
+            D->Tok != TOK_TYPE          && D->Tok != TOK_VALUE) {
 
             /* Try smart error recovery */
             if (D->Tok == TOK_IDENT || TokenIsKeyword (D->Tok)) {
@@ -2295,19 +2588,46 @@ static void ParseSym (InputData* D)
                 if (!IntConstFollows (D)) {
                     goto ErrorExit;
                 }
-                /* ### Drop value for now */
+                File = D->IVal;
                 InfoBits |= ibFile;
                 NextToken (D);
                 break;
 
+            case TOK_ID:
+                if (!IntConstFollows (D)) {
+                    goto ErrorExit;
+                }
+                Id = D->IVal;
+                NextToken (D);
+                InfoBits |= ibId;
+                break;
+
             case TOK_NAME:
                 if (!StrConstFollows (D)) {
                     goto ErrorExit;
                 }
-                SB_Copy (&SymName, &D->SVal);
-                SB_Terminate (&SymName);
-                InfoBits |= ibSymName;
+                SB_Copy (&Name, &D->SVal);
+                SB_Terminate (&Name);
+                InfoBits |= ibName;
+                NextToken (D);
+                break;
+
+            case TOK_PARENT:
+                if (!IntConstFollows (D)) {
+                    goto ErrorExit;
+                }
+                Parent = D->IVal;
                 NextToken (D);
+                InfoBits |= ibParent;
+                break;
+
+            case TOK_SCOPE:
+                if (!IntConstFollows (D)) {
+                    goto ErrorExit;
+                }
+                Scope = D->IVal;
+                NextToken (D);
+                InfoBits |= ibScope;
                 break;
 
             case TOK_SEGMENT:
@@ -2382,14 +2702,24 @@ static void ParseSym (InputData* D)
         goto ErrorExit;
     }
 
-    /* Create the symbol info and remember it */
-    S = NewSymInfo (&SymName, Value, Type, Size, Segment);
+    /* Create the symbol info */
+    S = NewSymInfo (&Name);
+    S->Id      = Id;
+    S->Type    = Type;
+    S->Value   = Value;
+    S->Size    = Size;
+    S->Segment = Segment;
+    S->Scope   = Scope;
+    S->Parent  = Parent;
+
+    /* Remember it */
+    CollAppend (&D->Info->SymInfoById, S);
     CollAppend (&D->Info->SymInfoByName, S);
     CollAppend (&D->Info->SymInfoByVal, S);
 
 ErrorExit:
     /* Entry point in case of errors */
-    SB_Done (&SymName);
+    SB_Done (&Name);
     return;
 }
 
@@ -2821,16 +3151,56 @@ static void ProcessSymInfo (InputData* D)
 /* Postprocess symbol infos */
 {
     /* Get pointers to the symbol info collections */
+    Collection* SymInfoById   = &D->Info->SymInfoById;
     Collection* SymInfoByName = &D->Info->SymInfoByName;
     Collection* SymInfoByVal  = &D->Info->SymInfoByVal;
 
     /* Sort the symbol infos */
+    CollSort (SymInfoById,   CompareSymInfoById);
     CollSort (SymInfoByName, CompareSymInfoByName);
     CollSort (SymInfoByVal,  CompareSymInfoByVal);
 }
 
 
 
+static int FindSymInfoById (Collection* SymInfos, unsigned Id, unsigned* Index)
+/* Find the SymInfo for a given id. The function returns true if the id
+ * was found. In this case, Index contains the index of the first item that
+ * matches. If the item wasn't found, the function returns false and Index
+ * contains the insert position for the given id.
+ */
+{
+    /* Do a binary search */
+    int Lo = 0;
+    int Hi = (int) CollCount (SymInfos) - 1;
+    int Found = 0;
+    while (Lo <= Hi) {
+
+        /* Mid of range */
+        int Cur = (Lo + Hi) / 2;
+
+        /* Get item */
+        SymInfo* CurItem = CollAt (SymInfos, Cur);
+
+        /* Found? */
+        if (Id > CurItem->Id) {
+            Lo = Cur + 1;
+        } else if (Id < CurItem->Id) {
+            Hi = Cur - 1;
+        } else {
+            Found = 1;
+            Lo = Cur;
+            break;
+        }
+    }
+
+    /* Pass back the index. This is also the insert position */
+    *Index = Lo;
+    return Found;
+}
+
+
+
 static int FindSymInfoByName (Collection* SymInfos, const char* SymName, unsigned* Index)
 /* Find the SymInfo for a given file name. The function returns true if the
  * name was found. In this case, Index contains the index of the first item
@@ -2914,6 +3284,70 @@ static int FindSymInfoByValue (Collection* SymInfos, long Value, unsigned* Index
 
 
 
+static void ProcessScopeInfo (InputData* D)
+/* Postprocess scope infos */
+{
+    unsigned I;
+
+    /* Get pointers to the scope info collections */
+    Collection* ScopeInfoById = &D->Info->ScopeInfoById;
+
+    /* Sort the scope infos */
+    CollSort (ScopeInfoById, CompareScopeInfoById);
+
+    /* Walk over all scope infos and replace the parent scope id by a pointer
+     * to the parent scope.
+     */
+    for (I = 0; I < CollCount (ScopeInfoById); ++I) {
+
+        /* Get this scope info */
+        ScopeInfo* S = CollAt (ScopeInfoById, I);
+
+        /* Replace the parent id by a pointer */
+        S->Parent.Scope = CollAt (ScopeInfoById, S->Parent.Id);
+    }
+}
+
+
+
+static int FindScopeInfoById (Collection* ScopeInfos, unsigned Id, unsigned* Index)
+/* Find the ScopeInfo for a given id. The function returns true if the id
+ * was found. In this case, Index contains the index of the first item that
+ * matches. If the item wasn't found, the function returns false and Index
+ * contains the insert position for the given id.
+ */
+{
+    /* Do a binary search */
+    int Lo = 0;
+    int Hi = (int) CollCount (ScopeInfos) - 1;
+    int Found = 0;
+    while (Lo <= Hi) {
+
+        /* Mid of range */
+        int Cur = (Lo + Hi) / 2;
+
+        /* Get item */
+        SymInfo* CurItem = CollAt (ScopeInfos, Cur);
+
+        /* Found? */
+        if (Id > CurItem->Id) {
+            Lo = Cur + 1;
+        } else if (Id < CurItem->Id) {
+            Hi = Cur - 1;
+        } else {
+            Found = 1;
+            Lo = Cur;
+            break;
+        }
+    }
+
+    /* Pass back the index. This is also the insert position */
+    *Index = Lo;
+    return Found;
+}
+
+
+
 /*****************************************************************************/
 /*                             Debug info files                              */
 /*****************************************************************************/
@@ -3018,6 +3452,10 @@ cc65_dbginfo cc65_read_dbginfo (const char* FileName, cc65_errorfunc ErrFunc)
                 ParseLine (&D);
                 break;
 
+            case TOK_SCOPE:
+                ParseScope (&D);
+                break;
+
             case TOK_SEGMENT:
                 ParseSegment (&D);
                 break;
@@ -3074,6 +3512,7 @@ CloseAndExit:
     ProcessFileInfo (&D);
     ProcessLineInfo (&D);
     ProcessSymInfo (&D);
+    ProcessScopeInfo (&D);
 
 #if DEBUG
     /* Debug output */
@@ -3424,6 +3863,43 @@ void cc65_free_segmentinfo (cc65_dbginfo Handle, cc65_segmentinfo* Info)
 
 
 
+cc65_symbolinfo* cc65_symbol_byid (cc65_dbginfo Handle, unsigned Id)
+/* Return the symbol with a given id. The function returns NULL if no symbol
+ * with this id was found.
+ */
+{
+    DbgInfo*            Info;
+    Collection*         SymInfoById;
+    cc65_symbolinfo*    D;
+    unsigned            Index;
+
+    /* Check the parameter */
+    assert (Handle != 0);
+
+    /* The handle is actually a pointer to a debug info struct */
+    Info = (DbgInfo*) Handle;
+
+    /* Get a pointer to the symbol list */
+    SymInfoById = &Info->SymInfoById;
+
+    /* Search for the symbol */
+    if (!FindSymInfoById (SymInfoById, Id, &Index)) {
+        /* Not found */
+        return 0;
+    }
+
+    /* Allocate memory for the data structure returned to the caller */
+    D = new_cc65_symbolinfo (1);
+
+    /* Fill in the data */
+    CopySymInfo (D->data, CollAt (SymInfoById, Index));
+
+    /* Return the result */
+    return D;
+}
+
+
+
 cc65_symbolinfo* cc65_symbol_byname (cc65_dbginfo Handle, const char* Name)
 /* Return a list of symbols with a given name. The function returns NULL if
  * no symbol with this name was found.
@@ -3467,7 +3943,6 @@ cc65_symbolinfo* cc65_symbol_byname (cc65_dbginfo Handle, const char* Name)
     D = new_cc65_symbolinfo (Count);
 
     /* Fill in the data */
-    D->count = Count;
     for (I = 0; I < Count; ++I) {
         /* Copy the data */
         CopySymInfo (D->data + I, CollAt (SymInfoByName, Index++));
@@ -3541,7 +4016,6 @@ cc65_symbolinfo* cc65_symbol_inrange (cc65_dbginfo Handle, cc65_addr Start, cc65
     D = new_cc65_symbolinfo (CollCount (&SymInfoList));
 
     /* Fill in the data */
-    D->count = CollCount (&SymInfoList);
     for (I = 0; I < CollCount (&SymInfoList); ++I) {
         /* Copy the data */
         CopySymInfo (D->data + I, CollAt (&SymInfoList, I));
@@ -3568,3 +4042,58 @@ void cc65_free_symbolinfo (cc65_dbginfo Handle, cc65_symbolinfo* Info)
 
 
 
+/*****************************************************************************/
+/*                                  Scopes                                   */
+/*****************************************************************************/
+
+
+
+cc65_scopeinfo* cc65_scope_byid (cc65_dbginfo Handle, unsigned Id)
+/* Return the scope with a given id. The function returns NULL if no scope
+ * with this id was found.
+ */
+{
+    DbgInfo*            Info;
+    Collection*         ScopeInfoById;
+    cc65_scopeinfo*     D;
+    unsigned            Index;
+
+    /* Check the parameter */
+    assert (Handle != 0);
+
+    /* The handle is actually a pointer to a debug info struct */
+    Info = (DbgInfo*) Handle;
+
+    /* Get a pointer to the scope list */
+    ScopeInfoById = &Info->ScopeInfoById;
+
+    /* Search for the scope */
+    if (!FindScopeInfoById (ScopeInfoById, Id, &Index)) {
+        /* Not found */
+        return 0;
+    }
+
+    /* Allocate memory for the data structure returned to the caller */
+    D = new_cc65_scopeinfo (1);
+
+    /* Fill in the data */
+    CopyScopeInfo (D->data, CollAt (ScopeInfoById, Index));
+
+    /* Return the result */
+    return D;
+}
+
+
+
+void cc65_free_scopeinfo (cc65_dbginfo Handle, cc65_scopeinfo* Info)
+/* Free a scope info record */
+{
+    /* Just for completeness, check the handle */
+    assert (Handle != 0);
+
+    /* Free the memory */
+    xfree (Info);
+}
+
+
+
index d63bd68b2a82f5be6377275c894b62c47092f117..ef80377008af13f6112135b5f0ed64ebb8a3d4b7 100644 (file)
@@ -123,7 +123,7 @@ struct cc65_lineinfo {
 /* Source file information */
 typedef struct cc65_sourcedata cc65_sourcedata;
 struct cc65_sourcedata {
-    unsigned            id;             /* The internal file id */
+    unsigned            source_id;      /* The internal file id */
     const char*         source_name;    /* Name of the file */
     unsigned long       source_size;    /* Size of file */
     unsigned long       source_mtime;   /* Modification time */
@@ -144,7 +144,7 @@ struct cc65_sourceinfo {
  */
 typedef struct cc65_segmentdata cc65_segmentdata;
 struct cc65_segmentdata {
-    unsigned            id;             /* The internal segment id */
+    unsigned            segment_id;     /* The internal segment id */
     const char*         segment_name;   /* Name of the segment */
     cc65_addr           segment_start;  /* Start address of segment */
     cc65_addr           segment_size;   /* Size of segment */
@@ -161,19 +161,21 @@ struct cc65_segmentinfo {
 /* Symbol information */
 typedef enum {
     CC65_SYM_EQUATE,
-    CC65_SYM_LABEL                      /* Some sort of address */
+    CC65_SYM_LABEL,                     /* Some sort of address */
 } cc65_symbol_type;
 
 typedef struct cc65_symboldata cc65_symboldata;
 struct cc65_symboldata {
+    unsigned            symbol_id;      /* Id of symbol */
     const char*         symbol_name;    /* Name of symbol */
     cc65_symbol_type    symbol_type;    /* Type of symbol */
     cc65_size           symbol_size;    /* Size of symbol, 0 if unknown */
     long                symbol_value;   /* Value of symbol */
     unsigned            symbol_segment; /* If the symbol is segment relative,
                                          * this contains the id of segment,
-                                         * otherwise CC65_INV_ID 
+                                         * otherwise CC65_INV_ID
                                          */
+    unsigned            scope_id;       /* The scope this symbol is in */
 };
 
 typedef struct cc65_symbolinfo cc65_symbolinfo;
@@ -182,6 +184,30 @@ struct cc65_symbolinfo {
     cc65_symboldata     data[1];        /* Data sets, number is dynamic */
 };
 
+/* Scope information */
+typedef enum {
+    CC65_SCOPE_GLOBAL,                  /* Global scope */
+    CC65_SCOPE_MODULE,                  /* Module scope */
+    CC65_SCOPE_SCOPE,                   /* .PROC/.SCOPE */
+    CC65_SCOPE_STRUCT,                  /* .STRUCT */
+    CC65_SCOPE_ENUM,                    /* .ENUM */
+} cc65_scope_type;
+
+typedef struct cc65_scopedata cc65_scopedata;
+struct cc65_scopedata {
+    unsigned            scope_id;       /* Id of scope */
+    const char*         scope_name;     /* Name of scope */
+    cc65_scope_type     scope_type;     /* Type of scope */
+    cc65_size           scope_size;     /* Size of scope, 0 if unknown */
+    unsigned            scope_parent;   /* Id of parent scope */
+};
+
+typedef struct cc65_scopeinfo cc65_scopeinfo;
+struct cc65_scopeinfo {
+    unsigned            count;          /* Number of data sets that follow */
+    cc65_scopedata      data[1];        /* Data sets, number is dynamic */
+};
+
 
 
 /*****************************************************************************/
@@ -272,6 +298,11 @@ void cc65_free_segmentinfo (cc65_dbginfo handle, cc65_segmentinfo* info);
 
 
 
+cc65_symbolinfo* cc65_symbol_byid (cc65_dbginfo handle, unsigned id);
+/* Return the symbol with a given id. The function returns NULL if no symbol
+ * with this id was found.
+ */
+
 cc65_symbolinfo* cc65_symbol_byname (cc65_dbginfo handle, const char* name);
 /* Return a list of symbols with a given name. The function returns NULL if
  * no symbol with this name was found.
@@ -289,6 +320,22 @@ void cc65_free_symbolinfo (cc65_dbginfo Handle, cc65_symbolinfo* Info);
 
 
 
+/*****************************************************************************/
+/*                                  Scopes                                   */
+/*****************************************************************************/
+
+
+
+cc65_scopeinfo* cc65_scope_byid (cc65_dbginfo handle, unsigned id);
+/* Return the scope with a given id. The function returns NULL if no scope
+ * with this id was found.
+ */
+
+void cc65_free_scopeinfo (cc65_dbginfo Handle, cc65_scopeinfo* Info);
+/* Free a scope info record */
+
+
+
 /* Allow usage from C++ */
 #ifdef __cplusplus
 }