From 1167d99a9be41e33416a65da431bf93cbacde34c Mon Sep 17 00:00:00 2001 From: cuz Date: Thu, 28 Nov 2002 17:42:16 +0000 Subject: [PATCH] New .PUSHSEG and .POPSEG commands git-svn-id: svn://svn.cc65.org/cc65/trunk@1671 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- src/ca65/error.c | 3 + src/ca65/error.h | 7 ++- src/ca65/main.c | 5 ++ src/ca65/objcode.c | 154 +++++++++++++++------------------------------ src/ca65/objcode.h | 31 ++++----- src/ca65/pseudo.c | 81 +++++++++++++++++++----- src/ca65/pseudo.h | 11 ++-- src/ca65/scanner.c | 2 + src/ca65/scanner.h | 4 +- 9 files changed, 155 insertions(+), 143 deletions(-) diff --git a/src/ca65/error.c b/src/ca65/error.c index 2145818aa..f8f0eabfa 100644 --- a/src/ca65/error.c +++ b/src/ca65/error.c @@ -184,6 +184,9 @@ void ErrorMsg (const FilePos* Pos, unsigned ErrNum, va_list ap) "Conditional assembly branch was never closed", "Lexical level was not terminated correctly", "Segment attribute mismatch", + "Segment stack overflow", + "Segment stack is empty", + "Segment stack is not empty at end of assembly", "CPU not supported", "Counter underflow", "Undefined label", diff --git a/src/ca65/error.h b/src/ca65/error.h index 043931253..c6c9a772d 100644 --- a/src/ca65/error.h +++ b/src/ca65/error.h @@ -44,14 +44,14 @@ /*****************************************************************************/ -/* Data */ +/* Data */ /*****************************************************************************/ /* Warning numbers */ enum Warnings { - WARN_NONE, /* No warning */ + WARN_NONE, /* No warning */ WARN_MASK_ERROR, WARN_SYM_NOT_REFERENCED, WARN_IMPORT_NOT_REFERENCED, @@ -125,6 +125,9 @@ enum Errors { ERR_OPEN_IF, ERR_OPEN_PROC, ERR_SEG_ATTR_MISMATCH, + ERR_SEGSTACK_OVERFLOW, + ERR_SEGSTACK_EMPTY, + ERR_SEGSTACK_NOT_EMPTY, ERR_CPU_NOT_SUPPORTED, ERR_COUNTER_UNDERFLOW, ERR_UNDEFINED_LABEL, diff --git a/src/ca65/main.c b/src/ca65/main.c index 5f7f2ca28..4fac8117c 100644 --- a/src/ca65/main.c +++ b/src/ca65/main.c @@ -621,6 +621,11 @@ int main (int argc, char* argv []) /* Assemble the input */ Assemble (); + /* If we didn't have any errors, check the segment stack */ + if (ErrorCount == 0) { + SegStackCheck (); + } + /* If we didn't have any errors, check the unnamed labels */ if (ErrorCount == 0) { ULabCheck (); diff --git a/src/ca65/objcode.c b/src/ca65/objcode.c index ccdec540d..f4429c6ff 100644 --- a/src/ca65/objcode.c +++ b/src/ca65/objcode.c @@ -70,36 +70,33 @@ unsigned long AbsPC = 0; /* PC if in absolute mode */ typedef struct Segment Segment; struct Segment { Segment* List; /* List of all segments */ - Fragment* Root; /* Root of fragment list */ - Fragment* Last; /* Pointer to last fragment */ - unsigned char Align; /* Segment alignment */ - unsigned char SegType; /* True if zero page segment */ + Fragment* Root; /* Root of fragment list */ + Fragment* Last; /* Pointer to last fragment */ + unsigned Num; /* Segment number */ + unsigned Align; /* Segment alignment */ unsigned long PC; - unsigned Num; /* Segment number */ - char* Name; /* Segment name */ + SegDef* Def; /* Segment definition (name and type) */ }; +#define SEG(segdef, num, prev) \ + { prev, 0, 0, num, 0, 0, segdef } + +/* Definitions for predefined segments */ +SegDef NullSegDef = STATIC_SEGDEF_INITIALIZER ("NULL", SEGTYPE_ABS); +SegDef ZeropageSegDef = STATIC_SEGDEF_INITIALIZER ("ZEROPAGE", SEGTYPE_ZP); +SegDef DataSegDef = STATIC_SEGDEF_INITIALIZER ("DATA", SEGTYPE_ABS); +SegDef BssSegDef = STATIC_SEGDEF_INITIALIZER ("BSS", SEGTYPE_ABS); +SegDef RODataSegDef = STATIC_SEGDEF_INITIALIZER ("RODATA", SEGTYPE_ABS); +SegDef CodeSegDef = STATIC_SEGDEF_INITIALIZER ("CODE", SEGTYPE_ABS); /* Predefined segments */ -static Segment NullSeg = { - 0, 0, 0, 0, SEGTYPE_ABS, 0, 5, "NULL" -}; -static Segment ZeropageSeg = { - &NullSeg, 0, 0, 0, SEGTYPE_ZP, 0, 4, "ZEROPAGE" -}; -static Segment DataSeg = { - &ZeropageSeg, 0, 0, 0, SEGTYPE_ABS, 0, 3, "DATA" -}; -static Segment BssSeg = { - &DataSeg, 0, 0, 0, SEGTYPE_ABS, 0, 2, "BSS" -}; -static Segment RODataSeg = { - &BssSeg, 0, 0, 0, SEGTYPE_ABS, 0, 1, "RODATA" -}; -static Segment CodeSeg = { - &RODataSeg, 0, 0, 0, SEGTYPE_ABS, 0, 0, "CODE" -}; +static Segment NullSeg = SEG (&NullSegDef, 5, NULL); +static Segment ZeropageSeg = SEG (&ZeropageSegDef, 4, &NullSeg); +static Segment DataSeg = SEG (&DataSegDef, 3, &ZeropageSeg); +static Segment BssSeg = SEG (&BssSegDef, 2, &DataSeg); +static Segment RODataSeg = SEG (&RODataSegDef, 1, &BssSeg); +static Segment CodeSeg = SEG (&CodeSegDef, 0, &RODataSeg); /* Number of segments */ static unsigned SegmentCount = 6; @@ -123,7 +120,6 @@ static Segment* NewSegment (const char* Name, unsigned SegType) /* Create a new segment, insert it into the global list and return it */ { Segment* S; - const char* N; /* Check for too many segments */ if (SegmentCount >= 256) { @@ -131,30 +127,21 @@ static Segment* NewSegment (const char* Name, unsigned SegType) } /* Check the segment name for invalid names */ - N = Name; - if ((*N != '_' && !IsAlpha (*N)) || strlen (Name) > 80) { + if (!ValidSegName (Name)) { Error (ERR_ILLEGAL_SEGMENT, Name); } - do { - if (*N != '_' && !IsAlNum (*N)) { - Error (ERR_ILLEGAL_SEGMENT, Name); - break; - } - ++N; - } while (*N); /* Create a new segment */ S = xmalloc (sizeof (*S)); /* Initialize it */ - S->List = 0; - S->Root = 0; - S->Last = 0; - S->Align = 0; - S->SegType = SegType; - S->PC = 0; - S->Num = SegmentCount++; - S->Name = xstrdup (Name); + S->List = 0; + S->Root = 0; + S->Last = 0; + S->Num = SegmentCount++; + S->Align = 0; + S->PC = 0; + S->Def = NewSegDef (Name, SegType); /* Insert it into the segment list */ SegmentLast->List = S; @@ -166,65 +153,17 @@ static Segment* NewSegment (const char* Name, unsigned SegType) -void UseCodeSeg (void) -/* Use the code segment */ -{ - ActiveSeg = &CodeSeg; -} - - - -void UseRODataSeg (void) -/* Use the r/o data segment */ -{ - ActiveSeg = &RODataSeg; -} - - - -void UseDataSeg (void) -/* Use the data segment */ -{ - ActiveSeg = &DataSeg; -} - - - -void UseBssSeg (void) -/* Use the BSS segment */ -{ - ActiveSeg = &BssSeg; -} - - - -void UseZeropageSeg (void) -/* Use the zero page segment */ -{ - ActiveSeg = &ZeropageSeg; -} - - - -void UseNullSeg (void) -/* Use the null segment */ -{ - ActiveSeg = &NullSeg; -} - - - -void UseSeg (const char* Name, unsigned SegType) +void UseSeg (const SegDef* D) /* Use the segment with the given name */ { Segment* Seg = SegmentList; while (Seg) { - if (strcmp (Seg->Name, Name) == 0) { + if (strcmp (Seg->Def->Name, D->Name) == 0) { /* We found this segment. Check if the type is identical */ - if (SegType != SEGTYPE_DEFAULT && Seg->SegType != SegType) { + if (D->Type != SEGTYPE_DEFAULT && Seg->Def->Type != D->Type) { Error (ERR_SEG_ATTR_MISMATCH); /* Use the new attribute to avoid errors */ - Seg->SegType = SegType; + Seg->Def->Type = D->Type; } ActiveSeg = Seg; return; @@ -234,10 +173,11 @@ void UseSeg (const char* Name, unsigned SegType) } /* Segment is not in list, create a new one */ - if (SegType == SEGTYPE_DEFAULT) { - SegType = SEGTYPE_ABS; + if (D->Type == SEGTYPE_DEFAULT) { + Seg = NewSegment (D->Name, SEGTYPE_ABS); + } else { + Seg = NewSegment (D->Name, D->Type); } - Seg = NewSegment (Name, SegType); ActiveSeg = Seg; } @@ -260,6 +200,14 @@ void SetAbsPC (unsigned long PC) +const SegDef* GetCurrentSeg (void) +/* Get a pointer to the segment defininition of the current segment */ +{ + return ActiveSeg->Def; +} + + + unsigned GetSegNum (void) /* Get the number of the current segment */ { @@ -307,7 +255,7 @@ void SegAlign (unsigned Power, int Val) int IsZPSeg (void) /* Return true if the current segment is a zeropage segment */ { - return (ActiveSeg->SegType == SEGTYPE_ZP); + return (ActiveSeg->Def->Type == SEGTYPE_ZP); } @@ -315,7 +263,7 @@ int IsZPSeg (void) int IsFarSeg (void) /* Return true if the current segment is a far segment */ { - return (ActiveSeg->SegType == SEGTYPE_FAR); + return (ActiveSeg->Def->Type == SEGTYPE_FAR); } @@ -336,7 +284,7 @@ unsigned GetSegType (unsigned SegNum) } /* Return the segment type */ - return S->SegType; + return S->Def->Type; } @@ -418,7 +366,7 @@ void SegDump (void) unsigned I; Fragment* F; int State = -1; - printf ("New segment: %s", S->Name); + printf ("New segment: %s", S->Def->Name); F = S->Root; while (F) { if (F->Type == FRAG_LITERAL) { @@ -461,10 +409,10 @@ static void WriteOneSeg (Segment* Seg) unsigned LineInfoIndex; /* Write the segment name followed by the byte count in this segment */ - ObjWriteStr (Seg->Name); + ObjWriteStr (Seg->Def->Name); ObjWrite32 (Seg->PC); ObjWrite8 (Seg->Align); - ObjWrite8 (Seg->SegType); + ObjWrite8 (Seg->Def->Type); /* Now walk through the fragment list for this segment and write the * fragments. diff --git a/src/ca65/objcode.h b/src/ca65/objcode.h index 0dc3744ab..96fa50100 100644 --- a/src/ca65/objcode.h +++ b/src/ca65/objcode.h @@ -55,6 +55,14 @@ /* Are we in absolute mode or in relocatable mode? */ extern int RelocMode; +/* Definitions for predefined segments */ +SegDef NullSegDef; +SegDef ZeropageSegDef; +SegDef DataSegDef; +SegDef BssSegDef; +SegDef RODataSegDef; +SegDef CodeSegDef; + /*****************************************************************************/ @@ -63,26 +71,11 @@ extern int RelocMode; -void UseCodeSeg (void); -/* Use the code segment */ - -void UseRODataSeg (void); -/* Use the r/o data segment */ - -void UseDataSeg (void); -/* Use the data segment */ - -void UseBssSeg (void); -/* Use the BSS segment */ - -void UseZeropageSeg (void); -/* Use the zero page segment */ - -void UseNullSeg (void); -/* Use the null segment */ +void UseSeg (const SegDef* D); +/* Use the given segment */ -void UseSeg (const char* Name, unsigned SegType); -/* Use the segment with the given name */ +const SegDef* GetCurrentSeg (void); +/* Get a pointer to the segment defininition of the current segment */ unsigned GetSegNum (void); /* Get the number of the current segment */ diff --git a/src/ca65/pseudo.c b/src/ca65/pseudo.c index f1ed0a139..2a25be6fa 100644 --- a/src/ca65/pseudo.c +++ b/src/ca65/pseudo.c @@ -42,7 +42,7 @@ /* common */ #include "bitops.h" #include "cddefs.h" -#include "check.h" +#include "coll.h" #include "symdefs.h" #include "tgttrans.h" @@ -75,6 +75,10 @@ /* Keyword we're about to handle */ static char Keyword [sizeof (SVal)+1] = "."; +/* Segment stack */ +#define MAX_PUSHED_SEGMENTS 16 +static Collection SegStack = STATIC_COLLECTION_INITIALIZER; + /*****************************************************************************/ @@ -331,7 +335,7 @@ static void DoAutoImport (void) static void DoBss (void) /* Switch to the BSS segment */ { - UseBssSeg (); + UseSeg (&BssSegDef); } @@ -407,7 +411,7 @@ static void DoCharMap (void) static void DoCode (void) /* Switch to the code segment */ { - UseCodeSeg (); + UseSeg (&CodeSegDef); } @@ -485,7 +489,7 @@ static void DoConstructor (void) static void DoData (void) /* Switch to the data segment */ { - UseDataSeg (); + UseSeg (&DataSegDef); } @@ -1059,7 +1063,7 @@ static void DoMacro (void) static void DoNull (void) /* Switch to the NULL segment */ { - UseNullSeg (); + UseSeg (&NullSegDef); } @@ -1126,6 +1130,29 @@ static void DoPageLength (void) +static void DoPopSeg (void) +/* Pop an old segment from the segment stack */ +{ + SegDef* Def; + + /* Must have a segment on the stack */ + if (CollCount (&SegStack) == 0) { + ErrorSkip (ERR_SEGSTACK_EMPTY); + return; + } + + /* Pop the last element */ + Def = CollPop (&SegStack); + + /* Restore this segment */ + UseSeg (Def); + + /* Delete the segment definition */ + FreeSegDef (Def); +} + + + static void DoProc (void) /* Start a new lexical scope */ { @@ -1139,6 +1166,21 @@ static void DoProc (void) +static void DoPushSeg (void) +/* Push the current segment onto the segment stack */ +{ + /* Can only push a limited size of segments */ + if (CollCount (&SegStack) >= MAX_PUSHED_SEGMENTS) { + ErrorSkip (ERR_SEGSTACK_OVERFLOW); + return; + } + + /* Get the current segment and push it */ + CollAppend (&SegStack, DupSegDef (GetCurrentSeg ())); +} + + + static void DoReloc (void) /* Enter relocatable mode */ { @@ -1191,7 +1233,7 @@ static void DoRes (void) static void DoROData (void) /* Switch to the r/o data segment */ { - UseRODataSeg (); + UseSeg (&RODataSegDef); } @@ -1205,7 +1247,7 @@ static void DoSegment (void) "FAR", "LONG" }; char Name [sizeof (SVal)]; - int SegType; + SegDef Def = { Name, SEGTYPE_DEFAULT }; if (Tok != TOK_STRCON) { ErrorSkip (ERR_STRCON_EXPECTED); @@ -1216,7 +1258,6 @@ static void DoSegment (void) NextTok (); /* Check for an optional segment attribute */ - SegType = SEGTYPE_DEFAULT; if (Tok == TOK_COMMA) { NextTok (); if (Tok != TOK_IDENT) { @@ -1228,18 +1269,18 @@ static void DoSegment (void) case 0: case 1: /* Zeropage */ - SegType = SEGTYPE_ZP; + Def.Type = SEGTYPE_ZP; break; case 2: /* Absolute */ - SegType = SEGTYPE_ABS; + Def.Type = SEGTYPE_ABS; break; case 3: case 4: /* Far */ - SegType = SEGTYPE_FAR; + Def.Type = SEGTYPE_FAR; break; default: @@ -1250,7 +1291,7 @@ static void DoSegment (void) } /* Set the segment */ - UseSeg (Name, SegType); + UseSeg (&Def); } } @@ -1312,7 +1353,7 @@ static void DoWord (void) static void DoZeropage (void) /* Switch to the zeropage segment */ { - UseZeropageSeg (); + UseSeg (&ZeropageSegDef); } @@ -1416,7 +1457,9 @@ static CtrlDesc CtrlCmdTab [] = { { ccNone, DoPageLength }, { ccNone, DoUnexpected }, /* .PARAMCOUNT */ { ccNone, DoPC02 }, + { ccNone, DoPopSeg }, { ccNone, DoProc }, + { ccNone, DoPushSeg }, { ccNone, DoUnexpected }, /* .REFERENCED */ { ccNone, DoReloc }, { ccNone, DoRepeat }, @@ -1440,7 +1483,7 @@ static CtrlDesc CtrlCmdTab [] = { /*****************************************************************************/ -/* Code */ +/* Code */ /*****************************************************************************/ @@ -1483,3 +1526,13 @@ void HandlePseudo (void) +void SegStackCheck (void) +/* Check if the segment stack is empty at end of assembly */ +{ + if (CollCount (&SegStack) != 0) { + Error (ERR_SEGSTACK_NOT_EMPTY); + } +} + + + diff --git a/src/ca65/pseudo.h b/src/ca65/pseudo.h index 5f67b6e9a..b9ebd3164 100644 --- a/src/ca65/pseudo.h +++ b/src/ca65/pseudo.h @@ -6,10 +6,10 @@ /* */ /* */ /* */ -/* (C) 1998 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ -/* EMail: uz@musoftware.de */ +/* (C) 1998-2002 Ullrich von Bassewitz */ +/* Wacholderweg 14 */ +/* D-70597 Stuttgart */ +/* EMail: uz@musoftware.de */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -64,6 +64,9 @@ int TokIsPseudo (unsigned Tok); void HandlePseudo (void); /* Handle a pseudo instruction */ +void SegStackCheck (void); +/* Check if the segment stack is empty at end of assembly */ + /* End of pseudo.h */ diff --git a/src/ca65/scanner.c b/src/ca65/scanner.c index 8ccc1f6a6..537c35ec4 100644 --- a/src/ca65/scanner.c +++ b/src/ca65/scanner.c @@ -211,7 +211,9 @@ struct DotKeyword { { ".PAGELENGTH", TOK_PAGELENGTH }, { ".PARAMCOUNT", TOK_PARAMCOUNT }, { ".PC02", TOK_PC02 }, + { ".POPSEG", TOK_POPSEG }, { ".PROC", TOK_PROC }, + { ".PUSHSEG", TOK_PUSHSEG }, { ".REF", TOK_REFERENCED }, { ".REFERENCED", TOK_REFERENCED }, { ".RELOC", TOK_RELOC }, diff --git a/src/ca65/scanner.h b/src/ca65/scanner.h index 720748937..eb214ab09 100644 --- a/src/ca65/scanner.h +++ b/src/ca65/scanner.h @@ -186,8 +186,10 @@ enum Token { TOK_P816, TOK_PAGELENGTH, TOK_PARAMCOUNT, - TOK_PC02, + TOK_PC02, + TOK_POPSEG, TOK_PROC, + TOK_PUSHSEG, TOK_REFERENCED, TOK_RELOC, TOK_REPEAT, -- 2.39.5