From eea9accba62e6e7b4d0f579585de21d055b498f9 Mon Sep 17 00:00:00 2001
From: cuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Date: Sat, 6 Dec 2003 14:16:27 +0000
Subject: [PATCH] Make .sizeof work with code scopes. First support for segment
 ranges.

git-svn-id: svn://svn.cc65.org/cc65/trunk@2718 b7a2c559-68d2-44c3-8de9-860c34a00d81
---
 src/ca65/make/gcc.mak    |  1 +
 src/ca65/make/watcom.mak |  1 +
 src/ca65/pseudo.c        |  6 +++---
 src/ca65/segment.c       |  2 +-
 src/ca65/segment.h       |  3 +++
 src/ca65/symtab.c        | 27 +++++++++++++++++++++++++++
 src/ca65/symtab.h        | 22 +++++++++++++---------
 7 files changed, 49 insertions(+), 13 deletions(-)

diff --git a/src/ca65/make/gcc.mak b/src/ca65/make/gcc.mak
index 87c6b1692..950d725dc 100644
--- a/src/ca65/make/gcc.mak
+++ b/src/ca65/make/gcc.mak
@@ -38,6 +38,7 @@ OBJS =  anonname.o      \
 	repeat.o	\
         scanner.o	\
         segment.o       \
+        segrange.o      \
         sizeof.o        \
         spool.o         \
         struct.o        \
diff --git a/src/ca65/make/watcom.mak b/src/ca65/make/watcom.mak
index d8b294a8d..fa7d9ee65 100644
--- a/src/ca65/make/watcom.mak
+++ b/src/ca65/make/watcom.mak
@@ -87,6 +87,7 @@ OBJS = 	anonname.obj    \
 	repeat.obj	\
 	scanner.obj	\
         segment.obj     \
+        segrange.obj    \
         sizeof.obj      \
         spool.obj       \
         struct.obj      \
diff --git a/src/ca65/pseudo.c b/src/ca65/pseudo.c
index b6460fe72..018232717 100644
--- a/src/ca65/pseudo.c
+++ b/src/ca65/pseudo.c
@@ -708,7 +708,7 @@ static void DoEnd (void)
 static void DoEndProc (void)
 /* Leave a lexical level */
 {
-    if (CurrentScope == RootScope || GetCurrentSymTabType () != ST_PROC) {
+    if (GetCurrentSymTabType () != ST_PROC) {
         /* No local scope */
         ErrorSkip ("No open .PROC");
     } else {
@@ -721,7 +721,7 @@ static void DoEndProc (void)
 static void DoEndScope (void)
 /* Leave a lexical level */
 {
-    if (CurrentScope == RootScope || GetCurrentSymTabType () != ST_SCOPE) {
+    if ( GetCurrentSymTabType () != ST_SCOPE) {
         /* No local scope */
         ErrorSkip ("No open .SCOPE");
     } else {
@@ -1508,7 +1508,7 @@ static void DoSunPlus (void)
 
 static void DoTag (void)
 /* Allocate space for a struct */
-{                                           
+{
     SymEntry* SizeSym;
     long Size;
 
diff --git a/src/ca65/segment.c b/src/ca65/segment.c
index c0e64b501..27066844f 100644
--- a/src/ca65/segment.c
+++ b/src/ca65/segment.c
@@ -91,7 +91,7 @@ static Segment CodeSeg     = SEG (&CodeSegDef,     0, &RODataSeg);
 static unsigned SegmentCount = 6;
 
 /* List of all segments */
-static Segment* SegmentList = &CodeSeg;
+Segment* SegmentList = &CodeSeg;
 static Segment* SegmentLast = &NullSeg;
 
 /* Currently active segment */
diff --git a/src/ca65/segment.h b/src/ca65/segment.h
index 57da03130..fb0a02dd4 100644
--- a/src/ca65/segment.h
+++ b/src/ca65/segment.h
@@ -78,6 +78,9 @@ extern SegDef BssSegDef;
 extern SegDef RODataSegDef;
 extern SegDef CodeSegDef;
 
+/* List of all segments */
+extern Segment* SegmentList;
+
 /* Currently active segment */
 extern Segment* ActiveSeg;
 
diff --git a/src/ca65/symtab.c b/src/ca65/symtab.c
index 68e2237c2..52a6f9f20 100644
--- a/src/ca65/symtab.c
+++ b/src/ca65/symtab.c
@@ -50,6 +50,7 @@
 #include "objfile.h"
 #include "scanner.h"
 #include "segment.h"
+#include "sizeof.h"
 #include "spool.h"
 #include "symtab.h"
 
@@ -109,6 +110,7 @@ static SymTable* NewSymTable (SymTable* Parent, const char* Name)
     S->Left         = 0;
     S->Right        = 0;
     S->Childs       = 0;
+    S->SegRanges    = AUTO_COLLECTION_INITIALIZER;
     S->Flags        = ST_NONE;
     S->AddrSize     = ADDR_SIZE_DEFAULT;
     S->Type         = ST_UNDEF;
@@ -195,6 +197,16 @@ void SymEnterLevel (const char* ScopeName, unsigned char Type, unsigned char Add
     CurrentScope->Flags    |= ST_DEFINED;
     CurrentScope->AddrSize = AddrSize;
     CurrentScope->Type     = Type;
+
+    /* If this is a scope that allows to emit data into segments, add segment
+     * ranges for all currently existing segments. Doing this for just a few
+     * scope types is not really necessary but an optimization, because it
+     * does not allocate memory for useless data (unhandled types here don't
+     * occupy space in any segment).
+     */
+    if (CurrentScope->Type <= ST_SCOPE_HAS_DATA) {
+        AddSegRanges (&CurrentScope->SegRanges);
+    }
 }
 
 
@@ -202,6 +214,21 @@ void SymEnterLevel (const char* ScopeName, unsigned char Type, unsigned char Add
 void SymLeaveLevel (void)
 /* Leave the current lexical level */
 {
+    /* Close the segment ranges. We don't care about the scope type here,
+     * since types without segment ranges will just have an empty list.
+     */
+    CloseSegRanges (&CurrentScope->SegRanges);
+
+    /* If we have segment ranges, the first one is the segment that was
+     * active, when the scope was opened. Set the size of the scope to the
+     * number of data bytes emitted into this segment.
+     */
+    if (CollCount (&CurrentScope->SegRanges) > 0) {                                       
+        const SegRange* R = CollAtUnchecked (&CurrentScope->SegRanges, 0);
+        DefSizeOfScope (CurrentScope, GetSegRangeSize (R));
+    }
+
+    /* Leave the scope */
     CurrentScope = CurrentScope->Parent;
 }
 
diff --git a/src/ca65/symtab.h b/src/ca65/symtab.h
index 22c0e778b..aaac2eeb8 100644
--- a/src/ca65/symtab.h
+++ b/src/ca65/symtab.h
@@ -45,6 +45,7 @@
 #include "inline.h"
 
 /* ca65 */
+#include "segrange.h"
 #include "symentry.h"
 
 
@@ -60,12 +61,15 @@
 #define ST_DEFINED      0x01            /* Scope has been defined */
 
 /* Symbol table types */
-#define ST_GLOBAL       0x00            /* Root level */
-#define ST_PROC         0x01            /* .PROC */
-#define ST_SCOPE        0x02            /* .SCOPE */
-#define ST_STRUCT       0x03            /* .STRUCT/.UNION */
-#define ST_ENUM         0x04            /* .ENUM */
-#define ST_UNDEF        0xFF
+enum {
+    ST_GLOBAL,                          /* Root level */
+    ST_PROC,                            /* .PROC */
+    ST_SCOPE,                           /* .SCOPE */
+    ST_SCOPE_HAS_DATA = ST_SCOPE,       /* Last scope that contains data */
+    ST_STRUCT,                          /* .STRUCT/.UNION */
+    ST_ENUM,                            /* .ENUM */
+    ST_UNDEF    = 0xFF
+};
 
 /* A symbol table */
 typedef struct SymTable SymTable;
@@ -74,12 +78,13 @@ struct SymTable {
     SymTable*           Right;          /* Pointer to greater entry */
     SymTable*          	Parent;   	/* Link to enclosing scope if any */
     SymTable*           Childs;         /* Pointer to child scopes */
+    Collection          SegRanges;      /* Segment ranges for this scope */
     unsigned short      Flags;          /* Symbol table flags */
-    unsigned char	AddrSize;       /* Address size */
+    unsigned char    	AddrSize;       /* Address size */
     unsigned char       Type;           /* Type of the scope */
     unsigned            Level;          /* Lexical level */
     unsigned   	     	TableSlots;	/* Number of hash table slots */
-    unsigned   	    	TableEntries;	/* Number of entries in the table */
+    unsigned   	     	TableEntries;	/* Number of entries in the table */
     unsigned            Name;           /* Name of the scope */
     SymEntry*  	       	Table[1];   	/* Dynamic allocation */
 };
@@ -168,4 +173,3 @@ void WriteDbgSyms (void);
 
 
 
-