From c6739be77d9060b072368b455ab665e3fb9fc1a0 Mon Sep 17 00:00:00 2001 From: marcobaye Date: Tue, 6 Feb 2024 21:56:52 +0000 Subject: [PATCH] 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 --- src/dynabuf.c | 41 ++++++++++++++++--- src/dynabuf.h | 18 ++++++--- src/pseudoopcodes.c | 31 ++++++++++++++- src/symbol.c | 97 ++++++++++++++++++++++++++++++--------------- src/version.h | 2 +- 5 files changed, 143 insertions(+), 46 deletions(-) diff --git a/src/dynabuf.c b/src/dynabuf.c index a61780f..5eaef6b 100644 --- a/src/dynabuf.c +++ b/src/dynabuf.c @@ -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, diff --git a/src/dynabuf.h b/src/dynabuf.h index 4e5634b..9e00a13 100644 --- a/src/dynabuf.h +++ b/src/dynabuf.h @@ -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); diff --git a/src/pseudoopcodes.c b/src/pseudoopcodes.c index cc65991..918461e 100644 --- a/src/pseudoopcodes.c +++ b/src/pseudoopcodes.c @@ -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 diff --git a/src/symbol.c b/src/symbol.c index 51d199d..b031ce1 100644 --- a/src/symbol.c +++ b/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; } diff --git a/src/version.h b/src/version.h index 3372070..2e122f2 100644 --- a/src/version.h +++ b/src/version.h @@ -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