/* */
/* */
/* */
-/* (C) 1998-2010, Ullrich von Bassewitz */
+/* (C) 1998-2012, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
#include <errno.h>
/* common */
+#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 "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 "repeat.h"
#include "segment.h"
#include "sizeof.h"
+#include "span.h"
#include "spool.h"
#include "struct.h"
#include "symbol.h"
/* Keyword we're about to handle */
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;
*/
{
unsigned AddrSize = ADDR_SIZE_DEFAULT;
- if (Tok == TOK_COLON) {
+ if (CurTok.Tok == TOK_COLON) {
NextTok ();
AddrSize = ParseAddrSize ();
if (!ValidAddrSizeForCPU (AddrSize)) {
"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 ("`on' or `off' expected"); break;
}
- } else if (TokIsSep (Tok)) {
+ } else if (TokIsSep (CurTok.Tok)) {
/* Without anything assume switch on */
*Flag = 1;
} else {
/* The name and optional address size spec may be followed by an assignment
* or equal token.
*/
- if (Tok == TOK_ASSIGN || Tok == TOK_EQ) {
+ if (CurTok.Tok == TOK_ASSIGN || CurTok.Tok == TOK_EQ) {
/* Assignment means the symbol is a label */
- if (Tok == TOK_ASSIGN) {
+ if (CurTok.Tok == TOK_ASSIGN) {
Flags |= SF_LABEL;
}
while (1) {
/* We need an identifier here */
- if (Tok != TOK_IDENT) {
+ 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) {
+ if (CurTok.Tok == TOK_COMMA) {
NextTok ();
} else {
break;
* and return -1 in this case.
*/
{
- if (Tok == TOK_IDENT && SB_CompareStr (&SVal, "unlimited") == 0) {
+ if (CurTok.Tok == TOK_IDENT && SB_CompareStr (&CurTok.SVal, "unlimited") == 0) {
NextTok ();
return -1;
} else {
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 ();
+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 */
/*****************************************************************************/
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 {
+ ExprNode* Expr = Expression ();
+ if (GetCPU () == CPU_65816 || ForceRange) {
/* Do a range check */
- EmitWord (Expression ());
- }
- if (Tok != TOK_COMMA) {
+ 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);
}
{
while (1) {
/* Must have a string constant */
- if (Tok != TOK_STRCON) {
+ if (CurTok.Tok != TOK_STRCON) {
ErrorSkip ("String constant expected");
return;
}
/* Translate into target charset and emit */
- TgtTranslateStrBuf (&SVal);
- EmitStrBuf (&SVal);
+ TgtTranslateStrBuf (&CurTok.SVal);
+ EmitStrBuf (&CurTok.SVal);
NextTok ();
- if (Tok == TOK_COMMA) {
+ if (CurTok.Tok == TOK_COMMA) {
NextTok ();
} else {
break;
ConsumeComma ();
/* Action follows */
- if (Tok != TOK_IDENT) {
+ if (CurTok.Tok != TOK_IDENT) {
ErrorSkip ("Identifier expected");
return;
}
/* We can have an optional message. If no message is present, use
* "Assertion failed".
*/
- if (Tok == TOK_COMMA) {
+ if (CurTok.Tok == TOK_COMMA) {
/* Skip the comma */
NextTok ();
/* Read the message */
- if (Tok != TOK_STRCON) {
+ 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 (&SVal);
+ Msg = GetStrBufId (&CurTok.SVal);
NextTok ();
} else {
{
while (1) {
EmitByte (FuncBankByte ());
- if (Tok != TOK_COMMA) {
+ if (CurTok.Tok != TOK_COMMA) {
break;
} else {
NextTok ();
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) {
+ if (CurTok.Tok == TOK_STRCON) {
/* A string, translate into target charset and emit */
- TgtTranslateStrBuf (&SVal);
- EmitStrBuf (&SVal);
+ TgtTranslateStrBuf (&CurTok.SVal);
+ EmitStrBuf (&CurTok.SVal);
NextTok ();
} else {
- EmitByte (Expression ());
+ EmitByte (BoundedExpr (Expression, 1));
}
- if (Tok != TOK_COMMA) {
+ if (CurTok.Tok != TOK_COMMA) {
break;
} else {
NextTok ();
/* Do smart handling of dangling comma */
- if (Tok == TOK_SEP) {
+ if (CurTok.Tok == TOK_SEP) {
Error ("Unexpected end of line");
- break;
+ 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 < 0 || Index > 255) {
+ if (Index <= 0 || Index > 255) {
/* Value out of range */
ErrorSkip ("Range error");
return;
long Type;
/* Symbol name follows */
- if (Tok != TOK_IDENT) {
+ if (CurTok.Tok != TOK_IDENT) {
ErrorSkip ("Identifier expected");
return;
}
- SB_Copy (&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]));
StrBuf Name = STATIC_STRBUF_INITIALIZER;
/* Symbol name follows */
- if (Tok != TOK_IDENT) {
+ if (CurTok.Tok != TOK_IDENT) {
ErrorSkip ("Identifier expected");
return;
}
- SB_Copy (&Name, &SVal);
+ SB_Copy (&Name, &CurTok.SVal);
NextTok ();
/* Parse the remainder of the line and export the symbol */
{
static const char* Keys[] = {
"FILE",
+ "FUNC",
"LINE",
"SYM",
};
/* We expect a subkey */
- if (Tok != TOK_IDENT) {
+ if (CurTok.Tok != TOK_IDENT) {
ErrorSkip ("Identifier expected");
return;
}
/* Check the key and dispatch to a handler */
switch (Key) {
case 0: DbgInfoFile (); break;
- case 1: DbgInfoLine (); break;
- case 2: DbgInfoSym (); 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) {
+ 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 */
{
StrBuf Name = STATIC_STRBUF_INITIALIZER;
/* Symbol name follows */
- if (Tok != TOK_IDENT) {
+ if (CurTok.Tok != TOK_IDENT) {
ErrorSkip ("Identifier expected");
return;
}
- SB_Copy (&Name, &SVal);
+ SB_Copy (&Name, &CurTok.SVal);
NextTok ();
/* Parse the remainder of the line and export the symbol */
/* Define dwords */
{
while (1) {
- EmitDWord (Expression ());
- if (Tok != TOK_COMMA) {
+ EmitDWord (BoundedExpr (Expression, 4));
+ if (CurTok.Tok != TOK_COMMA) {
break;
} else {
NextTok ();
static void DoEndProc (void)
/* Leave a lexical level */
{
- if (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 ( 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) {
+ if (CurTok.Tok != TOK_STRCON) {
ErrorSkip ("String constant expected");
} else {
- Error ("User error: %m%p", &SVal);
+ Error ("User error: %m%p", &CurTok.SVal);
SkipUntilSep ();
}
}
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) {
+ 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 ();
+ }
}
while (1) {
/* We expect an identifier */
- if (Tok != TOK_IDENT) {
+ if (CurTok.Tok != TOK_IDENT) {
ErrorSkip ("Identifier expected");
return;
}
LocaseSVal ();
/* Set the feature and check for errors */
- if (SetFeature (&SVal) == FEAT_UNKNOWN) {
+ if (SetFeature (&CurTok.SVal) == FEAT_UNKNOWN) {
/* Not found */
- ErrorSkip ("Invalid feature: `%m%p'", &SVal);
+ ErrorSkip ("Invalid feature: `%m%p'", &CurTok.SVal);
return;
} else {
/* Skip the keyword */
}
/* Allow more than one keyword */
- if (Tok == TOK_COMMA) {
+ 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) {
+ if (CurTok.Tok == TOK_IDENT) {
/* Option given as keyword */
static const char* Keys [] = {
ConsumeComma ();
/* We accept only string options for now */
- if (Tok != TOK_STRCON) {
+ if (CurTok.Tok != TOK_STRCON) {
ErrorSkip ("String constant expected");
return;
}
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:
ConsumeComma ();
/* We accept only string options for now */
- if (Tok != TOK_STRCON) {
+ 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 ();
{
while (1) {
EmitByte (FuncHiByte ());
- if (Tok != TOK_COMMA) {
+ if (CurTok.Tok != TOK_COMMA) {
break;
} else {
NextTok ();
/* Include a binary file */
{
StrBuf Name = STATIC_STRBUF_INITIALIZER;
+ struct stat StatBuf;
long Start = 0L;
long Count = -1L;
long Size;
FILE* F;
/* Name must follow */
- if (Tok != TOK_STRCON) {
+ if (CurTok.Tok != TOK_STRCON) {
ErrorSkip ("String constant expected");
return;
}
- SB_Copy (&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 ();
}
if (F == 0) {
/* Search for the file in the binary include directory */
- char* PathName = FindInclude (SB_GetConstBuf (&Name), INC_BIN);
+ 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);
-
- /* If we had an error before, bail out now */
- if (F == 0) {
- goto ExitPoint;
- }
}
/* 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, 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 */
+ Count = Size - Start;
+ if (Count < 0) {
+ /* Nothing to read - flag this as a range error */
ErrorSkip ("Range error");
goto Done;
}
/* Include another file */
{
/* Name must follow */
- if (Tok != TOK_STRCON) {
+ if (CurTok.Tok != TOK_STRCON) {
ErrorSkip ("String constant expected");
} else {
- SB_Terminate (&SVal);
- if (NewInputFile (SB_GetConstBuf (&SVal)) == 0) {
+ SB_Terminate (&CurTok.SVal);
+ if (NewInputFile (SB_GetConstBuf (&CurTok.SVal)) == 0) {
/* Error opening the file, skip remainder of line */
SkipUntilSep ();
}
StrBuf Name = STATIC_STRBUF_INITIALIZER;
/* Symbol name follows */
- if (Tok != TOK_IDENT) {
+ if (CurTok.Tok != TOK_IDENT) {
ErrorSkip ("Identifier expected");
return;
}
- SB_Copy (&Name, &SVal);
+ SB_Copy (&Name, &CurTok.SVal);
NextTok ();
/* Parse the remainder of the line and export the symbol */
{
while (1) {
EmitByte (FuncLoByte ());
- if (Tok != TOK_COMMA) {
+ if (CurTok.Tok != TOK_COMMA) {
break;
} else {
NextTok ();
static void DoLocalChar (void)
/* Define the character that starts local labels */
{
- if (Tok != TOK_CHARCON) {
+ if (CurTok.Tok != TOK_CHARCON) {
ErrorSkip ("Character constant expected");
} else {
- if (IVal != '@' && IVal != '?') {
+ if (CurTok.IVal != '@' && CurTok.IVal != '?') {
Error ("Invalid start character for locals");
} else {
- LocalStart = (char) IVal;
+ LocalStart = (char) CurTok.IVal;
}
NextTok ();
}
static void DoMacPack (void)
/* Insert a macro package */
{
- int Package;
-
/* We expect an identifier */
- if (Tok != TOK_IDENT) {
+ if (CurTok.Tok != TOK_IDENT) {
ErrorSkip ("Identifier expected");
- return;
- }
-
- /* Search for the macro package name */
- LocaseSVal ();
- Package = MacPackFind (&SVal);
- if (Package < 0) {
- /* Not found */
- ErrorSkip ("Invalid macro package");
- return;
- }
-
- /* Insert the package. If this fails, skip the remainder of the line to
- * avoid additional error messages.
- */
- if (MacPackInsert (Package) == 0) {
- SkipUntilSep ();
+ } 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 ();
+ }
}
}
static void DoOut (void)
/* Output a string */
{
- if (Tok != TOK_STRCON) {
+ 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", (int) SB_GetLen (&SVal), SB_GetConstBuf (&SVal));
+ 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 */
{
{
StrBuf Name = STATIC_STRBUF_INITIALIZER;
unsigned char AddrSize;
+ SymEntry* Sym = 0;
- if (Tok == TOK_IDENT) {
- SymEntry* Sym;
+ if (CurTok.Tok == TOK_IDENT) {
- /* The new scope has a name. Remember it. */
- SB_Copy (&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 */
Sym = SymFind (CurrentScope, &Name, SYM_ALLOC_NEW);
}
/* 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 */
{
ErrorSkip ("Range error");
return;
}
- if (Tok == TOK_COMMA) {
+ if (CurTok.Tok == TOK_COMMA) {
NextTok ();
Val = ConstExpression ();
/* We need a byte value here */
unsigned char AddrSize;
- if (Tok == TOK_IDENT) {
+ if (CurTok.Tok == TOK_IDENT) {
/* The new scope has a name. Remember and skip it. */
- SB_Copy (&Name, &SVal);
+ SB_Copy (&Name, &CurTok.SVal);
NextTok ();
} else {
AddrSize = OptionalAddrSize ();
/* Enter the new scope */
- SymEnterLevel (&Name, ST_SCOPE, AddrSize);
+ SymEnterLevel (&Name, SCOPE_SCOPE, AddrSize, 0);
/* Free memory for Name */
SB_Done (&Name);
StrBuf Name = STATIC_STRBUF_INITIALIZER;
SegDef Def;
- if (Tok != TOK_STRCON) {
+ if (CurTok.Tok != TOK_STRCON) {
ErrorSkip ("String constant expected");
} else {
/* Save the name of the segment and skip it */
- SB_Copy (&Name, &SVal);
+ SB_Copy (&Name, &CurTok.SVal);
NextTok ();
/* Use the name for the segment definition */
/* Switch the CPU instruction set */
{
/* We expect an identifier */
- if (Tok != TOK_STRCON) {
+ if (CurTok.Tok != TOK_STRCON) {
ErrorSkip ("String constant expected");
} else {
cpu_t CPU;
/* Try to find the CPU */
- SB_Terminate (&SVal);
- CPU = FindCPU (SB_GetConstBuf (&SVal));
+ SB_Terminate (&CurTok.SVal);
+ CPU = FindCPU (SB_GetConstBuf (&CurTok.SVal));
/* Switch to the new CPU */
SetCPU (CPU);
ErrorSkip ("Unknown struct");
return;
}
- if (GetSymTabType (Struct) != ST_STRUCT) {
+ if (GetSymTabType (Struct) != SCOPE_STRUCT) {
ErrorSkip ("Not a struct");
return;
}
}
/* Optional multiplicator may follow */
- if (Tok == TOK_COMMA) {
+ if (CurTok.Tok == TOK_COMMA) {
long Multiplicator;
NextTok ();
Multiplicator = ConstExpression ();
+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 */
{
static void DoWarning (void)
/* User warning */
{
- if (Tok != TOK_STRCON) {
+ if (CurTok.Tok != TOK_STRCON) {
ErrorSkip ("String constant expected");
} else {
- Warning (0, "User warning: %m%p", &SVal);
+ 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) {
+ 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 */
+ unsigned Flags; /* Flags for this directive */
void (*Handler) (void); /* Command handler */
};
{ ccNone, DoASCIIZ },
{ ccNone, DoAssert },
{ ccNone, DoAutoImport },
+ { ccNone, DoUnexpected }, /* .BANK */
{ ccNone, DoUnexpected }, /* .BANKBYTE */
{ ccNone, DoBankBytes },
{ ccNone, DoUnexpected }, /* .BLANK */
{ ccNone, DoDebugInfo },
{ ccNone, DoDefine },
{ ccNone, DoUnexpected }, /* .DEFINED */
+ { ccNone, DoDelMac },
{ ccNone, DoDestructor },
{ ccNone, DoDWord },
{ ccKeepToken, DoConditionals }, /* .ELSE */
{ ccNone, DoExport },
{ ccNone, DoExportZP },
{ ccNone, DoFarAddr },
+ { ccNone, DoFatal },
{ ccNone, DoFeature },
{ ccNone, DoFileOpt },
{ ccNone, DoForceImport },
{ ccKeepToken, DoConditionals }, /* .IFP816 */
{ ccKeepToken, DoConditionals }, /* .IFPC02 */
{ ccKeepToken, DoConditionals }, /* .IFPSC02 */
- { ccKeepToken, DoConditionals }, /* .IFREF */
+ { ccKeepToken, DoConditionals }, /* .IFREF */
{ ccNone, DoImport },
{ ccNone, DoImportZP },
{ ccNone, DoIncBin },
{ ccNone, DoUnexpected }, /* .MAX */
{ ccNone, DoInvalid }, /* .MID */
{ ccNone, DoUnexpected }, /* .MIN */
- { ccNone, DoNull },
- { ccNone, DoOrg },
+ { 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, DoPushCPU },
{ ccNone, DoPushSeg },
{ ccNone, DoUnexpected }, /* .REFERENCED */
{ ccNone, DoReloc },
{ ccNone, DoTag },
{ ccNone, DoUnexpected }, /* .TCOUNT */
{ ccNone, DoUnexpected }, /* .TIME */
+ { ccKeepToken, DoUnDef },
{ ccNone, DoUnion },
{ ccNone, DoUnexpected }, /* .VERSION */
{ ccNone, DoWarning },
- { ccNone, DoWord },
+ { ccNone, DoWord },
{ ccNone, DoUnexpected }, /* .XMATCH */
{ ccNone, DoZeropage },
};
/*****************************************************************************/
-/* Code */
+/* Code */
/*****************************************************************************/
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)) {
/* Remember the instruction, then skip it if needed */
if ((D->Flags & ccKeepToken) == 0) {
- SB_Copy (&Keyword, &SVal);
+ SB_Copy (&Keyword, &CurTok.SVal);
NextTok ();
}
-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");
}
}