diff --git a/src/flow.c b/src/flow.c index d4f3488..be08c43 100644 --- a/src/flow.c +++ b/src/flow.c @@ -85,8 +85,8 @@ void flow_forloop(struct for_loop *loop) loop_counter.type = &type_number; loop_counter.u.number.ntype = NUMTYPE_INT; loop_counter.u.number.flags = 0; - loop_counter.u.number.val.intval = loop->counter.first; - loop_counter.u.number.addr_refs = loop->counter.addr_refs; + loop_counter.u.number.val.intval = loop->u.counter.first; + loop_counter.u.number.addr_refs = loop->u.counter.addr_refs; // CAUTION: next line does not have power to change symbol type, but if // "symbol already defined" error is thrown, the type will still have // been changed. this was done so the code below has a counter var. @@ -102,23 +102,29 @@ void flow_forloop(struct for_loop *loop) symbol_set_force_bit(loop->symbol, loop->force_bit); loop_counter = loop->symbol->object; // update local copy with force bit loop->symbol->has_been_read = TRUE; // lock force bit - if (loop->use_old_algo) { - // old algo for old syntax: + switch (loop->algorithm) { + case FORALGO_OLD: // old algo for old syntax: // if count == 0, skip loop - if (loop->counter.last) { + if (loop->u.counter.last) { do { - loop_counter.u.number.val.intval += loop->counter.increment; + loop_counter.u.number.val.intval += loop->u.counter.increment; loop->symbol->object = loop_counter; // overwrite whole struct, in case some joker has re-assigned loop counter var parse_ram_block(&loop->block); - } while (loop_counter.u.number.val.intval < loop->counter.last); + } while (loop_counter.u.number.val.intval < loop->u.counter.last); } - } else { - // new algo for new syntax: + break; + case FORALGO_NEW: // new algo for new syntax: do { parse_ram_block(&loop->block); - loop_counter.u.number.val.intval += loop->counter.increment; + loop_counter.u.number.val.intval += loop->u.counter.increment; loop->symbol->object = loop_counter; // overwrite whole struct, in case some joker has re-assigned loop counter var - } while (loop_counter.u.number.val.intval != (loop->counter.last + loop->counter.increment)); + } while (loop_counter.u.number.val.intval != (loop->u.counter.last + loop->u.counter.increment)); + break; +// case FORALGO_ITER: // iterate over string/list contents: +// FIXME +// break; + default: + Bug_found("IllegalLoopAlgo", loop->algorithm); } // restore previous input: Input_now = outer_input; diff --git a/src/flow.h b/src/flow.h index 67fbcc6..ea573f3 100644 --- a/src/flow.h +++ b/src/flow.h @@ -17,16 +17,28 @@ struct block { }; // struct to pass "!for" loop stuff from pseudoopcodes.c to flow.c +enum foralgo { + FORALGO_OLD, // block can be skipped by passing zero, counter keeps value after block + FORALGO_NEW, // first and last value are given, counter is out of range after block + //FORALGO_ITER, // iterate over string/list contents (old algo could be changed to use this!) +}; struct for_loop { struct symbol *symbol; - bits force_bit; - boolean use_old_algo; - struct { - intval_t first, - last, - increment; - int addr_refs; // address reference count - } counter; + enum foralgo algorithm; + bits force_bit; // TODO - move to counter struct? illegal for iter algo! + union { + struct { + intval_t first, + last, + increment; // 1 or -1 + int addr_refs; // address reference count + } counter; +/* struct { + struct symbol *iterable; + int index; + add a "last" value here? or check len() in every iteration? + } iter;*/ + } u; struct block block; }; diff --git a/src/pseudoopcodes.c b/src/pseudoopcodes.c index a4adc17..8ca1a26 100644 --- a/src/pseudoopcodes.c +++ b/src/pseudoopcodes.c @@ -1011,6 +1011,7 @@ static enum eos po_ifndef(void) // now GotByte = illegal char // looping assembly ("!for"). has to be re-entrant. // old syntax: !for VAR, END { BLOCK } VAR counts from 1 to END // new syntax: !for VAR, START, END { BLOCK } VAR counts from START to END +// maybe future alternative: !for VAR in ITERABLE { BLOCK } VAR iterates over string/list contents static enum eos po_for(void) // now GotByte = illegal char { scope_t scope; @@ -1024,36 +1025,53 @@ static enum eos po_for(void) // now GotByte = illegal char loop.force_bit = Input_get_force_bit(); // skips spaces after loop.symbol = symbol_find(scope); // if not number, error will be reported on first assignment if (!Input_accept_comma()) { +#if 1 Throw_error(exception_syntax); return SKIP_REMAINDER; +#else + // check for "in" keyword + if (Input_read_and_lower_keyword() == 0) + return SKIP_REMAINDER; + + if (strcmp(GlobalDynaBuf->buffer, "in") != 0) { + Throw_error("Loop var must be followed by either \"in\" keyword or comma."); // TODO - add to docs! + return SKIP_REMAINDER; + } + if (loop.force_bit) { + Throw_error("Force bits can only be given to counters, not when iterating over string/list contents."); // TODO - add to docs! + return SKIP_REMAINDER; + } + loop.algorithm = FORALGO_ITER; + FIXME +#endif } ALU_defined_int(&intresult); // read first argument - loop.counter.addr_refs = intresult.addr_refs; + loop.u.counter.addr_refs = intresult.addr_refs; if (Input_accept_comma()) { // new format - yay! - loop.use_old_algo = FALSE; + loop.algorithm = FORALGO_NEW; if (config.wanted_version < VER_NEWFORSYNTAX) Throw_first_pass_warning("Found new \"!for\" syntax."); - loop.counter.first = intresult.val.intval; // use first argument + loop.u.counter.first = intresult.val.intval; // use first argument ALU_defined_int(&intresult); // read second argument - loop.counter.last = intresult.val.intval; // use second argument + loop.u.counter.last = intresult.val.intval; // use second argument // compare addr_ref counts and complain if not equal! if (config.warn_on_type_mismatch - && (intresult.addr_refs != loop.counter.addr_refs)) { + && (intresult.addr_refs != loop.u.counter.addr_refs)) { Throw_first_pass_warning("Wrong type for loop's END value - must match type of START value."); } - loop.counter.increment = (loop.counter.last < loop.counter.first) ? -1 : 1; + loop.u.counter.increment = (loop.u.counter.last < loop.u.counter.first) ? -1 : 1; } else { // old format - booo! - loop.use_old_algo = TRUE; + loop.algorithm = FORALGO_OLD; if (config.wanted_version >= VER_NEWFORSYNTAX) Throw_first_pass_warning("Found old \"!for\" syntax."); if (intresult.val.intval < 0) Throw_serious_error("Loop count is negative."); - loop.counter.first = 0; // CAUTION - old algo pre-increments and therefore starts with 1! - loop.counter.last = intresult.val.intval; // use given argument - loop.counter.increment = 1; + loop.u.counter.first = 0; // CAUTION - old algo pre-increments and therefore starts with 1! + loop.u.counter.last = intresult.val.intval; // use given argument + loop.u.counter.increment = 1; } if (GotByte != CHAR_SOB) Throw_serious_error(exception_no_left_brace); diff --git a/src/version.h b/src/version.h index 05c3146..d50ff21 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 "19 Oct" // update before release FIXME +#define CHANGE_DATE "21 Oct" // 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