This commit was generated by cvs2svn to compensate for changes in r2,
which included commits to RCS files with non-trunk default branches. git-svn-id: svn://svn.cc65.org/cc65/trunk@3 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
2
src/ca65/.cvsignore
Normal file
2
src/ca65/.cvsignore
Normal file
@@ -0,0 +1,2 @@
|
||||
.depend
|
||||
ca65
|
||||
418
src/ca65/condasm.c
Normal file
418
src/ca65/condasm.c
Normal file
@@ -0,0 +1,418 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* condasm.c */
|
||||
/* */
|
||||
/* Conditional assembly support for ca65 */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 2000 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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 "error.h"
|
||||
#include "expr.h"
|
||||
#include "scanner.h"
|
||||
#include "symtab.h"
|
||||
#include "condasm.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Maximum count of nested .ifs */
|
||||
#define MAX_IFS 32
|
||||
|
||||
/* Set of bitmapped flags for the if descriptor */
|
||||
enum {
|
||||
ifNone = 0x0000, /* No flag */
|
||||
ifCond = 0x0001, /* IF condition was true */
|
||||
ifElse = 0x0002, /* We had a .ELSE branch */
|
||||
ifNeedTerm = 0x0004 /* Need .ENDIF termination */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* struct IfDesc */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* One .IF descriptor */
|
||||
typedef struct IfDesc_ IfDesc;
|
||||
struct IfDesc_ {
|
||||
unsigned Flags; /* Bitmapped flags, see above */
|
||||
FilePos Pos; /* File position of the .IF */
|
||||
const char* Name; /* Name of the directive */
|
||||
};
|
||||
|
||||
/* The .IF stack */
|
||||
static IfDesc IfStack [MAX_IFS];
|
||||
static unsigned IfCount = 0;
|
||||
|
||||
|
||||
|
||||
static IfDesc* AllocIf (const char* Directive, int NeedTerm)
|
||||
/* Alloc a new element from the .IF stack */
|
||||
{
|
||||
IfDesc* ID;
|
||||
|
||||
/* Check for stack overflow */
|
||||
if (IfCount >= MAX_IFS) {
|
||||
Error (ERR_IF_NESTING);
|
||||
}
|
||||
|
||||
/* Alloc one element */
|
||||
ID = &IfStack [IfCount++];
|
||||
|
||||
/* Initialize elements */
|
||||
ID->Flags = NeedTerm? ifNeedTerm : ifNone;
|
||||
ID->Pos = CurPos;
|
||||
ID->Name = Directive;
|
||||
|
||||
/* Return the result */
|
||||
return ID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static IfDesc* GetCurrentIf (void)
|
||||
/* Return the current .IF descriptor */
|
||||
{
|
||||
if (IfCount == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return &IfStack [IfCount-1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void FreeIf (void)
|
||||
/* Free all .IF descriptors until we reach one with the NeedTerm bit set */
|
||||
{
|
||||
int Done = 0;
|
||||
do {
|
||||
IfDesc* D = GetCurrentIf();
|
||||
if (D == 0) {
|
||||
Error (ERR_UNEXPECTED, ".ENDIF");
|
||||
} else {
|
||||
Done = (D->Flags & ifNeedTerm) != 0;
|
||||
--IfCount;
|
||||
}
|
||||
} while (!Done);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int GetCurrentIfCond (void)
|
||||
/* Return the current condition based on all conditions on the stack */
|
||||
{
|
||||
unsigned Count;
|
||||
for (Count = 0; Count < IfCount; ++Count) {
|
||||
if ((IfStack[Count].Flags & ifCond) == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void SetIfCond (IfDesc* ID, int C)
|
||||
/* Set the .IF condition */
|
||||
{
|
||||
if (C) {
|
||||
ID->Flags |= ifCond;
|
||||
} else {
|
||||
ID->Flags &= ~ifCond;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void InvertIfCond (IfDesc* ID)
|
||||
/* Invert the current condition */
|
||||
{
|
||||
ID->Flags ^= ifCond;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int GetElse (const IfDesc* ID)
|
||||
/* Return true if we had a .ELSE */
|
||||
{
|
||||
return (ID->Flags & ifElse) != 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void SetElse (IfDesc* ID, int E)
|
||||
/* Set the .ELSE flag */
|
||||
{
|
||||
if (E) {
|
||||
ID->Flags |= ifElse;
|
||||
} else {
|
||||
ID->Flags &= ~ifElse;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void DoConditionals (void)
|
||||
/* Catch all for conditional directives */
|
||||
{
|
||||
IfDesc* D;
|
||||
|
||||
int IfCond = GetCurrentIfCond ();
|
||||
do {
|
||||
|
||||
switch (Tok) {
|
||||
|
||||
case TOK_ELSE:
|
||||
D = GetCurrentIf ();
|
||||
if (D == 0) {
|
||||
Error (ERR_UNEXPECTED, ".ELSE");
|
||||
} else if (GetElse(D)) {
|
||||
/* We already had a .ELSE ! */
|
||||
Error (ERR_DUPLICATE_ELSE);
|
||||
} else {
|
||||
/* Allow an .ELSE */
|
||||
InvertIfCond (D);
|
||||
SetElse (D, 1);
|
||||
D->Pos = CurPos;
|
||||
D->Name = ".ELSE";
|
||||
IfCond = GetCurrentIfCond ();
|
||||
}
|
||||
NextTok ();
|
||||
break;
|
||||
|
||||
case TOK_ELSEIF:
|
||||
D = GetCurrentIf ();
|
||||
if (D == 0) {
|
||||
Error (ERR_UNEXPECTED, ".ELSEIF");
|
||||
} else if (GetElse(D)) {
|
||||
/* We already had a .ELSE */
|
||||
Error (ERR_DUPLICATE_ELSE);
|
||||
} else {
|
||||
/* Handle as if there was an .ELSE first */
|
||||
InvertIfCond (D);
|
||||
SetElse (D, 1);
|
||||
|
||||
/* Allocate and prepare a new descriptor */
|
||||
D = AllocIf (".ELSEIF", 0);
|
||||
NextTok ();
|
||||
|
||||
/* Ignore the new condition if we are inside a false .ELSE
|
||||
* branch. This way we won't get any errors about undefined
|
||||
* symbols or similar...
|
||||
*/
|
||||
if (IfCond == 0) {
|
||||
SetIfCond (D, ConstExpression ());
|
||||
}
|
||||
|
||||
/* Get the new overall condition */
|
||||
IfCond = GetCurrentIfCond ();
|
||||
}
|
||||
break;
|
||||
|
||||
case TOK_ENDIF:
|
||||
/* We're done with this .IF.. - remove the descriptor(s) */
|
||||
FreeIf ();
|
||||
|
||||
/* Be sure not to read the next token until the .IF stack
|
||||
* has been cleanup up, since we may be at end of file.
|
||||
*/
|
||||
NextTok ();
|
||||
|
||||
/* Get the new overall condition */
|
||||
IfCond = GetCurrentIfCond ();
|
||||
break;
|
||||
|
||||
case TOK_IF:
|
||||
D = AllocIf (".IF", 1);
|
||||
NextTok ();
|
||||
if (IfCond) {
|
||||
SetIfCond (D, ConstExpression ());
|
||||
}
|
||||
IfCond = GetCurrentIfCond ();
|
||||
break;
|
||||
|
||||
case TOK_IFBLANK:
|
||||
D = AllocIf (".IFBLANK", 1);
|
||||
NextTok ();
|
||||
if (IfCond) {
|
||||
SetIfCond (D, Tok == TOK_SEP);
|
||||
}
|
||||
IfCond = GetCurrentIfCond ();
|
||||
break;
|
||||
|
||||
case TOK_IFCONST:
|
||||
D = AllocIf (".IFCONST", 1);
|
||||
NextTok ();
|
||||
if (IfCond) {
|
||||
ExprNode* Expr = Expression();
|
||||
SetIfCond (D, IsConstExpr (Expr));
|
||||
FreeExpr (Expr);
|
||||
}
|
||||
IfCond = GetCurrentIfCond ();
|
||||
break;
|
||||
|
||||
case TOK_IFDEF:
|
||||
D = AllocIf (".IFDEF", 1);
|
||||
NextTok ();
|
||||
if (IfCond) {
|
||||
if (Tok != TOK_IDENT) {
|
||||
ErrorSkip (ERR_IDENT_EXPECTED);
|
||||
} else {
|
||||
SetIfCond (D, SymIsDef (SVal));
|
||||
NextTok ();
|
||||
}
|
||||
}
|
||||
IfCond = GetCurrentIfCond ();
|
||||
break;
|
||||
|
||||
case TOK_IFNBLANK:
|
||||
D = AllocIf (".IFNBLANK", 1);
|
||||
NextTok ();
|
||||
if (IfCond) {
|
||||
SetIfCond (D, Tok != TOK_SEP);
|
||||
}
|
||||
IfCond = GetCurrentIfCond ();
|
||||
break;
|
||||
|
||||
case TOK_IFNCONST:
|
||||
D = AllocIf (".IFNCONST", 1);
|
||||
NextTok ();
|
||||
if (IfCond) {
|
||||
ExprNode* Expr = Expression();
|
||||
SetIfCond (D, !IsConstExpr (Expr));
|
||||
FreeExpr (Expr);
|
||||
}
|
||||
IfCond = GetCurrentIfCond ();
|
||||
break;
|
||||
|
||||
case TOK_IFNDEF:
|
||||
D = AllocIf (".IFNDEF", 1);
|
||||
NextTok ();
|
||||
if (IfCond) {
|
||||
if (Tok != TOK_IDENT) {
|
||||
ErrorSkip (ERR_IDENT_EXPECTED);
|
||||
} else {
|
||||
SetIfCond (D, !SymIsDef (SVal));
|
||||
NextTok ();
|
||||
}
|
||||
}
|
||||
IfCond = GetCurrentIfCond ();
|
||||
break;
|
||||
|
||||
case TOK_IFNREF:
|
||||
D = AllocIf (".IFNREF", 1);
|
||||
NextTok ();
|
||||
if (IfCond) {
|
||||
if (Tok != TOK_IDENT) {
|
||||
ErrorSkip (ERR_IDENT_EXPECTED);
|
||||
} else {
|
||||
SetIfCond (D, !SymIsRef (SVal));
|
||||
NextTok ();
|
||||
}
|
||||
}
|
||||
IfCond = GetCurrentIfCond ();
|
||||
break;
|
||||
|
||||
case TOK_IFP02:
|
||||
break;
|
||||
|
||||
case TOK_IFP816:
|
||||
break;
|
||||
|
||||
case TOK_IFPC02:
|
||||
break;
|
||||
|
||||
case TOK_IFREF:
|
||||
D = AllocIf (".IFREF", 1);
|
||||
NextTok ();
|
||||
if (IfCond) {
|
||||
if (Tok != TOK_IDENT) {
|
||||
ErrorSkip (ERR_IDENT_EXPECTED);
|
||||
} else {
|
||||
SetIfCond (D, SymIsRef (SVal));
|
||||
NextTok ();
|
||||
}
|
||||
}
|
||||
IfCond = GetCurrentIfCond ();
|
||||
break;
|
||||
|
||||
default:
|
||||
// Skip tokens
|
||||
NextTok ();
|
||||
|
||||
}
|
||||
|
||||
} while (IfCond == 0 && Tok != TOK_EOF);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CheckOpenIfs (void)
|
||||
/* Called from the scanner before closing an input file. Will check for any
|
||||
* open .ifs in this file.
|
||||
*/
|
||||
{
|
||||
while (1) {
|
||||
/* Get the current file number and check if the topmost entry on the
|
||||
* .IF stack was inserted with this file number
|
||||
*/
|
||||
IfDesc* D = GetCurrentIf ();
|
||||
if (D == 0) {
|
||||
/* There are no open .IFs */
|
||||
break;
|
||||
}
|
||||
|
||||
if (D->Pos.Name != CurPos.Name) {
|
||||
/* The .if is from another file, bail out */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Start of .if is in the file we're about to leave */
|
||||
PError (&D->Pos, ERR_OPEN_IF);
|
||||
FreeIf ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
62
src/ca65/condasm.h
Normal file
62
src/ca65/condasm.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* condasm.h */
|
||||
/* */
|
||||
/* Conditional assembly support for ca65 */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 2000 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef CONDASM_H
|
||||
#define CONDASM_H
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void DoConditionals (void);
|
||||
/* Catch all for conditional directives */
|
||||
|
||||
void CheckOpenIfs (void);
|
||||
/* Called from the scanner before closing an input file. Will check for any
|
||||
* open .ifs in this file.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* End of condasm.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
198
src/ca65/ea.c
Normal file
198
src/ca65/ea.c
Normal file
@@ -0,0 +1,198 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* ea.c */
|
||||
/* */
|
||||
/* Effective address parsing for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998-2000 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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 "error.h"
|
||||
#include "expr.h"
|
||||
#include "instr.h"
|
||||
#include "scanner.h"
|
||||
#include "ea.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void GetEA (unsigned long* AddrMode, ExprNode** Expr, ExprNode** Bank)
|
||||
/* Parse an effective address, return the possible modes in AddrMode, and the
|
||||
* expression involved (if any) in Expr.
|
||||
*/
|
||||
{
|
||||
/* Clear the expressions */
|
||||
*Bank = *Expr = 0;
|
||||
|
||||
|
||||
if (Tok == TOK_SEP) {
|
||||
|
||||
*AddrMode = AM_IMPLICIT;
|
||||
|
||||
} else if (Tok == TOK_HASH) {
|
||||
|
||||
/* #val */
|
||||
NextTok ();
|
||||
*Expr = Expression ();
|
||||
*AddrMode = AM_IMM;
|
||||
|
||||
} else if (Tok == TOK_A) {
|
||||
|
||||
NextTok ();
|
||||
*AddrMode = AM_ACCU;
|
||||
|
||||
} else if (Tok == TOK_LBRACK) {
|
||||
|
||||
/* [dir] or [dir],y */
|
||||
NextTok ();
|
||||
*Expr = Expression ();
|
||||
Consume (TOK_RBRACK, ERR_RBRACK_EXPECTED);
|
||||
if (Tok == TOK_COMMA) {
|
||||
/* [dir],y */
|
||||
NextTok ();
|
||||
Consume (TOK_Y, ERR_Y_EXPECTED);
|
||||
*AddrMode = AM_DIR_IND_LONG_Y;
|
||||
} else {
|
||||
/* [dir] */
|
||||
*AddrMode = AM_DIR_IND_LONG;
|
||||
}
|
||||
|
||||
} else if (Tok == TOK_LPAREN) {
|
||||
|
||||
/* One of the indirect modes */
|
||||
NextTok ();
|
||||
*Expr = Expression ();
|
||||
|
||||
if (Tok == TOK_COMMA) {
|
||||
|
||||
/* (expr,X) or (rel,S),y */
|
||||
NextTok ();
|
||||
if (Tok == TOK_X) {
|
||||
/* (adr,x) */
|
||||
NextTok ();
|
||||
*AddrMode = AM_ABS_X_IND | AM_DIR_X_IND;
|
||||
ConsumeRParen ();
|
||||
} else if (Tok == TOK_S) {
|
||||
/* (rel,s),y */
|
||||
NextTok ();
|
||||
*AddrMode = AM_STACK_REL_IND_Y;
|
||||
ConsumeRParen ();
|
||||
ConsumeComma ();
|
||||
Consume (TOK_Y, ERR_Y_EXPECTED);
|
||||
} else {
|
||||
Error (ERR_SYNTAX);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* (adr) or (adr),y */
|
||||
ConsumeRParen ();
|
||||
if (Tok == TOK_COMMA) {
|
||||
/* (adr),y */
|
||||
NextTok ();
|
||||
Consume (TOK_Y, ERR_Y_EXPECTED);
|
||||
*AddrMode = AM_DIR_IND_Y;
|
||||
} else {
|
||||
/* (adr) */
|
||||
*AddrMode = AM_ABS_IND | AM_DIR_IND;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* Remaining stuff:
|
||||
*
|
||||
* adr
|
||||
* bank.adr
|
||||
* adr,x
|
||||
* bank.adr,x
|
||||
* adr,y
|
||||
* adr,s
|
||||
*/
|
||||
*Expr = Expression ();
|
||||
|
||||
if (Tok == TOK_DOT) {
|
||||
|
||||
/* Expr was a bank specification: bank.adr or bank.adr,x */
|
||||
*Bank = *Expr;
|
||||
NextTok ();
|
||||
*Expr = Expression ();
|
||||
if (Tok == TOK_COMMA) {
|
||||
/* bank.adr,x */
|
||||
NextTok ();
|
||||
Consume (TOK_X, ERR_X_EXPECTED);
|
||||
*AddrMode = AM_ABS_LONG_X;
|
||||
} else {
|
||||
/* bank.adr */
|
||||
*AddrMode = AM_ABS_LONG;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (Tok == TOK_COMMA) {
|
||||
|
||||
NextTok ();
|
||||
switch (Tok) {
|
||||
|
||||
case TOK_X:
|
||||
*AddrMode = AM_ABS_X | AM_DIR_X;
|
||||
NextTok ();
|
||||
break;
|
||||
|
||||
case TOK_Y:
|
||||
*AddrMode = AM_ABS_Y | AM_DIR_Y;
|
||||
NextTok ();
|
||||
break;
|
||||
|
||||
case TOK_S:
|
||||
*AddrMode = AM_STACK_REL;
|
||||
NextTok ();
|
||||
break;
|
||||
|
||||
default:
|
||||
Error (ERR_SYNTAX);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
*AddrMode = AM_ABS | AM_DIR;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
69
src/ca65/ea.h
Normal file
69
src/ca65/ea.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* ea.h */
|
||||
/* */
|
||||
/* Effective address parsing for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef EA_H
|
||||
#define EA_H
|
||||
|
||||
|
||||
|
||||
#include "expr.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void GetEA (unsigned long* AddrMode, ExprNode** Expr, ExprNode** Bank);
|
||||
/* Parse an effective address, return the possible modes in AddrMode, and the
|
||||
* expression involved (if any) in Expr.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* End of ea.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
291
src/ca65/error.c
Normal file
291
src/ca65/error.c
Normal file
@@ -0,0 +1,291 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* error.c */
|
||||
/* */
|
||||
/* Error handling for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998-2000 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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 <stdarg.h>
|
||||
|
||||
#include "scanner.h"
|
||||
#include "error.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Warning level */
|
||||
unsigned WarnLevel = 1;
|
||||
|
||||
/* Messages for internal compiler errors */
|
||||
const char _MsgCheckFailed [] =
|
||||
"Check failed: `%s' (= %d), file `%s', line %u\n";
|
||||
const char _MsgPrecondition [] =
|
||||
"Precondition violated: `%s' (= %d), file `%s', line %u\n";
|
||||
const char _MsgFail [] =
|
||||
"%s, file `%s', line %u\n";
|
||||
|
||||
|
||||
/* Statistics */
|
||||
unsigned ErrorCount = 0;
|
||||
unsigned WarningCount = 0;
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Warnings */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void WarningMsg (const FilePos* Pos, unsigned WarnNum, va_list ap)
|
||||
/* Print warning message. */
|
||||
{
|
||||
static const struct {
|
||||
unsigned char Level;
|
||||
const char* Msg;
|
||||
} Warnings [WARN_COUNT-1] = {
|
||||
{ 1, "Mask error" },
|
||||
{ 2, "Symbol `%s' is defined but never used" },
|
||||
{ 2, "Symbol `%s' is imported but never used" },
|
||||
{ 1, "Cannot track processor status byte" },
|
||||
};
|
||||
|
||||
if (Warnings [WarnNum-1].Level <= WarnLevel) {
|
||||
fprintf (stderr, "%s(%lu): Warning #%u: ",
|
||||
GetFileName (Pos->Name), Pos->Line, WarnNum);
|
||||
vfprintf (stderr, Warnings [WarnNum-1].Msg, ap);
|
||||
fprintf (stderr, "\n");
|
||||
++WarningCount;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Warning (unsigned WarnNum, ...)
|
||||
/* Print warning message. */
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, WarnNum);
|
||||
WarningMsg (&CurPos, WarnNum, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PWarning (const FilePos* Pos, unsigned WarnNum, ...)
|
||||
/* Print warning message giving an explicit file and position. */
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, WarnNum);
|
||||
WarningMsg (Pos, WarnNum, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Errors */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void ErrorMsg (const FilePos* Pos, unsigned ErrNum, va_list ap)
|
||||
/* Print an error message */
|
||||
{
|
||||
static const char* Msgs [ERR_COUNT-1] = {
|
||||
"Command/operation not implemented",
|
||||
"Cannot open include file `%s': %s",
|
||||
"Include nesting too deep",
|
||||
"Invalid input character: %02X",
|
||||
"Hex digit expected",
|
||||
"Digit expected",
|
||||
"`0' or `1' expected",
|
||||
"Numerical overflow",
|
||||
"Control statement expected",
|
||||
"Too many characters",
|
||||
"`:' expected",
|
||||
"`(' expected",
|
||||
"`)' expected",
|
||||
"`]' expected",
|
||||
"`,' expected",
|
||||
"Boolean switch value expected (on/off/+/-)",
|
||||
"`Y' expected",
|
||||
"`X' expected",
|
||||
"Integer constant expected",
|
||||
"String constant expected",
|
||||
"Character constant expected",
|
||||
"Constant expression expected",
|
||||
"Identifier expected",
|
||||
"`.endmacro' expected",
|
||||
"Option key expected",
|
||||
"Command is only valid in 65816 mode",
|
||||
"User error: %s",
|
||||
"String constant too long",
|
||||
"Newline in string constant",
|
||||
"Illegal character constant",
|
||||
"Illegal addressing mode",
|
||||
"Illegal character to start local symbols",
|
||||
"Illegal use of local symbol",
|
||||
"Illegal segment name: `%s'",
|
||||
"Illegal segment attribute",
|
||||
"Illegal macro package name",
|
||||
"Illegal emulation feature",
|
||||
"Syntax error",
|
||||
"Symbol `%s' is already defined",
|
||||
"Undefined symbol `%s'",
|
||||
"Symbol `%s' is marked as import",
|
||||
"Symbol `%s' is marked as export",
|
||||
"Exported symbol `%s' is undefined",
|
||||
"Exported values must be constant",
|
||||
".IF nesting too deep",
|
||||
"Unexpected end of line",
|
||||
"Unexpected `%s'",
|
||||
"Division by zero",
|
||||
"Modulo operation with zero",
|
||||
"Range error",
|
||||
"Too many macro parameters",
|
||||
"Macro parameter expected",
|
||||
"Circular reference in symbol definition",
|
||||
"Symbol redeclaration mismatch",
|
||||
"Alignment value must be a power of 2",
|
||||
"Duplicate `.ELSE'",
|
||||
"Conditional assembly branch was never closed",
|
||||
"Lexical level was not terminated correctly",
|
||||
"Segment attribute mismatch",
|
||||
"CPU not supported",
|
||||
"Counter underflow",
|
||||
"Undefined label",
|
||||
};
|
||||
|
||||
fprintf (stderr, "%s(%lu): Error #%u: ",
|
||||
GetFileName (Pos->Name), Pos->Line, ErrNum);
|
||||
vfprintf (stderr, Msgs [ErrNum-1], ap);
|
||||
fprintf (stderr, "\n");
|
||||
++ErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Error (unsigned ErrNum, ...)
|
||||
/* Print an error message */
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, ErrNum);
|
||||
ErrorMsg (&CurPos, ErrNum, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PError (const FilePos* Pos, unsigned ErrNum, ...)
|
||||
/* Print an error message giving an explicit file and position. */
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, ErrNum);
|
||||
ErrorMsg (Pos, ErrNum, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ErrorSkip (unsigned ErrNum, ...)
|
||||
/* Print an error message and skip the rest of the line */
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, ErrNum);
|
||||
ErrorMsg (&CurPos, ErrNum, ap);
|
||||
va_end (ap);
|
||||
|
||||
SkipUntilSep ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void Fatal (unsigned FatNum, ...)
|
||||
/* Print a message about a fatal error and die */
|
||||
{
|
||||
static const char* Msgs [FAT_COUNT-1] = {
|
||||
"Maximum number of input files reached",
|
||||
"Out of memory",
|
||||
"Too many segments",
|
||||
"String too long",
|
||||
"Cannot open input file `%s': %s",
|
||||
"Cannot stat input file `%s': %s",
|
||||
"Cannot open output file `%s': %s",
|
||||
"Cannot write to output file `%s': %s",
|
||||
"Cannot open listing file: %s",
|
||||
"Cannot write to listing file: %s",
|
||||
"Cannot read from listing file: %s",
|
||||
"Macro nesting too deep",
|
||||
"Too many symbols",
|
||||
};
|
||||
va_list ap;
|
||||
|
||||
va_start (ap, FatNum);
|
||||
fprintf (stderr, "Fatal #%u: ", FatNum);
|
||||
vfprintf (stderr, Msgs [FatNum-1], ap);
|
||||
fprintf (stderr, "\n");
|
||||
va_end (ap);
|
||||
|
||||
/* And die... */
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Internal (const char* Format, ...)
|
||||
/* Print a message about an internal compiler error and die. */
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, Format);
|
||||
fprintf (stderr, "Internal assembler error\n");
|
||||
vfprintf (stderr, Format, ap);
|
||||
va_end (ap);
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
210
src/ca65/error.h
Normal file
210
src/ca65/error.h
Normal file
@@ -0,0 +1,210 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* error.h */
|
||||
/* */
|
||||
/* Error handling for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998-2000 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef ERROR_H
|
||||
#define ERROR_H
|
||||
|
||||
|
||||
|
||||
#include "scanner.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Warning numbers */
|
||||
enum Warnings {
|
||||
WARN_NONE, /* No warning */
|
||||
WARN_MASK_ERROR,
|
||||
WARN_SYM_NOT_REFERENCED,
|
||||
WARN_IMPORT_NOT_REFERENCED,
|
||||
WARN_CANNOT_TRACK_STATUS,
|
||||
WARN_COUNT /* Warning count */
|
||||
};
|
||||
|
||||
/* Error numbers */
|
||||
enum Errors {
|
||||
ERR_NONE, /* No error */
|
||||
ERR_NOT_IMPLEMENTED, /* Command/operation not implemented */
|
||||
ERR_CANNOT_OPEN_INCLUDE,
|
||||
ERR_INCLUDE_NESTING,
|
||||
ERR_INVALID_CHAR,
|
||||
ERR_HEX_DIGIT_EXPECTED,
|
||||
ERR_DIGIT_EXPECTED,
|
||||
ERR_01_EXPECTED,
|
||||
ERR_NUM_OVERFLOW,
|
||||
ERR_PSEUDO_EXPECTED,
|
||||
ERR_TOO_MANY_CHARS,
|
||||
ERR_COLON_EXPECTED,
|
||||
ERR_LPAREN_EXPECTED,
|
||||
ERR_RPAREN_EXPECTED,
|
||||
ERR_RBRACK_EXPECTED,
|
||||
ERR_COMMA_EXPECTED,
|
||||
ERR_ONOFF_EXPECTED,
|
||||
ERR_Y_EXPECTED,
|
||||
ERR_X_EXPECTED,
|
||||
ERR_INTCON_EXPECTED,
|
||||
ERR_STRCON_EXPECTED,
|
||||
ERR_CHARCON_EXPECTED,
|
||||
ERR_CONSTEXPR_EXPECTED,
|
||||
ERR_IDENT_EXPECTED,
|
||||
ERR_ENDMACRO_EXPECTED,
|
||||
ERR_OPTION_KEY_EXPECTED,
|
||||
ERR_816_MODE_ONLY,
|
||||
ERR_USER,
|
||||
ERR_STRING_TOO_LONG,
|
||||
ERR_NEWLINE_IN_STRING,
|
||||
ERR_ILLEGAL_CHARCON,
|
||||
ERR_ILLEGAL_ADDR_MODE,
|
||||
ERR_ILLEGAL_LOCALSTART,
|
||||
ERR_ILLEGAL_LOCAL_USE,
|
||||
ERR_ILLEGAL_SEGMENT,
|
||||
ERR_ILLEGAL_SEG_ATTR,
|
||||
ERR_ILLEGAL_MACPACK,
|
||||
ERR_ILLEGAL_FEATURE,
|
||||
ERR_SYNTAX,
|
||||
ERR_SYM_ALREADY_DEFINED,
|
||||
ERR_SYM_UNDEFINED,
|
||||
ERR_SYM_ALREADY_IMPORT,
|
||||
ERR_SYM_ALREADY_EXPORT,
|
||||
ERR_EXPORT_UNDEFINED,
|
||||
ERR_EXPORT_MUST_BE_CONST,
|
||||
ERR_IF_NESTING,
|
||||
ERR_UNEXPECTED_EOL,
|
||||
ERR_UNEXPECTED,
|
||||
ERR_DIV_BY_ZERO,
|
||||
ERR_MOD_BY_ZERO,
|
||||
ERR_RANGE,
|
||||
ERR_TOO_MANY_PARAMS,
|
||||
ERR_MACRO_PARAM_EXPECTED,
|
||||
ERR_CIRCULAR_REFERENCE,
|
||||
ERR_SYM_REDECL_MISMATCH,
|
||||
ERR_ALIGN,
|
||||
ERR_DUPLICATE_ELSE,
|
||||
ERR_OPEN_IF,
|
||||
ERR_OPEN_PROC,
|
||||
ERR_SEG_ATTR_MISMATCH,
|
||||
ERR_CPU_NOT_SUPPORTED,
|
||||
ERR_COUNTER_UNDERFLOW,
|
||||
ERR_UNDEFINED_LABEL,
|
||||
ERR_COUNT /* Error count */
|
||||
};
|
||||
|
||||
/* Fatal errors */
|
||||
enum Fatals {
|
||||
FAT_NONE,
|
||||
FAT_MAX_INPUT_FILES,
|
||||
FAT_OUT_OF_MEMORY,
|
||||
FAT_TOO_MANY_SEGMENTS,
|
||||
FAT_STRING_TOO_LONG,
|
||||
FAT_CANNOT_OPEN_INPUT,
|
||||
FAT_CANNOT_STAT_INPUT,
|
||||
FAT_CANNOT_OPEN_OUTPUT,
|
||||
FAT_CANNOT_WRITE_OUTPUT,
|
||||
FAT_CANNOT_OPEN_LISTING,
|
||||
FAT_CANNOT_WRITE_LISTING,
|
||||
FAT_CANNOT_READ_LISTING,
|
||||
FAT_MACRO_NESTING,
|
||||
FAT_TOO_MANY_SYMBOLS,
|
||||
FAT_COUNT /* Fatal error count */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Warning levels */
|
||||
extern unsigned WarnLevel;
|
||||
|
||||
/* Messages for internal compiler errors */
|
||||
extern const char _MsgCheckFailed [];
|
||||
extern const char _MsgPrecondition [];
|
||||
extern const char _MsgFail [];
|
||||
|
||||
/* Statistics */
|
||||
extern unsigned ErrorCount;
|
||||
extern unsigned WarningCount;
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void Warning (unsigned WarnNum, ...);
|
||||
/* Print warning message. */
|
||||
|
||||
void PWarning (const FilePos* Pos, unsigned WarnNum, ...);
|
||||
/* Print warning message giving an explicit file and position. */
|
||||
|
||||
void Error (unsigned ErrNum, ...);
|
||||
/* Print an error message */
|
||||
|
||||
void PError (const FilePos* Pos, unsigned ErrNum, ...);
|
||||
/* Print an error message giving an explicit file and position. */
|
||||
|
||||
void ErrorSkip (unsigned ErrNum, ...);
|
||||
/* Print an error message and skip the rest of the line */
|
||||
|
||||
void Fatal (unsigned FatNum, ...);
|
||||
/* Print a message about a fatal error and die */
|
||||
|
||||
void Internal (const char* Format, ...);
|
||||
/* Print a message about an internal compiler error and die. */
|
||||
|
||||
#define CHECK(c) \
|
||||
if (!(c)) \
|
||||
Internal (_MsgCheckFailed, #c, c, __FILE__, __LINE__)
|
||||
|
||||
#define PRECONDITION(c) \
|
||||
if (!(c)) \
|
||||
Internal (_MsgPrecondition, #c, c, __FILE__, __LINE__)
|
||||
|
||||
#define FAIL(s) \
|
||||
Internal (_MsgFail, s, __FILE__, __LINE__)
|
||||
|
||||
|
||||
|
||||
/* End of error.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
1566
src/ca65/expr.c
Normal file
1566
src/ca65/expr.c
Normal file
File diff suppressed because it is too large
Load Diff
127
src/ca65/expr.h
Normal file
127
src/ca65/expr.h
Normal file
@@ -0,0 +1,127 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* expr.h */
|
||||
/* */
|
||||
/* Expression evaluation for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef EXPR_H
|
||||
#define EXPR_H
|
||||
|
||||
|
||||
|
||||
#include "../common/exprdefs.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
ExprNode* Expression (void);
|
||||
/* Evaluate an expression, build the expression tree on the heap and return
|
||||
* a pointer to the root of the tree.
|
||||
*/
|
||||
|
||||
long ConstExpression (void);
|
||||
/* Parse an expression. Check if the expression is const, and print an error
|
||||
* message if not. Return the value of the expression, or a dummy, if it is
|
||||
* not constant.
|
||||
*/
|
||||
|
||||
void FreeExpr (ExprNode* Root);
|
||||
/* Free the expression tree, Root is pointing to. */
|
||||
|
||||
ExprNode* LiteralExpr (long Val);
|
||||
/* Return an expression tree that encodes the given literal value */
|
||||
|
||||
ExprNode* CurrentPC (void);
|
||||
/* Return the current program counter as expression */
|
||||
|
||||
ExprNode* SwapExpr (ExprNode* Expr);
|
||||
/* Return an extended expression with lo and hi bytes swapped */
|
||||
|
||||
ExprNode* BranchExpr (unsigned Offs);
|
||||
/* Return an expression that encodes the difference between current PC plus
|
||||
* offset and the target expression (that is, Expression() - (*+Offs) ).
|
||||
*/
|
||||
|
||||
ExprNode* ULabelExpr (unsigned Num);
|
||||
/* Return an expression for an unnamed label with the given index */
|
||||
|
||||
ExprNode* ForceWordExpr (ExprNode* Expr);
|
||||
/* Force the given expression into a word and return the result. */
|
||||
|
||||
int IsConstExpr (ExprNode* Root);
|
||||
/* Return true if the given expression is a constant expression, that is, one
|
||||
* with no references to external symbols.
|
||||
*/
|
||||
|
||||
int IsByteExpr (ExprNode* Root);
|
||||
/* Return true if this is a byte expression */
|
||||
|
||||
long GetExprVal (ExprNode* Expr);
|
||||
/* Get the value of a constant expression */
|
||||
|
||||
int IsByteRange (long Val);
|
||||
/* Return true if this is a byte value */
|
||||
|
||||
int IsWordRange (long Val);
|
||||
/* Return true if this is a word value */
|
||||
|
||||
void DumpExpr (ExprNode* Expr);
|
||||
/* Dump an expression tree to stdout */
|
||||
|
||||
ExprNode* FinalizeExpr (ExprNode* Expr);
|
||||
/* Resolve any symbols by cloning the symbol expression tree instead of the
|
||||
* symbol reference, then try to simplify the expression as much as possible.
|
||||
* This function must only be called if all symbols are resolved (no undefined
|
||||
* symbol errors).
|
||||
*/
|
||||
|
||||
ExprNode* CloneExpr (ExprNode* Expr);
|
||||
/* Clone the given expression tree. The function will simply clone symbol
|
||||
* nodes, it will not resolve them.
|
||||
*/
|
||||
|
||||
void WriteExpr (ExprNode* Expr);
|
||||
/* Write the given expression to the object file */
|
||||
|
||||
|
||||
|
||||
/* End of expr.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
74
src/ca65/fname.c
Normal file
74
src/ca65/fname.c
Normal file
@@ -0,0 +1,74 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* fname.c */
|
||||
/* */
|
||||
/* File name handling utilities */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 2000 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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 <string.h>
|
||||
|
||||
#include "mem.h"
|
||||
#include "fname.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
char* MakeFilename (const char* Origin, const char* Ext)
|
||||
/* Make a new file name from Origin and Ext. If Origin has an extension, it
|
||||
* is removed and Ext is appended. If Origin has no extension, Ext is simply
|
||||
* appended. The result is placed in a malloc'ed buffer and returned.
|
||||
* The function may be used to create "foo.o" from "foo.s".
|
||||
*/
|
||||
{
|
||||
/* Construct the name */
|
||||
char* Result;
|
||||
const char* P = strrchr (Origin, '.');
|
||||
if (P == 0) {
|
||||
/* No dot, add the extension */
|
||||
Result = Xmalloc (strlen (Origin) + strlen (Ext) + 1);
|
||||
strcpy (Result, Origin);
|
||||
strcat (Result, Ext);
|
||||
} else {
|
||||
Result = Xmalloc (P - Origin + strlen (Ext) + 1);
|
||||
memcpy (Result, Origin, P - Origin);
|
||||
strcpy (Result + (P - Origin), Ext);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
61
src/ca65/fname.h
Normal file
61
src/ca65/fname.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* fname.h */
|
||||
/* */
|
||||
/* File name handling utilities */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 2000 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef FNAME_H
|
||||
#define FNAME_H
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
char* MakeFilename (const char* Origin, const char* Ext);
|
||||
/* Make a new file name from Origin and Ext. If Origin has an extension, it
|
||||
* is removed and Ext is appended. If Origin has no extension, Ext is simply
|
||||
* appended. The result is placed in a malloc'ed buffer and returned.
|
||||
* The function may be used to create "foo.o" from "foo.s".
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* End of fname.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
51
src/ca65/fragment.c
Normal file
51
src/ca65/fragment.c
Normal file
@@ -0,0 +1,51 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* fragment.c */
|
||||
/* */
|
||||
/* Data fragments for the ca65 crossassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998-2000 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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 "fragment.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* struct Fragment */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* List of all fragments */
|
||||
Fragment* FragList = 0;
|
||||
Fragment* FragLast = 0;
|
||||
|
||||
|
||||
|
||||
78
src/ca65/fragment.h
Normal file
78
src/ca65/fragment.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* fragment.h */
|
||||
/* */
|
||||
/* Data fragments for the ca65 crossassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998-2000 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef FRAGMENT_H
|
||||
#define FRAGMENT_H
|
||||
|
||||
|
||||
|
||||
#include "../common/exprdefs.h"
|
||||
#include "../common/filepos.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* struct Fragment */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
typedef struct Fragment_ Fragment;
|
||||
struct Fragment_ {
|
||||
Fragment* List; /* List of all fragments */
|
||||
Fragment* Next; /* Fragment list in one segment */
|
||||
Fragment* LineList; /* List of fragments for one src line */
|
||||
FilePos Pos; /* File position for this fragment */
|
||||
unsigned short Len; /* Length for this fragment */
|
||||
unsigned char Type; /* Fragment type */
|
||||
union {
|
||||
unsigned char Data [4]; /* Literal values */
|
||||
ExprNode* Expr; /* Expression */
|
||||
} V;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* List of all fragments */
|
||||
extern Fragment* FragList;
|
||||
extern Fragment* FragLast;
|
||||
|
||||
|
||||
|
||||
/* End of fragment.h */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
76
src/ca65/global.c
Normal file
76
src/ca65/global.c
Normal file
@@ -0,0 +1,76 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* global.c */
|
||||
/* */
|
||||
/* Global variables for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998-2000 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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 "global.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
const char* ProgName = "ca65"; /* Program name */
|
||||
|
||||
/* File names */
|
||||
const char* InFile = 0; /* Name of input file */
|
||||
const char* OutFile = 0; /* Name of output file */
|
||||
const char* ListFile = 0; /* Name of listing file */
|
||||
|
||||
/* Default extensions */
|
||||
const char ObjExt[] = ".o"; /* Default object extension */
|
||||
const char ListExt[] = ".lst"; /* Default listing extension */
|
||||
|
||||
char LocalStart = '@'; /* This char starts local symbols */
|
||||
|
||||
unsigned char IgnoreCase = 0; /* Ignore case on identifiers? */
|
||||
unsigned char AutoImport = 0; /* Mark unresolveds as import */
|
||||
unsigned char Verbose = 0; /* Verbose operation flag */
|
||||
unsigned char SmartMode = 0; /* Smart mode */
|
||||
unsigned char DbgSyms = 0; /* Add debug symbols */
|
||||
unsigned char Listing = 0; /* Create listing file */
|
||||
unsigned char LineCont = 0; /* Allow line continuation */
|
||||
|
||||
/* Emulation features */
|
||||
unsigned char DollarIsPC = 0; /* Allow the $ symbol as current PC */
|
||||
unsigned char NoColonLabels = 0; /* Allow labels without a colon */
|
||||
unsigned char LooseStringTerm = 0; /* Allow ' as string terminator */
|
||||
unsigned char AtInIdents = 0; /* Allow '@' in identifiers */
|
||||
unsigned char DollarInIdents = 0; /* Allow '$' in identifiers */
|
||||
|
||||
|
||||
|
||||
|
||||
82
src/ca65/global.h
Normal file
82
src/ca65/global.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* global.h */
|
||||
/* */
|
||||
/* Global variables for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998-2000 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef GLOBAL_H
|
||||
#define GLOBAL_H
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
extern const char* ProgName; /* Program name */
|
||||
|
||||
/* File names */
|
||||
extern const char* InFile; /* Name of input file */
|
||||
extern const char* OutFile; /* Name of output file */
|
||||
extern const char* ListFile; /* Name of listing file */
|
||||
|
||||
/* Default extensions */
|
||||
extern const char ObjExt[]; /* Default object extension */
|
||||
extern const char ListExt[]; /* Default listing extension */
|
||||
|
||||
extern char LocalStart; /* This char starts local symbols */
|
||||
|
||||
extern unsigned char IgnoreCase; /* Ignore case on identifiers? */
|
||||
extern unsigned char AutoImport; /* Mark unresolveds as import */
|
||||
extern unsigned char Verbose; /* Verbose operation flag */
|
||||
extern unsigned char SmartMode; /* Smart mode */
|
||||
extern unsigned char DbgSyms; /* Add debug symbols */
|
||||
extern unsigned char Listing; /* Create listing file */
|
||||
extern unsigned char LineCont; /* Allow line continuation */
|
||||
|
||||
/* Emulation features */
|
||||
extern unsigned char DollarIsPC; /* Allow the $ symbol as current PC */
|
||||
extern unsigned char NoColonLabels; /* Allow labels without a colon */
|
||||
extern unsigned char LooseStringTerm;/* Allow ' as string terminator */
|
||||
extern unsigned char AtInIdents; /* Allow '@' in identifiers */
|
||||
extern unsigned char DollarInIdents; /* Allow '$' in identifiers */
|
||||
|
||||
|
||||
|
||||
/* End of global.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
748
src/ca65/instr.c
Normal file
748
src/ca65/instr.c
Normal file
@@ -0,0 +1,748 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* instr.c */
|
||||
/* */
|
||||
/* Instruction encoding for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998-2000 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "../common/bitops.h"
|
||||
|
||||
#include "ea.h"
|
||||
#include "error.h"
|
||||
#include "expr.h"
|
||||
#include "global.h"
|
||||
#include "objcode.h"
|
||||
#include "scanner.h"
|
||||
#include "instr.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Forwards for handler functions */
|
||||
static void PutPCRel8 (const InsDesc* Ins);
|
||||
static void PutPCRel16 (const InsDesc* Ins);
|
||||
static void PutBlockMove (const InsDesc* Ins);
|
||||
static void PutREP (const InsDesc* Ins);
|
||||
static void PutSEP (const InsDesc* Ins);
|
||||
static void PutAll (const InsDesc* Ins);
|
||||
|
||||
|
||||
|
||||
/* Instruction table for the 6502 */
|
||||
#define INS_COUNT_6502 56
|
||||
static const struct {
|
||||
unsigned Count;
|
||||
InsDesc Ins[INS_COUNT_6502];
|
||||
} InsTab6502 = {
|
||||
INS_COUNT_6502,
|
||||
{
|
||||
{ "ADC", 0x080A26C, 0x60, 0, PutAll },
|
||||
{ "AND", 0x080A26C, 0x20, 0, PutAll },
|
||||
{ "ASL", 0x000006e, 0x02, 1, PutAll },
|
||||
{ "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
|
||||
{ "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
|
||||
{ "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
|
||||
{ "BIT", 0x000000C, 0x00, 2, PutAll },
|
||||
{ "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
|
||||
{ "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
|
||||
{ "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
|
||||
{ "BRK", 0x0000001, 0x00, 0, PutAll },
|
||||
{ "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
|
||||
{ "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
|
||||
{ "CLC", 0x0000001, 0x18, 0, PutAll },
|
||||
{ "CLD", 0x0000001, 0xd8, 0, PutAll },
|
||||
{ "CLI", 0x0000001, 0x58, 0, PutAll },
|
||||
{ "CLV", 0x0000001, 0xb8, 0, PutAll },
|
||||
{ "CMP", 0x080A26C, 0xc0, 0, PutAll },
|
||||
{ "CPX", 0x080000C, 0xe0, 1, PutAll },
|
||||
{ "CPY", 0x080000C, 0xc0, 1, PutAll },
|
||||
{ "DEC", 0x000006C, 0x00, 3, PutAll },
|
||||
{ "DEX", 0x0000001, 0xca, 0, PutAll },
|
||||
{ "DEY", 0x0000001, 0x88, 0, PutAll },
|
||||
{ "EOR", 0x080A26C, 0x40, 0, PutAll },
|
||||
{ "INC", 0x000006c, 0x00, 4, PutAll },
|
||||
{ "INX", 0x0000001, 0xe8, 0, PutAll },
|
||||
{ "INY", 0x0000001, 0xc8, 0, PutAll },
|
||||
{ "JMP", 0x0000808, 0x4c, 6, PutAll },
|
||||
{ "JSR", 0x0000008, 0x20, 7, PutAll },
|
||||
{ "LDA", 0x080A26C, 0xa0, 0, PutAll },
|
||||
{ "LDX", 0x080030C, 0xa2, 1, PutAll },
|
||||
{ "LDY", 0x080006C, 0xa0, 1, PutAll },
|
||||
{ "LSR", 0x000006F, 0x42, 1, PutAll },
|
||||
{ "NOP", 0x0000001, 0xea, 0, PutAll },
|
||||
{ "ORA", 0x080A26C, 0x00, 0, PutAll },
|
||||
{ "PHA", 0x0000001, 0x48, 0, PutAll },
|
||||
{ "PHP", 0x0000001, 0x08, 0, PutAll },
|
||||
{ "PLA", 0x0000001, 0x68, 0, PutAll },
|
||||
{ "PLP", 0x0000001, 0x28, 0, PutAll },
|
||||
{ "ROL", 0x000006F, 0x22, 1, PutAll },
|
||||
{ "ROR", 0x000006F, 0x62, 1, PutAll },
|
||||
{ "RTI", 0x0000001, 0x40, 0, PutAll },
|
||||
{ "RTS", 0x0000001, 0x60, 0, PutAll },
|
||||
{ "SBC", 0x080A26C, 0xe0, 0, PutAll },
|
||||
{ "SEC", 0x0000001, 0x38, 0, PutAll },
|
||||
{ "SED", 0x0000001, 0xf8, 0, PutAll },
|
||||
{ "SEI", 0x0000001, 0x78, 0, PutAll },
|
||||
{ "STA", 0x000A26C, 0x80, 0, PutAll },
|
||||
{ "STX", 0x000010c, 0x82, 1, PutAll },
|
||||
{ "STY", 0x000002c, 0x80, 1, PutAll },
|
||||
{ "TAX", 0x0000001, 0xaa, 0, PutAll },
|
||||
{ "TAY", 0x0000001, 0xa8, 0, PutAll },
|
||||
{ "TSX", 0x0000001, 0xba, 0, PutAll },
|
||||
{ "TXA", 0x0000001, 0x8a, 0, PutAll },
|
||||
{ "TXS", 0x0000001, 0x9a, 0, PutAll },
|
||||
{ "TYA", 0x0000001, 0x98, 0, PutAll }
|
||||
}
|
||||
};
|
||||
|
||||
/* Instruction table for the 65SC02 */
|
||||
#define INS_COUNT_65SC02 66
|
||||
static const struct {
|
||||
unsigned Count;
|
||||
InsDesc Ins[INS_COUNT_65SC02];
|
||||
} InsTab65SC02 = {
|
||||
INS_COUNT_65SC02,
|
||||
{
|
||||
{ "ADC", 0x080A66C, 0x60, 0, PutAll },
|
||||
{ "AND", 0x080A66C, 0x20, 0, PutAll },
|
||||
{ "ASL", 0x000006e, 0x02, 1, PutAll },
|
||||
{ "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
|
||||
{ "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
|
||||
{ "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
|
||||
{ "BIT", 0x080006C, 0x00, 2, PutAll },
|
||||
{ "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
|
||||
{ "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
|
||||
{ "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
|
||||
{ "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
|
||||
{ "BRK", 0x0000001, 0x00, 0, PutAll },
|
||||
{ "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
|
||||
{ "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
|
||||
{ "CLC", 0x0000001, 0x18, 0, PutAll },
|
||||
{ "CLD", 0x0000001, 0xd8, 0, PutAll },
|
||||
{ "CLI", 0x0000001, 0x58, 0, PutAll },
|
||||
{ "CLV", 0x0000001, 0xb8, 0, PutAll },
|
||||
{ "CMP", 0x080A66C, 0xc0, 0, PutAll },
|
||||
{ "CPX", 0x080000C, 0xe0, 1, PutAll },
|
||||
{ "CPY", 0x080000C, 0xc0, 1, PutAll },
|
||||
{ "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
|
||||
{ "DEC", 0x000006F, 0x00, 3, PutAll },
|
||||
{ "DEX", 0x0000001, 0xca, 0, PutAll },
|
||||
{ "DEY", 0x0000001, 0x88, 0, PutAll },
|
||||
{ "EOR", 0x080A66C, 0x40, 0, PutAll },
|
||||
{ "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
|
||||
{ "INC", 0x000006f, 0x00, 4, PutAll },
|
||||
{ "INX", 0x0000001, 0xe8, 0, PutAll },
|
||||
{ "INY", 0x0000001, 0xc8, 0, PutAll },
|
||||
{ "JMP", 0x0010808, 0x4c, 6, PutAll },
|
||||
{ "JSR", 0x0000008, 0x20, 7, PutAll },
|
||||
{ "LDA", 0x080A66C, 0xa0, 0, PutAll },
|
||||
{ "LDX", 0x080030C, 0xa2, 1, PutAll },
|
||||
{ "LDY", 0x080006C, 0xa0, 1, PutAll },
|
||||
{ "LSR", 0x000006F, 0x42, 1, PutAll },
|
||||
{ "NOP", 0x0000001, 0xea, 0, PutAll },
|
||||
{ "ORA", 0x080A66C, 0x00, 0, PutAll },
|
||||
{ "PHA", 0x0000001, 0x48, 0, PutAll },
|
||||
{ "PHP", 0x0000001, 0x08, 0, PutAll },
|
||||
{ "PHX", 0x0000001, 0xda, 0, PutAll },
|
||||
{ "PHY", 0x0000001, 0x5a, 0, PutAll },
|
||||
{ "PLA", 0x0000001, 0x68, 0, PutAll },
|
||||
{ "PLP", 0x0000001, 0x28, 0, PutAll },
|
||||
{ "PLX", 0x0000001, 0xfa, 0, PutAll },
|
||||
{ "PLY", 0x0000001, 0x7a, 0, PutAll },
|
||||
{ "ROL", 0x000006F, 0x22, 1, PutAll },
|
||||
{ "ROR", 0x000006F, 0x62, 1, PutAll },
|
||||
{ "RTI", 0x0000001, 0x40, 0, PutAll },
|
||||
{ "RTS", 0x0000001, 0x60, 0, PutAll },
|
||||
{ "SBC", 0x080A66C, 0xe0, 0, PutAll },
|
||||
{ "SEC", 0x0000001, 0x38, 0, PutAll },
|
||||
{ "SED", 0x0000001, 0xf8, 0, PutAll },
|
||||
{ "SEI", 0x0000001, 0x78, 0, PutAll },
|
||||
{ "STA", 0x000A66C, 0x80, 0, PutAll },
|
||||
{ "STX", 0x000010c, 0x82, 1, PutAll },
|
||||
{ "STY", 0x000002c, 0x80, 1, PutAll },
|
||||
{ "STZ", 0x000006c, 0x04, 5, PutAll },
|
||||
{ "TAX", 0x0000001, 0xaa, 0, PutAll },
|
||||
{ "TAY", 0x0000001, 0xa8, 0, PutAll },
|
||||
{ "TRB", 0x000000c, 0x10, 1, PutAll },
|
||||
{ "TSB", 0x000000c, 0x00, 1, PutAll },
|
||||
{ "TSX", 0x0000001, 0xba, 0, PutAll },
|
||||
{ "TXA", 0x0000001, 0x8a, 0, PutAll },
|
||||
{ "TXS", 0x0000001, 0x9a, 0, PutAll },
|
||||
{ "TYA", 0x0000001, 0x98, 0, PutAll }
|
||||
}
|
||||
};
|
||||
|
||||
/* Instruction table for the 65816 */
|
||||
#define INS_COUNT_65816 101
|
||||
static const struct {
|
||||
unsigned Count;
|
||||
InsDesc Ins[INS_COUNT_65816];
|
||||
} InsTab65816 = {
|
||||
INS_COUNT_65816,
|
||||
{
|
||||
{ "ADC", 0x0b8f6fc, 0x60, 0, PutAll },
|
||||
{ "AND", 0x0b8f6fc, 0x20, 0, PutAll },
|
||||
{ "ASL", 0x000006e, 0x02, 1, PutAll },
|
||||
{ "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
|
||||
{ "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
|
||||
{ "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
|
||||
{ "BGE", 0x0020000, 0xb0, 0, PutPCRel8 }, /* == BCS */
|
||||
{ "BIT", 0x0a0006c, 0x00, 2, PutAll },
|
||||
{ "BLT", 0x0020000, 0x90, 0, PutPCRel8 }, /* == BCC */
|
||||
{ "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
|
||||
{ "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
|
||||
{ "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
|
||||
{ "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
|
||||
{ "BRK", 0x0000001, 0x00, 0, PutAll },
|
||||
{ "BRL", 0x0040000, 0x82, 0, PutPCRel16 },
|
||||
{ "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
|
||||
{ "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
|
||||
{ "CLC", 0x0000001, 0x18, 0, PutAll },
|
||||
{ "CLD", 0x0000001, 0xd8, 0, PutAll },
|
||||
{ "CLI", 0x0000001, 0x58, 0, PutAll },
|
||||
{ "CLV", 0x0000001, 0xb8, 0, PutAll },
|
||||
{ "CMP", 0x0b8f6fc, 0xc0, 0, PutAll },
|
||||
{ "COP", 0x0000004, 0x02, 6, PutAll },
|
||||
{ "CPA", 0x0b8f6fc, 0xc0, 0, PutAll }, /* == CMP */
|
||||
{ "CPX", 0x0c0000c, 0xe0, 1, PutAll },
|
||||
{ "CPY", 0x0c0000c, 0xc0, 1, PutAll },
|
||||
{ "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
|
||||
{ "DEC", 0x000006F, 0x00, 3, PutAll },
|
||||
{ "DEX", 0x0000001, 0xca, 0, PutAll },
|
||||
{ "DEY", 0x0000001, 0x88, 0, PutAll },
|
||||
{ "EOR", 0x0b8f6fc, 0x40, 0, PutAll },
|
||||
{ "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
|
||||
{ "INC", 0x000006F, 0x00, 4, PutAll },
|
||||
{ "INX", 0x0000001, 0xe8, 0, PutAll },
|
||||
{ "INY", 0x0000001, 0xc8, 0, PutAll },
|
||||
{ "JML", 0x0000810, 0x5c, 1, PutAll },
|
||||
{ "JMP", 0x0010818, 0x4c, 6, PutAll },
|
||||
{ "JSL", 0x0000010, 0x20, 7, PutAll },
|
||||
{ "JSR", 0x0010018, 0x20, 7, PutAll },
|
||||
{ "LDA", 0x0b8f6fc, 0xa0, 0, PutAll },
|
||||
{ "LDX", 0x0c0030c, 0xa2, 1, PutAll },
|
||||
{ "LDY", 0x0c0006c, 0xa0, 1, PutAll },
|
||||
{ "LSR", 0x000006F, 0x42, 1, PutAll },
|
||||
{ "MVN", 0x1000000, 0x54, 0, PutBlockMove },
|
||||
{ "MVP", 0x1000000, 0x44, 0, PutBlockMove },
|
||||
{ "NOP", 0x0000001, 0xea, 0, PutAll },
|
||||
{ "ORA", 0x0b8f6fc, 0x00, 0, PutAll },
|
||||
{ "PEA", 0x0000008, 0xf4, 6, PutAll },
|
||||
{ "PEI", 0x0800000, 0xd4, 0, PutAll },
|
||||
{ "PER", 0x0040000, 0x62, 0, PutPCRel16 },
|
||||
{ "PHA", 0x0000001, 0x48, 0, PutAll },
|
||||
{ "PHB", 0x0000001, 0x8b, 0, PutAll },
|
||||
{ "PHD", 0x0000001, 0x0b, 0, PutAll },
|
||||
{ "PHK", 0x0000001, 0x4b, 0, PutAll },
|
||||
{ "PHP", 0x0000001, 0x08, 0, PutAll },
|
||||
{ "PHX", 0x0000001, 0xda, 0, PutAll },
|
||||
{ "PHY", 0x0000001, 0x5a, 0, PutAll },
|
||||
{ "PLA", 0x0000001, 0x68, 0, PutAll },
|
||||
{ "PLB", 0x0000001, 0xab, 0, PutAll },
|
||||
{ "PLD", 0x0000001, 0x2b, 0, PutAll },
|
||||
{ "PLP", 0x0000001, 0x28, 0, PutAll },
|
||||
{ "PLX", 0x0000001, 0xfa, 0, PutAll },
|
||||
{ "PLY", 0x0000001, 0x7a, 0, PutAll },
|
||||
{ "REP", 0x0800000, 0xc2, 1, PutREP },
|
||||
{ "ROL", 0x000006F, 0x22, 1, PutAll },
|
||||
{ "ROR", 0x000006F, 0x62, 1, PutAll },
|
||||
{ "RTI", 0x0000001, 0x40, 0, PutAll },
|
||||
{ "RTL", 0x0000001, 0x6b, 0, PutAll },
|
||||
{ "RTS", 0x0000001, 0x60, 0, PutAll },
|
||||
{ "SBC", 0x0b8f6fc, 0xe0, 0, PutAll },
|
||||
{ "SEC", 0x0000001, 0x38, 0, PutAll },
|
||||
{ "SED", 0x0000001, 0xf8, 0, PutAll },
|
||||
{ "SEI", 0x0000001, 0x78, 0, PutAll },
|
||||
{ "SEP", 0x0800000, 0xe2, 1, PutSEP },
|
||||
{ "STA", 0x018f6fc, 0x80, 0, PutAll },
|
||||
{ "STP", 0x0000001, 0xdb, 0, PutAll },
|
||||
{ "STX", 0x000010c, 0x82, 1, PutAll },
|
||||
{ "STY", 0x000002c, 0x80, 1, PutAll },
|
||||
{ "STZ", 0x000006c, 0x04, 5, PutAll },
|
||||
{ "SWA", 0x0000001, 0xeb, 0, PutAll }, /* == XBA */
|
||||
{ "TAD", 0x0000001, 0x5b, 0, PutAll }, /* == TCD */
|
||||
{ "TAS", 0x0000001, 0x1b, 0, PutAll }, /* == TCS */
|
||||
{ "TAX", 0x0000001, 0xaa, 0, PutAll },
|
||||
{ "TAY", 0x0000001, 0xa8, 0, PutAll },
|
||||
{ "TCD", 0x0000001, 0x5b, 0, PutAll },
|
||||
{ "TCS", 0x0000001, 0x1b, 0, PutAll },
|
||||
{ "TDA", 0x0000001, 0x7b, 0, PutAll }, /* == TDC */
|
||||
{ "TDC", 0x0000001, 0x7b, 0, PutAll },
|
||||
{ "TRB", 0x000000c, 0x10, 1, PutAll },
|
||||
{ "TSA", 0x0000001, 0x3b, 0, PutAll }, /* == TSC */
|
||||
{ "TSB", 0x000000c, 0x00, 1, PutAll },
|
||||
{ "TSC", 0x0000001, 0x3b, 0, PutAll },
|
||||
{ "TSX", 0x0000001, 0xba, 0, PutAll },
|
||||
{ "TXA", 0x0000001, 0x8a, 0, PutAll },
|
||||
{ "TXS", 0x0000001, 0x9a, 0, PutAll },
|
||||
{ "TXY", 0x0000001, 0x9b, 0, PutAll },
|
||||
{ "TYA", 0x0000001, 0x98, 0, PutAll },
|
||||
{ "TYX", 0x0000001, 0xbb, 0, PutAll },
|
||||
{ "WAI", 0x0000001, 0xcb, 0, PutAll },
|
||||
{ "XBA", 0x0000001, 0xeb, 0, PutAll },
|
||||
{ "XCE", 0x0000001, 0xfb, 0, PutAll }
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef SUNPLUS
|
||||
/* Table for the SUNPLUS CPU */
|
||||
#include "sunplus.inc"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* The current CPU and an array with instruction tables */
|
||||
static enum CPUType CPU = CPU_6502;
|
||||
static const InsTable* InsTabs[CPU_COUNT] = {
|
||||
(const InsTable*) &InsTab6502,
|
||||
(const InsTable*) &InsTab65SC02,
|
||||
(const InsTable*) &InsTab65816,
|
||||
#ifdef SUNPLUS
|
||||
(const InsTable*) &InsTabSunPlus,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
};
|
||||
const InsTable* InsTab = (const InsTable*) &InsTab6502;
|
||||
|
||||
/* Table to build the effective opcode from a base opcode and an addressing
|
||||
* mode.
|
||||
*/
|
||||
unsigned char EATab [9][AMI_COUNT] = {
|
||||
{ /* Table 0 */
|
||||
0x00, 0x00, 0x05, 0x0D, 0x0F, 0x15, 0x1D, 0x1F,
|
||||
0x00, 0x19, 0x12, 0x00, 0x07, 0x11, 0x17, 0x01,
|
||||
0x00, 0x00, 0x00, 0x03, 0x13, 0x09, 0x00, 0x09,
|
||||
0x00
|
||||
},
|
||||
{ /* Table 1 */
|
||||
0x08, 0x08, 0x04, 0x0C, 0x00, 0x14, 0x1C, 0x00,
|
||||
0x14, 0x1C, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00
|
||||
},
|
||||
{ /* Table 2 */
|
||||
0x00, 0x00, 0x24, 0x2C, 0x0F, 0x34, 0x3C, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00,
|
||||
0x00
|
||||
},
|
||||
{ /* Table 3 */
|
||||
0x3A, 0x3A, 0xC6, 0xCE, 0x00, 0xD6, 0xDE, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00
|
||||
},
|
||||
{ /* Table 4 */
|
||||
0x1A, 0x1A, 0xE6, 0xEE, 0x00, 0xF6, 0xFE, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00
|
||||
},
|
||||
{ /* Table 5 */
|
||||
0x00, 0x00, 0x60, 0x98, 0x00, 0x70, 0x9E, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00
|
||||
},
|
||||
{ /* Table 6 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
|
||||
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00
|
||||
},
|
||||
{ /* Table 7 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00
|
||||
},
|
||||
{ /* Table 8 */
|
||||
0x00, 0x40, 0x01, 0x41, 0x00, 0x09, 0x49, 0x00,
|
||||
0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
|
||||
0x00
|
||||
},
|
||||
};
|
||||
|
||||
/* Table that encodes the additional bytes for each instruction */
|
||||
unsigned char ExtBytes [AMI_COUNT] = {
|
||||
0, /* Implicit */
|
||||
0, /* Accu */
|
||||
1, /* Direct */
|
||||
2, /* Absolute */
|
||||
3, /* Absolute long */
|
||||
1, /* Direct,X */
|
||||
2, /* Absolute,X */
|
||||
3, /* Absolute long,X */
|
||||
1, /* Direct,Y */
|
||||
2, /* Absolute,Y */
|
||||
1, /* (Direct) */
|
||||
2, /* (Absolute) */
|
||||
1, /* [Direct] */
|
||||
1, /* (Direct),Y */
|
||||
1, /* [Direct],Y */
|
||||
1, /* (Direct,X) */
|
||||
2, /* (Absolute,X) */
|
||||
1, /* Relative short */
|
||||
2, /* Relative long */
|
||||
1, /* r,s */
|
||||
1, /* (r,s),y */
|
||||
1, /* Immidiate accu */
|
||||
1, /* Immidiate index */
|
||||
1, /* Immidiate byte */
|
||||
2 /* Blockmove */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Handler functions */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static long PutImmed8 (const InsDesc* Ins)
|
||||
/* Parse and emit an immediate 8 bit instruction. Return the value of the
|
||||
* operand if it's available and const.
|
||||
*/
|
||||
{
|
||||
ExprNode* Expr;
|
||||
ExprNode* Bank;
|
||||
unsigned long AddrMode;
|
||||
unsigned char OpCode;
|
||||
long Val = -1;
|
||||
|
||||
/* Get the addressing mode used */
|
||||
GetEA (&AddrMode, &Expr, &Bank);
|
||||
|
||||
/* From the possible addressing modes, remove the ones that are invalid
|
||||
* for this instruction or CPU.
|
||||
*/
|
||||
AddrMode &= Ins->AddrMode;
|
||||
|
||||
/* If we have possible zero page addressing modes, and the expression
|
||||
* involved (if any) is not in byte range, remove the zero page addressing
|
||||
* modes.
|
||||
*/
|
||||
if (Expr && (AddrMode & AM_ZP) && !IsByteExpr (Expr)) {
|
||||
AddrMode &= ~AM_ZP;
|
||||
}
|
||||
|
||||
/* Check if we have any adressing modes left */
|
||||
if (AddrMode == 0) {
|
||||
Error (ERR_ILLEGAL_ADDR_MODE);
|
||||
return -1;
|
||||
}
|
||||
AddrMode = BitFind (AddrMode);
|
||||
|
||||
/* Build the opcode */
|
||||
OpCode = Ins->BaseCode | EATab [Ins->ExtCode][AddrMode];
|
||||
|
||||
/* If we have an expression and it's const, get it's value */
|
||||
if (Expr && IsConstExpr (Expr)) {
|
||||
Val = GetExprVal (Expr);
|
||||
}
|
||||
|
||||
/* Check how many extension bytes are needed and output the instruction */
|
||||
switch (ExtBytes [AddrMode]) {
|
||||
|
||||
case 1:
|
||||
Emit1 (OpCode, Expr);
|
||||
break;
|
||||
|
||||
default:
|
||||
Internal ("Invalid operand byte count: %u", ExtBytes [AddrMode]);
|
||||
}
|
||||
|
||||
/* Return the expression value */
|
||||
return Val;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PutPCRel8 (const InsDesc* Ins)
|
||||
/* Handle branches with a 8 bit distance */
|
||||
{
|
||||
EmitPCRel (Ins->BaseCode, BranchExpr (2), 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PutPCRel16 (const InsDesc* Ins)
|
||||
/* Handle branches with an 16 bit distance and PER */
|
||||
{
|
||||
EmitPCRel (Ins->BaseCode, BranchExpr (3), 2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PutBlockMove (const InsDesc* Ins)
|
||||
/* Handle the blockmove instructions */
|
||||
{
|
||||
Emit0 (Ins->BaseCode);
|
||||
EmitByte (Expression ());
|
||||
ConsumeComma ();
|
||||
EmitByte (Expression ());
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PutREP (const InsDesc* Ins)
|
||||
/* Emit a REP instruction, track register sizes */
|
||||
{
|
||||
/* Use the generic handler */
|
||||
long Val = PutImmed8 (Ins);
|
||||
|
||||
/* We track the status only for the 816 CPU and in smart mode */
|
||||
if (CPU == CPU_65816 && SmartMode) {
|
||||
|
||||
/* Check the range for Val. */
|
||||
if (Val < 0) {
|
||||
/* We had an error */
|
||||
Warning (WARN_CANNOT_TRACK_STATUS);
|
||||
} else {
|
||||
if (Val & 0x10) {
|
||||
/* Index registers to 16 bit */
|
||||
ExtBytes [AMI_IMM_INDEX] = 2;
|
||||
}
|
||||
if (Val & 0x20) {
|
||||
/* Accu to 16 bit */
|
||||
ExtBytes [AMI_IMM_ACCU] = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PutSEP (const InsDesc* Ins)
|
||||
/* Emit a SEP instruction, track register sizes */
|
||||
{
|
||||
/* Use the generic handler */
|
||||
long Val = PutImmed8 (Ins);
|
||||
|
||||
/* We track the status only for the 816 CPU and in smart mode */
|
||||
if (CPU == CPU_65816 && SmartMode) {
|
||||
|
||||
/* Check the range for Val. */
|
||||
if (Val < 0) {
|
||||
/* We had an error */
|
||||
Warning (WARN_CANNOT_TRACK_STATUS);
|
||||
} else {
|
||||
if (Val & 0x10) {
|
||||
/* Index registers to 8 bit */
|
||||
ExtBytes [AMI_IMM_INDEX] = 1;
|
||||
}
|
||||
if (Val & 0x20) {
|
||||
/* Accu to 8 bit */
|
||||
ExtBytes [AMI_IMM_ACCU] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PutAll (const InsDesc* Ins)
|
||||
/* Handle all other instructions */
|
||||
{
|
||||
ExprNode* Expr;
|
||||
ExprNode* Bank;
|
||||
unsigned long AddrModeSet;
|
||||
unsigned char OpCode;
|
||||
unsigned AddrMode;
|
||||
unsigned long AddrModeBit;
|
||||
|
||||
/* Get the addressing mode used */
|
||||
GetEA (&AddrModeSet, &Expr, &Bank);
|
||||
|
||||
/* From the possible addressing modes, remove the ones that are invalid
|
||||
* for this instruction or CPU.
|
||||
*/
|
||||
AddrModeSet &= Ins->AddrMode;
|
||||
|
||||
/* If we have possible zero page addressing modes, and the expression
|
||||
* involved (if any) is not in byte range, remove the zero page addressing
|
||||
* modes.
|
||||
*/
|
||||
if (Expr && (AddrModeSet & AM_ZP) && !IsByteExpr (Expr)) {
|
||||
AddrModeSet &= ~AM_ZP;
|
||||
}
|
||||
|
||||
/* Check if we have any adressing modes left */
|
||||
if (AddrModeSet == 0) {
|
||||
Error (ERR_ILLEGAL_ADDR_MODE);
|
||||
return;
|
||||
}
|
||||
AddrMode = BitFind (AddrModeSet);
|
||||
|
||||
/* Build the opcode */
|
||||
OpCode = Ins->BaseCode | EATab [Ins->ExtCode][AddrMode];
|
||||
|
||||
/* Check how many extension bytes are needed and output the instruction */
|
||||
switch (ExtBytes [AddrMode]) {
|
||||
|
||||
case 0:
|
||||
Emit0 (OpCode);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
Emit1 (OpCode, Expr);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
AddrModeBit = (1L << AddrMode);
|
||||
if (CPU == CPU_65816 && (AddrModeBit & (AM_ABS | AM_ABS_X | AM_ABS_Y))) {
|
||||
/* This is a 16 bit mode that uses an address. If in 65816,
|
||||
* mode, force this address into 16 bit range to allow
|
||||
* addressing inside a 64K segment.
|
||||
*/
|
||||
Emit2 (OpCode, ForceWordExpr (Expr));
|
||||
} else {
|
||||
Emit2 (OpCode, Expr);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if (Bank) {
|
||||
/* Separate bank given */
|
||||
Emit3b (OpCode, Expr, Bank);
|
||||
} else {
|
||||
/* One far argument */
|
||||
Emit3 (OpCode, Expr);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
Internal ("Invalid operand byte count: %u", ExtBytes [AddrMode]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static int CmpName (const void* Key, const void* Instr)
|
||||
/* Compare function for bsearch */
|
||||
{
|
||||
return strcmp ((const char*)Key, ((const InsDesc*) Instr)->Mnemonic);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SetCPU (enum CPUType NewCPU)
|
||||
/* Set a new CPU */
|
||||
{
|
||||
/* Make sure the parameter is correct */
|
||||
CHECK (NewCPU < CPU_COUNT);
|
||||
|
||||
/* Check if we have support for the new CPU, if so, use it */
|
||||
if (InsTabs[NewCPU]) {
|
||||
CPU = NewCPU;
|
||||
InsTab = InsTabs[CPU];
|
||||
} else {
|
||||
Error (ERR_CPU_NOT_SUPPORTED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
enum CPUType GetCPU (void)
|
||||
/* Return the current CPU */
|
||||
{
|
||||
return CPU;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int FindInstruction (const char* Ident)
|
||||
/* Check if Ident is a valid mnemonic. If so, return the index in the
|
||||
* instruction table. If not, return -1.
|
||||
*/
|
||||
{
|
||||
const InsDesc* I;
|
||||
char Key [sizeof (I->Mnemonic)];
|
||||
|
||||
/* Accept only strings with the right length */
|
||||
if (strlen (Ident) != sizeof (I->Mnemonic)-1) {
|
||||
/* Wrong length */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Make a copy, and uppercase that copy */
|
||||
Key [0] = toupper (Ident [0]);
|
||||
Key [1] = toupper (Ident [1]);
|
||||
Key [2] = toupper (Ident [2]);
|
||||
Key [3] = '\0';
|
||||
|
||||
/* Search for the key */
|
||||
I = bsearch (Key, InsTab->Ins, InsTab->Count, sizeof (InsDesc), CmpName);
|
||||
if (I == 0) {
|
||||
/* Not found */
|
||||
return -1;
|
||||
} else {
|
||||
/* Found, return the entry */
|
||||
return I - InsTab->Ins;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void HandleInstruction (unsigned Index)
|
||||
/* Handle the mnemonic with the given index */
|
||||
{
|
||||
/* Safety check */
|
||||
PRECONDITION (Index < InsTab->Count);
|
||||
|
||||
/* Skip the mnemonic token */
|
||||
NextTok ();
|
||||
|
||||
/* Call the handler */
|
||||
InsTab->Ins[Index].Emit (&InsTab->Ins[Index]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
156
src/ca65/instr.h
Normal file
156
src/ca65/instr.h
Normal file
@@ -0,0 +1,156 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* instr.h */
|
||||
/* */
|
||||
/* Instruction encoding for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998-2000 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef INSTR_H
|
||||
#define INSTR_H
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Supported CPUs */
|
||||
enum CPUType {
|
||||
CPU_6502,
|
||||
CPU_65C02,
|
||||
CPU_65816,
|
||||
CPU_SUNPLUS, /* Not in the freeware version - sorry */
|
||||
CPU_COUNT /* Count of different CPUs */
|
||||
};
|
||||
|
||||
/* Constants for the addressing mode. If an opcode is available in zero page
|
||||
* and absolut adressing mode, both bits are set. When checking for valid
|
||||
* modes, the zeropage bit is checked first. Similar, the implicit bit is set
|
||||
* on accu adressing modes, so the 'A' for accu adressing is not needed (but
|
||||
* may be specified).
|
||||
* When assembling for the 6502 or 65C02, all addressing modes that are not
|
||||
* available on these CPUs are removed before doing any checks.
|
||||
*/
|
||||
#define AM_IMPLICIT 0x00000003UL
|
||||
#define AM_ACCU 0x00000002UL
|
||||
#define AM_DIR 0x00000004UL
|
||||
#define AM_ABS 0x00000008UL
|
||||
#define AM_ABS_LONG 0x00000010UL
|
||||
#define AM_DIR_X 0x00000020UL
|
||||
#define AM_ABS_X 0x00000040UL
|
||||
#define AM_ABS_LONG_X 0x00000080UL
|
||||
#define AM_DIR_Y 0x00000100UL
|
||||
#define AM_ABS_Y 0x00000200UL
|
||||
#define AM_DIR_IND 0x00000400UL
|
||||
#define AM_ABS_IND 0x00000800UL
|
||||
#define AM_DIR_IND_LONG 0x00001000UL
|
||||
#define AM_DIR_IND_Y 0x00002000UL
|
||||
#define AM_DIR_IND_LONG_Y 0x00004000UL
|
||||
#define AM_DIR_X_IND 0x00008000UL
|
||||
#define AM_ABS_X_IND 0x00010000UL
|
||||
#define AM_REL 0x00020000UL
|
||||
#define AM_REL_LONG 0x00040000UL
|
||||
#define AM_STACK_REL 0x00080000UL
|
||||
#define AM_STACK_REL_IND_Y 0x00100000UL
|
||||
#define AM_IMM 0x00E00000UL
|
||||
#define AM_BLOCKMOVE 0x01000000UL
|
||||
|
||||
/* Bitmask for all ZP operations that have correspondent ABS ops */
|
||||
#define AM_ZP (AM_DIR | AM_DIR_X | AM_DIR_Y | AM_DIR_IND | AM_DIR_X_IND)
|
||||
|
||||
/* Bit numbers and count */
|
||||
#define AMI_IMM_ACCU 21
|
||||
#define AMI_IMM_INDEX 22
|
||||
#define AMI_COUNT 25
|
||||
|
||||
|
||||
|
||||
/* Description for one instruction */
|
||||
typedef struct InsDesc_ InsDesc;
|
||||
struct InsDesc_ {
|
||||
char Mnemonic [4];
|
||||
unsigned long AddrMode; /* Valid adressing modes */
|
||||
unsigned char BaseCode; /* Base opcode */
|
||||
unsigned char ExtCode; /* Number of ext code table */
|
||||
void (*Emit) (const InsDesc*);/* Handler function */
|
||||
};
|
||||
|
||||
/* An instruction table */
|
||||
typedef struct InsTable_ InsTable;
|
||||
struct InsTable_ {
|
||||
unsigned Count; /* Number of intstructions */
|
||||
InsDesc Ins[1]; /* Varying length */
|
||||
};
|
||||
|
||||
/* The instruction table for the currently active CPU */
|
||||
extern const InsTable* InsTab;
|
||||
|
||||
/* Table to build the effective opcode from a base opcode and an addressing
|
||||
* mode.
|
||||
*/
|
||||
extern unsigned char EATab [9][AMI_COUNT];
|
||||
|
||||
/* Table that encodes the additional bytes for each instruction */
|
||||
extern unsigned char ExtBytes [AMI_COUNT];
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void SetCPU (enum CPUType NewCPU);
|
||||
/* Set a new CPU */
|
||||
|
||||
enum CPUType GetCPU (void);
|
||||
/* Return the current CPU */
|
||||
|
||||
int FindInstruction (const char* Ident);
|
||||
/* Check if Ident is a valid mnemonic. If so, return the index in the
|
||||
* instruction table. If not, return -1.
|
||||
*/
|
||||
|
||||
void HandleInstruction (unsigned Index);
|
||||
/* Handle the mnemonic with the given index */
|
||||
|
||||
|
||||
|
||||
/* End of instr.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
437
src/ca65/listing.c
Normal file
437
src/ca65/listing.c
Normal file
@@ -0,0 +1,437 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* listing.c */
|
||||
/* */
|
||||
/* Listing support for the ca65 crossassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 2000 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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 <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "../common/segdefs.h"
|
||||
#include "../common/version.h"
|
||||
|
||||
#include "error.h"
|
||||
#include "fname.h"
|
||||
#include "global.h"
|
||||
#include "mem.h"
|
||||
#include "objcode.h"
|
||||
#include "listing.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Single linked list of lines */
|
||||
ListLine* LineList = 0; /* List of listing lines */
|
||||
ListLine* LineCur = 0; /* Current listing line */
|
||||
ListLine* LineLast = 0; /* Last (current) listing line */
|
||||
|
||||
/* Page and other formatting */
|
||||
int PageLength = -1; /* Length of a listing page */
|
||||
static unsigned PageNumber = 1; /* Current listing page number */
|
||||
static unsigned PageLines = 0; /* Current line on page */
|
||||
static unsigned ListBytes = 12; /* Number of bytes to list for one line */
|
||||
|
||||
/* Switch the listing on/off */
|
||||
static int ListingEnabled = 1; /* Enabled if > 0 */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void NewListingLine (const char* Line, unsigned char File, unsigned char Depth)
|
||||
/* Create a new ListLine struct and insert it */
|
||||
{
|
||||
/* Store only if listing is enabled */
|
||||
if (Listing) {
|
||||
|
||||
ListLine* L;
|
||||
|
||||
/* Get the length of the line */
|
||||
unsigned Len = strlen (Line);
|
||||
|
||||
/* Ignore trailing newlines */
|
||||
while (Len > 0 && Line[Len-1] == '\n') {
|
||||
--Len;
|
||||
}
|
||||
|
||||
/* Allocate memory */
|
||||
L = Xmalloc (sizeof (ListLine) + Len);
|
||||
|
||||
/* Initialize the fields. */
|
||||
L->Next = 0;
|
||||
L->FragList = 0;
|
||||
L->FragLast = 0;
|
||||
L->PC = GetPC ();
|
||||
L->Reloc = RelocMode;
|
||||
L->File = File;
|
||||
L->Depth = Depth;
|
||||
L->Output = (ListingEnabled > 0);
|
||||
L->ListBytes = (unsigned char) ListBytes;
|
||||
memcpy (L->Line, Line, Len);
|
||||
L->Line [Len] = '\0';
|
||||
|
||||
/* Insert the line into the list of lines */
|
||||
if (LineList == 0) {
|
||||
LineList = L;
|
||||
} else {
|
||||
LineLast->Next = L;
|
||||
}
|
||||
LineLast = L;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void EnableListing (void)
|
||||
/* Enable output of lines to the listing */
|
||||
{
|
||||
if (Listing) {
|
||||
/* If we're about to enable the listing, do this for the current line
|
||||
* also, so we will see the source line that did this.
|
||||
*/
|
||||
if (ListingEnabled++ == 0) {
|
||||
LineCur->Output = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DisableListing (void)
|
||||
/* Disable output of lines to the listing */
|
||||
{
|
||||
if (Listing) {
|
||||
if (ListingEnabled == 0) {
|
||||
/* Cannot switch the listing off once more */
|
||||
Error (ERR_COUNTER_UNDERFLOW);
|
||||
} else {
|
||||
--ListingEnabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SetListBytes (int Bytes)
|
||||
/* Set the maximum number of bytes listed for one line */
|
||||
{
|
||||
if (Bytes < 0) {
|
||||
Bytes = 0; /* Encode "unlimited" as zero */
|
||||
}
|
||||
ListBytes = Bytes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void InitListingLine (void)
|
||||
/* Initialize the current listing line */
|
||||
{
|
||||
if (Listing) {
|
||||
/* Make the last loaded line the current line */
|
||||
LineCur = LineLast;
|
||||
|
||||
/* Set the values for this line */
|
||||
CHECK (LineCur != 0);
|
||||
LineCur->PC = GetPC ();
|
||||
LineCur->Reloc = RelocMode;
|
||||
LineCur->Output = (ListingEnabled > 0);
|
||||
LineCur->ListBytes = (unsigned char) ListBytes;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static char* AddHex (char* S, unsigned Val)
|
||||
/* Add a hex byte in ASCII to the given string and return the new pointer */
|
||||
{
|
||||
static const char HexTab [16] = {
|
||||
'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
|
||||
};
|
||||
|
||||
*S++ = HexTab [(Val >> 4) & 0x0F];
|
||||
*S++ = HexTab [Val & 0x0F];
|
||||
|
||||
return S;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PrintPageHeader (FILE* F, const ListLine* L)
|
||||
/* Print the header for a new page. It is assumed that the given line is the
|
||||
* last line of the previous page.
|
||||
*/
|
||||
{
|
||||
/* Print the header on the new page */
|
||||
fprintf (F,
|
||||
"ca65 V%u.%u.%u - (C) Copyright 1998-2000 Ullrich von Bassewitz\n"
|
||||
"Main file : %s\n"
|
||||
"Current file: %s\n"
|
||||
"\n",
|
||||
VER_MAJOR, VER_MINOR, VER_PATCH,
|
||||
InFile,
|
||||
GetFileName (L->File));
|
||||
|
||||
/* Count pages, reset lines */
|
||||
++PageNumber;
|
||||
PageLines = 4;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PrintLine (FILE* F, const char* Header, const char* Line, const ListLine* L)
|
||||
/* Print one line to the listing file, adding a newline and counting lines */
|
||||
{
|
||||
/* Print the given line */
|
||||
fprintf (F, "%s%s\n", Header, Line);
|
||||
|
||||
/* Increment the current line */
|
||||
++PageLines;
|
||||
|
||||
/* Switch to a new page if needed. Do not switch, if the current line is
|
||||
* the last one, to avoid pages that consist of just the header.
|
||||
*/
|
||||
if (PageLength > 0 && PageLines >= PageLength && L->Next != 0) {
|
||||
/* Do a formfeed */
|
||||
putc ('\f', F);
|
||||
/* Print the header on the new page */
|
||||
PrintPageHeader (F, L);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static char* AddMult (char* S, char C, unsigned Count)
|
||||
/* Add multiple instances of character C to S, return updated S. */
|
||||
{
|
||||
memset (S, C, Count);
|
||||
return S + Count;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static char* MakeLineHeader (char* H, const ListLine* L)
|
||||
/* Prepare the line header */
|
||||
{
|
||||
char Mode;
|
||||
char Depth;
|
||||
|
||||
/* Setup the PC mode */
|
||||
Mode = (L->Reloc)? 'r' : ' ';
|
||||
|
||||
/* Set up the include depth */
|
||||
Depth = (L->Depth < 10)? L->Depth + '0' : '+';
|
||||
|
||||
/* Format the line */
|
||||
sprintf (H, "%06lX%c %c", L->PC, Mode, Depth);
|
||||
memset (H+9, ' ', LINE_HEADER_LEN-9);
|
||||
|
||||
/* Return the buffer */
|
||||
return H;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CreateListing (void)
|
||||
/* Create the listing */
|
||||
{
|
||||
FILE* F;
|
||||
Fragment* Frag;
|
||||
ListLine* L;
|
||||
char HeaderBuf [LINE_HEADER_LEN+1];
|
||||
|
||||
/* Create the name of the listing file if needed */
|
||||
if (ListFile == 0) {
|
||||
ListFile = MakeFilename (InFile, ListExt);
|
||||
}
|
||||
|
||||
/* Open the real listing file */
|
||||
F = fopen (ListFile, "w");
|
||||
if (F == 0) {
|
||||
Fatal (FAT_CANNOT_OPEN_LISTING, strerror (errno));
|
||||
}
|
||||
|
||||
/* Reset variables, print the header for the first page */
|
||||
PageNumber = 0;
|
||||
PrintPageHeader (F, LineList);
|
||||
|
||||
/* Terminate the header buffer. The last byte will never get overwritten */
|
||||
HeaderBuf [LINE_HEADER_LEN] = '\0';
|
||||
|
||||
/* Walk through all listing lines */
|
||||
L = LineList;
|
||||
while (L) {
|
||||
|
||||
char* Buf;
|
||||
char* B;
|
||||
unsigned Count;
|
||||
unsigned I;
|
||||
char* Line;
|
||||
|
||||
/* If we should not output this line, go to the next */
|
||||
if (L->Output == 0) {
|
||||
L = L->Next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If we don't have a fragment list for this line, things are easy */
|
||||
if (L->FragList == 0) {
|
||||
PrintLine (F, MakeLineHeader (HeaderBuf, L), L->Line, L);
|
||||
L = L->Next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Count the number of bytes in the complete fragment list */
|
||||
Count = 0;
|
||||
Frag = L->FragList;
|
||||
while (Frag) {
|
||||
Count += Frag->Len;
|
||||
Frag = Frag->LineList;
|
||||
}
|
||||
|
||||
/* Allocate memory for the given number of bytes */
|
||||
Buf = Xmalloc (Count*2+1);
|
||||
|
||||
/* Copy an ASCII representation of the bytes into the buffer */
|
||||
B = Buf;
|
||||
Frag = L->FragList;
|
||||
while (Frag) {
|
||||
|
||||
/* Write data depending on the type */
|
||||
switch (Frag->Type) {
|
||||
|
||||
case FRAG_LITERAL:
|
||||
for (I = 0; I < Frag->Len; ++I) {
|
||||
B = AddHex (B, Frag->V.Data[I]);
|
||||
}
|
||||
break;
|
||||
|
||||
case FRAG_EXPR:
|
||||
case FRAG_SEXPR:
|
||||
B = AddMult (B, 'r', Frag->Len*2);
|
||||
break;
|
||||
|
||||
case FRAG_FILL:
|
||||
B = AddMult (B, 'x', Frag->Len*2);
|
||||
break;
|
||||
|
||||
default:
|
||||
Internal ("Invalid fragment type: %u", Frag->Type);
|
||||
|
||||
}
|
||||
|
||||
/* Next fragment */
|
||||
Frag = Frag->LineList;
|
||||
|
||||
}
|
||||
|
||||
/* Limit the number of bytes actually printed */
|
||||
if (L->ListBytes != 0) {
|
||||
/* Not unlimited */
|
||||
if (Count > L->ListBytes) {
|
||||
Count = L->ListBytes;
|
||||
}
|
||||
}
|
||||
|
||||
/* Output the data. The format of a listing line is:
|
||||
*
|
||||
* PPPPPPm I 11 22 33 44
|
||||
*
|
||||
* where
|
||||
*
|
||||
* PPPPPP is the PC
|
||||
* m is the mode ('r' or empty)
|
||||
* I is the include level
|
||||
* 11 .. are code or data bytes
|
||||
*/
|
||||
Line = L->Line;
|
||||
B = Buf;
|
||||
while (Count) {
|
||||
|
||||
unsigned Chunk;
|
||||
char* P;
|
||||
|
||||
/* Prepare the line header */
|
||||
MakeLineHeader (HeaderBuf, L);
|
||||
|
||||
/* Get the number of bytes for the next line */
|
||||
Chunk = Count;
|
||||
if (Chunk > 4) {
|
||||
Chunk = 4;
|
||||
}
|
||||
Count -= Chunk;
|
||||
|
||||
/* Increment the program counter. Since we don't need the PC stored
|
||||
* in the LineList object for anything else, just increment this
|
||||
* variable.
|
||||
*/
|
||||
L->PC += Chunk;
|
||||
|
||||
/* Copy the bytes into the line */
|
||||
P = HeaderBuf + 11;
|
||||
for (I = 0; I < Chunk; ++I) {
|
||||
*P++ = *B++;
|
||||
*P++ = *B++;
|
||||
*P++ = ' ';
|
||||
}
|
||||
|
||||
/* Output this line */
|
||||
PrintLine (F, HeaderBuf, Line, L);
|
||||
|
||||
/* Don't output a line twice */
|
||||
Line = "";
|
||||
|
||||
}
|
||||
|
||||
/* Delete the temporary buffer */
|
||||
Xfree (Buf);
|
||||
|
||||
/* Next line */
|
||||
L = L->Next;
|
||||
|
||||
}
|
||||
|
||||
/* Close the listing file */
|
||||
(void) fclose (F);
|
||||
}
|
||||
|
||||
|
||||
|
||||
116
src/ca65/listing.h
Normal file
116
src/ca65/listing.h
Normal file
@@ -0,0 +1,116 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* listing.h */
|
||||
/* */
|
||||
/* Listing support for the ca65 crossassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 2000 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef LISTING_H
|
||||
#define LISTING_H
|
||||
|
||||
|
||||
|
||||
#include "fragment.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Length of the header of a listing line */
|
||||
#define LINE_HEADER_LEN 24
|
||||
|
||||
/* One listing line as it is stored in memory */
|
||||
typedef struct ListLine_ ListLine;
|
||||
struct ListLine_ {
|
||||
ListLine* Next; /* Pointer to next line */
|
||||
Fragment* FragList; /* List of fragments for this line */
|
||||
Fragment* FragLast; /* Last entry in fragment list */
|
||||
unsigned long PC; /* Program counter for this line */
|
||||
unsigned char Reloc; /* Relocatable mode? */
|
||||
unsigned char File; /* From which file is the line? */
|
||||
unsigned char Depth; /* Include depth */
|
||||
unsigned char Output; /* Should we output this line? */
|
||||
unsigned char ListBytes; /* How many bytes at max? */
|
||||
char Line[1]; /* Line with dynamic length */
|
||||
};
|
||||
|
||||
/* Single linked list of lines */
|
||||
extern ListLine* LineList; /* List of listing lines */
|
||||
extern ListLine* LineCur; /* Current listing line */
|
||||
extern ListLine* LineLast; /* Last listing line */
|
||||
|
||||
/* Page formatting */
|
||||
#define MIN_PAGE_LEN 32
|
||||
#define MAX_PAGE_LEN 127
|
||||
extern int PageLength; /* Length of a listing page */
|
||||
|
||||
/* Byte for one listing line */
|
||||
#define MIN_LIST_BYTES 4
|
||||
#define MAX_LIST_BYTES 255
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void NewListingLine (const char* Line, unsigned char File, unsigned char Depth);
|
||||
/* Create a new ListLine struct */
|
||||
|
||||
void EnableListing (void);
|
||||
/* Enable output of lines to the listing */
|
||||
|
||||
void DisableListing (void);
|
||||
/* Disable output of lines to the listing */
|
||||
|
||||
void SetListBytes (int Bytes);
|
||||
/* Set the maximum number of bytes listed for one line */
|
||||
|
||||
void InitListingLine (void);
|
||||
/* Initialize the current listing line */
|
||||
|
||||
void CreateListing (void);
|
||||
/* Create the listing */
|
||||
|
||||
|
||||
|
||||
/* End of listing.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
154
src/ca65/macpack.c
Normal file
154
src/ca65/macpack.c
Normal file
@@ -0,0 +1,154 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* macpack.c */
|
||||
/* */
|
||||
/* Predefined macro packages for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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 "error.h"
|
||||
#include "scanner.h"
|
||||
#include "macpack.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Predefined packages */
|
||||
static const char MacGeneric [] = /* Generic macros */
|
||||
".macro add Arg\n"
|
||||
" clc\n"
|
||||
" adc Arg\n"
|
||||
".endmacro\n\n"
|
||||
".macro sub Arg\n"
|
||||
" sec\n"
|
||||
" sbc Arg\n"
|
||||
".endmacro\n\n";
|
||||
|
||||
|
||||
|
||||
static const char MacLongBranch [] = /* Long branch macros */
|
||||
".macro jeq Target\n"
|
||||
" .if .def(Target) .and ((*+2)-(Target) <= 127)\n"
|
||||
" beq Target\n"
|
||||
" .else\n"
|
||||
" bne *+5\n"
|
||||
" jmp Target\n"
|
||||
" .endif\n"
|
||||
".endmacro\n\n"
|
||||
".macro jne Target\n"
|
||||
" .if .def(Target) .and ((*+2)-(Target) <= 127)\n"
|
||||
" bne Target\n"
|
||||
" .else\n"
|
||||
" beq *+5\n"
|
||||
" jmp Target\n"
|
||||
" .endif\n"
|
||||
".endmacro\n\n"
|
||||
".macro jmi Target\n"
|
||||
" .if .def(Target) .and ((*+2)-(Target) <= 127)\n"
|
||||
" bmi Target\n"
|
||||
" .else\n"
|
||||
" bpl *+5\n"
|
||||
" jmp Target\n"
|
||||
" .endif\n"
|
||||
".endmacro\n\n"
|
||||
".macro jpl Target\n"
|
||||
" .if .def(Target) .and ((*+2)-(Target) <= 127)\n"
|
||||
" bpl Target\n"
|
||||
" .else\n"
|
||||
" bmi *+5\n"
|
||||
" jmp Target\n"
|
||||
" .endif\n"
|
||||
".endmacro\n\n"
|
||||
".macro jcs Target\n"
|
||||
" .if .def(Target) .and ((*+2)-(Target) <= 127)\n"
|
||||
" bcs Target\n"
|
||||
" .else\n"
|
||||
" bcc *+5\n"
|
||||
" jmp Target\n"
|
||||
" .endif\n"
|
||||
".endmacro\n\n"
|
||||
".macro jcc Target\n"
|
||||
" .if .def(Target) .and ((*+2)-(Target) <= 127)\n"
|
||||
" bcc Target\n"
|
||||
" .else\n"
|
||||
" bcs *+5\n"
|
||||
" jmp Target\n"
|
||||
" .endif\n"
|
||||
".endmacro\n\n"
|
||||
".macro jvs Target\n"
|
||||
" .if .def(Target) .and ((*+2)-(Target) <= 127)\n"
|
||||
" bvs Target\n"
|
||||
" .else\n"
|
||||
" bvc *+5\n"
|
||||
" jmp Target\n"
|
||||
" .endif\n"
|
||||
".endmacro\n\n"
|
||||
".macro jvc Target\n"
|
||||
" .if .def(Target) .and ((*+2)-(Target) <= 127)\n"
|
||||
" bvc Target\n"
|
||||
" .else\n"
|
||||
" bvs *+5\n"
|
||||
" jmp Target\n"
|
||||
" .endif\n"
|
||||
".endmacro\n\n";
|
||||
|
||||
|
||||
|
||||
/* Table with pointers to the different packages */
|
||||
static const char* MacPackages [] = {
|
||||
MacGeneric,
|
||||
MacLongBranch,
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void InsertMacPack (unsigned Id)
|
||||
/* Insert the macro package with the given id in the input stream */
|
||||
{
|
||||
/* Check the parameter */
|
||||
CHECK (Id < sizeof (MacPackages) / sizeof (MacPackages [0]));
|
||||
|
||||
/* Insert the package */
|
||||
NewInputData (MacPackages [Id], 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
69
src/ca65/macpack.h
Normal file
69
src/ca65/macpack.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* macpack.h */
|
||||
/* */
|
||||
/* Predefined macro packages for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef MACPACK_H
|
||||
#define MACPACK_H
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Constants for the predefined packages */
|
||||
#define MAC_GENERIC 0
|
||||
#define MAC_LONGBRANCH 1
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void InsertMacPack (unsigned Id);
|
||||
/* Insert the macro package with the given id in the input stream */
|
||||
|
||||
|
||||
|
||||
/* End of macpack.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
769
src/ca65/macro.c
Normal file
769
src/ca65/macro.c
Normal file
@@ -0,0 +1,769 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* macro.c */
|
||||
/* */
|
||||
/* Macros for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998-2000 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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 <string.h>
|
||||
|
||||
#include "../common/hashstr.h"
|
||||
|
||||
#include "mem.h"
|
||||
#include "error.h"
|
||||
#include "scanner.h"
|
||||
#include "toknode.h"
|
||||
#include "pseudo.h"
|
||||
#include "macro.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Struct that describes an identifer (macro param, local list) */
|
||||
typedef struct IdDesc_ IdDesc;
|
||||
struct IdDesc_ {
|
||||
IdDesc* Next; /* Linked list */
|
||||
char Id [1]; /* Identifier, dynamically allocated */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Struct that describes a macro definition */
|
||||
typedef struct Macro_ Macro;
|
||||
struct Macro_ {
|
||||
Macro* Next; /* Next macro with same hash */
|
||||
Macro* List; /* List of all macros */
|
||||
unsigned LocalCount; /* Count of local symbols */
|
||||
IdDesc* Locals; /* List of local symbols */
|
||||
unsigned ParamCount; /* Parameter count of macro */
|
||||
IdDesc* Params; /* Identifiers of macro parameters */
|
||||
unsigned TokCount; /* Number of tokens for this macro */
|
||||
TokNode* TokRoot; /* Root of token list */
|
||||
TokNode* TokLast; /* Pointer to last token in list */
|
||||
unsigned char Style; /* Macro style */
|
||||
char Name [1]; /* Macro name, dynamically allocated */
|
||||
};
|
||||
|
||||
/* Macro hash table */
|
||||
#define HASHTAB_SIZE 117
|
||||
static Macro* MacroTab [HASHTAB_SIZE];
|
||||
|
||||
/* Global macro data */
|
||||
static Macro* MacroRoot = 0; /* List of all macros */
|
||||
|
||||
/* Structs that holds data for a macro expansion */
|
||||
typedef struct MacExp_ MacExp;
|
||||
struct MacExp_ {
|
||||
MacExp* Next; /* Pointer to next expansion */
|
||||
Macro* M; /* Which macro do we expand? */
|
||||
TokNode* Exp; /* Pointer to current token */
|
||||
TokNode* Final; /* Pointer to final token */
|
||||
unsigned LocalStart; /* Start of counter for local symbol names */
|
||||
unsigned ParamCount; /* Number of actual parameters */
|
||||
TokNode** Params; /* List of actual parameters */
|
||||
TokNode* ParamExp; /* Node for expanding parameters */
|
||||
};
|
||||
|
||||
/* Data for macro expansions */
|
||||
#define MAX_MACRO_EXPANSIONS 255
|
||||
static unsigned MacroNesting = 0;
|
||||
static MacExp* CurMac = 0;
|
||||
static unsigned LocalName = 0;
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static IdDesc* NewIdDesc (const char* Id)
|
||||
/* Create a new IdDesc, initialize and return it */
|
||||
{
|
||||
/* Allocate memory */
|
||||
unsigned Len = strlen (Id);
|
||||
IdDesc* I = Xmalloc (sizeof (IdDesc) + Len);
|
||||
|
||||
/* Initialize the struct */
|
||||
I->Next = 0;
|
||||
memcpy (I->Id, Id, Len);
|
||||
I->Id [Len] = '\0';
|
||||
|
||||
/* Return the new struct */
|
||||
return I;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static Macro* NewMacro (const char* Name, unsigned HashVal, unsigned char Style)
|
||||
/* Generate a new macro entry, initialize and return it */
|
||||
{
|
||||
/* Allocate memory */
|
||||
unsigned Len = strlen (Name);
|
||||
Macro* M = Xmalloc (sizeof (Macro) + Len);
|
||||
|
||||
/* Initialize the macro struct */
|
||||
M->LocalCount = 0;
|
||||
M->ParamCount = 0;
|
||||
M->Params = 0;
|
||||
M->TokCount = 0;
|
||||
M->TokRoot = 0;
|
||||
M->TokLast = 0;
|
||||
M->Style = Style;
|
||||
memcpy (M->Name, Name, Len);
|
||||
M->Name [Len] = '\0';
|
||||
|
||||
/* Insert the macro into the global macro list */
|
||||
M->List = MacroRoot;
|
||||
MacroRoot = M;
|
||||
|
||||
/* Insert the macro into the hash table */
|
||||
M->Next = MacroTab [HashVal];
|
||||
MacroTab [HashVal] = M;
|
||||
|
||||
/* Return the new macro struct */
|
||||
return M;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static MacExp* NewMacExp (Macro* M)
|
||||
/* Create a new expansion structure for the given macro */
|
||||
{
|
||||
unsigned I;
|
||||
|
||||
/* Allocate memory */
|
||||
MacExp* E = Xmalloc (sizeof (MacExp));
|
||||
|
||||
/* Initialize the data */
|
||||
E->M = M;
|
||||
E->Exp = M->TokRoot;
|
||||
E->Final = 0;
|
||||
E->LocalStart = LocalName;
|
||||
LocalName += M->LocalCount;
|
||||
E->ParamCount = 0;
|
||||
E->Params = Xmalloc (M->ParamCount * sizeof (TokNode*));
|
||||
E->ParamExp = 0;
|
||||
for (I = 0; I < M->ParamCount; ++I) {
|
||||
E->Params [I] = 0;
|
||||
}
|
||||
|
||||
/* And return it... */
|
||||
return E;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void MacInsertExp (MacExp* E)
|
||||
/* Insert a macro expansion into the list */
|
||||
{
|
||||
E->Next = CurMac;
|
||||
CurMac = E;
|
||||
++MacroNesting;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void FreeMacExp (void)
|
||||
/* Remove and free the current macro expansion */
|
||||
{
|
||||
unsigned I;
|
||||
MacExp* E;
|
||||
|
||||
/* Free the parameter list */
|
||||
for (I = 0; I < CurMac->ParamCount; ++I) {
|
||||
Xfree (CurMac->Params [I]);
|
||||
}
|
||||
Xfree (CurMac->Params);
|
||||
|
||||
/* Free the final token if we have one */
|
||||
if (CurMac->Final) {
|
||||
FreeTokNode (CurMac->Final);
|
||||
}
|
||||
|
||||
/* Reset the list pointer */
|
||||
E = CurMac;
|
||||
CurMac = E->Next;
|
||||
--MacroNesting;
|
||||
|
||||
/* Free the structure itself */
|
||||
Xfree (E);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void MacSkipDef (unsigned Style)
|
||||
/* Skip a macro definition */
|
||||
{
|
||||
if (Style == MAC_STYLE_CLASSIC) {
|
||||
/* Skip tokens until we reach the final .endmacro */
|
||||
while (Tok != TOK_ENDMACRO && Tok != TOK_EOF) {
|
||||
NextTok ();
|
||||
}
|
||||
if (Tok != TOK_EOF) {
|
||||
SkipUntilSep ();
|
||||
} else {
|
||||
Error (ERR_ENDMACRO_EXPECTED);
|
||||
}
|
||||
} else {
|
||||
/* Skip until end of line */
|
||||
SkipUntilSep ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static Macro* MacFind (const char* Name, unsigned HashVal)
|
||||
/* Search for a macro in the hash table */
|
||||
{
|
||||
/* Search for the identifier */
|
||||
Macro* M = MacroTab [HashVal];
|
||||
while (M) {
|
||||
if (strcmp (Name, M->Name) == 0) {
|
||||
return M;
|
||||
}
|
||||
M = M->Next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MacDef (unsigned Style)
|
||||
/* Parse a macro definition */
|
||||
{
|
||||
Macro* M;
|
||||
TokNode* T;
|
||||
unsigned HashVal;
|
||||
int HaveParams;
|
||||
|
||||
/* We expect a macro name here */
|
||||
if (Tok != TOK_IDENT) {
|
||||
Error (ERR_IDENT_EXPECTED);
|
||||
MacSkipDef (Style);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Generate the hash value */
|
||||
HashVal = HashStr (SVal) % HASHTAB_SIZE;
|
||||
|
||||
/* Did we already define that macro? */
|
||||
if (MacFind (SVal, HashVal) != 0) {
|
||||
/* Macro is already defined */
|
||||
Error (ERR_SYM_ALREADY_DEFINED, SVal);
|
||||
/* Skip tokens until we reach the final .endmacro */
|
||||
MacSkipDef (Style);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Define the macro */
|
||||
M = NewMacro (SVal, HashVal, Style);
|
||||
NextTok ();
|
||||
|
||||
/* If we have a DEFINE style macro, we may have parameters in braces,
|
||||
* otherwise we may have parameters without braces.
|
||||
*/
|
||||
if (Style == MAC_STYLE_CLASSIC) {
|
||||
HaveParams = 1;
|
||||
} else {
|
||||
if (Tok == TOK_LPAREN) {
|
||||
HaveParams = 1;
|
||||
NextTok ();
|
||||
} else {
|
||||
HaveParams = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse the parameter list */
|
||||
if (HaveParams) {
|
||||
|
||||
while (Tok == TOK_IDENT) {
|
||||
|
||||
/* Create a struct holding the identifier */
|
||||
IdDesc* I = NewIdDesc (SVal);
|
||||
|
||||
/* Insert the struct into the list, checking for duplicate idents */
|
||||
if (M->ParamCount == 0) {
|
||||
M->Params = I;
|
||||
} else {
|
||||
IdDesc* List = M->Params;
|
||||
while (1) {
|
||||
if (strcmp (List->Id, SVal) == 0) {
|
||||
Error (ERR_SYM_ALREADY_DEFINED, SVal);
|
||||
}
|
||||
if (List->Next == 0) {
|
||||
break;
|
||||
} else {
|
||||
List = List->Next;
|
||||
}
|
||||
}
|
||||
List->Next = I;
|
||||
}
|
||||
++M->ParamCount;
|
||||
|
||||
/* Skip the name */
|
||||
NextTok ();
|
||||
|
||||
/* Maybe there are more params... */
|
||||
if (Tok == TOK_COMMA) {
|
||||
NextTok ();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* For class macros, we expect a separator token, for define style macros,
|
||||
* we expect the closing paren.
|
||||
*/
|
||||
if (Style == MAC_STYLE_CLASSIC) {
|
||||
ConsumeSep ();
|
||||
} else if (HaveParams) {
|
||||
ConsumeRParen ();
|
||||
}
|
||||
|
||||
/* Preparse the macro body. We will read the tokens until we reach end of
|
||||
* file, or a .endmacro (or end of line for DEFINE style macros) and store
|
||||
* them into an token list internal to the macro. For classic macros, there
|
||||
* the .LOCAL command is detected and removed at this time.
|
||||
*/
|
||||
while (1) {
|
||||
|
||||
/* Check for end of macro */
|
||||
if (Style == MAC_STYLE_CLASSIC) {
|
||||
/* In classic macros, only .endmacro is allowed */
|
||||
if (Tok == TOK_ENDMACRO) {
|
||||
/* Done */
|
||||
break;
|
||||
}
|
||||
/* May not have end of file in a macro definition */
|
||||
if (Tok == TOK_EOF) {
|
||||
Error (ERR_ENDMACRO_EXPECTED);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
/* Accept a newline or end of file for new style macros */
|
||||
if (Tok == TOK_SEP || Tok == TOK_EOF) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for a .LOCAL declaration */
|
||||
if (Tok == TOK_LOCAL && Style == MAC_STYLE_CLASSIC) {
|
||||
|
||||
while (1) {
|
||||
|
||||
IdDesc* I;
|
||||
|
||||
/* Skip .local or comma */
|
||||
NextTok ();
|
||||
|
||||
/* Need an identifer */
|
||||
if (Tok != TOK_IDENT) {
|
||||
Error (ERR_IDENT_EXPECTED);
|
||||
SkipUntilSep ();
|
||||
break;
|
||||
}
|
||||
|
||||
/* Put the identifier into the locals list and skip it */
|
||||
I = NewIdDesc (SVal);
|
||||
I->Next = M->Locals;
|
||||
M->Locals = I;
|
||||
++M->LocalCount;
|
||||
NextTok ();
|
||||
|
||||
/* Check for end of list */
|
||||
if (Tok != TOK_COMMA) {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* We need end of line after the locals */
|
||||
ConsumeSep ();
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Create a token node for the current token */
|
||||
T = NewTokNode ();
|
||||
|
||||
/* If the token is an ident, check if it is a local parameter */
|
||||
if (Tok == TOK_IDENT) {
|
||||
unsigned Count = 0;
|
||||
IdDesc* I = M->Params;
|
||||
while (I) {
|
||||
if (strcmp (I->Id, SVal) == 0) {
|
||||
/* Local param name, replace it */
|
||||
T->Tok = TOK_MACPARAM;
|
||||
T->IVal = Count;
|
||||
break;
|
||||
}
|
||||
++Count;
|
||||
I = I->Next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Insert the new token in the list */
|
||||
if (M->TokCount == 0) {
|
||||
/* First token */
|
||||
M->TokRoot = M->TokLast = T;
|
||||
} else {
|
||||
/* We have already tokens */
|
||||
M->TokLast->Next = T;
|
||||
M->TokLast = T;
|
||||
}
|
||||
++M->TokCount;
|
||||
|
||||
/* Read the next token */
|
||||
NextTok ();
|
||||
}
|
||||
|
||||
/* Skip the .endmacro for a classic macro */
|
||||
if (Style == MAC_STYLE_CLASSIC) {
|
||||
NextTok ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void StartExpClassic (Macro* M)
|
||||
/* Start expanding the classic macro M */
|
||||
{
|
||||
MacExp* E;
|
||||
|
||||
/* Skip the macro name */
|
||||
NextTok ();
|
||||
|
||||
/* Create a structure holding expansion data */
|
||||
E = NewMacExp (M);
|
||||
|
||||
/* Read the actual parameters */
|
||||
while (Tok != TOK_SEP && Tok != TOK_EOF) {
|
||||
|
||||
TokNode* Last;
|
||||
|
||||
/* Check for maximum parameter count */
|
||||
if (E->ParamCount >= M->ParamCount) {
|
||||
Error (ERR_TOO_MANY_PARAMS);
|
||||
SkipUntilSep ();
|
||||
break;
|
||||
}
|
||||
|
||||
/* Read tokens for one parameter, accept empty params */
|
||||
Last = 0;
|
||||
while (Tok != TOK_COMMA && Tok != TOK_SEP) {
|
||||
|
||||
TokNode* T;
|
||||
|
||||
/* Check for end of file */
|
||||
if (Tok == TOK_EOF) {
|
||||
Error (ERR_SYNTAX);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the next token in a node */
|
||||
T = NewTokNode ();
|
||||
|
||||
/* Insert it into the list */
|
||||
if (Last == 0) {
|
||||
E->Params [E->ParamCount] = T;
|
||||
} else {
|
||||
Last->Next = T;
|
||||
}
|
||||
Last = T;
|
||||
|
||||
/* And skip it... */
|
||||
NextTok ();
|
||||
}
|
||||
|
||||
/* One parameter more */
|
||||
++E->ParamCount;
|
||||
|
||||
/* Check for a comma */
|
||||
if (Tok == TOK_COMMA) {
|
||||
NextTok ();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Insert the newly created structure into the expansion list */
|
||||
MacInsertExp (E);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void StartExpDefine (Macro* M)
|
||||
/* Start expanding a DEFINE style macro */
|
||||
{
|
||||
/* Create a structure holding expansion data */
|
||||
MacExp* E = NewMacExp (M);
|
||||
|
||||
/* A define style macro must be called with as many actual parameters
|
||||
* as there are formal ones. Get the parameter count.
|
||||
*/
|
||||
unsigned Count = M->ParamCount;
|
||||
|
||||
/* Skip the current token */
|
||||
NextTok ();
|
||||
|
||||
/* Read the actual parameters */
|
||||
while (Count--) {
|
||||
|
||||
TokNode* Last;
|
||||
|
||||
/* Check if there is really a parameter */
|
||||
if (Tok == TOK_SEP || Tok == TOK_EOF || Tok == TOK_COMMA) {
|
||||
Error (ERR_MACRO_PARAM_EXPECTED);
|
||||
SkipUntilSep ();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Read tokens for one parameter */
|
||||
Last = 0;
|
||||
do {
|
||||
|
||||
TokNode* T;
|
||||
|
||||
/* Get the next token in a node */
|
||||
T = NewTokNode ();
|
||||
|
||||
/* Insert it into the list */
|
||||
if (Last == 0) {
|
||||
E->Params [E->ParamCount] = T;
|
||||
} else {
|
||||
Last->Next = T;
|
||||
}
|
||||
Last = T;
|
||||
|
||||
/* And skip it... */
|
||||
NextTok ();
|
||||
|
||||
} while (Tok != TOK_COMMA && Tok != TOK_SEP && Tok != TOK_EOF);
|
||||
|
||||
/* One parameter more */
|
||||
++E->ParamCount;
|
||||
|
||||
/* Check for a comma */
|
||||
if (Count > 0) {
|
||||
if (Tok == TOK_COMMA) {
|
||||
NextTok ();
|
||||
} else {
|
||||
Error (ERR_COMMA_EXPECTED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Macro expansion will overwrite the current token. This is a problem
|
||||
* for define style macros since these are called from the scanner level.
|
||||
* To avoid it, remember the current token and re-insert it if macro
|
||||
* expansion is done.
|
||||
*/
|
||||
E->Final = NewTokNode ();
|
||||
|
||||
/* Insert the newly created structure into the expansion list */
|
||||
MacInsertExp (E);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MacExpandStart (void)
|
||||
/* Start expanding the macro in SVal */
|
||||
{
|
||||
Macro* M;
|
||||
|
||||
/* Beware of runoff macros */
|
||||
if (MacroNesting == MAX_MACRO_EXPANSIONS) {
|
||||
Fatal (FAT_MACRO_NESTING);
|
||||
}
|
||||
|
||||
/* Search for the macro */
|
||||
M = MacFind (SVal, HashStr (SVal) % HASHTAB_SIZE);
|
||||
CHECK (M != 0);
|
||||
|
||||
/* Call the apropriate subroutine */
|
||||
switch (M->Style) {
|
||||
case MAC_STYLE_CLASSIC: StartExpClassic (M); break;
|
||||
case MAC_STYLE_DEFINE: StartExpDefine (M); break;
|
||||
default: Internal ("Invalid macro style: %d", M->Style);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int MacExpand (void)
|
||||
/* If we're currently expanding a macro, set the the scanner token and
|
||||
* attribute to the next value and return true. If we are not expanding
|
||||
* a macro, return false.
|
||||
*/
|
||||
{
|
||||
if (MacroNesting == 0) {
|
||||
/* Not expanding a macro */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We're expanding a macro. Check if we are expanding one of the
|
||||
* macro parameters.
|
||||
*/
|
||||
if (CurMac->ParamExp) {
|
||||
|
||||
/* Ok, use token from parameter list */
|
||||
TokSet (CurMac->ParamExp);
|
||||
|
||||
/* Set pointer to next token */
|
||||
CurMac->ParamExp = CurMac->ParamExp->Next;
|
||||
|
||||
/* Done */
|
||||
return 1;
|
||||
|
||||
} else if (CurMac->Exp) {
|
||||
|
||||
/* We're not expanding a parameter, use next macro token */
|
||||
TokSet (CurMac->Exp);
|
||||
|
||||
/* Set pointer to next token */
|
||||
CurMac->Exp = CurMac->Exp->Next;
|
||||
|
||||
/* Is it a request for actual parameter count? */
|
||||
if (Tok == TOK_PARAMCOUNT) {
|
||||
Tok = TOK_INTCON;
|
||||
IVal = CurMac->ParamCount;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Is it an .exitmacro command? */
|
||||
if (Tok == TOK_EXITMACRO) {
|
||||
/* Forced exit from macro expansion */
|
||||
FreeMacExp ();
|
||||
return MacExpand ();
|
||||
}
|
||||
|
||||
/* Is it the name of a macro parameter? */
|
||||
if (Tok == TOK_MACPARAM) {
|
||||
|
||||
/* Start to expand the parameter token list */
|
||||
CurMac->ParamExp = CurMac->Params [IVal];
|
||||
|
||||
/* Recursive call to expand the parameter */
|
||||
return MacExpand ();
|
||||
}
|
||||
|
||||
/* If it's an identifier, it may in fact be a local symbol */
|
||||
if (Tok == TOK_IDENT && CurMac->M->LocalCount) {
|
||||
/* Search for the local symbol in the list */
|
||||
unsigned Index = 0;
|
||||
IdDesc* I = CurMac->M->Locals;
|
||||
while (I) {
|
||||
if (strcmp (SVal, I->Id) == 0) {
|
||||
/* This is in fact a local symbol, change the name */
|
||||
sprintf (SVal, "___%04X__", CurMac->LocalStart + Index);
|
||||
break;
|
||||
}
|
||||
/* Next symbol */
|
||||
++Index;
|
||||
I = I->Next;
|
||||
}
|
||||
|
||||
/* Done */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* The token was successfully set */
|
||||
return 1;
|
||||
|
||||
} else if (CurMac->Final) {
|
||||
|
||||
/* Set the final token and remove it */
|
||||
TokSet (CurMac->Final);
|
||||
FreeTokNode (CurMac->Final);
|
||||
CurMac->Final = 0;
|
||||
|
||||
/* The token was successfully set */
|
||||
return 1;
|
||||
|
||||
} else {
|
||||
|
||||
/* End of macro expansion */
|
||||
FreeMacExp ();
|
||||
return MacExpand ();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MacAbort (void)
|
||||
/* Abort the current macro expansion */
|
||||
{
|
||||
/* Must have an expansion */
|
||||
CHECK (CurMac != 0);
|
||||
|
||||
/* Free current structure */
|
||||
FreeMacExp ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
int IsMacro (const char* Name)
|
||||
/* Return true if the given name is the name of a macro */
|
||||
{
|
||||
return MacFind (SVal, HashStr (SVal) % HASHTAB_SIZE) != 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int IsDefine (const char* Name)
|
||||
/* Return true if the given name is the name of a define style macro */
|
||||
{
|
||||
Macro* M = MacFind (SVal, HashStr (SVal) % HASHTAB_SIZE);
|
||||
return (M != 0 && M->Style == MAC_STYLE_DEFINE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int InMacExpansion (void)
|
||||
/* Return true if we're currently expanding a macro */
|
||||
{
|
||||
return MacroNesting != 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
90
src/ca65/macro.h
Normal file
90
src/ca65/macro.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* macro.h */
|
||||
/* */
|
||||
/* Macros for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998-2000 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef MACRO_H
|
||||
#define MACRO_H
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Macro styles */
|
||||
#define MAC_STYLE_CLASSIC 0
|
||||
#define MAC_STYLE_DEFINE 1
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void MacDef (unsigned Style);
|
||||
/* Parse a macro definition */
|
||||
|
||||
void MacExpandStart (void);
|
||||
/* Start expanding the macro in SVal */
|
||||
|
||||
int MacExpand (void);
|
||||
/* If we're currently expanding a macro, set the the scanner token and
|
||||
* attribute to the next value and return true. If we are not expanding
|
||||
* a macro, return false.
|
||||
*/
|
||||
|
||||
void MacAbort (void);
|
||||
/* Abort the current macro expansion */
|
||||
|
||||
int IsMacro (const char* Name);
|
||||
/* Return true if the given name is the name of a macro */
|
||||
|
||||
int IsDefine (const char* Name);
|
||||
/* Return true if the given name is the name of a define style macro */
|
||||
|
||||
int InMacExpansion (void);
|
||||
/* Return true if we're currently expanding a macro */
|
||||
|
||||
|
||||
|
||||
/* End of macro.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
564
src/ca65/main.c
Normal file
564
src/ca65/main.c
Normal file
@@ -0,0 +1,564 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* main.c */
|
||||
/* */
|
||||
/* Main program for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998-2000 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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 <time.h>
|
||||
|
||||
#include "../common/version.h"
|
||||
|
||||
#include "error.h"
|
||||
#include "expr.h"
|
||||
#include "global.h"
|
||||
#include "instr.h"
|
||||
#include "listing.h"
|
||||
#include "macro.h"
|
||||
#include "mem.h"
|
||||
#include "objcode.h"
|
||||
#include "objfile.h"
|
||||
#include "options.h"
|
||||
#include "pseudo.h"
|
||||
#include "scanner.h"
|
||||
#include "symtab.h"
|
||||
#include "ulabel.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static void Usage (void)
|
||||
/* Print usage information and exit */
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Usage: %s [options] file\n"
|
||||
"Options:\n"
|
||||
"\t-g\t\tAdd debug info to object file\n"
|
||||
"\t-i\t\tIgnore case of symbols\n"
|
||||
"\t-l\t\tCreate a listing if assembly was ok\n"
|
||||
"\t-o name\t\tName the output file\n"
|
||||
"\t-s\t\tEnable smart mode\n"
|
||||
"\t-v\t\tIncrease verbosity\n"
|
||||
"\t-D name[=value]\tDefine a symbol\n"
|
||||
"\t-U\t\tMark unresolved symbols as import\n"
|
||||
"\t-V\t\tPrint the assembler version\n"
|
||||
"\t-W n\t\tSet warning level n\n"
|
||||
"\t--cpu type\tSet cpu type\n"
|
||||
"\t--pagelength n\tSet the page length for the listing\n"
|
||||
"\t--smart\t\tEnable smart mode\n",
|
||||
ProgName);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void UnknownOption (const char* Arg)
|
||||
/* Print an error about an unknown option. Print usage information and exit */
|
||||
{
|
||||
fprintf (stderr, "Unknown option: %s\n", Arg);
|
||||
Usage ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void NeedArg (const char* Arg)
|
||||
/* Print an error about a missing option argument and exit. */
|
||||
{
|
||||
fprintf (stderr, "Option requires an argument: %s\n", Arg);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void InvSym (const char* Def)
|
||||
/* Print an error about an invalid symbol definition and die */
|
||||
{
|
||||
fprintf (stderr, "Invalid symbol definition: `%s'\n", Def);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static const char* GetArg (int* ArgNum, char* argv [], unsigned Len)
|
||||
/* Get an option argument */
|
||||
{
|
||||
const char* Arg = argv [*ArgNum];
|
||||
if (Arg [Len] != '\0') {
|
||||
/* Argument appended */
|
||||
return Arg + Len;
|
||||
} else {
|
||||
/* Separate argument */
|
||||
Arg = argv [*ArgNum + 1];
|
||||
if (Arg == 0) {
|
||||
/* End of arguments */
|
||||
NeedArg (argv [*ArgNum]);
|
||||
}
|
||||
++(*ArgNum);
|
||||
return Arg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void SetOptions (void)
|
||||
/* Set the option for the translator */
|
||||
{
|
||||
char Buf [256];
|
||||
|
||||
/* Set the translator */
|
||||
sprintf (Buf, "ca65 V%u.%u.%u", VER_MAJOR, VER_MINOR, VER_PATCH);
|
||||
OptTranslator (Buf);
|
||||
|
||||
/* Set date and time */
|
||||
OptDateTime ((unsigned long) time(0));
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void DefineSymbol (const char* Def)
|
||||
/* Define a symbol from the command line */
|
||||
{
|
||||
const char* P;
|
||||
unsigned I;
|
||||
long Val;
|
||||
char SymName [MAX_STR_LEN+1];
|
||||
|
||||
/* The symbol must start with a character or underline */
|
||||
if (Def [0] != '_' && !isalpha (Def [0])) {
|
||||
InvSym (Def);
|
||||
}
|
||||
P = Def;
|
||||
|
||||
/* Copy the symbol, checking the rest */
|
||||
I = 0;
|
||||
while (isalnum (*P) || *P == '_') {
|
||||
if (I <= MAX_STR_LEN) {
|
||||
SymName [I++] = *P;
|
||||
}
|
||||
++P;
|
||||
}
|
||||
SymName [I] = '\0';
|
||||
|
||||
/* Do we have a value given? */
|
||||
if (*P != '=') {
|
||||
if (*P != '\0') {
|
||||
InvSym (Def);
|
||||
}
|
||||
Val = 0;
|
||||
} else {
|
||||
/* We have a value */
|
||||
++P;
|
||||
if (*P == '$') {
|
||||
++P;
|
||||
if (sscanf (P, "%lx", &Val) != 1) {
|
||||
InvSym (Def);
|
||||
}
|
||||
} else {
|
||||
if (sscanf (P, "%li", &Val) != 1) {
|
||||
InvSym (Def);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if have already a symbol with this name */
|
||||
if (SymIsDef (SymName)) {
|
||||
fprintf (stderr, "`%s' is already defined\n", SymName);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Define the symbol */
|
||||
SymDef (SymName, LiteralExpr (Val), 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void OptCPU (const char* Opt, const char* Arg)
|
||||
/* Handle the --cpu option */
|
||||
{
|
||||
if (Arg == 0) {
|
||||
NeedArg (Opt);
|
||||
}
|
||||
if (strcmp (Arg, "6502") == 0) {
|
||||
SetCPU (CPU_6502);
|
||||
} else if (strcmp (Arg, "65C02") == 0) {
|
||||
SetCPU (CPU_65C02);
|
||||
} else if (strcmp (Arg, "65816") == 0) {
|
||||
SetCPU (CPU_65816);
|
||||
#ifdef SUNPLUS
|
||||
} else if (strcmp (Arg, "sunplus") == 0) {
|
||||
SetCPU (CPU_SUNPLUS);
|
||||
#endif
|
||||
} else {
|
||||
fprintf (stderr, "Invalid CPU: `%s'\n", Arg);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void OptPageLength (const char* Opt, const char* Arg)
|
||||
/* Handle the --pagelength option */
|
||||
{
|
||||
int Len;
|
||||
if (Arg == 0) {
|
||||
NeedArg (Opt);
|
||||
}
|
||||
Len = atoi (Arg);
|
||||
if (Len != -1 && (Len < MIN_PAGE_LEN || Len > MAX_PAGE_LEN)) {
|
||||
fprintf (stderr, "Invalid page length: %d\n", Len);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
PageLength = Len;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void OptSmart (const char* Opt)
|
||||
/* Handle the -s/--smart options */
|
||||
{
|
||||
SmartMode = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void LongOption (int* ArgNum, char* argv [])
|
||||
/* Handle a long command line option */
|
||||
{
|
||||
const char* Opt = argv [*ArgNum];
|
||||
const char* Arg = argv [*ArgNum+1];
|
||||
|
||||
if (strcmp (Opt, "--cpu") == 0) {
|
||||
OptCPU (Opt, Arg);
|
||||
++(*ArgNum);
|
||||
} else if (strcmp (Opt, "--pagelength") == 0) {
|
||||
OptPageLength (Opt, Arg);
|
||||
++(*ArgNum);
|
||||
} else if (strcmp (Opt, "--smart") == 0) {
|
||||
OptSmart (Opt);
|
||||
} else {
|
||||
UnknownOption (Opt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void OneLine (void)
|
||||
/* Assemble one line */
|
||||
{
|
||||
char Ident [MAX_STR_LEN+1];
|
||||
int Done = 0;
|
||||
|
||||
/* Initialize the listing line */
|
||||
InitListingLine ();
|
||||
|
||||
if (Tok == TOK_COLON) {
|
||||
/* An unnamed label */
|
||||
ULabDef ();
|
||||
NextTok ();
|
||||
}
|
||||
|
||||
/* Assemble the line */
|
||||
if (Tok == TOK_IDENT) {
|
||||
|
||||
/* Is it a macro? */
|
||||
if (IsMacro (SVal)) {
|
||||
|
||||
/* Yes, start a macro expansion */
|
||||
MacExpandStart ();
|
||||
Done = 1;
|
||||
|
||||
} else {
|
||||
|
||||
/* No, label. Remember the identifier, then skip it */
|
||||
int HadWS = WS; /* Did we have whitespace before the ident? */
|
||||
strcpy (Ident, SVal);
|
||||
NextTok ();
|
||||
|
||||
/* If a colon follows, this is a label definition. If there
|
||||
* is no colon, it's an assignment.
|
||||
*/
|
||||
if (Tok == TOK_EQ) {
|
||||
/* Skip the '=' */
|
||||
NextTok ();
|
||||
/* Define the symbol with the expression following the
|
||||
* '='
|
||||
*/
|
||||
SymDef (Ident, Expression (), 0);
|
||||
/* Don't allow anything after a symbol definition */
|
||||
Done = 1;
|
||||
} else {
|
||||
/* Define a label */
|
||||
SymDef (Ident, CurrentPC (), IsZPSeg ());
|
||||
/* Skip the colon. If NoColonLabels is enabled, allow labels
|
||||
* without a colon if there is no whitespace before the
|
||||
* identifier.
|
||||
*/
|
||||
if (Tok != TOK_COLON) {
|
||||
if (HadWS || !NoColonLabels) {
|
||||
Error (ERR_COLON_EXPECTED);
|
||||
}
|
||||
if (Tok == TOK_NAMESPACE) {
|
||||
/* Smart :: handling */
|
||||
NextTok ();
|
||||
}
|
||||
} else {
|
||||
/* Skip the colon */
|
||||
NextTok ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!Done) {
|
||||
|
||||
if (TokIsPseudo (Tok)) {
|
||||
/* A control command, IVal is index into table */
|
||||
HandlePseudo ();
|
||||
} else if (Tok == TOK_MNEMO) {
|
||||
/* A mnemonic - assemble one instruction */
|
||||
HandleInstruction (IVal);
|
||||
} else if (Tok == TOK_IDENT && IsMacro (SVal)) {
|
||||
/* A macro expansion */
|
||||
MacExpandStart ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Calling InitListingLine again here is part of a hack that introduces
|
||||
* enough magic to make the PC output in the listing work.
|
||||
*/
|
||||
InitListingLine ();
|
||||
|
||||
/* Line separator must come here */
|
||||
ConsumeSep ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void Assemble (void)
|
||||
/* Start the ball rolling ... */
|
||||
{
|
||||
/* Prime the pump */
|
||||
NextTok ();
|
||||
|
||||
/* Assemble lines until end of file */
|
||||
while (Tok != TOK_EOF) {
|
||||
OneLine ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void CreateObjFile (void)
|
||||
/* Create the object file */
|
||||
{
|
||||
/* Open the object, write the header */
|
||||
ObjOpen ();
|
||||
|
||||
/* Write the object file options */
|
||||
WriteOptions ();
|
||||
|
||||
/* Write the list of input files */
|
||||
WriteFiles ();
|
||||
|
||||
/* Write the segment data to the file */
|
||||
WriteSegments ();
|
||||
|
||||
/* Write the import list */
|
||||
WriteImports ();
|
||||
|
||||
/* Write the export list */
|
||||
WriteExports ();
|
||||
|
||||
/* Write debug symbols if requested */
|
||||
WriteDbgSyms ();
|
||||
|
||||
/* Write an updated header and close the file */
|
||||
ObjClose ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main (int argc, char* argv [])
|
||||
/* Assembler main program */
|
||||
{
|
||||
int I;
|
||||
|
||||
/* Set the program name */
|
||||
ProgName = argv [0];
|
||||
|
||||
/* We must have a file name */
|
||||
if (argc < 2) {
|
||||
Usage ();
|
||||
}
|
||||
|
||||
/* Enter the base lexical level. We must do that here, since we may
|
||||
* define symbols using -D.
|
||||
*/
|
||||
SymEnterLevel ();
|
||||
|
||||
/* Check the parameters */
|
||||
I = 1;
|
||||
while (I < argc) {
|
||||
|
||||
/* Get the argument */
|
||||
const char* Arg = argv [I];
|
||||
|
||||
/* Check for an option */
|
||||
if (Arg [0] == '-') {
|
||||
switch (Arg [1]) {
|
||||
|
||||
case '-':
|
||||
LongOption (&I, argv);
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
DbgSyms = 1;
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
IgnoreCase = 1;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
Listing = 1;
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
OutFile = GetArg (&I, argv, 2);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
OptSmart (Arg);
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
++Verbose;
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
DefineSymbol (GetArg (&I, argv, 2));
|
||||
break;
|
||||
|
||||
case 'U':
|
||||
AutoImport = 1;
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
fprintf (stderr,
|
||||
"ca65 V%u.%u.%u - (C) Copyright 1998-2000 Ullrich von Bassewitz\n",
|
||||
VER_MAJOR, VER_MINOR, VER_PATCH);
|
||||
break;
|
||||
|
||||
case 'W':
|
||||
WarnLevel = atoi (GetArg (&I, argv, 2));
|
||||
break;
|
||||
|
||||
default:
|
||||
UnknownOption (Arg);
|
||||
break;
|
||||
|
||||
}
|
||||
} else {
|
||||
/* Filename. Check if we already had one */
|
||||
if (InFile) {
|
||||
fprintf (stderr, "Don't know what to do with `%s'\n", Arg);
|
||||
Usage ();
|
||||
} else {
|
||||
InFile = Arg;
|
||||
}
|
||||
}
|
||||
|
||||
/* Next argument */
|
||||
++I;
|
||||
}
|
||||
|
||||
/* Do we have an input file? */
|
||||
if (InFile == 0) {
|
||||
fprintf (stderr, "No input file\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Initialize the scanner, open the input file */
|
||||
InitScanner (InFile);
|
||||
|
||||
/* Define the default options */
|
||||
SetOptions ();
|
||||
|
||||
/* Assemble the input */
|
||||
Assemble ();
|
||||
|
||||
/* If we didn't have any errors, check the unnamed labels */
|
||||
if (ErrorCount == 0) {
|
||||
ULabCheck ();
|
||||
}
|
||||
|
||||
/* If we didn't have any errors, check the symbol table */
|
||||
if (ErrorCount == 0) {
|
||||
SymCheck ();
|
||||
}
|
||||
|
||||
/* If we didn't have any errors, check and resolve the segment data */
|
||||
if (ErrorCount == 0) {
|
||||
SegCheck ();
|
||||
}
|
||||
|
||||
/* Dump the data */
|
||||
if (Verbose >= 2) {
|
||||
SymDump (stdout);
|
||||
SegDump ();
|
||||
}
|
||||
|
||||
/* If we didn't have any errors, create the object and listing files */
|
||||
if (ErrorCount == 0) {
|
||||
CreateObjFile ();
|
||||
if (Listing) {
|
||||
CreateListing ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Close the input file */
|
||||
DoneScanner ();
|
||||
|
||||
/* Return an apropriate exit code */
|
||||
return (ErrorCount == 0)? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
63
src/ca65/make/gcc.mak
Normal file
63
src/ca65/make/gcc.mak
Normal file
@@ -0,0 +1,63 @@
|
||||
#
|
||||
# gcc Makefile for a65, link65 & libr65
|
||||
#
|
||||
|
||||
CFLAGS = -g -O2 -Wall
|
||||
CC = gcc
|
||||
LDFLAGS =
|
||||
|
||||
OBJS = condasm.o \
|
||||
ea.o \
|
||||
error.o \
|
||||
expr.o \
|
||||
fname.o \
|
||||
fragment.o \
|
||||
global.o \
|
||||
instr.o \
|
||||
listing.o \
|
||||
macpack.o \
|
||||
macro.o \
|
||||
main.o \
|
||||
mem.o \
|
||||
objcode.o \
|
||||
objfile.o \
|
||||
options.o \
|
||||
pseudo.o \
|
||||
scanner.o \
|
||||
strexpr.o \
|
||||
symtab.o \
|
||||
toknode.o \
|
||||
ulabel.o
|
||||
|
||||
LIBS = ../common/common.a
|
||||
|
||||
EXECS = ca65
|
||||
|
||||
.PHONY: all
|
||||
ifeq (.depend,$(wildcard .depend))
|
||||
all : $(EXECS)
|
||||
include .depend
|
||||
else
|
||||
all: depend
|
||||
@$(MAKE) -f make/gcc.mak all
|
||||
endif
|
||||
|
||||
|
||||
|
||||
ca65: $(OBJS) $(LIBS)
|
||||
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS)
|
||||
|
||||
clean:
|
||||
rm -f *~ core *.lst
|
||||
|
||||
zap: clean
|
||||
rm -f *.o $(EXECS) .depend
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Make the dependencies
|
||||
|
||||
.PHONY: depend dep
|
||||
depend dep: $(OBJS:.o=.c)
|
||||
@echo "Creating dependency information"
|
||||
$(CC) -MM $^ > .depend
|
||||
|
||||
140
src/ca65/make/watcom.mak
Normal file
140
src/ca65/make/watcom.mak
Normal file
@@ -0,0 +1,140 @@
|
||||
#
|
||||
# CA65 Makefile for the Watcom compiler
|
||||
#
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Generic stuff
|
||||
|
||||
.AUTODEPEND
|
||||
.SUFFIXES .ASM .C .CC .CPP
|
||||
.SWAP
|
||||
|
||||
AR = WLIB
|
||||
LD = WLINK
|
||||
|
||||
!if !$d(TARGET)
|
||||
!if $d(__OS2__)
|
||||
TARGET = OS2
|
||||
!else
|
||||
TARGET = NT
|
||||
!endif
|
||||
!endif
|
||||
|
||||
# target specific macros.
|
||||
!if $(TARGET)==OS2
|
||||
|
||||
# --------------------- OS2 ---------------------
|
||||
SYSTEM = os2v2
|
||||
CC = WCC386
|
||||
CCCFG = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
|
||||
|
||||
!elif $(TARGET)==DOS32
|
||||
|
||||
# -------------------- DOS4G --------------------
|
||||
SYSTEM = dos4g
|
||||
CC = WCC386
|
||||
CCCFG = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
|
||||
|
||||
!elif $(TARGET)==DOS
|
||||
|
||||
# --------------------- DOS ---------------------
|
||||
SYSTEM = dos
|
||||
CC = WCC
|
||||
CCCFG = -bt=$(TARGET) -d1 -onatx -zp2 -2 -ml -zq -w2
|
||||
|
||||
!elif $(TARGET)==NT
|
||||
|
||||
# --------------------- NT ----------------------
|
||||
SYSTEM = nt
|
||||
CC = WCC386
|
||||
CCCFG = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
|
||||
|
||||
!else
|
||||
!error
|
||||
!endif
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Implicit rules
|
||||
|
||||
.c.obj:
|
||||
$(CC) $(CCCFG) $<
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# All library OBJ files
|
||||
|
||||
OBJS = condasm.obj \
|
||||
ea.obj \
|
||||
error.obj \
|
||||
expr.obj \
|
||||
fname.obj \
|
||||
fragment.obj \
|
||||
global.obj \
|
||||
instr.obj \
|
||||
listing.obj \
|
||||
macpack.obj \
|
||||
macro.obj \
|
||||
main.obj \
|
||||
mem.obj \
|
||||
objcode.obj \
|
||||
objfile.obj \
|
||||
options.obj \
|
||||
pseudo.obj \
|
||||
scanner.obj \
|
||||
strexpr.obj \
|
||||
symtab.obj \
|
||||
toknode.obj \
|
||||
ulabel.obj
|
||||
|
||||
LIBS = ..\common\common.lib
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Main targets
|
||||
|
||||
all: ca65
|
||||
|
||||
ca65: ca65.exe
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Other targets
|
||||
|
||||
|
||||
ca65.exe: $(OBJS) $(LIBS)
|
||||
$(LD) system $(SYSTEM) @&&|
|
||||
DEBUG ALL
|
||||
OPTION QUIET
|
||||
NAME $<
|
||||
FILE condasm.obj
|
||||
FILE ea.obj
|
||||
FILE error.obj
|
||||
FILE expr.obj
|
||||
FILE fname.obj
|
||||
FILE fragment.obj
|
||||
FILE global.obj
|
||||
FILE instr.obj
|
||||
FILE listing.obj
|
||||
FILE macpack.obj
|
||||
FILE macro.obj
|
||||
FILE main.obj
|
||||
FILE mem.obj
|
||||
FILE objcode.obj
|
||||
FILE objfile.obj
|
||||
FILE options.obj
|
||||
FILE pseudo.obj
|
||||
FILE scanner.obj
|
||||
FILE strexpr.obj
|
||||
FILE symtab.obj
|
||||
FILE toknode.obj
|
||||
FILE ulabel.obj
|
||||
LIBRARY ..\common\common.lib
|
||||
|
|
||||
|
||||
clean:
|
||||
@if exist *.obj del *.obj
|
||||
@if exist ca65.exe del ca65.exe
|
||||
|
||||
strip:
|
||||
@-wstrip ca65.exe
|
||||
|
||||
84
src/ca65/mem.c
Normal file
84
src/ca65/mem.c
Normal file
@@ -0,0 +1,84 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* mem.c */
|
||||
/* */
|
||||
/* Memory allocation for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "error.h"
|
||||
#include "mem.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void* Xmalloc (size_t size)
|
||||
/* Allocate memory, check for out of memory condition. Do some debugging */
|
||||
{
|
||||
void* p;
|
||||
|
||||
p = malloc (size);
|
||||
if (p == 0 && size != 0) {
|
||||
Fatal (FAT_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
/* Return a pointer to the block */
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Xfree (const void* block)
|
||||
/* Free the block, do some debugging */
|
||||
{
|
||||
free ((void*) block);
|
||||
}
|
||||
|
||||
|
||||
|
||||
char* StrDup (const char* s)
|
||||
/* Duplicate a string on the heap. The function checks for out of memory */
|
||||
{
|
||||
unsigned len;
|
||||
|
||||
len = strlen (s) + 1;
|
||||
return memcpy (Xmalloc (len), s, len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
67
src/ca65/mem.h
Normal file
67
src/ca65/mem.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* mem.h */
|
||||
/* */
|
||||
/* Memory allocation for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef MEM_H
|
||||
#define MEM_H
|
||||
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void* Xmalloc (size_t size);
|
||||
/* Allocate memory, check for out of memory condition. Do some debugging */
|
||||
|
||||
void Xfree (const void* block);
|
||||
/* Free the block, do some debugging */
|
||||
|
||||
char* StrDup (const char* s);
|
||||
/* Duplicate a string on the heap. The function checks for out of memory */
|
||||
|
||||
|
||||
|
||||
/* End of mem.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
842
src/ca65/objcode.c
Normal file
842
src/ca65/objcode.c
Normal file
@@ -0,0 +1,842 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* objcode.c */
|
||||
/* */
|
||||
/* Objectcode management for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998-2000 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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 <string.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "../common/segdefs.h"
|
||||
|
||||
#include "error.h"
|
||||
#include "fragment.h"
|
||||
#include "global.h"
|
||||
#include "listing.h"
|
||||
#include "mem.h"
|
||||
#include "objfile.h"
|
||||
#include "scanner.h"
|
||||
#include "symtab.h"
|
||||
#include "objcode.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Are we in absolute mode or in relocatable mode? */
|
||||
int RelocMode = 1;
|
||||
unsigned long AbsPC = 0; /* PC if in absolute mode */
|
||||
|
||||
|
||||
|
||||
typedef struct Segment_ Segment;
|
||||
struct Segment_ {
|
||||
Segment* List; /* List of all segments */
|
||||
Fragment* Root; /* Root of fragment list */
|
||||
Fragment* Last; /* Pointer to last fragment */
|
||||
unsigned char Align; /* Segment alignment */
|
||||
unsigned char SegType; /* True if zero page segment */
|
||||
unsigned long PC;
|
||||
unsigned Num; /* Segment number */
|
||||
char* Name; /* Segment name */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Predefined segments */
|
||||
static Segment NullSeg = {
|
||||
0, 0, 0, 0, SEGTYPE_ABS, 0, 5, "NULL"
|
||||
};
|
||||
static Segment ZeropageSeg = {
|
||||
&NullSeg, 0, 0, 0, SEGTYPE_ZP, 0, 4, "ZEROPAGE"
|
||||
};
|
||||
static Segment DataSeg = {
|
||||
&ZeropageSeg, 0, 0, 0, SEGTYPE_ABS, 0, 3, "DATA"
|
||||
};
|
||||
static Segment BssSeg = {
|
||||
&DataSeg, 0, 0, 0, SEGTYPE_ABS, 0, 2, "BSS"
|
||||
};
|
||||
static Segment RODataSeg = {
|
||||
&BssSeg, 0, 0, 0, SEGTYPE_ABS, 0, 1, "RODATA"
|
||||
};
|
||||
static Segment CodeSeg = {
|
||||
&RODataSeg, 0, 0, 0, SEGTYPE_ABS, 0, 0, "CODE"
|
||||
};
|
||||
|
||||
/* Number of segments */
|
||||
static unsigned SegmentCount = 6;
|
||||
|
||||
/* List of all segments */
|
||||
static Segment* SegmentList = &CodeSeg;
|
||||
static Segment* SegmentLast = &NullSeg;
|
||||
|
||||
/* Currently active segment */
|
||||
static Segment* ActiveSeg = &CodeSeg;
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Segment management */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static Segment* NewSegment (const char* Name, unsigned SegType)
|
||||
/* Create a new segment, insert it into the global list and return it */
|
||||
{
|
||||
Segment* S;
|
||||
const char* N;
|
||||
|
||||
/* Check for too many segments */
|
||||
if (SegmentCount >= 256) {
|
||||
Fatal (FAT_TOO_MANY_SEGMENTS);
|
||||
}
|
||||
|
||||
/* Check the segment name for invalid names */
|
||||
N = Name;
|
||||
if ((*N != '_' && !isalpha (*N)) || strlen (Name) > 80) {
|
||||
Error (ERR_ILLEGAL_SEGMENT, Name);
|
||||
}
|
||||
do {
|
||||
if (*N != '_' && !isalnum (*N)) {
|
||||
Error (ERR_ILLEGAL_SEGMENT, Name);
|
||||
break;
|
||||
}
|
||||
++N;
|
||||
} while (*N);
|
||||
|
||||
/* Create a new segment */
|
||||
S = Xmalloc (sizeof (*S));
|
||||
|
||||
/* Initialize it */
|
||||
S->List = 0;
|
||||
S->Root = 0;
|
||||
S->Last = 0;
|
||||
S->Align = 0;
|
||||
S->SegType = SegType;
|
||||
S->PC = 0;
|
||||
S->Num = SegmentCount++;
|
||||
S->Name = StrDup (Name);
|
||||
|
||||
/* Insert it into the segment list */
|
||||
SegmentLast->List = S;
|
||||
SegmentLast = S;
|
||||
|
||||
/* And return it... */
|
||||
return S;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void UseCodeSeg (void)
|
||||
/* Use the code segment */
|
||||
{
|
||||
ActiveSeg = &CodeSeg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void UseRODataSeg (void)
|
||||
/* Use the r/o data segment */
|
||||
{
|
||||
ActiveSeg = &RODataSeg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void UseDataSeg (void)
|
||||
/* Use the data segment */
|
||||
{
|
||||
ActiveSeg = &DataSeg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void UseBssSeg (void)
|
||||
/* Use the BSS segment */
|
||||
{
|
||||
ActiveSeg = &BssSeg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void UseZeropageSeg (void)
|
||||
/* Use the zero page segment */
|
||||
{
|
||||
ActiveSeg = &ZeropageSeg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void UseNullSeg (void)
|
||||
/* Use the null segment */
|
||||
{
|
||||
ActiveSeg = &NullSeg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void UseSeg (const char* Name, unsigned SegType)
|
||||
/* Use the segment with the given name */
|
||||
{
|
||||
Segment* Seg = SegmentList;
|
||||
while (Seg) {
|
||||
if (strcmp (Seg->Name, Name) == 0) {
|
||||
/* We found this segment. Check if the type is identical */
|
||||
if (SegType != SEGTYPE_DEFAULT && Seg->SegType != SegType) {
|
||||
Error (ERR_SEG_ATTR_MISMATCH);
|
||||
/* Use the new attribute to avoid errors */
|
||||
Seg->SegType = SegType;
|
||||
}
|
||||
ActiveSeg = Seg;
|
||||
return;
|
||||
}
|
||||
/* Check next segment */
|
||||
Seg = Seg->List;
|
||||
}
|
||||
|
||||
/* Segment is not in list, create a new one */
|
||||
if (SegType == SEGTYPE_DEFAULT) {
|
||||
SegType = SEGTYPE_ABS;
|
||||
}
|
||||
Seg = NewSegment (Name, SegType);
|
||||
ActiveSeg = Seg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned long GetPC (void)
|
||||
/* Get the program counter of the current segment */
|
||||
{
|
||||
return RelocMode? ActiveSeg->PC : AbsPC;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SetAbsPC (unsigned long PC)
|
||||
/* Set the program counter in absolute mode */
|
||||
{
|
||||
RelocMode = 0;
|
||||
AbsPC = PC;
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned GetSegNum (void)
|
||||
/* Get the number of the current segment */
|
||||
{
|
||||
return ActiveSeg->Num;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SegAlign (unsigned Power, int Val)
|
||||
/* Align the PC segment to 2^Power. If Val is -1, emit fill fragments (the
|
||||
* actual fill value will be determined by the linker), otherwise use the
|
||||
* given value.
|
||||
*/
|
||||
{
|
||||
unsigned char Data [4];
|
||||
unsigned long Align = (1UL << Power) - 1;
|
||||
unsigned long NewPC = (ActiveSeg->PC + Align) & ~Align;
|
||||
unsigned long Count = NewPC - ActiveSeg->PC;
|
||||
|
||||
if (Val != -1) {
|
||||
/* User defined fill value */
|
||||
memset (Data, Val, sizeof (Data));
|
||||
while (Count) {
|
||||
if (Count > sizeof (Data)) {
|
||||
EmitData (Data, sizeof (Data));
|
||||
Count -= sizeof (Data);
|
||||
} else {
|
||||
EmitData (Data, Count);
|
||||
Count = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Linker defined fill value */
|
||||
EmitFill (Count);
|
||||
}
|
||||
|
||||
/* Remember the alignment in the header */
|
||||
if (ActiveSeg->Align < Power) {
|
||||
ActiveSeg->Align = Power;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int IsZPSeg (void)
|
||||
/* Return true if the current segment is a zeropage segment */
|
||||
{
|
||||
return (ActiveSeg->SegType == SEGTYPE_ZP);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int IsFarSeg (void)
|
||||
/* Return true if the current segment is a far segment */
|
||||
{
|
||||
return (ActiveSeg->SegType == SEGTYPE_FAR);
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned GetSegType (unsigned SegNum)
|
||||
/* Return the type of the segment with the given number */
|
||||
{
|
||||
/* Search for the segment */
|
||||
Segment* S = SegmentList;
|
||||
while (S && SegNum) {
|
||||
--SegNum;
|
||||
S = S->List;
|
||||
}
|
||||
|
||||
/* Did we find it? */
|
||||
if (S == 0) {
|
||||
FAIL ("Invalid segment number");
|
||||
}
|
||||
|
||||
/* Return the segment type */
|
||||
return S->SegType;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SegCheck (void)
|
||||
/* Check the segments for range and other errors */
|
||||
{
|
||||
Segment* S = SegmentList;
|
||||
while (S) {
|
||||
Fragment* F = S->Root;
|
||||
while (F) {
|
||||
if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
|
||||
F->V.Expr = FinalizeExpr (F->V.Expr);
|
||||
if (IsConstExpr (F->V.Expr)) {
|
||||
/* We are able to evaluate the expression. Get the value
|
||||
* and check for range errors.
|
||||
*/
|
||||
unsigned I;
|
||||
long Val = GetExprVal (F->V.Expr);
|
||||
int Abs = (F->Type != FRAG_SEXPR);
|
||||
|
||||
if (F->Len == 1) {
|
||||
if (Abs) {
|
||||
/* Absolute value */
|
||||
if (Val > 255) {
|
||||
PError (&F->Pos, ERR_RANGE);
|
||||
}
|
||||
} else {
|
||||
/* PC relative value */
|
||||
if (Val < -128 || Val > 127) {
|
||||
PError (&F->Pos, ERR_RANGE);
|
||||
}
|
||||
}
|
||||
} else if (F->Len == 2) {
|
||||
if (Abs) {
|
||||
/* Absolute value */
|
||||
if (Val > 65535) {
|
||||
PError (&F->Pos, ERR_RANGE);
|
||||
}
|
||||
} else {
|
||||
/* PC relative value */
|
||||
if (Val < -32768 || Val > 32767) {
|
||||
PError (&F->Pos, ERR_RANGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert the fragment into a literal fragment */
|
||||
for (I = 0; I < F->Len; ++I) {
|
||||
F->V.Data [I] = Val & 0xFF;
|
||||
Val >>= 8;
|
||||
}
|
||||
F->Type = FRAG_LITERAL;
|
||||
} else {
|
||||
/* We cannot evaluate the expression now, leave the job for
|
||||
* the linker. However, we are able to check for explicit
|
||||
* byte expressions and we will do so.
|
||||
*/
|
||||
if (F->Type == FRAG_EXPR && F->Len == 1 && !IsByteExpr (F->V.Expr)) {
|
||||
PError (&F->Pos, ERR_RANGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
F = F->Next;
|
||||
}
|
||||
S = S->List;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SegDump (void)
|
||||
/* Dump the contents of all segments */
|
||||
{
|
||||
unsigned X = 0;
|
||||
Segment* S = SegmentList;
|
||||
printf ("\n");
|
||||
while (S) {
|
||||
unsigned I;
|
||||
Fragment* F;
|
||||
int State = -1;
|
||||
printf ("New segment: %s", S->Name);
|
||||
F = S->Root;
|
||||
while (F) {
|
||||
if (F->Type == FRAG_LITERAL) {
|
||||
if (State != 0) {
|
||||
printf ("\n Literal:");
|
||||
X = 15;
|
||||
State = 0;
|
||||
}
|
||||
for (I = 0; I < F->Len; ++I) {
|
||||
printf (" %02X", F->V.Data [I]);
|
||||
X += 3;
|
||||
}
|
||||
} else if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
|
||||
State = 1;
|
||||
printf ("\n Expression (%u): ", F->Len);
|
||||
DumpExpr (F->V.Expr);
|
||||
} else if (F->Type == FRAG_FILL) {
|
||||
State = 1;
|
||||
printf ("\n Fill bytes (%u)", F->Len);
|
||||
} else {
|
||||
Internal ("Unknown fragment type: %u", F->Type);
|
||||
}
|
||||
if (X > 65) {
|
||||
State = -1;
|
||||
}
|
||||
F = F->Next;
|
||||
}
|
||||
printf ("\n End PC = $%04X\n", (unsigned)(S->PC & 0xFFFF));
|
||||
S = S->List;
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void WriteOneSeg (Segment* Seg)
|
||||
/* Write one segment to the object file */
|
||||
{
|
||||
Fragment* Frag;
|
||||
Fragment* F;
|
||||
unsigned long Size;
|
||||
|
||||
/* Write the segment name followed by the byte count in this segment */
|
||||
ObjWriteStr (Seg->Name);
|
||||
ObjWrite32 (Seg->PC);
|
||||
ObjWrite8 (Seg->Align);
|
||||
ObjWrite8 (Seg->SegType);
|
||||
|
||||
/* Now walk through the fragment list for this segment and write the
|
||||
* fragments.
|
||||
*/
|
||||
Frag = Seg->Root;
|
||||
while (Frag) {
|
||||
|
||||
/* Write data depending on the type */
|
||||
switch (Frag->Type) {
|
||||
|
||||
case FRAG_LITERAL:
|
||||
/* To make the object file somewhat smaller, write all literal
|
||||
* data of this and the following fragments preceeded by the
|
||||
* length.
|
||||
*/
|
||||
F = Frag;
|
||||
Size = 0;
|
||||
while (F && F->Type == FRAG_LITERAL) {
|
||||
Size += F->Len;
|
||||
F = F->Next;
|
||||
}
|
||||
if (Size < 0x100) {
|
||||
ObjWrite8 (FRAG_LITERAL8);
|
||||
ObjWrite8 (Size);
|
||||
} else if (Size < 0x10000) {
|
||||
ObjWrite8 (FRAG_LITERAL16);
|
||||
ObjWrite16 (Size);
|
||||
} else if (Size < 0x1000000) {
|
||||
ObjWrite8 (FRAG_LITERAL24);
|
||||
ObjWrite24 (Size);
|
||||
} else {
|
||||
ObjWrite8 (FRAG_LITERAL32);
|
||||
ObjWrite32 (Size);
|
||||
}
|
||||
|
||||
/* Now write the literal data */
|
||||
F = Frag;
|
||||
while (F && F->Type == FRAG_LITERAL) {
|
||||
ObjWriteData (F->V.Data, F->Len);
|
||||
Frag = F;
|
||||
F = F->Next;
|
||||
}
|
||||
break;
|
||||
|
||||
case FRAG_EXPR:
|
||||
switch (Frag->Len) {
|
||||
case 1: ObjWrite8 (FRAG_EXPR8); break;
|
||||
case 2: ObjWrite8 (FRAG_EXPR16); break;
|
||||
case 3: ObjWrite8 (FRAG_EXPR24); break;
|
||||
case 4: ObjWrite8 (FRAG_EXPR32); break;
|
||||
default: Internal ("Invalid fragment size: %u", Frag->Len);
|
||||
}
|
||||
WriteExpr (Frag->V.Expr);
|
||||
break;
|
||||
|
||||
case FRAG_SEXPR:
|
||||
switch (Frag->Len) {
|
||||
case 1: ObjWrite8 (FRAG_SEXPR8); break;
|
||||
case 2: ObjWrite8 (FRAG_SEXPR16); break;
|
||||
case 3: ObjWrite8 (FRAG_SEXPR24); break;
|
||||
case 4: ObjWrite8 (FRAG_SEXPR32); break;
|
||||
default: Internal ("Invalid fragment size: %u", Frag->Len);
|
||||
}
|
||||
WriteExpr (Frag->V.Expr);
|
||||
break;
|
||||
|
||||
case FRAG_FILL:
|
||||
ObjWrite8 (FRAG_FILL);
|
||||
ObjWrite16 (Frag->Len);
|
||||
break;
|
||||
|
||||
default:
|
||||
Internal ("Invalid fragment type: %u", Frag->Type);
|
||||
|
||||
}
|
||||
|
||||
/* Write the file position of this fragment */
|
||||
ObjWritePos (&Frag->Pos);
|
||||
|
||||
/* Next fragment */
|
||||
Frag = Frag->Next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void WriteSegments (void)
|
||||
/* Write the segment data to the object file */
|
||||
{
|
||||
Segment* Seg;
|
||||
|
||||
/* Tell the object file module that we're about to start the seg list */
|
||||
ObjStartSegments ();
|
||||
|
||||
/* First thing is segment count */
|
||||
ObjWrite8 (SegmentCount);
|
||||
|
||||
/* Now walk through all segments and write them to the object file */
|
||||
Seg = SegmentList;
|
||||
while (Seg) {
|
||||
/* Write one segment */
|
||||
WriteOneSeg (Seg);
|
||||
/* Next segment */
|
||||
Seg = Seg->List;
|
||||
}
|
||||
|
||||
/* Done writing segments */
|
||||
ObjEndSegments ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static void IncPC (unsigned Value)
|
||||
/* Increment the PC counter */
|
||||
{
|
||||
ActiveSeg->PC += Value;
|
||||
if (!RelocMode) {
|
||||
AbsPC += Value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static Fragment* NewFragment (unsigned char Type, unsigned short Len)
|
||||
/* Create, initialize and return a new fragment. The fragment will be inserted
|
||||
* into the current segment.
|
||||
*/
|
||||
{
|
||||
Fragment* F;
|
||||
|
||||
/* Create a new fragment */
|
||||
F = Xmalloc (sizeof (*F));
|
||||
|
||||
/* Initialize it */
|
||||
F->List = 0;
|
||||
F->Next = 0;
|
||||
F->LineList = 0;
|
||||
F->Pos = CurPos;
|
||||
F->Len = Len;
|
||||
F->Type = Type;
|
||||
|
||||
/* Insert it into the list of all segments */
|
||||
if (FragList == 0) {
|
||||
FragList = F;
|
||||
} else {
|
||||
FragLast->List = F;
|
||||
}
|
||||
FragLast = F;
|
||||
|
||||
/* Insert it into the current segment */
|
||||
if (ActiveSeg->Root) {
|
||||
ActiveSeg->Last->Next = F;
|
||||
ActiveSeg->Last = F;
|
||||
} else {
|
||||
ActiveSeg->Root = ActiveSeg->Last = F;
|
||||
}
|
||||
|
||||
/* Add this fragment to the current listing line */
|
||||
if (LineCur) {
|
||||
if (LineCur->FragList == 0) {
|
||||
LineCur->FragList = F;
|
||||
/* First fragment - set the PC
|
||||
LineCur->PC = GetPC ();
|
||||
LineCur->Reloc = RelocMode;
|
||||
*/
|
||||
} else {
|
||||
LineCur->FragLast->LineList = F;
|
||||
}
|
||||
LineCur->FragLast = F;
|
||||
}
|
||||
|
||||
/* Increment the program counter */
|
||||
IncPC (Len);
|
||||
|
||||
/* And return it */
|
||||
return F;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Emit0 (unsigned char OPC)
|
||||
/* Emit an instruction with a zero sized operand */
|
||||
{
|
||||
/* First fragment, wrong type or out of space, create new one */
|
||||
Fragment* F = NewFragment (FRAG_LITERAL, 1);
|
||||
F->V.Data [0] = OPC;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Emit1 (unsigned char OPC, ExprNode* Value)
|
||||
/* Emit an instruction with an one byte argument */
|
||||
{
|
||||
Emit0 (OPC);
|
||||
EmitByte (Value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Emit2 (unsigned char OPC, ExprNode* Value)
|
||||
/* Emit an instruction with a two byte argument */
|
||||
{
|
||||
Emit0 (OPC);
|
||||
EmitWord (Value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Emit3 (unsigned char OPC, ExprNode* Expr)
|
||||
/* Emit an instruction with a three byte argument */
|
||||
{
|
||||
Emit0 (OPC);
|
||||
EmitFarAddr (Expr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Emit3b (unsigned char OPC, ExprNode* Expr, ExprNode* Bank)
|
||||
/* Emit an instruction with a three byte argument and separate bank */
|
||||
{
|
||||
Emit0 (OPC);
|
||||
EmitWord (Expr);
|
||||
EmitByte (Bank);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void EmitPCRel (unsigned char OPC, ExprNode* Expr, unsigned Size)
|
||||
/* Emit an opcode with a PC relative argument of one or two bytes */
|
||||
{
|
||||
Fragment* F;
|
||||
Emit0 (OPC);
|
||||
F = NewFragment (FRAG_SEXPR, Size);
|
||||
F->V.Expr = Expr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void EmitData (const unsigned char* Data, unsigned Size)
|
||||
/* Emit data into the current segment */
|
||||
{
|
||||
/* Create lots of fragments for the data */
|
||||
while (Size) {
|
||||
Fragment* F;
|
||||
|
||||
/* Determine the length of the next fragment */
|
||||
unsigned Len = Size;
|
||||
if (Len > sizeof (F->V.Data)) {
|
||||
Len = sizeof (F->V.Data);
|
||||
}
|
||||
|
||||
/* Create a new fragment */
|
||||
F = NewFragment (FRAG_LITERAL, Len);
|
||||
|
||||
/* Copy the data */
|
||||
memcpy (F->V.Data, Data, Len);
|
||||
|
||||
/* Next chunk */
|
||||
Data += Len;
|
||||
Size -= Len;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void EmitByte (ExprNode* Expr)
|
||||
/* Emit one byte */
|
||||
{
|
||||
if (IsConstExpr (Expr)) {
|
||||
/* Constant expression, emit literal byte */
|
||||
long Val = GetExprVal (Expr);
|
||||
FreeExpr (Expr);
|
||||
if ((Val & ~0xFF) != 0) {
|
||||
Error (ERR_RANGE);
|
||||
}
|
||||
Emit0 (Val & 0xFF);
|
||||
} else {
|
||||
/* Create a new fragment */
|
||||
Fragment* F = NewFragment (FRAG_EXPR, 1);
|
||||
|
||||
/* Set the data */
|
||||
F->V.Expr = Expr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void EmitWord (ExprNode* Expr)
|
||||
/* Emit one word */
|
||||
{
|
||||
if (IsConstExpr (Expr)) {
|
||||
/* Constant expression, emit literal byte */
|
||||
long Val = GetExprVal (Expr);
|
||||
FreeExpr (Expr);
|
||||
if ((Val & ~0xFFFF) != 0) {
|
||||
Error (ERR_RANGE);
|
||||
}
|
||||
Emit0 (Val & 0xFF);
|
||||
Emit0 ((Val >> 8) & 0xFF);
|
||||
} else {
|
||||
/* Create a new fragment */
|
||||
Fragment* F = NewFragment (FRAG_EXPR, 2);
|
||||
|
||||
/* Set the data */
|
||||
F->V.Expr = Expr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void EmitFarAddr (ExprNode* Expr)
|
||||
/* Emit a 24 bit expression */
|
||||
{
|
||||
if (IsConstExpr (Expr)) {
|
||||
/* Constant expression, emit literal byte */
|
||||
long Val = GetExprVal (Expr);
|
||||
FreeExpr (Expr);
|
||||
if ((Val & ~0xFFFFFF) != 0) {
|
||||
Error (ERR_RANGE);
|
||||
}
|
||||
Emit0 (Val & 0xFF);
|
||||
Emit0 ((Val >> 8) & 0xFF);
|
||||
Emit0 ((Val >> 16) & 0xFF);
|
||||
} else {
|
||||
/* Create a new fragment */
|
||||
Fragment* F = NewFragment (FRAG_EXPR, 3);
|
||||
|
||||
/* Set the data */
|
||||
F->V.Expr = Expr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void EmitDWord (ExprNode* Expr)
|
||||
/* Emit one dword */
|
||||
{
|
||||
if (IsConstExpr (Expr)) {
|
||||
/* Constant expression, emit literal byte */
|
||||
long Val = GetExprVal (Expr);
|
||||
FreeExpr (Expr);
|
||||
Emit0 (Val & 0xFF);
|
||||
Emit0 ((Val >> 8) & 0xFF);
|
||||
Emit0 ((Val >> 16) & 0xFF);
|
||||
Emit0 ((Val >> 24) & 0xFF);
|
||||
} else {
|
||||
/* Create a new fragment */
|
||||
Fragment* F = NewFragment (FRAG_EXPR, 4);
|
||||
|
||||
/* Set the data */
|
||||
F->V.Expr = Expr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void EmitFill (unsigned long Count)
|
||||
/* Emit Count fill bytes */
|
||||
{
|
||||
while (Count) {
|
||||
/* Calculate the size of the next chunk */
|
||||
unsigned Chunk = (Count > 0xFFFF)? 0xFFFF : (unsigned) Count;
|
||||
Count -= Chunk;
|
||||
|
||||
/* Emit one chunk */
|
||||
NewFragment (FRAG_FILL, Chunk);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
168
src/ca65/objcode.h
Normal file
168
src/ca65/objcode.h
Normal file
@@ -0,0 +1,168 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* objcode.h */
|
||||
/* */
|
||||
/* Objectcode management for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998-2000 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef OBJCODE_H
|
||||
#define OBJCODE_H
|
||||
|
||||
|
||||
|
||||
#include "../common/segdefs.h"
|
||||
#include "expr.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Are we in absolute mode or in relocatable mode? */
|
||||
extern int RelocMode;
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Segment management */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void UseCodeSeg (void);
|
||||
/* Use the code segment */
|
||||
|
||||
void UseRODataSeg (void);
|
||||
/* Use the r/o data segment */
|
||||
|
||||
void UseDataSeg (void);
|
||||
/* Use the data segment */
|
||||
|
||||
void UseBssSeg (void);
|
||||
/* Use the BSS segment */
|
||||
|
||||
void UseZeropageSeg (void);
|
||||
/* Use the zero page segment */
|
||||
|
||||
void UseNullSeg (void);
|
||||
/* Use the null segment */
|
||||
|
||||
void UseSeg (const char* Name, unsigned SegType);
|
||||
/* Use the segment with the given name */
|
||||
|
||||
unsigned GetSegNum (void);
|
||||
/* Get the number of the current segment */
|
||||
|
||||
void SegAlign (unsigned Power, int Val);
|
||||
/* Align the PC segment to 2^Power. If Val is -1, emit fill fragments (the
|
||||
* actual fill value will be determined by the linker), otherwise use the
|
||||
* given value.
|
||||
*/
|
||||
|
||||
int IsZPSeg (void);
|
||||
/* Return true if the current segment is a zeropage segment */
|
||||
|
||||
int IsFarSeg (void);
|
||||
/* Return true if the current segment is a far segment */
|
||||
|
||||
unsigned GetSegType (unsigned SegNum);
|
||||
/* Return the type of the segment with the given number */
|
||||
|
||||
unsigned long GetPC (void);
|
||||
/* Get the program counter of the current segment */
|
||||
|
||||
void SetAbsPC (unsigned long AbsPC);
|
||||
/* Set the program counter in absolute mode */
|
||||
|
||||
void SegCheck (void);
|
||||
/* Check the segments for range and other errors */
|
||||
|
||||
void SegDump (void);
|
||||
/* Dump the contents of all segments */
|
||||
|
||||
void WriteSegments (void);
|
||||
/* Write the segment data to the object file */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void Emit0 (unsigned char OPC);
|
||||
/* Emit an instruction with a zero sized operand */
|
||||
|
||||
void Emit1 (unsigned char OPC, ExprNode* Value);
|
||||
/* Emit an instruction with an one byte argument */
|
||||
|
||||
void Emit2 (unsigned char OPC, ExprNode* Value);
|
||||
/* Emit an instruction with a two byte argument */
|
||||
|
||||
void Emit3 (unsigned char OPC, ExprNode* Expr);
|
||||
/* Emit an instruction with a three byte argument */
|
||||
|
||||
void Emit3b (unsigned char OPC, ExprNode* Expr, ExprNode* Bank);
|
||||
/* Emit an instruction with a three byte argument and separate bank */
|
||||
|
||||
void EmitPCRel (unsigned char OPC, ExprNode* Expr, unsigned Size);
|
||||
/* Emit an opcode with a PC relative argument of one or two bytes */
|
||||
|
||||
void EmitData (const unsigned char* Data, unsigned Size);
|
||||
/* Emit data into the current segment */
|
||||
|
||||
void EmitByte (ExprNode* Expr);
|
||||
/* Emit one byte */
|
||||
|
||||
void EmitWord (ExprNode* Expr);
|
||||
/* Emit one word */
|
||||
|
||||
void EmitFarAddr (ExprNode* Expr);
|
||||
/* Emit a 24 bit expression */
|
||||
|
||||
void EmitDWord (ExprNode* Expr);
|
||||
/* Emit one dword */
|
||||
|
||||
void EmitFill (unsigned long Count);
|
||||
/* Emit Count fill bytes */
|
||||
|
||||
|
||||
|
||||
/* End of objcode.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
351
src/ca65/objfile.c
Normal file
351
src/ca65/objfile.c
Normal file
@@ -0,0 +1,351 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* objfile.c */
|
||||
/* */
|
||||
/* Object file writing routines for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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 <errno.h>
|
||||
|
||||
#include "../common/objdefs.h"
|
||||
|
||||
#include "global.h"
|
||||
#include "error.h"
|
||||
#include "fname.h"
|
||||
#include "mem.h"
|
||||
#include "objfile.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* File descriptor */
|
||||
static FILE* F = 0;
|
||||
|
||||
/* Default extension */
|
||||
#define OBJ_EXT ".o"
|
||||
|
||||
/* Header structure */
|
||||
static ObjHeader Header = {
|
||||
OBJ_MAGIC,
|
||||
OBJ_VERSION
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Internally used functions */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static void ObjWriteError (void)
|
||||
/* Called on a write error. Will try to close and remove the file, then
|
||||
* print a fatal error.
|
||||
*/
|
||||
{
|
||||
/* Remember the error */
|
||||
int Error = errno;
|
||||
|
||||
/* Force a close of the file, ignoring errors */
|
||||
fclose (F);
|
||||
|
||||
/* Try to remove the file, also ignoring errors */
|
||||
remove (OutFile);
|
||||
|
||||
/* Now abort with a fatal error */
|
||||
Fatal (FAT_CANNOT_WRITE_OUTPUT, OutFile, strerror (Error));
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void ObjWriteHeader (void)
|
||||
/* Write the object file header to the current file position */
|
||||
{
|
||||
ObjWrite32 (Header.Magic);
|
||||
ObjWrite16 (Header.Version);
|
||||
ObjWrite16 (Header.Flags);
|
||||
ObjWrite32 (Header.OptionOffs);
|
||||
ObjWrite32 (Header.OptionSize);
|
||||
ObjWrite32 (Header.FileOffs);
|
||||
ObjWrite32 (Header.FileSize);
|
||||
ObjWrite32 (Header.SegOffs);
|
||||
ObjWrite32 (Header.SegSize);
|
||||
ObjWrite32 (Header.ImportOffs);
|
||||
ObjWrite32 (Header.ImportSize);
|
||||
ObjWrite32 (Header.ExportOffs);
|
||||
ObjWrite32 (Header.ExportSize);
|
||||
ObjWrite32 (Header.DbgSymOffs);
|
||||
ObjWrite32 (Header.DbgSymSize);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void ObjOpen (void)
|
||||
/* Open the object file for writing, write a dummy header */
|
||||
{
|
||||
/* Do we have a name for the output file? */
|
||||
if (OutFile == 0) {
|
||||
/* We don't have an output name explicitly given, construct one from
|
||||
* the name of the input file.
|
||||
*/
|
||||
OutFile = MakeFilename (InFile, OBJ_EXT);
|
||||
}
|
||||
|
||||
/* Create the output file */
|
||||
F = fopen (OutFile, "w+b");
|
||||
if (F == 0) {
|
||||
Fatal (FAT_CANNOT_OPEN_OUTPUT, OutFile, strerror (errno));
|
||||
}
|
||||
|
||||
/* Write a dummy header */
|
||||
ObjWriteHeader ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ObjClose (void)
|
||||
/* Write an update header and close the object file. */
|
||||
{
|
||||
/* Go back to the beginning */
|
||||
if (fseek (F, 0, SEEK_SET) != 0) {
|
||||
ObjWriteError ();
|
||||
}
|
||||
|
||||
/* If we have debug infos, set the flag in the header */
|
||||
if (DbgSyms) {
|
||||
Header.Flags |= OBJ_FLAGS_DBGINFO;
|
||||
}
|
||||
|
||||
/* Write the updated header */
|
||||
ObjWriteHeader ();
|
||||
|
||||
/* Close the file */
|
||||
if (fclose (F) != 0) {
|
||||
ObjWriteError ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ObjWrite8 (unsigned char V)
|
||||
/* Write an 8 bit value to the file */
|
||||
{
|
||||
if (putc (V, F) == EOF) {
|
||||
ObjWriteError ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ObjWrite16 (unsigned V)
|
||||
/* Write a 16 bit value to the file */
|
||||
{
|
||||
ObjWrite8 (V);
|
||||
ObjWrite8 (V >> 8);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ObjWrite24 (unsigned long V)
|
||||
/* Write a 24 bit value to the file */
|
||||
{
|
||||
ObjWrite8 (V);
|
||||
ObjWrite8 (V >> 8);
|
||||
ObjWrite8 (V >> 16);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ObjWrite32 (unsigned long V)
|
||||
/* Write a 32 bit value to the file */
|
||||
{
|
||||
ObjWrite8 (V);
|
||||
ObjWrite8 (V >> 8);
|
||||
ObjWrite8 (V >> 16);
|
||||
ObjWrite8 (V >> 24);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ObjWriteStr (const char* S)
|
||||
/* Write a string to the object file */
|
||||
{
|
||||
unsigned Len = strlen (S);
|
||||
if (Len > 255) {
|
||||
Internal ("String too long in ObjWriteStr");
|
||||
}
|
||||
|
||||
/* Write the string with a length byte preceeded (this is easier for
|
||||
* the reading routine than the C format since the length is known in
|
||||
* advance).
|
||||
*/
|
||||
ObjWrite8 ((unsigned char) Len);
|
||||
ObjWriteData (S, Len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ObjWriteData (const void* Data, unsigned Size)
|
||||
/* Write literal data to the file */
|
||||
{
|
||||
if (fwrite (Data, 1, Size, F) != Size) {
|
||||
ObjWriteError ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ObjWritePos (const FilePos* Pos)
|
||||
/* Write a file position to the object file */
|
||||
{
|
||||
/* Write the line number as 24 bit value to save one byte */
|
||||
ObjWrite24 (Pos->Line);
|
||||
ObjWrite8 (Pos->Col);
|
||||
if (Pos->Name == 0) {
|
||||
/* Position is outside file scope, use the main file instead */
|
||||
ObjWrite8 (0);
|
||||
} else {
|
||||
ObjWrite8 (Pos->Name - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ObjStartOptions (void)
|
||||
/* Mark the start of the option section */
|
||||
{
|
||||
Header.OptionOffs = ftell (F);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ObjEndOptions (void)
|
||||
/* Mark the end of the option section */
|
||||
{
|
||||
Header.OptionSize = ftell (F) - Header.OptionOffs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ObjStartFiles (void)
|
||||
/* Mark the start of the files section */
|
||||
{
|
||||
Header.FileOffs = ftell (F);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ObjEndFiles (void)
|
||||
/* Mark the end of the files section */
|
||||
{
|
||||
Header.FileSize = ftell (F) - Header.FileOffs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ObjStartSegments (void)
|
||||
/* Mark the start of the segment section */
|
||||
{
|
||||
Header.SegOffs = ftell (F);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ObjEndSegments (void)
|
||||
/* Mark the end of the segment section */
|
||||
{
|
||||
Header.SegSize = ftell (F) - Header.SegOffs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ObjStartImports (void)
|
||||
/* Mark the start of the import section */
|
||||
{
|
||||
Header.ImportOffs = ftell (F);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ObjEndImports (void)
|
||||
/* Mark the end of the import section */
|
||||
{
|
||||
Header.ImportSize = ftell (F) - Header.ImportOffs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ObjStartExports (void)
|
||||
/* Mark the start of the export section */
|
||||
{
|
||||
Header.ExportOffs = ftell (F);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ObjEndExports (void)
|
||||
/* Mark the end of the export section */
|
||||
{
|
||||
Header.ExportSize = ftell (F) - Header.ExportOffs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ObjStartDbgSyms (void)
|
||||
/* Mark the start of the debug symbol section */
|
||||
{
|
||||
Header.DbgSymOffs = ftell (F);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ObjEndDbgSyms (void)
|
||||
/* Mark the end of the debug symbol section */
|
||||
{
|
||||
Header.DbgSymSize = ftell (F) - Header.DbgSymOffs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
121
src/ca65/objfile.h
Normal file
121
src/ca65/objfile.h
Normal file
@@ -0,0 +1,121 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* objfile.h */
|
||||
/* */
|
||||
/* Object file writing routines for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef OBJFILE_H
|
||||
#define OBJFILE_H
|
||||
|
||||
|
||||
|
||||
#include "../common/filepos.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void ObjOpen (void);
|
||||
/* Open the object file for writing, write a dummy header */
|
||||
|
||||
void ObjClose (void);
|
||||
/* Write an update header and close the object file. */
|
||||
|
||||
void ObjWrite8 (unsigned char V);
|
||||
/* Write an 8 bit value to the file */
|
||||
|
||||
void ObjWrite16 (unsigned V);
|
||||
/* Write a 16 bit value to the file */
|
||||
|
||||
void ObjWrite24 (unsigned long V);
|
||||
/* Write a 24 bit value to the file */
|
||||
|
||||
void ObjWrite32 (unsigned long V);
|
||||
/* Write a 32 bit value to the file */
|
||||
|
||||
void ObjWriteStr (const char* S);
|
||||
/* Write a string to the object file */
|
||||
|
||||
void ObjWriteData (const void* Data, unsigned Size);
|
||||
/* Write literal data to the file */
|
||||
|
||||
void ObjWritePos (const FilePos* Pos);
|
||||
/* Write a file position to the object file */
|
||||
|
||||
void ObjStartOptions (void);
|
||||
/* Mark the start of the option section */
|
||||
|
||||
void ObjEndOptions (void);
|
||||
/* Mark the end of the option section */
|
||||
|
||||
void ObjStartFiles (void);
|
||||
/* Mark the start of the files section */
|
||||
|
||||
void ObjEndFiles (void);
|
||||
/* Mark the end of the files section */
|
||||
|
||||
void ObjStartSegments (void);
|
||||
/* Mark the start of the segment section */
|
||||
|
||||
void ObjEndSegments (void);
|
||||
/* Mark the end of the segment section */
|
||||
|
||||
void ObjStartImports (void);
|
||||
/* Mark the start of the import section */
|
||||
|
||||
void ObjEndImports (void);
|
||||
/* Mark the end of the import section */
|
||||
|
||||
void ObjStartExports (void);
|
||||
/* Mark the start of the export section */
|
||||
|
||||
void ObjEndExports (void);
|
||||
/* Mark the end of the export section */
|
||||
|
||||
void ObjStartDbgSyms (void);
|
||||
/* Mark the start of the debug symbol section */
|
||||
|
||||
void ObjEndDbgSyms (void);
|
||||
/* Mark the end of the debug symbol section */
|
||||
|
||||
|
||||
|
||||
/* End of objfile.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
202
src/ca65/options.c
Normal file
202
src/ca65/options.c
Normal file
@@ -0,0 +1,202 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* options.c */
|
||||
/* */
|
||||
/* Object file options for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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 "../common/optdefs.h"
|
||||
|
||||
#include "mem.h"
|
||||
#include "error.h"
|
||||
#include "objfile.h"
|
||||
#include "options.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Option list */
|
||||
static Option* OptRoot = 0;
|
||||
static Option* OptLast = 0;
|
||||
static unsigned OptCount = 0;
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static Option* NewOption (unsigned char Type)
|
||||
/* Create a new option, insert it into the list and return it */
|
||||
{
|
||||
Option* Opt;
|
||||
|
||||
/* Allocate memory */
|
||||
Opt = Xmalloc (sizeof (*Opt));
|
||||
|
||||
/* Initialize fields */
|
||||
Opt->Next = 0;
|
||||
Opt->Type = Type;
|
||||
Opt->V.Str = 0;
|
||||
|
||||
/* Insert it into the list */
|
||||
if (OptRoot == 0) {
|
||||
OptRoot = Opt;
|
||||
} else {
|
||||
OptLast->Next = Opt;
|
||||
}
|
||||
OptLast = Opt;
|
||||
|
||||
/* One more option now */
|
||||
++OptCount;
|
||||
|
||||
/* Return the new struct */
|
||||
return Opt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void OptStr (unsigned char Type, const char* Text)
|
||||
/* Add a string option */
|
||||
{
|
||||
Option* O;
|
||||
|
||||
/* String must have less than 255 bytes */
|
||||
if (strlen (Text) > 255) {
|
||||
Fatal (FAT_STRING_TOO_LONG);
|
||||
}
|
||||
O = NewOption (Type);
|
||||
O->V.Str = StrDup (Text);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void OptComment (const char* Comment)
|
||||
/* Add a comment */
|
||||
{
|
||||
OptStr (OPT_COMMENT, Comment);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void OptAuthor (const char* Author)
|
||||
/* Add an author statement */
|
||||
{
|
||||
OptStr (OPT_AUTHOR, Author);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void OptTranslator (const char* Translator)
|
||||
/* Add a translator option */
|
||||
{
|
||||
OptStr (OPT_TRANSLATOR, Translator);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void OptCompiler (const char* Compiler)
|
||||
/* Add a compiler option */
|
||||
{
|
||||
OptStr (OPT_COMPILER, Compiler);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void OptOS (const char* OS)
|
||||
/* Add an operating system option */
|
||||
{
|
||||
OptStr (OPT_OS, OS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void OptDateTime (unsigned long DateTime)
|
||||
/* Add a date/time option */
|
||||
{
|
||||
Option* O = NewOption (OPT_DATETIME);
|
||||
O->V.Val = DateTime;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void WriteOptions (void)
|
||||
/* Write the options to the object file */
|
||||
{
|
||||
Option* O;
|
||||
|
||||
/* Tell the object file module that we're about to start the options */
|
||||
ObjStartOptions ();
|
||||
|
||||
/* Write the option count */
|
||||
ObjWrite16 (OptCount);
|
||||
|
||||
/* Walk through the list and write the options */
|
||||
O = OptRoot;
|
||||
while (O) {
|
||||
|
||||
/* Write the type of the option */
|
||||
ObjWrite8 (O->Type);
|
||||
|
||||
/* Write the argument */
|
||||
switch (O->Type & OPT_ARGMASK) {
|
||||
|
||||
case OPT_ARGSTR:
|
||||
ObjWriteStr (O->V.Str);
|
||||
break;
|
||||
|
||||
case OPT_ARGNUM:
|
||||
ObjWrite32 (O->V.Val);
|
||||
break;
|
||||
|
||||
default:
|
||||
Internal ("Invalid option type: $%02X", O->Type & 0xFF);
|
||||
|
||||
}
|
||||
|
||||
/* Next option */
|
||||
O = O->Next;
|
||||
|
||||
}
|
||||
|
||||
/* Done writing options */
|
||||
ObjEndOptions ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
78
src/ca65/options.h
Normal file
78
src/ca65/options.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* options.h */
|
||||
/* */
|
||||
/* Object file options for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef OPTIONS_H
|
||||
#define OPTIONS_H
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void OptStr (unsigned char Type, const char* Text);
|
||||
/* Add a string option */
|
||||
|
||||
void OptComment (const char* Comment);
|
||||
/* Add a comment */
|
||||
|
||||
void OptAuthor (const char* Author);
|
||||
/* Add an author statement */
|
||||
|
||||
void OptTranslator (const char* Translator);
|
||||
/* Add a translator option */
|
||||
|
||||
void OptCompiler (const char* Compiler);
|
||||
/* Add a compiler option */
|
||||
|
||||
void OptOS (const char* OS);
|
||||
/* Add an operating system option */
|
||||
|
||||
void OptDateTime (unsigned long DateTime);
|
||||
/* Add a date/time option */
|
||||
|
||||
void WriteOptions (void);
|
||||
/* Write the options to the object file */
|
||||
|
||||
|
||||
|
||||
/* End of options.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
1190
src/ca65/pseudo.c
Normal file
1190
src/ca65/pseudo.c
Normal file
File diff suppressed because it is too large
Load Diff
74
src/ca65/pseudo.h
Normal file
74
src/ca65/pseudo.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* pseudo.h */
|
||||
/* */
|
||||
/* Pseudo instructions for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef PSEUDO_H
|
||||
#define PSEUDO_H
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Are we inside a .IF condition that has been evaluated to TRUE? */
|
||||
extern unsigned char IfCond;
|
||||
|
||||
/* How many .IFs are currently open? */
|
||||
extern unsigned OpenIfs;
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
int TokIsPseudo (unsigned Tok);
|
||||
/* Return true if the given token is a pseudo instruction token */
|
||||
|
||||
void HandlePseudo (void);
|
||||
/* Handle a pseudo instruction */
|
||||
|
||||
|
||||
|
||||
/* End of pseudo.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
1202
src/ca65/scanner.c
Normal file
1202
src/ca65/scanner.c
Normal file
File diff suppressed because it is too large
Load Diff
283
src/ca65/scanner.h
Normal file
283
src/ca65/scanner.h
Normal file
@@ -0,0 +1,283 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* scanner.h */
|
||||
/* */
|
||||
/* The scanner for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998-2000 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef SCANNER_H
|
||||
#define SCANNER_H
|
||||
|
||||
|
||||
|
||||
#include "../common/filepos.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Tokens */
|
||||
enum Token {
|
||||
TOK_NONE, /* Start value, invalid */
|
||||
TOK_EOF, /* End of input file */
|
||||
TOK_SEP, /* Separator (usually newline) */
|
||||
TOK_IDENT, /* An identifier */
|
||||
TOK_MNEMO, /* A mnemonic */
|
||||
|
||||
TOK_INTCON, /* Integer constant */
|
||||
TOK_CHARCON, /* Character constant */
|
||||
TOK_STRCON, /* String constant */
|
||||
|
||||
TOK_A, /* A)ccu */
|
||||
TOK_X, /* X register */
|
||||
TOK_Y, /* Y register */
|
||||
TOK_S, /* S register */
|
||||
|
||||
TOK_ULABEL, /* :++ or :-- */
|
||||
|
||||
TOK_EQ, /* = */
|
||||
TOK_NE, /* <> */
|
||||
TOK_LT, /* < */
|
||||
TOK_GT, /* > */
|
||||
TOK_LE, /* <= */
|
||||
TOK_GE, /* >= */
|
||||
|
||||
TOK_BAND, /* .and */
|
||||
TOK_BOR, /* .or */
|
||||
TOK_BXOR, /* .xor */
|
||||
TOK_BNOT, /* .not */
|
||||
|
||||
TOK_PLUS, /* + */
|
||||
TOK_MINUS, /* - */
|
||||
TOK_MUL, /* * */
|
||||
TOK_STAR = TOK_MUL, /* Alias */
|
||||
TOK_DIV, /* / */
|
||||
TOK_MOD, /* ! */
|
||||
TOK_OR, /* | */
|
||||
TOK_XOR, /* ^ */
|
||||
TOK_AND, /* & */
|
||||
TOK_SHL, /* << */
|
||||
TOK_SHR, /* >> */
|
||||
TOK_NOT, /* ~ */
|
||||
|
||||
TOK_PC, /* $ if enabled */
|
||||
TOK_NAMESPACE, /* :: */
|
||||
TOK_DOT, /* . */
|
||||
TOK_COMMA, /* , */
|
||||
TOK_HASH, /* # */
|
||||
TOK_COLON, /* : */
|
||||
TOK_LPAREN, /* ( */
|
||||
TOK_RPAREN, /* ) */
|
||||
TOK_LBRACK, /* [ */
|
||||
TOK_RBRACK, /* ] */
|
||||
|
||||
TOK_MACPARAM, /* Macro parameter, not generated by scanner */
|
||||
|
||||
/* The next ones are tokens for the pseudo instructions. Keep together! */
|
||||
TOK_FIRSTPSEUDO,
|
||||
TOK_A16 = TOK_FIRSTPSEUDO,
|
||||
TOK_A8,
|
||||
TOK_ADDR,
|
||||
TOK_ALIGN,
|
||||
TOK_ASCIIZ,
|
||||
TOK_AUTOIMPORT,
|
||||
TOK_BLANK,
|
||||
TOK_BSS,
|
||||
TOK_BYTE,
|
||||
TOK_CASE,
|
||||
TOK_CODE,
|
||||
TOK_CONST,
|
||||
TOK_CPU,
|
||||
TOK_DATA,
|
||||
TOK_DBYT,
|
||||
TOK_DEBUGINFO,
|
||||
TOK_DEFINE,
|
||||
TOK_DEFINED,
|
||||
TOK_DWORD,
|
||||
TOK_ELSE,
|
||||
TOK_ELSEIF,
|
||||
TOK_END,
|
||||
TOK_ENDIF,
|
||||
TOK_ENDMACRO,
|
||||
TOK_ENDPROC,
|
||||
TOK_ENDREP,
|
||||
TOK_ERROR,
|
||||
TOK_EXITMACRO,
|
||||
TOK_EXPORT,
|
||||
TOK_EXPORTZP,
|
||||
TOK_FARADDR,
|
||||
TOK_FEATURE,
|
||||
TOK_FILEOPT,
|
||||
TOK_GLOBAL,
|
||||
TOK_GLOBALZP,
|
||||
TOK_I16,
|
||||
TOK_I8,
|
||||
TOK_IF,
|
||||
TOK_IFBLANK,
|
||||
TOK_IFCONST,
|
||||
TOK_IFDEF,
|
||||
TOK_IFNBLANK,
|
||||
TOK_IFNCONST,
|
||||
TOK_IFNDEF,
|
||||
TOK_IFNREF,
|
||||
TOK_IFP02,
|
||||
TOK_IFP816,
|
||||
TOK_IFPC02,
|
||||
TOK_IFREF,
|
||||
TOK_IMPORT,
|
||||
TOK_IMPORTZP,
|
||||
TOK_INCBIN,
|
||||
TOK_INCLUDE,
|
||||
TOK_LINECONT,
|
||||
TOK_LIST,
|
||||
TOK_LISTBYTES,
|
||||
TOK_LOCAL,
|
||||
TOK_LOCALCHAR,
|
||||
TOK_MACPACK,
|
||||
TOK_MACRO,
|
||||
TOK_MATCH,
|
||||
TOK_NULL,
|
||||
TOK_ORG,
|
||||
TOK_OUT,
|
||||
TOK_P02,
|
||||
TOK_P816,
|
||||
TOK_PAGELENGTH,
|
||||
TOK_PARAMCOUNT,
|
||||
TOK_PC02,
|
||||
TOK_PROC,
|
||||
TOK_REFERENCED,
|
||||
TOK_RELOC,
|
||||
TOK_REPEAT,
|
||||
TOK_RES,
|
||||
TOK_RODATA,
|
||||
TOK_SEGMENT,
|
||||
TOK_SMART,
|
||||
TOK_STRING,
|
||||
TOK_SUNPLUS,
|
||||
TOK_WORD,
|
||||
TOK_XMATCH,
|
||||
TOK_ZEROPAGE,
|
||||
TOK_LASTPSEUDO = TOK_ZEROPAGE,
|
||||
|
||||
TOK_COUNT /* Count of tokens */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Scanner variables */
|
||||
#define MAX_INPUT_FILES 254 /* No more than this files total */
|
||||
#define MAX_STR_LEN 255 /* Maximum length of any string */
|
||||
extern enum Token Tok; /* Current token */
|
||||
extern int WS; /* Flag: Whitespace before token */
|
||||
extern long IVal; /* Integer token attribute */
|
||||
extern char SVal [MAX_STR_LEN+1]; /* String token attribute */
|
||||
|
||||
extern FilePos CurPos; /* Name and position in file */
|
||||
extern int ForcedEnd; /* Force end of assembly */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
const char* GetFileName (unsigned char Name);
|
||||
/* Get the name of a file where the name index is known */
|
||||
|
||||
void NewInputFile (const char* Name);
|
||||
/* Open a new input file */
|
||||
|
||||
void DoneInputFile (void);
|
||||
/* Close the current input file */
|
||||
|
||||
void NewInputData (const char* Data, int Malloced);
|
||||
/* Add a chunk of input data to the input stream */
|
||||
|
||||
void UpcaseSVal (void);
|
||||
/* Make SVal upper case */
|
||||
|
||||
void NextTok (void);
|
||||
/* Read the next token from the input stream */
|
||||
|
||||
void Consume (enum Token Expected, unsigned ErrMsg);
|
||||
/* Consume Token, print an error if we don't find it */
|
||||
|
||||
void ConsumeSep (void);
|
||||
/* Consume a separator token */
|
||||
|
||||
void ConsumeLParen (void);
|
||||
/* Consume a left paren */
|
||||
|
||||
void ConsumeRParen (void);
|
||||
/* Consume a right paren */
|
||||
|
||||
void ConsumeComma (void);
|
||||
/* Consume a comma */
|
||||
|
||||
void SkipUntilSep (void);
|
||||
/* Skip tokens until we reach a line separator */
|
||||
|
||||
int TokHasSVal (enum Token Tok);
|
||||
/* Return true if the given token has an attached SVal */
|
||||
|
||||
int TokHasIVal (enum Token Tok);
|
||||
/* Return true if the given token has an attached IVal */
|
||||
|
||||
int GetSubKey (const char** Keys, unsigned Count);
|
||||
/* Search for a subkey in a table of keywords. The current token must be an
|
||||
* identifier and all keys must be in upper case. The identifier will be
|
||||
* uppercased in the process. The function returns the index of the keyword,
|
||||
* or -1 if the keyword was not found.
|
||||
*/
|
||||
|
||||
void WriteFiles (void);
|
||||
/* Write the list of input files to the object file */
|
||||
|
||||
void InitScanner (const char* InFile);
|
||||
/* Initialize the scanner, open the given input file */
|
||||
|
||||
void DoneScanner (void);
|
||||
/* Release scanner resources */
|
||||
|
||||
|
||||
|
||||
/* End of scanner.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
97
src/ca65/strexpr.c
Normal file
97
src/ca65/strexpr.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* strexpr.c */
|
||||
/* */
|
||||
/* String expressions for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 2000 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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 "error.h"
|
||||
#include "expr.h"
|
||||
#include "scanner.h"
|
||||
#include "strexpr.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
const char* StringExpression (void)
|
||||
/* Evaluate a string expression. If there are no errors, the function will
|
||||
* place the string into the token attribute buffer SVal and the token will
|
||||
* be TOK_STRCON. A pointer to the buffer is returned.
|
||||
* If there was an error, a NULL pointer is returned.
|
||||
*/
|
||||
{
|
||||
char Buf [sizeof (SVal)];
|
||||
|
||||
/* Check for a string constant or a function that returns a string */
|
||||
switch (Tok) {
|
||||
|
||||
case TOK_STRING:
|
||||
NextTok ();
|
||||
ConsumeLParen ();
|
||||
if (Tok == TOK_IDENT) {
|
||||
/* Save the identifier, then skip it */
|
||||
strcpy (Buf, SVal);
|
||||
NextTok ();
|
||||
} else {
|
||||
/* Numeric expression */
|
||||
long Val = ConstExpression ();
|
||||
sprintf (Buf, "%ld", Val);
|
||||
}
|
||||
if (Tok != TOK_RPAREN) {
|
||||
Error (ERR_RPAREN_EXPECTED);
|
||||
}
|
||||
/* Overwrite the token, do not skip it! */
|
||||
strcpy (SVal, Buf);
|
||||
Tok = TOK_STRCON;
|
||||
break;
|
||||
|
||||
case TOK_STRCON:
|
||||
/* We already have a string */
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Error - no string constant */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return a pointer to the buffer */
|
||||
return SVal;
|
||||
}
|
||||
|
||||
|
||||
|
||||
61
src/ca65/strexpr.h
Normal file
61
src/ca65/strexpr.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* strexpr.h */
|
||||
/* */
|
||||
/* String expressions for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 2000 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef STREXPR_H
|
||||
#define STREXPR_H
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
const char* StringExpression (void);
|
||||
/* Evaluate a string expression. If there are no errors, the function will
|
||||
* place the string into the token attribute buffer SVal and the token will
|
||||
* be TOK_STRCON. A pointer to the buffer is returned.
|
||||
* If there was an error, a NULL pointer is returned.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* End of strexpr.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
57
src/ca65/symentry.h
Normal file
57
src/ca65/symentry.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* symentry.h */
|
||||
/* */
|
||||
/* Symbol table entry forward for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef SYMENTRY_H
|
||||
#define SYMENTRY_H
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Forward declaration for struct SymEntry */
|
||||
typedef struct SymEntry_ SymEntry;
|
||||
|
||||
|
||||
|
||||
/* End of symentry.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
1127
src/ca65/symtab.c
Normal file
1127
src/ca65/symtab.c
Normal file
File diff suppressed because it is too large
Load Diff
145
src/ca65/symtab.h
Normal file
145
src/ca65/symtab.h
Normal file
@@ -0,0 +1,145 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* symtab.h */
|
||||
/* */
|
||||
/* Symbol table for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef SYMTAB_H
|
||||
#define SYMTAB_H
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../common/exprdefs.h"
|
||||
|
||||
#include "symentry.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void SymEnterLevel (void);
|
||||
/* Enter a new lexical level */
|
||||
|
||||
void SymLeaveLevel (void);
|
||||
/* Leave the current lexical level */
|
||||
|
||||
void SymDef (const char* Name, ExprNode* Expr, int ZP);
|
||||
/* Define a new symbol */
|
||||
|
||||
SymEntry* SymRef (const char* Name);
|
||||
/* Search for the symbol and return it */
|
||||
|
||||
SymEntry* SymRefGlobal (const char* Name);
|
||||
/* Search for the symbol in the global namespace and return it */
|
||||
|
||||
int SymIsDef (const char* Name);
|
||||
/* Return true if the given symbol is already defined */
|
||||
|
||||
int SymIsRef (const char* Name);
|
||||
/* Return true if the given symbol has been referenced */
|
||||
|
||||
void SymImport (const char* Name, int ZP);
|
||||
/* Mark the given symbol as an imported symbol */
|
||||
|
||||
void SymExport (const char* Name, int ZP);
|
||||
/* Mark the given symbol as an exported symbol */
|
||||
|
||||
void SymGlobal (const char* Name, int ZP);
|
||||
/* Mark the given symbol as a global symbol, that is, as a symbol that is
|
||||
* either imported or exported.
|
||||
*/
|
||||
|
||||
int SymIsConst (SymEntry* Sym);
|
||||
/* Return true if the given symbol has a constant value */
|
||||
|
||||
int SymIsZP (SymEntry* Sym);
|
||||
/* Return true if the symbol is explicitly marked as zeropage symbol */
|
||||
|
||||
int SymIsImport (SymEntry* Sym);
|
||||
/* Return true if the given symbol is marked as import */
|
||||
|
||||
int SymHasExpr (SymEntry* Sym);
|
||||
/* Return true if the given symbol has an associated expression */
|
||||
|
||||
void SymMarkUser (SymEntry* Sym);
|
||||
/* Set a user mark on the specified symbol */
|
||||
|
||||
void SymUnmarkUser (SymEntry* Sym);
|
||||
/* Remove a user mark from the specified symbol */
|
||||
|
||||
int SymHasUserMark (SymEntry* Sym);
|
||||
/* Return the state of the user mark for the specified symbol */
|
||||
|
||||
long GetSymVal (SymEntry* Sym);
|
||||
/* Return the symbol value */
|
||||
|
||||
ExprNode* GetSymExpr (SymEntry* Sym);
|
||||
/* Get the expression for a non-const symbol */
|
||||
|
||||
const char* GetSymName (SymEntry* Sym);
|
||||
/* Return the name of the symbol */
|
||||
|
||||
unsigned GetSymIndex (SymEntry* Sym);
|
||||
/* Return the symbol index for the given symbol */
|
||||
|
||||
const FilePos* GetSymPos (SymEntry* Sym);
|
||||
/* Return the position of first occurence in the source for the given symbol */
|
||||
|
||||
void SymCheck (void);
|
||||
/* Run through all symbols and check for anomalies and errors */
|
||||
|
||||
void SymDump (FILE* F);
|
||||
/* Dump the symbol table */
|
||||
|
||||
void WriteImports (void);
|
||||
/* Write the imports list to the object file */
|
||||
|
||||
void WriteExports (void);
|
||||
/* Write the exports list to the object file */
|
||||
|
||||
void WriteDbgSyms (void);
|
||||
/* Write a list of all symbols to the object file */
|
||||
|
||||
|
||||
|
||||
/* End of symtab.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
117
src/ca65/toknode.c
Normal file
117
src/ca65/toknode.c
Normal file
@@ -0,0 +1,117 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* toknode.c */
|
||||
/* */
|
||||
/* Token list node for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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 <string.h>
|
||||
|
||||
#include "mem.h"
|
||||
#include "scanner.h"
|
||||
#include "toknode.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
TokNode* NewTokNode (void)
|
||||
/* Create and return a token node with the current token value */
|
||||
{
|
||||
TokNode* T;
|
||||
|
||||
/* Allocate memory */
|
||||
unsigned Len = TokHasSVal (Tok)? strlen (SVal) : 0;
|
||||
T = Xmalloc (sizeof (TokNode) + Len);
|
||||
|
||||
/* Initialize the token contents */
|
||||
T->Next = 0;
|
||||
T->Tok = Tok;
|
||||
T->WS = WS;
|
||||
T->IVal = IVal;
|
||||
memcpy (T->SVal, SVal, Len);
|
||||
T->SVal [Len] = '\0';
|
||||
|
||||
/* Return the node */
|
||||
return T;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void FreeTokNode (TokNode* T)
|
||||
/* Free the given token node */
|
||||
{
|
||||
Xfree (T);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void TokSet (TokNode* T)
|
||||
/* Set the scanner token from the given token node */
|
||||
{
|
||||
/* Set the values */
|
||||
Tok = T->Tok;
|
||||
WS = T->WS;
|
||||
IVal = T->IVal;
|
||||
strcpy (SVal, T->SVal);
|
||||
}
|
||||
|
||||
|
||||
|
||||
enum TC TokCmp (const TokNode* T)
|
||||
/* Compare the token given as parameter against the current token */
|
||||
{
|
||||
if (T->Tok != Tok) {
|
||||
/* Different token */
|
||||
return tcDifferent;
|
||||
}
|
||||
|
||||
/* If the token has string attribute, check it */
|
||||
if (TokHasSVal (T->Tok)) {
|
||||
if (strcmp (T->SVal, SVal) != 0) {
|
||||
return tcSameToken;
|
||||
}
|
||||
} else if (TokHasIVal (T->Tok)) {
|
||||
if (T->IVal != IVal) {
|
||||
return tcSameToken;
|
||||
}
|
||||
}
|
||||
|
||||
/* Tokens are identical */
|
||||
return tcIdentical;
|
||||
}
|
||||
|
||||
|
||||
|
||||
94
src/ca65/toknode.h
Normal file
94
src/ca65/toknode.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* toknode.h */
|
||||
/* */
|
||||
/* Token list node for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef TOKNODE_H
|
||||
#define TOKNODE_H
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Struct holding a token */
|
||||
typedef struct TokNode_ TokNode;
|
||||
struct TokNode_ {
|
||||
TokNode* Next; /* For single linked list */
|
||||
enum Token Tok; /* Token value */
|
||||
int WS; /* Whitespace before token? */
|
||||
long IVal; /* Integer token attribute */
|
||||
char SVal [1]; /* String attribute, dyn. allocated */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Return codes for TokCmp - higher numeric code means better match */
|
||||
enum TC {
|
||||
tcDifferent, /* Different tokents */
|
||||
tcSameToken, /* Same token, different attribute */
|
||||
tcIdentical /* Identical (token + attribute) */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
TokNode* NewTokNode (void);
|
||||
/* Create and return a token node with the current token value */
|
||||
|
||||
void FreeTokNode (TokNode* T);
|
||||
/* Free the given token node */
|
||||
|
||||
void TokSet (TokNode* T);
|
||||
/* Set the scanner token from the given token node */
|
||||
|
||||
enum TC TokCmp (const TokNode* T);
|
||||
/* Compare the token given as parameter against the current token */
|
||||
|
||||
|
||||
|
||||
/* End of toknode.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
242
src/ca65/ulabel.c
Normal file
242
src/ca65/ulabel.c
Normal file
@@ -0,0 +1,242 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* ulabel.c */
|
||||
/* */
|
||||
/* Unnamed labels for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 2000 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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 "../common/filepos.h"
|
||||
|
||||
#include "error.h"
|
||||
#include "expr.h"
|
||||
#include "mem.h"
|
||||
#include "scanner.h"
|
||||
#include "ulabel.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Struct that describes an unnamed label */
|
||||
typedef struct ULabel_ ULabel;
|
||||
struct ULabel_ {
|
||||
ULabel* Prev; /* Pointer to previous node in list */
|
||||
ULabel* Next; /* Pointer to next node in list */
|
||||
FilePos Pos; /* Position of the label in the source */
|
||||
ExprNode* Val; /* The label value - may be NULL */
|
||||
};
|
||||
|
||||
/* List management */
|
||||
static ULabel* ULabRoot = 0; /* Root of the list */
|
||||
static ULabel* ULabLast = 0; /* Last ULabel */
|
||||
static ULabel* ULabLastDef = 0; /* Last defined ULabel */
|
||||
static unsigned ULabCount = 0; /* Number of labels */
|
||||
static unsigned ULabDefCount = 0; /* Number of defined labels */
|
||||
static ULabel** ULabList = 0; /* Array with pointers to all labels */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static ULabel* NewULabel (ExprNode* Val)
|
||||
/* Create a new ULabel and insert it into the list. The function will move
|
||||
* ULabelLast, but not ULabelLastDef. The created label structure is returned.
|
||||
*/
|
||||
{
|
||||
/* Allocate memory for the ULabel structure */
|
||||
ULabel* L = Xmalloc (sizeof (ULabel));
|
||||
|
||||
/* Initialize the fields */
|
||||
L->Pos = CurPos;
|
||||
L->Val = Val;
|
||||
|
||||
/* Insert the label into the list */
|
||||
L->Next = 0;
|
||||
if (ULabRoot == 0) {
|
||||
/* First label */
|
||||
L->Prev = 0;
|
||||
ULabRoot = L;
|
||||
} else {
|
||||
ULabLast->Next = L;
|
||||
L->Prev = ULabLast;
|
||||
}
|
||||
ULabLast = L;
|
||||
|
||||
/* One label more */
|
||||
++ULabCount;
|
||||
|
||||
/* Return the created label */
|
||||
return L;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ExprNode* ULabRef (int Which)
|
||||
/* Get an unnamed label. If Which is negative, it is a backreference (a
|
||||
* reference to an already defined label), and the function will return a
|
||||
* segment relative expression. If Which is positive, it is a forward ref,
|
||||
* and the function will return a expression node for an unnamed label that
|
||||
* must be resolved later.
|
||||
*/
|
||||
{
|
||||
ULabel* L;
|
||||
|
||||
/* Which can never be 0 */
|
||||
PRECONDITION (Which != 0);
|
||||
|
||||
/* Which is never really big (usually -3..+3), so a linear search is
|
||||
* the best we can do here.
|
||||
*/
|
||||
L = ULabLastDef;
|
||||
if (Which < 0) {
|
||||
/* Backward reference */
|
||||
while (Which < -1 && L != 0) {
|
||||
L = L->Prev;
|
||||
++Which;
|
||||
}
|
||||
if (L == 0) {
|
||||
/* Label does not exist */
|
||||
Error (ERR_UNDEFINED_LABEL);
|
||||
/* We must return something valid */
|
||||
return CurrentPC();
|
||||
} else {
|
||||
/* Return a copy of the label value */
|
||||
return CloneExpr (L->Val);
|
||||
}
|
||||
} else {
|
||||
/* Forward reference. Create labels as needed */
|
||||
unsigned LabelNum = ULabDefCount + Which - 1;
|
||||
while (Which > 0) {
|
||||
if (L->Next == 0) {
|
||||
NewULabel (0);
|
||||
}
|
||||
L = L->Next;
|
||||
--Which;
|
||||
}
|
||||
/* Return an unnamed label expression */
|
||||
return ULabelExpr (LabelNum);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ULabDef (void)
|
||||
/* Define an unnamed label at the current PC */
|
||||
{
|
||||
/* Create a new label if needed, or use an existing one */
|
||||
if (ULabLastDef == 0 || ULabLastDef->Next == 0) {
|
||||
/* The last label is also the last defined label, we need a new one */
|
||||
ULabLastDef = NewULabel (CurrentPC ());
|
||||
} else {
|
||||
/* We do already have the label, but it's undefined until now */
|
||||
ULabLastDef = ULabLastDef->Next;
|
||||
ULabLastDef->Val = CurrentPC ();
|
||||
ULabLastDef->Pos = CurPos;
|
||||
}
|
||||
++ULabDefCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ULabCanResolve (void)
|
||||
/* Return true if we can resolve arbitrary ULabels. */
|
||||
{
|
||||
/* We can resolve labels if we have built the necessary access array */
|
||||
return (ULabList != 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
ExprNode* ULabResolve (unsigned Index)
|
||||
/* Return a valid expression for the unnamed label with the given index. This
|
||||
* is used to resolve unnamed labels when assembly is done, so it is an error
|
||||
* if a label is still undefined in this phase.
|
||||
*/
|
||||
{
|
||||
ULabel* L;
|
||||
|
||||
/* Must be in resolve phase and the index must be valid */
|
||||
CHECK (ULabList != 0 && Index < ULabCount);
|
||||
|
||||
/* Get the label */
|
||||
L = ULabList [Index];
|
||||
|
||||
/* If the label is open (not defined), return some valid value */
|
||||
if (L->Val == 0) {
|
||||
return LiteralExpr (0);
|
||||
} else {
|
||||
return CloneExpr (L->Val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ULabCheck (void)
|
||||
/* Run through all unnamed labels and check for anomalies and errors */
|
||||
{
|
||||
ULabel* L;
|
||||
|
||||
/* Check if there are undefined labels */
|
||||
if (ULabLastDef) {
|
||||
L = ULabLastDef->Next;
|
||||
while (L) {
|
||||
PError (&L->Pos, ERR_UNDEFINED_LABEL);
|
||||
L = L->Next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create an array that holds pointers to all labels. This allows us to
|
||||
* access the labels quickly by index in the resolver phase at the end of
|
||||
* the assembly.
|
||||
*/
|
||||
if (ULabCount) {
|
||||
unsigned I = 0;
|
||||
ULabList = Xmalloc (ULabCount * sizeof (ULabel*));
|
||||
L = ULabRoot;
|
||||
while (L) {
|
||||
ULabList[I] = L;
|
||||
++I;
|
||||
L = L->Next;
|
||||
}
|
||||
CHECK (I == ULabCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
77
src/ca65/ulabel.h
Normal file
77
src/ca65/ulabel.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* ulabel.h */
|
||||
/* */
|
||||
/* Unnamed labels for the ca65 macroassembler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 2000 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* */
|
||||
/* */
|
||||
/* 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. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef ULABEL_H
|
||||
#define ULABEL_H
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
ExprNode* ULabRef (int Which);
|
||||
/* Get an unnamed label. If Which is negative, it is a backreference (a
|
||||
* reference to an already defined label), and the function will return a
|
||||
* segment relative expression. If Which is positive, it is a forward ref,
|
||||
* and the function will return a expression node for an unnamed label that
|
||||
* must be resolved later.
|
||||
*/
|
||||
|
||||
void ULabDef (void);
|
||||
/* Define an unnamed label at the current PC */
|
||||
|
||||
int ULabCanResolve (void);
|
||||
/* Return true if we can resolve arbitrary ULabels. */
|
||||
|
||||
ExprNode* ULabResolve (unsigned Index);
|
||||
/* Return a valid expression for the unnamed label with the given index. This
|
||||
* is used to resolve unnamed labels when assembly is done, so it is an error
|
||||
* if a label is still undefined in this phase.
|
||||
*/
|
||||
|
||||
void ULabCheck (void);
|
||||
/* Run through all unnamed labels and check for anomalies and errors */
|
||||
|
||||
|
||||
|
||||
/* End of ulabel.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user