X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fca65%2Fpseudo.c;h=3a2e391d39796aa600a99d896c3c4ff0a46b5c12;hb=1917591b940bd1223ee0b3de3a82cf6665c67689;hp=c00d75a9ccaf6854efe8939bd6d2ca929fd1e95c;hpb=6b002da6039523520f6370e464c51b8278ae1629;p=cc65 diff --git a/src/ca65/pseudo.c b/src/ca65/pseudo.c index c00d75a9c..3a2e391d3 100644 --- a/src/ca65/pseudo.c +++ b/src/ca65/pseudo.c @@ -6,10 +6,10 @@ /* */ /* */ /* */ -/* (C) 1998-2000 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ -/* EMail: uz@musoftware.de */ +/* (C) 1998-2011, Ullrich von Bassewitz */ +/* Roemerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -38,13 +38,32 @@ #include #include #include - -#include "../common/bitops.h" - +#include /* EMX needs this */ +#include + +/* common */ +#include "assertion.h" +#include "bitops.h" +#include "cddefs.h" +#include "coll.h" +#include "intstack.h" +#include "scopedefs.h" +#include "symdefs.h" +#include "tgttrans.h" +#include "xmalloc.h" + +/* ca65 */ +#include "anonname.h" +#include "asserts.h" #include "condasm.h" +#include "dbginfo.h" +#include "enum.h" #include "error.h" #include "expr.h" +#include "feature.h" +#include "filetab.h" #include "global.h" +#include "incpath.h" #include "instr.h" #include "listing.h" #include "macpack.h" @@ -52,8 +71,14 @@ #include "nexttok.h" #include "objcode.h" #include "options.h" -#include "symtab.h" #include "pseudo.h" +#include "repeat.h" +#include "segment.h" +#include "sizeof.h" +#include "spool.h" +#include "struct.h" +#include "symbol.h" +#include "symtab.h" @@ -64,7 +89,14 @@ /* Keyword we're about to handle */ -static char Keyword [sizeof (SVal)+1] = "."; +static StrBuf Keyword = STATIC_STRBUF_INITIALIZER; + +/* CPU stack */ +static IntStack CPUStack = STATIC_INTSTACK_INITIALIZER; + +/* Segment stack */ +#define MAX_PUSHED_SEGMENTS 16 +static Collection SegStack = STATIC_COLLECTION_INITIALIZER; @@ -75,6 +107,16 @@ static char Keyword [sizeof (SVal)+1] = "."; static void DoUnexpected (void); +/* Got an unexpected keyword */ + +static void DoInvalid (void); +/* Handle a token that is invalid here, since it should have been handled on + * a much lower level of the expression hierarchy. Getting this sort of token + * means that the lower level code has bugs. + * This function differs to DoUnexpected in that the latter may be triggered + * by the user by using keywords in the wrong location. DoUnexpected is not + * an error in the assembler itself, while DoInvalid is. + */ @@ -84,6 +126,27 @@ static void DoUnexpected (void); +static unsigned char OptionalAddrSize (void) +/* If a colon follows, parse an optional address size spec and return it. + * Otherwise return ADDR_SIZE_DEFAULT. + */ +{ + unsigned AddrSize = ADDR_SIZE_DEFAULT; + if (CurTok.Tok == TOK_COLON) { + NextTok (); + AddrSize = ParseAddrSize (); + if (!ValidAddrSizeForCPU (AddrSize)) { + /* Print an error and reset to default */ + Error ("Invalid address size specification for current CPU"); + AddrSize = ADDR_SIZE_DEFAULT; + } + NextTok (); + } + return AddrSize; +} + + + static void SetBoolOption (unsigned char* Flag) /* Read a on/off/+/- option and set flag accordingly */ { @@ -92,40 +155,88 @@ static void SetBoolOption (unsigned char* Flag) "ON", }; - if (Tok == TOK_PLUS) { + if (CurTok.Tok == TOK_PLUS) { *Flag = 1; NextTok (); - } else if (Tok == TOK_MINUS) { + } else if (CurTok.Tok == TOK_MINUS) { *Flag = 0; NextTok (); - } else if (Tok == TOK_IDENT) { + } else if (CurTok.Tok == TOK_IDENT) { /* Map the keyword to a number */ switch (GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]))) { - case 0: *Flag = 0; NextTok (); break; - case 1: *Flag = 1; NextTok (); break; - default: ErrorSkip (ERR_ONOFF_EXPECTED); break; + case 0: *Flag = 0; NextTok (); break; + case 1: *Flag = 1; NextTok (); break; + default: ErrorSkip ("`on' or `off' expected"); break; } - } else if (Tok == TOK_SEP || Tok == TOK_EOF) { + } else if (TokIsSep (CurTok.Tok)) { /* Without anything assume switch on */ *Flag = 1; } else { - ErrorSkip (ERR_ONOFF_EXPECTED); + ErrorSkip ("`on' or `off' expected"); } } -static void ExportImport (void (*SymFunc) (const char*, int), int ZP) +static void ExportWithAssign (SymEntry* Sym, unsigned char AddrSize, unsigned Flags) +/* Allow to assign the value of an export in an .export statement */ +{ + /* The name and optional address size spec may be followed by an assignment + * or equal token. + */ + if (CurTok.Tok == TOK_ASSIGN || CurTok.Tok == TOK_EQ) { + + /* Assignment means the symbol is a label */ + if (CurTok.Tok == TOK_ASSIGN) { + Flags |= SF_LABEL; + } + + /* Skip the assignment token */ + NextTok (); + + /* Define the symbol with the expression following the '=' */ + SymDef (Sym, Expression(), ADDR_SIZE_DEFAULT, Flags); + + } + + /* Now export the symbol */ + SymExport (Sym, AddrSize, Flags); +} + + + +static void ExportImport (void (*Func) (SymEntry*, unsigned char, unsigned), + unsigned char DefAddrSize, unsigned Flags) /* Export or import symbols */ { + SymEntry* Sym; + unsigned char AddrSize; + while (1) { - if (Tok != TOK_IDENT) { - ErrorSkip (ERR_IDENT_EXPECTED); - break; + + /* We need an identifier here */ + if (CurTok.Tok != TOK_IDENT) { + ErrorSkip ("Identifier expected"); + return; } - SymFunc (SVal, ZP); - NextTok (); - if (Tok == TOK_COMMA) { + + /* Find the symbol table entry, allocate a new one if necessary */ + Sym = SymFind (CurrentScope, &CurTok.SVal, SYM_ALLOC_NEW); + + /* Skip the name */ + NextTok (); + + /* Get an optional address size */ + AddrSize = OptionalAddrSize (); + if (AddrSize == ADDR_SIZE_DEFAULT) { + AddrSize = DefAddrSize; + } + + /* Call the actual import/export function */ + Func (Sym, AddrSize, Flags); + + /* More symbols? */ + if (CurTok.Tok == TOK_COMMA) { NextTok (); } else { break; @@ -140,13 +251,13 @@ static long IntArg (long Min, long Max) * and return -1 in this case. */ { - if (Tok == TOK_IDENT && strcmp (SVal, "unlimited") == 0) { + if (CurTok.Tok == TOK_IDENT && SB_CompareStr (&CurTok.SVal, "unlimited") == 0) { NextTok (); return -1; } else { long Val = ConstExpression (); if (Val < Min || Val > Max) { - Error (ERR_RANGE); + Error ("Range error"); Val = Min; } return Val; @@ -155,6 +266,36 @@ static long IntArg (long Min, long Max) +static void ConDes (const StrBuf* Name, unsigned Type) +/* Parse remaining line for constructor/destructor of the remaining type */ +{ + long Prio; + + + /* Find the symbol table entry, allocate a new one if necessary */ + SymEntry* Sym = SymFind (CurrentScope, Name, SYM_ALLOC_NEW); + + /* Optional constructor priority */ + if (CurTok.Tok == TOK_COMMA) { + /* Priority value follows */ + NextTok (); + Prio = ConstExpression (); + if (Prio < CD_PRIO_MIN || Prio > CD_PRIO_MAX) { + /* Value out of range */ + Error ("Range error"); + return; + } + } else { + /* Use the default priority value */ + Prio = CD_PRIO_DEF; + } + + /* Define the symbol */ + SymConDes (Sym, ADDR_SIZE_DEFAULT, Type, (unsigned) Prio); +} + + + /*****************************************************************************/ /* Handler functions */ /*****************************************************************************/ @@ -165,10 +306,10 @@ static void DoA16 (void) /* Switch the accu to 16 bit mode (assembler only) */ { if (GetCPU() != CPU_65816) { - Error (ERR_816_MODE_ONLY); + Error ("Command is only valid in 65816 mode"); } else { /* Immidiate mode has two extension bytes */ - ExtBytes [AMI_IMM_ACCU] = 2; + ExtBytes [AM65I_IMM_ACCU] = 2; } } @@ -178,10 +319,10 @@ static void DoA8 (void) /* Switch the accu to 8 bit mode (assembler only) */ { if (GetCPU() != CPU_65816) { - Error (ERR_816_MODE_ONLY); + Error ("Command is only valid in 65816 mode"); } else { /* Immidiate mode has one extension byte */ - ExtBytes [AMI_IMM_ACCU] = 1; + ExtBytes [AM65I_IMM_ACCU] = 1; } } @@ -192,12 +333,12 @@ static void DoAddr (void) { while (1) { if (GetCPU() == CPU_65816) { - EmitWord (ForceWordExpr (Expression ())); + EmitWord (GenWordExpr (Expression ())); } else { /* Do a range check */ EmitWord (Expression ()); } - if (Tok != TOK_COMMA) { + if (CurTok.Tok != TOK_COMMA) { break; } else { NextTok (); @@ -217,17 +358,17 @@ static void DoAlign (void) /* Read the alignment value */ Align = ConstExpression (); if (Align <= 0 || Align > 0x10000) { - ErrorSkip (ERR_RANGE); + ErrorSkip ("Range error"); return; } /* Optional value follows */ - if (Tok == TOK_COMMA) { + if (CurTok.Tok == TOK_COMMA) { NextTok (); Val = ConstExpression (); /* We need a byte value here */ if (!IsByteRange (Val)) { - ErrorSkip (ERR_RANGE); + ErrorSkip ("Range error"); return; } } else { @@ -237,7 +378,7 @@ static void DoAlign (void) /* Check if the alignment is a power of two */ Bit = BitFind (Align); if (Align != (0x01L << Bit)) { - Error (ERR_ALIGN); + Error ("Alignment value must be a power of 2"); } else { SegAlign (Bit, (int) Val); } @@ -249,13 +390,17 @@ static void DoASCIIZ (void) /* Define text with a zero terminator */ { while (1) { - if (Tok != TOK_STRCON) { - ErrorSkip (ERR_STRCON_EXPECTED); + /* Must have a string constant */ + if (CurTok.Tok != TOK_STRCON) { + ErrorSkip ("String constant expected"); return; } - EmitData (SVal, strlen (SVal)); + + /* Translate into target charset and emit */ + TgtTranslateStrBuf (&CurTok.SVal); + EmitStrBuf (&CurTok.SVal); NextTok (); - if (Tok == TOK_COMMA) { + if (CurTok.Tok == TOK_COMMA) { NextTok (); } else { break; @@ -266,6 +411,94 @@ static void DoASCIIZ (void) +static void DoAssert (void) +/* Add an assertion */ +{ + static const char* ActionTab [] = { + "WARN", "WARNING", + "ERROR", + "LDWARN", "LDWARNING", + "LDERROR", + }; + + AssertAction Action; + unsigned Msg; + + /* First we have the expression that has to evaluated */ + ExprNode* Expr = Expression (); + ConsumeComma (); + + /* Action follows */ + if (CurTok.Tok != TOK_IDENT) { + ErrorSkip ("Identifier expected"); + return; + } + switch (GetSubKey (ActionTab, sizeof (ActionTab) / sizeof (ActionTab[0]))) { + + case 0: + case 1: + /* Warning */ + Action = ASSERT_ACT_WARN; + break; + + case 2: + /* Error */ + Action = ASSERT_ACT_ERROR; + break; + + case 3: + case 4: + /* Linker warning */ + Action = ASSERT_ACT_LDWARN; + break; + + case 5: + /* Linker error */ + Action = ASSERT_ACT_LDERROR; + break; + + default: + Error ("Illegal assert action specifier"); + /* Use lderror - there won't be an .o file anyway */ + Action = ASSERT_ACT_LDERROR; + break; + + } + NextTok (); + + /* We can have an optional message. If no message is present, use + * "Assertion failed". + */ + if (CurTok.Tok == TOK_COMMA) { + + /* Skip the comma */ + NextTok (); + + /* Read the message */ + if (CurTok.Tok != TOK_STRCON) { + ErrorSkip ("String constant expected"); + return; + } + + /* Translate the message into a string id. We can then skip the input + * string. + */ + Msg = GetStrBufId (&CurTok.SVal); + NextTok (); + + } else { + + /* Use "Assertion failed" */ + Msg = GetStringId ("Assertion failed"); + + } + + /* Remember the assertion */ + AddAssertion (Expr, (AssertAction) Action, Msg); +} + + + static void DoAutoImport (void) /* Mark unresolved symbols as imported */ { @@ -273,11 +506,25 @@ static void DoAutoImport (void) } +static void DoBankBytes (void) +/* Define bytes, extracting the bank byte from each expression in the list */ +{ + while (1) { + EmitByte (FuncBankByte ()); + if (CurTok.Tok != TOK_COMMA) { + break; + } else { + NextTok (); + } + } +} + + static void DoBss (void) /* Switch to the BSS segment */ { - UseBssSeg (); + UseSeg (&BssSegDef); } @@ -286,20 +533,21 @@ static void DoByte (void) /* Define bytes */ { while (1) { - if (Tok == TOK_STRCON) { - /* A string */ - EmitData (SVal, strlen (SVal)); + if (CurTok.Tok == TOK_STRCON) { + /* A string, translate into target charset and emit */ + TgtTranslateStrBuf (&CurTok.SVal); + EmitStrBuf (&CurTok.SVal); NextTok (); } else { EmitByte (Expression ()); } - if (Tok != TOK_COMMA) { + if (CurTok.Tok != TOK_COMMA) { break; } else { NextTok (); /* Do smart handling of dangling comma */ - if (Tok == TOK_SEP) { - Error (ERR_UNEXPECTED_EOL); + if (CurTok.Tok == TOK_SEP) { + Error ("Unexpected end of line"); break; } } @@ -317,10 +565,118 @@ static void DoCase (void) +static void DoCharMap (void) +/* Allow custome character mappings */ +{ + long Index; + long Code; + + /* Read the index as numerical value */ + Index = ConstExpression (); + if (Index < 0 || Index > 255) { + /* Value out of range */ + ErrorSkip ("Range error"); + return; + } + + /* Comma follows */ + ConsumeComma (); + + /* Read the character code */ + Code = ConstExpression (); + if (Code < 0 || Code > 255) { + /* Value out of range */ + ErrorSkip ("Range error"); + return; + } + + /* Set the character translation */ + TgtTranslateSet ((unsigned) Index, (unsigned char) Code); +} + + + static void DoCode (void) /* Switch to the code segment */ { - UseCodeSeg (); + UseSeg (&CodeSegDef); +} + + + +static void DoConDes (void) +/* Export a symbol as constructor/destructor */ +{ + static const char* Keys[] = { + "CONSTRUCTOR", + "DESTRUCTOR", + "INTERRUPTOR", + }; + StrBuf Name = STATIC_STRBUF_INITIALIZER; + long Type; + + /* Symbol name follows */ + if (CurTok.Tok != TOK_IDENT) { + ErrorSkip ("Identifier expected"); + return; + } + SB_Copy (&Name, &CurTok.SVal); + NextTok (); + + /* Type follows. May be encoded as identifier or numerical */ + ConsumeComma (); + if (CurTok.Tok == TOK_IDENT) { + + /* Map the following keyword to a number, then skip it */ + Type = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0])); + NextTok (); + + /* Check if we got a valid keyword */ + if (Type < 0) { + ErrorSkip ("Syntax error"); + goto ExitPoint; + } + + } else { + + /* Read the type as numerical value */ + Type = ConstExpression (); + if (Type < CD_TYPE_MIN || Type > CD_TYPE_MAX) { + /* Value out of range */ + ErrorSkip ("Range error"); + goto ExitPoint; + } + + } + + /* Parse the remainder of the line and export the symbol */ + ConDes (&Name, (unsigned) Type); + +ExitPoint: + /* Free string memory */ + SB_Done (&Name); +} + + + +static void DoConstructor (void) +/* Export a symbol as constructor */ +{ + StrBuf Name = STATIC_STRBUF_INITIALIZER; + + /* Symbol name follows */ + if (CurTok.Tok != TOK_IDENT) { + ErrorSkip ("Identifier expected"); + return; + } + SB_Copy (&Name, &CurTok.SVal); + NextTok (); + + /* Parse the remainder of the line and export the symbol */ + ConDes (&Name, CD_TYPE_CON); + + /* Free string memory */ + SB_Done (&Name); } @@ -328,7 +684,41 @@ static void DoCode (void) static void DoData (void) /* Switch to the data segment */ { - UseDataSeg (); + UseSeg (&DataSegDef); +} + + + +static void DoDbg (void) +/* Add debug information from high level code */ +{ + static const char* Keys[] = { + "FILE", + "LINE", + "SYM", + }; + int Key; + + + /* We expect a subkey */ + if (CurTok.Tok != TOK_IDENT) { + ErrorSkip ("Identifier expected"); + return; + } + + /* Map the following keyword to a number */ + Key = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0])); + + /* Skip the subkey */ + NextTok (); + + /* Check the key and dispatch to a handler */ + switch (Key) { + case 0: DbgInfoFile (); break; + case 1: DbgInfoLine (); break; + case 2: DbgInfoSym (); break; + default: ErrorSkip ("Syntax error"); break; + } } @@ -337,8 +727,8 @@ static void DoDByt (void) /* Output double bytes */ { while (1) { - EmitWord (SwapExpr (Expression ())); - if (Tok != TOK_COMMA) { + EmitWord (GenSwapExpr (Expression ())); + if (CurTok.Tok != TOK_COMMA) { break; } else { NextTok (); @@ -364,12 +754,48 @@ static void DoDefine (void) +static void DoDelMac (void) +/* Delete a classic macro */ +{ + /* We expect an identifier */ + if (CurTok.Tok != TOK_IDENT) { + ErrorSkip ("Identifier expected"); + } else { + MacUndef (&CurTok.SVal, MAC_STYLE_CLASSIC); + NextTok (); + } +} + + + +static void DoDestructor (void) +/* Export a symbol as destructor */ +{ + StrBuf Name = STATIC_STRBUF_INITIALIZER; + + /* Symbol name follows */ + if (CurTok.Tok != TOK_IDENT) { + ErrorSkip ("Identifier expected"); + return; + } + SB_Copy (&Name, &CurTok.SVal); + NextTok (); + + /* Parse the remainder of the line and export the symbol */ + ConDes (&Name, CD_TYPE_DES); + + /* Free string memory */ + SB_Done (&Name); +} + + + static void DoDWord (void) /* Define dwords */ { while (1) { EmitDWord (Expression ()); - if (Tok != TOK_COMMA) { + if (CurTok.Tok != TOK_COMMA) { break; } else { NextTok (); @@ -383,6 +809,7 @@ static void DoEnd (void) /* End of assembly */ { ForcedEnd = 1; + NextTok (); } @@ -390,18 +817,36 @@ static void DoEnd (void) static void DoEndProc (void) /* Leave a lexical level */ { - SymLeaveLevel (); + if (CurrentScope->Type != SCOPE_SCOPE || CurrentScope->Label == 0) { + /* No local scope */ + ErrorSkip ("No open .PROC"); + } else { + SymLeaveLevel (); + } +} + + + +static void DoEndScope (void) +/* Leave a lexical level */ +{ + if (CurrentScope->Type != SCOPE_SCOPE || CurrentScope->Label != 0) { + /* No local scope */ + ErrorSkip ("No open .SCOPE"); + } else { + SymLeaveLevel (); + } } static void DoError (void) -/* Use error */ +/* User error */ { - if (Tok == TOK_STRCON) { - ErrorSkip (ERR_STRCON_EXPECTED); + if (CurTok.Tok != TOK_STRCON) { + ErrorSkip ("String constant expected"); } else { - Error (ERR_USER, SVal); + Error ("User error: %m%p", &CurTok.SVal); SkipUntilSep (); } } @@ -424,7 +869,7 @@ static void DoExitMacro (void) static void DoExport (void) /* Export a symbol */ { - ExportImport (SymExport, 0); + ExportImport (ExportWithAssign, ADDR_SIZE_DEFAULT, SF_NONE); } @@ -432,7 +877,7 @@ static void DoExport (void) static void DoExportZP (void) /* Export a zeropage symbol */ { - ExportImport (SymExport, 1); + ExportImport (ExportWithAssign, ADDR_SIZE_ZP, SF_NONE); } @@ -442,7 +887,7 @@ static void DoFarAddr (void) { while (1) { EmitFarAddr (Expression ()); - if (Tok != TOK_COMMA) { + if (CurTok.Tok != TOK_COMMA) { break; } else { NextTok (); @@ -452,51 +897,46 @@ static void DoFarAddr (void) -static void DoFeature (void) -/* Switch the Feature option */ +static void DoFatal (void) +/* Fatal user error */ { - int Feature; + if (CurTok.Tok != TOK_STRCON) { + ErrorSkip ("String constant expected"); + } else { + Fatal ("User error: %m%p", &CurTok.SVal); + SkipUntilSep (); + } +} + - static const char* Keys[] = { - "DOLLAR_IS_PC", - "LABELS_WITHOUT_COLONS", - "LOOSE_STRING_TERM", - "AT_IN_IDENTIFIERS", - "DOLLAR_IN_IDENTIFIERS", - }; +static void DoFeature (void) +/* Switch the Feature option */ +{ /* Allow a list of comma separated keywords */ while (1) { /* We expect an identifier */ - if (Tok != TOK_IDENT) { - ErrorSkip (ERR_IDENT_EXPECTED); + if (CurTok.Tok != TOK_IDENT) { + ErrorSkip ("Identifier expected"); return; } - /* Map the keyword to a number */ - Feature = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0])); - if (Feature < 0) { + /* Make the string attribute lower case */ + LocaseSVal (); + + /* Set the feature and check for errors */ + if (SetFeature (&CurTok.SVal) == FEAT_UNKNOWN) { /* Not found */ - ErrorSkip (ERR_ILLEGAL_FEATURE); + ErrorSkip ("Invalid feature: `%m%p'", &CurTok.SVal); return; - } - - /* Skip the keyword */ - NextTok (); - - /* Switch the feature on */ - switch (Feature) { - case 0: DollarIsPC = 1; break; - case 1: NoColonLabels = 1; break; - case 2: LooseStringTerm = 1; break; - case 3: AtInIdents = 1; break; - case 4: DollarInIdents = 1; break; - default: Internal ("Invalid feature: %d", Feature); - } + } else { + /* Skip the keyword */ + NextTok (); + } /* Allow more than one keyword */ - if (Tok == TOK_COMMA) { + if (CurTok.Tok == TOK_COMMA) { NextTok (); } else { break; @@ -512,7 +952,7 @@ static void DoFileOpt (void) long OptNum; /* The option type may be given as a keyword or as a number. */ - if (Tok == TOK_IDENT) { + if (CurTok.Tok == TOK_IDENT) { /* Option given as keyword */ static const char* Keys [] = { @@ -523,7 +963,7 @@ static void DoFileOpt (void) OptNum = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0])); if (OptNum < 0) { /* Not found */ - ErrorSkip (ERR_OPTION_KEY_EXPECTED); + ErrorSkip ("File option keyword expected"); return; } @@ -534,8 +974,8 @@ static void DoFileOpt (void) ConsumeComma (); /* We accept only string options for now */ - if (Tok != TOK_STRCON) { - ErrorSkip (ERR_STRCON_EXPECTED); + if (CurTok.Tok != TOK_STRCON) { + ErrorSkip ("String constant expected"); return; } @@ -544,21 +984,21 @@ static void DoFileOpt (void) case 0: /* Author */ - OptAuthor (SVal); + OptAuthor (&CurTok.SVal); break; case 1: /* Comment */ - OptComment (SVal); + OptComment (&CurTok.SVal); break; case 2: /* Compiler */ - OptCompiler (SVal); + OptCompiler (&CurTok.SVal); break; default: - Internal ("Invalid OptNum: %l", OptNum); + Internal ("Invalid OptNum: %ld", OptNum); } @@ -570,7 +1010,7 @@ static void DoFileOpt (void) /* Option given as number */ OptNum = ConstExpression (); if (!IsByteRange (OptNum)) { - ErrorSkip (ERR_RANGE); + ErrorSkip ("Range error"); return; } @@ -578,13 +1018,13 @@ static void DoFileOpt (void) ConsumeComma (); /* We accept only string options for now */ - if (Tok != TOK_STRCON) { - ErrorSkip (ERR_STRCON_EXPECTED); + if (CurTok.Tok != TOK_STRCON) { + ErrorSkip ("String constant expected"); return; } /* Insert the option */ - OptStr ((unsigned char) OptNum, SVal); + OptStr ((unsigned char) OptNum, &CurTok.SVal); /* Done */ NextTok (); @@ -593,10 +1033,18 @@ static void DoFileOpt (void) +static void DoForceImport (void) +/* Do a forced import on a symbol */ +{ + ExportImport (SymImport, ADDR_SIZE_DEFAULT, SF_FORCED); +} + + + static void DoGlobal (void) /* Declare a global symbol */ { - ExportImport (SymGlobal, 0); + ExportImport (SymGlobal, ADDR_SIZE_DEFAULT, SF_NONE); } @@ -604,7 +1052,21 @@ static void DoGlobal (void) static void DoGlobalZP (void) /* Declare a global zeropage symbol */ { - ExportImport (SymGlobal, 1); + ExportImport (SymGlobal, ADDR_SIZE_ZP, SF_NONE); +} + + +static void DoHiBytes (void) +/* Define bytes, extracting the hi byte from each expression in the list */ +{ + while (1) { + EmitByte (FuncHiByte ()); + if (CurTok.Tok != TOK_COMMA) { + break; + } else { + NextTok (); + } + } } @@ -613,10 +1075,10 @@ static void DoI16 (void) /* Switch the index registers to 16 bit mode (assembler only) */ { if (GetCPU() != CPU_65816) { - Error (ERR_816_MODE_ONLY); + Error ("Command is only valid in 65816 mode"); } else { /* Immidiate mode has two extension bytes */ - ExtBytes [AMI_IMM_INDEX] = 2; + ExtBytes [AM65I_IMM_INDEX] = 2; } } @@ -626,10 +1088,10 @@ static void DoI8 (void) /* Switch the index registers to 16 bit mode (assembler only) */ { if (GetCPU() != CPU_65816) { - Error (ERR_816_MODE_ONLY); + Error ("Command is only valid in 65816 mode"); } else { /* Immidiate mode has one extension byte */ - ExtBytes [AMI_IMM_INDEX] = 1; + ExtBytes [AM65I_IMM_INDEX] = 1; } } @@ -638,7 +1100,7 @@ static void DoI8 (void) static void DoImport (void) /* Import a symbol */ { - ExportImport (SymImport, 0); + ExportImport (SymImport, ADDR_SIZE_DEFAULT, SF_NONE); } @@ -646,7 +1108,7 @@ static void DoImport (void) static void DoImportZP (void) /* Import a zero page symbol */ { - ExportImport (SymImport, 1); + ExportImport (SymImport, ADDR_SIZE_ZP, SF_NONE); } @@ -654,27 +1116,125 @@ static void DoImportZP (void) static void DoIncBin (void) /* Include a binary file */ { + StrBuf Name = STATIC_STRBUF_INITIALIZER; + struct stat StatBuf; + long Start = 0L; + long Count = -1L; + long Size; + FILE* F; + /* Name must follow */ - if (Tok != TOK_STRCON) { - ErrorSkip (ERR_STRCON_EXPECTED); + if (CurTok.Tok != TOK_STRCON) { + ErrorSkip ("String constant expected"); + return; + } + SB_Copy (&Name, &CurTok.SVal); + SB_Terminate (&Name); + NextTok (); + + /* A starting offset may follow */ + if (CurTok.Tok == TOK_COMMA) { + NextTok (); + Start = ConstExpression (); + + /* And a length may follow */ + if (CurTok.Tok == TOK_COMMA) { + NextTok (); + Count = ConstExpression (); + } + + } + + /* Try to open the file */ + F = fopen (SB_GetConstBuf (&Name), "rb"); + if (F == 0) { + + /* Search for the file in the binary include directory */ + char* PathName = SearchFile (BinSearchPath, SB_GetConstBuf (&Name)); + if (PathName == 0 || (F = fopen (PathName, "rb")) == 0) { + /* Not found or cannot open, print an error and bail out */ + ErrorSkip ("Cannot open include file `%m%p': %s", &Name, strerror (errno)); + xfree (PathName); + goto ExitPoint; + } + + /* Remember the new file name */ + SB_CopyStr (&Name, PathName); + + /* Free the allocated memory */ + xfree (PathName); + } + + /* Get the size of the file */ + fseek (F, 0, SEEK_END); + Size = ftell (F); + + /* Stat the file and remember the values. There a race condition here, + * since we cannot use fileno() (non standard identifier in standard + * header file), and therefore not fstat. When using stat with the + * file name, there's a risk that the file was deleted and recreated + * while it was open. Since mtime and size are only used to check + * if a file has changed in the debugger, we will ignore this problem + * here. + */ + SB_Terminate (&Name); + if (stat (SB_GetConstBuf (&Name), &StatBuf) != 0) { + Fatal ("Cannot stat input file `%m%p': %s", &Name, strerror (errno)); + } + + /* Add the file to the input file table */ + AddFile (&Name, FT_BINARY, Size, StatBuf.st_mtime); + + /* If a count was not given, calculate it now */ + if (Count < 0) { + Count = Size - Start; + if (Count < 0) { + /* Nothing to read - flag this as a range error */ + ErrorSkip ("Range error"); + goto Done; + } } else { - /* Try to open the file */ - FILE* F = fopen (SVal, "rb"); - if (F == 0) { - Error (ERR_CANNOT_OPEN_INCLUDE, SVal, strerror (errno)); - } else { - unsigned char Buf [1024]; - size_t Count; - /* Read chunks and insert them into the output */ - while ((Count = fread (Buf, 1, sizeof (Buf), F)) > 0) { - EmitData (Buf, Count); - } - /* Close the file, ignore errors since it's r/o */ - (void) fclose (F); + /* Count was given, check if it is valid */ + if (Start + Count > Size) { + ErrorSkip ("Range error"); + goto Done; + } + } + + /* Seek to the start position */ + fseek (F, Start, SEEK_SET); + + /* Read chunks and insert them into the output */ + while (Count > 0) { + + unsigned char Buf [1024]; + + /* Calculate the number of bytes to read */ + size_t BytesToRead = (Count > (long)sizeof(Buf))? sizeof(Buf) : (size_t) Count; + + /* Read chunk */ + size_t BytesRead = fread (Buf, 1, BytesToRead, F); + if (BytesToRead != BytesRead) { + /* Some sort of error */ + ErrorSkip ("Cannot read from include file `%m%p': %s", + &Name, strerror (errno)); + break; } - /* Skip the name */ - NextTok (); + + /* Insert it into the output */ + EmitData (Buf, BytesRead); + + /* Keep the counters current */ + Count -= BytesRead; } + +Done: + /* Close the file, ignore errors since it's r/o */ + (void) fclose (F); + +ExitPoint: + /* Free string memory */ + SB_Done (&Name); } @@ -682,16 +1242,52 @@ static void DoIncBin (void) static void DoInclude (void) /* Include another file */ { - char Name [MAX_STR_LEN+1]; - /* Name must follow */ - if (Tok != TOK_STRCON) { - ErrorSkip (ERR_STRCON_EXPECTED); + if (CurTok.Tok != TOK_STRCON) { + ErrorSkip ("String constant expected"); } else { - strcpy (Name, SVal); - NextTok (); - NewInputFile (Name); + SB_Terminate (&CurTok.SVal); + if (NewInputFile (SB_GetConstBuf (&CurTok.SVal)) == 0) { + /* Error opening the file, skip remainder of line */ + SkipUntilSep (); + } + } +} + + + +static void DoInterruptor (void) +/* Export a symbol as interruptor */ +{ + StrBuf Name = STATIC_STRBUF_INITIALIZER; + + /* Symbol name follows */ + if (CurTok.Tok != TOK_IDENT) { + ErrorSkip ("Identifier expected"); + return; } + SB_Copy (&Name, &CurTok.SVal); + NextTok (); + + /* Parse the remainder of the line and export the symbol */ + ConDes (&Name, CD_TYPE_INT); + + /* Free string memory */ + SB_Done (&Name); +} + + + +static void DoInvalid (void) +/* Handle a token that is invalid here, since it should have been handled on + * a much lower level of the expression hierarchy. Getting this sort of token + * means that the lower level code has bugs. + * This function differs to DoUnexpected in that the latter may be triggered + * by the user by using keywords in the wrong location. DoUnexpected is not + * an error in the assembler itself, while DoInvalid is. + */ +{ + Internal ("Unexpected token: %m%p", &Keyword); } @@ -721,6 +1317,20 @@ static void DoList (void) +static void DoLoBytes (void) +/* Define bytes, extracting the lo byte from each expression in the list */ +{ + while (1) { + EmitByte (FuncLoByte ()); + if (CurTok.Tok != TOK_COMMA) { + break; + } else { + NextTok (); + } + } +} + + static void DoListBytes (void) /* Set maximum number of bytes to list for one line */ { @@ -732,13 +1342,13 @@ static void DoListBytes (void) static void DoLocalChar (void) /* Define the character that starts local labels */ { - if (Tok != TOK_CHARCON) { - ErrorSkip (ERR_CHARCON_EXPECTED); + if (CurTok.Tok != TOK_CHARCON) { + ErrorSkip ("Character constant expected"); } else { - if (IVal != '@' && IVal != '?') { - Error (ERR_ILLEGAL_LOCALSTART); + if (CurTok.IVal != '@' && CurTok.IVal != '?') { + Error ("Invalid start character for locals"); } else { - LocalStart = (char) IVal; + LocalStart = (char) CurTok.IVal; } NextTok (); } @@ -749,33 +1359,29 @@ static void DoLocalChar (void) static void DoMacPack (void) /* Insert a macro package */ { - /* Macro package names */ - static const char* Keys [] = { - "GENERIC", - "LONGBRANCH", - }; - int Package; /* We expect an identifier */ - if (Tok != TOK_IDENT) { - ErrorSkip (ERR_IDENT_EXPECTED); + if (CurTok.Tok != TOK_IDENT) { + ErrorSkip ("Identifier expected"); return; } - /* Map the keyword to a number */ - Package = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0])); + /* Search for the macro package name */ + LocaseSVal (); + Package = MacPackFind (&CurTok.SVal); if (Package < 0) { /* Not found */ - ErrorSkip (ERR_ILLEGAL_MACPACK); + ErrorSkip ("Invalid macro package"); return; } - /* Skip the package name */ - NextTok (); - - /* Insert the package */ - InsertMacPack (Package); + /* Insert the package. If this fails, skip the remainder of the line to + * avoid additional error messages. + */ + if (MacPackInsert (Package) == 0) { + SkipUntilSep (); + } } @@ -788,20 +1394,10 @@ 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 */ { - UseNullSeg (); + UseSeg (&NullSegDef); } @@ -810,11 +1406,11 @@ static void DoOrg (void) /* Start absolute code */ { long PC = ConstExpression (); - if (PC < 0 || PC > 0xFFFF) { - Error (ERR_RANGE); + if (PC < 0 || PC > 0xFFFFFF) { + Error ("Range error"); return; } - SetAbsPC (PC); + EnterAbsoluteMode (PC); } @@ -822,13 +1418,15 @@ static void DoOrg (void) static void DoOut (void) /* Output a string */ { - if (Tok != TOK_STRCON) { - ErrorSkip (ERR_STRCON_EXPECTED); + if (CurTok.Tok != TOK_STRCON) { + ErrorSkip ("String constant expected"); } else { /* Output the string and be sure to flush the output to keep it in * sync with any error messages if the output is redirected to a file. */ - printf ("%s\n", SVal); + printf ("%.*s\n", + (int) SB_GetLen (&CurTok.SVal), + SB_GetConstBuf (&CurTok.SVal)); fflush (stdout); NextTok (); } @@ -868,15 +1466,121 @@ static void DoPageLength (void) +static void DoPopCPU (void) +/* Pop an old CPU setting from the CPU stack */ +{ + /* Must have a CPU on the stack */ + if (IS_IsEmpty (&CPUStack)) { + ErrorSkip ("CPU stack is empty"); + return; + } + + /* Set the CPU to the value popped from stack */ + SetCPU (IS_Pop (&CPUStack)); +} + + + +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 ("Segment stack is 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 */ { - if (Tok == TOK_IDENT) { - /* The new scope has a name */ - SymDef (SVal, CurrentPC (), IsZPSeg ()); - NextTok (); + StrBuf Name = STATIC_STRBUF_INITIALIZER; + unsigned char AddrSize; + SymEntry* Sym = 0; + + + if (CurTok.Tok == TOK_IDENT) { + + /* The new scope has a name. Remember it. */ + SB_Copy (&Name, &CurTok.SVal); + + /* Search for the symbol, generate a new one if needed */ + Sym = SymFind (CurrentScope, &Name, SYM_ALLOC_NEW); + + /* Skip the scope name */ + NextTok (); + + /* Read an optional address size specifier */ + AddrSize = OptionalAddrSize (); + + /* Mark the symbol as defined */ + SymDef (Sym, GenCurrentPC (), AddrSize, SF_LABEL); + + } else { + + /* A .PROC statement without a name */ + Warning (1, "Unnamed .PROCs are deprecated, please use .SCOPE"); + AnonName (&Name, "PROC"); + AddrSize = ADDR_SIZE_DEFAULT; + + } + + /* Enter a new scope */ + SymEnterLevel (&Name, SCOPE_SCOPE, AddrSize, Sym); + + /* Free memory for Name */ + SB_Done (&Name); +} + + + +static void DoPSC02 (void) +/* Switch to 65SC02 CPU */ +{ + SetCPU (CPU_65SC02); +} + + + +static void DoPushCPU (void) +/* Push the current CPU setting onto the CPU stack */ +{ + /* Can only push a limited size of segments */ + if (IS_IsFull (&CPUStack)) { + ErrorSkip ("CPU stack overflow"); + return; } - SymEnterLevel (); + + /* Get the current segment and push it */ + IS_Push (&CPUStack, GetCPU ()); +} + + + +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 ("Segment stack overflow"); + return; + } + + /* Get the current segment and push it */ + CollAppend (&SegStack, DupSegDef (GetCurrentSegDef ())); } @@ -884,7 +1588,7 @@ static void DoProc (void) static void DoReloc (void) /* Enter relocatable mode */ { - RelocMode = 1; + EnterRelocMode (); } @@ -892,7 +1596,7 @@ static void DoReloc (void) static void DoRepeat (void) /* Repeat some instruction block */ { - ErrorSkip (ERR_NOT_IMPLEMENTED); + ParseRepeat (); } @@ -905,15 +1609,15 @@ static void DoRes (void) Count = ConstExpression (); if (Count > 0xFFFF || Count < 0) { - ErrorSkip (ERR_RANGE); + ErrorSkip ("Range error"); return; } - if (Tok == TOK_COMMA) { + if (CurTok.Tok == TOK_COMMA) { NextTok (); Val = ConstExpression (); /* We need a byte value here */ if (!IsByteRange (Val)) { - ErrorSkip (ERR_RANGE); + ErrorSkip ("Range error"); return; } @@ -933,7 +1637,39 @@ static void DoRes (void) static void DoROData (void) /* Switch to the r/o data segment */ { - UseRODataSeg (); + UseSeg (&RODataSegDef); +} + + + +static void DoScope (void) +/* Start a local scope */ +{ + StrBuf Name = STATIC_STRBUF_INITIALIZER; + unsigned char AddrSize; + + + if (CurTok.Tok == TOK_IDENT) { + + /* The new scope has a name. Remember and skip it. */ + SB_Copy (&Name, &CurTok.SVal); + NextTok (); + + } else { + + /* An unnamed scope */ + AnonName (&Name, "SCOPE"); + + } + + /* Read an optional address size specifier */ + AddrSize = OptionalAddrSize (); + + /* Enter the new scope */ + SymEnterLevel (&Name, SCOPE_SCOPE, AddrSize, 0); + + /* Free memory for Name */ + SB_Done (&Name); } @@ -941,58 +1677,54 @@ static void DoROData (void) static void DoSegment (void) /* Switch to another segment */ { - static const char* AttrTab [] = { - "ZEROPAGE", "DIRECT", - "ABSOLUTE", - "FAR", "LONG" - }; - char Name [sizeof (SVal)]; - int SegType; + StrBuf Name = STATIC_STRBUF_INITIALIZER; + SegDef Def; - if (Tok != TOK_STRCON) { - ErrorSkip (ERR_STRCON_EXPECTED); + if (CurTok.Tok != TOK_STRCON) { + ErrorSkip ("String constant expected"); } else { /* Save the name of the segment and skip it */ - strcpy (Name, SVal); + SB_Copy (&Name, &CurTok.SVal); NextTok (); - /* Check for an optional segment attribute */ - SegType = SEGTYPE_DEFAULT; - if (Tok == TOK_COMMA) { - NextTok (); - if (Tok != TOK_IDENT) { - ErrorSkip (ERR_IDENT_EXPECTED); - } else { - int Attr = GetSubKey (AttrTab, sizeof (AttrTab) / sizeof (AttrTab [0])); - switch (Attr) { - - case 0: - case 1: - /* Zeropage */ - SegType = SEGTYPE_ZP; - break; - - case 2: - /* Absolute */ - SegType = SEGTYPE_ABS; - break; - - case 3: - case 4: - /* Far */ - SegType = SEGTYPE_FAR; - break; - - default: - Error (ERR_ILLEGAL_SEG_ATTR); - } - NextTok (); - } - } + /* Use the name for the segment definition */ + SB_Terminate (&Name); + Def.Name = SB_GetBuf (&Name); + + /* Check for an optional address size modifier */ + Def.AddrSize = OptionalAddrSize (); /* Set the segment */ - UseSeg (Name, SegType); + UseSeg (&Def); + } + + /* Free memory for Name */ + SB_Done (&Name); +} + + + +static void DoSetCPU (void) +/* Switch the CPU instruction set */ +{ + /* We expect an identifier */ + if (CurTok.Tok != TOK_STRCON) { + ErrorSkip ("String constant expected"); + } else { + cpu_t CPU; + + /* Try to find the CPU */ + SB_Terminate (&CurTok.SVal); + CPU = FindCPU (SB_GetConstBuf (&CurTok.SVal)); + + /* Switch to the new CPU */ + SetCPU (CPU); + + /* Skip the identifier. If the CPU switch was successful, the scanner + * will treat the input now correctly for the new CPU. + */ + NextTok (); } } @@ -1014,21 +1746,104 @@ static void DoSunPlus (void) +static void DoTag (void) +/* Allocate space for a struct */ +{ + SymEntry* SizeSym; + long Size; + + /* Read the struct name */ + SymTable* Struct = ParseScopedSymTable (); + + /* Check the supposed struct */ + if (Struct == 0) { + ErrorSkip ("Unknown struct"); + return; + } + if (GetSymTabType (Struct) != SCOPE_STRUCT) { + ErrorSkip ("Not a struct"); + return; + } + + /* Get the symbol that defines the size of the struct */ + SizeSym = GetSizeOfScope (Struct); + + /* Check if it does exist and if its value is known */ + if (SizeSym == 0 || !SymIsConst (SizeSym, &Size)) { + ErrorSkip ("Size of struct/union is unknown"); + return; + } + + /* Optional multiplicator may follow */ + if (CurTok.Tok == TOK_COMMA) { + long Multiplicator; + NextTok (); + Multiplicator = ConstExpression (); + /* Multiplicator must make sense */ + if (Multiplicator <= 0) { + ErrorSkip ("Range error"); + return; + } + Size *= Multiplicator; + } + + /* Emit fill fragments */ + EmitFill (Size); +} + + + +static void DoUnDef (void) +/* Undefine a define style macro */ +{ + /* The function is called with the .UNDEF token in place, because we need + * to disable .define macro expansions before reading the next token. + * Otherwise the name of the macro would be expanded, so we would never + * see it. + */ + DisableDefineStyleMacros (); + NextTok (); + EnableDefineStyleMacros (); + + /* We expect an identifier */ + if (CurTok.Tok != TOK_IDENT) { + ErrorSkip ("Identifier expected"); + } else { + MacUndef (&CurTok.SVal, MAC_STYLE_DEFINE); + NextTok (); + } +} + + + static void DoUnexpected (void) /* Got an unexpected keyword */ { - Error (ERR_UNEXPECTED, Keyword); + Error ("Unexpected `%m%p'", &Keyword); SkipUntilSep (); } +static void DoWarning (void) +/* User warning */ +{ + if (CurTok.Tok != TOK_STRCON) { + ErrorSkip ("String constant expected"); + } else { + Warning (0, "User warning: %m%p", &CurTok.SVal); + SkipUntilSep (); + } +} + + + static void DoWord (void) /* Define words */ { while (1) { EmitWord (Expression ()); - if (Tok != TOK_COMMA) { + if (CurTok.Tok != TOK_COMMA) { break; } else { NextTok (); @@ -1041,13 +1856,13 @@ static void DoWord (void) static void DoZeropage (void) /* Switch to the zeropage segment */ { - UseZeropageSeg (); + UseSeg (&ZeropageSegDef); } /*****************************************************************************/ -/* Table data */ +/* Table data */ /*****************************************************************************/ @@ -1059,11 +1874,11 @@ enum { }; /* Control command table */ -struct CtrlDesc_ { +typedef struct CtrlDesc CtrlDesc; +struct CtrlDesc { unsigned Flags; /* Flags for this directive */ void (*Handler) (void); /* Command handler */ }; -typedef struct CtrlDesc_ CtrlDesc; #define PSEUDO_COUNT (sizeof (CtrlCmdTab) / sizeof (CtrlCmdTab [0])) static CtrlDesc CtrlCmdTab [] = { @@ -1072,39 +1887,60 @@ static CtrlDesc CtrlCmdTab [] = { { ccNone, DoAddr }, /* .ADDR */ { ccNone, DoAlign }, { ccNone, DoASCIIZ }, + { ccNone, DoAssert }, { ccNone, DoAutoImport }, + { ccNone, DoUnexpected }, /* .BANKBYTE */ + { ccNone, DoBankBytes }, { ccNone, DoUnexpected }, /* .BLANK */ { ccNone, DoBss }, { ccNone, DoByte }, { ccNone, DoCase }, + { ccNone, DoCharMap }, { ccNone, DoCode }, { ccNone, DoUnexpected, }, /* .CONCAT */ + { ccNone, DoConDes }, { ccNone, DoUnexpected }, /* .CONST */ + { ccNone, DoConstructor }, { ccNone, DoUnexpected }, /* .CPU */ { ccNone, DoData }, + { ccNone, DoDbg, }, { ccNone, DoDByt }, { ccNone, DoDebugInfo }, { ccNone, DoDefine }, { ccNone, DoUnexpected }, /* .DEFINED */ + { ccNone, DoDelMac }, + { ccNone, DoDestructor }, { ccNone, DoDWord }, { ccKeepToken, DoConditionals }, /* .ELSE */ { ccKeepToken, DoConditionals }, /* .ELSEIF */ - { ccNone, DoEnd }, + { ccKeepToken, DoEnd }, + { ccNone, DoUnexpected }, /* .ENDENUM */ { ccKeepToken, DoConditionals }, /* .ENDIF */ { ccNone, DoUnexpected }, /* .ENDMACRO */ { ccNone, DoEndProc }, { ccNone, DoUnexpected }, /* .ENDREPEAT */ + { ccNone, DoEndScope }, + { ccNone, DoUnexpected }, /* .ENDSTRUCT */ + { ccNone, DoUnexpected }, /* .ENDUNION */ + { ccNone, DoEnum }, { ccNone, DoError }, { ccNone, DoExitMacro }, { ccNone, DoExport }, { ccNone, DoExportZP }, { ccNone, DoFarAddr }, + { ccNone, DoFatal }, { ccNone, DoFeature }, { ccNone, DoFileOpt }, + { ccNone, DoForceImport }, + { ccNone, DoUnexpected }, /* .FORCEWORD */ { ccNone, DoGlobal }, { ccNone, DoGlobalZP }, + { ccNone, DoUnexpected }, /* .HIBYTE */ + { ccNone, DoHiBytes }, + { ccNone, DoUnexpected }, /* .HIWORD */ { ccNone, DoI16 }, { ccNone, DoI8 }, + { ccNone, DoUnexpected }, /* .IDENT */ { ccKeepToken, DoConditionals }, /* .IF */ { ccKeepToken, DoConditionals }, /* .IFBLANK */ { ccKeepToken, DoConditionals }, /* .IFCONST */ @@ -1116,71 +1952,92 @@ static CtrlDesc CtrlCmdTab [] = { { ccKeepToken, DoConditionals }, /* .IFP02 */ { ccKeepToken, DoConditionals }, /* .IFP816 */ { ccKeepToken, DoConditionals }, /* .IFPC02 */ - { ccKeepToken, DoConditionals }, /* .IFREF */ + { ccKeepToken, DoConditionals }, /* .IFPSC02 */ + { ccKeepToken, DoConditionals }, /* .IFREF */ { ccNone, DoImport }, { ccNone, DoImportZP }, { ccNone, DoIncBin }, { ccNone, DoInclude }, + { ccNone, DoInterruptor }, + { ccNone, DoInvalid }, /* .LEFT */ { ccNone, DoLineCont }, { ccNone, DoList }, { ccNone, DoListBytes }, + { ccNone, DoUnexpected }, /* .LOBYTE */ + { ccNone, DoLoBytes }, { ccNone, DoUnexpected }, /* .LOCAL */ { ccNone, DoLocalChar }, + { ccNone, DoUnexpected }, /* .LOWORD */ { ccNone, DoMacPack }, { ccNone, DoMacro }, { ccNone, DoUnexpected }, /* .MATCH */ - { ccNone, DoMid }, + { ccNone, DoUnexpected }, /* .MAX */ + { ccNone, DoInvalid }, /* .MID */ + { ccNone, DoUnexpected }, /* .MIN */ { ccNone, DoNull }, - { ccNone, DoOrg }, + { ccNone, DoOrg }, { ccNone, DoOut }, { ccNone, DoP02 }, { ccNone, DoP816 }, { ccNone, DoPageLength }, - { ccNone, DoUnexpected }, /* .PARAMCOUNT */ + { ccNone, DoUnexpected }, /* .PARAMCOUNT */ { ccNone, DoPC02 }, + { ccNone, DoPopCPU }, + { ccNone, DoPopSeg }, { ccNone, DoProc }, - { ccNone, DoUnexpected }, /* .REFERENCED */ + { ccNone, DoPSC02 }, + { ccNone, DoPushCPU }, + { ccNone, DoPushSeg }, + { ccNone, DoUnexpected }, /* .REFERENCED */ { ccNone, DoReloc }, { ccNone, DoRepeat }, { ccNone, DoRes }, + { ccNone, DoInvalid }, /* .RIGHT */ { ccNone, DoROData }, + { ccNone, DoScope }, { ccNone, DoSegment }, + { ccNone, DoUnexpected }, /* .SET */ + { ccNone, DoSetCPU }, + { ccNone, DoUnexpected }, /* .SIZEOF */ { ccNone, DoSmart }, - { ccNone, DoUnexpected }, /* .STRING */ + { ccNone, DoUnexpected }, /* .SPRINTF */ + { ccNone, DoUnexpected }, /* .STRAT */ + { ccNone, DoUnexpected }, /* .STRING */ + { ccNone, DoUnexpected }, /* .STRLEN */ + { ccNone, DoStruct }, { ccNone, DoSunPlus }, - { ccNone, DoWord }, - { ccNone, DoUnexpected }, /* .XMATCH */ + { ccNone, DoTag }, + { ccNone, DoUnexpected }, /* .TCOUNT */ + { ccNone, DoUnexpected }, /* .TIME */ + { ccKeepToken, DoUnDef }, + { ccNone, DoUnion }, + { ccNone, DoUnexpected }, /* .VERSION */ + { ccNone, DoWarning }, + { ccNone, DoWord }, + { ccNone, DoUnexpected }, /* .XMATCH */ { ccNone, DoZeropage }, }; /*****************************************************************************/ -/* Code */ +/* Code */ /*****************************************************************************/ -int TokIsPseudo (unsigned Tok) -/* Return true if the given token is a pseudo instruction token */ -{ - return (Tok >= TOK_FIRSTPSEUDO && Tok <= TOK_LASTPSEUDO); -} - - - void HandlePseudo (void) /* Handle a pseudo instruction */ { CtrlDesc* D; /* Calculate the index into the table */ - unsigned Index = Tok - TOK_FIRSTPSEUDO; + unsigned Index = CurTok.Tok - TOK_FIRSTPSEUDO; /* Safety check */ if (PSEUDO_COUNT != (TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1)) { Internal ("Pseudo mismatch: PSEUDO_COUNT = %u, actual count = %u\n", - PSEUDO_COUNT, TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1); + (unsigned) PSEUDO_COUNT, TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1); } CHECK (Index < PSEUDO_COUNT); @@ -1189,7 +2046,7 @@ void HandlePseudo (void) /* Remember the instruction, then skip it if needed */ if ((D->Flags & ccKeepToken) == 0) { - strcpy (Keyword+1, SVal); + SB_Copy (&Keyword, &CurTok.SVal); NextTok (); } @@ -1199,3 +2056,16 @@ void HandlePseudo (void) +void CheckPseudo (void) +/* Check if the stacks are empty at end of assembly */ +{ + if (CollCount (&SegStack) != 0) { + Warning (1, "Segment stack is not empty"); + } + if (!IS_IsEmpty (&CPUStack)) { + Warning (1, "CPU stack is not empty"); + } +} + + +