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