[Richard Suchenwirth] 2013-11-30 - [dis2asm], the converter from the language produced by tcl::unsupported::'''disassemble'''. to the one accepted by tcl::unsupported::'''assemble''', [TAL], had a troublesome issue: it could do [for] and [while] loops, but not [foreach]. Disassembling a foreach loop came out as % aproc f x {foreach j $x {puts $j}} ByteCode 0x0x9eaad68, refCt 1, epoch 16, interp 0x0x9e057a0 (epoch 16) Source "foreach j $x {puts $j}" Cmds 2, src 22, inst 29, litObjs 2, aux 1, stkDepth 2, code/src 0.00 Proc 0x0x9ebb820, refCt 1, args 1, compiled locals 4 slot 0, scalar, arg, "x" slot 1, scalar, temp slot 2, scalar, temp slot 3, scalar, "j" Exception ranges 1, depth 1: 0: level 0, loop, pc 17-22, continue 10, break 26 Commands 2: 1: pc 0-27, src 0-21 2: pc 17-22, src 14-20 Command 1: "foreach j $x {puts $j}" (0) loadScalar1 %v0 # var "x" (2) storeScalar1 %v1 # temp var 1 (4) pop (5) foreach_start4 0 [data=[%v1], loop=%v2 it%v1 [%v3]] (10) foreach_step4 0 [data=[%v1], loop=%v2 it%v1 [%v3]] (15) jumpFalse1 +11 # pc 26 Command 2: "puts $j" (17) push1 0 # "puts" (19) loadScalar1 %v3 # var "j" (21) invokeStk1 2 (23) pop (24) jump1 -14 # pc 10 (26) push1 1 # "" (28) done and in [TAL] there are no instructions ''foreach_start'' (see (5)) or ''foreach_step'' (see (10)). But I wanted them so badly... Luckily it was weekend, and I had some time on my hands - so I made this my fun project of the day. At first, I manually coded a working solution in TAL: proc foreachtest {x {_i ""} {_l ""}} {asm { load x listLength store _l push -1 store _i label loop; push puts load x load _i listIndex invokeStk 2 pop incrImm _i +1 load _l lt jumpTrue loop pop pop push {} }} foreachtest {a b c d} This uses two local variables, _i as index into the input list, and _l to hold the length of the list. The code at the [push] invocation did not match the disassembly above. so as next step I restructured the code to look exactly like the disassembly, except for extra instructions to replace ''foreach_start'' and ''foreach_step'' - I considered them macros. So here is the second version. that meets that expectation: proc foreachtest {x {i ""} {2 ""} {1 ""}} {asm { load x store 1 pop #foreach_start ;# push -1 ;# store 2 ;# pop ;# label L10 #foreach_step ;# incrImm 2 +1 ;# load 1 ;# load 2 ;# listIndex ;# store i ;# pop ;# load 1 ;# listLength ;# lt ;# jumpFalse L26 push puts load i invokeStk 2 pop jump L10 label L26 push {} }} foreachtest {e f g h} The macros are comments, followed by their expansions also marked by a trailing comment. In the local variables, I accepted the numeric names * "1" (for a local copy of the list to be iterated over, in case it was changed in the loop) and * "2" (for the index into the list), which are valid in Tcl as well. "i" now holds the current list element, like it should. The [llength] can be checked at runtime, no variable needed for that. <>Example