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:
1
src/.cvsignore
Normal file
1
src/.cvsignore
Normal file
@@ -0,0 +1 @@
|
||||
*.obj
|
||||
3
src/ar65/.cvsignore
Normal file
3
src/ar65/.cvsignore
Normal file
@@ -0,0 +1,3 @@
|
||||
.depend
|
||||
ar65
|
||||
|
||||
83
src/ar65/add.c
Normal file
83
src/ar65/add.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* add.c */
|
||||
/* */
|
||||
/* Object file adding for the ar65 archiver */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 "error.h"
|
||||
#include "objfile.h"
|
||||
#include "library.h"
|
||||
#include "add.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void AddObjFiles (int argc, char* argv [])
|
||||
/* Add object files to a library */
|
||||
{
|
||||
int I;
|
||||
|
||||
/* Check the argument count */
|
||||
if (argc <= 0) {
|
||||
Error ("No library name given");
|
||||
}
|
||||
if (argc <= 1) {
|
||||
Error ("No object files to add");
|
||||
}
|
||||
|
||||
/* Open the library, read the index */
|
||||
LibOpen (argv [0], 0, 1);
|
||||
|
||||
/* Add the object files */
|
||||
I = 1;
|
||||
while (I < argc) {
|
||||
ObjAdd (argv [I]);
|
||||
++I;
|
||||
}
|
||||
|
||||
/* Create a new library file and close the old one */
|
||||
LibClose ();
|
||||
|
||||
/* Successful end */
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
58
src/ar65/add.h
Normal file
58
src/ar65/add.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* add.h */
|
||||
/* */
|
||||
/* Object file adding for the ar65 archiver */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 ADD_H
|
||||
#define ADD_H
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void AddObjFiles (int argc, char* argv []);
|
||||
/* Add object files to a library */
|
||||
|
||||
|
||||
|
||||
/* End of add.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
84
src/ar65/del.c
Normal file
84
src/ar65/del.c
Normal file
@@ -0,0 +1,84 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* del.h */
|
||||
/* */
|
||||
/* Object file deleting for the ar65 archiver */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 "error.h"
|
||||
#include "objdata.h"
|
||||
#include "library.h"
|
||||
#include "del.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void DelObjFiles (int argc, char* argv [])
|
||||
/* Delete modules from a library */
|
||||
{
|
||||
int I;
|
||||
|
||||
/* Check the argument count */
|
||||
if (argc <= 0) {
|
||||
Error ("No library name given");
|
||||
}
|
||||
if (argc <= 1) {
|
||||
Error ("No modules to delete");
|
||||
}
|
||||
|
||||
/* Open the library, read the index */
|
||||
LibOpen (argv [0], 1, 1);
|
||||
|
||||
/* Delete the modules */
|
||||
I = 1;
|
||||
while (I < argc) {
|
||||
/* Delete the module from the list */
|
||||
DelObjData (argv [I]);
|
||||
++I;
|
||||
}
|
||||
|
||||
/* Create a new library file and close the old one */
|
||||
LibClose ();
|
||||
|
||||
/* Successful end */
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
58
src/ar65/del.h
Normal file
58
src/ar65/del.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* del.h */
|
||||
/* */
|
||||
/* Object file deleting for the ar65 archiver */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 DEL_H
|
||||
#define DEL_H
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void DelObjFiles (int argc, char* argv []);
|
||||
/* Delete modules from a library */
|
||||
|
||||
|
||||
|
||||
/* End of del.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
106
src/ar65/error.c
Normal file
106
src/ar65/error.c
Normal file
@@ -0,0 +1,106 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* global.c */
|
||||
/* */
|
||||
/* Error handling for the ar65 archiver */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 <stdarg.h>
|
||||
|
||||
#include "error.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* 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";
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void Warning (const char* Format, ...)
|
||||
/* Print a warning message */
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, Format);
|
||||
fprintf (stderr, "Warning: ");
|
||||
vfprintf (stderr, Format, ap);
|
||||
putc ('\n', stderr);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Error (const char* Format, ...)
|
||||
/* Print an error message and die */
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, Format);
|
||||
fprintf (stderr, "Error: ");
|
||||
vfprintf (stderr, Format, ap);
|
||||
putc ('\n', stderr);
|
||||
va_end (ap);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Internal (const char* Format, ...)
|
||||
/* Print an internal error message and die */
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, Format);
|
||||
fprintf (stderr, "Internal error: ");
|
||||
vfprintf (stderr, Format, ap);
|
||||
putc ('\n', stderr);
|
||||
va_end (ap);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
87
src/ar65/error.h
Normal file
87
src/ar65/error.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* global.h */
|
||||
/* */
|
||||
/* Error handling for the ar65 archiver */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 ERROR_H
|
||||
#define ERROR_H
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Messages for internal compiler errors */
|
||||
extern const char _MsgCheckFailed [];
|
||||
extern const char _MsgPrecondition [];
|
||||
extern const char _MsgFail [];
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void Warning (const char* Format, ...);
|
||||
/* Print a warning message */
|
||||
|
||||
void Error (const char* Format, ...);
|
||||
/* Print an error message and die */
|
||||
|
||||
void Internal (const char* Format, ...);
|
||||
/* Print an internal error message 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
|
||||
|
||||
|
||||
|
||||
149
src/ar65/exports.c
Normal file
149
src/ar65/exports.c
Normal file
@@ -0,0 +1,149 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* exports.c */
|
||||
/* */
|
||||
/* Duplicate export checking for the ar65 archiver */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 "../common/hashstr.h"
|
||||
|
||||
#include "mem.h"
|
||||
#include "error.h"
|
||||
#include "objdata.h"
|
||||
#include "exports.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* A hash table entry */
|
||||
typedef struct HashEntry_ HashEntry;
|
||||
struct HashEntry_ {
|
||||
HashEntry* Next; /* Next in list */
|
||||
unsigned Module; /* Module index */
|
||||
char Name [1]; /* Name of identifier */
|
||||
};
|
||||
|
||||
/* Hash table */
|
||||
#define HASHTAB_SIZE 4783
|
||||
static HashEntry* HashTab [HASHTAB_SIZE];
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static HashEntry* NewHashEntry (const char* Name, unsigned Module)
|
||||
/* Create and return a new hash entry */
|
||||
{
|
||||
/* Get the length of the name */
|
||||
unsigned Len = strlen (Name);
|
||||
|
||||
/* Get memory for the struct */
|
||||
HashEntry* H = Xmalloc (sizeof (HashEntry) + Len);
|
||||
|
||||
/* Initialize the fields and return it */
|
||||
H->Next = 0;
|
||||
H->Module = Module;
|
||||
memcpy (H->Name, Name, Len);
|
||||
H->Name [Len] = '\0';
|
||||
return H;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ExpInsert (const char* Name, unsigned Module)
|
||||
/* Insert an exported identifier and check if it's already in the list */
|
||||
{
|
||||
HashEntry* L;
|
||||
|
||||
/* Create a hash value for the given name */
|
||||
unsigned HashVal = HashStr (Name) % HASHTAB_SIZE;
|
||||
|
||||
/* Create a new hash entry */
|
||||
HashEntry* H = NewHashEntry (Name, Module);
|
||||
|
||||
/* Search through the list in that slot and print matching duplicates */
|
||||
if (HashTab [HashVal] == 0) {
|
||||
/* The slot is empty */
|
||||
HashTab [HashVal] = H;
|
||||
return;
|
||||
}
|
||||
L = HashTab [HashVal];
|
||||
while (1) {
|
||||
if (strcmp (L->Name, Name) == 0) {
|
||||
/* Duplicate entry */
|
||||
Warning ("External symbol `%s' in module `%s' is duplicated in "
|
||||
"module `%s'",
|
||||
Name, GetObjName (L->Module), GetObjName (Module));
|
||||
}
|
||||
if (L->Next == 0) {
|
||||
break;
|
||||
} else {
|
||||
L = L->Next;
|
||||
}
|
||||
}
|
||||
L->Next = H;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ExpFind (const char* Name)
|
||||
/* Check for an identifier in the list. Return -1 if not found, otherwise
|
||||
* return the number of the module, that exports the identifer.
|
||||
*/
|
||||
{
|
||||
/* Get a pointer to the list with the symbols hash value */
|
||||
HashEntry* L = HashTab [HashStr (Name) % HASHTAB_SIZE];
|
||||
while (L) {
|
||||
/* Search through the list in that slot */
|
||||
if (strcmp (L->Name, Name) == 0) {
|
||||
/* Entry found */
|
||||
return L->Module;
|
||||
}
|
||||
L = L->Next;
|
||||
}
|
||||
|
||||
/* Not found */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
62
src/ar65/exports.h
Normal file
62
src/ar65/exports.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* exports.h */
|
||||
/* */
|
||||
/* Duplicate export checking for the ar65 archiver */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 EXPORTS_H
|
||||
#define EXPORTS_H
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void ExpInsert (const char* Name, unsigned Module);
|
||||
/* Insert an exported identifier and check if it's already in the list */
|
||||
|
||||
int ExpFind (const char* Name);
|
||||
/* Check for an identifier in the list. Return -1 if not found, otherwise
|
||||
* return the number of the module, that exports the identifer.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* End of exports.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
83
src/ar65/extract.c
Normal file
83
src/ar65/extract.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* extract.c */
|
||||
/* */
|
||||
/* Object file extraction for the ar65 archiver */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 "mem.h"
|
||||
#include "error.h"
|
||||
#include "objfile.h"
|
||||
#include "library.h"
|
||||
#include "extract.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void ExtractObjFiles (int argc, char* argv [])
|
||||
/* Extract object files from a library */
|
||||
{
|
||||
int I;
|
||||
|
||||
/* Check the argument count */
|
||||
if (argc <= 0) {
|
||||
Error ("No library name given");
|
||||
}
|
||||
if (argc <= 1) {
|
||||
Error ("No object files to add");
|
||||
}
|
||||
|
||||
/* Open the library, read the index */
|
||||
LibOpen (argv [0], 1, 0);
|
||||
|
||||
/* Extract the object files */
|
||||
I = 1;
|
||||
while (I < argc) {
|
||||
ObjExtract (argv [I]);
|
||||
++I;
|
||||
}
|
||||
|
||||
/* Create a new library file and close the old one */
|
||||
LibClose ();
|
||||
|
||||
/* Successful end */
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
58
src/ar65/extract.h
Normal file
58
src/ar65/extract.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* extract.h */
|
||||
/* */
|
||||
/* Object file extraction for the ar65 archiver */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 EXTRACT_H
|
||||
#define EXTRACT_H
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void ExtractObjFiles (int argc, char* argv []);
|
||||
/* Extract object files from a library */
|
||||
|
||||
|
||||
|
||||
/* End of extract.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
210
src/ar65/fileio.c
Normal file
210
src/ar65/fileio.c
Normal file
@@ -0,0 +1,210 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* fileio.c */
|
||||
/* */
|
||||
/* File I/O for the ar65 archiver */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 "error.h"
|
||||
#include "mem.h"
|
||||
#include "fileio.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void Write8 (FILE* F, unsigned char Val)
|
||||
/* Write an 8 bit value to the file */
|
||||
{
|
||||
if (putc (Val, F) == EOF) {
|
||||
Error ("Write error (disk full?)");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Write16 (FILE* F, unsigned Val)
|
||||
/* Write a 16 bit value to the file */
|
||||
{
|
||||
Write8 (F, (unsigned char) Val);
|
||||
Write8 (F, (unsigned char) (Val >> 8));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Write32 (FILE* F, unsigned long Val)
|
||||
/* Write a 32 bit value to the file */
|
||||
{
|
||||
Write8 (F, (unsigned char) Val);
|
||||
Write8 (F, (unsigned char) (Val >> 8));
|
||||
Write8 (F, (unsigned char) (Val >> 16));
|
||||
Write8 (F, (unsigned char) (Val >> 24));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void WriteStr (FILE* F, const char* S)
|
||||
/* Write a string to the file */
|
||||
{
|
||||
unsigned Len = strlen (S);
|
||||
if (Len > 255) {
|
||||
Internal ("String too long");
|
||||
}
|
||||
Write8 (F, (unsigned char) Len);
|
||||
WriteData (F, S, Len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void WriteData (FILE* F, const void* Data, unsigned Size)
|
||||
/* Write data to the file */
|
||||
{
|
||||
if (fwrite (Data, 1, Size, F) != Size) {
|
||||
Error ("Write error (disk full?)");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned Read8 (FILE* F)
|
||||
/* Read an 8 bit value from the file */
|
||||
{
|
||||
int C = getc (F);
|
||||
if (C == EOF) {
|
||||
Error ("Read error (file corrupt?)");
|
||||
}
|
||||
return C;
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned Read16 (FILE* F)
|
||||
/* Read a 16 bit value from the file */
|
||||
{
|
||||
unsigned Lo = Read8 (F);
|
||||
unsigned Hi = Read8 (F);
|
||||
return (Hi << 8) | Lo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned long Read32 (FILE* F)
|
||||
/* Read a 32 bit value from the file */
|
||||
{
|
||||
unsigned long Lo = Read16 (F);
|
||||
unsigned long Hi = Read16 (F);
|
||||
return (Hi << 16) | Lo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
char* ReadStr (FILE* F)
|
||||
/* Read a string from the file (the memory will be malloc'ed) */
|
||||
{
|
||||
/* Read the length byte */
|
||||
unsigned Len = Read8 (F);
|
||||
|
||||
/* Allocate memory and read the string itself */
|
||||
char* S = Xmalloc (Len + 1);
|
||||
ReadData (F, S, Len);
|
||||
|
||||
/* Terminate the string and return it */
|
||||
S [Len] = '\0';
|
||||
return S;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void* ReadData (FILE* F, void* Data, unsigned Size)
|
||||
/* Read data from the file */
|
||||
{
|
||||
if (fread (Data, 1, Size, F) != Size) {
|
||||
Error ("Read error (file corrupt?)");
|
||||
}
|
||||
return Data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
88
src/ar65/fileio.h
Normal file
88
src/ar65/fileio.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* fileio.h */
|
||||
/* */
|
||||
/* File I/O for the ar65 archiver */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 FILEIO_H
|
||||
#define FILEIO_H
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void Write8 (FILE* F, unsigned char Val);
|
||||
/* Write an 8 bit value to the file */
|
||||
|
||||
void Write16 (FILE* F, unsigned Val);
|
||||
/* Write a 16 bit value to the file */
|
||||
|
||||
void Write32 (FILE* F, unsigned long Val);
|
||||
/* Write a 32 bit value to the file */
|
||||
|
||||
void WriteStr (FILE* F, const char* S);
|
||||
/* Write a string to the file */
|
||||
|
||||
void WriteData (FILE* F, const void* Data, unsigned Size);
|
||||
/* Write data to the file */
|
||||
|
||||
unsigned Read8 (FILE* F);
|
||||
/* Read an 8 bit value from the file */
|
||||
|
||||
unsigned Read16 (FILE* F);
|
||||
/* Read a 16 bit value from the file */
|
||||
|
||||
unsigned long Read32 (FILE* F);
|
||||
/* Read a 32 bit value from the file */
|
||||
|
||||
char* ReadStr (FILE* F);
|
||||
/* Read a string from the file (the memory will be malloc'ed) */
|
||||
|
||||
void* ReadData (FILE* F, void* Data, unsigned Size);
|
||||
/* Read data from the file */
|
||||
|
||||
|
||||
|
||||
/* End of fileio.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
51
src/ar65/global.c
Normal file
51
src/ar65/global.c
Normal file
@@ -0,0 +1,51 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* global.c */
|
||||
/* */
|
||||
/* Global variables for the ar65 archiver */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 "global.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
const char* ProgName = "ar65"; /* Program name */
|
||||
|
||||
int Verbose = 0; /* Verbose operation flag */
|
||||
|
||||
|
||||
|
||||
58
src/ar65/global.h
Normal file
58
src/ar65/global.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* global.h */
|
||||
/* */
|
||||
/* Global variables for the ar65 archiver */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 GLOBAL_H
|
||||
#define GLOBAL_H
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
extern const char* ProgName; /* Program name */
|
||||
|
||||
extern int Verbose; /* Verbose operation flag */
|
||||
|
||||
|
||||
|
||||
/* End of global.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
470
src/ar65/library.c
Normal file
470
src/ar65/library.c
Normal file
@@ -0,0 +1,470 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* library.c */
|
||||
/* */
|
||||
/* Library data structures and helpers for the ar65 archiver */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "../common/libdefs.h"
|
||||
#include "../common/symdefs.h"
|
||||
#include "../common/exprdefs.h"
|
||||
#include "../common/filepos.h"
|
||||
#include "../common/bitops.h"
|
||||
|
||||
#include "mem.h"
|
||||
#include "error.h"
|
||||
#include "global.h"
|
||||
#include "fileio.h"
|
||||
#include "objdata.h"
|
||||
#include "exports.h"
|
||||
#include "library.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* File descriptor for the library file */
|
||||
FILE* NewLib = 0;
|
||||
static FILE* Lib = 0;
|
||||
static const char* LibName = 0;
|
||||
|
||||
/* The library header */
|
||||
static LibHeader Header = {
|
||||
LIB_MAGIC,
|
||||
LIB_VERSION
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Writing file data structures */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static void ReadHeader (void)
|
||||
/* Read the header of a library file */
|
||||
{
|
||||
/* Seek to position zero */
|
||||
fseek (Lib, 0, SEEK_SET);
|
||||
|
||||
/* Read the header fields, checking magic and version */
|
||||
Header.Magic = Read32 (Lib);
|
||||
if (Header.Magic != LIB_MAGIC) {
|
||||
Error ("`%s' is not a valid library file", LibName);
|
||||
}
|
||||
Header.Version = Read16 (Lib);
|
||||
if (Header.Version != LIB_VERSION) {
|
||||
Error ("Wrong data version in `%s'", LibName);
|
||||
}
|
||||
Header.Flags = Read16 (Lib);
|
||||
Header.IndexOffs = Read32 (Lib);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void ReadIndexEntry (void)
|
||||
/* Read one entry in the index */
|
||||
{
|
||||
/* Create a new entry and insert it into the list */
|
||||
ObjData* O = NewObjData ();
|
||||
|
||||
/* Module name/flags/MTime/Start/Size */
|
||||
O->Name = ReadStr (Lib);
|
||||
O->Flags = Read16 (Lib);
|
||||
O->MTime = Read32 (Lib);
|
||||
O->Start = Read32 (Lib);
|
||||
O->Size = Read32 (Lib);
|
||||
|
||||
/* Exports */
|
||||
O->ExportSize = Read16 (Lib);
|
||||
O->Exports = Xmalloc (O->ExportSize);
|
||||
ReadData (Lib, O->Exports, O->ExportSize);
|
||||
|
||||
/* Imports */
|
||||
O->ImportSize = Read16 (Lib);
|
||||
O->Imports = Xmalloc (O->ImportSize);
|
||||
ReadData (Lib, O->Imports, O->ImportSize);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void ReadIndex (void)
|
||||
/* Read the index of a library file */
|
||||
{
|
||||
unsigned Count;
|
||||
|
||||
/* Seek to the start of the index */
|
||||
fseek (Lib, Header.IndexOffs, SEEK_SET);
|
||||
|
||||
/* Read the object file count and calculate the cross ref size */
|
||||
Count = Read16 (Lib);
|
||||
|
||||
/* Read all entries in the index */
|
||||
while (Count--) {
|
||||
ReadIndexEntry ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Writing file data structures */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static void WriteHeader (void)
|
||||
/* Write the header to the library file */
|
||||
{
|
||||
/* Seek to position zero */
|
||||
fseek (NewLib, 0, SEEK_SET);
|
||||
|
||||
/* Write the header fields */
|
||||
Write32 (NewLib, Header.Magic);
|
||||
Write16 (NewLib, Header.Version);
|
||||
Write16 (NewLib, Header.Flags);
|
||||
Write32 (NewLib, Header.IndexOffs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void WriteIndexEntry (ObjData* O)
|
||||
/* Write one index entry */
|
||||
{
|
||||
/* Module name/flags/MTime/start/size */
|
||||
WriteStr (NewLib, O->Name);
|
||||
Write16 (NewLib, O->Flags & ~OBJ_HAVEDATA);
|
||||
Write32 (NewLib, O->MTime);
|
||||
Write32 (NewLib, O->Start);
|
||||
Write32 (NewLib, O->Size);
|
||||
|
||||
/* Exports */
|
||||
Write16 (NewLib, O->ExportSize);
|
||||
WriteData (NewLib, O->Exports, O->ExportSize);
|
||||
|
||||
/* Imports */
|
||||
Write16 (NewLib, O->ImportSize);
|
||||
WriteData (NewLib, O->Imports, O->ImportSize);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void WriteIndex (void)
|
||||
/* Write the index of a library file */
|
||||
{
|
||||
ObjData* O;
|
||||
|
||||
/* Sync I/O in case the last operation was a read */
|
||||
fseek (NewLib, 0, SEEK_CUR);
|
||||
|
||||
/* Remember the current offset in the header */
|
||||
Header.IndexOffs = ftell (NewLib);
|
||||
|
||||
/* Write the object file count */
|
||||
Write16 (NewLib, ObjCount);
|
||||
|
||||
/* Write the object files */
|
||||
O = ObjRoot;
|
||||
while (O) {
|
||||
WriteIndexEntry (O);
|
||||
O = O->Next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* High level stuff */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void LibOpen (const char* Name, int MustExist, int NeedTemp)
|
||||
/* Open an existing library and a temporary copy. If MustExist is true, the
|
||||
* old library is expected to exist. If NeedTemp is true, a temporary library
|
||||
* is created.
|
||||
*/
|
||||
{
|
||||
/* Remember the name */
|
||||
LibName = StrDup (Name);
|
||||
|
||||
/* Open the existing library for reading */
|
||||
Lib = fopen (Name, "rb");
|
||||
if (Lib == 0) {
|
||||
|
||||
/* File does not exist */
|
||||
if (MustExist) {
|
||||
Error ("Library `%s' does not exist", Name);
|
||||
} else {
|
||||
Warning ("Library `%s' not found - will be created", Name);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* We have an existing file: Read the header */
|
||||
ReadHeader ();
|
||||
|
||||
/* Now read the existing index */
|
||||
ReadIndex ();
|
||||
|
||||
}
|
||||
|
||||
if (NeedTemp) {
|
||||
/* Create the temporary library */
|
||||
NewLib = tmpfile ();
|
||||
if (NewLib == 0) {
|
||||
Error ("Cannot create temporary file: %s", strerror (errno));
|
||||
}
|
||||
|
||||
/* Write a dummy header to the temp file */
|
||||
WriteHeader ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned long LibCopyTo (FILE* F, unsigned long Bytes)
|
||||
/* Copy data from F to the temp library file, return the start position in
|
||||
* the temporary library file.
|
||||
*/
|
||||
{
|
||||
unsigned char Buf [4096];
|
||||
|
||||
/* Remember the position */
|
||||
unsigned long Pos = ftell (NewLib);
|
||||
|
||||
/* Copy loop */
|
||||
while (Bytes) {
|
||||
unsigned Count = (Bytes > sizeof (Buf))? sizeof (Buf) : Bytes;
|
||||
ReadData (F, Buf, Count);
|
||||
WriteData (NewLib, Buf, Count);
|
||||
Bytes -= Count;
|
||||
}
|
||||
|
||||
/* Return the start position */
|
||||
return Pos;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void LibCopyFrom (unsigned long Pos, unsigned long Bytes, FILE* F)
|
||||
/* Copy data from the library file into another file */
|
||||
{
|
||||
unsigned char Buf [4096];
|
||||
|
||||
/* Seek to the correct position */
|
||||
fseek (Lib, Pos, SEEK_SET);
|
||||
|
||||
/* Copy loop */
|
||||
while (Bytes) {
|
||||
unsigned Count = (Bytes > sizeof (Buf))? sizeof (Buf) : Bytes;
|
||||
ReadData (Lib, Buf, Count);
|
||||
WriteData (F, Buf, Count);
|
||||
Bytes -= Count;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void SkipExpr (unsigned char** Buf)
|
||||
/* Skip an expression in Buf */
|
||||
{
|
||||
/* Get the operation and skip it */
|
||||
unsigned char Op = **Buf;
|
||||
++(*Buf);
|
||||
|
||||
/* Filter leaf nodes */
|
||||
switch (Op) {
|
||||
|
||||
case EXPR_NULL:
|
||||
return;
|
||||
|
||||
case EXPR_LITERAL:
|
||||
/* 32 bit literal value */
|
||||
*Buf += 4;
|
||||
return;
|
||||
|
||||
case EXPR_SYMBOL:
|
||||
/* 16 bit symbol index */
|
||||
*Buf += 2;
|
||||
return;
|
||||
|
||||
case EXPR_SEGMENT:
|
||||
/* 8 bit segment number */
|
||||
*Buf += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* What's left are unary and binary nodes */
|
||||
SkipExpr (Buf); /* Skip left */
|
||||
SkipExpr (Buf); /* Skip right */
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void LibCheckExports (ObjData* O)
|
||||
/* Insert all exports from the given object file into the global list
|
||||
* checking for duplicates.
|
||||
*/
|
||||
{
|
||||
char Name [256];
|
||||
|
||||
/* Get a pointer to the buffer */
|
||||
unsigned char* Exports = O->Exports;
|
||||
|
||||
/* First two bytes are export count */
|
||||
unsigned Lo = *Exports++;
|
||||
unsigned Hi = *Exports++;
|
||||
unsigned Count = (Hi << 8) + Lo;
|
||||
|
||||
/* Read the exports */
|
||||
if (Verbose > 1) {
|
||||
printf ("Module `%s' (%u exports):\n", O->Name, Count);
|
||||
}
|
||||
while (Count--) {
|
||||
|
||||
unsigned char Len;
|
||||
|
||||
/* Get the export tag */
|
||||
unsigned char Tag = *Exports++;
|
||||
|
||||
/* Next thing is name of symbol */
|
||||
Len = *Exports++;
|
||||
memcpy (Name, Exports, Len);
|
||||
Name [Len] = '\0';
|
||||
Exports += Len;
|
||||
|
||||
/* Skip value of symbol */
|
||||
if (Tag & EXP_EXPR) {
|
||||
/* Expression tree */
|
||||
SkipExpr (&Exports);
|
||||
} else {
|
||||
/* Constant 32 bit value */
|
||||
Exports += 4;
|
||||
}
|
||||
|
||||
/* Skip the position */
|
||||
Exports += POS_SIZE;
|
||||
|
||||
/* Insert the name into the hash table */
|
||||
if (Verbose > 1) {
|
||||
printf (" %s\n", Name);
|
||||
}
|
||||
ExpInsert (Name, O->Index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void LibClose (void)
|
||||
/* Write remaining data, close both files and copy the temp file to the old
|
||||
* filename
|
||||
*/
|
||||
{
|
||||
/* Do we have a temporary library? */
|
||||
if (NewLib) {
|
||||
|
||||
unsigned I;
|
||||
unsigned char Buf [4096];
|
||||
size_t Count;
|
||||
|
||||
/* Index the object files and make an array containing the objects */
|
||||
MakeObjPool ();
|
||||
|
||||
/* Walk through the object file list, inserting exports into the
|
||||
* export list checking for duplicates. Copy any data that is still
|
||||
* in the old library into the new one.
|
||||
*/
|
||||
for (I = 0; I < ObjCount; ++I) {
|
||||
|
||||
/* Get a pointer to the object */
|
||||
ObjData* O = ObjPool [I];
|
||||
|
||||
/* Check exports, make global export table */
|
||||
LibCheckExports (O);
|
||||
|
||||
/* Copy data if needed */
|
||||
if ((O->Flags & OBJ_HAVEDATA) == 0) {
|
||||
/* Data is still in the old library */
|
||||
fseek (Lib, O->Start, SEEK_SET);
|
||||
O->Start = ftell (NewLib);
|
||||
LibCopyTo (Lib, O->Size);
|
||||
O->Flags |= OBJ_HAVEDATA;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write the index */
|
||||
WriteIndex ();
|
||||
|
||||
/* Write the updated header */
|
||||
WriteHeader ();
|
||||
|
||||
/* Close the file */
|
||||
if (Lib && fclose (Lib) != 0) {
|
||||
Error ("Error closing library: %s", strerror (errno));
|
||||
}
|
||||
|
||||
/* Reopen the library and truncate it */
|
||||
Lib = fopen (LibName, "wb");
|
||||
if (Lib == 0) {
|
||||
Error ("Cannot open library `%s' for writing: %s",
|
||||
LibName, strerror (errno));
|
||||
}
|
||||
|
||||
/* Copy the new library to the new one */
|
||||
fseek (NewLib, 0, SEEK_SET);
|
||||
while ((Count = fread (Buf, 1, sizeof (Buf), NewLib)) != 0) {
|
||||
if (fwrite (Buf, 1, Count, Lib) != Count) {
|
||||
Error ("Cannot write to `%s': %s", LibName, strerror (errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Close both files */
|
||||
if (Lib && fclose (Lib) != 0) {
|
||||
Error ("Problem closing `%s': %s", LibName, strerror (errno));
|
||||
}
|
||||
if (NewLib && fclose (NewLib) != 0) {
|
||||
Error ("Problem closing temporary library file: %s", strerror (errno));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
88
src/ar65/library.h
Normal file
88
src/ar65/library.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* library.h */
|
||||
/* */
|
||||
/* Library data structures and helpers for the ar65 archiver */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 LIBRARY_H
|
||||
#define LIBRARY_H
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* File descriptor for the new library file */
|
||||
extern FILE* NewLib;
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void LibOpen (const char* Name, int MustExist, int NeedTemp);
|
||||
/* Open an existing library and a temporary copy. If MustExist is true, the
|
||||
* old library is expected to exist. If NeedTemp is true, a temporary library
|
||||
* is created.
|
||||
*/
|
||||
|
||||
unsigned long LibCopyTo (FILE* F, unsigned long Bytes);
|
||||
/* Copy data from F to the temp library file, return the start position in
|
||||
* the temporary library file.
|
||||
*/
|
||||
|
||||
void LibCopyFrom (unsigned long Pos, unsigned long Bytes, FILE* F);
|
||||
/* Copy data from the library file into another file */
|
||||
|
||||
void LibClose (void);
|
||||
/* Write remaining data, close both files and copy the temp file to the old
|
||||
* filename
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* End of library.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
83
src/ar65/list.c
Normal file
83
src/ar65/list.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* list.c */
|
||||
/* */
|
||||
/* Module listing for the ar65 archiver */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 "error.h"
|
||||
#include "objdata.h"
|
||||
#include "library.h"
|
||||
#include "list.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void ListObjFiles (int argc, char* argv [])
|
||||
/* List modules in a library */
|
||||
{
|
||||
ObjData* O;
|
||||
|
||||
/* Check the argument count */
|
||||
if (argc <= 0) {
|
||||
Error ("No library name given");
|
||||
}
|
||||
if (argc > 2) {
|
||||
Error ("Too many arguments");
|
||||
}
|
||||
|
||||
/* Open the library, read the index */
|
||||
LibOpen (argv [0], 1, 0);
|
||||
|
||||
/* List the modules */
|
||||
O = ObjRoot;
|
||||
while (O) {
|
||||
printf ("%s\n", O->Name);
|
||||
O = O->Next;
|
||||
}
|
||||
|
||||
/* Create a new library file and close the old one */
|
||||
LibClose ();
|
||||
|
||||
/* Successful end */
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
58
src/ar65/list.h
Normal file
58
src/ar65/list.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* list.h */
|
||||
/* */
|
||||
/* Module listing for the ar65 archiver */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 LIST_H
|
||||
#define LIST_H
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void ListObjFiles (int argc, char* argv []);
|
||||
/* List modules in a library */
|
||||
|
||||
|
||||
|
||||
/* End of list.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
140
src/ar65/main.c
Normal file
140
src/ar65/main.c
Normal file
@@ -0,0 +1,140 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* main.c */
|
||||
/* */
|
||||
/* Main program for the ar65 archiver */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 <time.h>
|
||||
|
||||
#include "../common/version.h"
|
||||
|
||||
#include "global.h"
|
||||
#include "error.h"
|
||||
#include "mem.h"
|
||||
#include "add.h"
|
||||
#include "del.h"
|
||||
#include "list.h"
|
||||
#include "extract.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static void Usage (void)
|
||||
/* Print usage information and exit */
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Usage: %s <operation> lib file|module ...\n"
|
||||
"Operation is one of:\n"
|
||||
"\ta\tAdd modules\n"
|
||||
"\td\tDelete modules\n"
|
||||
"\tl\tList library contents\n"
|
||||
"\tx\tExtract modules\n"
|
||||
"\tV\tPrint the archiver version\n",
|
||||
ProgName);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main (int argc, char* argv [])
|
||||
/* Assembler main program */
|
||||
{
|
||||
int I;
|
||||
|
||||
/* We must have a file name */
|
||||
if (argc < 2) {
|
||||
Usage ();
|
||||
}
|
||||
|
||||
/* Check the parameters */
|
||||
I = 1;
|
||||
while (I < argc) {
|
||||
|
||||
/* Get the argument */
|
||||
const char* Arg = argv [I];
|
||||
|
||||
/* Check for an option */
|
||||
if (strlen (Arg) != 1) {
|
||||
Usage ();
|
||||
}
|
||||
switch (Arg [0]) {
|
||||
|
||||
case 'a':
|
||||
AddObjFiles (argc - I - 1, &argv [I+1]);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
DelObjFiles (argc - I - 1, &argv [I+1]);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
ListObjFiles (argc - I - 1, &argv [I+1]);
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
++Verbose;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
ExtractObjFiles (argc - I - 1, &argv [I+1]);
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
fprintf (stderr,
|
||||
"ar65 V%u.%u.%u - (C) Copyright 1998-1999 Ullrich von Bassewitz\n",
|
||||
VER_MAJOR, VER_MINOR, VER_PATCH);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf (stderr, "Unknown option: %s\n", Arg);
|
||||
Usage ();
|
||||
|
||||
}
|
||||
|
||||
/* Next argument */
|
||||
++I;
|
||||
}
|
||||
|
||||
/* Return an apropriate exit code */
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
56
src/ar65/make/gcc.mak
Normal file
56
src/ar65/make/gcc.mak
Normal file
@@ -0,0 +1,56 @@
|
||||
#
|
||||
# gcc Makefile for ar65
|
||||
#
|
||||
|
||||
CFLAGS = -g -O2 -Wall
|
||||
CC = gcc
|
||||
LDFLAGS =
|
||||
|
||||
OBJS = add.o \
|
||||
del.o \
|
||||
error.o \
|
||||
exports.o \
|
||||
extract.o \
|
||||
fileio.o \
|
||||
global.o \
|
||||
library.o \
|
||||
list.o \
|
||||
main.o \
|
||||
mem.o \
|
||||
objdata.o \
|
||||
objfile.o
|
||||
|
||||
LIBS = ../common/common.a
|
||||
|
||||
|
||||
EXECS = ar65
|
||||
|
||||
.PHONY: all
|
||||
ifeq (.depend,$(wildcard .depend))
|
||||
all : $(EXECS)
|
||||
include .depend
|
||||
else
|
||||
all: depend
|
||||
@$(MAKE) -f make/gcc.mak all
|
||||
endif
|
||||
|
||||
|
||||
|
||||
ar65: $(OBJS) $(LIBS)
|
||||
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS)
|
||||
|
||||
clean:
|
||||
rm -f *~ core
|
||||
|
||||
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
|
||||
|
||||
|
||||
123
src/ar65/make/watcom.mak
Normal file
123
src/ar65/make/watcom.mak
Normal file
@@ -0,0 +1,123 @@
|
||||
#
|
||||
# ar65 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 = add.obj \
|
||||
del.obj \
|
||||
error.obj \
|
||||
exports.obj \
|
||||
extract.obj \
|
||||
fileio.obj \
|
||||
global.obj \
|
||||
library.obj \
|
||||
list.obj \
|
||||
main.obj \
|
||||
mem.obj \
|
||||
objdata.obj \
|
||||
objfile.obj
|
||||
|
||||
LIBS = ..\common\common.lib
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Main targets
|
||||
|
||||
all: ar65
|
||||
|
||||
ar65: ar65.exe
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Other targets
|
||||
|
||||
|
||||
ar65.exe: $(OBJS) $(LIBS)
|
||||
$(LD) system $(SYSTEM) @&&|
|
||||
DEBUG ALL
|
||||
OPTION QUIET
|
||||
NAME $<
|
||||
FILE add.obj
|
||||
FILE del.obj
|
||||
FILE error.obj
|
||||
FILE exports.obj
|
||||
FILE extract.obj
|
||||
FILE fileio.obj
|
||||
FILE global.obj
|
||||
FILE library.obj
|
||||
FILE list.obj
|
||||
FILE main.obj
|
||||
FILE mem.obj
|
||||
FILE objdata.obj
|
||||
FILE objfile.obj
|
||||
LIBRARY ..\common\common.lib
|
||||
|
|
||||
|
||||
|
||||
clean:
|
||||
@if exist *.obj del *.obj
|
||||
@if exist ar65.exe del ar65.exe
|
||||
|
||||
strip:
|
||||
@-wstrip ar65.exe
|
||||
|
||||
84
src/ar65/mem.c
Normal file
84
src/ar65/mem.c
Normal file
@@ -0,0 +1,84 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* mem.c */
|
||||
/* */
|
||||
/* Memory allocation for the ar65 archiver */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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) {
|
||||
Error ("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/ar65/mem.h
Normal file
67
src/ar65/mem.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* mem.h */
|
||||
/* */
|
||||
/* Memory allocation for the ar65 archiver */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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
|
||||
|
||||
|
||||
|
||||
207
src/ar65/objdata.c
Normal file
207
src/ar65/objdata.c
Normal file
@@ -0,0 +1,207 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* objdata.c */
|
||||
/* */
|
||||
/* Handling object file data for the ar65 archiver */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 "error.h"
|
||||
#include "objdata.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Object data list management */
|
||||
unsigned ObjCount = 0; /* Count of object files in the list */
|
||||
ObjData* ObjRoot = 0; /* List of object files */
|
||||
ObjData* ObjLast = 0; /* Last entry in list */
|
||||
ObjData** ObjPool = 0; /* Object files as array */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
ObjData* NewObjData (void)
|
||||
/* Allocate a new structure on the heap, insert it into the list, return it */
|
||||
{
|
||||
/* Allocate memory */
|
||||
ObjData* O = Xmalloc (sizeof (ObjData));
|
||||
|
||||
/* Initialize the data */
|
||||
O->Next = 0;
|
||||
O->Name = 0;
|
||||
O->Index = ~0;
|
||||
O->Flags = 0;
|
||||
O->MTime = 0;
|
||||
O->Start = 0;
|
||||
O->Size = 0;
|
||||
O->ImportSize = 0;
|
||||
O->Imports = 0;
|
||||
O->ExportSize = 0;
|
||||
O->Exports = 0;
|
||||
|
||||
/* Link it into the list */
|
||||
if (ObjLast) {
|
||||
ObjLast->Next = O;
|
||||
ObjLast = O;
|
||||
} else {
|
||||
/* First entry */
|
||||
ObjRoot = ObjLast = O;
|
||||
}
|
||||
|
||||
/* One object file more now */
|
||||
++ObjCount;
|
||||
|
||||
/* Return the new entry */
|
||||
return O;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void FreeObjData (ObjData* O)
|
||||
/* Free a complete struct */
|
||||
{
|
||||
Xfree (O->Name);
|
||||
Xfree (O->Imports);
|
||||
Xfree (O->Exports);
|
||||
Xfree (O);
|
||||
}
|
||||
|
||||
|
||||
|
||||
ObjData* FindObjData (const char* Module)
|
||||
/* Search for the module with the given name and return it. Return NULL if the
|
||||
* module is not in the list.
|
||||
*/
|
||||
{
|
||||
/* Hmm. Maybe we should hash the module names? */
|
||||
ObjData* O = ObjRoot;
|
||||
while (O) {
|
||||
if (strcmp (O->Name, Module) == 0) {
|
||||
return O;
|
||||
}
|
||||
O = O->Next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DelObjData (const char* Module)
|
||||
/* Delete the object module from the list */
|
||||
{
|
||||
ObjData* O = ObjRoot;
|
||||
ObjData* Last = 0;
|
||||
while (O) {
|
||||
if (strcmp (O->Name, Module) == 0) {
|
||||
/* Found the module, remove it from the list */
|
||||
if (Last == 0) {
|
||||
/* This was the first entry in the list */
|
||||
ObjRoot = O->Next;
|
||||
} else {
|
||||
Last->Next = O->Next;
|
||||
}
|
||||
if (ObjLast == O) {
|
||||
/* O was the last object in the list */
|
||||
ObjLast = Last;
|
||||
}
|
||||
--ObjCount;
|
||||
|
||||
/* Free the entry */
|
||||
FreeObjData (O);
|
||||
|
||||
/* Done */
|
||||
return;
|
||||
}
|
||||
Last = O;
|
||||
O = O->Next;
|
||||
}
|
||||
|
||||
/* Not found! */
|
||||
Warning ("Module `%s' not found in library", Module);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MakeObjPool (void)
|
||||
/* Allocate memory, index the entries and make the ObjPool valid */
|
||||
{
|
||||
ObjData* O;
|
||||
unsigned Index;
|
||||
|
||||
/* Allocate memory for the pool */
|
||||
ObjPool = Xmalloc (ObjCount * sizeof (ObjData*));
|
||||
|
||||
/* Setup the pointers and index the objects */
|
||||
Index = 0;
|
||||
O = ObjRoot;
|
||||
while (O) {
|
||||
|
||||
/* Safety */
|
||||
CHECK (Index < ObjCount);
|
||||
|
||||
/* Set the Index */
|
||||
O->Index = Index;
|
||||
|
||||
/* Set the pool pointer */
|
||||
ObjPool [Index] = O;
|
||||
|
||||
/* Next object */
|
||||
++Index;
|
||||
O = O->Next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char* GetObjName (unsigned Index)
|
||||
/* Get the name of a module by index */
|
||||
{
|
||||
PRECONDITION (ObjPool != 0 && Index < ObjCount && ObjPool [Index] != 0);
|
||||
return ObjPool [Index]->Name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
111
src/ar65/objdata.h
Normal file
111
src/ar65/objdata.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* objdata.h */
|
||||
/* */
|
||||
/* Handling object file data for the ar65 archiver */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 OBJDATA_H
|
||||
#define OBJDATA_H
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Values for the Flags field */
|
||||
#define OBJ_HAVEDATA 0x0001 /* The object data is in the tmp file */
|
||||
#define OBJ_MARKED 0x0002 /* Generic marker bit */
|
||||
|
||||
|
||||
/* Internal structure holding object file data */
|
||||
typedef struct ObjData_ ObjData;
|
||||
struct ObjData_ {
|
||||
ObjData* Next; /* Linked list of all objects */
|
||||
char* Name; /* Module name */
|
||||
unsigned Index; /* Module index */
|
||||
unsigned Flags;
|
||||
unsigned long MTime; /* Modifiation time of object file */
|
||||
unsigned long Start; /* Start offset of data in library */
|
||||
unsigned long Size; /* Size of data in library */
|
||||
unsigned long ImportSize; /* Size of imports */
|
||||
void* Imports; /* Imports as raw data */
|
||||
unsigned long ExportSize; /* Size of exports */
|
||||
void* Exports; /* Exports as raw data */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Object data list management */
|
||||
extern unsigned ObjCount; /* Count of files in the list */
|
||||
extern ObjData* ObjRoot; /* List of object files */
|
||||
extern ObjData* ObjLast; /* Last entry in list */
|
||||
extern ObjData** ObjPool; /* Object files as array */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
ObjData* NewObjData (void);
|
||||
/* Allocate a new structure on the heap, insert it into the list, return it */
|
||||
|
||||
void FreeObjData (ObjData* O);
|
||||
/* Free a complete struct */
|
||||
|
||||
ObjData* FindObjData (const char* Module);
|
||||
/* Search for the module with the given name and return it. Return NULL if the
|
||||
* module is not in the list.
|
||||
*/
|
||||
|
||||
void DelObjData (const char* Module);
|
||||
/* Delete the object module from the list */
|
||||
|
||||
void MakeObjPool (void);
|
||||
/* Allocate memory, index the entries and make the ObjPool valid */
|
||||
|
||||
const char* GetObjName (unsigned Index);
|
||||
/* Get the name of a module by index */
|
||||
|
||||
|
||||
|
||||
/* End of objdata.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
288
src/ar65/objfile.c
Normal file
288
src/ar65/objfile.c
Normal file
@@ -0,0 +1,288 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* objfile.c */
|
||||
/* */
|
||||
/* Object file handling for the ar65 archiver */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 <errno.h>
|
||||
#ifdef __WATCOMC__
|
||||
/* Watcom has the file in the wrong directory */
|
||||
# include <sys/utime.h>
|
||||
#else
|
||||
# include <sys/types.h> /* FreeBSD needs this */
|
||||
# include <utime.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "error.h"
|
||||
#include "mem.h"
|
||||
#include "objdata.h"
|
||||
#include "fileio.h"
|
||||
#include "library.h"
|
||||
#include "objfile.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static const char* GetModule (const char* Name)
|
||||
/* Get a module name from the file name */
|
||||
{
|
||||
/* Make a module name from the file name */
|
||||
const char* Module = Name + strlen (Name);
|
||||
while (Module > Name) {
|
||||
--Module;
|
||||
if (*Module == '/' || *Module == '\\') {
|
||||
++Module;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*Module == 0) {
|
||||
Error ("Cannot make module name from `%s'", Name);
|
||||
}
|
||||
return Module;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ObjReadHeader (FILE* Obj, ObjHeader* H, const char* Name)
|
||||
/* Read the header of the object file checking the signature */
|
||||
{
|
||||
H->Magic = Read32 (Obj);
|
||||
if (H->Magic != OBJ_MAGIC) {
|
||||
Error ("`%s' is not an object file", Name);
|
||||
}
|
||||
H->Version = Read16 (Obj);
|
||||
if (H->Version != OBJ_VERSION) {
|
||||
Error ("Object file `%s' has wrong version", Name);
|
||||
}
|
||||
H->Flags = Read16 (Obj);
|
||||
H->OptionOffs = Read32 (Obj);
|
||||
H->OptionSize = Read32 (Obj);
|
||||
H->FileOffs = Read32 (Obj);
|
||||
H->FileSize = Read32 (Obj);
|
||||
H->SegOffs = Read32 (Obj);
|
||||
H->SegSize = Read32 (Obj);
|
||||
H->ImportOffs = Read32 (Obj);
|
||||
H->ImportSize = Read32 (Obj);
|
||||
H->ExportOffs = Read32 (Obj);
|
||||
H->ExportSize = Read32 (Obj);
|
||||
H->DbgSymOffs = Read32 (Obj);
|
||||
H->DbgSymSize = Read32 (Obj);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ObjWriteHeader (FILE* Obj, ObjHeader* H)
|
||||
/* Write the header of the object file */
|
||||
{
|
||||
Write32 (Obj, H->Magic);
|
||||
Write16 (Obj, H->Version);
|
||||
Write16 (Obj, H->Flags);
|
||||
Write32 (Obj, H->OptionOffs);
|
||||
Write32 (Obj, H->OptionSize);
|
||||
Write32 (Obj, H->FileOffs);
|
||||
Write32 (Obj, H->FileSize);
|
||||
Write32 (Obj, H->SegOffs);
|
||||
Write32 (Obj, H->SegSize);
|
||||
Write32 (Obj, H->ImportOffs);
|
||||
Write32 (Obj, H->ImportSize);
|
||||
Write32 (Obj, H->ExportOffs);
|
||||
Write32 (Obj, H->ExportSize);
|
||||
Write32 (Obj, H->DbgSymOffs);
|
||||
Write32 (Obj, H->DbgSymSize);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ObjAdd (const char* Name)
|
||||
/* Add an object file to the library */
|
||||
{
|
||||
struct stat StatBuf;
|
||||
const char* Module;
|
||||
ObjHeader H;
|
||||
ObjData* O;
|
||||
|
||||
/* Open the object file */
|
||||
FILE* Obj = fopen (Name, "rb");
|
||||
if (Obj == 0) {
|
||||
Error ("Could not open `%s': %s", Name, strerror (errno));
|
||||
}
|
||||
|
||||
/* Get the modification time of the object file */
|
||||
if (fstat (fileno (Obj), &StatBuf) != 0) {
|
||||
Error ("Cannot stat object file `%s': %s", Name, strerror (errno));
|
||||
}
|
||||
|
||||
/* Read and check the header */
|
||||
ObjReadHeader (Obj, &H, Name);
|
||||
|
||||
/* Make a module name from the file name */
|
||||
Module = GetModule (Name);
|
||||
|
||||
/* Check if we already have a module with this name */
|
||||
O = FindObjData (Module);
|
||||
if (O == 0) {
|
||||
/* Not found, create a new entry */
|
||||
O = NewObjData ();
|
||||
} else {
|
||||
/* Found - check the file modification times of the internal copy
|
||||
* and the external one.
|
||||
*/
|
||||
if (difftime ((time_t)O->MTime, StatBuf.st_mtime) > 0.0) {
|
||||
Warning ("Replacing module `%s' by older version", O->Name);
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize the object module data structure */
|
||||
O->Name = StrDup (Module);
|
||||
O->Flags = OBJ_HAVEDATA;
|
||||
O->MTime = StatBuf.st_mtime;
|
||||
O->ImportSize = H.ImportSize;
|
||||
O->Imports = Xmalloc (O->ImportSize);
|
||||
O->ExportSize = H.ExportSize;
|
||||
O->Exports = Xmalloc (O->ExportSize);
|
||||
|
||||
/* Read imports and exports */
|
||||
fseek (Obj, H.ImportOffs, SEEK_SET);
|
||||
ReadData (Obj, O->Imports, O->ImportSize);
|
||||
fseek (Obj, H.ExportOffs, SEEK_SET);
|
||||
ReadData (Obj, O->Exports, O->ExportSize);
|
||||
|
||||
/* Skip the object file header */
|
||||
O->Start = ftell (NewLib);
|
||||
fseek (NewLib, OBJ_HDR_SIZE, SEEK_CUR);
|
||||
|
||||
/* Copy the remaining sections */
|
||||
fseek (Obj, H.DbgSymOffs, SEEK_SET);
|
||||
H.DbgSymOffs = LibCopyTo (Obj, H.DbgSymSize) - O->Start;
|
||||
fseek (Obj, H.OptionOffs, SEEK_SET);
|
||||
H.OptionOffs = LibCopyTo (Obj, H.OptionSize) - O->Start;
|
||||
fseek (Obj, H.SegOffs, SEEK_SET);
|
||||
H.SegOffs = LibCopyTo (Obj, H.SegSize) - O->Start;
|
||||
fseek (Obj, H.FileOffs, SEEK_SET);
|
||||
H.FileOffs = LibCopyTo (Obj, H.FileSize) - O->Start;
|
||||
|
||||
/* Calculate the amount of data written */
|
||||
O->Size = ftell (NewLib) - O->Start;
|
||||
|
||||
/* Clear the remaining header fields */
|
||||
H.ImportOffs = H.ImportSize = 0;
|
||||
H.ExportOffs = H.ExportSize = 0;
|
||||
|
||||
/* Seek back and write the updated header */
|
||||
fseek (NewLib, O->Start, SEEK_SET);
|
||||
ObjWriteHeader (NewLib, &H);
|
||||
|
||||
/* Now seek again to end of file */
|
||||
fseek (NewLib, 0, SEEK_END);
|
||||
|
||||
/* Done, close the file (we read it only, so no error check) */
|
||||
fclose (Obj);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ObjExtract (const char* Name)
|
||||
/* Extract a module from the library */
|
||||
{
|
||||
unsigned long ImportStart;
|
||||
unsigned long ExportStart;
|
||||
struct utimbuf U;
|
||||
ObjHeader H;
|
||||
FILE* Obj;
|
||||
|
||||
|
||||
/* Make a module name from the file name */
|
||||
const char* Module = GetModule (Name);
|
||||
|
||||
/* Try to find the module in the library */
|
||||
ObjData* O = FindObjData (Module);
|
||||
|
||||
/* Bail out if the module does not exist */
|
||||
if (O == 0) {
|
||||
Error ("Module `%s' not found in library", Module);
|
||||
}
|
||||
|
||||
/* Open the output file */
|
||||
Obj = fopen (Name, "w+b");
|
||||
if (Obj == 0) {
|
||||
Error ("Cannot open target file `%s': %s", Name, strerror (errno));
|
||||
}
|
||||
|
||||
/* Copy the first four segments including the header to the new file */
|
||||
LibCopyFrom (O->Start, O->Size, Obj);
|
||||
|
||||
/* Write imports and exports */
|
||||
ImportStart = ftell (Obj);
|
||||
WriteData (Obj, O->Imports, O->ImportSize);
|
||||
ExportStart = ftell (Obj);
|
||||
WriteData (Obj, O->Exports, O->ExportSize);
|
||||
|
||||
/* Seek back and read the header */
|
||||
fseek (Obj, 0, SEEK_SET);
|
||||
ObjReadHeader (Obj, &H, Name);
|
||||
|
||||
/* Update the header fields */
|
||||
H.ImportOffs = ImportStart;
|
||||
H.ImportSize = O->ImportSize;
|
||||
H.ExportOffs = ExportStart;
|
||||
H.ExportSize = O->ExportSize;
|
||||
|
||||
/* Write the changed header */
|
||||
fseek (Obj, 0, SEEK_SET);
|
||||
ObjWriteHeader (Obj, &H);
|
||||
|
||||
/* Close the file */
|
||||
if (fclose (Obj) != 0) {
|
||||
Error ("Problem closing object file `%s': %s", Name, strerror (errno));
|
||||
}
|
||||
|
||||
/* Set access and modification time */
|
||||
U.actime = O->MTime;
|
||||
U.modtime = O->MTime;
|
||||
if (utime (Name, &U) != 0) {
|
||||
Error ("Cannot set mod time on `%s': %s", Name, strerror (errno));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
72
src/ar65/objfile.h
Normal file
72
src/ar65/objfile.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* objfile.h */
|
||||
/* */
|
||||
/* Object file handling for the ar65 archiver */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 <stdio.h>
|
||||
|
||||
#include "../common/objdefs.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void ObjReadHeader (FILE* Obj, ObjHeader* H, const char* Name);
|
||||
/* Read the header of the object file checking the signature */
|
||||
|
||||
void ObjWriteHeader (FILE* Obj, ObjHeader* H);
|
||||
/* Write the header of the object file */
|
||||
|
||||
void ObjAdd (const char* Name);
|
||||
/* Add an object file to the library */
|
||||
|
||||
void ObjExtract (const char* Name);
|
||||
/* Extract a module from the library */
|
||||
|
||||
|
||||
|
||||
/* End of objfile.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
||||
29
src/cc65/.cvsignore
Normal file
29
src/cc65/.cvsignore
Normal file
@@ -0,0 +1,29 @@
|
||||
.depend
|
||||
.kdbgrc.cc65
|
||||
cc65
|
||||
*.com
|
||||
*.map
|
||||
xopt
|
||||
predent
|
||||
postdent
|
||||
code-gen.m65
|
||||
glb.m65
|
||||
cc64
|
||||
error.m65
|
||||
expr1.m65
|
||||
expr2.m65
|
||||
save
|
||||
expr3.m65
|
||||
function.m65
|
||||
globlvar.m65
|
||||
io.m65
|
||||
lexer.m65
|
||||
main.m65
|
||||
optab1.m65
|
||||
optab2.m65
|
||||
optimize.m65
|
||||
preproc.m65
|
||||
rwords.m65
|
||||
stmt1.m65
|
||||
stmt2.m65
|
||||
symtab.m65
|
||||
59
src/cc65/anonname.c
Normal file
59
src/cc65/anonname.c
Normal file
@@ -0,0 +1,59 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* anonname.c */
|
||||
/* */
|
||||
/* Create names for anonymous variables/types */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 "anonname.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
char* AnonName (char* Buf, const char* Spec)
|
||||
/* Get a name for an anonymous variable or type. The given buffer is expected
|
||||
* to be IDENTSIZE characters long. A pointer to the buffer is returned.
|
||||
*/
|
||||
{
|
||||
static unsigned ACount = 0;
|
||||
sprintf (Buf, "$anon-%s-%04X", Spec, ++ACount);
|
||||
return Buf;
|
||||
}
|
||||
|
||||
|
||||
|
||||
58
src/cc65/anonname.h
Normal file
58
src/cc65/anonname.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* anonname.h */
|
||||
/* */
|
||||
/* Create names for anonymous variables/types */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 ANONNAME_H
|
||||
#define ANONNAME_H
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
char* AnonName (char* Buf, const char* Spec);
|
||||
/* Get a name for an anonymous variable or type. The given buffer is expected
|
||||
* to be IDENTSIZE characters long. A pointer to the buffer is returned.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* End of anonname.h */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
115
src/cc65/asmcode.c
Normal file
115
src/cc65/asmcode.c
Normal file
@@ -0,0 +1,115 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* asmcode.c */
|
||||
/* */
|
||||
/* Assembler output code handling for the cc65 C compiler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 "asmline.h"
|
||||
#include "check.h"
|
||||
#include "global.h"
|
||||
#include "asmcode.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void AddCodeLine (const char* Format, ...)
|
||||
/* Add a new line of code to the output */
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, Format);
|
||||
NewCodeLine (Format, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AddCodeHint (const char* Hint)
|
||||
/* Add an optimizer hint */
|
||||
{
|
||||
AddCodeLine ("+%s", Hint);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AddEmptyLine (void)
|
||||
/* Add an empty line for formatting purposes */
|
||||
{
|
||||
AddCodeLine ("");
|
||||
}
|
||||
|
||||
|
||||
|
||||
CodeMark GetCodePos (void)
|
||||
/* Get a marker pointing to the current output position */
|
||||
{
|
||||
/* This function should never be called without any code output */
|
||||
CHECK (LastLine != 0);
|
||||
|
||||
return LastLine;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RemoveCode (CodeMark M)
|
||||
/* Remove all code after the given code marker */
|
||||
{
|
||||
while (LastLine != M) {
|
||||
FreeCodeLine (LastLine);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void WriteOutput (FILE* F)
|
||||
/* Write the final output to a file */
|
||||
{
|
||||
Line* L = FirstLine;
|
||||
while (L) {
|
||||
/* Don't write optimizer hints if not requested to do so */
|
||||
if (L->Line[0] == '+') {
|
||||
if (Debug) {
|
||||
fprintf (F, ";%s\n", L->Line);
|
||||
}
|
||||
} else {
|
||||
fprintf (F, "%s\n", L->Line);
|
||||
}
|
||||
L = L->Next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
86
src/cc65/asmcode.h
Normal file
86
src/cc65/asmcode.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* asmcode.h */
|
||||
/* */
|
||||
/* Assembler output code handling for the cc65 C compiler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 ASMCODE_H
|
||||
#define ASMCODE_H
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Marker for an assembler code position */
|
||||
typedef struct Line_* CodeMark;
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void AddCodeLine (const char* Format, ...);
|
||||
/* Add a new line of code to the output */
|
||||
|
||||
void AddCodeHint (const char* Hint);
|
||||
/* Add an optimizer hint */
|
||||
|
||||
void AddEmptyLine (void);
|
||||
/* Add an empty line for formatting purposes */
|
||||
|
||||
CodeMark GetCodePos (void);
|
||||
/* Get a marker pointing to the current output position */
|
||||
|
||||
void RemoveCode (CodeMark M);
|
||||
/* Remove all code after the given code marker */
|
||||
|
||||
void WriteOutput (FILE* F);
|
||||
/* Write the final output to a file */
|
||||
|
||||
|
||||
|
||||
/* End of asmcode.h */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
55
src/cc65/asmlabel.c
Normal file
55
src/cc65/asmlabel.c
Normal file
@@ -0,0 +1,55 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* asmlabel.c */
|
||||
/* */
|
||||
/* Generate assembler code labels */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 "asmlabel.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
unsigned GetLabel (void)
|
||||
/* Get an unused label. Will never return zero. */
|
||||
{
|
||||
/* Number to generate unique labels */
|
||||
static unsigned NextLabel = 0;
|
||||
return ++NextLabel;
|
||||
}
|
||||
|
||||
|
||||
|
||||
56
src/cc65/asmlabel.h
Normal file
56
src/cc65/asmlabel.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* asmlabel.h */
|
||||
/* */
|
||||
/* Generate assembler code labels */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 ASMLABEL_H
|
||||
#define ASMLABEL_H
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
unsigned GetLabel (void);
|
||||
/* Get an unused assembler label. Will never return zero. */
|
||||
|
||||
|
||||
|
||||
/* End of asmlabel.h */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
184
src/cc65/asmline.c
Normal file
184
src/cc65/asmline.c
Normal file
@@ -0,0 +1,184 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* asmline.h */
|
||||
/* */
|
||||
/* Internal assembler line structure */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 "mem.h"
|
||||
#include "asmline.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Number used to index lines */
|
||||
static unsigned long LineIndex = 0;
|
||||
|
||||
/* The line list */
|
||||
Line* FirstLine = 0; /* Pointer to first line */
|
||||
Line* LastLine = 0; /* Pointer to last line */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static Line* NewLine (const char* Format, va_list ap)
|
||||
/* Interal routine to create a new line from the given text */
|
||||
{
|
||||
char Buf [8192];
|
||||
int OVF;
|
||||
unsigned Len;
|
||||
Line* L;
|
||||
|
||||
|
||||
/* Make a string from the given format and arguments */
|
||||
#if defined(__WATCOMC__)
|
||||
OVF = (_vbprintf (Buf, sizeof (Buf), Format, ap) >= sizeof (S));
|
||||
#else
|
||||
/* Assume gcc running on a Unix OS */
|
||||
OVF = (vsnprintf (Buf, sizeof (Buf), Format, ap) < 0);
|
||||
#endif
|
||||
if (OVF) {
|
||||
Internal ("String size overflow");
|
||||
}
|
||||
|
||||
/* Get the length of the line */
|
||||
Len = strlen (Buf);
|
||||
|
||||
/* Allocate memory */
|
||||
L = xmalloc (sizeof (Line) + Len);
|
||||
|
||||
/* Partially initialize the struct (the remaining fields are initialized
|
||||
* by the caller).
|
||||
*/
|
||||
L->Flags = 0;
|
||||
L->Size = 0;
|
||||
L->Len = Len;
|
||||
memcpy (L->Line, Buf, Len+1);
|
||||
|
||||
/* Return the new line */
|
||||
return L;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Line* NewCodeLine (const char* Format, va_list ap)
|
||||
/* Create a new code line and return it */
|
||||
{
|
||||
/* Create a new line struct */
|
||||
Line* L = NewLine (Format, ap);
|
||||
|
||||
/* Initialize struct fields */
|
||||
L->Index = LineIndex++;
|
||||
|
||||
/* Insert the line into the list */
|
||||
if (FirstLine == 0) {
|
||||
/* The list is empty */
|
||||
L->Next = L->Prev = 0;
|
||||
FirstLine = LastLine = L;
|
||||
} else {
|
||||
/* There are entries in the list, add the new one at the end */
|
||||
LastLine->Next = L;
|
||||
L->Prev = LastLine;
|
||||
L->Next = 0;
|
||||
LastLine = L;
|
||||
}
|
||||
|
||||
/* Return the new line */
|
||||
return L;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Line* NewCodeLineAfter (Line* LineBefore, const char* Format, va_list ap)
|
||||
/* Create a new line, insert it after L and return it. */
|
||||
{
|
||||
/* Create a new line struct */
|
||||
Line* L = NewLine (Format, ap);
|
||||
|
||||
/* Initialize struct fields. We use the same index for the inserted line
|
||||
* as for its predecessor, since we cannot create new numbers on the
|
||||
* fly and the index is only used to determine sort order.
|
||||
*/
|
||||
L->Index = LineBefore->Index;
|
||||
|
||||
/* Insert the line after its predecessor */
|
||||
L->Next = LineBefore->Next;
|
||||
LineBefore->Next = L;
|
||||
L->Prev = LineBefore;
|
||||
if (L->Next) {
|
||||
L->Next->Prev = L;
|
||||
} else {
|
||||
/* This is the last line */
|
||||
LastLine = L;
|
||||
}
|
||||
|
||||
/* Return the new line */
|
||||
return L;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void FreeCodeLine (Line* L)
|
||||
/* Remove a line from the list and free it */
|
||||
{
|
||||
/* Unlink the line */
|
||||
if (L->Prev == 0) {
|
||||
/* No line before this one */
|
||||
FirstLine = L->Next;
|
||||
} else {
|
||||
L->Prev->Next = L->Next;
|
||||
}
|
||||
if (L->Next == 0) {
|
||||
/* No line after this one */
|
||||
LastLine = L->Prev;
|
||||
} else {
|
||||
L->Next->Prev = L->Prev;
|
||||
}
|
||||
|
||||
/* Free the struct */
|
||||
xfree (L);
|
||||
}
|
||||
|
||||
|
||||
|
||||
90
src/cc65/asmline.h
Normal file
90
src/cc65/asmline.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* asmline.h */
|
||||
/* */
|
||||
/* Internal assembler line structure */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 ASMLINE_H
|
||||
#define ASMLINE_H
|
||||
|
||||
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Structure that contains one line */
|
||||
typedef struct Line_ Line;
|
||||
struct Line_ {
|
||||
Line* Next; /* Next line on double linked list */
|
||||
Line* Prev; /* Revious line in list */
|
||||
unsigned Flags; /* Flags for this line */
|
||||
unsigned long Index; /* Index of this line */
|
||||
unsigned Size; /* Size of this code */
|
||||
unsigned Len; /* Length of the line */
|
||||
char Line [1]; /* The line itself */
|
||||
};
|
||||
|
||||
/* The line list */
|
||||
extern Line* FirstLine; /* Pointer to first line */
|
||||
extern Line* LastLine; /* Pointer to last line */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
Line* NewCodeLine (const char* Format, va_list ap);
|
||||
/* Create a new code line and return it */
|
||||
|
||||
Line* NewCodeLineAfter (Line* LineBefore, const char* Format, va_list ap);
|
||||
/* Create a new line, insert it after L and return it. */
|
||||
|
||||
void FreeCodeLine (Line* L);
|
||||
/* Remove a line from the list and free it */
|
||||
|
||||
|
||||
|
||||
/* End of asmline.h */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
102
src/cc65/check.c
Normal file
102
src/cc65/check.c
Normal file
@@ -0,0 +1,102 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* check.c */
|
||||
/* */
|
||||
/* Assert macros for the cc65 C compiler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 "error.h"
|
||||
#include "check.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Predefined messages */
|
||||
const char* _MsgInternalError = "Internal error: ";
|
||||
const char* _MsgAbstractCall = "Call to abstract method";
|
||||
const char* _MsgPrecondition = "Precondition violated: ";
|
||||
const char* _MsgCheckFailed = "Check failed: ";
|
||||
const char* _MsgProgramAborted = "Program aborted: ";
|
||||
|
||||
|
||||
|
||||
static void _CheckFailed (const char* msg, const char* cond,
|
||||
int code, const char* file, unsigned line);
|
||||
|
||||
void (*CheckFailed) (const char* Msg, const char* Cond, int Code,
|
||||
const char* File, unsigned Line) = _CheckFailed;
|
||||
/* Function pointer that is called from check if the condition code is true. */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static void _CheckFailed (const char* Msg, const char* Cond,
|
||||
int Code, const char* File, unsigned Line)
|
||||
{
|
||||
/* Log the error */
|
||||
if (Code) {
|
||||
Internal ("%s%s (= %d), file `%s', line %u", Msg, Cond, Code, File, Line);
|
||||
} else {
|
||||
Internal ("%s%s, file `%s', line %u", Msg, Cond, File, Line);
|
||||
}
|
||||
|
||||
/* Use abort() to create a core for debugging */
|
||||
abort ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Check (const char* Msg, const char* Cond, int Code,
|
||||
const char* File, unsigned Line)
|
||||
/* This function is called from all check macros (see below). It checks,
|
||||
* wether the given Code is true (!= 0). If so, it calls the CheckFailed
|
||||
* vector with the given strings. If not, it simply returns.
|
||||
*/
|
||||
{
|
||||
if (Code != 0) {
|
||||
CheckFailed (Msg, Cond, Code, File, Line);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
96
src/cc65/check.h
Normal file
96
src/cc65/check.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* check.h */
|
||||
/* */
|
||||
/* Assert macros for the cc65 C compiler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 CHECK_H
|
||||
#define CHECK_H
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
extern const char* _MsgInternalError; /* "Internal error: " */
|
||||
extern const char* _MsgPrecondition; /* "Precondition violated: " */
|
||||
extern const char* _MsgCheckFailed; /* "Check failed: " */
|
||||
extern const char* _MsgProgramAborted; /* "Program aborted: " */
|
||||
|
||||
|
||||
|
||||
extern void (*CheckFailed) (const char* Msg, const char* Cond,
|
||||
int Code, const char* File, unsigned Line);
|
||||
/* Function pointer that is called from check if the condition code is true. */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void Check (const char* Msg, const char* Cond, int Code,
|
||||
const char* File, unsigned Line);
|
||||
/* This function is called from all check macros (see below). It checks,
|
||||
* wether the given Code is true (!= 0). If so, it calls the CheckFailed
|
||||
* vector with the given strings. If not, it simply returns.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#define FAIL(s) CheckFailed (_MsgInternalError, s, 0, __FILE__, __LINE__)
|
||||
/* Fail macro. Is used if something evil happens, calls checkfailed directly. */
|
||||
|
||||
#define ABORT(s) CheckFailed (_MsgProgramAborted, s, 0, __FILE__, __LINE__)
|
||||
/* Use this one instead of FAIL if there is no internal program error but an
|
||||
* error condition that is caused by the user or operating system (FAIL and
|
||||
* ABORT are essentially the same but the message differs).
|
||||
*/
|
||||
|
||||
#define PRECONDITION(c) Check (_MsgPrecondition, #c, !(c), __FILE__, __LINE__)
|
||||
|
||||
#define CHECK(c) Check (_MsgCheckFailed, #c, !(c), __FILE__, __LINE__)
|
||||
|
||||
#define ZCHECK(c) Check (_MsgCheckFailed, #c, c, __FILE__, __LINE__)
|
||||
|
||||
|
||||
|
||||
/* End of check.h */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
3712
src/cc65/codegen.c
Normal file
3712
src/cc65/codegen.c
Normal file
File diff suppressed because it is too large
Load Diff
395
src/cc65/codegen.h
Normal file
395
src/cc65/codegen.h
Normal file
@@ -0,0 +1,395 @@
|
||||
/*
|
||||
* codegen.h
|
||||
*
|
||||
* Ullrich von Bassewitz, 04.06.1998
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef CODEGEN_H
|
||||
#define CODEGEN_H
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Code generator flags.
|
||||
* Note: The type flags are designed so that a smaller type may override a
|
||||
* larger one by or'ing it into the existing one.
|
||||
*/
|
||||
#define CF_NONE 0x0000 /* No special flags */
|
||||
|
||||
#define CF_TYPE 0x000F /* Mask for operand type */
|
||||
#define CF_CHAR 0x0003 /* Operation on characters */
|
||||
#define CF_INT 0x0001 /* Operation on ints */
|
||||
#define CF_PTR CF_INT /* Alias for readability */
|
||||
#define CF_LONG 0x0000 /* Operation on longs */
|
||||
|
||||
#define CF_UNSIGNED 0x0010 /* Value is unsigned */
|
||||
#define CF_CONST 0x0020 /* Constant value available */
|
||||
#define CF_CONSTADDR 0x0040 /* Constant address value available */
|
||||
#define CF_TEST 0x0080 /* Test value */
|
||||
#define CF_FIXARGC 0x0100 /* Function has fixed arg count */
|
||||
#define CF_FORCECHAR 0x0200 /* Handle chars as chars, not ints */
|
||||
#define CF_SHORT 0x0400 /* Use short addressing */
|
||||
#define CF_REG 0x0800 /* Value is in primary register */
|
||||
|
||||
/* Type of static address */
|
||||
#define CF_ADDRMASK 0xF000 /* Type of address */
|
||||
#define CF_STATIC 0x0000 /* Static local */
|
||||
#define CF_EXTERNAL 0x1000 /* Static external */
|
||||
#define CF_ABSOLUTE 0x2000 /* Numeric absolute address */
|
||||
#define CF_LOCAL 0x4000 /* Auto variable */
|
||||
#define CF_REGVAR 0x8000 /* Register variable */
|
||||
|
||||
|
||||
|
||||
/* Compiler relative stackpointer */
|
||||
extern int oursp;
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Pre- and postamble */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void g_preamble (void);
|
||||
/* Generate the assembler code preamble */
|
||||
|
||||
void g_postamble (void);
|
||||
/* Generate assembler code postamble */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Segment support */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void g_usecode (void);
|
||||
/* Switch to the code segment */
|
||||
|
||||
void g_userodata (void);
|
||||
/* Switch to the read only data segment */
|
||||
|
||||
void g_usedata (void);
|
||||
/* Switch to the data segment */
|
||||
|
||||
void g_usebss (void);
|
||||
/* Switch to the bss segment */
|
||||
|
||||
void g_codename (const char* Name);
|
||||
/* Set the name of the CODE segment */
|
||||
|
||||
void g_rodataname (const char* Name);
|
||||
/* Set the name of the RODATA segment */
|
||||
|
||||
void g_dataname (const char* Name);
|
||||
/* Set the name of the DATA segment */
|
||||
|
||||
void g_bssname (const char* Name);
|
||||
/* Set the name of the BSS segment */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Functions handling local labels */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void g_defloclabel (unsigned label);
|
||||
/* Define a local label */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Functions handling global labels */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void g_defgloblabel (const char* Name);
|
||||
/* Define a global label with the given name */
|
||||
|
||||
void g_defexport (const char* Name, int ZP);
|
||||
/* Export the given label */
|
||||
|
||||
void g_defimport (const char* Name, int ZP);
|
||||
/* Import the given label */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* stack */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
int pop (unsigned flags);
|
||||
/* Pop an argument of the given size */
|
||||
|
||||
int push (unsigned flags);
|
||||
/* Push an argument of the given size */
|
||||
|
||||
unsigned sizeofarg (unsigned flags);
|
||||
/* Return the size of a function argument type that is encoded in flags */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* type conversion and similiar stuff */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void g_toslong (unsigned flags);
|
||||
/* Make sure, the value on TOS is a long. Convert if necessary */
|
||||
|
||||
void g_tosint (unsigned flags);
|
||||
/* Make sure, the value on TOS is an int. Convert if necessary */
|
||||
|
||||
void g_reglong (unsigned flags);
|
||||
/* Make sure, the value in the primary register a long. Convert if necessary */
|
||||
|
||||
unsigned g_typeadjust (unsigned lhs, unsigned rhs);
|
||||
/* Adjust the integer operands before doing a binary operation. lhs is a flags
|
||||
* value, that corresponds to the value on TOS, rhs corresponds to the value
|
||||
* in (e)ax. The return value is the the flags value for the resulting type.
|
||||
*/
|
||||
|
||||
unsigned g_typecast (unsigned lhs, unsigned rhs);
|
||||
/* Cast the value in the primary register to the operand size that is flagged
|
||||
* by the lhs value. Return the result value.
|
||||
*/
|
||||
|
||||
void g_scale (unsigned flags, long val);
|
||||
/* Scale the value in the primary register by the given value. If val is positive,
|
||||
* scale up, is val is negative, scale down. This function is used to scale
|
||||
* the operands or results of pointer arithmetic by the size of the type, the
|
||||
* pointer points to.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Function entry and exit */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void g_enter (unsigned flags, const char* Name, unsigned argsize);
|
||||
/* Function prologue */
|
||||
|
||||
void g_leave (int flags, int val);
|
||||
/* Function epilogue */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Register variables */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void g_save_regvars (int RegOffs, unsigned Bytes);
|
||||
/* Save register variables */
|
||||
|
||||
void g_restore_regvars (int StackOffs, int RegOffs, unsigned Bytes);
|
||||
/* Restore register variables */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Fetching memory cells */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void g_getimmed (unsigned flags, unsigned long val, unsigned offs);
|
||||
void g_getstatic (unsigned flags, unsigned long label, unsigned offs);
|
||||
void g_getlocal (unsigned flags, int offs);
|
||||
void g_getind (unsigned flags, unsigned offs);
|
||||
void g_leasp (int offs);
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Store into memory */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void g_putstatic (unsigned flags, unsigned long label, unsigned offs);
|
||||
/* Store the primary register into the specified static memory cell */
|
||||
|
||||
void g_putlocal (unsigned flags, int offs);
|
||||
/* Put data into local object. */
|
||||
|
||||
void g_putind (unsigned flags, unsigned offs);
|
||||
/* Store the specified object type in the primary register at the address
|
||||
* on the top of the stack
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Adds and subs of variables fix a fixed address */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void g_addlocal (unsigned flags, int offs);
|
||||
/* Add a local variable to ax */
|
||||
|
||||
void g_addstatic (unsigned flags, unsigned long label, unsigned offs);
|
||||
/* Add a static variable to ax */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Compares of ax with a variable with fixed address */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void g_cmplocal (unsigned flags, int offs);
|
||||
/* Compare a local variable to ax */
|
||||
|
||||
void g_cmpstatic (unsigned flags, unsigned label, unsigned offs);
|
||||
/* Compare a static variable to ax */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Special op= functions */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void g_addeqstatic (unsigned flags, unsigned long label, unsigned offs,
|
||||
unsigned long val);
|
||||
/* Emit += for a static variable */
|
||||
|
||||
void g_addeqlocal (unsigned flags, int offs, unsigned long val);
|
||||
/* Emit += for a local variable */
|
||||
|
||||
void g_addeqind (unsigned flags, unsigned offs, unsigned long val);
|
||||
/* Emit += for the location with address in ax */
|
||||
|
||||
void g_subeqstatic (unsigned flags, unsigned long label, unsigned offs,
|
||||
unsigned long val);
|
||||
/* Emit -= for a static variable */
|
||||
|
||||
void g_subeqlocal (unsigned flags, int offs, unsigned long val);
|
||||
/* Emit -= for a local variable */
|
||||
|
||||
void g_subeqind (unsigned flags, unsigned offs, unsigned long val);
|
||||
/* Emit -= for the location with address in ax */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Add a variable address to the value in ax */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void g_addaddr_local (unsigned flags, int offs);
|
||||
/* Add the address of a local variable to ax */
|
||||
|
||||
void g_addaddr_static (unsigned flags, unsigned long label, unsigned offs);
|
||||
/* Add the address of a static variable to ax */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void g_save (unsigned flags);
|
||||
void g_restore (unsigned flags);
|
||||
|
||||
void g_cmp (unsigned flags, unsigned long val);
|
||||
/* Immidiate compare. The primary register will not be changed, Z flag
|
||||
* will be set.
|
||||
*/
|
||||
|
||||
void g_test (unsigned flags);
|
||||
void g_push (unsigned flags, unsigned long val);
|
||||
void g_swap (unsigned flags);
|
||||
void g_call (unsigned flags, char *lbl, unsigned argsize);
|
||||
void g_callind (unsigned flags, unsigned argsize);
|
||||
void g_jump (unsigned label);
|
||||
void g_switch (unsigned flags);
|
||||
|
||||
void g_case (unsigned flags, unsigned label, unsigned long val);
|
||||
/* Create table code for one case selector */
|
||||
|
||||
void g_truejump (unsigned flags, unsigned label);
|
||||
/* Jump to label if zero flag clear */
|
||||
|
||||
void g_falsejump (unsigned flags, unsigned label);
|
||||
/* Jump to label if zero flag set */
|
||||
|
||||
void g_space (int space);
|
||||
/* Create or drop space on the stack */
|
||||
|
||||
void g_add (unsigned flags, unsigned long val);
|
||||
void g_sub (unsigned flags, unsigned long val);
|
||||
void g_rsub (unsigned flags, unsigned long val);
|
||||
void g_mul (unsigned flags, unsigned long val);
|
||||
void g_div (unsigned flags, unsigned long val);
|
||||
void g_mod (unsigned flags, unsigned long val);
|
||||
void g_or (unsigned flags, unsigned long val);
|
||||
void g_xor (unsigned flags, unsigned long val);
|
||||
void g_and (unsigned flags, unsigned long val);
|
||||
void g_asr (unsigned flags, unsigned long val);
|
||||
void g_asl (unsigned flags, unsigned long val);
|
||||
void g_neg (unsigned flags);
|
||||
void g_bneg (unsigned flags);
|
||||
void g_com (unsigned flags);
|
||||
void g_inc (unsigned flags, unsigned long n);
|
||||
void g_dec (unsigned flags, unsigned long n);
|
||||
void g_eq (unsigned flags, unsigned long val);
|
||||
void g_ne (unsigned flags, unsigned long val);
|
||||
void g_lt (unsigned flags, unsigned long val);
|
||||
void g_le (unsigned flags, unsigned long val);
|
||||
void g_gt (unsigned flags, unsigned long val);
|
||||
void g_ge (unsigned flags, unsigned long val);
|
||||
void g_makebool (unsigned flags);
|
||||
void outdat (int n);
|
||||
void g_res (unsigned n);
|
||||
|
||||
void g_defdata (unsigned flags, unsigned long val, unsigned offs);
|
||||
/* Define data with the size given in flags */
|
||||
|
||||
void g_defbytes (const unsigned char *bytes, unsigned count);
|
||||
void g_zerobytes (unsigned n);
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Inlined known functions */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void g_strlen (unsigned flags, unsigned long val, unsigned offs);
|
||||
/* Inline the strlen() function */
|
||||
|
||||
|
||||
|
||||
/* End of codegen.h */
|
||||
#endif
|
||||
|
||||
|
||||
32
src/cc65/copyleft.jrd
Normal file
32
src/cc65/copyleft.jrd
Normal file
@@ -0,0 +1,32 @@
|
||||
-*- Mode: Text -*-
|
||||
|
||||
This is the copyright notice for RA65, LINK65, LIBR65, and other
|
||||
Atari 8-bit programs. Said programs are Copyright 1989, by John R.
|
||||
Dunning. All rights reserved, with the following exceptions:
|
||||
|
||||
Anyone may copy or redistribute these programs, provided that:
|
||||
|
||||
1: You don't charge anything for the copy. It is permissable to
|
||||
charge a nominal fee for media, etc.
|
||||
|
||||
2: All source code and documentation for the programs is made
|
||||
available as part of the distribution.
|
||||
|
||||
3: This copyright notice is preserved verbatim, and included in
|
||||
the distribution.
|
||||
|
||||
You are allowed to modify these programs, and redistribute the
|
||||
modified versions, provided that the modifications are clearly noted.
|
||||
|
||||
There is NO WARRANTY with this software, it comes as is, and is
|
||||
distributed in the hope that it may be useful.
|
||||
|
||||
This copyright notice applies to any program which contains
|
||||
this text, or the refers to this file.
|
||||
|
||||
This copyright notice is based on the one published by the Free
|
||||
Software Foundation, sometimes known as the GNU project. The idea
|
||||
is the same as theirs, ie the software is free, and is intended to
|
||||
stay that way. Everybody has the right to copy, modify, and re-
|
||||
distribute this software. Nobody has the right to prevent anyone
|
||||
else from copying, modifying or redistributing it.
|
||||
137
src/cc65/ctrans.c
Normal file
137
src/cc65/ctrans.c
Normal file
@@ -0,0 +1,137 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* ctrans.c */
|
||||
/* */
|
||||
/* Character set translation for the cc65 C compiler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 "global.h"
|
||||
#include "ctrans.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static unsigned char CTNone [256] = {
|
||||
/* No system - no translation */
|
||||
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
|
||||
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
|
||||
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
|
||||
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
|
||||
0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
|
||||
0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
|
||||
0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
|
||||
0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
|
||||
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
|
||||
0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
|
||||
0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
|
||||
0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
|
||||
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
|
||||
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
|
||||
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
|
||||
};
|
||||
|
||||
static unsigned char CTAtari [256] = {
|
||||
/* ASCII -> ATASCII */
|
||||
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x7E,0x08,0x7F,0x9B,0x0B,0x7D,0x0D,0x0E,0x0F,
|
||||
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
|
||||
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
|
||||
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
|
||||
0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
|
||||
0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
|
||||
0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
|
||||
0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
|
||||
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
|
||||
0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
|
||||
0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
|
||||
0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
|
||||
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
|
||||
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
|
||||
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
|
||||
};
|
||||
|
||||
static unsigned char CTPET [256] = {
|
||||
/* ASCII -> PETSCII */
|
||||
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x14,0x09,0x0D,0x11,0x93,0x0A,0x0E,0x0F,
|
||||
0x10,0x0B,0x12,0x13,0x08,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
|
||||
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
|
||||
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
|
||||
0x40,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
|
||||
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0x5B,0x5C,0x5D,0x5E,0x5F,
|
||||
0xC0,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
|
||||
0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0xDB,0xDC,0xDD,0xDE,0xDF,
|
||||
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
|
||||
0x90,0x91,0x92,0x0C,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
|
||||
0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
|
||||
0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
|
||||
0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
|
||||
0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
|
||||
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
|
||||
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
|
||||
};
|
||||
|
||||
static unsigned char* CTab [TGT_COUNT] = {
|
||||
CTNone, /* No system */
|
||||
CTAtari, /* Atari */
|
||||
CTPET, /* C64 */
|
||||
CTPET, /* C128 */
|
||||
CTPET, /* ACE */
|
||||
CTPET, /* Plus/4 */
|
||||
CTPET, /* CBM610 */
|
||||
CTPET, /* PET */
|
||||
CTNone, /* NES */
|
||||
CTNone, /* Apple2 */
|
||||
CTPET, /* GEOS */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
int ctrans (unsigned char C)
|
||||
/* Translate a character from source charset into target charset */
|
||||
{
|
||||
/* Translate for the given system */
|
||||
return CTab [Target][C];
|
||||
}
|
||||
|
||||
|
||||
|
||||
57
src/cc65/ctrans.h
Normal file
57
src/cc65/ctrans.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* ctrans.h */
|
||||
/* */
|
||||
/* Character set translation for the cc65 C compiler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 CTRANS_H
|
||||
#define CTRANS_H
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
int ctrans (unsigned char c);
|
||||
/* Translate a character from source charset into target charset */
|
||||
|
||||
|
||||
|
||||
/* End of ctrans.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
568
src/cc65/datatype.c
Normal file
568
src/cc65/datatype.c
Normal file
@@ -0,0 +1,568 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* datatype.c */
|
||||
/* */
|
||||
/* Type string handling for the cc65 C compiler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 "check.h"
|
||||
#include "codegen.h"
|
||||
#include "datatype.h"
|
||||
#include "error.h"
|
||||
#include "funcdesc.h"
|
||||
#include "global.h"
|
||||
#include "mem.h"
|
||||
#include "util.h"
|
||||
#include "symtab.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Predefined type strings */
|
||||
type type_int [] = { T_INT, T_END };
|
||||
type type_uint [] = { T_UINT, T_END };
|
||||
type type_long [] = { T_LONG, T_END };
|
||||
type type_ulong [] = { T_ULONG, T_END };
|
||||
type type_void [] = { T_VOID, T_END };
|
||||
type type_pschar [] = { T_PTR, T_CHAR, T_END };
|
||||
type type_puchar [] = { T_PTR, T_UCHAR, T_END };
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
unsigned TypeLen (const type* T)
|
||||
/* Return the length of the type string */
|
||||
{
|
||||
const type* Start = T;
|
||||
while (*T) {
|
||||
++T;
|
||||
}
|
||||
return T - Start;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int TypeCmp (const type* T1, const type* T2)
|
||||
/* Compare two type strings */
|
||||
{
|
||||
int A, B, D;
|
||||
do {
|
||||
A = *T1++;
|
||||
B = *T2++;
|
||||
D = A - B;
|
||||
} while (D == 0 && A != 0);
|
||||
return D;
|
||||
}
|
||||
|
||||
|
||||
|
||||
type* TypeCpy (type* Dest, const type* Src)
|
||||
/* Copy a type string */
|
||||
{
|
||||
type T;
|
||||
type* Orig = Dest;
|
||||
do {
|
||||
T = *Src++;
|
||||
*Dest++ = T;
|
||||
} while (T);
|
||||
return Orig;
|
||||
}
|
||||
|
||||
|
||||
|
||||
type* TypeCat (type* Dest, const type* Src)
|
||||
/* Append Src */
|
||||
{
|
||||
TypeCpy (Dest + TypeLen (Dest), Src);
|
||||
return Dest;
|
||||
}
|
||||
|
||||
|
||||
|
||||
type* TypeDup (const type* T)
|
||||
/* Create a copy of the given type on the heap */
|
||||
{
|
||||
unsigned Len = (TypeLen (T) + 1) * sizeof (type);
|
||||
return memcpy (xmalloc (Len), T, Len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
type* TypeAlloc (unsigned Len)
|
||||
/* Allocate memory for a type string of length Len. Len *must* include the
|
||||
* trailing T_END.
|
||||
*/
|
||||
{
|
||||
return xmalloc (Len * sizeof (type));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void TypeFree (type* T)
|
||||
/* Free a type string */
|
||||
{
|
||||
xfree (T);
|
||||
}
|
||||
|
||||
|
||||
|
||||
type GetDefaultChar (void)
|
||||
/* Return the default char type (signed/unsigned) depending on the settings */
|
||||
{
|
||||
return SignedChars? T_CHAR : T_UCHAR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
type* GetCharArrayType (unsigned Len)
|
||||
/* Return the type for a char array of the given length */
|
||||
{
|
||||
/* Allocate memory for the type string */
|
||||
type* T = TypeAlloc (1 + DECODE_SIZE + 2);
|
||||
|
||||
/* Fill the type string */
|
||||
T [0] = T_ARRAY;
|
||||
T [DECODE_SIZE+1] = GetDefaultChar();
|
||||
T [DECODE_SIZE+2] = T_END;
|
||||
|
||||
/* Encode the length in the type string */
|
||||
Encode (T+1, Len);
|
||||
|
||||
/* Return the new type */
|
||||
return T;
|
||||
}
|
||||
|
||||
|
||||
|
||||
type* GetImplicitFuncType (void)
|
||||
/* Return a type string for an inplicitly declared function */
|
||||
{
|
||||
/* Get a new function descriptor */
|
||||
FuncDesc* F = NewFuncDesc ();
|
||||
|
||||
/* Allocate memory for the type string */
|
||||
type* T = TypeAlloc (1 + DECODE_SIZE + 2);
|
||||
|
||||
/* Prepare the function descriptor */
|
||||
F->Flags = FD_IMPLICIT | FD_ELLIPSIS;
|
||||
F->SymTab = &EmptySymTab;
|
||||
F->StructTab = &EmptySymTab;
|
||||
F->EnumTab = &EmptySymTab;
|
||||
|
||||
/* Fill the type string */
|
||||
T [0] = T_FUNC;
|
||||
T [DECODE_SIZE+1] = T_INT;
|
||||
T [DECODE_SIZE+2] = T_END;
|
||||
|
||||
/* Encode the function descriptor into the type string */
|
||||
EncodePtr (T+1, F);
|
||||
|
||||
/* Return the new type */
|
||||
return T;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PrintType (FILE* F, const type* tarray)
|
||||
/* Output translation of type array. */
|
||||
{
|
||||
const type* p;
|
||||
|
||||
for (p = tarray; *p != T_END; ++p) {
|
||||
if (*p & T_UNSIGNED) {
|
||||
fprintf (F, "unsigned ");
|
||||
}
|
||||
switch (*p) {
|
||||
case T_VOID:
|
||||
fprintf (F, "void\n");
|
||||
break;
|
||||
case T_CHAR:
|
||||
case T_UCHAR:
|
||||
fprintf (F, "char\n");
|
||||
break;
|
||||
case T_INT:
|
||||
case T_UINT:
|
||||
fprintf (F, "int\n");
|
||||
break;
|
||||
case T_SHORT:
|
||||
case T_USHORT:
|
||||
fprintf (F, "short\n");
|
||||
break;
|
||||
case T_LONG:
|
||||
case T_ULONG:
|
||||
fprintf (F, "long\n");
|
||||
break;
|
||||
case T_FLOAT:
|
||||
fprintf (F, "float\n");
|
||||
break;
|
||||
case T_DOUBLE:
|
||||
fprintf (F, "double\n");
|
||||
break;
|
||||
case T_PTR:
|
||||
fprintf (F, "pointer to ");
|
||||
break;
|
||||
case T_ARRAY:
|
||||
fprintf (F, "array[%lu] of ", Decode (p + 1));
|
||||
p += DECODE_SIZE;
|
||||
break;
|
||||
case T_STRUCT:
|
||||
fprintf (F, "struct %s\n", ((SymEntry*) Decode (p + 1))->Name);
|
||||
p += DECODE_SIZE;
|
||||
break;
|
||||
case T_UNION:
|
||||
fprintf (F, "union %s\n", ((SymEntry*) Decode (p + 1))->Name);
|
||||
p += DECODE_SIZE;
|
||||
break;
|
||||
case T_FUNC:
|
||||
fprintf (F, "function returning ");
|
||||
p += DECODE_SIZE;
|
||||
break;
|
||||
default:
|
||||
fprintf (F, "unknown type: %04X\n", *p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PrintRawType (FILE* F, const type* Type)
|
||||
/* Print a type string in raw format (for debugging) */
|
||||
{
|
||||
while (*Type != T_END) {
|
||||
fprintf (F, "%04X ", *Type++);
|
||||
}
|
||||
fprintf (F, "\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Encode (type* Type, unsigned long Val)
|
||||
/* Encode p[0] and p[1] so that neither p[0] nore p[1] is zero */
|
||||
{
|
||||
int I;
|
||||
for (I = 0; I < DECODE_SIZE; ++I) {
|
||||
*Type++ = ((type) Val) | 0x8000;
|
||||
Val >>= 15;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void EncodePtr (type* Type, void* P)
|
||||
/* Encode a pointer into a type array */
|
||||
{
|
||||
Encode (Type, (unsigned long) P);
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned long Decode (const type* Type)
|
||||
/* Decode */
|
||||
{
|
||||
int I;
|
||||
unsigned long Val = 0;
|
||||
for (I = DECODE_SIZE-1; I >= 0; I--) {
|
||||
Val <<= 15;
|
||||
Val |= (Type[I] & 0x7FFF);
|
||||
}
|
||||
return Val;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void* DecodePtr (const type* Type)
|
||||
/* Decode a pointer from a type array */
|
||||
{
|
||||
return (void*) Decode (Type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int HasEncode (const type* Type)
|
||||
/* Return true if the given type has encoded data */
|
||||
{
|
||||
return IsStruct (Type) || IsArray (Type) || IsFunc (Type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CopyEncode (const type* Source, type* Target)
|
||||
/* Copy encoded data from Source to Target */
|
||||
{
|
||||
memcpy (Target, Source, DECODE_SIZE * sizeof (type));
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned SizeOf (const type* tarray)
|
||||
/* Compute size of object represented by type array. */
|
||||
{
|
||||
SymEntry* Entry;
|
||||
|
||||
switch (*tarray) {
|
||||
|
||||
case T_VOID:
|
||||
return 0;
|
||||
|
||||
case T_CHAR:
|
||||
case T_UCHAR:
|
||||
return 1;
|
||||
|
||||
case T_INT:
|
||||
case T_UINT:
|
||||
case T_SHORT:
|
||||
case T_USHORT:
|
||||
case T_PTR:
|
||||
case T_ENUM:
|
||||
return 2;
|
||||
|
||||
case T_LONG:
|
||||
case T_ULONG:
|
||||
return 4;
|
||||
|
||||
case T_ARRAY:
|
||||
return (Decode (tarray + 1) * SizeOf (tarray + DECODE_SIZE + 1));
|
||||
|
||||
case T_STRUCT:
|
||||
case T_UNION:
|
||||
Entry = DecodePtr (tarray+1);
|
||||
return Entry->V.S.Size;
|
||||
|
||||
default:
|
||||
Internal ("Unknown type: %04X", *tarray);
|
||||
return 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned PSizeOf (const type* tptr)
|
||||
/* Compute size of pointer object. */
|
||||
{
|
||||
/* We are expecting a pointer expression */
|
||||
CHECK (*tptr & T_POINTER);
|
||||
|
||||
/* Skip the pointer or array token itself */
|
||||
if (*tptr == T_ARRAY) {
|
||||
return SizeOf (tptr + DECODE_SIZE + 1);
|
||||
} else {
|
||||
return SizeOf (tptr + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned TypeOf (const type* Type)
|
||||
/* Get the code generator base type of the object */
|
||||
{
|
||||
FuncDesc* F;
|
||||
|
||||
switch (*Type) {
|
||||
|
||||
case T_CHAR:
|
||||
return CF_CHAR;
|
||||
|
||||
case T_UCHAR:
|
||||
return CF_CHAR | CF_UNSIGNED;
|
||||
|
||||
case T_SHORT:
|
||||
case T_INT:
|
||||
case T_ENUM:
|
||||
return CF_INT;
|
||||
|
||||
case T_USHORT:
|
||||
case T_UINT:
|
||||
case T_PTR:
|
||||
case T_ARRAY:
|
||||
return CF_INT | CF_UNSIGNED;
|
||||
|
||||
case T_LONG:
|
||||
return CF_LONG;
|
||||
|
||||
case T_ULONG:
|
||||
return CF_LONG | CF_UNSIGNED;
|
||||
|
||||
case T_FUNC:
|
||||
F = DecodePtr (Type+1);
|
||||
return (F->Flags & FD_ELLIPSIS)? 0 : CF_FIXARGC;
|
||||
|
||||
case T_STRUCT:
|
||||
case T_UNION:
|
||||
/* Address of ... */
|
||||
return CF_INT | CF_UNSIGNED;
|
||||
|
||||
default:
|
||||
Error (ERR_ILLEGAL_TYPE);
|
||||
return CF_INT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
type* Indirect (type* Type)
|
||||
/* Do one indirection for the given type, that is, return the type where the
|
||||
* given type points to.
|
||||
*/
|
||||
{
|
||||
/* We are expecting a pointer expression */
|
||||
CHECK (Type[0] & T_POINTER);
|
||||
|
||||
/* Skip the pointer or array token itself */
|
||||
if (Type[0] == T_ARRAY) {
|
||||
return Type + DECODE_SIZE + 1;
|
||||
} else {
|
||||
return Type + 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int IsVoid (const type* Type)
|
||||
/* Return true if this is a void type */
|
||||
{
|
||||
return (Type[0] == T_VOID && Type[1] == T_END);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int IsPtr (const type* Type)
|
||||
/* Return true if this is a pointer type */
|
||||
{
|
||||
return (Type[0] & T_POINTER) != 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int IsChar (const type* Type)
|
||||
/* Return true if this is a character type */
|
||||
{
|
||||
return (Type[0] == T_CHAR || Type[0] == T_UCHAR) && Type[1] == T_END;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int IsInt (const type* Type)
|
||||
/* Return true if this is an integer type */
|
||||
{
|
||||
return (Type[0] & T_INTEGER) != 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int IsLong (const type* Type)
|
||||
/* Return true if this is a long type (signed or unsigned) */
|
||||
{
|
||||
return (Type[0] & T_LONG) == T_LONG;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int IsUnsigned (const type* Type)
|
||||
/* Return true if this is an unsigned type */
|
||||
{
|
||||
return (Type[0] & T_UNSIGNED) != 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int IsStruct (const type* Type)
|
||||
/* Return true if this is a struct type */
|
||||
{
|
||||
return (Type[0] == T_STRUCT || Type[0] == T_UNION);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int IsFunc (const type* Type)
|
||||
/* Return true if this is a function type */
|
||||
{
|
||||
return (Type[0] == T_FUNC);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int IsFastCallFunc (const type* Type)
|
||||
/* Return true if this is a function type with __fastcall__ calling conventions */
|
||||
{
|
||||
FuncDesc* F;
|
||||
CHECK (*Type == T_FUNC);
|
||||
F = DecodePtr (Type+1);
|
||||
return (F->Flags & FD_FASTCALL) != 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int IsFuncPtr (const type* Type)
|
||||
/* Return true if this is a function pointer */
|
||||
{
|
||||
return (Type[0] == T_PTR && Type[1] == T_FUNC);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int IsArray (const type* Type)
|
||||
/* Return true if this is an array type */
|
||||
{
|
||||
return (Type[0] == T_ARRAY);
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct FuncDesc* GetFuncDesc (const type* Type)
|
||||
/* Get the FuncDesc pointer from a function or pointer-to-function type */
|
||||
{
|
||||
if (Type[0] == T_PTR) {
|
||||
/* Pointer to function */
|
||||
++Type;
|
||||
}
|
||||
|
||||
/* Be sure it's a function type */
|
||||
CHECK (Type[0] == T_FUNC);
|
||||
|
||||
/* Decode the function descriptor and return it */
|
||||
return DecodePtr (Type+1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
223
src/cc65/datatype.h
Normal file
223
src/cc65/datatype.h
Normal file
@@ -0,0 +1,223 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* datatype.h */
|
||||
/* */
|
||||
/* Type string handling for the cc65 C compiler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 DATATYPE_H
|
||||
#define DATATYPE_H
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Data types */
|
||||
#define T_END 0x0000
|
||||
#define T_CHAR 0x0011
|
||||
#define T_INT 0x0012
|
||||
#define T_SHORT 0x0013
|
||||
#define T_LONG 0x0014
|
||||
#define T_ENUM 0x0015
|
||||
#define T_UCHAR 0x0019
|
||||
#define T_UINT 0x001A
|
||||
#define T_USHORT 0x001B
|
||||
#define T_ULONG 0x001C
|
||||
|
||||
#define T_FLOAT 0x0025
|
||||
#define T_DOUBLE 0x0026
|
||||
|
||||
#define T_VOID 0x0001 /* void parameter list */
|
||||
#define T_FUNC 0x0002 /* Function */
|
||||
|
||||
#define T_UNSIGNED 0x0008 /* Class */
|
||||
#define T_INTEGER 0x0010 /* Class */
|
||||
#define T_REAL 0x0020 /* Class */
|
||||
#define T_POINTER 0x0040 /* Class */
|
||||
#define T_PTR 0x0049
|
||||
#define T_ARRAY 0x004A
|
||||
#define T_STRUCT 0x0080
|
||||
#define T_UNION 0x0081
|
||||
#define T_SMASK 0x003F
|
||||
|
||||
|
||||
|
||||
/* Forward for a symbol entry */
|
||||
struct SymEntry;
|
||||
|
||||
/* Type entry */
|
||||
typedef unsigned short type;
|
||||
|
||||
/* Maximum length of a type string */
|
||||
#define MAXTYPELEN 30
|
||||
|
||||
/* type elements needed for Encode/Decode */
|
||||
#define DECODE_SIZE 5
|
||||
|
||||
/* Predefined type strings */
|
||||
extern type type_int [];
|
||||
extern type type_uint [];
|
||||
extern type type_long [];
|
||||
extern type type_ulong [];
|
||||
extern type type_void [];
|
||||
extern type type_pschar [];
|
||||
extern type type_puchar [];
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
unsigned TypeLen (const type* Type);
|
||||
/* Return the length of the type string */
|
||||
|
||||
int TypeCmp (const type* T1, const type* T2);
|
||||
/* Compare two type strings */
|
||||
|
||||
type* TypeCpy (type* Dest, const type* Src);
|
||||
/* Copy a type string */
|
||||
|
||||
type* TypeCat (type* Dest, const type* Src);
|
||||
/* Append Src */
|
||||
|
||||
type* TypeDup (const type* Type);
|
||||
/* Create a copy of the given type on the heap */
|
||||
|
||||
type* TypeAlloc (unsigned Len);
|
||||
/* Allocate memory for a type string of length Len. Len *must* include the
|
||||
* trailing T_END.
|
||||
*/
|
||||
|
||||
void TypeFree (type* Type);
|
||||
/* Free a type string */
|
||||
|
||||
type GetDefaultChar (void);
|
||||
/* Return the default char type (signed/unsigned) depending on the settings */
|
||||
|
||||
type* GetCharArrayType (unsigned Len);
|
||||
/* Return the type for a char array of the given length */
|
||||
|
||||
type* GetImplicitFuncType (void);
|
||||
/* Return a type string for an inplicitly declared function */
|
||||
|
||||
void PrintType (FILE* F, const type* Type);
|
||||
/* Output translation of type array. */
|
||||
|
||||
void PrintRawType (FILE* F, const type* Type);
|
||||
/* Print a type string in raw format (for debugging) */
|
||||
|
||||
void Encode (type* Type, unsigned long Val);
|
||||
/* Encode an unsigned long into a type array */
|
||||
|
||||
void EncodePtr (type* Type, void* P);
|
||||
/* Encode a pointer into a type array */
|
||||
|
||||
unsigned long Decode (const type* Type);
|
||||
/* Decode an unsigned long from a type array */
|
||||
|
||||
void* DecodePtr (const type* Type);
|
||||
/* Decode a pointer from a type array */
|
||||
|
||||
int HasEncode (const type* Type);
|
||||
/* Return true if the given type has encoded data */
|
||||
|
||||
void CopyEncode (const type* Source, type* Target);
|
||||
/* Copy encoded data from Source to Target */
|
||||
|
||||
unsigned SizeOf (const type* Type);
|
||||
/* Compute size of object represented by type array. */
|
||||
|
||||
unsigned PSizeOf (const type* Type);
|
||||
/* Compute size of pointer object. */
|
||||
|
||||
unsigned TypeOf (const type* Type);
|
||||
/* Get the code generator base type of the object */
|
||||
|
||||
type* Indirect (type* Type);
|
||||
/* Do one indirection for the given type, that is, return the type where the
|
||||
* given type points to.
|
||||
*/
|
||||
|
||||
int IsVoid (const type* Type);
|
||||
/* Return true if this is a void type */
|
||||
|
||||
int IsPtr (const type* Type);
|
||||
/* Return true if this is a pointer type */
|
||||
|
||||
int IsChar (const type* Type);
|
||||
/* Return true if this is a character type */
|
||||
|
||||
int IsInt (const type* Type);
|
||||
/* Return true if this is an integer type */
|
||||
|
||||
int IsLong (const type* Type);
|
||||
/* Return true if this is a long type (signed or unsigned) */
|
||||
|
||||
int IsUnsigned (const type* Type);
|
||||
/* Return true if this is an unsigned type */
|
||||
|
||||
int IsStruct (const type* Type);
|
||||
/* Return true if this is a struct type */
|
||||
|
||||
int IsFunc (const type* Type);
|
||||
/* Return true if this is a function type */
|
||||
|
||||
int IsFastCallFunc (const type* Type);
|
||||
/* Return true if this is a function type with __fastcall__ calling conventions */
|
||||
|
||||
int IsFuncPtr (const type* Type);
|
||||
/* Return true if this is a function pointer */
|
||||
|
||||
int IsArray (const type* Type);
|
||||
/* Return true if this is an array type */
|
||||
|
||||
struct FuncDesc* GetFuncDesc (const type* Type);
|
||||
/* Get the FuncDesc pointer from a function or pointer-to-function type */
|
||||
|
||||
|
||||
|
||||
/* End of datatype.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
938
src/cc65/declare.c
Normal file
938
src/cc65/declare.c
Normal file
@@ -0,0 +1,938 @@
|
||||
/*
|
||||
* declare.c
|
||||
*
|
||||
* Ullrich von Bassewitz, 20.06.1998
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "anonname.h"
|
||||
#include "codegen.h"
|
||||
#include "datatype.h"
|
||||
#include "error.h"
|
||||
#include "expr.h"
|
||||
#include "funcdesc.h"
|
||||
#include "function.h"
|
||||
#include "global.h"
|
||||
#include "litpool.h"
|
||||
#include "mem.h"
|
||||
#include "pragma.h"
|
||||
#include "scanner.h"
|
||||
#include "symtab.h"
|
||||
#include "declare.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Forwards */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static void ParseTypeSpec (DeclSpec* D, int Default);
|
||||
/* Parse a type specificier */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* internal functions */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static void optional_modifiers (void)
|
||||
/* Eat optional "const" or "volatile" tokens */
|
||||
{
|
||||
while (curtok == CONST || curtok == VOLATILE) {
|
||||
/* Skip it */
|
||||
gettok ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void optionalint (void)
|
||||
/* Eat an optional "int" token */
|
||||
{
|
||||
if (curtok == INT) {
|
||||
/* Skip it */
|
||||
gettok ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void optionalsigned (void)
|
||||
/* Eat an optional "signed" token */
|
||||
{
|
||||
if (curtok == SIGNED) {
|
||||
/* Skip it */
|
||||
gettok ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void InitDeclSpec (DeclSpec* D)
|
||||
/* Initialize the DeclSpec struct for use */
|
||||
{
|
||||
D->StorageClass = 0;
|
||||
D->Type[0] = T_END;
|
||||
D->Flags = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void InitDeclaration (Declaration* D)
|
||||
/* Initialize the Declaration struct for use */
|
||||
{
|
||||
D->Ident[0] = '\0';
|
||||
D->Type[0] = T_END;
|
||||
D->T = D->Type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void ParseStorageClass (DeclSpec* D, unsigned DefStorage)
|
||||
/* Parse a storage class */
|
||||
{
|
||||
/* Assume we're using an explicit storage class */
|
||||
D->Flags &= ~DS_DEF_STORAGE;
|
||||
|
||||
/* Check the storage class given */
|
||||
switch (curtok) {
|
||||
|
||||
case EXTERN:
|
||||
D->StorageClass = SC_EXTERN | SC_STATIC;
|
||||
gettok ();
|
||||
break;
|
||||
|
||||
case STATIC:
|
||||
D->StorageClass = SC_STATIC;
|
||||
gettok ();
|
||||
break;
|
||||
|
||||
case REGISTER:
|
||||
D->StorageClass = SC_REGISTER | SC_STATIC;
|
||||
gettok ();
|
||||
break;
|
||||
|
||||
case AUTO:
|
||||
D->StorageClass = SC_AUTO;
|
||||
gettok ();
|
||||
break;
|
||||
|
||||
case TYPEDEF:
|
||||
D->StorageClass = SC_TYPEDEF;
|
||||
gettok ();
|
||||
break;
|
||||
|
||||
default:
|
||||
/* No storage class given, use default */
|
||||
D->Flags |= DS_DEF_STORAGE;
|
||||
D->StorageClass = DefStorage;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void ParseEnumDecl (void)
|
||||
/* Process an enum declaration . */
|
||||
{
|
||||
int EnumVal;
|
||||
ident Ident;
|
||||
|
||||
/* Accept forward definitions */
|
||||
if (curtok != LCURLY) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Skip the opening curly brace */
|
||||
gettok ();
|
||||
|
||||
/* Read the enum tags */
|
||||
EnumVal = 0;
|
||||
while (curtok != RCURLY) {
|
||||
|
||||
/* We expect an identifier */
|
||||
if (curtok != IDENT) {
|
||||
Error (ERR_IDENT_EXPECTED);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Remember the identifier and skip it */
|
||||
strcpy (Ident, CurTok.Ident);
|
||||
gettok ();
|
||||
|
||||
/* Check for an assigned value */
|
||||
if (curtok == ASGN) {
|
||||
struct expent lval;
|
||||
gettok ();
|
||||
constexpr (&lval);
|
||||
EnumVal = lval.e_const;
|
||||
}
|
||||
|
||||
/* Add an entry to the symbol table */
|
||||
AddEnumSym (Ident, EnumVal++);
|
||||
|
||||
/* Check for end of definition */
|
||||
if (curtok != COMMA)
|
||||
break;
|
||||
gettok ();
|
||||
}
|
||||
ConsumeRCurly ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
static SymEntry* ParseStructDecl (const char* Name, type StructType)
|
||||
/* Parse a struct/union declaration. */
|
||||
{
|
||||
|
||||
unsigned Size;
|
||||
unsigned Offs;
|
||||
SymTable* FieldTab;
|
||||
SymEntry* Entry;
|
||||
|
||||
|
||||
if (curtok != LCURLY) {
|
||||
/* Just a forward declaration. Try to find a struct with the given
|
||||
* name. If there is none, insert a forward declaration into the
|
||||
* current lexical level.
|
||||
*/
|
||||
Entry = FindStructSym (Name);
|
||||
if (Entry == 0 || Entry->Flags != SC_STRUCT) {
|
||||
Entry = AddStructSym (Name, 0, 0);
|
||||
}
|
||||
return Entry;
|
||||
}
|
||||
|
||||
/* Add a forward declaration for the struct in the current lexical level */
|
||||
Entry = AddStructSym (Name, 0, 0);
|
||||
|
||||
/* Skip the curly brace */
|
||||
gettok ();
|
||||
|
||||
/* Enter a new lexical level for the struct */
|
||||
EnterStructLevel ();
|
||||
|
||||
/* Parse struct fields */
|
||||
Size = 0;
|
||||
while (curtok != RCURLY) {
|
||||
|
||||
/* Get the type of the entry */
|
||||
DeclSpec Spec;
|
||||
InitDeclSpec (&Spec);
|
||||
ParseTypeSpec (&Spec, -1);
|
||||
|
||||
/* Read fields with this type */
|
||||
while (1) {
|
||||
|
||||
/* Get type and name of the struct field */
|
||||
Declaration Decl;
|
||||
ParseDecl (&Spec, &Decl, 0);
|
||||
|
||||
/* Add a field entry to the table */
|
||||
AddLocalSym (Decl.Ident, Decl.Type, SC_SFLD, (StructType == T_STRUCT)? Size : 0);
|
||||
|
||||
/* Calculate offset of next field/size of the union */
|
||||
Offs = SizeOf (Decl.Type);
|
||||
if (StructType == T_STRUCT) {
|
||||
Size += Offs;
|
||||
} else {
|
||||
if (Offs > Size) {
|
||||
Size = Offs;
|
||||
}
|
||||
}
|
||||
|
||||
if (curtok != COMMA)
|
||||
break;
|
||||
gettok ();
|
||||
}
|
||||
ConsumeSemi ();
|
||||
}
|
||||
|
||||
/* Skip the closing brace */
|
||||
gettok ();
|
||||
|
||||
/* Remember the symbol table and leave the struct level */
|
||||
FieldTab = GetSymTab ();
|
||||
LeaveStructLevel ();
|
||||
|
||||
/* Make a real entry from the forward decl and return it */
|
||||
return AddStructSym (Name, Size, FieldTab);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void ParseTypeSpec (DeclSpec* D, int Default)
|
||||
/* Parse a type specificier */
|
||||
{
|
||||
ident Ident;
|
||||
SymEntry* Entry;
|
||||
type StructType;
|
||||
|
||||
/* Assume have an explicit type */
|
||||
D->Flags &= ~DS_DEF_TYPE;
|
||||
|
||||
/* Skip const or volatile modifiers if needed */
|
||||
optional_modifiers ();
|
||||
|
||||
/* Look at the data type */
|
||||
switch (curtok) {
|
||||
|
||||
case VOID:
|
||||
gettok ();
|
||||
D->Type[0] = T_VOID;
|
||||
D->Type[1] = T_END;
|
||||
break;
|
||||
|
||||
case CHAR:
|
||||
gettok ();
|
||||
D->Type[0] = GetDefaultChar();
|
||||
D->Type[1] = T_END;
|
||||
break;
|
||||
|
||||
case LONG:
|
||||
gettok ();
|
||||
if (curtok == UNSIGNED) {
|
||||
gettok ();
|
||||
optionalint ();
|
||||
D->Type[0] = T_ULONG;
|
||||
D->Type[1] = T_END;
|
||||
} else {
|
||||
optionalsigned ();
|
||||
optionalint ();
|
||||
D->Type[0] = T_LONG;
|
||||
D->Type[1] = T_END;
|
||||
}
|
||||
break;
|
||||
|
||||
case SHORT:
|
||||
gettok ();
|
||||
if (curtok == UNSIGNED) {
|
||||
gettok ();
|
||||
optionalint ();
|
||||
D->Type[0] = T_USHORT;
|
||||
D->Type[1] = T_END;
|
||||
} else {
|
||||
optionalsigned ();
|
||||
optionalint ();
|
||||
D->Type[0] = T_SHORT;
|
||||
D->Type[1] = T_END;
|
||||
}
|
||||
break;
|
||||
|
||||
case INT:
|
||||
gettok ();
|
||||
D->Type[0] = T_INT;
|
||||
D->Type[1] = T_END;
|
||||
break;
|
||||
|
||||
case SIGNED:
|
||||
gettok ();
|
||||
switch (curtok) {
|
||||
|
||||
case CHAR:
|
||||
gettok ();
|
||||
D->Type[0] = T_CHAR;
|
||||
D->Type[1] = T_END;
|
||||
break;
|
||||
|
||||
case SHORT:
|
||||
gettok ();
|
||||
optionalint ();
|
||||
D->Type[0] = T_SHORT;
|
||||
D->Type[1] = T_END;
|
||||
break;
|
||||
|
||||
case LONG:
|
||||
gettok ();
|
||||
optionalint ();
|
||||
D->Type[0] = T_LONG;
|
||||
D->Type[1] = T_END;
|
||||
break;
|
||||
|
||||
case INT:
|
||||
gettok ();
|
||||
/* FALL THROUGH */
|
||||
|
||||
default:
|
||||
D->Type[0] = T_INT;
|
||||
D->Type[1] = T_END;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case UNSIGNED:
|
||||
gettok ();
|
||||
switch (curtok) {
|
||||
|
||||
case CHAR:
|
||||
gettok ();
|
||||
D->Type[0] = T_UCHAR;
|
||||
D->Type[1] = T_END;
|
||||
break;
|
||||
|
||||
case SHORT:
|
||||
gettok ();
|
||||
optionalint ();
|
||||
D->Type[0] = T_USHORT;
|
||||
D->Type[1] = T_END;
|
||||
break;
|
||||
|
||||
case LONG:
|
||||
gettok ();
|
||||
optionalint ();
|
||||
D->Type[0] = T_ULONG;
|
||||
D->Type[1] = T_END;
|
||||
break;
|
||||
|
||||
case INT:
|
||||
gettok ();
|
||||
/* FALL THROUGH */
|
||||
|
||||
default:
|
||||
D->Type[0] = T_UINT;
|
||||
D->Type[1] = T_END;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case STRUCT:
|
||||
case UNION:
|
||||
StructType = (curtok == STRUCT)? T_STRUCT : T_UNION;
|
||||
gettok ();
|
||||
if (curtok == IDENT) {
|
||||
strcpy (Ident, CurTok.Ident);
|
||||
gettok ();
|
||||
} else {
|
||||
AnonName (Ident, (StructType == T_STRUCT)? "struct" : "union");
|
||||
}
|
||||
/* Declare the struct in the current scope */
|
||||
Entry = ParseStructDecl (Ident, StructType);
|
||||
/* Encode the struct entry into the type */
|
||||
D->Type[0] = StructType;
|
||||
EncodePtr (D->Type+1, Entry);
|
||||
D->Type[DECODE_SIZE+1] = T_END;
|
||||
break;
|
||||
|
||||
case ENUM:
|
||||
gettok ();
|
||||
if (curtok != LCURLY) {
|
||||
/* Named enum */
|
||||
Consume (IDENT, ERR_IDENT_EXPECTED);
|
||||
}
|
||||
ParseEnumDecl ();
|
||||
D->Type[0] = T_INT;
|
||||
D->Type[1] = T_END;
|
||||
break;
|
||||
|
||||
case IDENT:
|
||||
Entry = FindSym (CurTok.Ident);
|
||||
if (Entry && IsTypeDef (Entry)) {
|
||||
/* It's a typedef */
|
||||
gettok ();
|
||||
TypeCpy (D->Type, Entry->Type);
|
||||
break;
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
|
||||
default:
|
||||
if (Default < 0) {
|
||||
Error (ERR_TYPE_EXPECTED);
|
||||
D->Type[0] = T_INT;
|
||||
D->Type[1] = T_END;
|
||||
} else {
|
||||
D->Flags |= DS_DEF_TYPE;
|
||||
D->Type[0] = (type) Default;
|
||||
D->Type[1] = T_END;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static FuncDesc* ParseFuncDecl (void)
|
||||
/* Parse the argument list of a function. */
|
||||
{
|
||||
unsigned UnnamedCount = 0;
|
||||
unsigned Offs;
|
||||
SymEntry* Sym;
|
||||
type* Type;
|
||||
|
||||
/* Create a new function descriptor */
|
||||
FuncDesc* F = NewFuncDesc ();
|
||||
|
||||
/* Enter a new lexical level */
|
||||
EnterFunctionLevel ();
|
||||
|
||||
/* Check for an empty or void parameter list */
|
||||
if (curtok == RPAREN) {
|
||||
/* Parameter list is empty */
|
||||
F->Flags |= (FD_EMPTY | FD_ELLIPSIS);
|
||||
} else if (curtok == VOID && nxttok == RPAREN) {
|
||||
/* Parameter list declared as void */
|
||||
gettok ();
|
||||
F->Flags |= FD_VOID_PARAM;
|
||||
}
|
||||
|
||||
/* Parse params */
|
||||
while (curtok != RPAREN) {
|
||||
|
||||
DeclSpec Spec;
|
||||
Declaration Decl;
|
||||
|
||||
/* Allow an ellipsis as last parameter */
|
||||
if (curtok == ELLIPSIS) {
|
||||
gettok ();
|
||||
F->Flags |= FD_ELLIPSIS;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Read the declaration specifier */
|
||||
ParseDeclSpec (&Spec, SC_AUTO, T_INT);
|
||||
|
||||
/* We accept only auto and register as storage class specifiers, but
|
||||
* we ignore all this and use auto.
|
||||
*/
|
||||
if ((Spec.StorageClass & SC_AUTO) == 0 &&
|
||||
(Spec.StorageClass & SC_REGISTER) == 0) {
|
||||
Error (ERR_ILLEGAL_STORAGE_CLASS);
|
||||
}
|
||||
Spec.StorageClass = SC_AUTO | SC_PARAM | SC_DEF;
|
||||
|
||||
/* Allow parameters without a name, but remember if we had some to
|
||||
* eventually print an error message later.
|
||||
*/
|
||||
ParseDecl (&Spec, &Decl, DM_ACCEPT_IDENT);
|
||||
if (Decl.Ident[0] == '\0') {
|
||||
|
||||
/* Unnamed symbol. Generate a name that is not user accessible,
|
||||
* then handle the symbol normal.
|
||||
*/
|
||||
AnonName (Decl.Ident, "param");
|
||||
++UnnamedCount;
|
||||
|
||||
/* Clear defined bit on nonames */
|
||||
Spec.StorageClass &= ~SC_DEF;
|
||||
}
|
||||
|
||||
/* If the parameter is an array, convert it to a pointer */
|
||||
Type = Decl.Type;
|
||||
if (IsArray (Type)) {
|
||||
Type += DECODE_SIZE;
|
||||
Type[0] = T_PTR;
|
||||
}
|
||||
|
||||
/* Create a symbol table entry */
|
||||
AddLocalSym (Decl.Ident, Type, Spec.StorageClass, 0);
|
||||
|
||||
/* Count arguments */
|
||||
++F->ParamCount;
|
||||
F->ParamSize += SizeOf (Type);
|
||||
|
||||
/* Check for more parameters */
|
||||
if (curtok == COMMA) {
|
||||
gettok ();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Skip right paren. We must explicitly check for one here, since some of
|
||||
* the breaks above bail out without checking.
|
||||
*/
|
||||
ConsumeRParen ();
|
||||
|
||||
/* Assign offsets. If the function has a variable parameter list,
|
||||
* there's one additional byte (the arg size).
|
||||
*/
|
||||
Offs = (F->Flags & FD_ELLIPSIS)? 1 : 0;
|
||||
Sym = GetSymTab()->SymTail;
|
||||
while (Sym) {
|
||||
Sym->V.Offs = Offs;
|
||||
Offs += SizeOf (Sym->Type);
|
||||
Sym = Sym->PrevSym;
|
||||
}
|
||||
|
||||
/* Check if this is a function definition */
|
||||
if (curtok == LCURLY) {
|
||||
/* Print an error if in strict ANSI mode and we have unnamed
|
||||
* parameters.
|
||||
*/
|
||||
if (ANSI && UnnamedCount > 0) {
|
||||
Error (ERR_MISSING_PARAM_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
/* Leave the lexical level remembering the symbol tables */
|
||||
RememberFunctionLevel (F);
|
||||
|
||||
/* Return the function descriptor */
|
||||
return F;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void Decl (Declaration* D, unsigned Mode)
|
||||
/* Recursively process declarators. Build a type array in reverse order. */
|
||||
{
|
||||
if (curtok == STAR) {
|
||||
gettok ();
|
||||
/* Allow optional const or volatile modifiers */
|
||||
optional_modifiers ();
|
||||
Decl (D, Mode);
|
||||
*D->T++ = T_PTR;
|
||||
return;
|
||||
} else if (curtok == LPAREN) {
|
||||
gettok ();
|
||||
Decl (D, Mode);
|
||||
ConsumeRParen ();
|
||||
} else if (curtok == FASTCALL) {
|
||||
/* Remember the current type pointer */
|
||||
type* T = D->T;
|
||||
/* Skip the fastcall token */
|
||||
gettok ();
|
||||
/* Parse the function */
|
||||
Decl (D, Mode);
|
||||
/* Set the fastcall flag */
|
||||
if (!IsFunc (T)) {
|
||||
Error (ERR_ILLEGAL_MODIFIER);
|
||||
} else {
|
||||
FuncDesc* F = DecodePtr (T+1);
|
||||
F->Flags |= FD_FASTCALL;
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
/* Things depend on Mode now:
|
||||
* - Mode == DM_NEED_IDENT means:
|
||||
* we *must* have a type and a variable identifer.
|
||||
* - Mode == DM_NO_IDENT means:
|
||||
* we must have a type but no variable identifer
|
||||
* (if there is one, it's not read).
|
||||
* - Mode == DM_ACCEPT_IDENT means:
|
||||
* we *may* have an identifier. If there is an identifier,
|
||||
* it is read, but it is no error, if there is none.
|
||||
*/
|
||||
if (Mode == DM_NO_IDENT) {
|
||||
D->Ident[0] = '\0';
|
||||
} else if (curtok == IDENT) {
|
||||
strcpy (D->Ident, CurTok.Ident);
|
||||
gettok ();
|
||||
} else {
|
||||
if (Mode == DM_NEED_IDENT) {
|
||||
Error (ERR_IDENT_EXPECTED);
|
||||
}
|
||||
D->Ident[0] = '\0';
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
while (curtok == LBRACK || curtok == LPAREN) {
|
||||
if (curtok == LPAREN) {
|
||||
/* Function declaration */
|
||||
FuncDesc* F;
|
||||
gettok ();
|
||||
/* Parse the function declaration */
|
||||
F = ParseFuncDecl ();
|
||||
*D->T++ = T_FUNC;
|
||||
EncodePtr (D->T, F);
|
||||
D->T += DECODE_SIZE;
|
||||
} else {
|
||||
/* Array declaration */
|
||||
unsigned long Size = 0;
|
||||
gettok ();
|
||||
/* Read the size if it is given */
|
||||
if (curtok != RBRACK) {
|
||||
struct expent lval;
|
||||
constexpr (&lval);
|
||||
Size = lval.e_const;
|
||||
}
|
||||
ConsumeRBrack ();
|
||||
*D->T++ = T_ARRAY;
|
||||
Encode (D->T, Size);
|
||||
D->T += DECODE_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
type* ParseType (type* Type)
|
||||
/* Parse a complete type specification */
|
||||
{
|
||||
DeclSpec Spec;
|
||||
Declaration Decl;
|
||||
|
||||
/* Get a type without a default */
|
||||
InitDeclSpec (&Spec);
|
||||
ParseTypeSpec (&Spec, -1);
|
||||
|
||||
/* Parse additional declarators */
|
||||
InitDeclaration (&Decl);
|
||||
ParseDecl (&Spec, &Decl, DM_NO_IDENT);
|
||||
|
||||
/* Copy the type to the target buffer */
|
||||
TypeCpy (Type, Decl.Type);
|
||||
|
||||
/* Return a pointer to the target buffer */
|
||||
return Type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ParseDecl (const DeclSpec* Spec, Declaration* D, unsigned Mode)
|
||||
/* Parse a variable, type or function declaration */
|
||||
{
|
||||
/* Initialize the Declaration struct */
|
||||
InitDeclaration (D);
|
||||
|
||||
/* Get additional declarators and the identifier */
|
||||
Decl (D, Mode);
|
||||
|
||||
/* Add the base type. */
|
||||
TypeCpy (D->T, Spec->Type);
|
||||
|
||||
/* Check the size of the generated type */
|
||||
if (!IsFunc (D->Type) && SizeOf (D->Type) >= 0x10000) {
|
||||
Error (ERR_ILLEGAL_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ParseDeclSpec (DeclSpec* D, unsigned DefStorage, int DefType)
|
||||
/* Parse a declaration specification */
|
||||
{
|
||||
/* Initialize the DeclSpec struct */
|
||||
InitDeclSpec (D);
|
||||
|
||||
/* First, get the storage class specifier for this declaration */
|
||||
ParseStorageClass (D, DefStorage);
|
||||
|
||||
/* Parse the type specifiers */
|
||||
ParseTypeSpec (D, DefType);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void ParseVoidInit (void)
|
||||
/* Parse an initialization of a void variable (special cc65 extension) */
|
||||
{
|
||||
struct expent lval;
|
||||
|
||||
/* Allow an arbitrary list of values */
|
||||
ConsumeLCurly ();
|
||||
do {
|
||||
constexpr (&lval);
|
||||
switch (lval.e_tptr[0]) {
|
||||
|
||||
case T_CHAR:
|
||||
case T_UCHAR:
|
||||
if ((lval.e_flags & E_MCTYPE) == E_TCONST) {
|
||||
/* Make it byte sized */
|
||||
lval.e_const &= 0xFF;
|
||||
}
|
||||
DefineData (&lval);
|
||||
break;
|
||||
|
||||
case T_SHORT:
|
||||
case T_USHORT:
|
||||
case T_INT:
|
||||
case T_UINT:
|
||||
case T_PTR:
|
||||
case T_ARRAY:
|
||||
if ((lval.e_flags & E_MCTYPE) == E_TCONST) {
|
||||
/* Make it word sized */
|
||||
lval.e_const &= 0xFFFF;
|
||||
}
|
||||
DefineData (&lval);
|
||||
break;
|
||||
|
||||
case T_LONG:
|
||||
case T_ULONG:
|
||||
DefineData (&lval);
|
||||
break;
|
||||
|
||||
default:
|
||||
Error (ERR_ILLEGAL_TYPE);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (curtok != COMMA) {
|
||||
break;
|
||||
}
|
||||
gettok ();
|
||||
|
||||
} while (curtok != RCURLY);
|
||||
|
||||
ConsumeRCurly ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void ParseStructInit (type* Type)
|
||||
/* Parse initialization of a struct or union */
|
||||
{
|
||||
SymEntry* Entry;
|
||||
SymTable* Tab;
|
||||
|
||||
/* Consume the opening curly brace */
|
||||
ConsumeLCurly ();
|
||||
|
||||
/* Get a pointer to the struct entry from the type */
|
||||
Entry = (SymEntry*) Decode (Type + 1);
|
||||
|
||||
/* Check if this struct definition has a field table. If it doesn't, it
|
||||
* is an incomplete definition.
|
||||
*/
|
||||
Tab = Entry->V.S.SymTab;
|
||||
if (Tab == 0) {
|
||||
Error (ERR_INIT_INCOMPLETE_TYPE);
|
||||
/* Returning here will cause lots of errors, but recovery is difficult */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get a pointer to the list of symbols */
|
||||
Entry = Tab->SymHead;
|
||||
while (curtok != RCURLY) {
|
||||
if (Entry == NULL) {
|
||||
Error (ERR_TOO_MANY_INITIALIZERS);
|
||||
return;
|
||||
}
|
||||
ParseInit (Entry->Type);
|
||||
Entry = Entry->NextSym;
|
||||
if (curtok != COMMA)
|
||||
break;
|
||||
gettok ();
|
||||
}
|
||||
|
||||
/* Consume the closing curly brace */
|
||||
ConsumeRCurly ();
|
||||
|
||||
/* If there are struct fields left, reserve additional storage */
|
||||
while (Entry) {
|
||||
g_zerobytes (SizeOf (Entry->Type));
|
||||
Entry = Entry->NextSym;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void ParseInit (type *tptr)
|
||||
/* Parse initialization of variables */
|
||||
{
|
||||
int count;
|
||||
struct expent lval;
|
||||
type* t;
|
||||
const char* str;
|
||||
int sz;
|
||||
|
||||
switch (*tptr) {
|
||||
|
||||
case T_CHAR:
|
||||
case T_UCHAR:
|
||||
constexpr (&lval);
|
||||
if ((lval.e_flags & E_MCTYPE) == E_TCONST) {
|
||||
/* Make it byte sized */
|
||||
lval.e_const &= 0xFF;
|
||||
}
|
||||
assignadjust (tptr, &lval);
|
||||
DefineData (&lval);
|
||||
break;
|
||||
|
||||
case T_SHORT:
|
||||
case T_USHORT:
|
||||
case T_INT:
|
||||
case T_UINT:
|
||||
case T_PTR:
|
||||
constexpr (&lval);
|
||||
if ((lval.e_flags & E_MCTYPE) == E_TCONST) {
|
||||
/* Make it word sized */
|
||||
lval.e_const &= 0xFFFF;
|
||||
}
|
||||
assignadjust (tptr, &lval);
|
||||
DefineData (&lval);
|
||||
break;
|
||||
|
||||
case T_LONG:
|
||||
case T_ULONG:
|
||||
constexpr (&lval);
|
||||
if ((lval.e_flags & E_MCTYPE) == E_TCONST) {
|
||||
/* Make it long sized */
|
||||
lval.e_const &= 0xFFFFFFFF;
|
||||
}
|
||||
assignadjust (tptr, &lval);
|
||||
DefineData (&lval);
|
||||
break;
|
||||
|
||||
case T_ARRAY:
|
||||
sz = Decode (tptr + 1);
|
||||
t = tptr + DECODE_SIZE + 1;
|
||||
if ((t [0] == T_CHAR || t [0] == T_UCHAR) && curtok == SCONST) {
|
||||
str = GetLiteral (curval);
|
||||
count = strlen (str) + 1;
|
||||
TranslateLiteralPool (curval); /* Translate into target charset */
|
||||
g_defbytes (str, count);
|
||||
ResetLiteralOffs (curval); /* Remove string from pool */
|
||||
gettok ();
|
||||
} else {
|
||||
ConsumeLCurly ();
|
||||
count = 0;
|
||||
while (curtok != RCURLY) {
|
||||
ParseInit (tptr + DECODE_SIZE + 1);
|
||||
++count;
|
||||
if (curtok != COMMA)
|
||||
break;
|
||||
gettok ();
|
||||
}
|
||||
ConsumeRCurly ();
|
||||
}
|
||||
if (sz == 0) {
|
||||
Encode (tptr + 1, count);
|
||||
} else if (count < sz) {
|
||||
g_zerobytes ((sz - count) * SizeOf (tptr + DECODE_SIZE + 1));
|
||||
} else if (count > sz) {
|
||||
Error (ERR_TOO_MANY_INITIALIZERS);
|
||||
}
|
||||
break;
|
||||
|
||||
case T_STRUCT:
|
||||
case T_UNION:
|
||||
ParseStructInit (tptr);
|
||||
break;
|
||||
|
||||
case T_VOID:
|
||||
if (!ANSI) {
|
||||
/* Special cc65 extension in non ANSI mode */
|
||||
ParseVoidInit ();
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
|
||||
default:
|
||||
Error (ERR_ILLEGAL_TYPE);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
79
src/cc65/declare.h
Normal file
79
src/cc65/declare.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* declare.h
|
||||
*
|
||||
* Ullrich von Bassewitz, 20.06.1998
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef DECLARE_H
|
||||
#define DECLARE_H
|
||||
|
||||
|
||||
|
||||
#include "scanner.h"
|
||||
#include "symtab.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Masks for the Flags field in DeclSpec */
|
||||
#define DS_DEF_STORAGE 0x0001U /* Default storage class used */
|
||||
#define DS_DEF_TYPE 0x0002U /* Default type used */
|
||||
|
||||
/* Result of ParseDeclSpec */
|
||||
typedef struct DeclSpec DeclSpec;
|
||||
struct DeclSpec {
|
||||
unsigned StorageClass; /* One of the SC_xxx flags */
|
||||
type Type [MAXTYPELEN]; /* Type of the declaration spec */
|
||||
unsigned Flags; /* Bitmapped flags */
|
||||
};
|
||||
|
||||
/* Result of ParseDecl */
|
||||
typedef struct Declaration Declaration;
|
||||
struct Declaration {
|
||||
ident Ident; /* The identifier if any, else empty */
|
||||
type Type [MAXTYPELEN]; /* The type */
|
||||
|
||||
/* Working variables */
|
||||
type* T; /* Used to build Type */
|
||||
};
|
||||
|
||||
/* Modes for ParseDecl */
|
||||
#define DM_NEED_IDENT 0U /* We must have an identifier */
|
||||
#define DM_NO_IDENT 1U /* We won't read an identifier */
|
||||
#define DM_ACCEPT_IDENT 2U /* We will accept an id if there is one */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
type* ParseType (type* Type);
|
||||
/* Parse a complete type specification */
|
||||
|
||||
void ParseDecl (const DeclSpec* Spec, Declaration* D, unsigned Mode);
|
||||
/* Parse a variable, type or function declaration */
|
||||
|
||||
void ParseDeclSpec (DeclSpec* D, unsigned DefStorage, int DefType);
|
||||
/* Parse a declaration specification */
|
||||
|
||||
void ParseInit (type* tptr);
|
||||
/* Parse initialization of variables */
|
||||
|
||||
|
||||
|
||||
/* End of declare.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
310
src/cc65/error.c
Normal file
310
src/cc65/error.c
Normal file
@@ -0,0 +1,310 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* error.c */
|
||||
/* */
|
||||
/* Error handling for the cc65 C compiler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 <stdarg.h>
|
||||
|
||||
#include "global.h"
|
||||
#include "io.h"
|
||||
#include "scanner.h"
|
||||
#include "stmt.h"
|
||||
#include "error.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static char* WarnMsg [WARN_COUNT-1] = {
|
||||
"Unreachable code",
|
||||
"Condition is never true",
|
||||
"Condition is always true",
|
||||
"Converting pointer to integer without a cast",
|
||||
"Converting integer to pointer without a cast",
|
||||
"Function call without a prototype",
|
||||
"Unknown #pragma",
|
||||
"No case labels",
|
||||
"Function must be extern",
|
||||
"Parameter `%s' is never used",
|
||||
"`%s' is defined but never used",
|
||||
"Constant is long",
|
||||
"`/*' found inside a comment",
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Error messages sorted by ErrTypes */
|
||||
static char* ErrMsg [ERR_COUNT-1] = {
|
||||
"Invalid character (%u)",
|
||||
"Unexpected newline",
|
||||
"End-of-file reached in comment starting at line %u",
|
||||
"Syntax error",
|
||||
"`\"' expected",
|
||||
"`:' expected",
|
||||
"`;' expected",
|
||||
"`(' expected",
|
||||
"`)' expected",
|
||||
"`[' expected",
|
||||
"`]' expected",
|
||||
"`{' expected",
|
||||
"`}' expected",
|
||||
"Identifier expected",
|
||||
"Type expected",
|
||||
"Incompatible types",
|
||||
"Incompatible pointer types",
|
||||
"Too many arguments in function call",
|
||||
"Too few arguments in function call",
|
||||
"Macro argument count mismatch",
|
||||
"Duplicate macro parameter: %s",
|
||||
"Variable identifier expected",
|
||||
"Integer expression expected",
|
||||
"Constant expression expected",
|
||||
"No active loop",
|
||||
"`\"' or `<' expected",
|
||||
"Missing terminator or name too long",
|
||||
"Include file `%s' not found",
|
||||
"Open failure on include file `%s'",
|
||||
"Invalid #error directive",
|
||||
"#error: %s",
|
||||
"Unexpected `#endif'",
|
||||
"Unexpected `#else'",
|
||||
"`#endif' expected",
|
||||
"Compiler directive expected",
|
||||
"Symbol `%s' defined more than once",
|
||||
"String literal expected",
|
||||
"`while' expected",
|
||||
"Function must return a value",
|
||||
"Function cannot return a value",
|
||||
"Unexpected `continue'",
|
||||
"Undefined symbol: `%s'",
|
||||
"Undefined label: `%s'",
|
||||
"Include nesting too deep",
|
||||
"Too many local variables",
|
||||
"Too many initializers",
|
||||
"Cannot initialize incomplete type",
|
||||
"Cannot subscript",
|
||||
"Operation not allowed on these types",
|
||||
"Struct expected",
|
||||
"Struct/union has no field named `%s'",
|
||||
"Struct pointer expected",
|
||||
"lvalue expected",
|
||||
"Expression expected",
|
||||
"Preprocessor expression expected",
|
||||
"Illegal type",
|
||||
"Illegal function call",
|
||||
"Illegal indirection",
|
||||
"Illegal address",
|
||||
"Illegal macro call",
|
||||
"Illegal hex digit",
|
||||
"Illegal character constant",
|
||||
"Illegal modifier",
|
||||
"Illegal storage class",
|
||||
"Division by zero",
|
||||
"Modulo operation with zero",
|
||||
"Range error",
|
||||
"Symbol is already different kind",
|
||||
"Too many lexical levels",
|
||||
"Parameter name omitted",
|
||||
"Old style function decl used as prototype",
|
||||
"Declaration for parameter `%s' but no such parameter",
|
||||
"Cannot take address of a register variable",
|
||||
"Illegal size of data type",
|
||||
"__fastcall__ is not allowed for C functions",
|
||||
"Variable has unknown size",
|
||||
};
|
||||
|
||||
|
||||
|
||||
static char* FatMsg [FAT_COUNT-1] = {
|
||||
"Too many errors",
|
||||
"Cannot open output file: %s",
|
||||
"Cannot write to output file (disk full?)",
|
||||
"Cannot open input file: %s",
|
||||
"Out of memory",
|
||||
"Stack overflow",
|
||||
"Stack empty",
|
||||
"Out of string space",
|
||||
"Too many case labels",
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Count of errors/warnings */
|
||||
unsigned ErrorCount = 0;
|
||||
unsigned WarningCount = 0;
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void Warning (unsigned WarnNum, ...)
|
||||
/* Print warning message. */
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (!NoWarn) {
|
||||
fprintf (stderr, "%s(%u): Warning #%u: ", fin, curpos, WarnNum);
|
||||
|
||||
va_start (ap, WarnNum);
|
||||
vfprintf (stderr, WarnMsg [WarnNum-1], ap);
|
||||
va_end (ap);
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
if (Verbose) {
|
||||
fprintf (stderr, "Line: %s\n", line);
|
||||
}
|
||||
}
|
||||
++ WarningCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PPWarning (unsigned WarnNum, ...)
|
||||
/* Print warning message. For use within the preprocessor. */
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (!NoWarn) {
|
||||
fprintf (stderr, "%s(%u): Warning #%u: ", fin, ln, WarnNum);
|
||||
|
||||
va_start (ap, WarnNum);
|
||||
vfprintf (stderr, WarnMsg [WarnNum-1], ap);
|
||||
va_end (ap);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
++WarningCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Error (unsigned ErrNum, ...)
|
||||
/* Print an error message */
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf (stderr, "%s(%u): Error #%u: ", fin, curpos, ErrNum);
|
||||
|
||||
va_start (ap, ErrNum);
|
||||
vfprintf (stderr, ErrMsg [ErrNum-1], ap);
|
||||
va_end (ap);
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
if (Verbose) {
|
||||
fprintf (stderr, "Line: %s\n", line);
|
||||
}
|
||||
++ErrorCount;
|
||||
if (ErrorCount > 10) {
|
||||
Fatal (FAT_TOO_MANY_ERRORS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PPError (unsigned ErrNum, ...)
|
||||
/* Print an error message. For use within the preprocessor. */
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf (stderr, "%s(%u): Error #%u: ", fin, ln, ErrNum);
|
||||
|
||||
va_start (ap, ErrNum);
|
||||
vfprintf (stderr, ErrMsg [ErrNum-1], ap);
|
||||
va_end (ap);
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
++ErrorCount;
|
||||
if (ErrorCount > 10) {
|
||||
Fatal (FAT_TOO_MANY_ERRORS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Fatal (unsigned FatNum, ...)
|
||||
/* Print a message about a fatal error and die */
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf (stderr, "%s(%u): Fatal #%u: ", fin, curpos, FatNum);
|
||||
|
||||
va_start (ap, FatNum);
|
||||
vfprintf (stderr, FatMsg [FatNum-1], ap);
|
||||
va_end (ap);
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
if (Verbose) {
|
||||
fprintf (stderr, "Line: %s\n", line);
|
||||
}
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Internal (char* Format, ...)
|
||||
/* Print a message about an internal compiler error and die. */
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf (stderr, "%s(%u): Internal compiler error:\n", fin, curpos);
|
||||
|
||||
va_start (ap, Format);
|
||||
vfprintf (stderr, Format, ap);
|
||||
va_end (ap);
|
||||
fprintf (stderr, "\nLine: %s\n", line);
|
||||
|
||||
/* Use abort to create a core dump */
|
||||
abort ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ErrorReport (void)
|
||||
/* Report errors (called at end of compile) */
|
||||
{
|
||||
if (ErrorCount == 0 && Verbose) {
|
||||
printf ("No errors.\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
206
src/cc65/error.h
Normal file
206
src/cc65/error.h
Normal file
@@ -0,0 +1,206 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* error.h */
|
||||
/* */
|
||||
/* Error handling for the cc65 C compiler */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 ERROR_H
|
||||
#define ERROR_H
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Warning numbers */
|
||||
enum Warnings {
|
||||
WARN_NONE, /* No warning */
|
||||
WARN_UNREACHABLE_CODE,
|
||||
WARN_COND_NEVER_TRUE,
|
||||
WARN_COND_ALWAYS_TRUE,
|
||||
WARN_PTR_TO_INT_CONV,
|
||||
WARN_INT_TO_PTR_CONV,
|
||||
WARN_FUNC_WITHOUT_PROTO,
|
||||
WARN_UNKNOWN_PRAGMA,
|
||||
WARN_NO_CASE_LABELS,
|
||||
WARN_FUNC_MUST_BE_EXTERN,
|
||||
WARN_UNUSED_PARM,
|
||||
WARN_UNUSED_ITEM,
|
||||
WARN_CONSTANT_IS_LONG,
|
||||
WARN_NESTED_COMMENT,
|
||||
WARN_COUNT /* Warning count */
|
||||
};
|
||||
|
||||
/* Error numbers */
|
||||
enum Errors {
|
||||
ERR_NONE, /* No error */
|
||||
ERR_INVALID_CHAR,
|
||||
ERR_UNEXPECTED_NEWLINE,
|
||||
ERR_EOF_IN_COMMENT,
|
||||
ERR_SYNTAX,
|
||||
ERR_QUOTE_EXPECTED,
|
||||
ERR_COLON_EXPECTED,
|
||||
ERR_SEMICOLON_EXPECTED,
|
||||
ERR_LPAREN_EXPECTED,
|
||||
ERR_RPAREN_EXPECTED,
|
||||
ERR_LBRACK_EXPECTED,
|
||||
ERR_RBRACK_EXPECTED,
|
||||
ERR_LCURLY_EXPECTED,
|
||||
ERR_RCURLY_EXPECTED,
|
||||
ERR_IDENT_EXPECTED,
|
||||
ERR_TYPE_EXPECTED,
|
||||
ERR_INCOMPATIBLE_TYPES,
|
||||
ERR_INCOMPATIBLE_POINTERS,
|
||||
ERR_TOO_MANY_FUNC_ARGS,
|
||||
ERR_TOO_FEW_FUNC_ARGS,
|
||||
ERR_MACRO_ARGCOUNT,
|
||||
ERR_DUPLICATE_MACRO_ARG,
|
||||
ERR_VAR_IDENT_EXPECTED,
|
||||
ERR_INT_EXPR_EXPECTED,
|
||||
ERR_CONST_EXPR_EXPECTED,
|
||||
ERR_NO_ACTIVE_LOOP,
|
||||
ERR_INCLUDE_LTERM_EXPECTED,
|
||||
ERR_INCLUDE_RTERM_EXPECTED,
|
||||
ERR_INCLUDE_NOT_FOUND,
|
||||
ERR_INCLUDE_OPEN_FAILURE,
|
||||
ERR_INVALID_USER_ERROR,
|
||||
ERR_USER_ERROR,
|
||||
ERR_UNEXPECTED_CPP_ENDIF,
|
||||
ERR_UNEXPECTED_CPP_ELSE,
|
||||
ERR_CPP_ENDIF_EXPECTED,
|
||||
ERR_CPP_DIRECTIVE_EXPECTED,
|
||||
ERR_MULTIPLE_DEFINITION,
|
||||
ERR_STRLIT_EXPECTED,
|
||||
ERR_WHILE_EXPECTED,
|
||||
ERR_MUST_RETURN_VALUE,
|
||||
ERR_CANNOT_RETURN_VALUE,
|
||||
ERR_UNEXPECTED_CONTINUE,
|
||||
ERR_UNDEFINED_SYMBOL,
|
||||
ERR_UNDEFINED_LABEL,
|
||||
ERR_INCLUDE_NESTING,
|
||||
ERR_TOO_MANY_LOCALS,
|
||||
ERR_TOO_MANY_INITIALIZERS,
|
||||
ERR_INIT_INCOMPLETE_TYPE,
|
||||
ERR_CANNOT_SUBSCRIPT,
|
||||
ERR_OP_NOT_ALLOWED,
|
||||
ERR_STRUCT_EXPECTED,
|
||||
ERR_STRUCT_FIELD_MISMATCH,
|
||||
ERR_STRUCT_PTR_EXPECTED,
|
||||
ERR_LVALUE_EXPECTED,
|
||||
ERR_EXPR_EXPECTED,
|
||||
ERR_CPP_EXPR_EXPECTED,
|
||||
ERR_ILLEGAL_TYPE,
|
||||
ERR_ILLEGAL_FUNC_CALL,
|
||||
ERR_ILLEGAL_INDIRECT,
|
||||
ERR_ILLEGAL_ADDRESS,
|
||||
ERR_ILLEGAL_MACRO_CALL,
|
||||
ERR_ILLEGAL_HEX_DIGIT,
|
||||
ERR_ILLEGAL_CHARCONST,
|
||||
ERR_ILLEGAL_MODIFIER,
|
||||
ERR_ILLEGAL_STORAGE_CLASS,
|
||||
ERR_DIV_BY_ZERO,
|
||||
ERR_MOD_BY_ZERO,
|
||||
ERR_RANGE,
|
||||
ERR_SYMBOL_KIND,
|
||||
ERR_LEVEL_NESTING,
|
||||
ERR_MISSING_PARAM_NAME,
|
||||
ERR_OLD_STYLE_PROTO,
|
||||
ERR_PARAM_DECL,
|
||||
ERR_CANNOT_TAKE_ADDR_OF_REG,
|
||||
ERR_ILLEGAL_SIZE,
|
||||
ERR_FASTCALL,
|
||||
ERR_UNKNOWN_SIZE,
|
||||
ERR_COUNT /* Error count */
|
||||
};
|
||||
|
||||
/* Fatal errors */
|
||||
enum Fatals {
|
||||
FAT_NONE,
|
||||
FAT_TOO_MANY_ERRORS,
|
||||
FAT_CANNOT_OPEN_OUTPUT,
|
||||
FAT_CANNOT_WRITE_OUTPUT,
|
||||
FAT_CANNOT_OPEN_INPUT,
|
||||
FAT_OUT_OF_MEMORY,
|
||||
FAT_STACK_OVERFLOW,
|
||||
FAT_STACK_EMPTY,
|
||||
FAT_OUT_OF_STRSPACE,
|
||||
FAT_TOO_MANY_CASE_LABELS,
|
||||
FAT_COUNT /* Fatal error count */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Count of errors/warnings */
|
||||
extern unsigned ErrorCount;
|
||||
extern unsigned WarningCount;
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void Warning (unsigned WarnNum, ...);
|
||||
/* Print warning message. */
|
||||
|
||||
void PPWarning (unsigned WarnNum, ...);
|
||||
/* Print warning message. For use within the preprocessor. */
|
||||
|
||||
void Error (unsigned ErrNum, ...);
|
||||
/* Print an error message */
|
||||
|
||||
void PPError (unsigned ErrNum, ...);
|
||||
/* Print an error message. For use within the preprocessor. */
|
||||
|
||||
void Fatal (unsigned FatNum, ...);
|
||||
/* Print a message about a fatal error and die */
|
||||
|
||||
void Internal (char* Format, ...);
|
||||
/* Print a message about an internal compiler error and die. */
|
||||
|
||||
void ErrorReport (void);
|
||||
/* Report errors (called at end of compile) */
|
||||
|
||||
|
||||
|
||||
/* End of error.h */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
2980
src/cc65/expr.c
Normal file
2980
src/cc65/expr.c
Normal file
File diff suppressed because it is too large
Load Diff
125
src/cc65/expr.h
Normal file
125
src/cc65/expr.h
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* expr.h
|
||||
*
|
||||
* Ullrich von Bassewitz, 21.06.1998
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef EXPR_H
|
||||
#define EXPR_H
|
||||
|
||||
|
||||
|
||||
#include "datatype.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Defines for the flags field of the expression descriptor */
|
||||
#define E_MREG 0x0110 /* Special: Expression is primary register */
|
||||
#define E_MGLOBAL 0x0080 /* Reference to static variable */
|
||||
#define E_MLOCAL 0x0040 /* Reference to local variable (stack offset) */
|
||||
#define E_MCONST 0x0020 /* Constant value */
|
||||
#define E_MEXPR 0x0010 /* Result is in primary register */
|
||||
#define E_MEOFFS 0x0011 /* Offset is in primary register, base on stack */
|
||||
|
||||
#define E_MCTYPE 0x0007 /* Type of a constant */
|
||||
#define E_TCONST 0x0000 /* Constant */
|
||||
#define E_TGLAB 0x0001 /* Global label */
|
||||
#define E_TLIT 0x0002 /* Literal of some kind */
|
||||
#define E_TLOFFS 0x0003 /* Constant stack offset */
|
||||
#define E_TLLAB 0x0004 /* Local label */
|
||||
#define E_TREGISTER 0x0005 /* Register variable */
|
||||
|
||||
/* Defines for the test field of the expression descriptor */
|
||||
#define E_CC 0x0001 /* expr has set cond codes apropos result value */
|
||||
#define E_FORCETEST 0x0002 /* if expr has NOT set CC, force a test */
|
||||
#define E_LOGL 0x0004 /* expr has left a logical value (1 or 0) in AX */
|
||||
#define E_XINV 0x0008 /* flip this bit to invert sense of test */
|
||||
#define E_TEST 0x0010 /* We're evaluating a test */
|
||||
|
||||
/* Describe the result of an expression */
|
||||
struct expent {
|
||||
struct SymEntry* Sym; /* Symbol table entry if known */
|
||||
type* e_tptr; /* Type array of expression */
|
||||
long e_const; /* Value if expression constant */
|
||||
unsigned e_flags;
|
||||
unsigned e_test; /* */
|
||||
unsigned long e_name; /* Name or label number */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void doasm (void);
|
||||
/* This function parses ASM statements. The syntax of the ASM directive
|
||||
* looks like the one defined for C++ (C has no ASM directive), that is,
|
||||
* a string literal in parenthesis.
|
||||
*/
|
||||
|
||||
unsigned assignadjust (type* lhst, struct expent* rhs);
|
||||
/* Adjust the type of the right hand expression so that it can be assigned to
|
||||
* the type on the left hand side. This function is used for assignment and
|
||||
* for converting parameters in a function call. It returns the code generator
|
||||
* flags for the operation.
|
||||
*/
|
||||
|
||||
void exprhs (unsigned flags, int k, struct expent *lval);
|
||||
/* Put the result of an expression into the primary register */
|
||||
|
||||
void expression1 (struct expent* lval);
|
||||
/* Evaluate an expression on level 1 (no comma operator) and put it into
|
||||
* the primary register
|
||||
*/
|
||||
|
||||
void expression (struct expent* lval);
|
||||
/* Evaluate an expression and put it into the primary register */
|
||||
|
||||
int evalexpr (unsigned flags, int (*f) (struct expent*), struct expent* lval);
|
||||
/* Will evaluate an expression via the given function. If the result is a
|
||||
* constant, 0 is returned and the value is put in the lval struct. If the
|
||||
* result is not constant, exprhs is called to bring the value into the
|
||||
* primary register and 1 is returned.
|
||||
*/
|
||||
|
||||
void constexpr (struct expent* lval);
|
||||
/* Get a constant value */
|
||||
|
||||
void intexpr (struct expent* lval);
|
||||
/* Get an integer expression */
|
||||
|
||||
void boolexpr (struct expent* lval);
|
||||
/* Get a boolean expression */
|
||||
|
||||
void test (unsigned label, int cond);
|
||||
/* Generate code to perform test and jump if false. */
|
||||
|
||||
int hie1 (struct expent* lval);
|
||||
/* Parse first level of expression hierarchy. */
|
||||
|
||||
int hie0 (struct expent* lval);
|
||||
/* Parse comma operator (highest level of expression hierarchy) */
|
||||
|
||||
void DefineData (struct expent* lval);
|
||||
/* Output a data definition for the given expression */
|
||||
|
||||
|
||||
|
||||
/* End of expr.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user