/*****************************************************************************/
/* */
-/* pseudo.c */
+/* pseudo.c */
/* */
-/* Pseudo instructions for the ca65 macroassembler */
+/* Pseudo instructions for the ca65 macroassembler */
/* */
/* */
/* */
-/* (C) 1998-2003 Ullrich von Bassewitz */
-/* Römerstraße 52 */
-/* D-70794 Filderstadt */
-/* EMail: uz@cc65.org */
+/* (C) 1998-2012, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
#include <errno.h>
/* common */
-#include "assertdefs.h"
+#include "alignment.h"
+#include "assertion.h"
#include "bitops.h"
#include "cddefs.h"
#include "coll.h"
+#include "filestat.h"
+#include "gentype.h"
+#include "intstack.h"
+#include "scopedefs.h"
#include "symdefs.h"
#include "tgttrans.h"
#include "xmalloc.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"
#include "macro.h"
#include "nexttok.h"
#include "objcode.h"
#include "pseudo.h"
#include "repeat.h"
#include "segment.h"
+#include "sizeof.h"
+#include "span.h"
#include "spool.h"
+#include "struct.h"
+#include "symbol.h"
#include "symtab.h"
/*****************************************************************************/
-/* Data */
+/* Data */
/*****************************************************************************/
/* 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
/*****************************************************************************/
-/* Forwards */
+/* Forwards */
/*****************************************************************************/
/*****************************************************************************/
-/* Helper functions */
+/* Helper functions */
/*****************************************************************************/
*/
{
unsigned AddrSize = ADDR_SIZE_DEFAULT;
- if (Tok == TOK_COLON) {
+ 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;
/* Read a on/off/+/- option and set flag accordingly */
{
static const char* Keys[] = {
- "OFF",
- "ON",
+ "OFF",
+ "ON",
};
- if (Tok == TOK_PLUS) {
- *Flag = 1;
- NextTok ();
- } else if (Tok == TOK_MINUS) {
- *Flag = 0;
- NextTok ();
- } else if (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 ("`on' or `off' expected"); break;
- }
- } else if (TokIsSep (Tok)) {
- /* Without anything assume switch on */
- *Flag = 1;
+ if (CurTok.Tok == TOK_PLUS) {
+ *Flag = 1;
+ NextTok ();
+ } else if (CurTok.Tok == TOK_MINUS) {
+ *Flag = 0;
+ NextTok ();
+ } 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 ("`on' or `off' expected"); break;
+ }
+ } else if (TokIsSep (CurTok.Tok)) {
+ /* Without anything assume switch on */
+ *Flag = 1;
} else {
- ErrorSkip ("`on' or `off' 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 (*Func) (SymEntry*, unsigned char, unsigned),
unsigned char DefAddrSize, unsigned Flags)
/* Export or import symbols */
while (1) {
/* We need an identifier here */
- if (Tok != TOK_IDENT) {
- ErrorSkip ("Identifier expected");
- return;
- }
+ if (CurTok.Tok != TOK_IDENT) {
+ ErrorSkip ("Identifier expected");
+ return;
+ }
/* Find the symbol table entry, allocate a new one if necessary */
- Sym = SymFind (CurrentScope, SVal, SYM_ALLOC_NEW);
+ Sym = SymFind (CurrentScope, &CurTok.SVal, SYM_ALLOC_NEW);
/* Skip the name */
NextTok ();
Func (Sym, AddrSize, Flags);
/* More symbols? */
- if (Tok == TOK_COMMA) {
- NextTok ();
- } else {
- break;
- }
+ if (CurTok.Tok == TOK_COMMA) {
+ NextTok ();
+ } else {
+ break;
+ }
}
}
* and return -1 in this case.
*/
{
- if (Tok == TOK_IDENT && strcmp (SVal, "unlimited") == 0) {
- NextTok ();
- return -1;
+ if (CurTok.Tok == TOK_IDENT && SB_CompareStr (&CurTok.SVal, "unlimited") == 0) {
+ NextTok ();
+ return -1;
} else {
- long Val = ConstExpression ();
- if (Val < Min || Val > Max) {
- Error ("Range error");
- Val = Min;
- }
- return Val;
+ long Val = ConstExpression ();
+ if (Val < Min || Val > Max) {
+ Error ("Range error");
+ Val = Min;
+ }
+ return Val;
}
}
-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;
SymEntry* Sym = SymFind (CurrentScope, Name, SYM_ALLOC_NEW);
/* Optional constructor priority */
- if (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;
- }
+ 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;
+ /* Use the default priority value */
+ Prio = CD_PRIO_DEF;
}
/* Define the symbol */
+static StrBuf* GenArrayType (StrBuf* Type, unsigned SpanSize,
+ const char* ElementType,
+ unsigned ElementTypeLen)
+/* Create an array (or single data) of the given type. SpanSize is the size
+ * of the span, ElementType is a string that encodes the element data type.
+ * The function returns Type.
+ */
+{
+ /* Get the size of the element type */
+ unsigned ElementSize = GT_GET_SIZE (ElementType[0]);
+
+ /* Get the number of array elements */
+ unsigned ElementCount = SpanSize / ElementSize;
+
+ /* The span size must be divideable by the element size */
+ CHECK ((SpanSize % ElementSize) == 0);
+
+ /* Encode the array */
+ GT_AddArray (Type, ElementCount);
+ SB_AppendBuf (Type, ElementType, ElementTypeLen);
+
+ /* Return the pointer to the created array type */
+ return Type;
+}
+
+
+
/*****************************************************************************/
-/* Handler functions */
+/* Handler functions */
/*****************************************************************************/
/* Switch the accu to 16 bit mode (assembler only) */
{
if (GetCPU() != CPU_65816) {
- Error ("Command is only valid in 65816 mode");
+ Error ("Command is only valid in 65816 mode");
} else {
- /* Immidiate mode has two extension bytes */
- ExtBytes [AMI_IMM_ACCU] = 2;
+ /* Immidiate mode has two extension bytes */
+ ExtBytes [AM65I_IMM_ACCU] = 2;
}
}
/* Switch the accu to 8 bit mode (assembler only) */
{
if (GetCPU() != CPU_65816) {
- Error ("Command is only valid in 65816 mode");
+ Error ("Command is only valid in 65816 mode");
} else {
- /* Immidiate mode has one extension byte */
- ExtBytes [AMI_IMM_ACCU] = 1;
+ /* Immidiate mode has one extension byte */
+ ExtBytes [AM65I_IMM_ACCU] = 1;
}
}
static void DoAddr (void)
/* Define addresses */
{
+ /* Element type for the generated array */
+ static const char EType[2] = { GT_PTR, GT_VOID };
+
+ /* Record type information */
+ Span* S = OpenSpan ();
+ StrBuf Type = STATIC_STRBUF_INITIALIZER;
+
+ /* Parse arguments */
while (1) {
- if (GetCPU() == CPU_65816) {
- EmitWord (GenWordExpr (Expression ()));
- } else {
- /* Do a range check */
- EmitWord (Expression ());
- }
- if (Tok != TOK_COMMA) {
- break;
- } else {
- NextTok ();
- }
+ ExprNode* Expr = Expression ();
+ if (GetCPU () == CPU_65816 || ForceRange) {
+ /* Do a range check */
+ Expr = GenWordExpr (Expr);
+ }
+ EmitWord (Expr);
+ if (CurTok.Tok != TOK_COMMA) {
+ break;
+ } else {
+ NextTok ();
+ }
}
+
+ /* Close the span, then add type information to it */
+ S = CloseSpan (S);
+ SetSpanType (S, GenArrayType (&Type, GetSpanSize (S), EType, sizeof (EType)));
+
+ /* Free the strings */
+ SB_Done (&Type);
}
static void DoAlign (void)
/* Align the PC to some boundary */
{
- long Val;
- long Align;
- unsigned Bit;
+ long FillVal;
+ long Alignment;
/* Read the alignment value */
- Align = ConstExpression ();
- if (Align <= 0 || Align > 0x10000) {
- ErrorSkip ("Range error");
- return;
+ Alignment = ConstExpression ();
+ if (Alignment <= 0 || (unsigned long) Alignment > MAX_ALIGNMENT) {
+ ErrorSkip ("Range error");
+ return;
}
/* Optional value follows */
- if (Tok == TOK_COMMA) {
- NextTok ();
- Val = ConstExpression ();
- /* We need a byte value here */
- if (!IsByteRange (Val)) {
- ErrorSkip ("Range error");
- return;
- }
+ if (CurTok.Tok == TOK_COMMA) {
+ NextTok ();
+ FillVal = ConstExpression ();
+ /* We need a byte value here */
+ if (!IsByteRange (FillVal)) {
+ ErrorSkip ("Range error");
+ return;
+ }
} else {
- Val = -1;
+ FillVal = -1;
}
- /* Check if the alignment is a power of two */
- Bit = BitFind (Align);
- if (Align != (0x01L << Bit)) {
- Error ("Alignment value must be a power of 2");
- } else {
- SegAlign (Bit, (int) Val);
- }
+ /* Generate the alignment */
+ SegAlign (Alignment, (int) FillVal);
}
static void DoASCIIZ (void)
/* Define text with a zero terminator */
{
- unsigned Len;
-
while (1) {
- /* Must have a string constant */
- if (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);
- NextTok ();
- if (Tok == TOK_COMMA) {
- NextTok ();
- } else {
- break;
- }
+ /* Must have a string constant */
+ if (CurTok.Tok != TOK_STRCON) {
+ ErrorSkip ("String constant expected");
+ return;
+ }
+
+ /* Translate into target charset and emit */
+ TgtTranslateStrBuf (&CurTok.SVal);
+ EmitStrBuf (&CurTok.SVal);
+ NextTok ();
+ if (CurTok.Tok == TOK_COMMA) {
+ NextTok ();
+ } else {
+ break;
+ }
}
Emit0 (0);
}
/* Add an assertion */
{
static const char* ActionTab [] = {
- "WARN", "WARNING",
- "ERROR"
+ "WARN", "WARNING",
+ "ERROR",
+ "LDWARN", "LDWARNING",
+ "LDERROR",
};
- int Action;
-
+ AssertAction Action;
+ unsigned Msg;
/* First we have the expression that has to evaluated */
ExprNode* Expr = Expression ();
ConsumeComma ();
/* Action follows */
- if (Tok != TOK_IDENT) {
+ if (CurTok.Tok != TOK_IDENT) {
ErrorSkip ("Identifier expected");
return;
}
- Action = GetSubKey (ActionTab, sizeof (ActionTab) / sizeof (ActionTab[0]));
- switch (Action) {
+ switch (GetSubKey (ActionTab, sizeof (ActionTab) / sizeof (ActionTab[0]))) {
case 0:
case 1:
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 ();
- ConsumeComma ();
- /* Read the message */
- if (Tok != TOK_STRCON) {
- ErrorSkip ("String constant expected");
- } else {
- AddAssertion (Expr, Action, GetStringId (SVal));
+ /* 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 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 */
static void DoByte (void)
/* Define bytes */
{
+ /* Element type for the generated array */
+ static const char EType[1] = { GT_BYTE };
+
+ /* Record type information */
+ Span* S = OpenSpan ();
+ StrBuf Type = STATIC_STRBUF_INITIALIZER;
+
+ /* Parse arguments */
while (1) {
- if (Tok == TOK_STRCON) {
- /* A string, translate into target charset and emit */
- unsigned Len = strlen (SVal);
- TgtTranslateBuf (SVal, Len);
- EmitData ((unsigned char*) SVal, Len);
- NextTok ();
- } else {
- EmitByte (Expression ());
- }
- if (Tok != TOK_COMMA) {
- break;
- } else {
- NextTok ();
- /* Do smart handling of dangling comma */
- if (Tok == TOK_SEP) {
- Error ("Unexpected end of line");
- break;
- }
- }
+ if (CurTok.Tok == TOK_STRCON) {
+ /* A string, translate into target charset and emit */
+ TgtTranslateStrBuf (&CurTok.SVal);
+ EmitStrBuf (&CurTok.SVal);
+ NextTok ();
+ } else {
+ EmitByte (BoundedExpr (Expression, 1));
+ }
+ if (CurTok.Tok != TOK_COMMA) {
+ break;
+ } else {
+ NextTok ();
+ /* Do smart handling of dangling comma */
+ if (CurTok.Tok == TOK_SEP) {
+ Error ("Unexpected end of line");
+ break;
+ }
+ }
}
+
+ /* Close the span, then add type information to it */
+ S = CloseSpan (S);
+ SetSpanType (S, GenArrayType (&Type, GetSpanSize (S), EType, sizeof (EType)));
+
+ /* Free the type string */
+ SB_Done (&Type);
}
/* Read the index as numerical value */
Index = ConstExpression ();
- if (Index < 1 || Index > 255) {
- /* Value out of range */
- ErrorSkip ("Range error");
- return;
+ if (Index <= 0 || Index > 255) {
+ /* Value out of range */
+ ErrorSkip ("Range error");
+ return;
}
/* Comma follows */
/* Read the character code */
Code = ConstExpression ();
- if (Code < 1 || Code > 255) {
- /* Value out of range */
- ErrorSkip ("Range error");
- return;
+ if (Code < 0 || Code > 255) {
+ /* Value out of range */
+ ErrorSkip ("Range error");
+ return;
}
/* Set the character translation */
/* Export a symbol as constructor/destructor */
{
static const char* Keys[] = {
- "CONSTRUCTOR",
- "DESTRUCTOR",
+ "CONSTRUCTOR",
+ "DESTRUCTOR",
+ "INTERRUPTOR",
};
- char Name [sizeof (SVal)];
+ StrBuf Name = STATIC_STRBUF_INITIALIZER;
long Type;
/* Symbol name follows */
- if (Tok != TOK_IDENT) {
- ErrorSkip ("Identifier expected");
- return;
+ 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]));
- NextTok ();
+ /* 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) {
- Error ("Syntax error");
- SkipUntilSep ();
- return;
- }
+ /* 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 */
- Error ("Range error");
- return;
- }
+ /* 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);
+ ConDes (&Name, (unsigned) Type);
+
+ExitPoint:
+ /* Free string memory */
+ SB_Done (&Name);
}
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 ("Identifier expected");
- return;
+ 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);
}
/* Add debug information from high level code */
{
static const char* Keys[] = {
- "FILE",
- "LINE",
- "SYM",
+ "FILE",
+ "FUNC",
+ "LINE",
+ "SYM",
};
int Key;
/* We expect a subkey */
- if (Tok != TOK_IDENT) {
- ErrorSkip ("Identifier expected");
- return;
+ if (CurTok.Tok != TOK_IDENT) {
+ ErrorSkip ("Identifier expected");
+ return;
}
/* Map the following keyword to a number */
/* 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;
+ case 0: DbgInfoFile (); break;
+ case 1: DbgInfoFunc (); break;
+ case 2: DbgInfoLine (); break;
+ case 3: DbgInfoSym (); break;
+ default: ErrorSkip ("Syntax error"); break;
}
}
static void DoDByt (void)
/* Output double bytes */
{
+ /* Element type for the generated array */
+ static const char EType[1] = { GT_DBYTE };
+
+ /* Record type information */
+ Span* S = OpenSpan ();
+ StrBuf Type = STATIC_STRBUF_INITIALIZER;
+
+ /* Parse arguments */
while (1) {
- EmitWord (GenSwapExpr (Expression ()));
- if (Tok != TOK_COMMA) {
- break;
- } else {
- NextTok ();
- }
+ EmitWord (GenSwapExpr (BoundedExpr (Expression, 2)));
+ if (CurTok.Tok != TOK_COMMA) {
+ break;
+ } else {
+ NextTok ();
+ }
}
+
+ /* Close the span, then add type information to it */
+ S = CloseSpan (S);
+ SetSpanType (S, GenArrayType (&Type, GetSpanSize (S), EType, sizeof (EType)));
+
+ /* Free the type string */
+ SB_Done (&Type);
}
+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 ("Identifier expected");
- return;
+ 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);
}
/* Define dwords */
{
while (1) {
- EmitDWord (Expression ());
- if (Tok != TOK_COMMA) {
- break;
- } else {
- NextTok ();
- }
+ EmitDWord (BoundedExpr (Expression, 4));
+ if (CurTok.Tok != TOK_COMMA) {
+ break;
+ } else {
+ NextTok ();
+ }
}
}
static void DoEndProc (void)
/* Leave a lexical level */
{
- if (CurrentScope == RootScope || GetCurrentSymTabType () != ST_PROC) {
+ if (CurrentScope->Type != SCOPE_SCOPE || CurrentScope->Label == 0) {
/* No local scope */
ErrorSkip ("No open .PROC");
} else {
static void DoEndScope (void)
/* Leave a lexical level */
{
- if (CurrentScope == RootScope || GetCurrentSymTabType () != ST_SCOPE) {
+ if (CurrentScope->Type != SCOPE_SCOPE || CurrentScope->Label != 0) {
/* No local scope */
ErrorSkip ("No open .SCOPE");
} else {
static void DoError (void)
/* User error */
{
- if (Tok != TOK_STRCON) {
- ErrorSkip ("String constant expected");
+ if (CurTok.Tok != TOK_STRCON) {
+ ErrorSkip ("String constant expected");
} else {
- Error ("User error: %s", SVal);
- SkipUntilSep ();
+ Error ("User error: %m%p", &CurTok.SVal);
+ SkipUntilSep ();
}
}
/* Exit a macro expansion */
{
if (!InMacExpansion ()) {
- /* We aren't expanding a macro currently */
- DoUnexpected ();
+ /* We aren't expanding a macro currently */
+ DoUnexpected ();
} else {
- MacAbort ();
+ MacAbort ();
}
}
static void DoExport (void)
/* Export a symbol */
{
- ExportImport (SymExport, ADDR_SIZE_DEFAULT, SF_NONE);
+ ExportImport (ExportWithAssign, ADDR_SIZE_DEFAULT, SF_NONE);
}
static void DoExportZP (void)
/* Export a zeropage symbol */
{
- ExportImport (SymExport, ADDR_SIZE_ZP, SF_NONE);
+ ExportImport (ExportWithAssign, ADDR_SIZE_ZP, SF_NONE);
}
static void DoFarAddr (void)
/* Define far addresses (24 bit) */
{
+ /* Element type for the generated array */
+ static const char EType[2] = { GT_FAR_PTR, GT_VOID };
+
+ /* Record type information */
+ Span* S = OpenSpan ();
+ StrBuf Type = STATIC_STRBUF_INITIALIZER;
+
+ /* Parse arguments */
while (1) {
- EmitFarAddr (Expression ());
- if (Tok != TOK_COMMA) {
- break;
- } else {
- NextTok ();
- }
+ EmitFarAddr (BoundedExpr (Expression, 3));
+ if (CurTok.Tok != TOK_COMMA) {
+ break;
+ } else {
+ NextTok ();
+ }
+ }
+
+ /* Close the span, then add type information to it */
+ S = CloseSpan (S);
+ SetSpanType (S, GenArrayType (&Type, GetSpanSize (S), EType, sizeof (EType)));
+
+ /* Free the type string */
+ SB_Done (&Type);
+}
+
+
+
+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 ();
}
}
/* Allow a list of comma separated keywords */
while (1) {
- /* We expect an identifier */
- if (Tok != TOK_IDENT) {
- ErrorSkip ("Identifier expected");
- return;
- }
+ /* We expect an identifier */
+ if (CurTok.Tok != TOK_IDENT) {
+ ErrorSkip ("Identifier expected");
+ return;
+ }
- /* Make the string attribute lower case */
- LocaseSVal ();
+ /* Make the string attribute lower case */
+ LocaseSVal ();
- /* Set the feature and check for errors */
- if (SetFeature (SVal) == FEAT_UNKNOWN) {
- /* Not found */
- ErrorSkip ("Invalid feature: `%s'", SVal);
- return;
- } else {
- /* Skip the keyword */
- NextTok ();
- }
+ /* Set the feature and check for errors */
+ if (SetFeature (&CurTok.SVal) == FEAT_UNKNOWN) {
+ /* Not found */
+ ErrorSkip ("Invalid feature: `%m%p'", &CurTok.SVal);
+ return;
+ } else {
+ /* Skip the keyword */
+ NextTok ();
+ }
- /* Allow more than one keyword */
- if (Tok == TOK_COMMA) {
- NextTok ();
- } else {
- break;
- }
+ /* Allow more than one keyword */
+ if (CurTok.Tok == TOK_COMMA) {
+ NextTok ();
+ } else {
+ break;
+ }
}
}
long OptNum;
/* The option type may be given as a keyword or as a number. */
- if (Tok == TOK_IDENT) {
-
- /* Option given as keyword */
- static const char* Keys [] = {
- "AUTHOR", "COMMENT", "COMPILER"
- };
-
- /* Map the option to a number */
- OptNum = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
- if (OptNum < 0) {
- /* Not found */
- ErrorSkip ("File option keyword expected");
- return;
- }
+ if (CurTok.Tok == TOK_IDENT) {
+
+ /* Option given as keyword */
+ static const char* Keys [] = {
+ "AUTHOR", "COMMENT", "COMPILER"
+ };
+
+ /* Map the option to a number */
+ OptNum = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
+ if (OptNum < 0) {
+ /* Not found */
+ ErrorSkip ("File option keyword expected");
+ return;
+ }
- /* Skip the keyword */
- NextTok ();
+ /* Skip the keyword */
+ NextTok ();
- /* Must be followed by a comma */
- ConsumeComma ();
+ /* Must be followed by a comma */
+ ConsumeComma ();
- /* We accept only string options for now */
- if (Tok != TOK_STRCON) {
- ErrorSkip ("String constant expected");
- return;
- }
+ /* We accept only string options for now */
+ if (CurTok.Tok != TOK_STRCON) {
+ ErrorSkip ("String constant expected");
+ return;
+ }
- /* Insert the option */
- switch (OptNum) {
+ /* Insert the option */
+ switch (OptNum) {
- case 0:
- /* Author */
- OptAuthor (SVal);
- break;
+ case 0:
+ /* Author */
+ OptAuthor (&CurTok.SVal);
+ break;
- case 1:
- /* Comment */
- OptComment (SVal);
- break;
+ case 1:
+ /* Comment */
+ OptComment (&CurTok.SVal);
+ break;
- case 2:
- /* Compiler */
- OptCompiler (SVal);
- break;
+ case 2:
+ /* Compiler */
+ OptCompiler (&CurTok.SVal);
+ break;
- default:
- Internal ("Invalid OptNum: %ld", OptNum);
+ default:
+ Internal ("Invalid OptNum: %ld", OptNum);
- }
+ }
- /* Done */
- NextTok ();
+ /* Done */
+ NextTok ();
} else {
- /* Option given as number */
- OptNum = ConstExpression ();
- if (!IsByteRange (OptNum)) {
- ErrorSkip ("Range error");
- return;
- }
+ /* Option given as number */
+ OptNum = ConstExpression ();
+ if (!IsByteRange (OptNum)) {
+ ErrorSkip ("Range error");
+ return;
+ }
- /* Must be followed by a comma */
- ConsumeComma ();
+ /* Must be followed by a comma */
+ ConsumeComma ();
- /* We accept only string options for now */
- if (Tok != TOK_STRCON) {
- ErrorSkip ("String constant expected");
- return;
- }
+ /* We accept only string options for now */
+ if (CurTok.Tok != TOK_STRCON) {
+ ErrorSkip ("String constant expected");
+ return;
+ }
- /* Insert the option */
- OptStr ((unsigned char) OptNum, SVal);
+ /* Insert the option */
+ OptStr ((unsigned char) OptNum, &CurTok.SVal);
- /* Done */
- NextTok ();
+ /* Done */
+ NextTok ();
}
}
}
+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 ();
+ }
+ }
+}
+
+
static void DoI16 (void)
/* Switch the index registers to 16 bit mode (assembler only) */
{
if (GetCPU() != CPU_65816) {
- Error ("Command is only valid in 65816 mode");
+ Error ("Command is only valid in 65816 mode");
} else {
- /* Immidiate mode has two extension bytes */
- ExtBytes [AMI_IMM_INDEX] = 2;
+ /* Immidiate mode has two extension bytes */
+ ExtBytes [AM65I_IMM_INDEX] = 2;
}
}
/* Switch the index registers to 16 bit mode (assembler only) */
{
if (GetCPU() != CPU_65816) {
- Error ("Command is only valid in 65816 mode");
+ Error ("Command is only valid in 65816 mode");
} else {
- /* Immidiate mode has one extension byte */
- ExtBytes [AMI_IMM_INDEX] = 1;
+ /* Immidiate mode has one extension byte */
+ ExtBytes [AM65I_IMM_INDEX] = 1;
}
}
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 ("String constant expected");
- return;
+ 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) {
- NextTok ();
- Start = ConstExpression ();
+ if (CurTok.Tok == TOK_COMMA) {
+ NextTok ();
+ Start = ConstExpression ();
- /* And a length may follow */
- if (Tok == TOK_COMMA) {
- NextTok ();
- Count = ConstExpression ();
- }
+ /* And a length may follow */
+ if (CurTok.Tok == TOK_COMMA) {
+ NextTok ();
+ Count = ConstExpression ();
+ }
}
/* Try to open the file */
- F = fopen (Name, "rb");
+ F = fopen (SB_GetConstBuf (&Name), "rb");
if (F == 0) {
- /* Search for the file in the include directories. */
- char* PathName = FindInclude (Name);
- if (PathName == 0 || (F = fopen (PathName, "r")) == 0) {
- /* Not found or cannot open, print an error and bail out */
- ErrorSkip ("Cannot open include file `%s': %s", Name, strerror (errno));
- }
+ /* 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;
+ }
- /* Free the allocated memory */
- xfree (PathName);
+ /* Remember the new file name */
+ SB_CopyStr (&Name, PathName);
- /* If we had an error before, bail out now */
- if (F == 0) {
- return;
- }
+ /* 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 (FileStat (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, (unsigned long) 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;
- }
+ 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 ("Range error");
- goto Done;
- }
+ /* Count was given, check if it is valid */
+ if (Start + Count > Size) {
+ ErrorSkip ("Range error");
+ goto Done;
+ }
}
/* Seek to the start position */
/* 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 */
- size_t BytesToRead = (Count > (long)sizeof(Buf))? sizeof(Buf) : (size_t) Count;
+ /* 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 `%s': %s",
- Name, strerror (errno));
- break;
- }
+ /* 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;
+ }
- /* Insert it into the output */
- EmitData (Buf, BytesRead);
+ /* Insert it into the output */
+ EmitData (Buf, BytesRead);
- /* Keep the counters current */
- Count -= 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);
}
static void DoInclude (void)
/* Include another file */
{
- char Name [MAX_STR_LEN+1];
-
/* Name must follow */
- if (Tok != TOK_STRCON) {
- ErrorSkip ("String constant 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);
}
* an error in the assembler itself, while DoInvalid is.
*/
{
- Internal ("Unexpected token: %s", Keyword);
+ Internal ("Unexpected token: %m%p", &Keyword);
}
/* Manage the counter */
if (List) {
- EnableListing ();
+ EnableListing ();
} else {
- DisableListing ();
+ DisableListing ();
}
}
+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 */
{
static void DoLocalChar (void)
/* Define the character that starts local labels */
{
- if (Tok != TOK_CHARCON) {
- ErrorSkip ("Character constant expected");
+ if (CurTok.Tok != TOK_CHARCON) {
+ ErrorSkip ("Character constant expected");
} else {
- if (IVal != '@' && IVal != '?') {
- Error ("Invalid start character for locals");
- } else {
- LocalStart = (char) IVal;
- }
- NextTok ();
+ if (CurTok.IVal != '@' && CurTok.IVal != '?') {
+ Error ("Invalid start character for locals");
+ } else {
+ LocalStart = (char) CurTok.IVal;
+ }
+ NextTok ();
}
}
static void DoMacPack (void)
/* Insert a macro package */
{
- /* Macro package names */
- static const char* Keys [] = {
- "GENERIC",
- "LONGBRANCH",
- "CBM",
- "CPU"
- };
-
- int Package;
-
/* We expect an identifier */
- if (Tok != TOK_IDENT) {
- ErrorSkip ("Identifier expected");
- return;
- }
-
- /* Map the keyword to a number */
- Package = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
- if (Package < 0) {
- /* Not found */
- ErrorSkip ("Invalid macro package");
- return;
+ if (CurTok.Tok != TOK_IDENT) {
+ ErrorSkip ("Identifier expected");
+ } else {
+ SB_AppendStr (&CurTok.SVal, ".mac");
+ SB_Terminate (&CurTok.SVal);
+ if (NewInputFile (SB_GetConstBuf (&CurTok.SVal)) == 0) {
+ /* Error opening the file, skip remainder of line */
+ SkipUntilSep ();
+ }
}
-
- /* Skip the package name */
- NextTok ();
-
- /* Insert the package */
- InsertMacPack (Package);
}
{
long PC = ConstExpression ();
if (PC < 0 || PC > 0xFFFFFF) {
- Error ("Range error");
- return;
+ Error ("Range error");
+ return;
}
- SetAbsPC (PC);
+ EnterAbsoluteMode (PC);
}
static void DoOut (void)
/* Output a string */
{
- if (Tok != TOK_STRCON) {
- ErrorSkip ("String constant 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);
- fflush (stdout);
- NextTok ();
+ /* 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",
+ (int) SB_GetLen (&CurTok.SVal),
+ SB_GetConstBuf (&CurTok.SVal));
+ fflush (stdout);
+ NextTok ();
}
}
+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 */
{
static void DoProc (void)
/* Start a new lexical scope */
{
- char Name[sizeof(SVal)];
+ StrBuf Name = STATIC_STRBUF_INITIALIZER;
unsigned char AddrSize;
+ SymEntry* Sym = 0;
+
- if (Tok == TOK_IDENT) {
+ if (CurTok.Tok == TOK_IDENT) {
- /* The new scope has a name. Remember it. */
- strcpy (Name, SVal);
+ /* The new scope has a name. Remember it. */
+ SB_Copy (&Name, &CurTok.SVal);
/* Search for the symbol, generate a new one if needed */
- SymEntry* Sym = SymFind (CurrentScope, Name, SYM_ALLOC_NEW);
+ Sym = SymFind (CurrentScope, &Name, SYM_ALLOC_NEW);
/* Skip the scope name */
NextTok ();
AddrSize = OptionalAddrSize ();
/* Mark the symbol as defined */
- SymDef (Sym, GenCurrentPC (), AddrSize, SF_LABEL);
+ SymDef (Sym, GenCurrentPC (), AddrSize, SF_LABEL);
} else {
/* A .PROC statement without a name */
Warning (1, "Unnamed .PROCs are deprecated, please use .SCOPE");
- AnonName (Name, sizeof (Name), "PROC");
+ AnonName (&Name, "PROC");
AddrSize = ADDR_SIZE_DEFAULT;
}
/* Enter a new scope */
- SymEnterLevel (Name, ST_PROC, AddrSize);
+ SymEnterLevel (&Name, SCOPE_SCOPE, AddrSize, Sym);
+
+ /* Free memory for Name */
+ SB_Done (&Name);
}
+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 */
{
static void DoReloc (void)
/* Enter relocatable mode */
{
- RelocMode = 1;
+ EnterRelocMode ();
}
Count = ConstExpression ();
if (Count > 0xFFFF || Count < 0) {
- ErrorSkip ("Range error");
- return;
- }
- if (Tok == TOK_COMMA) {
- NextTok ();
- Val = ConstExpression ();
- /* We need a byte value here */
- if (!IsByteRange (Val)) {
- ErrorSkip ("Range error");
- return;
- }
-
- /* Emit constant values */
- while (Count--) {
- Emit0 ((unsigned char) Val);
- }
+ ErrorSkip ("Range error");
+ return;
+ }
+ if (CurTok.Tok == TOK_COMMA) {
+ NextTok ();
+ Val = ConstExpression ();
+ /* We need a byte value here */
+ if (!IsByteRange (Val)) {
+ ErrorSkip ("Range error");
+ return;
+ }
+
+ /* Emit constant values */
+ while (Count--) {
+ Emit0 ((unsigned char) Val);
+ }
} else {
- /* Emit fill fragments */
- EmitFill (Count);
+ /* Emit fill fragments */
+ EmitFill (Count);
}
}
static void DoScope (void)
/* Start a local scope */
{
- char Name[sizeof (SVal)];
+ StrBuf Name = STATIC_STRBUF_INITIALIZER;
unsigned char AddrSize;
- if (Tok == TOK_IDENT) {
+ if (CurTok.Tok == TOK_IDENT) {
- /* The new scope has a name. Remember and skip it. */
- strcpy (Name, SVal);
+ /* The new scope has a name. Remember and skip it. */
+ SB_Copy (&Name, &CurTok.SVal);
NextTok ();
} else {
/* An unnamed scope */
- AnonName (Name, sizeof (Name), "SCOPE");
+ AnonName (&Name, "SCOPE");
}
AddrSize = OptionalAddrSize ();
/* Enter the new scope */
- SymEnterLevel (Name, ST_SCOPE, AddrSize);
+ SymEnterLevel (&Name, SCOPE_SCOPE, AddrSize, 0);
+ /* Free memory for Name */
+ SB_Done (&Name);
}
static void DoSegment (void)
/* Switch to another segment */
{
- char Name [sizeof (SVal)];
+ StrBuf Name = STATIC_STRBUF_INITIALIZER;
SegDef Def;
- Def.Name = Name;
- if (Tok != TOK_STRCON) {
- ErrorSkip ("String constant expected");
+ if (CurTok.Tok != TOK_STRCON) {
+ ErrorSkip ("String constant expected");
} else {
- /* Save the name of the segment and skip it */
- strcpy (Name, SVal);
- NextTok ();
+ /* Save the name of the segment and skip it */
+ SB_Copy (&Name, &CurTok.SVal);
+ NextTok ();
- /* Check for an optional address size modifier */
+ /* 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 (&Def);
+ /* Set the segment */
+ UseSeg (&Def);
}
+
+ /* Free memory for Name */
+ SB_Done (&Name);
}
/* Switch the CPU instruction set */
{
/* We expect an identifier */
- if (Tok != TOK_STRCON) {
- ErrorSkip ("String constant expected");
+ if (CurTok.Tok != TOK_STRCON) {
+ ErrorSkip ("String constant expected");
} else {
- /* Try to find the CPU, then skip the identifier */
- cpu_t CPU = FindCPU (SVal);
- NextTok ();
+ 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 ();
}
}
-static void DoStruct (void)
-/* Struct definition */
+static void DoTag (void)
+/* Allocate space for a struct */
{
- Error ("Not implemented");
-}
+ 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;
+ }
-static void DoSunPlus (void)
-/* Switch to the SUNPLUS CPU */
-{
- SetCPU (CPU_SUNPLUS);
+ /* 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 DoUnion (void)
-/* Union definition */
+static void DoUnDef (void)
+/* Undefine a define style macro */
{
- Error ("Not implemented");
+ /* 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 ("Unexpected `%s'", Keyword);
+ Error ("Unexpected `%m%p'", &Keyword);
SkipUntilSep ();
}
static void DoWarning (void)
/* User warning */
{
- if (Tok != TOK_STRCON) {
- ErrorSkip ("String constant expected");
+ if (CurTok.Tok != TOK_STRCON) {
+ ErrorSkip ("String constant expected");
} else {
- Warning (0, "User warning: %s", SVal);
- SkipUntilSep ();
+ Warning (0, "User warning: %m%p", &CurTok.SVal);
+ SkipUntilSep ();
}
}
static void DoWord (void)
/* Define words */
{
+ /* Element type for the generated array */
+ static const char EType[1] = { GT_WORD };
+
+ /* Record type information */
+ Span* S = OpenSpan ();
+ StrBuf Type = STATIC_STRBUF_INITIALIZER;
+
+ /* Parse arguments */
while (1) {
- EmitWord (Expression ());
- if (Tok != TOK_COMMA) {
- break;
- } else {
- NextTok ();
- }
+ EmitWord (BoundedExpr (Expression, 2));
+ if (CurTok.Tok != TOK_COMMA) {
+ break;
+ } else {
+ NextTok ();
+ }
}
+
+ /* Close the span, then add type information to it */
+ S = CloseSpan (S);
+ SetSpanType (S, GenArrayType (&Type, GetSpanSize (S), EType, sizeof (EType)));
+
+ /* Free the type string */
+ SB_Done (&Type);
}
/*****************************************************************************/
-/* Table data */
+/* Table data */
/*****************************************************************************/
/* Control commands flags */
enum {
- ccNone = 0x0000, /* No special flags */
- ccKeepToken = 0x0001 /* Do not skip the current token */
+ ccNone = 0x0000, /* No special flags */
+ ccKeepToken = 0x0001 /* Do not skip the current token */
};
/* Control command table */
typedef struct CtrlDesc CtrlDesc;
struct CtrlDesc {
- unsigned Flags; /* Flags for this directive */
- void (*Handler) (void); /* Command handler */
+ unsigned Flags; /* Flags for this directive */
+ void (*Handler) (void); /* Command handler */
};
-#define PSEUDO_COUNT (sizeof (CtrlCmdTab) / sizeof (CtrlCmdTab [0]))
+#define PSEUDO_COUNT (sizeof (CtrlCmdTab) / sizeof (CtrlCmdTab [0]))
static CtrlDesc CtrlCmdTab [] = {
- { ccNone, DoA16 },
- { ccNone, DoA8 },
- { ccNone, DoAddr }, /* .ADDR */
- { ccNone, DoAlign },
- { ccNone, DoASCIIZ },
+ { ccNone, DoA16 },
+ { ccNone, DoA8 },
+ { ccNone, DoAddr }, /* .ADDR */
+ { ccNone, DoAlign },
+ { ccNone, DoASCIIZ },
{ ccNone, DoAssert },
- { ccNone, DoAutoImport },
- { 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, DoDestructor },
- { ccNone, DoDWord },
- { ccKeepToken, DoConditionals }, /* .ELSE */
- { ccKeepToken, DoConditionals }, /* .ELSEIF */
- { ccKeepToken, DoEnd },
- { ccKeepToken, DoConditionals }, /* .ENDIF */
- { ccNone, DoUnexpected }, /* .ENDMACRO */
- { ccNone, DoEndProc },
- { ccNone, DoUnexpected }, /* .ENDREPEAT */
+ { ccNone, DoAutoImport },
+ { ccNone, DoUnexpected }, /* .BANK */
+ { 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 */
+ { ccKeepToken, DoEnd },
+ { ccNone, DoUnexpected }, /* .ENDENUM */
+ { ccKeepToken, DoConditionals }, /* .ENDIF */
+ { ccNone, DoUnexpected }, /* .ENDMACRO */
+ { ccNone, DoEndProc },
+ { ccNone, DoUnexpected }, /* .ENDREPEAT */
{ ccNone, DoEndScope },
{ ccNone, DoUnexpected }, /* .ENDSTRUCT */
- { ccNone, DoError },
- { ccNone, DoExitMacro },
- { ccNone, DoExport },
- { ccNone, DoExportZP },
- { ccNone, DoFarAddr },
- { ccNone, DoFeature },
- { ccNone, DoFileOpt },
+ { 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, DoI16 },
- { ccNone, DoI8 },
- { ccKeepToken, DoConditionals }, /* .IF */
- { ccKeepToken, DoConditionals }, /* .IFBLANK */
- { ccKeepToken, DoConditionals }, /* .IFCONST */
- { ccKeepToken, DoConditionals }, /* .IFDEF */
- { ccKeepToken, DoConditionals }, /* .IFNBLANK */
- { ccKeepToken, DoConditionals }, /* .IFNCONST */
- { ccKeepToken, DoConditionals }, /* .IFNDEF */
- { ccKeepToken, DoConditionals }, /* .IFNREF */
- { ccKeepToken, DoConditionals }, /* .IFP02 */
- { ccKeepToken, DoConditionals }, /* .IFP816 */
- { ccKeepToken, DoConditionals }, /* .IFPC02 */
- { ccKeepToken, DoConditionals }, /* .IFPSC02 */
- { ccKeepToken, DoConditionals }, /* .IFREF */
- { ccNone, DoImport },
- { ccNone, DoImportZP },
- { ccNone, DoIncBin },
- { ccNone, DoInclude },
- { ccNone, DoInvalid }, /* .LEFT */
- { ccNone, DoLineCont },
- { ccNone, DoList },
- { ccNone, DoListBytes },
- { ccNone, DoUnexpected }, /* .LOCAL */
- { ccNone, DoLocalChar },
- { ccNone, DoMacPack },
- { ccNone, DoMacro },
- { ccNone, DoUnexpected }, /* .MATCH */
- { ccNone, DoInvalid }, /* .MID */
- { ccNone, DoNull },
- { ccNone, DoOrg },
- { ccNone, DoOut },
- { ccNone, DoP02 },
- { ccNone, DoP816 },
- { ccNone, DoPageLength },
- { ccNone, DoUnexpected }, /* .PARAMCOUNT */
- { ccNone, DoPC02 },
+ { 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 */
+ { ccKeepToken, DoConditionals }, /* .IFDEF */
+ { ccKeepToken, DoConditionals }, /* .IFNBLANK */
+ { ccKeepToken, DoConditionals }, /* .IFNCONST */
+ { ccKeepToken, DoConditionals }, /* .IFNDEF */
+ { ccKeepToken, DoConditionals }, /* .IFNREF */
+ { ccKeepToken, DoConditionals }, /* .IFP02 */
+ { ccKeepToken, DoConditionals }, /* .IFP816 */
+ { ccKeepToken, DoConditionals }, /* .IFPC02 */
+ { 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, DoOut },
+ { ccNone, DoP02 },
+ { ccNone, DoP816 },
+ { ccNone, DoPageLength },
+ { ccNone, DoUnexpected }, /* .PARAMCOUNT */
+ { ccNone, DoPC02 },
+ { ccNone, DoPopCPU },
{ ccNone, DoPopSeg },
- { ccNone, DoProc },
- { ccNone, DoPSC02 },
+ { ccNone, DoProc },
+ { ccNone, DoPSC02 },
+ { ccNone, DoPushCPU },
{ ccNone, DoPushSeg },
- { ccNone, DoUnexpected }, /* .REFERENCED */
- { ccNone, DoReloc },
- { ccNone, DoRepeat },
- { ccNone, DoRes },
- { ccNone, DoInvalid }, /* .RIGHT */
- { ccNone, DoROData },
+ { ccNone, DoUnexpected }, /* .REFERENCED */
+ { ccNone, DoReloc },
+ { ccNone, DoRepeat },
+ { ccNone, DoRes },
+ { ccNone, DoInvalid }, /* .RIGHT */
+ { ccNone, DoROData },
{ ccNone, DoScope },
- { ccNone, DoSegment },
- { ccNone, DoSetCPU },
- { ccNone, DoSmart },
- { ccNone, DoUnexpected }, /* .STRAT */
- { ccNone, DoUnexpected }, /* .STRING */
- { ccNone, DoUnexpected }, /* .STRLEN */
+ { ccNone, DoSegment },
+ { ccNone, DoUnexpected }, /* .SET */
+ { ccNone, DoSetCPU },
+ { ccNone, DoUnexpected }, /* .SIZEOF */
+ { ccNone, DoSmart },
+ { ccNone, DoUnexpected }, /* .SPRINTF */
+ { ccNone, DoUnexpected }, /* .STRAT */
+ { ccNone, DoUnexpected }, /* .STRING */
+ { ccNone, DoUnexpected }, /* .STRLEN */
{ ccNone, DoStruct },
- { ccNone, DoSunPlus },
- { ccNone, DoUnexpected }, /* .TAG */
- { 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, DoZeropage },
+ { 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);
+ Internal ("Pseudo mismatch: PSEUDO_COUNT = %u, actual count = %u\n",
+ (unsigned) PSEUDO_COUNT, TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1);
}
CHECK (Index < PSEUDO_COUNT);
/* Remember the instruction, then skip it if needed */
if ((D->Flags & ccKeepToken) == 0) {
- strcpy (Keyword+1, SVal);
- NextTok ();
+ SB_Copy (&Keyword, &CurTok.SVal);
+ NextTok ();
}
/* Call the handler */
-void SegStackCheck (void)
-/* Check if the segment stack is empty at end of assembly */
+void CheckPseudo (void)
+/* Check if the stacks are empty at end of assembly */
{
if (CollCount (&SegStack) != 0) {
- Error ("Segment stack is not empty");
+ Warning (1, "Segment stack is not empty");
+ }
+ if (!IS_IsEmpty (&CPUStack)) {
+ Warning (1, "CPU stack is not empty");
}
}