diff --git a/src/alu.c b/src/alu.c index e53d189..900690b 100644 --- a/src/alu.c +++ b/src/alu.c @@ -351,7 +351,14 @@ static void get_symbol_value(scope_t scope, char optional_prefix_char, size_t na struct object *arg; // if the symbol gets created now, mark it as unsure - symbol = symbol_find(scope, NUMBER_EVER_UNDEFINED); // TODO - split into "find" and "if NULL object, make into undefined int" + symbol = symbol_find(scope); + if (symbol->object.type == NULL) { + // finish symbol item by making it an undefined int + symbol->object.type = &type_int; + symbol->object.u.number.flags = NUMBER_EVER_UNDEFINED; + symbol->object.u.number.addr_refs = 0; + symbol->object.u.number.val.intval = 0; + } // first push on arg stack, so we have a local copy we can "unpseudopc" arg = &arg_stack[arg_sp++]; *arg = symbol->object; diff --git a/src/global.c b/src/global.c index 026c18b..3e1c805 100644 --- a/src/global.c +++ b/src/global.c @@ -168,16 +168,17 @@ static void set_label(scope_t scope, int stat_flags, int force_bit, boolean chan struct object result; struct symbol *symbol; - symbol = symbol_find(scope, force_bit); // TODO - split into "find", "forcebit handling", "if NULL object, make int" and "if not int, complain" - // label definition if ((stat_flags & SF_FOUND_BLANK) && config.warn_on_indented_labels) Throw_first_pass_warning("Label name not in leftmost column."); + symbol = symbol_find(scope); + // label definition vcpu_read_pc(&pc); // FIXME - if undefined, check pass.complain_about_undefined and maybe throw "value not defined"! result.type = &type_int; result.u.number.flags = pc.flags & NUMBER_IS_DEFINED; result.u.number.val.intval = pc.val.intval; result.u.number.addr_refs = pc.addr_refs; + symbol_forcebit(symbol, force_bit); // TODO - "if NULL object, make int" and "if not int, complain" symbol_set_object(symbol, &result, change_allowed); // FIXME - "backward anon allows number redef" is different from "!set allows object redef"! symbol->pseudopc = pseudopc_get_context(); // global labels must open new scope for cheap locals @@ -186,29 +187,55 @@ static void set_label(scope_t scope, int stat_flags, int force_bit, boolean chan } +// call with symbol name in GlobalDynaBuf and GotByte == '=' +// "po_set" is for "!set" pseudo opcode, so changes are allowed +void parse_assignment(scope_t scope, int force_bit, boolean po_set) +{ + struct symbol *symbol; + struct object result; + + GetByte(); // eat '=' + symbol = symbol_find(scope); + ALU_any_result(&result); + // if wanted, mark as address reference + if (typesystem_says_address()) { + // FIXME - checking types explicitly is ugly... + if ((result.type == &type_int) + || (result.type == &type_float)) + result.u.number.addr_refs = 1; + } + // FIXME - force bit can only be used if result is number! check! + symbol_forcebit(symbol, force_bit); + // if this was called by !set, new force bit replaces old one: + if (po_set) { + // clear symbol's force bits and set new ones + // (but only do this for numbers!) + if (((symbol->object.type == &type_int) || (symbol->object.type == &type_float)) + && ((result.type == &type_int) || (result.type == &type_float))) { + symbol->object.u.number.flags &= ~(NUMBER_FORCEBITS | NUMBER_FITS_BYTE); + if (force_bit) { + symbol->object.u.number.flags |= force_bit; + result.u.number.flags &= ~(NUMBER_FORCEBITS | NUMBER_FITS_BYTE); + } + } + // FIXME - take a good look at the flags handling above and in the fn called below and clean this up! + } + symbol_set_object(symbol, &result, po_set); +} + + // parse symbol definition (can be either global or local, may turn out to be a label). // name must be held in GlobalDynaBuf. static void parse_symbol_definition(scope_t scope, int stat_flags) { struct object result; struct symbol *symbol; - int force_bit = Input_get_force_bit(); // skips spaces after - // FIXME - force bit is allowed for label definitions?! + int force_bit; + force_bit = Input_get_force_bit(); // skips spaces after (yes, force bit is allowed for label definitions) if (GotByte == '=') { // explicit symbol definition (symbol = ) - symbol = symbol_find(scope, force_bit); // FIXME - split into "find", "forcebit handling", "if not NULL object, types must be equal"... - // symbol = parsed value - GetByte(); // skip '=' - ALU_any_result(&result); - // if wanted, mark as address reference - if (typesystem_says_address()) { - // FIXME - checking types explicitly is ugly... - if ((result.type == &type_int) - || (result.type == &type_float)) - result.u.number.addr_refs = 1; - } - symbol_set_object(symbol, &result, FALSE); + parse_assignment(scope, force_bit, FALSE); Input_ensure_EOS(); } else { // implicit symbol definition (label) @@ -220,8 +247,11 @@ static void parse_symbol_definition(scope_t scope, int stat_flags) // Parse global symbol definition or assembler mnemonic static void parse_mnemo_or_global_symbol_def(int *statement_flags) { + boolean is_mnemonic; + + is_mnemonic = CPU_state.type->keyword_is_mnemonic(Input_read_keyword()); // It is only a label if it isn't a mnemonic - if ((CPU_state.type->keyword_is_mnemonic(Input_read_keyword()) == FALSE) + if ((!is_mnemonic) && first_label_of_statement(statement_flags)) { // Now GotByte = illegal char // 04 Jun 2005: this fix should help to explain "strange" error messages. @@ -297,7 +327,7 @@ void Parse_until_eob_or_eof(void) statement_flags = 0; // no "label = pc" definition yet typesystem_force_address_statement(FALSE); // Parse until end of statement. Only loops if statement - // contains "label = pc" definition and something else; or + // contains implicit label definition (=pc) and something else; or // if "!ifdef/ifndef" is true/false, or if "!addr" is used without block. do { // check for pseudo opcodes was moved out of switch, diff --git a/src/global.h b/src/global.h index 62508e3..24b6bc0 100644 --- a/src/global.h +++ b/src/global.h @@ -134,6 +134,9 @@ do { \ extern void config_default(struct config *conf); // allocate memory and die if not available extern void *safe_malloc(size_t amount); +// call with symbol name in GlobalDynaBuf and GotByte == '=' +// "po_set" is for "!set" pseudo opcode, so changes are allowed +extern void parse_assignment(scope_t scope, int force_bit, boolean po_set); // Parse block, beginning with next byte. // End reason (either CHAR_EOB or CHAR_EOF) can be found in GotByte afterwards // Has to be re-entrant. diff --git a/src/macro.c b/src/macro.c index 24316f3..ff50035 100644 --- a/src/macro.c +++ b/src/macro.c @@ -250,8 +250,8 @@ void Macro_parse_call(void) // Now GotByte = dot or first char of macro name // internal_name = MacroTitle ARG_SEPARATOR (grows to signature) // Accept n>=0 comma-separated arguments before CHAR_EOS. // Valid argument formats are: - // EXPRESSION (everything that does NOT start with '~' - // ~SYMBOL + // ~SYMBOL call by ref + // EXPRESSION call by value (everything that does NOT start with '~') // now GotByte = non-space if (GotByte != CHAR_EOS) { // any at all? do { @@ -263,10 +263,10 @@ void Macro_parse_call(void) // Now GotByte = dot or first char of macro name if (GotByte == REFERENCE_CHAR) { // read call-by-reference arg DynaBuf_append(internal_name, ARGTYPE_REF); - GetByte(); // skip '~' character + GetByte(); // eat '~' Input_read_scope_and_keyword(&symbol_scope); // GotByte = illegal char - arg_table[arg_count].symbol = symbol_find(symbol_scope, 0); // FIXME - do not default to undefined int! + arg_table[arg_count].symbol = symbol_find(symbol_scope); // CAUTION, object type may be NULL! } else { // read call-by-value arg DynaBuf_append(internal_name, ARGTYPE_VALUE); @@ -317,22 +317,21 @@ void Macro_parse_call(void) // Now GotByte = dot or first char of macro name // In both cases, GlobalDynaBuf may be used. if (GotByte == REFERENCE_CHAR) { // assign call-by-reference arg - GetByte(); // skip '~' character + GetByte(); // eat '~' Input_read_scope_and_keyword(&symbol_scope); // create new tree node and link existing symbol struct from arg list to it if ((Tree_hard_scan(&symbol_node, symbols_forest, symbol_scope, TRUE) == FALSE) && (FIRST_PASS)) Throw_error("Macro parameter twice."); - symbol_node->body = arg_table[arg_count].symbol; + symbol_node->body = arg_table[arg_count].symbol; // CAUTION, object type may be NULL } else { // assign call-by-value arg Input_read_scope_and_keyword(&symbol_scope); - symbol = symbol_find(symbol_scope, 0); // FIXME - split into "find", "ensure freshly created" -// FIXME - add a possibility to symbol_find to make it possible to find out -// whether symbol was just created. Then check for the same error message here -// as above ("Macro parameter twice."). + symbol = symbol_find(symbol_scope); +// FIXME - find out if symbol was just created. +// Then check for the same error message here as above ("Macro parameter twice."). // TODO - on the other hand, this would rule out globals as args (stupid anyway, but not illegal yet!) - symbol->object = arg_table[arg_count].result; // FIXME - this assignment redefines globals without throwing errors! + symbol->object = arg_table[arg_count].result; // FIXME - this assignment redefines globals/whatever without throwing errors! } ++arg_count; } while (Input_accept_comma()); diff --git a/src/pseudoopcodes.c b/src/pseudoopcodes.c index 05a7f0f..cfad295 100644 --- a/src/pseudoopcodes.c +++ b/src/pseudoopcodes.c @@ -739,37 +739,19 @@ Throw_serious_error("Not yet"); // FIXME // (re)set symbol static enum eos po_set(void) // now GotByte = illegal char { - struct object result; - int force_bit; - struct symbol *symbol; - scope_t scope; + scope_t scope; + int force_bit; if (Input_read_scope_and_keyword(&scope) == 0) // skips spaces before - // now GotByte = illegal char - return SKIP_REMAINDER; + return SKIP_REMAINDER; // zero length force_bit = Input_get_force_bit(); // skips spaces after - symbol = symbol_find(scope, force_bit); // FIXME - split into "find" and "handle forcebits", remove the "default to undefined int" part! if (GotByte != '=') { Throw_error(exception_syntax); return SKIP_REMAINDER; } - // symbol = parsed value - GetByte(); // proceed with next char - ALU_any_result(&result); - // clear symbol's force bits and set new ones - // (but only do this for numbers!) - if (((symbol->object.type == &type_int) || (symbol->object.type == &type_float)) - && ((result.type == &type_int) || (result.type == &type_float))) { - symbol->object.u.number.flags &= ~(NUMBER_FORCEBITS | NUMBER_FITS_BYTE); - if (force_bit) { - symbol->object.u.number.flags |= force_bit; - result.u.number.flags &= ~(NUMBER_FORCEBITS | NUMBER_FITS_BYTE); - } - } - // FIXME - take a good look at the flags handling above and in the fn called below and clean this up! - symbol_set_object(symbol, &result, TRUE); + parse_assignment(scope, force_bit, TRUE); return ENSURE_EOS; } @@ -1053,11 +1035,12 @@ static enum eos po_for(void) // now GotByte = illegal char struct for_loop loop; if (Input_read_scope_and_keyword(&scope) == 0) // skips spaces before - return SKIP_REMAINDER; + return SKIP_REMAINDER; // zero length // now GotByte = illegal char force_bit = Input_get_force_bit(); // skips spaces after - loop.symbol = symbol_find(scope, force_bit); // FIXME - split into "find" and "handle force bit". if type is not NULL, complain if not number! + loop.symbol = symbol_find(scope); // FIXME - if type is not NULL, complain if not number! + symbol_forcebit(loop.symbol, force_bit); if (!Input_accept_comma()) { Throw_error(exception_syntax); return SKIP_REMAINDER; @@ -1066,7 +1049,8 @@ static enum eos po_for(void) // now GotByte = illegal char ALU_defined_int(&intresult); // read first argument loop.counter.addr_refs = intresult.addr_refs; if (Input_accept_comma()) { - loop.use_old_algo = FALSE; // new format - yay! + // new format - yay! + loop.use_old_algo = FALSE; if (config.wanted_version < VER_NEWFORSYNTAX) Throw_first_pass_warning("Found new \"!for\" syntax."); loop.counter.first = intresult.val.intval; // use first argument @@ -1079,7 +1063,8 @@ static enum eos po_for(void) // now GotByte = illegal char } loop.counter.increment = (loop.counter.last < loop.counter.first) ? -1 : 1; } else { - loop.use_old_algo = TRUE; // old format - booo! + // old format - booo! + loop.use_old_algo = TRUE; if (config.wanted_version >= VER_NEWFORSYNTAX) Throw_first_pass_warning("Found old \"!for\" syntax."); if (intresult.val.intval < 0) diff --git a/src/symbol.c b/src/symbol.c index fbbd7b2..97ac2ad 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -107,8 +107,9 @@ static void dump_vice_unusednonaddress(struct rwnode *node, FILE *fd) } -// temporary helper function to properly refactor this mess -static struct symbol *temp_find(scope_t scope) +// search for symbol. if it does not exist, create with NULL object (CAUTION!). +// the symbol name must be held in GlobalDynaBuf. +struct symbol *symbol_find(scope_t scope) { struct rwnode *node; struct symbol *symbol; @@ -132,51 +133,27 @@ static struct symbol *temp_find(scope_t scope) return symbol; // now symbol->object.type can be tested to see if this was freshly created. // CAUTION: this only works if caller always sets a type pointer after checking! if NULL is kept, the struct still looks new later on... } -// search for symbol. create if nonexistant. if created, give it flags "flags". -// the symbol name must be held in GlobalDynaBuf. -/* -FIXME - to get lists/strings to work, this can no longer create an int by default! -maybe get rid of "int flags" and use some "struct object *default" instead? -called by; -alu.c - get_symbol_value (here it's okay to create an undefined int) -global.c - set_label implicit symbol definition (gets assigned pc, so int is ok) - parse_symbol_definition explicit symbol definition -macro.c - Macro_parse_call early to build array of outer refs in case of call-by-ref - Macro_parse_call later to lookup inner symbols in case of call-by-value -symbol.c - symbol_define - symbol_fix_forward_anon_name -*/ -struct symbol *symbol_find(scope_t scope, int flags) // FIXME - "flags" is either 0 or UNDEFINED or a forcebit, right? move UNDEFINED and forcebit stuff elsewhere! -{ - struct symbol *symbol; - int new_force_bits; - symbol = temp_find(scope); + +// FIXME - merge with function below! +void symbol_forcebit(struct symbol *symbol, int force_bit) +{ // if symbol has no object assigned to it, make it an int if (symbol->object.type == NULL) { // finish empty symbol item symbol->object.type = &type_int; - symbol->object.u.number.flags = flags; + symbol->object.u.number.flags = force_bit; symbol->object.u.number.addr_refs = 0; symbol->object.u.number.val.intval = 0; } else { // make sure the force bits don't clash if ((symbol->object.type == &type_int) || (symbol->object.type == &type_float)) { - new_force_bits = flags & NUMBER_FORCEBITS; - if (new_force_bits) - if ((symbol->object.u.number.flags & NUMBER_FORCEBITS) != new_force_bits) - Throw_error("Too late for postfix."); + if ((symbol->object.u.number.flags & NUMBER_FORCEBITS) != force_bit) + Throw_error("Too late for postfix."); } } - return symbol; } - - // assign value to symbol. the function acts upon the symbol's flag bits and // produces an error if needed. // TODO - split checks into two parts: first deal with object type. in case of number, then check value/flags/whatever @@ -237,8 +214,8 @@ void symbol_define(intval_t value) result.type = &type_int; result.u.number.flags = NUMBER_IS_DEFINED; result.u.number.val.intval = value; - symbol = symbol_find(SCOPE_GLOBAL, 0); - symbol_set_object(symbol, &result, TRUE); + symbol = symbol_find(SCOPE_GLOBAL); + symbol->object = result; } @@ -268,6 +245,12 @@ void symbols_vicelabels(FILE *fd) // references the *next* anonymous forward label definition. The tricky bit is, // each name length would need its own counter. But hey, ACME's real quick in // finding symbols, so I'll just abuse the symbol system to store those counters. +// example: +// forward anon name is "+++" +// we look up that symbol's value in the current local scope -> $12 +// we attach hex digits to name -> "+++21" +// that's the name of the symbol that _actually_ contains the address +// caller sets "increment" to TRUE for writing, FALSE for reading void symbol_fix_forward_anon_name(boolean increment) { struct symbol *counter_symbol; @@ -275,10 +258,17 @@ void symbol_fix_forward_anon_name(boolean increment) // terminate name, find "counter" symbol and read value DynaBuf_append(GlobalDynaBuf, '\0'); - counter_symbol = symbol_find(section_now->local_scope, 0); - // sanity check: it must be an int! - if (counter_symbol->object.type != &type_int) + counter_symbol = symbol_find(section_now->local_scope); + if (counter_symbol->object.type == NULL) { + // finish freshly created symbol item + counter_symbol->object.type = &type_int; + counter_symbol->object.u.number.flags = NUMBER_IS_DEFINED; + counter_symbol->object.u.number.addr_refs = 0; + counter_symbol->object.u.number.val.intval = 0; + } else if (counter_symbol->object.type != &type_int) { + // sanity check: it must be an int! Bug_found("ForwardAnonCounterNotInt", 0); + } // make sure it gets reset to zero in each new pass if (counter_symbol->pass != pass.number) { counter_symbol->pass = pass.number; diff --git a/src/symbol.h b/src/symbol.h index bbf7fee..3dc7447 100644 --- a/src/symbol.h +++ b/src/symbol.h @@ -31,9 +31,11 @@ extern struct rwnode *symbols_forest[]; // trees (because of 8-bit hash) // function acts upon the symbol's flag bits and produces an error if needed. extern void symbol_set_object(struct symbol *symbol, struct object *new_obj, boolean change_allowed); -// search for symbol. create if nonexistant. if created, assign flags. -// name must be held in GlobalDynaBuf. -extern struct symbol *symbol_find(scope_t, int flags); +// search for symbol. if it does not exist, create with NULL object (CAUTION!). +// the symbol name must be held in GlobalDynaBuf. +extern struct symbol *symbol_find(scope_t scope); +// FIXME +extern void symbol_forcebit(struct symbol *symbol, int force_bit); // set global symbol to value, no questions asked (for "-D" switch) // name must be held in GlobalDynaBuf. extern void symbol_define(intval_t value); diff --git a/src/version.h b/src/version.h index f407018..f4a8f1c 100644 --- a/src/version.h +++ b/src/version.h @@ -9,7 +9,7 @@ #define RELEASE "0.96.5" // update before release FIXME #define CODENAME "Fenchurch" // update before release -#define CHANGE_DATE "3 June" // update before release FIXME +#define CHANGE_DATE "5 June" // update before release FIXME #define CHANGE_YEAR "2020" // update before release //#define HOME_PAGE "http://home.pages.de/~mac_bacon/smorbrod/acme/" #define HOME_PAGE "http://sourceforge.net/p/acme-crossass/" // FIXME