2000-05-28 13:40:48 +00:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/* */
|
|
|
|
|
/* pseudo.c */
|
|
|
|
|
/* */
|
|
|
|
|
/* Pseudo instructions for the ca65 macroassembler */
|
|
|
|
|
/* */
|
|
|
|
|
/* */
|
|
|
|
|
/* */
|
2003-01-19 12:04:33 +00:00
|
|
|
|
/* (C) 1998-2003 Ullrich von Bassewitz */
|
2003-02-26 23:17:42 +00:00
|
|
|
|
/* R<>merstrasse 52 */
|
|
|
|
|
/* D-70794 Filderstadt */
|
|
|
|
|
/* EMail: uz@cc65.org */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
/* */
|
|
|
|
|
/* */
|
|
|
|
|
/* This software is provided 'as-is', without any expressed or implied */
|
|
|
|
|
/* warranty. In no event will the authors be held liable for any damages */
|
|
|
|
|
/* arising from the use of this software. */
|
|
|
|
|
/* */
|
|
|
|
|
/* Permission is granted to anyone to use this software for any purpose, */
|
|
|
|
|
/* including commercial applications, and to alter it and redistribute it */
|
|
|
|
|
/* freely, subject to the following restrictions: */
|
|
|
|
|
/* */
|
|
|
|
|
/* 1. The origin of this software must not be misrepresented; you must not */
|
|
|
|
|
/* claim that you wrote the original software. If you use this software */
|
|
|
|
|
/* in a product, an acknowledgment in the product documentation would be */
|
|
|
|
|
/* appreciated but is not required. */
|
|
|
|
|
/* 2. Altered source versions must be plainly marked as such, and must not */
|
|
|
|
|
/* be misrepresented as being the original software. */
|
|
|
|
|
/* 3. This notice may not be removed or altered from any source */
|
|
|
|
|
/* distribution. */
|
|
|
|
|
/* */
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
2003-06-06 21:09:36 +00:00
|
|
|
|
/* common */
|
2003-06-06 20:47:59 +00:00
|
|
|
|
#include "assertdefs.h"
|
2000-07-28 12:15:40 +00:00
|
|
|
|
#include "bitops.h"
|
2000-11-20 15:22:57 +00:00
|
|
|
|
#include "cddefs.h"
|
2002-11-28 17:42:16 +00:00
|
|
|
|
#include "coll.h"
|
2000-10-30 20:48:11 +00:00
|
|
|
|
#include "symdefs.h"
|
2000-08-23 07:01:18 +00:00
|
|
|
|
#include "tgttrans.h"
|
2003-02-26 23:17:42 +00:00
|
|
|
|
#include "xmalloc.h"
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2000-07-28 12:15:40 +00:00
|
|
|
|
/* ca65 */
|
2003-06-06 20:47:59 +00:00
|
|
|
|
#include "asserts.h"
|
2000-05-28 13:40:48 +00:00
|
|
|
|
#include "condasm.h"
|
2000-08-01 21:36:45 +00:00
|
|
|
|
#include "dbginfo.h"
|
2000-05-28 13:40:48 +00:00
|
|
|
|
#include "error.h"
|
|
|
|
|
#include "expr.h"
|
2000-09-02 11:35:22 +00:00
|
|
|
|
#include "feature.h"
|
2000-05-28 13:40:48 +00:00
|
|
|
|
#include "global.h"
|
2003-02-26 23:17:42 +00:00
|
|
|
|
#include "incpath.h"
|
2000-05-28 13:40:48 +00:00
|
|
|
|
#include "instr.h"
|
|
|
|
|
#include "listing.h"
|
|
|
|
|
#include "macpack.h"
|
|
|
|
|
#include "macro.h"
|
2000-06-03 11:15:11 +00:00
|
|
|
|
#include "nexttok.h"
|
2000-05-28 13:40:48 +00:00
|
|
|
|
#include "objcode.h"
|
|
|
|
|
#include "options.h"
|
2003-06-06 12:45:19 +00:00
|
|
|
|
#include "pseudo.h"
|
2000-07-28 12:15:40 +00:00
|
|
|
|
#include "repeat.h"
|
2003-06-06 12:45:19 +00:00
|
|
|
|
#include "spool.h"
|
2000-05-28 13:40:48 +00:00
|
|
|
|
#include "symtab.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/* Data */
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Keyword we're about to handle */
|
|
|
|
|
static char Keyword [sizeof (SVal)+1] = ".";
|
|
|
|
|
|
2002-11-28 17:42:16 +00:00
|
|
|
|
/* Segment stack */
|
|
|
|
|
#define MAX_PUSHED_SEGMENTS 16
|
|
|
|
|
static Collection SegStack = STATIC_COLLECTION_INITIALIZER;
|
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/* Forwards */
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoUnexpected (void);
|
2000-07-08 14:01:43 +00:00
|
|
|
|
/* Got an unexpected keyword */
|
|
|
|
|
|
|
|
|
|
static void DoInvalid (void);
|
|
|
|
|
/* Handle a token that is invalid here, since it should have been handled on
|
|
|
|
|
* a much lower level of the expression hierarchy. Getting this sort of token
|
|
|
|
|
* means that the lower level code has bugs.
|
|
|
|
|
* This function differs to DoUnexpected in that the latter may be triggered
|
|
|
|
|
* by the user by using keywords in the wrong location. DoUnexpected is not
|
|
|
|
|
* an error in the assembler itself, while DoInvalid is.
|
|
|
|
|
*/
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/* Helper functions */
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void SetBoolOption (unsigned char* Flag)
|
|
|
|
|
/* Read a on/off/+/- option and set flag accordingly */
|
|
|
|
|
{
|
|
|
|
|
static const char* Keys[] = {
|
|
|
|
|
"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 (ERR_ONOFF_EXPECTED); break;
|
|
|
|
|
}
|
2003-01-19 12:04:33 +00:00
|
|
|
|
} else if (TokIsSep (Tok)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
/* Without anything assume switch on */
|
|
|
|
|
*Flag = 1;
|
|
|
|
|
} else {
|
|
|
|
|
ErrorSkip (ERR_ONOFF_EXPECTED);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-03-07 11:33:14 +00:00
|
|
|
|
static void ExportImport (void (*SymFunc) (const char*))
|
2000-05-28 13:40:48 +00:00
|
|
|
|
/* Export or import symbols */
|
|
|
|
|
{
|
|
|
|
|
while (1) {
|
|
|
|
|
if (Tok != TOK_IDENT) {
|
|
|
|
|
ErrorSkip (ERR_IDENT_EXPECTED);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2003-03-07 11:33:14 +00:00
|
|
|
|
SymFunc (SVal);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
NextTok ();
|
|
|
|
|
if (Tok == TOK_COMMA) {
|
|
|
|
|
NextTok ();
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static long IntArg (long Min, long Max)
|
|
|
|
|
/* Read an integer argument and check a range. Accept the token "unlimited"
|
|
|
|
|
* and return -1 in this case.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
if (Tok == TOK_IDENT && strcmp (SVal, "unlimited") == 0) {
|
|
|
|
|
NextTok ();
|
|
|
|
|
return -1;
|
|
|
|
|
} else {
|
|
|
|
|
long Val = ConstExpression ();
|
|
|
|
|
if (Val < Min || Val > Max) {
|
|
|
|
|
Error (ERR_RANGE);
|
|
|
|
|
Val = Min;
|
|
|
|
|
}
|
|
|
|
|
return Val;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-11-20 15:22:57 +00:00
|
|
|
|
static void ConDes (const char* Name, unsigned Type)
|
|
|
|
|
/* Parse remaining line for constructor/destructor of the remaining type */
|
|
|
|
|
{
|
|
|
|
|
long Prio;
|
|
|
|
|
|
|
|
|
|
/* 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 (ERR_RANGE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
/* Use the default priority value */
|
|
|
|
|
Prio = CD_PRIO_DEF;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Define the symbol */
|
|
|
|
|
SymConDes (Name, Type, (unsigned) Prio);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/* Handler functions */
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoA16 (void)
|
|
|
|
|
/* Switch the accu to 16 bit mode (assembler only) */
|
|
|
|
|
{
|
|
|
|
|
if (GetCPU() != CPU_65816) {
|
|
|
|
|
Error (ERR_816_MODE_ONLY);
|
|
|
|
|
} else {
|
|
|
|
|
/* Immidiate mode has two extension bytes */
|
|
|
|
|
ExtBytes [AMI_IMM_ACCU] = 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoA8 (void)
|
|
|
|
|
/* Switch the accu to 8 bit mode (assembler only) */
|
|
|
|
|
{
|
|
|
|
|
if (GetCPU() != CPU_65816) {
|
|
|
|
|
Error (ERR_816_MODE_ONLY);
|
|
|
|
|
} else {
|
|
|
|
|
/* Immidiate mode has one extension byte */
|
|
|
|
|
ExtBytes [AMI_IMM_ACCU] = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoAddr (void)
|
|
|
|
|
/* Define addresses */
|
|
|
|
|
{
|
|
|
|
|
while (1) {
|
|
|
|
|
if (GetCPU() == CPU_65816) {
|
2003-06-06 21:09:36 +00:00
|
|
|
|
EmitWord (GenWordExpr (Expression ()));
|
2000-05-28 13:40:48 +00:00
|
|
|
|
} else {
|
|
|
|
|
/* Do a range check */
|
|
|
|
|
EmitWord (Expression ());
|
|
|
|
|
}
|
|
|
|
|
if (Tok != TOK_COMMA) {
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
NextTok ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoAlign (void)
|
|
|
|
|
/* Align the PC to some boundary */
|
|
|
|
|
{
|
|
|
|
|
long Val;
|
|
|
|
|
long Align;
|
|
|
|
|
unsigned Bit;
|
|
|
|
|
|
|
|
|
|
/* Read the alignment value */
|
|
|
|
|
Align = ConstExpression ();
|
|
|
|
|
if (Align <= 0 || Align > 0x10000) {
|
|
|
|
|
ErrorSkip (ERR_RANGE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Optional value follows */
|
|
|
|
|
if (Tok == TOK_COMMA) {
|
|
|
|
|
NextTok ();
|
|
|
|
|
Val = ConstExpression ();
|
|
|
|
|
/* We need a byte value here */
|
|
|
|
|
if (!IsByteRange (Val)) {
|
|
|
|
|
ErrorSkip (ERR_RANGE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
Val = -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check if the alignment is a power of two */
|
|
|
|
|
Bit = BitFind (Align);
|
2000-06-08 21:02:46 +00:00
|
|
|
|
if (Align != (0x01L << Bit)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
Error (ERR_ALIGN);
|
|
|
|
|
} else {
|
|
|
|
|
SegAlign (Bit, (int) Val);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoASCIIZ (void)
|
|
|
|
|
/* Define text with a zero terminator */
|
|
|
|
|
{
|
2000-11-29 15:22:06 +00:00
|
|
|
|
unsigned Len;
|
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
|
while (1) {
|
2000-11-29 15:22:06 +00:00
|
|
|
|
/* Must have a string constant */
|
2000-06-23 20:49:47 +00:00
|
|
|
|
if (Tok != TOK_STRCON) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
ErrorSkip (ERR_STRCON_EXPECTED);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2000-11-29 15:22:06 +00:00
|
|
|
|
|
|
|
|
|
/* Get the length of the string constant */
|
|
|
|
|
Len = strlen (SVal);
|
|
|
|
|
|
2000-08-21 21:20:40 +00:00
|
|
|
|
/* Translate into target charset and emit */
|
2001-03-23 17:56:28 +00:00
|
|
|
|
TgtTranslateBuf (SVal, Len);
|
|
|
|
|
EmitData ((unsigned char*) SVal, Len);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
NextTok ();
|
|
|
|
|
if (Tok == TOK_COMMA) {
|
|
|
|
|
NextTok ();
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Emit0 (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-06-06 12:45:19 +00:00
|
|
|
|
static void DoAssert (void)
|
|
|
|
|
/* Add an assertion */
|
|
|
|
|
{
|
|
|
|
|
static const char* ActionTab [] = {
|
|
|
|
|
"WARN", "WARNING",
|
|
|
|
|
"ERROR"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int Action;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* First we have the expression that has to evaluated */
|
|
|
|
|
ExprNode* Expr = Expression ();
|
|
|
|
|
ConsumeComma ();
|
|
|
|
|
|
|
|
|
|
/* Action follows */
|
|
|
|
|
if (Tok != TOK_IDENT) {
|
|
|
|
|
ErrorSkip (ERR_IDENT_EXPECTED);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
Action = GetSubKey (ActionTab, sizeof (ActionTab) / sizeof (ActionTab[0]));
|
|
|
|
|
switch (Action) {
|
|
|
|
|
|
|
|
|
|
case 0:
|
|
|
|
|
case 1:
|
|
|
|
|
/* Warning */
|
2003-06-06 20:47:59 +00:00
|
|
|
|
Action = ASSERT_ACT_WARN;
|
2003-06-06 12:45:19 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
|
/* Error */
|
2003-06-06 20:47:59 +00:00
|
|
|
|
Action = ASSERT_ACT_ERROR;
|
2003-06-06 12:45:19 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
Error (ERR_ILLEGAL_SEG_ATTR);
|
|
|
|
|
}
|
|
|
|
|
NextTok ();
|
|
|
|
|
ConsumeComma ();
|
|
|
|
|
|
|
|
|
|
/* Read the message */
|
|
|
|
|
if (Tok != TOK_STRCON) {
|
|
|
|
|
ErrorSkip (ERR_STRCON_EXPECTED);
|
|
|
|
|
} else {
|
|
|
|
|
AddAssertion (Expr, Action, GetStringId (SVal));
|
|
|
|
|
NextTok ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
|
static void DoAutoImport (void)
|
|
|
|
|
/* Mark unresolved symbols as imported */
|
|
|
|
|
{
|
|
|
|
|
SetBoolOption (&AutoImport);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoBss (void)
|
|
|
|
|
/* Switch to the BSS segment */
|
|
|
|
|
{
|
2002-11-28 17:42:16 +00:00
|
|
|
|
UseSeg (&BssSegDef);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoByte (void)
|
|
|
|
|
/* Define bytes */
|
|
|
|
|
{
|
|
|
|
|
while (1) {
|
2000-06-23 20:49:47 +00:00
|
|
|
|
if (Tok == TOK_STRCON) {
|
2000-08-21 21:20:40 +00:00
|
|
|
|
/* A string, translate into target charset and emit */
|
2000-11-29 15:22:06 +00:00
|
|
|
|
unsigned Len = strlen (SVal);
|
2001-03-23 17:56:28 +00:00
|
|
|
|
TgtTranslateBuf (SVal, Len);
|
|
|
|
|
EmitData ((unsigned char*) SVal, Len);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
NextTok ();
|
|
|
|
|
} else {
|
|
|
|
|
EmitByte (Expression ());
|
|
|
|
|
}
|
|
|
|
|
if (Tok != TOK_COMMA) {
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
NextTok ();
|
|
|
|
|
/* Do smart handling of dangling comma */
|
|
|
|
|
if (Tok == TOK_SEP) {
|
2000-11-20 15:22:57 +00:00
|
|
|
|
Error (ERR_UNEXPECTED_EOL);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoCase (void)
|
|
|
|
|
/* Switch the IgnoreCase option */
|
|
|
|
|
{
|
|
|
|
|
SetBoolOption (&IgnoreCase);
|
|
|
|
|
IgnoreCase = !IgnoreCase;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2002-02-18 09:11:57 +00:00
|
|
|
|
static void DoCharMap (void)
|
|
|
|
|
/* Allow custome character mappings */
|
|
|
|
|
{
|
|
|
|
|
long Index;
|
|
|
|
|
long Code;
|
|
|
|
|
|
|
|
|
|
/* Read the index as numerical value */
|
|
|
|
|
Index = ConstExpression ();
|
|
|
|
|
if (Index < 1 || Index > 255) {
|
|
|
|
|
/* Value out of range */
|
|
|
|
|
ErrorSkip (ERR_RANGE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Comma follows */
|
|
|
|
|
ConsumeComma ();
|
|
|
|
|
|
|
|
|
|
/* Read the character code */
|
|
|
|
|
Code = ConstExpression ();
|
|
|
|
|
if (Code < 1 || Code > 255) {
|
|
|
|
|
/* Value out of range */
|
|
|
|
|
ErrorSkip (ERR_RANGE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Set the character translation */
|
|
|
|
|
TgtTranslateSet ((unsigned) Index, (unsigned char) Code);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
|
static void DoCode (void)
|
|
|
|
|
/* Switch to the code segment */
|
|
|
|
|
{
|
2002-11-28 17:42:16 +00:00
|
|
|
|
UseSeg (&CodeSegDef);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-11-20 15:22:57 +00:00
|
|
|
|
static void DoConDes (void)
|
|
|
|
|
/* Export a symbol as constructor/destructor */
|
|
|
|
|
{
|
|
|
|
|
static const char* Keys[] = {
|
|
|
|
|
"CONSTRUCTOR",
|
|
|
|
|
"DESTRUCTOR",
|
|
|
|
|
};
|
|
|
|
|
char Name [sizeof (SVal)];
|
|
|
|
|
long Type;
|
|
|
|
|
|
|
|
|
|
/* Symbol name follows */
|
|
|
|
|
if (Tok != TOK_IDENT) {
|
|
|
|
|
ErrorSkip (ERR_IDENT_EXPECTED);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
strcpy (Name, SVal);
|
|
|
|
|
NextTok ();
|
|
|
|
|
|
|
|
|
|
/* Type follows. May be encoded as identifier or numerical */
|
|
|
|
|
ConsumeComma ();
|
|
|
|
|
if (Tok == TOK_IDENT) {
|
|
|
|
|
|
|
|
|
|
/* Map the following keyword to a number, then skip it */
|
|
|
|
|
Type = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
|
|
|
|
|
NextTok ();
|
|
|
|
|
|
|
|
|
|
/* Check if we got a valid keyword */
|
|
|
|
|
if (Type < 0) {
|
|
|
|
|
Error (ERR_SYNTAX);
|
|
|
|
|
SkipUntilSep ();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
/* Read the type as numerical value */
|
|
|
|
|
Type = ConstExpression ();
|
|
|
|
|
if (Type < CD_TYPE_MIN || Type > CD_TYPE_MAX) {
|
|
|
|
|
/* Value out of range */
|
|
|
|
|
Error (ERR_RANGE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Parse the remainder of the line and export the symbol */
|
|
|
|
|
ConDes (Name, (unsigned) Type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoConstructor (void)
|
|
|
|
|
/* Export a symbol as constructor */
|
|
|
|
|
{
|
|
|
|
|
char Name [sizeof (SVal)];
|
|
|
|
|
|
|
|
|
|
/* Symbol name follows */
|
|
|
|
|
if (Tok != TOK_IDENT) {
|
|
|
|
|
ErrorSkip (ERR_IDENT_EXPECTED);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
strcpy (Name, SVal);
|
|
|
|
|
NextTok ();
|
|
|
|
|
|
|
|
|
|
/* Parse the remainder of the line and export the symbol */
|
|
|
|
|
ConDes (Name, CD_TYPE_CON);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
|
static void DoData (void)
|
|
|
|
|
/* Switch to the data segment */
|
|
|
|
|
{
|
2002-11-28 17:42:16 +00:00
|
|
|
|
UseSeg (&DataSegDef);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-08-01 21:36:45 +00:00
|
|
|
|
static void DoDbg (void)
|
|
|
|
|
/* Add debug information from high level code */
|
|
|
|
|
{
|
|
|
|
|
static const char* Keys[] = {
|
|
|
|
|
"FILE",
|
|
|
|
|
"LINE",
|
|
|
|
|
"SYM",
|
|
|
|
|
};
|
|
|
|
|
int Key;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* We expect a subkey */
|
|
|
|
|
if (Tok != TOK_IDENT) {
|
|
|
|
|
ErrorSkip (ERR_IDENT_EXPECTED);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Map the following keyword to a number */
|
|
|
|
|
Key = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
|
|
|
|
|
|
|
|
|
|
/* Skip the subkey */
|
|
|
|
|
NextTok ();
|
2000-08-02 13:23:06 +00:00
|
|
|
|
|
2000-08-01 21:36:45 +00:00
|
|
|
|
/* Check the key and dispatch to a handler */
|
|
|
|
|
switch (Key) {
|
|
|
|
|
case 0: DbgInfoFile (); break;
|
2000-08-02 13:23:06 +00:00
|
|
|
|
case 1: DbgInfoLine (); break;
|
|
|
|
|
case 2: DbgInfoSym (); break;
|
2000-08-01 21:36:45 +00:00
|
|
|
|
default: ErrorSkip (ERR_SYNTAX); break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
|
static void DoDByt (void)
|
|
|
|
|
/* Output double bytes */
|
|
|
|
|
{
|
|
|
|
|
while (1) {
|
2003-06-06 21:09:36 +00:00
|
|
|
|
EmitWord (GenSwapExpr (Expression ()));
|
2000-05-28 13:40:48 +00:00
|
|
|
|
if (Tok != TOK_COMMA) {
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
NextTok ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoDebugInfo (void)
|
|
|
|
|
/* Switch debug info on or off */
|
|
|
|
|
{
|
|
|
|
|
SetBoolOption (&DbgSyms);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoDefine (void)
|
|
|
|
|
/* Define a one line macro */
|
|
|
|
|
{
|
|
|
|
|
MacDef (MAC_STYLE_DEFINE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-11-20 15:22:57 +00:00
|
|
|
|
static void DoDestructor (void)
|
|
|
|
|
/* Export a symbol as destructor */
|
|
|
|
|
{
|
|
|
|
|
char Name [sizeof (SVal)];
|
|
|
|
|
|
|
|
|
|
/* Symbol name follows */
|
|
|
|
|
if (Tok != TOK_IDENT) {
|
|
|
|
|
ErrorSkip (ERR_IDENT_EXPECTED);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
strcpy (Name, SVal);
|
|
|
|
|
NextTok ();
|
|
|
|
|
|
|
|
|
|
/* Parse the remainder of the line and export the symbol */
|
|
|
|
|
ConDes (Name, CD_TYPE_DES);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
|
static void DoDWord (void)
|
|
|
|
|
/* Define dwords */
|
|
|
|
|
{
|
|
|
|
|
while (1) {
|
|
|
|
|
EmitDWord (Expression ());
|
|
|
|
|
if (Tok != TOK_COMMA) {
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
NextTok ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoEnd (void)
|
|
|
|
|
/* End of assembly */
|
|
|
|
|
{
|
|
|
|
|
ForcedEnd = 1;
|
2003-04-25 20:21:38 +00:00
|
|
|
|
NextTok ();
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoEndProc (void)
|
|
|
|
|
/* Leave a lexical level */
|
2003-03-17 10:19:53 +00:00
|
|
|
|
{
|
2003-03-17 10:14:43 +00:00
|
|
|
|
if (!SymIsLocalLevel ()) {
|
2003-03-17 10:19:53 +00:00
|
|
|
|
/* No local scope */
|
2003-03-17 10:14:43 +00:00
|
|
|
|
ErrorSkip (ERR_NO_OPEN_PROC);
|
|
|
|
|
} else {
|
|
|
|
|
SymLeaveLevel ();
|
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoError (void)
|
2000-07-27 06:38:36 +00:00
|
|
|
|
/* User error */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
{
|
2000-07-27 06:38:22 +00:00
|
|
|
|
if (Tok != TOK_STRCON) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
ErrorSkip (ERR_STRCON_EXPECTED);
|
|
|
|
|
} else {
|
|
|
|
|
Error (ERR_USER, SVal);
|
|
|
|
|
SkipUntilSep ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoExitMacro (void)
|
|
|
|
|
/* Exit a macro expansion */
|
|
|
|
|
{
|
|
|
|
|
if (!InMacExpansion ()) {
|
|
|
|
|
/* We aren't expanding a macro currently */
|
|
|
|
|
DoUnexpected ();
|
|
|
|
|
} else {
|
|
|
|
|
MacAbort ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoExport (void)
|
|
|
|
|
/* Export a symbol */
|
|
|
|
|
{
|
2003-03-07 11:33:14 +00:00
|
|
|
|
ExportImport (SymExport);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoExportZP (void)
|
|
|
|
|
/* Export a zeropage symbol */
|
|
|
|
|
{
|
2003-03-07 11:33:14 +00:00
|
|
|
|
ExportImport (SymExportZP);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoFarAddr (void)
|
|
|
|
|
/* Define far addresses (24 bit) */
|
|
|
|
|
{
|
|
|
|
|
while (1) {
|
|
|
|
|
EmitFarAddr (Expression ());
|
|
|
|
|
if (Tok != TOK_COMMA) {
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
NextTok ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoFeature (void)
|
|
|
|
|
/* Switch the Feature option */
|
|
|
|
|
{
|
|
|
|
|
/* Allow a list of comma separated keywords */
|
|
|
|
|
while (1) {
|
|
|
|
|
|
|
|
|
|
/* We expect an identifier */
|
|
|
|
|
if (Tok != TOK_IDENT) {
|
|
|
|
|
ErrorSkip (ERR_IDENT_EXPECTED);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2000-09-02 11:35:22 +00:00
|
|
|
|
/* Make the string attribute lower case */
|
|
|
|
|
LocaseSVal ();
|
|
|
|
|
|
|
|
|
|
/* Set the feature and check for errors */
|
|
|
|
|
if (SetFeature (SVal) == FEAT_UNKNOWN) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
/* Not found */
|
|
|
|
|
ErrorSkip (ERR_ILLEGAL_FEATURE);
|
|
|
|
|
return;
|
2000-09-02 11:35:22 +00:00
|
|
|
|
} else {
|
|
|
|
|
/* Skip the keyword */
|
|
|
|
|
NextTok ();
|
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
/* Allow more than one keyword */
|
|
|
|
|
if (Tok == TOK_COMMA) {
|
|
|
|
|
NextTok ();
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoFileOpt (void)
|
|
|
|
|
/* Insert a file option */
|
|
|
|
|
{
|
|
|
|
|
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 (ERR_OPTION_KEY_EXPECTED);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Skip the keyword */
|
|
|
|
|
NextTok ();
|
|
|
|
|
|
|
|
|
|
/* Must be followed by a comma */
|
|
|
|
|
ConsumeComma ();
|
|
|
|
|
|
|
|
|
|
/* We accept only string options for now */
|
2000-06-23 20:49:47 +00:00
|
|
|
|
if (Tok != TOK_STRCON) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
ErrorSkip (ERR_STRCON_EXPECTED);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Insert the option */
|
|
|
|
|
switch (OptNum) {
|
|
|
|
|
|
|
|
|
|
case 0:
|
|
|
|
|
/* Author */
|
|
|
|
|
OptAuthor (SVal);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
|
/* Comment */
|
|
|
|
|
OptComment (SVal);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
|
/* Compiler */
|
|
|
|
|
OptCompiler (SVal);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
Internal ("Invalid OptNum: %l", OptNum);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Done */
|
|
|
|
|
NextTok ();
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
/* Option given as number */
|
|
|
|
|
OptNum = ConstExpression ();
|
|
|
|
|
if (!IsByteRange (OptNum)) {
|
|
|
|
|
ErrorSkip (ERR_RANGE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Must be followed by a comma */
|
|
|
|
|
ConsumeComma ();
|
|
|
|
|
|
|
|
|
|
/* We accept only string options for now */
|
2000-06-23 20:49:47 +00:00
|
|
|
|
if (Tok != TOK_STRCON) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
ErrorSkip (ERR_STRCON_EXPECTED);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Insert the option */
|
|
|
|
|
OptStr ((unsigned char) OptNum, SVal);
|
|
|
|
|
|
|
|
|
|
/* Done */
|
|
|
|
|
NextTok ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-03-07 11:33:14 +00:00
|
|
|
|
static void DoForceImport (void)
|
|
|
|
|
/* Do a forced import on a symbol */
|
|
|
|
|
{
|
|
|
|
|
ExportImport (SymImportForced);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
|
static void DoGlobal (void)
|
|
|
|
|
/* Declare a global symbol */
|
|
|
|
|
{
|
2003-03-07 11:33:14 +00:00
|
|
|
|
ExportImport (SymGlobal);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoGlobalZP (void)
|
|
|
|
|
/* Declare a global zeropage symbol */
|
|
|
|
|
{
|
2003-03-07 11:33:14 +00:00
|
|
|
|
ExportImport (SymGlobalZP);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoI16 (void)
|
|
|
|
|
/* Switch the index registers to 16 bit mode (assembler only) */
|
|
|
|
|
{
|
|
|
|
|
if (GetCPU() != CPU_65816) {
|
|
|
|
|
Error (ERR_816_MODE_ONLY);
|
|
|
|
|
} else {
|
|
|
|
|
/* Immidiate mode has two extension bytes */
|
|
|
|
|
ExtBytes [AMI_IMM_INDEX] = 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoI8 (void)
|
|
|
|
|
/* Switch the index registers to 16 bit mode (assembler only) */
|
|
|
|
|
{
|
|
|
|
|
if (GetCPU() != CPU_65816) {
|
|
|
|
|
Error (ERR_816_MODE_ONLY);
|
|
|
|
|
} else {
|
|
|
|
|
/* Immidiate mode has one extension byte */
|
|
|
|
|
ExtBytes [AMI_IMM_INDEX] = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoImport (void)
|
|
|
|
|
/* Import a symbol */
|
|
|
|
|
{
|
2003-03-07 11:33:14 +00:00
|
|
|
|
ExportImport (SymImport);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoImportZP (void)
|
|
|
|
|
/* Import a zero page symbol */
|
|
|
|
|
{
|
2003-03-07 11:33:14 +00:00
|
|
|
|
ExportImport (SymImportZP);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoIncBin (void)
|
|
|
|
|
/* Include a binary file */
|
|
|
|
|
{
|
2001-03-09 23:12:34 +00:00
|
|
|
|
char Name [sizeof (SVal)];
|
|
|
|
|
long Start = 0L;
|
|
|
|
|
long Count = -1L;
|
|
|
|
|
long Size;
|
|
|
|
|
FILE* F;
|
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
|
/* Name must follow */
|
2000-06-23 20:49:47 +00:00
|
|
|
|
if (Tok != TOK_STRCON) {
|
2001-03-09 23:12:34 +00:00
|
|
|
|
ErrorSkip (ERR_STRCON_EXPECTED);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
strcpy (Name, SVal);
|
|
|
|
|
NextTok ();
|
|
|
|
|
|
|
|
|
|
/* A starting offset may follow */
|
|
|
|
|
if (Tok == TOK_COMMA) {
|
|
|
|
|
NextTok ();
|
|
|
|
|
Start = ConstExpression ();
|
|
|
|
|
|
|
|
|
|
/* And a length may follow */
|
|
|
|
|
if (Tok == TOK_COMMA) {
|
|
|
|
|
NextTok ();
|
|
|
|
|
Count = ConstExpression ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Try to open the file */
|
|
|
|
|
F = fopen (Name, "rb");
|
|
|
|
|
if (F == 0) {
|
2003-02-26 23:17:42 +00:00
|
|
|
|
|
|
|
|
|
/* 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 (ERR_CANNOT_OPEN_INCLUDE, Name, strerror (errno));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Free the allocated memory */
|
|
|
|
|
xfree (PathName);
|
|
|
|
|
|
|
|
|
|
/* If we had an error before, bail out now */
|
|
|
|
|
if (F == 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2001-03-09 23:12:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get the size of the file */
|
|
|
|
|
fseek (F, 0, SEEK_END);
|
|
|
|
|
Size = ftell (F);
|
|
|
|
|
|
|
|
|
|
/* If a count was not given, calculate it now */
|
|
|
|
|
if (Count < 0) {
|
|
|
|
|
Count = Size - Start;
|
|
|
|
|
if (Count < 0) {
|
|
|
|
|
/* Nothing to read - flag this as a range error */
|
|
|
|
|
ErrorSkip (ERR_RANGE);
|
|
|
|
|
goto Done;
|
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
} else {
|
2001-03-09 23:12:34 +00:00
|
|
|
|
/* Count was given, check if it is valid */
|
|
|
|
|
if (Start + Count > Size) {
|
|
|
|
|
ErrorSkip (ERR_RANGE);
|
|
|
|
|
goto Done;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2001-03-09 23:12:34 +00:00
|
|
|
|
|
|
|
|
|
/* Seek to the start position */
|
|
|
|
|
fseek (F, Start, SEEK_SET);
|
|
|
|
|
|
|
|
|
|
/* Read chunks and insert them into the output */
|
|
|
|
|
while (Count > 0) {
|
|
|
|
|
|
|
|
|
|
unsigned char Buf [1024];
|
|
|
|
|
|
|
|
|
|
/* Calculate the number of bytes to read */
|
|
|
|
|
size_t BytesToRead = (Count > (long)sizeof(Buf))? sizeof(Buf) : (size_t) Count;
|
|
|
|
|
|
|
|
|
|
/* Read chunk */
|
|
|
|
|
size_t BytesRead = fread (Buf, 1, BytesToRead, F);
|
|
|
|
|
if (BytesToRead != BytesRead) {
|
|
|
|
|
/* Some sort of error */
|
|
|
|
|
ErrorSkip (ERR_CANNOT_READ_INCLUDE, Name, strerror (errno));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Insert it into the output */
|
2001-04-30 15:42:52 +00:00
|
|
|
|
EmitData (Buf, BytesRead);
|
2001-03-09 23:12:34 +00:00
|
|
|
|
|
|
|
|
|
/* Keep the counters current */
|
|
|
|
|
Count -= BytesRead;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Done:
|
|
|
|
|
/* Close the file, ignore errors since it's r/o */
|
|
|
|
|
(void) fclose (F);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoInclude (void)
|
|
|
|
|
/* Include another file */
|
|
|
|
|
{
|
|
|
|
|
char Name [MAX_STR_LEN+1];
|
|
|
|
|
|
|
|
|
|
/* Name must follow */
|
2000-06-23 20:49:47 +00:00
|
|
|
|
if (Tok != TOK_STRCON) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
ErrorSkip (ERR_STRCON_EXPECTED);
|
|
|
|
|
} else {
|
2000-10-30 20:48:11 +00:00
|
|
|
|
strcpy (Name, SVal);
|
|
|
|
|
NextTok ();
|
|
|
|
|
NewInputFile (Name);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-07-08 14:01:43 +00:00
|
|
|
|
static void DoInvalid (void)
|
|
|
|
|
/* Handle a token that is invalid here, since it should have been handled on
|
|
|
|
|
* a much lower level of the expression hierarchy. Getting this sort of token
|
|
|
|
|
* means that the lower level code has bugs.
|
|
|
|
|
* This function differs to DoUnexpected in that the latter may be triggered
|
|
|
|
|
* by the user by using keywords in the wrong location. DoUnexpected is not
|
|
|
|
|
* an error in the assembler itself, while DoInvalid is.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
Internal ("Unexpected token: %s", Keyword);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
|
static void DoLineCont (void)
|
|
|
|
|
/* Switch the use of line continuations */
|
|
|
|
|
{
|
|
|
|
|
SetBoolOption (&LineCont);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoList (void)
|
|
|
|
|
/* Enable/disable the listing */
|
|
|
|
|
{
|
|
|
|
|
/* Get the setting */
|
|
|
|
|
unsigned char List;
|
|
|
|
|
SetBoolOption (&List);
|
|
|
|
|
|
|
|
|
|
/* Manage the counter */
|
|
|
|
|
if (List) {
|
|
|
|
|
EnableListing ();
|
|
|
|
|
} else {
|
|
|
|
|
DisableListing ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoListBytes (void)
|
|
|
|
|
/* Set maximum number of bytes to list for one line */
|
|
|
|
|
{
|
|
|
|
|
SetListBytes (IntArg (MIN_LIST_BYTES, MAX_LIST_BYTES));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoLocalChar (void)
|
|
|
|
|
/* Define the character that starts local labels */
|
|
|
|
|
{
|
|
|
|
|
if (Tok != TOK_CHARCON) {
|
|
|
|
|
ErrorSkip (ERR_CHARCON_EXPECTED);
|
|
|
|
|
} else {
|
|
|
|
|
if (IVal != '@' && IVal != '?') {
|
|
|
|
|
Error (ERR_ILLEGAL_LOCALSTART);
|
|
|
|
|
} else {
|
2000-06-08 21:02:46 +00:00
|
|
|
|
LocalStart = (char) IVal;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
NextTok ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoMacPack (void)
|
|
|
|
|
/* Insert a macro package */
|
|
|
|
|
{
|
|
|
|
|
/* Macro package names */
|
|
|
|
|
static const char* Keys [] = {
|
2003-05-04 21:25:55 +00:00
|
|
|
|
"GENERIC",
|
2000-05-28 13:40:48 +00:00
|
|
|
|
"LONGBRANCH",
|
2003-05-04 21:25:55 +00:00
|
|
|
|
"CBM"
|
2000-05-28 13:40:48 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int Package;
|
|
|
|
|
|
|
|
|
|
/* We expect an identifier */
|
|
|
|
|
if (Tok != TOK_IDENT) {
|
|
|
|
|
ErrorSkip (ERR_IDENT_EXPECTED);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Map the keyword to a number */
|
|
|
|
|
Package = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
|
|
|
|
|
if (Package < 0) {
|
|
|
|
|
/* Not found */
|
|
|
|
|
ErrorSkip (ERR_ILLEGAL_MACPACK);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Skip the package name */
|
|
|
|
|
NextTok ();
|
|
|
|
|
|
|
|
|
|
/* Insert the package */
|
|
|
|
|
InsertMacPack (Package);
|
2003-06-06 12:45:19 +00:00
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoMacro (void)
|
|
|
|
|
/* Start a macro definition */
|
|
|
|
|
{
|
|
|
|
|
MacDef (MAC_STYLE_CLASSIC);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoNull (void)
|
|
|
|
|
/* Switch to the NULL segment */
|
|
|
|
|
{
|
2002-11-28 17:42:16 +00:00
|
|
|
|
UseSeg (&NullSegDef);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoOrg (void)
|
|
|
|
|
/* Start absolute code */
|
|
|
|
|
{
|
|
|
|
|
long PC = ConstExpression ();
|
2000-09-02 11:05:32 +00:00
|
|
|
|
if (PC < 0 || PC > 0xFFFFFF) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
Error (ERR_RANGE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
SetAbsPC (PC);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoOut (void)
|
|
|
|
|
/* Output a string */
|
|
|
|
|
{
|
2000-06-23 20:49:47 +00:00
|
|
|
|
if (Tok != TOK_STRCON) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
ErrorSkip (ERR_STRCON_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 ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoP02 (void)
|
|
|
|
|
/* Switch to 6502 CPU */
|
|
|
|
|
{
|
|
|
|
|
SetCPU (CPU_6502);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoPC02 (void)
|
|
|
|
|
/* Switch to 65C02 CPU */
|
|
|
|
|
{
|
|
|
|
|
SetCPU (CPU_65C02);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoP816 (void)
|
|
|
|
|
/* Switch to 65816 CPU */
|
|
|
|
|
{
|
|
|
|
|
SetCPU (CPU_65816);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoPageLength (void)
|
|
|
|
|
/* Set the page length for the listing */
|
|
|
|
|
{
|
|
|
|
|
PageLength = IntArg (MIN_PAGE_LEN, MAX_PAGE_LEN);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2002-11-28 17:42:16 +00:00
|
|
|
|
static void DoPopSeg (void)
|
|
|
|
|
/* Pop an old segment from the segment stack */
|
|
|
|
|
{
|
|
|
|
|
SegDef* Def;
|
|
|
|
|
|
|
|
|
|
/* Must have a segment on the stack */
|
|
|
|
|
if (CollCount (&SegStack) == 0) {
|
|
|
|
|
ErrorSkip (ERR_SEGSTACK_EMPTY);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Pop the last element */
|
|
|
|
|
Def = CollPop (&SegStack);
|
|
|
|
|
|
|
|
|
|
/* Restore this segment */
|
|
|
|
|
UseSeg (Def);
|
|
|
|
|
|
|
|
|
|
/* Delete the segment definition */
|
|
|
|
|
FreeSegDef (Def);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
|
static void DoProc (void)
|
|
|
|
|
/* Start a new lexical scope */
|
|
|
|
|
{
|
|
|
|
|
if (Tok == TOK_IDENT) {
|
|
|
|
|
/* The new scope has a name */
|
2003-06-06 21:09:36 +00:00
|
|
|
|
SymDef (SVal, GenCurrentPC (), IsZPSeg (), 1);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
NextTok ();
|
|
|
|
|
}
|
|
|
|
|
SymEnterLevel ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-08-07 08:13:46 +00:00
|
|
|
|
static void DoPSC02 (void)
|
|
|
|
|
/* Switch to 65SC02 CPU */
|
|
|
|
|
{
|
|
|
|
|
SetCPU (CPU_65SC02);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2002-11-28 17:42:16 +00:00
|
|
|
|
static void DoPushSeg (void)
|
|
|
|
|
/* Push the current segment onto the segment stack */
|
|
|
|
|
{
|
|
|
|
|
/* Can only push a limited size of segments */
|
|
|
|
|
if (CollCount (&SegStack) >= MAX_PUSHED_SEGMENTS) {
|
|
|
|
|
ErrorSkip (ERR_SEGSTACK_OVERFLOW);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get the current segment and push it */
|
|
|
|
|
CollAppend (&SegStack, DupSegDef (GetCurrentSeg ()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
|
static void DoReloc (void)
|
|
|
|
|
/* Enter relocatable mode */
|
|
|
|
|
{
|
|
|
|
|
RelocMode = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoRepeat (void)
|
|
|
|
|
/* Repeat some instruction block */
|
|
|
|
|
{
|
2000-07-28 12:15:40 +00:00
|
|
|
|
ParseRepeat ();
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoRes (void)
|
|
|
|
|
/* Reserve some number of storage bytes */
|
|
|
|
|
{
|
|
|
|
|
long Count;
|
|
|
|
|
long Val;
|
|
|
|
|
|
|
|
|
|
Count = ConstExpression ();
|
|
|
|
|
if (Count > 0xFFFF || Count < 0) {
|
|
|
|
|
ErrorSkip (ERR_RANGE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (Tok == TOK_COMMA) {
|
|
|
|
|
NextTok ();
|
|
|
|
|
Val = ConstExpression ();
|
|
|
|
|
/* We need a byte value here */
|
|
|
|
|
if (!IsByteRange (Val)) {
|
|
|
|
|
ErrorSkip (ERR_RANGE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Emit constant values */
|
|
|
|
|
while (Count--) {
|
|
|
|
|
Emit0 ((unsigned char) Val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
/* Emit fill fragments */
|
|
|
|
|
EmitFill (Count);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoROData (void)
|
|
|
|
|
/* Switch to the r/o data segment */
|
|
|
|
|
{
|
2002-11-28 17:42:16 +00:00
|
|
|
|
UseSeg (&RODataSegDef);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoSegment (void)
|
|
|
|
|
/* Switch to another segment */
|
|
|
|
|
{
|
|
|
|
|
static const char* AttrTab [] = {
|
|
|
|
|
"ZEROPAGE", "DIRECT",
|
|
|
|
|
"ABSOLUTE",
|
|
|
|
|
"FAR", "LONG"
|
|
|
|
|
};
|
|
|
|
|
char Name [sizeof (SVal)];
|
2002-12-12 21:53:26 +00:00
|
|
|
|
SegDef Def;
|
|
|
|
|
Def.Name = Name;
|
|
|
|
|
Def.Type = SEGTYPE_DEFAULT;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2000-06-23 20:49:47 +00:00
|
|
|
|
if (Tok != TOK_STRCON) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
ErrorSkip (ERR_STRCON_EXPECTED);
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
/* Save the name of the segment and skip it */
|
|
|
|
|
strcpy (Name, SVal);
|
|
|
|
|
NextTok ();
|
|
|
|
|
|
2003-08-07 08:13:46 +00:00
|
|
|
|
/* Check for an optional segment attribute */
|
|
|
|
|
if (Tok == TOK_COMMA) {
|
|
|
|
|
NextTok ();
|
|
|
|
|
if (Tok != TOK_IDENT) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
ErrorSkip (ERR_IDENT_EXPECTED);
|
2003-08-07 08:13:46 +00:00
|
|
|
|
} else {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
int Attr = GetSubKey (AttrTab, sizeof (AttrTab) / sizeof (AttrTab [0]));
|
|
|
|
|
switch (Attr) {
|
|
|
|
|
|
|
|
|
|
case 0:
|
|
|
|
|
case 1:
|
|
|
|
|
/* Zeropage */
|
2002-11-28 17:42:16 +00:00
|
|
|
|
Def.Type = SEGTYPE_ZP;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
|
/* Absolute */
|
2002-11-28 17:42:16 +00:00
|
|
|
|
Def.Type = SEGTYPE_ABS;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 3:
|
|
|
|
|
case 4:
|
|
|
|
|
/* Far */
|
2002-11-28 17:42:16 +00:00
|
|
|
|
Def.Type = SEGTYPE_FAR;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
Error (ERR_ILLEGAL_SEG_ATTR);
|
|
|
|
|
}
|
|
|
|
|
NextTok ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Set the segment */
|
2002-11-28 17:42:16 +00:00
|
|
|
|
UseSeg (&Def);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-08-07 08:13:46 +00:00
|
|
|
|
static void DoSetCPU (void)
|
|
|
|
|
/* Switch the CPU instruction set */
|
|
|
|
|
{
|
|
|
|
|
/* We expect an identifier */
|
|
|
|
|
if (Tok != TOK_STRCON) {
|
|
|
|
|
ErrorSkip (ERR_STRCON_EXPECTED);
|
|
|
|
|
} else {
|
|
|
|
|
/* Try to find the CPU, then skip the identifier */
|
|
|
|
|
cpu_t CPU = FindCPU (SVal);
|
|
|
|
|
NextTok ();
|
|
|
|
|
|
|
|
|
|
/* Switch to the new CPU */
|
|
|
|
|
SetCPU (CPU);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
|
static void DoSmart (void)
|
|
|
|
|
/* Smart mode on/off */
|
|
|
|
|
{
|
|
|
|
|
SetBoolOption (&SmartMode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoSunPlus (void)
|
|
|
|
|
/* Switch to the SUNPLUS CPU */
|
|
|
|
|
{
|
|
|
|
|
SetCPU (CPU_SUNPLUS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoUnexpected (void)
|
|
|
|
|
/* Got an unexpected keyword */
|
|
|
|
|
{
|
|
|
|
|
Error (ERR_UNEXPECTED, Keyword);
|
|
|
|
|
SkipUntilSep ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-07-27 18:47:57 +00:00
|
|
|
|
static void DoWarning (void)
|
|
|
|
|
/* User warning */
|
|
|
|
|
{
|
|
|
|
|
if (Tok != TOK_STRCON) {
|
|
|
|
|
ErrorSkip (ERR_STRCON_EXPECTED);
|
|
|
|
|
} else {
|
2000-07-28 12:15:40 +00:00
|
|
|
|
Warning (WARN_USER, SVal);
|
2000-07-27 18:47:57 +00:00
|
|
|
|
SkipUntilSep ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
|
static void DoWord (void)
|
|
|
|
|
/* Define words */
|
|
|
|
|
{
|
|
|
|
|
while (1) {
|
|
|
|
|
EmitWord (Expression ());
|
|
|
|
|
if (Tok != TOK_COMMA) {
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
NextTok ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void DoZeropage (void)
|
|
|
|
|
/* Switch to the zeropage segment */
|
|
|
|
|
{
|
2002-11-28 17:42:16 +00:00
|
|
|
|
UseSeg (&ZeropageSegDef);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/* Table data */
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Control commands flags */
|
|
|
|
|
enum {
|
|
|
|
|
ccNone = 0x0000, /* No special flags */
|
|
|
|
|
ccKeepToken = 0x0001 /* Do not skip the current token */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Control command table */
|
2003-06-06 12:45:19 +00:00
|
|
|
|
typedef struct CtrlDesc CtrlDesc;
|
|
|
|
|
struct CtrlDesc {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
unsigned Flags; /* Flags for this directive */
|
|
|
|
|
void (*Handler) (void); /* Command handler */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#define PSEUDO_COUNT (sizeof (CtrlCmdTab) / sizeof (CtrlCmdTab [0]))
|
|
|
|
|
static CtrlDesc CtrlCmdTab [] = {
|
|
|
|
|
{ ccNone, DoA16 },
|
|
|
|
|
{ ccNone, DoA8 },
|
|
|
|
|
{ ccNone, DoAddr }, /* .ADDR */
|
|
|
|
|
{ ccNone, DoAlign },
|
|
|
|
|
{ ccNone, DoASCIIZ },
|
2003-06-06 12:45:19 +00:00
|
|
|
|
{ ccNone, DoAssert },
|
2000-05-28 13:40:48 +00:00
|
|
|
|
{ ccNone, DoAutoImport },
|
|
|
|
|
{ ccNone, DoUnexpected }, /* .BLANK */
|
|
|
|
|
{ ccNone, DoBss },
|
|
|
|
|
{ ccNone, DoByte },
|
|
|
|
|
{ ccNone, DoCase },
|
2002-02-18 09:11:57 +00:00
|
|
|
|
{ ccNone, DoCharMap },
|
2000-05-28 13:40:48 +00:00
|
|
|
|
{ ccNone, DoCode },
|
2000-06-23 20:49:47 +00:00
|
|
|
|
{ ccNone, DoUnexpected, }, /* .CONCAT */
|
2000-11-20 15:22:57 +00:00
|
|
|
|
{ ccNone, DoConDes },
|
2000-05-28 13:40:48 +00:00
|
|
|
|
{ ccNone, DoUnexpected }, /* .CONST */
|
2000-11-20 15:22:57 +00:00
|
|
|
|
{ ccNone, DoConstructor },
|
2000-05-28 13:40:48 +00:00
|
|
|
|
{ ccNone, DoUnexpected }, /* .CPU */
|
|
|
|
|
{ ccNone, DoData },
|
2000-08-01 21:36:45 +00:00
|
|
|
|
{ ccNone, DoDbg, },
|
2000-05-28 13:40:48 +00:00
|
|
|
|
{ ccNone, DoDByt },
|
|
|
|
|
{ ccNone, DoDebugInfo },
|
|
|
|
|
{ ccNone, DoDefine },
|
|
|
|
|
{ ccNone, DoUnexpected }, /* .DEFINED */
|
2000-11-20 15:22:57 +00:00
|
|
|
|
{ ccNone, DoDestructor },
|
2000-05-28 13:40:48 +00:00
|
|
|
|
{ ccNone, DoDWord },
|
|
|
|
|
{ ccKeepToken, DoConditionals }, /* .ELSE */
|
|
|
|
|
{ ccKeepToken, DoConditionals }, /* .ELSEIF */
|
2003-04-25 20:21:38 +00:00
|
|
|
|
{ ccKeepToken, DoEnd },
|
2000-05-28 13:40:48 +00:00
|
|
|
|
{ ccKeepToken, DoConditionals }, /* .ENDIF */
|
|
|
|
|
{ ccNone, DoUnexpected }, /* .ENDMACRO */
|
|
|
|
|
{ ccNone, DoEndProc },
|
|
|
|
|
{ ccNone, DoUnexpected }, /* .ENDREPEAT */
|
|
|
|
|
{ ccNone, DoError },
|
|
|
|
|
{ ccNone, DoExitMacro },
|
|
|
|
|
{ ccNone, DoExport },
|
|
|
|
|
{ ccNone, DoExportZP },
|
|
|
|
|
{ ccNone, DoFarAddr },
|
|
|
|
|
{ ccNone, DoFeature },
|
|
|
|
|
{ ccNone, DoFileOpt },
|
2003-03-07 11:33:14 +00:00
|
|
|
|
{ ccNone, DoForceImport },
|
2000-07-29 15:53:33 +00:00
|
|
|
|
{ ccNone, DoUnexpected }, /* .FORCEWORD */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
{ 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 */
|
2003-08-07 08:13:46 +00:00
|
|
|
|
{ ccKeepToken, DoConditionals }, /* .IFPSC02 */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
{ ccKeepToken, DoConditionals }, /* .IFREF */
|
|
|
|
|
{ ccNone, DoImport },
|
|
|
|
|
{ ccNone, DoImportZP },
|
|
|
|
|
{ ccNone, DoIncBin },
|
|
|
|
|
{ ccNone, DoInclude },
|
2000-07-08 14:01:43 +00:00
|
|
|
|
{ ccNone, DoInvalid }, /* .LEFT */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
{ ccNone, DoLineCont },
|
|
|
|
|
{ ccNone, DoList },
|
|
|
|
|
{ ccNone, DoListBytes },
|
|
|
|
|
{ ccNone, DoUnexpected }, /* .LOCAL */
|
|
|
|
|
{ ccNone, DoLocalChar },
|
|
|
|
|
{ ccNone, DoMacPack },
|
|
|
|
|
{ ccNone, DoMacro },
|
|
|
|
|
{ ccNone, DoUnexpected }, /* .MATCH */
|
2000-07-08 14:01:43 +00:00
|
|
|
|
{ ccNone, DoInvalid }, /* .MID */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
{ ccNone, DoNull },
|
|
|
|
|
{ ccNone, DoOrg },
|
|
|
|
|
{ ccNone, DoOut },
|
|
|
|
|
{ ccNone, DoP02 },
|
|
|
|
|
{ ccNone, DoP816 },
|
|
|
|
|
{ ccNone, DoPageLength },
|
|
|
|
|
{ ccNone, DoUnexpected }, /* .PARAMCOUNT */
|
|
|
|
|
{ ccNone, DoPC02 },
|
2002-11-28 17:42:16 +00:00
|
|
|
|
{ ccNone, DoPopSeg },
|
2000-05-28 13:40:48 +00:00
|
|
|
|
{ ccNone, DoProc },
|
2003-08-07 08:13:46 +00:00
|
|
|
|
{ ccNone, DoPSC02 },
|
2002-11-28 17:42:16 +00:00
|
|
|
|
{ ccNone, DoPushSeg },
|
2000-05-28 13:40:48 +00:00
|
|
|
|
{ ccNone, DoUnexpected }, /* .REFERENCED */
|
|
|
|
|
{ ccNone, DoReloc },
|
|
|
|
|
{ ccNone, DoRepeat },
|
|
|
|
|
{ ccNone, DoRes },
|
2000-07-08 14:01:43 +00:00
|
|
|
|
{ ccNone, DoInvalid }, /* .RIGHT */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
{ ccNone, DoROData },
|
|
|
|
|
{ ccNone, DoSegment },
|
2003-08-07 08:13:46 +00:00
|
|
|
|
{ ccNone, DoSetCPU },
|
2000-05-28 13:40:48 +00:00
|
|
|
|
{ ccNone, DoSmart },
|
2000-07-25 21:32:11 +00:00
|
|
|
|
{ ccNone, DoUnexpected }, /* .STRAT */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
{ ccNone, DoUnexpected }, /* .STRING */
|
2000-07-25 21:32:11 +00:00
|
|
|
|
{ ccNone, DoUnexpected }, /* .STRLEN */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
{ ccNone, DoSunPlus },
|
2000-07-15 10:33:32 +00:00
|
|
|
|
{ ccNone, DoUnexpected }, /* .TCOUNT */
|
2002-11-26 13:44:35 +00:00
|
|
|
|
{ ccNone, DoUnexpected }, /* .TIME */
|
2003-08-12 15:11:55 +00:00
|
|
|
|
{ ccNone, DoUnexpected }, /* .VERSION */
|
2000-07-27 18:47:57 +00:00
|
|
|
|
{ ccNone, DoWarning },
|
2000-05-28 13:40:48 +00:00
|
|
|
|
{ ccNone, DoWord },
|
|
|
|
|
{ ccNone, DoUnexpected }, /* .XMATCH */
|
|
|
|
|
{ ccNone, DoZeropage },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2002-11-28 17:42:16 +00:00
|
|
|
|
/* Code */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
}
|
|
|
|
|
CHECK (Index < PSEUDO_COUNT);
|
|
|
|
|
|
|
|
|
|
/* Get the pseudo intruction descriptor */
|
|
|
|
|
D = &CtrlCmdTab [Index];
|
|
|
|
|
|
|
|
|
|
/* Remember the instruction, then skip it if needed */
|
|
|
|
|
if ((D->Flags & ccKeepToken) == 0) {
|
|
|
|
|
strcpy (Keyword+1, SVal);
|
|
|
|
|
NextTok ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Call the handler */
|
|
|
|
|
D->Handler ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2002-11-28 17:42:16 +00:00
|
|
|
|
void SegStackCheck (void)
|
|
|
|
|
/* Check if the segment stack is empty at end of assembly */
|
|
|
|
|
{
|
|
|
|
|
if (CollCount (&SegStack) != 0) {
|
|
|
|
|
Error (ERR_SEGSTACK_NOT_EMPTY);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|