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
This commit is contained in:
cuz 2000-06-03 11:15:11 +00:00
parent 5e561a0f40
commit 522c7e8c46
21 changed files with 880 additions and 300 deletions

View File

@ -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 ();
}
}

View File

@ -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 */

View File

@ -36,7 +36,7 @@
#include "error.h"
#include "expr.h"
#include "instr.h"
#include "scanner.h"
#include "nexttok.h"
#include "ea.h"

View File

@ -37,7 +37,7 @@
#include <stdlib.h>
#include <stdarg.h>
#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;

View File

@ -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 */
};

View File

@ -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"

View File

@ -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"

149
src/ca65/istack.c Normal file
View File

@ -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);
}
}

71
src/ca65/istack.h Normal file
View File

@ -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

View File

@ -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);
}

View File

@ -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 */

View File

@ -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;

View File

@ -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

View File

@ -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
|

219
src/ca65/nexttok.c Normal file
View File

@ -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 ();
}
}

80
src/ca65/nexttok.h Normal file
View File

@ -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

View File

@ -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 },

View File

@ -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 */
{

View File

@ -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 */

View File

@ -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++;
}

View File

@ -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