/* */
/* */
/* (C) 1998-2003 Ullrich von Bassewitz */
-/* Römerstrasse 52 */
+/* Römerstraße 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
#include "asserts.h"
#include "condasm.h"
#include "dbginfo.h"
+#include "enum.h"
#include "error.h"
#include "expr.h"
#include "feature.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"
/* Keyword we're about to handle */
-static char Keyword [sizeof (SVal)+1] = ".";
+static char Keyword [sizeof (SVal)+1];
/* Segment stack */
#define MAX_PUSHED_SEGMENTS 16
-static unsigned OptionalAddrSize (void)
+static unsigned char OptionalAddrSize (void)
/* If a colon follows, parse an optional address size spec and return it.
* Otherwise return ADDR_SIZE_DEFAULT.
*/
} 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 (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 (TokIsSep (Tok)) {
/* Without anything assume switch on */
*Flag = 1;
} else {
- ErrorSkip (ERR_ONOFF_EXPECTED);
+ ErrorSkip ("`on' or `off' expected");
}
}
-static void ExportImport (void (*Func) (SymEntry*, unsigned, unsigned),
- unsigned DefAddrSize, unsigned Flags)
+static void ExportImport (void (*Func) (SymEntry*, unsigned char, unsigned),
+ unsigned char DefAddrSize, unsigned Flags)
/* Export or import symbols */
{
SymEntry* Sym;
- unsigned AddrSize;
+ unsigned char AddrSize;
while (1) {
/* We need an identifier here */
if (Tok != TOK_IDENT) {
- ErrorSkip (ERR_IDENT_EXPECTED);
+ ErrorSkip ("Identifier expected");
return;
}
} else {
long Val = ConstExpression ();
if (Val < Min || Val > Max) {
- Error (ERR_RANGE);
+ Error ("Range error");
Val = Min;
}
return Val;
{
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) {
/* Priority value follows */
Prio = ConstExpression ();
if (Prio < CD_PRIO_MIN || Prio > CD_PRIO_MAX) {
/* Value out of range */
- Error (ERR_RANGE);
+ Error ("Range error");
return;
}
} else {
}
/* Define the symbol */
- SymConDes (Name, Type, (unsigned) Prio);
+ SymConDes (Sym, ADDR_SIZE_DEFAULT, Type, (unsigned) Prio);
}
/* 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;
/* 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;
/* Read the alignment value */
Align = ConstExpression ();
if (Align <= 0 || Align > 0x10000) {
- ErrorSkip (ERR_RANGE);
+ ErrorSkip ("Range error");
return;
}
Val = ConstExpression ();
/* We need a byte value here */
if (!IsByteRange (Val)) {
- ErrorSkip (ERR_RANGE);
+ ErrorSkip ("Range error");
return;
}
} else {
/* 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);
}
while (1) {
/* Must have a string constant */
if (Tok != TOK_STRCON) {
- ErrorSkip (ERR_STRCON_EXPECTED);
+ ErrorSkip ("String constant expected");
return;
}
/* Action follows */
if (Tok != TOK_IDENT) {
- ErrorSkip (ERR_IDENT_EXPECTED);
+ ErrorSkip ("Identifier expected");
return;
}
Action = GetSubKey (ActionTab, sizeof (ActionTab) / sizeof (ActionTab[0]));
break;
default:
- Error (ERR_ILLEGAL_ASSERT_ACTION);
+ Error ("Illegal assert action specifier");
}
NextTok ();
ConsumeComma ();
/* Read the message */
if (Tok != TOK_STRCON) {
- ErrorSkip (ERR_STRCON_EXPECTED);
+ ErrorSkip ("String constant expected");
} else {
AddAssertion (Expr, Action, GetStringId (SVal));
NextTok ();
NextTok ();
/* Do smart handling of dangling comma */
if (Tok == TOK_SEP) {
- Error (ERR_UNEXPECTED_EOL);
+ Error ("Unexpected end of line");
break;
}
}
Index = ConstExpression ();
if (Index < 1 || Index > 255) {
/* Value out of range */
- ErrorSkip (ERR_RANGE);
+ ErrorSkip ("Range error");
return;
}
Code = ConstExpression ();
if (Code < 1 || Code > 255) {
/* Value out of range */
- ErrorSkip (ERR_RANGE);
+ ErrorSkip ("Range error");
return;
}
/* Symbol name follows */
if (Tok != TOK_IDENT) {
- ErrorSkip (ERR_IDENT_EXPECTED);
+ ErrorSkip ("Identifier expected");
return;
}
strcpy (Name, SVal);
/* Check if we got a valid keyword */
if (Type < 0) {
- Error (ERR_SYNTAX);
+ Error ("Syntax error");
SkipUntilSep ();
return;
}
Type = ConstExpression ();
if (Type < CD_TYPE_MIN || Type > CD_TYPE_MAX) {
/* Value out of range */
- Error (ERR_RANGE);
+ Error ("Range error");
return;
}
/* Symbol name follows */
if (Tok != TOK_IDENT) {
- ErrorSkip (ERR_IDENT_EXPECTED);
+ ErrorSkip ("Identifier expected");
return;
}
strcpy (Name, SVal);
/* We expect a subkey */
if (Tok != TOK_IDENT) {
- ErrorSkip (ERR_IDENT_EXPECTED);
+ ErrorSkip ("Identifier expected");
return;
}
case 0: DbgInfoFile (); break;
case 1: DbgInfoLine (); break;
case 2: DbgInfoSym (); break;
- default: ErrorSkip (ERR_SYNTAX); break;
+ default: ErrorSkip ("Syntax error"); break;
}
}
/* Symbol name follows */
if (Tok != TOK_IDENT) {
- ErrorSkip (ERR_IDENT_EXPECTED);
+ ErrorSkip ("Identifier expected");
return;
}
strcpy (Name, SVal);
static void DoEndProc (void)
/* Leave a lexical level */
{
- if (CurrentScope != RootScope) {
- SymLeaveLevel ();
+ if (GetCurrentSymTabType () != ST_PROC) {
+ /* No local scope */
+ ErrorSkip ("No open .PROC");
} else {
+ SymLeaveLevel ();
+ }
+}
+
+
+
+static void DoEndScope (void)
+/* Leave a lexical level */
+{
+ if ( GetCurrentSymTabType () != ST_SCOPE) {
/* No local scope */
- ErrorSkip (ERR_NO_OPEN_PROC);
+ ErrorSkip ("No open .SCOPE");
+ } else {
+ SymLeaveLevel ();
}
}
/* User error */
{
if (Tok != TOK_STRCON) {
- ErrorSkip (ERR_STRCON_EXPECTED);
+ ErrorSkip ("String constant expected");
} else {
- Error (ERR_USER, SVal);
+ Error ("User error: %s", SVal);
SkipUntilSep ();
}
}
/* We expect an identifier */
if (Tok != TOK_IDENT) {
- ErrorSkip (ERR_IDENT_EXPECTED);
+ ErrorSkip ("Identifier expected");
return;
}
/* Set the feature and check for errors */
if (SetFeature (SVal) == FEAT_UNKNOWN) {
/* Not found */
- ErrorSkip (ERR_ILLEGAL_FEATURE);
+ ErrorSkip ("Invalid feature: `%s'", SVal);
return;
} else {
/* Skip the keyword */
OptNum = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
if (OptNum < 0) {
/* Not found */
- ErrorSkip (ERR_OPTION_KEY_EXPECTED);
+ ErrorSkip ("File option keyword expected");
return;
}
/* We accept only string options for now */
if (Tok != TOK_STRCON) {
- ErrorSkip (ERR_STRCON_EXPECTED);
+ ErrorSkip ("String constant expected");
return;
}
/* Option given as number */
OptNum = ConstExpression ();
if (!IsByteRange (OptNum)) {
- ErrorSkip (ERR_RANGE);
+ ErrorSkip ("Range error");
return;
}
/* We accept only string options for now */
if (Tok != TOK_STRCON) {
- ErrorSkip (ERR_STRCON_EXPECTED);
+ ErrorSkip ("String constant expected");
return;
}
/* 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;
/* 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;
/* Name must follow */
if (Tok != TOK_STRCON) {
- ErrorSkip (ERR_STRCON_EXPECTED);
+ ErrorSkip ("String constant expected");
return;
}
strcpy (Name, SVal);
char* PathName = FindInclude (Name);
if (PathName == 0 || (F = fopen (PathName, "r")) == 0) {
/* Not found or cannot open, print an error and bail out */
- ErrorSkip (ERR_CANNOT_OPEN_INCLUDE, Name, strerror (errno));
+ ErrorSkip ("Cannot open include file `%s': %s", Name, strerror (errno));
}
/* Free the allocated memory */
Count = Size - Start;
if (Count < 0) {
/* Nothing to read - flag this as a range error */
- ErrorSkip (ERR_RANGE);
+ ErrorSkip ("Range error");
goto Done;
}
} else {
/* Count was given, check if it is valid */
if (Start + Count > Size) {
- ErrorSkip (ERR_RANGE);
+ ErrorSkip ("Range error");
goto Done;
}
}
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 `%s': %s",
+ Name, strerror (errno));
break;
}
/* Name must follow */
if (Tok != TOK_STRCON) {
- ErrorSkip (ERR_STRCON_EXPECTED);
+ ErrorSkip ("String constant expected");
} else {
strcpy (Name, SVal);
NextTok ();
/* Define the character that starts local labels */
{
if (Tok != TOK_CHARCON) {
- ErrorSkip (ERR_CHARCON_EXPECTED);
+ ErrorSkip ("Character constant expected");
} else {
if (IVal != '@' && IVal != '?') {
- Error (ERR_ILLEGAL_LOCALSTART);
+ Error ("Invalid start character for locals");
} else {
LocalStart = (char) IVal;
}
/* We expect an identifier */
if (Tok != TOK_IDENT) {
- ErrorSkip (ERR_IDENT_EXPECTED);
+ ErrorSkip ("Identifier expected");
return;
}
Package = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
if (Package < 0) {
/* Not found */
- ErrorSkip (ERR_ILLEGAL_MACPACK);
+ ErrorSkip ("Invalid macro package");
return;
}
{
long PC = ConstExpression ();
if (PC < 0 || PC > 0xFFFFFF) {
- Error (ERR_RANGE);
+ Error ("Range error");
return;
}
SetAbsPC (PC);
/* Output a string */
{
if (Tok != TOK_STRCON) {
- ErrorSkip (ERR_STRCON_EXPECTED);
+ 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.
/* Must have a segment on the stack */
if (CollCount (&SegStack) == 0) {
- ErrorSkip (ERR_SEGSTACK_EMPTY);
+ ErrorSkip ("Segment stack is empty");
return;
}
static void DoProc (void)
/* Start a new lexical scope */
{
+ char Name[sizeof(SVal)];
+ unsigned char AddrSize;
+
if (Tok == TOK_IDENT) {
- unsigned AddrSize;
+ SymEntry* Sym;
/* The new scope has a name. Remember it. */
- char Name[sizeof(SVal)];
strcpy (Name, 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 ();
/* Mark the symbol as defined */
SymDef (Sym, GenCurrentPC (), AddrSize, SF_LABEL);
- /* Enter a new scope with the given name */
- SymEnterLevel (Name, AddrSize);
-
} else {
/* A .PROC statement without a name */
- char Buf[sizeof (SVal)];
- SymEnterLevel (AnonName (Buf, sizeof (Buf), "Scope"), ADDR_SIZE_DEFAULT);
- Warning (WARN_UNNAMED_PROC);
+ Warning (1, "Unnamed .PROCs are deprecated, please use .SCOPE");
+ AnonName (Name, sizeof (Name), "PROC");
+ AddrSize = ADDR_SIZE_DEFAULT;
}
+
+ /* Enter a new scope */
+ SymEnterLevel (Name, ST_PROC, AddrSize);
}
{
/* Can only push a limited size of segments */
if (CollCount (&SegStack) >= MAX_PUSHED_SEGMENTS) {
- ErrorSkip (ERR_SEGSTACK_OVERFLOW);
+ ErrorSkip ("Segment stack overflow");
return;
}
Count = ConstExpression ();
if (Count > 0xFFFF || Count < 0) {
- ErrorSkip (ERR_RANGE);
+ ErrorSkip ("Range error");
return;
}
if (Tok == TOK_COMMA) {
Val = ConstExpression ();
/* We need a byte value here */
if (!IsByteRange (Val)) {
- ErrorSkip (ERR_RANGE);
+ ErrorSkip ("Range error");
return;
}
+static void DoScope (void)
+/* Start a local scope */
+{
+ char Name[sizeof (SVal)];
+ unsigned char AddrSize;
+
+
+ if (Tok == TOK_IDENT) {
+
+ /* The new scope has a name. Remember and skip it. */
+ strcpy (Name, SVal);
+ NextTok ();
+
+ } else {
+
+ /* An unnamed scope */
+ AnonName (Name, sizeof (Name), "SCOPE");
+
+ }
+
+ /* Read an optional address size specifier */
+ AddrSize = OptionalAddrSize ();
+
+ /* Enter the new scope */
+ SymEnterLevel (Name, ST_SCOPE, AddrSize);
+
+}
+
+
+
static void DoSegment (void)
/* Switch to another segment */
{
Def.Name = Name;
if (Tok != TOK_STRCON) {
- ErrorSkip (ERR_STRCON_EXPECTED);
+ ErrorSkip ("String constant expected");
} else {
/* Save the name of the segment and skip it */
{
/* We expect an identifier */
if (Tok != TOK_STRCON) {
- ErrorSkip (ERR_STRCON_EXPECTED);
+ ErrorSkip ("String constant expected");
} else {
/* Try to find the CPU, then skip the identifier */
cpu_t CPU = FindCPU (SVal);
-static void DoStruct (void)
-/* Struct definition */
-{
- Error (ERR_NOT_IMPLEMENTED);
-}
-
-
-
static void DoSunPlus (void)
/* Switch to the SUNPLUS CPU */
{
-static void DoUnion (void)
-/* Union definition */
+static void DoTag (void)
+/* Allocate space for a struct */
{
- Error (ERR_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) != ST_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 (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 DoUnexpected (void)
/* Got an unexpected keyword */
{
- Error (ERR_UNEXPECTED, Keyword);
+ Error ("Unexpected `%s'", Keyword);
SkipUntilSep ();
}
/* User warning */
{
if (Tok != TOK_STRCON) {
- ErrorSkip (ERR_STRCON_EXPECTED);
+ ErrorSkip ("String constant expected");
} else {
- Warning (WARN_USER, SVal);
+ Warning (0, "User warning: %s", SVal);
SkipUntilSep ();
}
}
{ ccNone, DoASCIIZ },
{ ccNone, DoAssert },
{ ccNone, DoAutoImport },
+ { ccNone, DoUnexpected }, /* .BANKBYTE */
{ ccNone, DoUnexpected }, /* .BLANK */
{ ccNone, DoBss },
{ ccNone, DoByte },
{ 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, DoUnexpected }, /* .ENDUNION */
+ { ccNone, DoEnum },
{ ccNone, DoError },
{ ccNone, DoExitMacro },
{ ccNone, DoExport },
{ ccNone, DoUnexpected }, /* .FORCEWORD */
{ ccNone, DoGlobal },
{ ccNone, DoGlobalZP },
+ { ccNone, DoUnexpected }, /* .HIBYTE */
+ { ccNone, DoUnexpected }, /* .HIWORD */
{ ccNone, DoI16 },
{ ccNone, DoI8 },
{ ccKeepToken, DoConditionals }, /* .IF */
{ ccNone, DoLineCont },
{ ccNone, DoList },
{ ccNone, DoListBytes },
+ { ccNone, DoUnexpected }, /* .LOBYTE */
{ ccNone, DoUnexpected }, /* .LOCAL */
{ ccNone, DoLocalChar },
+ { ccNone, DoUnexpected }, /* .LOWORD */
{ ccNone, DoMacPack },
{ ccNone, DoMacro },
{ ccNone, DoUnexpected }, /* .MATCH */
{ ccNone, DoP02 },
{ ccNone, DoP816 },
{ ccNone, DoPageLength },
- { ccNone, DoUnexpected }, /* .PARAMCOUNT */
+ { ccNone, DoUnexpected }, /* .PARAMCOUNT */
{ ccNone, DoPC02 },
{ ccNone, DoPopSeg },
{ ccNone, DoProc },
{ ccNone, DoPSC02 },
{ ccNone, DoPushSeg },
- { ccNone, DoUnexpected }, /* .REFERENCED */
+ { ccNone, DoUnexpected }, /* .REFERENCED */
{ ccNone, DoReloc },
{ ccNone, DoRepeat },
{ ccNone, DoRes },
{ ccNone, DoInvalid }, /* .RIGHT */
{ ccNone, DoROData },
+ { ccNone, DoScope },
{ ccNone, DoSegment },
{ ccNone, DoSetCPU },
+ { ccNone, DoUnexpected }, /* .SIZEOF */
{ ccNone, DoSmart },
- { ccNone, DoUnexpected }, /* .STRAT */
- { ccNone, DoUnexpected }, /* .STRING */
- { ccNone, DoUnexpected }, /* .STRLEN */
+ { 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 */
{ ccNone, DoUnion },
{ ccNone, DoUnexpected }, /* .VERSION */
{ ccNone, DoWarning },
{ ccNone, DoWord },
- { ccNone, DoUnexpected }, /* .XMATCH */
+ { 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 */
{
/* Remember the instruction, then skip it if needed */
if ((D->Flags & ccKeepToken) == 0) {
- strcpy (Keyword+1, SVal);
+ strcpy (Keyword, SVal);
NextTok ();
}
/* Check if the segment stack is empty at end of assembly */
{
if (CollCount (&SegStack) != 0) {
- Error (ERR_SEGSTACK_NOT_EMPTY);
+ Error ("Segment stack is not empty");
}
}