mirror of
https://github.com/uffejakobsen/acme.git
synced 2025-04-05 01:30:08 +00:00
changed experimental feature "dynamic symbol names" to "dynamic <ANYTHING>"
git-svn-id: https://svn.code.sf.net/p/acme-crossass/code-0/trunk@394 4df02467-bbd4-4a76-a152-e7ce94205b78
This commit is contained in:
parent
fcfb32ed0a
commit
169541d452
13
src/alu.c
13
src/alu.c
@ -727,9 +727,6 @@ static int parse_octal_or_unpseudo(void) // now GotByte = '&'
|
||||
if (input_read_scope_and_symbol_name(&scope)) // now GotByte = illegal char
|
||||
return 1; // error (no string given)
|
||||
|
||||
if ((GotByte == '?') && symbol_fix_dynamic_name())
|
||||
return 1; // error
|
||||
|
||||
get_symbol_value(scope, GlobalDynaBuf->size - 1, unpseudo_count); // -1 to not count terminator
|
||||
// } else if (...) {
|
||||
// // anonymous symbol
|
||||
@ -994,10 +991,6 @@ static boolean expect_argument_or_monadic_operator(struct expression *expression
|
||||
|
||||
// here we need to put '.' into GlobalDynaBuf even though we have already skipped it:
|
||||
if (input_read_scope_and_symbol_name_KLUGED(&scope) == 0) { // now GotByte = illegal char
|
||||
if ((GotByte == '?') && symbol_fix_dynamic_name()) {
|
||||
alu_state = STATE_ERROR;
|
||||
break;//goto done;
|
||||
}
|
||||
get_symbol_value(scope, GlobalDynaBuf->size - 1, 0); // -1 to not count terminator, no unpseudo
|
||||
goto now_expect_dyadic_op; // ok
|
||||
}
|
||||
@ -1008,10 +1001,6 @@ static boolean expect_argument_or_monadic_operator(struct expression *expression
|
||||
case CHEAP_PREFIX: // cheap local symbol
|
||||
//printf("looking in cheap scope %d\n", section_now->cheap_scope);
|
||||
if (input_read_scope_and_symbol_name(&scope) == 0) { // now GotByte = illegal char
|
||||
if ((GotByte == '?') && symbol_fix_dynamic_name()) {
|
||||
alu_state = STATE_ERROR;
|
||||
break;//goto done;
|
||||
}
|
||||
get_symbol_value(scope, GlobalDynaBuf->size - 1, 0); // -1 to not count terminator, no unpseudo
|
||||
goto now_expect_dyadic_op; // ok
|
||||
}
|
||||
@ -1052,8 +1041,6 @@ static boolean expect_argument_or_monadic_operator(struct expression *expression
|
||||
// however, apart from that check above, function calls have nothing to do with
|
||||
// parentheses: "sin(x+y)" gets parsed just like "not(x+y)".
|
||||
} else {
|
||||
if (GotByte == '?')
|
||||
symbol_fix_dynamic_name();
|
||||
get_symbol_value(SCOPE_GLOBAL, GlobalDynaBuf->size - 1, 0); // no prefix, -1 to not count terminator, no unpseudo
|
||||
goto now_expect_dyadic_op;
|
||||
}
|
||||
|
@ -260,9 +260,6 @@ static void parse_symbol_definition(scope_t scope)
|
||||
{
|
||||
bits force_bit;
|
||||
|
||||
if (GotByte == '?')
|
||||
symbol_fix_dynamic_name();
|
||||
|
||||
force_bit = parser_get_force_bit(); // skips spaces after (yes, force bit is allowed for label definitions)
|
||||
if (GotByte == '=') {
|
||||
// explicit symbol definition (symbol = <something>)
|
||||
|
159
src/input.c
159
src/input.c
@ -310,12 +310,122 @@ static char get_processed_from_file(void)
|
||||
}
|
||||
}
|
||||
|
||||
int subst_chars_left = 0; // number of bytes left in buffer
|
||||
boolean subst_enabled = TRUE; // flag to disable substing (for example while substing, or when copying block to RAM)
|
||||
const char *subst_read_ptr = NULL; // pointer to read bytes from
|
||||
STRUCT_DYNABUF_REF(subst_buffer, 40); // buffer to hold substitution result
|
||||
|
||||
// fetch next byte from buffer
|
||||
static char subst_get_char(void)
|
||||
{
|
||||
if (subst_chars_left-- == 0)
|
||||
BUG("NoSubstLeft", 0);
|
||||
return *(subst_read_ptr++);
|
||||
}
|
||||
// read symbol name from source and then setup substitution buffer with contents
|
||||
// of symbol (string or integer). int is converted to decimal digits.
|
||||
// example:
|
||||
// if "somesymbol" is 42 and "endsymbol" is 47,
|
||||
// basename?(somesymbol)middle?endsymbol=9
|
||||
// becomes
|
||||
// basename42middle47=9
|
||||
// this would happen in two steps,
|
||||
// the first result would be "42m" and the second would be "47="
|
||||
static void subst_substitute(void) // now GotByte = '?'
|
||||
{
|
||||
scope_t tmp_scope;
|
||||
struct symbol *tmp_symbol;
|
||||
boolean parenthesized;
|
||||
|
||||
if (GotByte != '?')
|
||||
BUG("NotQuestionMark", GotByte);
|
||||
|
||||
GetByte(); // eat '?' character
|
||||
// handle parentheses
|
||||
if (GotByte == '(') {
|
||||
GetByte(); // eat '(' character
|
||||
parenthesized = TRUE;
|
||||
} else {
|
||||
parenthesized = FALSE;
|
||||
}
|
||||
|
||||
// reading symbol name will clobber GlobalDynaBuf, so we'll use our own
|
||||
// buffer as tmp storage:
|
||||
dynabuf_clear(subst_buffer);
|
||||
dynabuf_add_bytes(subst_buffer, GlobalDynaBuf->buffer, GlobalDynaBuf->size);
|
||||
|
||||
// read symbol name into GlobalDynaBuf and get symbol ptr:
|
||||
if (input_read_scope_and_symbol_name(&tmp_scope)) {
|
||||
tmp_symbol = NULL; // remember failure (check after restoring GlobalDynaBuf)
|
||||
} else {
|
||||
tmp_symbol = symbol_find(tmp_scope); // reads name from GlobalDynaBuf
|
||||
tmp_symbol->has_been_read = TRUE;
|
||||
}
|
||||
|
||||
// restore previous contents of GlobalDynaBuf:
|
||||
dynabuf_clear(GlobalDynaBuf);
|
||||
dynabuf_add_bytes(GlobalDynaBuf, subst_buffer->buffer, subst_buffer->size);
|
||||
|
||||
// read symbol and put value into subst buffer
|
||||
dynabuf_clear(subst_buffer);
|
||||
if (tmp_symbol == NULL) {
|
||||
goto fail; // input_read_scope_and_symbol_name will have thrown error
|
||||
}
|
||||
if (tmp_symbol->object.type == NULL) {
|
||||
Throw_error("Substitution symbol is undefined.");
|
||||
// FIXME - set type to undefined int, just to make sure later refs via type do not crash!
|
||||
goto fail;
|
||||
} else if (tmp_symbol->object.type == &type_number) {
|
||||
if (tmp_symbol->object.u.number.ntype != NUMTYPE_INT) {
|
||||
Throw_error("Substitution symbol is undefined or not integer.");
|
||||
goto fail;
|
||||
}
|
||||
dynabuf_add_signed_long(subst_buffer, (long) tmp_symbol->object.u.number.val.intval);
|
||||
} else if (tmp_symbol->object.type == &type_string) {
|
||||
dynabuf_add_bytes(subst_buffer, tmp_symbol->object.u.string->payload, tmp_symbol->object.u.string->length);
|
||||
} else {
|
||||
Throw_error("Substitution symbol is neither number nor string.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// check for closing parenthesis
|
||||
if (parenthesized) {
|
||||
SKIPSPACE();
|
||||
if (GotByte == ')') {
|
||||
GetByte(); // eat ')'
|
||||
} else {
|
||||
Throw_error("Substitution does not end with ')' character.");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
// now append the delimiter character to the buffer, otherwise it would
|
||||
// be lost because reading from the buffer keeps clobbering GotByte:
|
||||
dynabuf_append(subst_buffer, GotByte);
|
||||
subst_chars_left = subst_buffer->size;
|
||||
subst_read_ptr = subst_buffer->buffer;
|
||||
// FIXME: do we need checks for "buffer contains braces, colon, EOS, ..."
|
||||
// or is it enough to add "user, do not try stupid things" to docs?
|
||||
return;
|
||||
fail:
|
||||
dynabuf_clear(subst_buffer);
|
||||
dynabuf_append(subst_buffer, GotByte);
|
||||
subst_chars_left = subst_buffer->size;
|
||||
subst_read_ptr = subst_buffer->buffer;
|
||||
}
|
||||
|
||||
// This function delivers the next byte from the currently active byte source
|
||||
// in shortened high-level format. FIXME - use fn ptr?
|
||||
// When inside quotes, use input_quoted_to_dynabuf() instead!
|
||||
// CAUTION, symbol substitutions cause this fn to be called recursively!
|
||||
char GetByte(void)
|
||||
{
|
||||
// for (;;) {
|
||||
// substitution buffer has priority, so if anything is in there,
|
||||
// deliver that:
|
||||
if (subst_chars_left) {
|
||||
GotByte = subst_get_char();
|
||||
} else {
|
||||
// otherwise get a byte from file/ram:
|
||||
|
||||
// If byte source is RAM, then no conversions are
|
||||
// necessary, because in RAM the source already has
|
||||
// high-level format
|
||||
@ -333,14 +443,33 @@ char GetByte(void)
|
||||
default:
|
||||
BUG("IllegalInputSrc", current_input.srctype);
|
||||
}
|
||||
// // if start-of-line was read, increment line counter and repeat
|
||||
// if (GotByte != CHAR_SOL)
|
||||
// return GotByte;
|
||||
// current_input.location.line_number++;
|
||||
// }
|
||||
|
||||
if (GotByte == CHAR_SOL)
|
||||
current_input.location.line_number++;
|
||||
return GotByte;
|
||||
}
|
||||
// check for '?' substitutions
|
||||
if ((GotByte == '?') && (subst_enabled) && (subst_chars_left == 0)) {
|
||||
// start a new substitution
|
||||
/*
|
||||
the check for "subst_chars_left" is needed because characters from the buffer
|
||||
are not allowed to start a new substitution, except for the very last char!
|
||||
the last char wasn't part of the result, it was the original delimiter. example:
|
||||
cd = "xyz"
|
||||
!info ab?cd?ef
|
||||
the first '?' causes a lookup for "cd" and will write the result "xyz" to the
|
||||
buffer. then the second '?' (now GotByte because it was the keyword delimiter)
|
||||
will be appended to the buffer because otherwise it would get lost during buffer
|
||||
reads.
|
||||
*/
|
||||
subst_enabled = FALSE; // no substitutions in substitutions!
|
||||
subst_substitute(); // do the actual work
|
||||
subst_enabled = TRUE; // back to previous state
|
||||
// because the delimiter is put into the buffer, we know the
|
||||
// buffer isn't empty, even if the substitution result was "".
|
||||
// so this is allowed:
|
||||
GotByte = subst_get_char();
|
||||
}
|
||||
return GotByte;
|
||||
}
|
||||
|
||||
// This function delivers the next byte from the currently active byte source
|
||||
@ -350,6 +479,13 @@ static void get_quoted_byte(void)
|
||||
{
|
||||
int from_file; // must be an int to catch EOF
|
||||
|
||||
// substitution buffer has priority, so if anything is in there,
|
||||
// deliver that:
|
||||
if (subst_chars_left) {
|
||||
GotByte = subst_get_char();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (current_input.srctype) {
|
||||
case INPUTSRC_RAM:
|
||||
// if byte source is RAM, then no conversion is necessary,
|
||||
@ -518,6 +654,10 @@ static void block_to_dynabuf(void)
|
||||
{
|
||||
char byte;
|
||||
int depth = 1; // to find matching block end
|
||||
boolean substflagbuf = subst_enabled;
|
||||
|
||||
// make sure not to subst while reading block (should only be done while parsing)
|
||||
subst_enabled = FALSE;
|
||||
|
||||
// prepare global dynamic buffer
|
||||
dynabuf_clear(GlobalDynaBuf);
|
||||
@ -543,6 +683,9 @@ static void block_to_dynabuf(void)
|
||||
break;
|
||||
}
|
||||
} while (depth);
|
||||
|
||||
// restore subst state
|
||||
subst_enabled = substflagbuf;
|
||||
}
|
||||
// Skip block (starting with next byte, so call directly after reading opening brace).
|
||||
// After calling this function, GotByte holds '}'. Unless EOF was found first,
|
||||
@ -656,7 +799,7 @@ int parser_read_keyword(void)
|
||||
// Clear dynamic buffer, then append to it until an illegal (for a keyword)
|
||||
// character is read. Zero-terminate the string, then convert to lower case.
|
||||
// Return its length (without terminator).
|
||||
// Zero lengths will produce a "missing string" error.
|
||||
// Zero lengths will produce a "missing string" error. (FIXME - change error msg!)
|
||||
int parser_read_and_lower_keyword(void)
|
||||
{
|
||||
int length;
|
||||
|
83
src/symbol.c
83
src/symbol.c
@ -283,86 +283,3 @@ void symbol_fix_forward_anon_name(boolean increment)
|
||||
if (increment)
|
||||
counter_symbol->object.u.number.val.intval++;
|
||||
}
|
||||
|
||||
// temporary buffer for base name while handling second part
|
||||
STRUCT_DYNABUF_REF(dyn_sym_name, 40);
|
||||
|
||||
// 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.
|
||||
int symbol_fix_dynamic_name(void)
|
||||
{
|
||||
scope_t tmp_scope;
|
||||
struct symbol *tmp_symbol;
|
||||
boolean parenthesized;
|
||||
|
||||
if (GotByte != '?')
|
||||
BUG("NotQuestionMark", GotByte);
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
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, dyn_sym_name->buffer);
|
||||
dynabuf_append(GlobalDynaBuf, '\0');
|
||||
//printf("created dynamic symbol name <%s>\n", GLOBALDYNABUF_CURRENT);
|
||||
return 0;
|
||||
}
|
||||
|
@ -58,9 +58,5 @@ extern void symbols_vicelabels(FILE *fd);
|
||||
// so it references the *next* anonymous forward label definition.
|
||||
extern void symbol_fix_forward_anon_name(boolean increment);
|
||||
|
||||
// replace name of dynamic symbol with its final version.
|
||||
// return whether there was an error.
|
||||
extern int symbol_fix_dynamic_name(void);
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
#define RELEASE "0.97" // update before release FIXME
|
||||
#define CODENAME "Zem" // update before release
|
||||
#define CHANGE_DATE "29 Jul" // update before release FIXME
|
||||
#define CHANGE_DATE "30 Jul" // 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
|
||||
|
3
testing/errors/subst0.a
Normal file
3
testing/errors/subst0.a
Normal file
@ -0,0 +1,3 @@
|
||||
*=$1000
|
||||
base? ; -> "no string given"
|
||||
nop
|
@ -1,3 +1,3 @@
|
||||
*=$1000
|
||||
;sub= we do not define sub at all
|
||||
base?sub nop ; -> "neither number nor string"
|
||||
base?sub nop ; -> "Substitution symbol is undefined"
|
||||
|
Loading…
x
Reference in New Issue
Block a user