X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fca65%2Fpseudo.c;h=3a2e391d39796aa600a99d896c3c4ff0a46b5c12;hb=115db5974355a73ae486019c78779d24049e6513;hp=f1ed0a139cb3d380decd145222572ad094f55683;hpb=8fc78c2c8de45065836c92208830cf4f56afabc8;p=cc65 diff --git a/src/ca65/pseudo.c b/src/ca65/pseudo.c index f1ed0a139..3a2e391d3 100644 --- a/src/ca65/pseudo.c +++ b/src/ca65/pseudo.c @@ -6,10 +6,10 @@ /* */ /* */ /* */ -/* (C) 1998-2002 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,21 +38,32 @@ #include #include #include +#include /* EMX needs this */ +#include /* common */ +#include "assertion.h" #include "bitops.h" #include "cddefs.h" -#include "check.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" @@ -60,9 +71,14 @@ #include "nexttok.h" #include "objcode.h" #include "options.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" -#include "pseudo.h" @@ -73,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; @@ -103,6 +126,27 @@ static void DoInvalid (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 */ { @@ -111,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 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 (*SymFunc) (const char*, int), int ZP) +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; @@ -159,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; @@ -174,19 +266,23 @@ static long IntArg (long Min, long Max) -static void ConDes (const char* Name, unsigned Type) +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 (Tok == TOK_COMMA) { + 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 (ERR_RANGE); + Error ("Range error"); return; } } else { @@ -195,7 +291,7 @@ static void ConDes (const char* Name, unsigned Type) } /* Define the symbol */ - SymConDes (Name, Type, (unsigned) Prio); + SymConDes (Sym, ADDR_SIZE_DEFAULT, Type, (unsigned) Prio); } @@ -210,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; } } @@ -223,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; } } @@ -237,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 (); @@ -262,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 { @@ -282,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); } @@ -293,23 +389,18 @@ static void DoAlign (void) static void DoASCIIZ (void) /* Define text with a zero terminator */ { - unsigned Len; - while (1) { /* Must have a string constant */ - if (Tok != TOK_STRCON) { - ErrorSkip (ERR_STRCON_EXPECTED); + if (CurTok.Tok != TOK_STRCON) { + ErrorSkip ("String constant expected"); return; } - /* Get the length of the string constant */ - Len = strlen (SVal); - /* Translate into target charset and emit */ - TgtTranslateBuf (SVal, Len); - EmitData ((unsigned char*) SVal, Len); + TgtTranslateStrBuf (&CurTok.SVal); + EmitStrBuf (&CurTok.SVal); NextTok (); - if (Tok == TOK_COMMA) { + if (CurTok.Tok == TOK_COMMA) { NextTok (); } else { break; @@ -320,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 */ { @@ -327,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); } @@ -340,22 +533,21 @@ static void DoByte (void) /* Define bytes */ { while (1) { - if (Tok == TOK_STRCON) { + if (CurTok.Tok == TOK_STRCON) { /* A string, translate into target charset and emit */ - unsigned Len = strlen (SVal); - TgtTranslateBuf (SVal, Len); - EmitData ((unsigned char*) SVal, Len); + 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; } } @@ -381,9 +573,9 @@ static void DoCharMap (void) /* Read the index as numerical value */ Index = ConstExpression (); - if (Index < 1 || Index > 255) { + if (Index < 0 || Index > 255) { /* Value out of range */ - ErrorSkip (ERR_RANGE); + ErrorSkip ("Range error"); return; } @@ -392,10 +584,10 @@ static void DoCharMap (void) /* Read the character code */ Code = ConstExpression (); - if (Code < 1 || Code > 255) { - /* Value out of range */ - ErrorSkip (ERR_RANGE); - return; + if (Code < 0 || Code > 255) { + /* Value out of range */ + ErrorSkip ("Range error"); + return; } /* Set the character translation */ @@ -407,7 +599,7 @@ static void DoCharMap (void) static void DoCode (void) /* Switch to the code segment */ { - UseCodeSeg (); + UseSeg (&CodeSegDef); } @@ -418,21 +610,22 @@ static void DoConDes (void) static const char* Keys[] = { "CONSTRUCTOR", "DESTRUCTOR", + "INTERRUPTOR", }; - char Name [sizeof (SVal)]; + StrBuf Name = STATIC_STRBUF_INITIALIZER; long Type; /* Symbol name follows */ - if (Tok != TOK_IDENT) { - ErrorSkip (ERR_IDENT_EXPECTED); + if (CurTok.Tok != TOK_IDENT) { + ErrorSkip ("Identifier expected"); return; } - strcpy (Name, SVal); + SB_Copy (&Name, &CurTok.SVal); NextTok (); /* Type follows. May be encoded as identifier or numerical */ ConsumeComma (); - if (Tok == TOK_IDENT) { + if (CurTok.Tok == TOK_IDENT) { /* Map the following keyword to a number, then skip it */ Type = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0])); @@ -440,9 +633,8 @@ static void DoConDes (void) /* Check if we got a valid keyword */ if (Type < 0) { - Error (ERR_SYNTAX); - SkipUntilSep (); - return; + ErrorSkip ("Syntax error"); + goto ExitPoint; } } else { @@ -451,14 +643,18 @@ static void DoConDes (void) Type = ConstExpression (); if (Type < CD_TYPE_MIN || Type > CD_TYPE_MAX) { /* Value out of range */ - Error (ERR_RANGE); - return; + ErrorSkip ("Range error"); + goto ExitPoint; } } /* Parse the remainder of the line and export the symbol */ - ConDes (Name, (unsigned) Type); + ConDes (&Name, (unsigned) Type); + +ExitPoint: + /* Free string memory */ + SB_Done (&Name); } @@ -466,18 +662,21 @@ static void DoConDes (void) static void DoConstructor (void) /* Export a symbol as constructor */ { - char Name [sizeof (SVal)]; + StrBuf Name = STATIC_STRBUF_INITIALIZER; /* Symbol name follows */ - if (Tok != TOK_IDENT) { - ErrorSkip (ERR_IDENT_EXPECTED); + if (CurTok.Tok != TOK_IDENT) { + ErrorSkip ("Identifier expected"); return; } - strcpy (Name, SVal); + SB_Copy (&Name, &CurTok.SVal); NextTok (); /* Parse the remainder of the line and export the symbol */ - ConDes (Name, CD_TYPE_CON); + ConDes (&Name, CD_TYPE_CON); + + /* Free string memory */ + SB_Done (&Name); } @@ -485,7 +684,7 @@ static void DoConstructor (void) static void DoData (void) /* Switch to the data segment */ { - UseDataSeg (); + UseSeg (&DataSegDef); } @@ -502,8 +701,8 @@ static void DoDbg (void) /* We expect a subkey */ - if (Tok != TOK_IDENT) { - ErrorSkip (ERR_IDENT_EXPECTED); + if (CurTok.Tok != TOK_IDENT) { + ErrorSkip ("Identifier expected"); return; } @@ -518,7 +717,7 @@ static void DoDbg (void) case 0: DbgInfoFile (); break; case 1: DbgInfoLine (); break; case 2: DbgInfoSym (); break; - default: ErrorSkip (ERR_SYNTAX); break; + default: ErrorSkip ("Syntax error"); break; } } @@ -528,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 (); @@ -555,21 +754,38 @@ 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 */ { - char Name [sizeof (SVal)]; + StrBuf Name = STATIC_STRBUF_INITIALIZER; /* Symbol name follows */ - if (Tok != TOK_IDENT) { - ErrorSkip (ERR_IDENT_EXPECTED); + if (CurTok.Tok != TOK_IDENT) { + ErrorSkip ("Identifier expected"); return; } - strcpy (Name, SVal); + SB_Copy (&Name, &CurTok.SVal); NextTok (); /* Parse the remainder of the line and export the symbol */ - ConDes (Name, CD_TYPE_DES); + ConDes (&Name, CD_TYPE_DES); + + /* Free string memory */ + SB_Done (&Name); } @@ -579,7 +795,7 @@ static void DoDWord (void) { while (1) { EmitDWord (Expression ()); - if (Tok != TOK_COMMA) { + if (CurTok.Tok != TOK_COMMA) { break; } else { NextTok (); @@ -593,6 +809,7 @@ static void DoEnd (void) /* End of assembly */ { ForcedEnd = 1; + NextTok (); } @@ -600,7 +817,25 @@ 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 (); + } } @@ -608,10 +843,10 @@ static void DoEndProc (void) static void DoError (void) /* 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 (); } } @@ -634,7 +869,7 @@ static void DoExitMacro (void) static void DoExport (void) /* Export a symbol */ { - ExportImport (SymExport, 0); + ExportImport (ExportWithAssign, ADDR_SIZE_DEFAULT, SF_NONE); } @@ -642,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); } @@ -652,7 +887,7 @@ static void DoFarAddr (void) { while (1) { EmitFarAddr (Expression ()); - if (Tok != TOK_COMMA) { + if (CurTok.Tok != TOK_COMMA) { break; } else { NextTok (); @@ -662,6 +897,19 @@ static void DoFarAddr (void) +static void DoFatal (void) +/* Fatal user error */ +{ + if (CurTok.Tok != TOK_STRCON) { + ErrorSkip ("String constant expected"); + } else { + Fatal ("User error: %m%p", &CurTok.SVal); + SkipUntilSep (); + } +} + + + static void DoFeature (void) /* Switch the Feature option */ { @@ -669,8 +917,8 @@ static void DoFeature (void) while (1) { /* We expect an identifier */ - if (Tok != TOK_IDENT) { - ErrorSkip (ERR_IDENT_EXPECTED); + if (CurTok.Tok != TOK_IDENT) { + ErrorSkip ("Identifier expected"); return; } @@ -678,9 +926,9 @@ static void DoFeature (void) LocaseSVal (); /* Set the feature and check for errors */ - if (SetFeature (SVal) == FEAT_UNKNOWN) { + if (SetFeature (&CurTok.SVal) == FEAT_UNKNOWN) { /* Not found */ - ErrorSkip (ERR_ILLEGAL_FEATURE); + ErrorSkip ("Invalid feature: `%m%p'", &CurTok.SVal); return; } else { /* Skip the keyword */ @@ -688,7 +936,7 @@ static void DoFeature (void) } /* Allow more than one keyword */ - if (Tok == TOK_COMMA) { + if (CurTok.Tok == TOK_COMMA) { NextTok (); } else { break; @@ -704,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 [] = { @@ -715,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; } @@ -726,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; } @@ -736,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); } @@ -762,7 +1010,7 @@ static void DoFileOpt (void) /* Option given as number */ OptNum = ConstExpression (); if (!IsByteRange (OptNum)) { - ErrorSkip (ERR_RANGE); + ErrorSkip ("Range error"); return; } @@ -770,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 (); @@ -785,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); } @@ -796,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 (); + } + } } @@ -805,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; } } @@ -818,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; } } @@ -830,7 +1100,7 @@ static void DoI8 (void) static void DoImport (void) /* Import a symbol */ { - ExportImport (SymImport, 0); + ExportImport (SymImport, ADDR_SIZE_DEFAULT, SF_NONE); } @@ -838,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); } @@ -846,27 +1116,29 @@ static void DoImportZP (void) static void DoIncBin (void) /* Include a binary file */ { - char Name [sizeof (SVal)]; + 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; } - strcpy (Name, SVal); + SB_Copy (&Name, &CurTok.SVal); + SB_Terminate (&Name); NextTok (); /* A starting offset may follow */ - if (Tok == TOK_COMMA) { + if (CurTok.Tok == TOK_COMMA) { NextTok (); Start = ConstExpression (); /* And a length may follow */ - if (Tok == TOK_COMMA) { + if (CurTok.Tok == TOK_COMMA) { NextTok (); Count = ConstExpression (); } @@ -874,30 +1146,59 @@ static void DoIncBin (void) } /* Try to open the file */ - F = fopen (Name, "rb"); + F = fopen (SB_GetConstBuf (&Name), "rb"); if (F == 0) { - ErrorSkip (ERR_CANNOT_OPEN_INCLUDE, Name, strerror (errno)); - return; + + /* 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 (ERR_RANGE); - goto Done; - } + Count = Size - Start; + if (Count < 0) { + /* Nothing to read - flag this as a range error */ + ErrorSkip ("Range error"); + goto Done; + } } else { - /* Count was given, check if it is valid */ - if (Start + Count > Size) { - ErrorSkip (ERR_RANGE); - goto Done; - } + /* Count was given, check if it is valid */ + if (Start + Count > Size) { + ErrorSkip ("Range error"); + goto Done; + } } /* Seek to the start position */ @@ -906,16 +1207,17 @@ static void DoIncBin (void) /* Read chunks and insert them into the output */ while (Count > 0) { - unsigned char Buf [1024]; + unsigned char Buf [1024]; - /* Calculate the number of bytes to read */ + /* Calculate the number of bytes to read */ size_t BytesToRead = (Count > (long)sizeof(Buf))? sizeof(Buf) : (size_t) Count; - /* Read chunk */ + /* Read chunk */ size_t BytesRead = fread (Buf, 1, BytesToRead, F); if (BytesToRead != BytesRead) { /* Some sort of error */ - ErrorSkip (ERR_CANNOT_READ_INCLUDE, Name, strerror (errno)); + ErrorSkip ("Cannot read from include file `%m%p': %s", + &Name, strerror (errno)); break; } @@ -929,6 +1231,10 @@ static void DoIncBin (void) Done: /* Close the file, ignore errors since it's r/o */ (void) fclose (F); + +ExitPoint: + /* Free string memory */ + SB_Done (&Name); } @@ -936,20 +1242,42 @@ Done: 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 @@ -959,7 +1287,7 @@ static void DoInvalid (void) * an error in the assembler itself, while DoInvalid is. */ { - Internal ("Unexpected token: %s", Keyword); + Internal ("Unexpected token: %m%p", &Keyword); } @@ -989,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 */ { @@ -1000,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 (); } @@ -1017,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 (); + } } @@ -1059,7 +1397,7 @@ static void DoMacro (void) static void DoNull (void) /* Switch to the NULL segment */ { - UseNullSeg (); + UseSeg (&NullSegDef); } @@ -1069,10 +1407,10 @@ static void DoOrg (void) { long PC = ConstExpression (); if (PC < 0 || PC > 0xFFFFFF) { - Error (ERR_RANGE); + Error ("Range error"); return; } - SetAbsPC (PC); + EnterAbsoluteMode (PC); } @@ -1080,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 (); } @@ -1126,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 (), 1); - 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; + } - SymEnterLevel (); + + /* 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; + } + + /* 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 ())); } @@ -1142,7 +1588,7 @@ static void DoProc (void) static void DoReloc (void) /* Enter relocatable mode */ { - RelocMode = 1; + EnterRelocMode (); } @@ -1163,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; } @@ -1191,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); } @@ -1199,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 (); } } @@ -1272,10 +1746,80 @@ 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 (); } @@ -1284,10 +1828,10 @@ static void DoUnexpected (void) static void DoWarning (void) /* User warning */ { - if (Tok != TOK_STRCON) { - ErrorSkip (ERR_STRCON_EXPECTED); + if (CurTok.Tok != TOK_STRCON) { + ErrorSkip ("String constant expected"); } else { - Warning (WARN_USER, SVal); + Warning (0, "User warning: %m%p", &CurTok.SVal); SkipUntilSep (); } } @@ -1299,7 +1843,7 @@ static void DoWord (void) { while (1) { EmitWord (Expression ()); - if (Tok != TOK_COMMA) { + if (CurTok.Tok != TOK_COMMA) { break; } else { NextTok (); @@ -1312,13 +1856,13 @@ static void DoWord (void) static void DoZeropage (void) /* Switch to the zeropage segment */ { - UseZeropageSeg (); + UseSeg (&ZeropageSegDef); } /*****************************************************************************/ -/* Table data */ +/* Table data */ /*****************************************************************************/ @@ -1330,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 [] = { @@ -1343,7 +1887,10 @@ 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 }, @@ -1361,27 +1908,39 @@ static CtrlDesc CtrlCmdTab [] = { { 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 */ @@ -1393,78 +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, 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 }, /* .STRAT */ - { ccNone, DoUnexpected }, /* .STRING */ - { ccNone, DoUnexpected }, /* .STRLEN */ + { ccNone, DoUnexpected }, /* .SPRINTF */ + { ccNone, DoUnexpected }, /* .STRAT */ + { ccNone, DoUnexpected }, /* .STRING */ + { ccNone, DoUnexpected }, /* .STRLEN */ + { ccNone, DoStruct }, { ccNone, DoSunPlus }, - { ccNone, DoUnexpected }, /* .TCOUNT */ - { ccNone, DoUnexpected }, /* .TIME */ + { ccNone, DoTag }, + { ccNone, DoUnexpected }, /* .TCOUNT */ + { ccNone, DoUnexpected }, /* .TIME */ + { ccKeepToken, DoUnDef }, + { ccNone, DoUnion }, + { ccNone, DoUnexpected }, /* .VERSION */ { ccNone, DoWarning }, - { ccNone, DoWord }, - { ccNone, DoUnexpected }, /* .XMATCH */ + { 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); @@ -1473,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 (); } @@ -1483,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"); + } +} + + +