mirror of
https://github.com/uffejakobsen/acme.git
synced 2024-12-22 18:30:44 +00:00
slightly improved experimental feature to dynamically create symbol names
git-svn-id: https://svn.code.sf.net/p/acme-crossass/code-0/trunk@329 4df02467-bbd4-4a76-a152-e7ce94205b78
This commit is contained in:
parent
aec6f8e99d
commit
c6739be77d
@ -70,7 +70,7 @@ void dynabuf_clear(struct dynabuf *db)
|
||||
db->size = 0; // clear buffer
|
||||
}
|
||||
|
||||
// Enlarge buffer
|
||||
// this gets called by "APPEND" macro whenever buffer is too small
|
||||
void dynabuf_enlarge(struct dynabuf *db)
|
||||
{
|
||||
resize(db, MAKE_LARGER_THAN(db->reserved));
|
||||
@ -94,15 +94,18 @@ void dynabuf_append(struct dynabuf *db, char byte)
|
||||
DYNABUF_APPEND(db, byte);
|
||||
}
|
||||
|
||||
// Append string to buffer (without terminator)
|
||||
// add string to buffer (terminator is added, but not included in "size"!)
|
||||
void dynabuf_add_string(struct dynabuf *db, const char *string)
|
||||
{
|
||||
char byte;
|
||||
|
||||
while ((byte = *string++))
|
||||
do {
|
||||
byte = *string++;
|
||||
DYNABUF_APPEND(db, byte);
|
||||
} while (byte);
|
||||
db->size--; // do not consider terminator to be part of content
|
||||
}
|
||||
/*
|
||||
|
||||
// make sure DynaBuf is large enough to take "size" more bytes
|
||||
// return pointer to end of current contents
|
||||
static char *ensure_free_space(struct dynabuf *db, int size)
|
||||
@ -110,9 +113,35 @@ static char *ensure_free_space(struct dynabuf *db, int size)
|
||||
while ((db->reserved - db->size) < size)
|
||||
resize(db, MAKE_LARGER_THAN(db->reserved));
|
||||
return db->buffer + db->size;
|
||||
}*/
|
||||
}
|
||||
|
||||
// Convert buffer contents to lower case (target and source may be identical)
|
||||
// append byte sequence to buffer
|
||||
void dynabuf_add_bytes(struct dynabuf *db, const char *src, size_t size)
|
||||
{
|
||||
char *target;
|
||||
|
||||
target = ensure_free_space(db, size);
|
||||
memcpy(target, src, size);
|
||||
db->size += size;
|
||||
}
|
||||
|
||||
// add long integer as decimal number to buffer
|
||||
#define NUMBUFSIZE 30 // 21 would be large enough(tm) even for 64bit systems
|
||||
void dynabuf_add_signed_long(struct dynabuf *db, signed long number)
|
||||
{
|
||||
char *target;
|
||||
int added;
|
||||
|
||||
target = ensure_free_space(db, NUMBUFSIZE);
|
||||
#if _BSD_SOURCE || _XOPEN_SOURCE >= 500 || _ISOC99_SOURCE || _POSIX_C_SOURCE >= 200112L
|
||||
added = snprintf(target, NUMBUFSIZE, "%ld", number);
|
||||
#else
|
||||
added = sprintf(target, "%ld", number);
|
||||
#endif
|
||||
db->size += added;
|
||||
}
|
||||
|
||||
// convert buffer contents to lower case (target and source may be identical)
|
||||
void dynabuf_to_lower(struct dynabuf *target, struct dynabuf *source)
|
||||
{
|
||||
char *read,
|
||||
|
@ -1,5 +1,5 @@
|
||||
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
||||
// Copyright (C) 1998-2020 Marco Baye
|
||||
// Copyright (C) 1998-2024 Marco Baye
|
||||
// Have a look at "acme.c" for further info
|
||||
//
|
||||
// Dynamic buffer stuff
|
||||
@ -47,19 +47,25 @@ extern struct dynabuf GlobalDynaBuf[1]; // global dynamic buffer
|
||||
// (ensure buffer is ready to use, then) clear dynamic buffer
|
||||
extern void dynabuf_clear(struct dynabuf *db);
|
||||
|
||||
// call whenever buffer is too small
|
||||
// this gets called by "APPEND" macro whenever buffer is too small
|
||||
extern void dynabuf_enlarge(struct dynabuf *db);
|
||||
|
||||
// return malloc'd copy of buffer contents
|
||||
extern char *dynabuf_get_copy(struct dynabuf *db);
|
||||
|
||||
// copy string to buffer (without terminator)
|
||||
extern void dynabuf_add_string(struct dynabuf *db, const char *);
|
||||
// add string to buffer (terminator is added, but not included in "size"!)
|
||||
extern void dynabuf_add_string(struct dynabuf *db, const char *str);
|
||||
|
||||
// converts buffer contents to lower case
|
||||
// add byte sequence to buffer
|
||||
extern void dynabuf_add_bytes(struct dynabuf *db, const char *src, size_t size);
|
||||
|
||||
// add long integer as decimal number to buffer
|
||||
extern void dynabuf_add_signed_long(struct dynabuf *db, signed long number);
|
||||
|
||||
// convert buffer contents to lower case
|
||||
extern void dynabuf_to_lower(struct dynabuf *target, struct dynabuf *source);
|
||||
|
||||
// add char to buffer
|
||||
// append char to buffer
|
||||
extern void dynabuf_append(struct dynabuf *db, char);
|
||||
|
||||
|
||||
|
@ -106,6 +106,7 @@ static enum eos po_initmem(void)
|
||||
|
||||
|
||||
// change output "encryption" ("!xor" pseudo opcode)
|
||||
// (allows for block, so must be reentrant)
|
||||
static enum eos po_xor(void)
|
||||
{
|
||||
char old_value;
|
||||
@ -309,6 +310,7 @@ static enum eos po_cbm(void)
|
||||
}
|
||||
|
||||
// read encoding table from file
|
||||
// (allows for block, so must be reentrant)
|
||||
static enum eos user_defined_encoding(FILE *stream)
|
||||
{
|
||||
unsigned char local_table[256],
|
||||
@ -335,6 +337,7 @@ static enum eos user_defined_encoding(FILE *stream)
|
||||
}
|
||||
|
||||
// use one of the pre-defined encodings (raw, pet, scr)
|
||||
// (allows for block, so must be reentrant)
|
||||
static enum eos predefined_encoding(void)
|
||||
{
|
||||
unsigned char local_table[256],
|
||||
@ -356,6 +359,7 @@ static enum eos predefined_encoding(void)
|
||||
return ENSURE_EOS;
|
||||
}
|
||||
// set current encoding ("!convtab" pseudo opcode)
|
||||
// (allows for block, so must be reentrant)
|
||||
static enum eos po_convtab(void)
|
||||
{
|
||||
boolean uses_lib;
|
||||
@ -610,6 +614,7 @@ static void old_offset_assembly(void)
|
||||
}
|
||||
|
||||
// start offset assembly
|
||||
// (allows for block, so must be reentrant)
|
||||
// TODO - maybe add a label argument to assign the block size afterwards (for assemble-to-end-address) (or add another pseudo opcode)
|
||||
static enum eos po_pseudopc(void)
|
||||
{
|
||||
@ -657,6 +662,7 @@ static enum eos po_realpc(void)
|
||||
|
||||
|
||||
// select CPU ("!cpu" pseudo opcode)
|
||||
// (allows for block, so must be reentrant)
|
||||
static enum eos po_cpu(void)
|
||||
{
|
||||
const struct cpu_type *cpu_buffer = CPU_state.type; // remember current cpu
|
||||
@ -677,6 +683,7 @@ static enum eos po_cpu(void)
|
||||
|
||||
|
||||
// set register length, block-wise if needed.
|
||||
// (allows for block, so must be reentrant)
|
||||
static enum eos set_register_length(boolean *var, boolean make_long)
|
||||
{
|
||||
int old_size = *var;
|
||||
@ -794,6 +801,7 @@ static enum eos po_symbollist(void)
|
||||
|
||||
|
||||
// switch to new zone ("!zone" or "!zn"). has to be re-entrant.
|
||||
// (allows for block, so must be reentrant)
|
||||
static enum eos po_zone(void)
|
||||
{
|
||||
struct section entry_values; // buffer for outer zone
|
||||
@ -1245,6 +1253,24 @@ static enum eos po_watch(void)
|
||||
}
|
||||
*/
|
||||
|
||||
/* // disable warnings for a statement or block of code
|
||||
static enum eos po_nowarn(void)
|
||||
{
|
||||
boolean flag_buf = global_inhibit_warnings;
|
||||
|
||||
global_inhibit_warnings = TRUE;
|
||||
// if there's a block, parse it and then restore old value
|
||||
if (Parse_optional_block()) {
|
||||
global_inhibit_warnings = flag_buf;
|
||||
return ENSURE_EOS;
|
||||
} else {
|
||||
return PARSE_REMAINDER;
|
||||
TODO: restore previous state after the current statement,
|
||||
do it like "!address" does it!
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// constants
|
||||
#define USERMSG_INITIALSIZE 80
|
||||
|
||||
@ -1291,6 +1317,7 @@ static enum eos throw_string(const char prefix[], void (*fn)(const char *))
|
||||
static enum eos po_debug(void)
|
||||
{
|
||||
// FIXME - make debug output depend on some cli switch
|
||||
// FIXME - add a number arg to this po so user can decide how much to display?
|
||||
return throw_string("!debug: ", throw_message);
|
||||
}
|
||||
// show info given in source code
|
||||
@ -1305,7 +1332,6 @@ static enum eos po_info(void)
|
||||
static enum eos po_warn(void)
|
||||
{
|
||||
return throw_string("!warn: ", Throw_warning);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -1398,11 +1424,14 @@ static struct ronode pseudo_opcode_tree[] = {
|
||||
PREDEFNODE("macro", po_macro),
|
||||
/* PREDEFNODE("trace", po_trace),
|
||||
PREDEFNODE("watch", po_watch), */
|
||||
// PREDEFNODE("nowarn", po_nowarn),
|
||||
// PREDEFNODE("debug", po_debug),
|
||||
// PREDEFNODE("info", po_info),
|
||||
PREDEFNODE("warn", po_warn),
|
||||
PREDEFNODE("error", po_error),
|
||||
PREDEFNODE("serious", po_serious),
|
||||
// PREDEFNODE("filestart", po_),
|
||||
// PREDEFNODE("filestop", po_),
|
||||
PREDEFNODE("eof", po_endoffile),
|
||||
PREDEF_END("endoffile", po_endoffile),
|
||||
// ^^^^ this marks the last element
|
||||
|
97
src/symbol.c
97
src/symbol.c
@ -283,51 +283,84 @@ void symbol_fix_forward_anon_name(boolean increment)
|
||||
}
|
||||
|
||||
// temporary buffer for base name while handling second part
|
||||
STRUCT_DYNABUF_REF(basename_db, 64);
|
||||
STRUCT_DYNABUF_REF(dyn_sym_name, 40);
|
||||
|
||||
// replace dynamic symbol name with its final version.
|
||||
// ("basename?indexsymbol" -> "basename4711")
|
||||
// replace dynamic symbol name with its final version, for example:
|
||||
// if "somesymbol" is 42 and "endsymbol" is 47,
|
||||
// basename?(somesymbol)middle?endsymbol
|
||||
// becomes
|
||||
// basename42middle47
|
||||
// on entry: GlobalDynaBuf holds base name, GotByte holds '?'
|
||||
// on exit: GlobalDynaBuf holds fixed name
|
||||
// return whether there was an error.
|
||||
#define NUMBUFSIZE 64 // large enough(tm) even for 64bit systems
|
||||
int symbol_fix_dynamic_name(void)
|
||||
{
|
||||
scope_t second_scope;
|
||||
struct symbol *second_symbol;
|
||||
char numbuf[NUMBUFSIZE];
|
||||
scope_t tmp_scope;
|
||||
struct symbol *tmp_symbol;
|
||||
boolean parenthesized;
|
||||
|
||||
if (GotByte != '?')
|
||||
Bug_found("NotQuestionMark", GotByte);
|
||||
GetByte(); // eat '?' character
|
||||
// remember base name
|
||||
dynabuf_clear(basename_db);
|
||||
dynabuf_add_string(basename_db, GLOBALDYNABUF_CURRENT);
|
||||
dynabuf_append(basename_db, '\0'); // terminate
|
||||
// read second part (CAUTION, this will overwrite GlobalDynaBuf!)
|
||||
if (Input_read_scope_and_symbol_name(&second_scope))
|
||||
return 1;
|
||||
|
||||
second_symbol = symbol_find(second_scope);
|
||||
if (second_symbol->object.type != &type_number) {
|
||||
Throw_error("Second part of dynamic symbol name is not a number.");
|
||||
return 1;
|
||||
// start with base name
|
||||
// (reading the inner parts will clobber GlobalDynaBuf, so copy it now)
|
||||
dynabuf_clear(dyn_sym_name);
|
||||
dynabuf_add_string(dyn_sym_name, GLOBALDYNABUF_CURRENT);
|
||||
|
||||
while (GotByte == '?') {
|
||||
GetByte(); // eat '?' character
|
||||
|
||||
if (GotByte == '(') {
|
||||
GetByte(); // eat '(' character
|
||||
parenthesized = TRUE;
|
||||
} else {
|
||||
parenthesized = FALSE;
|
||||
}
|
||||
|
||||
// read inner part
|
||||
if (Input_read_scope_and_symbol_name(&tmp_scope))
|
||||
return 1;
|
||||
|
||||
tmp_symbol = symbol_find(tmp_scope);
|
||||
tmp_symbol->has_been_read = TRUE;
|
||||
if (tmp_symbol->object.type == &type_number) {
|
||||
if (tmp_symbol->object.u.number.ntype != NUMTYPE_INT) {
|
||||
Throw_error("Inner part of dynamic symbol name is undefined or not integer.");
|
||||
return 1;
|
||||
}
|
||||
dynabuf_add_signed_long(dyn_sym_name, (long) tmp_symbol->object.u.number.val.intval);
|
||||
} else if (tmp_symbol->object.type == &type_string) {
|
||||
dynabuf_add_bytes(dyn_sym_name, tmp_symbol->object.u.string->payload, tmp_symbol->object.u.string->length);
|
||||
} else {
|
||||
Throw_error("Inner part of dynamic symbol name is neither number nor string.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// check for closing parenthesis
|
||||
if (parenthesized) {
|
||||
SKIPSPACE();
|
||||
if (GotByte == ')') {
|
||||
GetByte(); // eat ')'
|
||||
} else {
|
||||
Throw_error("Inner part of dynamic symbol name does not end with ')' character.");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// any more characters?
|
||||
while (BYTE_CONTINUES_KEYWORD(GotByte)) {
|
||||
DYNABUF_APPEND(dyn_sym_name, GotByte);
|
||||
GetByte();
|
||||
}
|
||||
}
|
||||
if (second_symbol->object.u.number.ntype != NUMTYPE_INT) {
|
||||
Throw_error("Second part of dynamic symbol name is undefined or not integer.");
|
||||
return 1;
|
||||
}
|
||||
second_symbol->has_been_read = TRUE;
|
||||
#if _BSD_SOURCE || _XOPEN_SOURCE >= 500 || _ISOC99_SOURCE || _POSIX_C_SOURCE >= 200112L
|
||||
snprintf(numbuf, NUMBUFSIZE, "%ld", (long) second_symbol->object.u.number.val.intval);
|
||||
#else
|
||||
sprintf(numbuf, "%ld", (long) second_symbol->object.u.number.val.intval);
|
||||
#endif
|
||||
dynabuf_append(dyn_sym_name, '\0');
|
||||
// FIXME: now the dynamically created symbol name should be checked for
|
||||
// its validity, because a string subst could have put anything in there!
|
||||
|
||||
// return basename and number in GlobalDynaBuf:
|
||||
dynabuf_clear(GlobalDynaBuf);
|
||||
dynabuf_add_string(GlobalDynaBuf, basename_db->buffer);
|
||||
dynabuf_add_string(GlobalDynaBuf, numbuf);
|
||||
dynabuf_add_string(GlobalDynaBuf, dyn_sym_name->buffer);
|
||||
dynabuf_append(GlobalDynaBuf, '\0');
|
||||
//printf("skipping '?' for <%s>\n", GLOBALDYNABUF_CURRENT);
|
||||
//printf("created dynamic symbol name <%s>\n", GLOBALDYNABUF_CURRENT);
|
||||
return 0;
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
#define RELEASE "0.97" // update before release FIXME
|
||||
#define CODENAME "Zem" // update before release
|
||||
#define CHANGE_DATE "29 Jan" // update before release FIXME
|
||||
#define CHANGE_DATE "6 Feb" // update before release FIXME
|
||||
#define CHANGE_YEAR "2024" // update before release
|
||||
//#define HOME_PAGE "http://home.pages.de/~mac_bacon/smorbrod/acme/"
|
||||
#define HOME_PAGE "http://sourceforge.net/p/acme-crossass/" // FIXME
|
||||
|
Loading…
Reference in New Issue
Block a user