From 522c7e8c46d0aae3b13885a769ca4a9e87e36733 Mon Sep 17 00:00:00 2001 From: cuz Date: Sat, 3 Jun 2000 11:15:11 +0000 Subject: [PATCH] Added a more generic way to push sources that deliver a token stream independent of the actual input from the file. Change macro handling to use the new input stack. Fixed an error in FreeIf: If an unexpected .ENDIF was reached, the assembler started an endless loop printing error messages. git-svn-id: svn://svn.cc65.org/cc65/trunk@24 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- src/ca65/condasm.c | 23 ++- src/ca65/condasm.h | 6 + src/ca65/ea.c | 2 +- src/ca65/error.c | 5 +- src/ca65/error.h | 3 +- src/ca65/expr.c | 4 +- src/ca65/instr.c | 2 +- src/ca65/istack.c | 149 +++++++++++++++ src/ca65/istack.h | 71 +++++++ src/ca65/macro.c | 306 +++++++++++++++--------------- src/ca65/macro.h | 8 +- src/ca65/main.c | 3 +- src/ca65/make/gcc.mak | 9 +- src/ca65/make/watcom.mak | 8 +- src/ca65/nexttok.c | 219 +++++++++++++++++++++ src/ca65/nexttok.h | 80 ++++++++ src/ca65/pseudo.c | 13 +- src/ca65/scanner.c | 116 +++-------- src/ca65/scanner.h | 23 +-- src/ca65/{toknode.c => toklist.c} | 78 +++++++- src/ca65/{toknode.h => toklist.h} | 52 +++-- 21 files changed, 880 insertions(+), 300 deletions(-) create mode 100644 src/ca65/istack.c create mode 100644 src/ca65/istack.h create mode 100644 src/ca65/nexttok.c create mode 100644 src/ca65/nexttok.h rename src/ca65/{toknode.c => toklist.c} (75%) rename src/ca65/{toknode.h => toklist.h} (71%) diff --git a/src/ca65/condasm.c b/src/ca65/condasm.c index 831802c37..5b699e574 100644 --- a/src/ca65/condasm.c +++ b/src/ca65/condasm.c @@ -35,7 +35,7 @@ #include "error.h" #include "expr.h" -#include "scanner.h" +#include "nexttok.h" #include "symtab.h" #include "condasm.h" @@ -124,6 +124,7 @@ static void FreeIf (void) IfDesc* D = GetCurrentIf(); if (D == 0) { Error (ERR_UNEXPECTED, ".ENDIF"); + Done = 1; } else { Done = (D->Flags & ifNeedTerm) != 0; --IfCount; @@ -402,7 +403,7 @@ void CheckOpenIfs (void) /* There are no open .IFs */ break; } - + if (D->Pos.Name != CurPos.Name) { /* The .if is from another file, bail out */ break; @@ -416,3 +417,21 @@ void CheckOpenIfs (void) +unsigned GetIfStack (void) +/* Get the current .IF stack pointer */ +{ + return IfCount; +} + + + +void CleanupIfStack (unsigned SP) +/* Cleanup the .IF stack, remove anything above the given stack pointer */ +{ + while (IfCount > SP) { + FreeIf (); + } +} + + + diff --git a/src/ca65/condasm.h b/src/ca65/condasm.h index 3994b3929..84a2ac026 100644 --- a/src/ca65/condasm.h +++ b/src/ca65/condasm.h @@ -52,6 +52,12 @@ void CheckOpenIfs (void); * open .ifs in this file. */ +unsigned GetIfStack (void); +/* Get the current .IF stack pointer */ + +void CleanupIfStack (unsigned SP); +/* Cleanup the .IF stack, remove anything above the given stack pointer */ + /* End of condasm.h */ diff --git a/src/ca65/ea.c b/src/ca65/ea.c index 8bc8e810d..f715ec6d7 100644 --- a/src/ca65/ea.c +++ b/src/ca65/ea.c @@ -36,7 +36,7 @@ #include "error.h" #include "expr.h" #include "instr.h" -#include "scanner.h" +#include "nexttok.h" #include "ea.h" diff --git a/src/ca65/error.c b/src/ca65/error.c index 5dea2d6e5..a81afc07c 100644 --- a/src/ca65/error.c +++ b/src/ca65/error.c @@ -37,7 +37,7 @@ #include #include -#include "scanner.h" +#include "nexttok.h" #include "error.h" @@ -190,6 +190,7 @@ void ErrorMsg (const FilePos* Pos, unsigned ErrNum, va_list ap) "CPU not supported", "Counter underflow", "Undefined label", + "Open `%sī", }; fprintf (stderr, "%s(%lu): Error #%u: ", @@ -257,7 +258,7 @@ void Fatal (unsigned FatNum, ...) "Cannot open listing file: %s", "Cannot write to listing file: %s", "Cannot read from listing file: %s", - "Macro nesting too deep", + "Too many nested constructs", "Too many symbols", }; va_list ap; diff --git a/src/ca65/error.h b/src/ca65/error.h index 7dba96924..ff365a999 100644 --- a/src/ca65/error.h +++ b/src/ca65/error.h @@ -123,6 +123,7 @@ enum Errors { ERR_CPU_NOT_SUPPORTED, ERR_COUNTER_UNDERFLOW, ERR_UNDEFINED_LABEL, + ERR_OPEN_STMT, ERR_COUNT /* Error count */ }; @@ -140,7 +141,7 @@ enum Fatals { FAT_CANNOT_OPEN_LISTING, FAT_CANNOT_WRITE_LISTING, FAT_CANNOT_READ_LISTING, - FAT_MACRO_NESTING, + FAT_NESTING, FAT_TOO_MANY_SYMBOLS, FAT_COUNT /* Fatal error count */ }; diff --git a/src/ca65/expr.c b/src/ca65/expr.c index 6131e39a0..509dc6eba 100644 --- a/src/ca65/expr.c +++ b/src/ca65/expr.c @@ -39,11 +39,11 @@ #include "global.h" #include "instr.h" #include "mem.h" +#include "nexttok.h" #include "objcode.h" #include "objfile.h" -#include "scanner.h" #include "symtab.h" -#include "toknode.h" +#include "toklist.h" #include "ulabel.h" #include "expr.h" diff --git a/src/ca65/instr.c b/src/ca65/instr.c index 50c74923b..6f8b3fea7 100644 --- a/src/ca65/instr.c +++ b/src/ca65/instr.c @@ -43,8 +43,8 @@ #include "error.h" #include "expr.h" #include "global.h" +#include "nexttok.h" #include "objcode.h" -#include "scanner.h" #include "instr.h" diff --git a/src/ca65/istack.c b/src/ca65/istack.c new file mode 100644 index 000000000..6e2f9e241 --- /dev/null +++ b/src/ca65/istack.c @@ -0,0 +1,149 @@ +/*****************************************************************************/ +/* */ +/* istack.c */ +/* */ +/* Input stack for the scanner */ +/* */ +/* */ +/* */ +/* (C) 2000 Ullrich von Bassewitz */ +/* Wacholderweg 14 */ +/* D-70597 Stuttgart */ +/* EMail: uz@musoftware.de */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +#include "error.h" +#include "mem.h" +#include "istack.h" + + + +/*****************************************************************************/ +/* Data */ +/*****************************************************************************/ + + + +/* Size of the stack (== maximum nested macro or repeat count) */ +#define ISTACK_MAX 256 + +/* Structure holding a stack element */ +typedef struct IElement IElement; +struct IElement { + IElement* Next; /* Next stack element */ + int (*Func)(void*); /* Function called for input */ + void* Data; /* User data given as argument */ + const char* Desc; /* Description */ +}; + +/* The stack */ +static IElement* IStack = 0; /* Input stack pointer */ +static unsigned ICount = 0; /* Number of items on the stack */ + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +void PushInput (int (*Func) (void*), void* Data, const char* Desc) +/* Push an input function onto the input stack */ +{ + IElement* E; + + /* Check for a stack overflow */ + if (ICount > ISTACK_MAX) { + Fatal (FAT_NESTING); + } + + /* Create a new stack element */ + E = Xmalloc (sizeof (*E)); + + /* Initialize it */ + E->Func = Func; + E->Data = Data; + E->Desc = Desc; + + /* Push it */ + E->Next = IStack; + IStack = E; +} + + + +void PopInput (void) +/* Pop the current input function from the input stack */ +{ + IElement* E; + + /* We cannot pop from an empty stack */ + PRECONDITION (IStack != 0); + + /* Remember the last element */ + E = IStack; + + /* Pop it */ + IStack = IStack->Next; + + /* And delete it */ + Xfree (E); +} + + + +int InputFromStack (void) +/* Try to get input from the input stack. Return true if we had such input, + * return false otherwise. + */ +{ + /* Repeatedly call the TOS routine until we have a token or if run out of + * routines. + */ + while (IStack) { + if (IStack->Func (IStack->Data) != 0) { + /* We have a token */ + return 1; + } + } + + /* Nothing is on the stack */ + return 0; +} + + + +void CheckInputStack (void) +/* Called from the scanner before closing an input file. Will check for any + * stuff on the input stack. + */ +{ + if (IStack) { + Error (ERR_OPEN_STMT, IStack->Desc); + } +} + + + diff --git a/src/ca65/istack.h b/src/ca65/istack.h new file mode 100644 index 000000000..0e8d893e9 --- /dev/null +++ b/src/ca65/istack.h @@ -0,0 +1,71 @@ +/*****************************************************************************/ +/* */ +/* istack.h */ +/* */ +/* Input stack for the scanner */ +/* */ +/* */ +/* */ +/* (C) 2000 Ullrich von Bassewitz */ +/* Wacholderweg 14 */ +/* D-70597 Stuttgart */ +/* EMail: uz@musoftware.de */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +#ifndef ISTACK_H +#define ISTACK_H + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +void PushInput (int (*Func) (void*), void* Data, const char* Desc); +/* Push an input function onto the input stack */ + +void PopInput (void); +/* Pop the current input function from the input stack */ + +int InputFromStack (void); +/* Try to get input from the input stack. Return true if we had such input, + * return false otherwise. + */ + +void CheckInputStack (void); +/* Called from the scanner before closing an input file. Will check for any + * stuff on the input stack. + */ + + + +/* End of istack.h */ + +#endif + + + + diff --git a/src/ca65/macro.c b/src/ca65/macro.c index 73d8a0018..a5eb78262 100644 --- a/src/ca65/macro.c +++ b/src/ca65/macro.c @@ -38,11 +38,13 @@ #include "../common/hashstr.h" -#include "mem.h" +#include "condasm.h" #include "error.h" -#include "scanner.h" -#include "toknode.h" +#include "istack.h" +#include "mem.h" +#include "nexttok.h" #include "pseudo.h" +#include "toklist.h" #include "macro.h" @@ -90,6 +92,7 @@ typedef struct MacExp_ MacExp; struct MacExp_ { MacExp* Next; /* Pointer to next expansion */ Macro* M; /* Which macro do we expand? */ + unsigned IfSP; /* .IF stack pointer at start of expansion */ TokNode* Exp; /* Pointer to current token */ TokNode* Final; /* Pointer to final token */ unsigned LocalStart; /* Start of counter for local symbol names */ @@ -98,11 +101,14 @@ struct MacExp_ { TokNode* ParamExp; /* Node for expanding parameters */ }; -/* Data for macro expansions */ -#define MAX_MACRO_EXPANSIONS 255 -static unsigned MacroNesting = 0; -static MacExp* CurMac = 0; -static unsigned LocalName = 0; +/* Number of active macro expansions */ +static unsigned MacExpansions = 0; + +/* Flag if a macro expansion should get aborted */ +static int DoMacAbort = 0; + +/* Counter to create local names for symbols */ +static unsigned LocalName = 0; @@ -172,6 +178,7 @@ static MacExp* NewMacExp (Macro* M) /* Initialize the data */ E->M = M; + E->IfSP = GetIfStack (); E->Exp = M->TokRoot; E->Final = 0; E->LocalStart = LocalName; @@ -183,44 +190,34 @@ static MacExp* NewMacExp (Macro* M) E->Params [I] = 0; } - /* And return it... */ + /* One macro expansion more */ + ++MacExpansions; + + /* Return the new macro expansion */ return E; } -static void MacInsertExp (MacExp* E) -/* Insert a macro expansion into the list */ -{ - E->Next = CurMac; - CurMac = E; - ++MacroNesting; -} - - - -static void FreeMacExp (void) +static void FreeMacExp (MacExp* E) /* Remove and free the current macro expansion */ { unsigned I; - MacExp* E; + + /* One macro expansion less */ + --MacExpansions; /* Free the parameter list */ - for (I = 0; I < CurMac->ParamCount; ++I) { - Xfree (CurMac->Params [I]); + for (I = 0; I < E->ParamCount; ++I) { + Xfree (E->Params [I]); } - Xfree (CurMac->Params); + Xfree (E->Params); /* Free the final token if we have one */ - if (CurMac->Final) { - FreeTokNode (CurMac->Final); + if (E->Final) { + FreeTokNode (E->Final); } - /* Reset the list pointer */ - E = CurMac; - CurMac = E->Next; - --MacroNesting; - /* Free the structure itself */ Xfree (E); } @@ -390,7 +387,7 @@ void MacDef (unsigned Style) IdDesc* I; - /* Skip .local or comma */ + /* Skip .local or comma */ NextTok (); /* Need an identifer */ @@ -461,6 +458,123 @@ void MacDef (unsigned Style) +static int MacExpand (void* Data) +/* If we're currently expanding a macro, set the the scanner token and + * attribute to the next value and return true. If we are not expanding + * a macro, return false. + */ +{ + /* Cast the Data pointer to the actual data structure */ + MacExp* Mac = (MacExp*) Data; + + /* Check if we should abort this macro */ + if (DoMacAbort) { + + /* Reset the flag */ + DoMacAbort = 0; + + /* Abort any open .IF statements in this macro expansion */ + CleanupIfStack (Mac->IfSP); + + /* Terminate macro expansion */ + goto MacEnd; + } + + /* We're expanding a macro. Check if we are expanding one of the + * macro parameters. + */ + if (Mac->ParamExp) { + + /* Ok, use token from parameter list */ + TokSet (Mac->ParamExp); + + /* Set pointer to next token */ + Mac->ParamExp = Mac->ParamExp->Next; + + /* Done */ + return 1; + + } + + /* We're not expanding macro parameters. Check if we have tokens left from + * the macro itself. + */ + if (Mac->Exp) { + + /* Use next macro token */ + TokSet (Mac->Exp); + + /* Set pointer to next token */ + Mac->Exp = Mac->Exp->Next; + + /* Is it a request for actual parameter count? */ + if (Tok == TOK_PARAMCOUNT) { + Tok = TOK_INTCON; + IVal = Mac->ParamCount; + return 1; + } + + /* Is it the name of a macro parameter? */ + if (Tok == TOK_MACPARAM) { + + /* Start to expand the parameter token list */ + Mac->ParamExp = Mac->Params [IVal]; + + /* Recursive call to expand the parameter */ + return MacExpand (Mac); + } + + /* If it's an identifier, it may in fact be a local symbol */ + if (Tok == TOK_IDENT && Mac->M->LocalCount) { + /* Search for the local symbol in the list */ + unsigned Index = 0; + IdDesc* I = Mac->M->Locals; + while (I) { + if (strcmp (SVal, I->Id) == 0) { + /* This is in fact a local symbol, change the name */ + sprintf (SVal, "___%04X__", Mac->LocalStart + Index); + break; + } + /* Next symbol */ + ++Index; + I = I->Next; + } + + /* Done */ + return 1; + } + + /* The token was successfully set */ + return 1; + + } + + /* No more macro tokens. Do we have a final token? */ + if (Mac->Final) { + + /* Set the final token and remove it */ + TokSet (Mac->Final); + FreeTokNode (Mac->Final); + Mac->Final = 0; + + /* The token was successfully set */ + return 1; + + } + +MacEnd: + /* End of macro expansion */ + FreeMacExp (Mac); + + /* Pop the input function */ + PopInput (); + + /* No token available */ + return 0; +} + + + static void StartExpClassic (Macro* M) /* Start expanding the classic macro M */ { @@ -522,8 +636,8 @@ static void StartExpClassic (Macro* M) } } - /* Insert the newly created structure into the expansion list */ - MacInsertExp (E); + /* Insert a new token input function */ + PushInput (MacExpand, E, ".MACRO"); } @@ -596,8 +710,8 @@ static void StartExpDefine (Macro* M) */ E->Final = NewTokNode (); - /* Insert the newly created structure into the expansion list */ - MacInsertExp (E); + /* Insert a new token input function */ + PushInput (MacExpand, E, ".DEFINE"); } @@ -605,123 +719,15 @@ static void StartExpDefine (Macro* M) void MacExpandStart (void) /* Start expanding the macro in SVal */ { - Macro* M; - - /* Beware of runoff macros */ - if (MacroNesting == MAX_MACRO_EXPANSIONS) { - Fatal (FAT_MACRO_NESTING); - } - /* Search for the macro */ - M = MacFind (SVal, HashStr (SVal) % HASHTAB_SIZE); + Macro* M = MacFind (SVal, HashStr (SVal) % HASHTAB_SIZE); CHECK (M != 0); /* Call the apropriate subroutine */ switch (M->Style) { case MAC_STYLE_CLASSIC: StartExpClassic (M); break; case MAC_STYLE_DEFINE: StartExpDefine (M); break; - default: Internal ("Invalid macro style: %d", M->Style); - } -} - - - -int MacExpand (void) -/* If we're currently expanding a macro, set the the scanner token and - * attribute to the next value and return true. If we are not expanding - * a macro, return false. - */ -{ - if (MacroNesting == 0) { - /* Not expanding a macro */ - return 0; - } - - /* We're expanding a macro. Check if we are expanding one of the - * macro parameters. - */ - if (CurMac->ParamExp) { - - /* Ok, use token from parameter list */ - TokSet (CurMac->ParamExp); - - /* Set pointer to next token */ - CurMac->ParamExp = CurMac->ParamExp->Next; - - /* Done */ - return 1; - - } else if (CurMac->Exp) { - - /* We're not expanding a parameter, use next macro token */ - TokSet (CurMac->Exp); - - /* Set pointer to next token */ - CurMac->Exp = CurMac->Exp->Next; - - /* Is it a request for actual parameter count? */ - if (Tok == TOK_PARAMCOUNT) { - Tok = TOK_INTCON; - IVal = CurMac->ParamCount; - return 1; - } - - /* Is it an .exitmacro command? */ - if (Tok == TOK_EXITMACRO) { - /* Forced exit from macro expansion */ - FreeMacExp (); - return MacExpand (); - } - - /* Is it the name of a macro parameter? */ - if (Tok == TOK_MACPARAM) { - - /* Start to expand the parameter token list */ - CurMac->ParamExp = CurMac->Params [IVal]; - - /* Recursive call to expand the parameter */ - return MacExpand (); - } - - /* If it's an identifier, it may in fact be a local symbol */ - if (Tok == TOK_IDENT && CurMac->M->LocalCount) { - /* Search for the local symbol in the list */ - unsigned Index = 0; - IdDesc* I = CurMac->M->Locals; - while (I) { - if (strcmp (SVal, I->Id) == 0) { - /* This is in fact a local symbol, change the name */ - sprintf (SVal, "___%04X__", CurMac->LocalStart + Index); - break; - } - /* Next symbol */ - ++Index; - I = I->Next; - } - - /* Done */ - return 1; - } - - /* The token was successfully set */ - return 1; - - } else if (CurMac->Final) { - - /* Set the final token and remove it */ - TokSet (CurMac->Final); - FreeTokNode (CurMac->Final); - CurMac->Final = 0; - - /* The token was successfully set */ - return 1; - - } else { - - /* End of macro expansion */ - FreeMacExp (); - return MacExpand (); - + default: Internal ("Invalid macro style: %d", M->Style); } } @@ -731,10 +737,10 @@ void MacAbort (void) /* Abort the current macro expansion */ { /* Must have an expansion */ - CHECK (CurMac != 0); + CHECK (MacExpansions > 0); - /* Free current structure */ - FreeMacExp (); + /* Set a flag so macro expansion will terminate on the next call */ + DoMacAbort = 1; } @@ -759,7 +765,7 @@ int IsDefine (const char* Name) int InMacExpansion (void) /* Return true if we're currently expanding a macro */ { - return MacroNesting != 0; + return (MacExpansions > 0); } diff --git a/src/ca65/macro.h b/src/ca65/macro.h index defcd9ad8..d889f1aa0 100644 --- a/src/ca65/macro.h +++ b/src/ca65/macro.h @@ -62,12 +62,6 @@ void MacDef (unsigned Style); void MacExpandStart (void); /* Start expanding the macro in SVal */ -int MacExpand (void); -/* If we're currently expanding a macro, set the the scanner token and - * attribute to the next value and return true. If we are not expanding - * a macro, return false. - */ - void MacAbort (void); /* Abort the current macro expansion */ @@ -77,7 +71,7 @@ int IsMacro (const char* Name); int IsDefine (const char* Name); /* Return true if the given name is the name of a define style macro */ -int InMacExpansion (void); +int InMacExpansion (void); /* Return true if we're currently expanding a macro */ diff --git a/src/ca65/main.c b/src/ca65/main.c index ec5dac13d..063f467af 100644 --- a/src/ca65/main.c +++ b/src/ca65/main.c @@ -49,6 +49,7 @@ #include "listing.h" #include "macro.h" #include "mem.h" +#include "nexttok.h" #include "objcode.h" #include "objfile.h" #include "options.h" @@ -543,7 +544,7 @@ int main (int argc, char* argv []) OptIgnoreCase (Arg); break; - case 'l': + case 'l': OptListing (Arg); break; diff --git a/src/ca65/make/gcc.mak b/src/ca65/make/gcc.mak index 97d58b76a..7476985a0 100644 --- a/src/ca65/make/gcc.mak +++ b/src/ca65/make/gcc.mak @@ -15,11 +15,13 @@ OBJS = condasm.o \ global.o \ incpath.o \ instr.o \ + istack.o \ listing.o \ macpack.o \ macro.o \ - main.o \ - mem.o \ + main.o \ + mem.o \ + nexttok.o \ objcode.o \ objfile.o \ options.o \ @@ -27,7 +29,7 @@ OBJS = condasm.o \ scanner.o \ strexpr.o \ symtab.o \ - toknode.o \ + toklist.o \ ulabel.o LIBS = ../common/common.a @@ -62,3 +64,4 @@ depend dep: $(OBJS:.o=.c) @echo "Creating dependency information" $(CC) -MM $^ > .depend + diff --git a/src/ca65/make/watcom.mak b/src/ca65/make/watcom.mak index 0e3c28734..92e34ce43 100644 --- a/src/ca65/make/watcom.mak +++ b/src/ca65/make/watcom.mak @@ -72,11 +72,13 @@ OBJS = condasm.obj \ global.obj \ incpath.obj \ instr.obj \ + istack.obj \ listing.obj \ macpack.obj \ macro.obj \ main.obj \ mem.obj \ + nexttok.obj \ objcode.obj \ objfile.obj \ options.obj \ @@ -84,7 +86,7 @@ OBJS = condasm.obj \ scanner.obj \ strexpr.obj \ symtab.obj \ - toknode.obj \ + toklist.obj \ ulabel.obj LIBS = ..\common\common.lib @@ -116,11 +118,13 @@ FILE fragment.obj FILE global.obj FILE incpath.obj FILE instr.obj +FILE istack.obj FILE listing.obj FILE macpack.obj FILE macro.obj FILE main.obj FILE mem.obj +FILE nexttok.obj FILE objcode.obj FILE objfile.obj FILE options.obj @@ -128,7 +132,7 @@ FILE pseudo.obj FILE scanner.obj FILE strexpr.obj FILE symtab.obj -FILE toknode.obj +FILE toklist.obj FILE ulabel.obj LIBRARY ..\common\common.lib | diff --git a/src/ca65/nexttok.c b/src/ca65/nexttok.c new file mode 100644 index 000000000..393412634 --- /dev/null +++ b/src/ca65/nexttok.c @@ -0,0 +1,219 @@ +/*****************************************************************************/ +/* */ +/* nexttok.c */ +/* */ +/* Get next token and handle token level functions */ +/* */ +/* */ +/* */ +/* (C) 2000 Ullrich von Bassewitz */ +/* Wacholderweg 14 */ +/* D-70597 Stuttgart */ +/* EMail: uz@musoftware.de */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +#include "error.h" +#include "expr.h" +#include "scanner.h" +#include "toklist.h" +#include "nexttok.h" + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +static TokList* CollectTokens (unsigned Start, unsigned Count) +/* Read a list of tokens that is terminated by a right paren. For all tokens + * starting at the one with index Start, and ending at (Start+Count-1), place + * them into a token list, and return this token list. + */ +{ + /* Create the token list */ + TokList* List = NewTokList (); + + /* Read the token list */ + unsigned Current = 0; + unsigned Parens = 0; + while (Parens != 0 && Tok != TOK_RPAREN) { + + /* Check for end of line or end of input */ + if (Tok == TOK_SEP || Tok == TOK_EOF) { + Error (ERR_UNEXPECTED_EOL); + return List; + } + + /* Collect tokens in the given range */ + if (Current >= Start && Current < Start+Count) { + /* Add the current token to the list */ + AddCurTok (List); + } + + /* Check for and count parenthesii */ + if (Tok == TOK_LPAREN) { + ++Parens; + } else if (Tok == TOK_RPAREN) { + --Parens; + } + + /* Get the next token */ + NextTok (); + } + + /* Eat the closing paren */ + ConsumeRParen (); + + /* Return the list of collected tokens */ + return List; +} + + + +static void FuncMid (void) +/* Handle the .MID function */ +{ + long Start; + long Count; + TokList* List; + + /* Skip it */ + NextTok (); + + /* Left paren expected */ + ConsumeRParen (); + + /* Start argument */ + Start = ConstExpression (); + if (Start < 0 || Start > 100) { + Error (ERR_RANGE); + Start = 0; + } + ConsumeComma (); + + /* Count argument */ + Count = ConstExpression (); + if (Count > 100) { + Error (ERR_RANGE); + Count = 1; + } + ConsumeComma (); + + /* Read the token list */ + List = CollectTokens ((unsigned) Start, (unsigned) Count); + + /* Insert it into the scanner feed */ + + + +} + + + +void NextTok (void) +/* Get next token and handle token level functions */ +{ + /* Get the next raw token */ + NextRawTok (); + + /* Check for token handling functions */ + switch (Tok) { + + case TOK_MID: + FuncMid (); + break; + + default: + /* Quiet down gcc */ + break; + + } +} + + + +void Consume (enum Token Expected, unsigned ErrMsg) +/* Consume Expected, print an error if we don't find it */ +{ + if (Tok == Expected) { + NextTok (); + } else { + Error (ErrMsg); + } +} + + + +void ConsumeSep (void) +/* Consume a separator token */ +{ + /* Accept an EOF as separator */ + if (Tok != TOK_EOF) { + if (Tok != TOK_SEP) { + Error (ERR_TOO_MANY_CHARS); + SkipUntilSep (); + } else { + NextTok (); + } + } +} + + + +void ConsumeLParen (void) +/* Consume a left paren */ +{ + Consume (TOK_LPAREN, ERR_LPAREN_EXPECTED); +} + + + +void ConsumeRParen (void) +/* Consume a right paren */ +{ + Consume (TOK_RPAREN, ERR_RPAREN_EXPECTED); +} + + + +void ConsumeComma (void) +/* Consume a comma */ +{ + Consume (TOK_COMMA, ERR_COMMA_EXPECTED); +} + + + +void SkipUntilSep (void) +/* Skip tokens until we reach a line separator */ +{ + while (Tok != TOK_SEP && Tok != TOK_EOF) { + NextTok (); + } +} + + + diff --git a/src/ca65/nexttok.h b/src/ca65/nexttok.h new file mode 100644 index 000000000..bc63b699e --- /dev/null +++ b/src/ca65/nexttok.h @@ -0,0 +1,80 @@ +/*****************************************************************************/ +/* */ +/* nexttok.h */ +/* */ +/* Get next token and handle token level functions */ +/* */ +/* */ +/* */ +/* (C) 2000 Ullrich von Bassewitz */ +/* Wacholderweg 14 */ +/* D-70597 Stuttgart */ +/* EMail: uz@musoftware.de */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +#ifndef NEXTTOK_H +#define NEXTTOK_H + + + +#include "scanner.h" + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +void NextTok (void); +/* Get next token and handle token level functions */ + +void Consume (enum Token Expected, unsigned ErrMsg); +/* Consume Token, print an error if we don't find it */ + +void ConsumeSep (void); +/* Consume a separator token */ + +void ConsumeLParen (void); +/* Consume a left paren */ + +void ConsumeRParen (void); +/* Consume a right paren */ + +void ConsumeComma (void); +/* Consume a comma */ + +void SkipUntilSep (void); +/* Skip tokens until we reach a line separator */ + + + +/* End of nexttok.h */ + +#endif + + + + diff --git a/src/ca65/pseudo.c b/src/ca65/pseudo.c index f2ad9b350..2edf19ec8 100644 --- a/src/ca65/pseudo.c +++ b/src/ca65/pseudo.c @@ -49,9 +49,9 @@ #include "listing.h" #include "macpack.h" #include "macro.h" +#include "nexttok.h" #include "objcode.h" #include "options.h" -#include "scanner.h" #include "strexpr.h" #include "symtab.h" #include "pseudo.h" @@ -789,6 +789,16 @@ static void DoMacro (void) +static void DoMid (void) +/* Handle .MID - this should never happen, since the keyword is actually + * handled on a much lower level of the expression hierarchy. + */ +{ + Internal ("Unexpected token: .MID"); +} + + + static void DoNull (void) /* Switch to the NULL segment */ { @@ -1119,6 +1129,7 @@ static CtrlDesc CtrlCmdTab [] = { { ccNone, DoMacPack }, { ccNone, DoMacro }, { ccNone, DoUnexpected }, /* .MATCH */ + { ccNone, DoMid }, { ccNone, DoNull }, { ccNone, DoOrg }, { ccNone, DoOut }, diff --git a/src/ca65/scanner.c b/src/ca65/scanner.c index 8a2a376ad..30ba6db7c 100644 --- a/src/ca65/scanner.c +++ b/src/ca65/scanner.c @@ -46,10 +46,12 @@ #include "global.h" #include "incpath.h" #include "instr.h" +#include "istack.h" #include "listing.h" #include "macro.h" #include "mem.h" #include "objfile.h" +#include "toklist.h" #include "scanner.h" @@ -104,10 +106,10 @@ static struct { static unsigned FileCount = 0; /* Current input variables */ -static InputFile* IFile = 0; -static InputData* IData = 0; -static unsigned ICount = 0; /* Count of input files */ -static int C = 0; +static InputFile* IFile = 0; /* Current input file */ +static InputData* IData = 0; /* Current input memory data */ +static unsigned ICount = 0; /* Count of input files */ +static int C = 0; /* Current input character */ /* Force end of assembly */ int ForcedEnd = 0; @@ -121,7 +123,7 @@ struct DotKeyword { { "A8", TOK_A8 }, { "ADDR", TOK_ADDR }, { "ALIGN", TOK_ALIGN }, - { "AND", TOK_BAND }, + { "AND", TOK_BAND }, { "ASCIIZ", TOK_ASCIIZ }, { "AUTOIMPORT", TOK_AUTOIMPORT }, { "BITAND", TOK_AND }, @@ -131,15 +133,15 @@ struct DotKeyword { { "BLANK", TOK_BLANK }, { "BSS", TOK_BSS }, { "BYTE", TOK_BYTE }, - { "CASE", TOK_CASE }, + { "CASE", TOK_CASE }, { "CODE", TOK_CODE }, { "CONST", TOK_CONST }, - { "CPU", TOK_CPU }, + { "CPU", TOK_CPU }, { "DATA", TOK_DATA }, { "DBYT", TOK_DBYT }, { "DEBUGINFO", TOK_DEBUGINFO }, { "DEF", TOK_DEFINED }, - { "DEFINE", TOK_DEFINE }, + { "DEFINE", TOK_DEFINE }, { "DEFINED", TOK_DEFINED }, { "DWORD", TOK_DWORD }, { "ELSE", TOK_ELSE }, @@ -189,10 +191,11 @@ struct DotKeyword { { "MACPACK", TOK_MACPACK }, { "MACRO", TOK_MACRO }, { "MATCH", TOK_MATCH }, - { "MOD", TOK_MOD }, - { "NOT", TOK_BNOT }, + { "MID", TOK_MID }, + { "MOD", TOK_MOD }, + { "NOT", TOK_BNOT }, { "NULL", TOK_NULL }, - { "OR", TOK_BOR }, + { "OR", TOK_BOR }, { "ORG", TOK_ORG }, { "OUT", TOK_OUT }, { "P02", TOK_P02 }, @@ -202,15 +205,15 @@ struct DotKeyword { { "PARAMCOUNT", TOK_PARAMCOUNT }, { "PC02", TOK_PC02 }, { "PROC", TOK_PROC }, - { "REF", TOK_REFERENCED }, + { "REF", TOK_REFERENCED }, { "REFERENCED", TOK_REFERENCED }, { "RELOC", TOK_RELOC }, { "REPEAT", TOK_REPEAT }, { "RES", TOK_RES }, { "RODATA", TOK_RODATA }, { "SEGMENT", TOK_SEGMENT }, - { "SHL", TOK_SHL }, - { "SHR", TOK_SHR }, + { "SHL", TOK_SHL }, + { "SHR", TOK_SHR }, { "SMART", TOK_SMART }, { "STRING", TOK_STRING }, { "SUNPLUS", TOK_SUNPLUS }, @@ -489,7 +492,7 @@ static void NextChar (void) /* End of file. Add an empty line to the listing. This is a * small hack needed to keep the PC output in sync. */ - NewListingLine ("", IFile->Pos.Name, ICount); + NewListingLine ("", IFile->Pos.Name, ICount); C = EOF; return; } @@ -627,7 +630,7 @@ static unsigned ReadStringConst (int StringTerm) -void NextTok (void) +void NextRawTok (void) /* Read the next raw token from the input stream */ { /* If we've a forced end of assembly, don't read further */ @@ -636,8 +639,9 @@ void NextTok (void) return; } - /* If we're expanding a macro, the tokens come from the macro expansion */ - if (MacExpand ()) { +Restart: + /* Check if we have tokens from another input source */ + if (InputFromStack ()) { return; } @@ -813,9 +817,7 @@ Again: } else if (IsDefine (SVal)) { /* This is a define style macro - expand it */ MacExpandStart (); - if (!MacExpand ()) { - goto Again; - } + goto Restart; } else { /* An identifier */ Tok = TOK_IDENT; @@ -894,8 +896,8 @@ CharAgain: IVal = 0; do { ++IVal; - NextChar (); - } while (C == '+'); + NextChar (); + } while (C == '+'); Tok = TOK_ULABEL; break; @@ -1029,8 +1031,8 @@ CharAgain: /* Handle as white space */ NextChar (); C = ' '; - goto Again; - } + goto Again; + } } break; @@ -1042,6 +1044,8 @@ CharAgain: case EOF: /* Check if we have any open .IFs in this file */ CheckOpenIfs (); + /* Check if we have any open token lists in this file */ + CheckInputStack (); /* If this was an include file, then close it and handle like a * separator. Do not close the main file, but return EOF. @@ -1065,68 +1069,6 @@ CharAgain: -void Consume (enum Token Expected, unsigned ErrMsg) -/* Consume Expected, print an error if we don't find it */ -{ - if (Tok == Expected) { - NextTok (); - } else { - Error (ErrMsg); - } -} - - - -void ConsumeSep (void) -/* Consume a separator token */ -{ - /* Accept an EOF as separator */ - if (Tok != TOK_EOF) { - if (Tok != TOK_SEP) { - Error (ERR_TOO_MANY_CHARS); - SkipUntilSep (); - } else { - NextTok (); - } - } -} - - - -void ConsumeLParen (void) -/* Consume a left paren */ -{ - Consume (TOK_LPAREN, ERR_LPAREN_EXPECTED); -} - - - -void ConsumeRParen (void) -/* Consume a right paren */ -{ - Consume (TOK_RPAREN, ERR_RPAREN_EXPECTED); -} - - - -void ConsumeComma (void) -/* Consume a comma */ -{ - Consume (TOK_COMMA, ERR_COMMA_EXPECTED); -} - - - -void SkipUntilSep (void) -/* Skip tokens until we reach a line separator */ -{ - while (Tok != TOK_SEP && Tok != TOK_EOF) { - NextTok (); - } -} - - - int TokHasSVal (enum Token Tok) /* Return true if the given token has an attached SVal */ { diff --git a/src/ca65/scanner.h b/src/ca65/scanner.h index 813a54f76..7c1a424c2 100644 --- a/src/ca65/scanner.h +++ b/src/ca65/scanner.h @@ -168,6 +168,7 @@ enum Token { TOK_MACPACK, TOK_MACRO, TOK_MATCH, + TOK_MID, TOK_NULL, TOK_ORG, TOK_OUT, @@ -230,26 +231,8 @@ void NewInputData (const char* Data, int Malloced); void UpcaseSVal (void); /* Make SVal upper case */ -void NextTok (void); -/* Read the next token from the input stream */ - -void Consume (enum Token Expected, unsigned ErrMsg); -/* Consume Token, print an error if we don't find it */ - -void ConsumeSep (void); -/* Consume a separator token */ - -void ConsumeLParen (void); -/* Consume a left paren */ - -void ConsumeRParen (void); -/* Consume a right paren */ - -void ConsumeComma (void); -/* Consume a comma */ - -void SkipUntilSep (void); -/* Skip tokens until we reach a line separator */ +void NextRawTok (void); +/* Read the next raw token from the input stream */ int TokHasSVal (enum Token Tok); /* Return true if the given token has an attached SVal */ diff --git a/src/ca65/toknode.c b/src/ca65/toklist.c similarity index 75% rename from src/ca65/toknode.c rename to src/ca65/toklist.c index b1eeb8b64..dc2712d39 100644 --- a/src/ca65/toknode.c +++ b/src/ca65/toklist.c @@ -1,8 +1,8 @@ /*****************************************************************************/ /* */ -/* toknode.c */ +/* toklist.c */ /* */ -/* Token list node for the ca65 macroassembler */ +/* Token list for the ca65 macroassembler */ /* */ /* */ /* */ @@ -37,7 +37,7 @@ #include "mem.h" #include "scanner.h" -#include "toknode.h" +#include "toklist.h" @@ -97,7 +97,7 @@ enum TC TokCmp (const TokNode* T) /* Different token */ return tcDifferent; } - + /* If the token has string attribute, check it */ if (TokHasSVal (T->Tok)) { if (strcmp (T->SVal, SVal) != 0) { @@ -108,10 +108,78 @@ enum TC TokCmp (const TokNode* T) return tcSameToken; } } - + /* Tokens are identical */ return tcIdentical; } +void InitTokList (TokList* T) +/* Initialize a token list structure for later use */ +{ + /* Initialize the fields */ + T->Next = 0; + T->Root = 0; + T->Last = 0; + T->Repeat = 1; + T->Count = 0; +} + + + +TokList* NewTokList (void) +/* Create a new, empty token list */ +{ + /* Allocate memory for the list structure */ + TokList* T = Xmalloc (sizeof (TokList)); + + /* Initialize the fields */ + InitTokList (T); + + /* Return the new list */ + return T; +} + + + +void FreeTokList (TokList* List) +/* Delete the token list including all token nodes */ +{ + /* Free the token list */ + TokNode* T = List->Root; + while (T) { + TokNode* Tmp = T; + T = T->Next; + FreeTokNode (Tmp); + } + + /* Free the list structure itself */ + Xfree (List); +} + + + +void AddCurTok (TokList* List) +/* Add the current token to the token list */ +{ + /* Create a token node with the current token value */ + TokNode* T = NewTokNode (); + + /* Insert the node into the list */ + if (List->Root == 0) { + List->Root = T; + } else { + List->Last->Next = T; + } + List->Last = T; + + /* Count nodes */ + List->Count++; +} + + + + + + diff --git a/src/ca65/toknode.h b/src/ca65/toklist.h similarity index 71% rename from src/ca65/toknode.h rename to src/ca65/toklist.h index e3580e2aa..fb0351349 100644 --- a/src/ca65/toknode.h +++ b/src/ca65/toklist.h @@ -1,12 +1,12 @@ /*****************************************************************************/ /* */ -/* toknode.h */ +/* toklist.h */ /* */ -/* Token list node for the ca65 macroassembler */ +/* Token list for the ca65 macroassembler */ /* */ /* */ /* */ -/* (C) 1998 Ullrich von Bassewitz */ +/* (C) 2000 Ullrich von Bassewitz */ /* Wacholderweg 14 */ /* D-70597 Stuttgart */ /* EMail: uz@musoftware.de */ @@ -33,8 +33,8 @@ -#ifndef TOKNODE_H -#define TOKNODE_H +#ifndef TOKLIST_H +#define TOKLIST_H @@ -45,22 +45,32 @@ /* Struct holding a token */ -typedef struct TokNode_ TokNode; -struct TokNode_ { - TokNode* Next; /* For single linked list */ - enum Token Tok; /* Token value */ +typedef struct TokNode TokNode; +struct TokNode { + TokNode* Next; /* For single linked list */ + enum Token Tok; /* Token value */ int WS; /* Whitespace before token? */ - long IVal; /* Integer token attribute */ - char SVal [1]; /* String attribute, dyn. allocated */ + long IVal; /* Integer token attribute */ + char SVal [1]; /* String attribute, dyn. allocated */ +}; + +/* Struct holding a token list */ +typedef struct TokList TokList; +struct TokList { + TokList* Next; /* Single linked list (for replay) */ + TokNode* Root; /* First node in list */ + TokNode* Last; /* Last node in list or replay */ + unsigned Repeat; /* Repeat counter (used for replay) */ + unsigned Count; /* Token count */ }; /* Return codes for TokCmp - higher numeric code means better match */ enum TC { - tcDifferent, /* Different tokents */ - tcSameToken, /* Same token, different attribute */ - tcIdentical /* Identical (token + attribute) */ + tcDifferent, /* Different tokents */ + tcSameToken, /* Same token, different attribute */ + tcIdentical /* Identical (token + attribute) */ }; @@ -83,9 +93,21 @@ void TokSet (TokNode* T); enum TC TokCmp (const TokNode* T); /* Compare the token given as parameter against the current token */ +void InitTokList (TokList* T); +/* Initialize a token list structure for later use */ + +TokList* NewTokList (void); +/* Create a new, empty token list */ + +void FreeTokList (TokList* T); +/* Delete the token list including all token nodes */ + +void AddCurTok (TokList* T); +/* Add the current token to the token list */ -/* End of toknode.h */ + +/* End of toklist.h */ #endif