Checking conditionals
Jos-Ven opened this issue · 11 comments
Hi Mitch,
When the following test3 is compiled on a ESP8266 or ESP32
: test3 then ;
then cforth crashes and reboots.
When if else then are redefined as follows the unfriendly reboot
is avoided and you get the msg: Conditionals not paired
: if2 \ runtime: ( flag - ) compiletime: ( - 2Pair )
+level compile ?branch >mark 2
; immediate
: else2 \ compiletime: ( 2Pair - 2Pair )
2 ?pairs postpone ahead postpone but postpone then 2
; immediate
: then2 \ compiletime: ( 2Pair - )
2 ?pairs >resolve -level
; immediate
: test 1 if2 10 else2 100 then2 . ;
: test2 0 if2 10 else2 100 then2 . ;
: test3 then2 1 . ;
: test4 if2 1 . ;
Note: test4 also changes the stack
No idea if this generate other problems.
I played around a bit trying to figure out how to merge this into control.fth, but hit difficulties and ran out of time.
Changed from;
: if ( -- >mark ) +level compile ?branch >mark ; immediate
: then ( >mark -- ) >resolve -level ; immediate
: else ( -- ) [compile] ahead [compile] but [compile] then ; immediate
Changed to;
: if ( -- >mark 2 ) +level compile ?branch >mark 2 ; immediate
: then ( 2 >mark -- ) 2 ?pairs >resolve -level ; immediate
: else ( >mark 2 -- >mark 2 )
2 ?pairs [compile] ahead [compile] but [compile] then 2 ; immediate
What goes wrong;
./forth kernel.dic ../../src/cforth/load.fth
Tried to execute a null token
Tried to execute a null token
Tried to execute a null token
Tried to execute a null token
make: *** [../../src/cforth/targets.mk:87: forth.dic] Error 1
Hi, Same problem here when control.fth is changed.
However on a ESP8266, it is possible to make a new file containing the redefined words
and add that file to app.fth.
Now 'make flash' shows lines with:
if isn't unique
else isn't unique
then isn't unique
Okay not very nice, but they seem to work.
Jos
Thanks, all controls could be checked as follows in app.fth:
warning off
: if ( -- >mark 2 ) +level compile ?branch >mark 2 ; immediate
: else ( 2 -- 2 ) 2 ?pairs [compile] ahead [compile] but [compile] then 2 ; immediate
: then ( >mark 2 - ) 2 ?pairs >resolve -level ; immediate
: do ( -- >mark 3 ) +level compile (do) >mark 3 ; immediate
: ?do ( -- >mark 3 ) +level compile (?do) >mark 3 ; immediate
: loop ( >mark 3 -- )
3 ?pairs compile (loop) [compile] yet /branch + resolve -level
; immediate
: +loop ( >mark 3 -- )
3 ?pairs compile (+loop) [compile] yet /branch + resolve -level
; immediate
: begin ( -- 1 ) +level <mark 1 ; immediate
: until ( 1 -- ) 1 ?pairs compile ?branch <resolve -level ; immediate
: again ( 1 -- ) 1 ?pairs compile branch <resolve -level ; immediate
: while ( 1 -- 1 ) 1 ?pairs [compile] if drop [compile] but 1 ; immediate
: repeat ( 1 -- ) [compile] again 2 [compile] then ; immediate
warning on
I also tried to use a patch after ?pairs is defined.
That did not solve the problem in control.fth.
Checking like this could potentially break ANS Forth compatibility. ANS Forth permits the intermixing of IF and WHILE constructs. If that isn't important to you, the ?pairs thing is okay. If you want to be ANS compliant, you probably need to check for <mark / >mark matching. I.e. the consumer of a >mark needs to see a >mark on the stack.
Loops must be handled separately.
5 begin
dup
while \ Resolved by then
dup . 1-
key? 0=
while \ Resolved by repeat
#1000 ms
repeat
." Key stop" cr
then
.
It can get wilder than that. The words IF ELSE THEN BEGIN WHILE REPEAT UNTIL AHEAD BUT CS-PICK CS-ROLL can be combined in any way that matches forward / backward branches and resolutions. You can use them to make arbitrary control flow graphs.
The addition of markers like those used for ?PAIRS breaks the implementation of this model because the primitives BUT, CS-PICK, and CS-ROLL must be able to rearrange the control flow items on the stack. When you add a marker, a control flow item becomes two stack entries, so, for example, BUT, which is basically just SWAP (albeit implemented as 1 CS-ROLL), would need to become 2SWAP to handle both the address and the marker.
There are two ways to fix that. One way would be to change CS-PICK and CS-ROLL to pick and roll pairs of numbers. The second would be to change the encoding of a target address to include some tag bits to identify it as a forward or backward mark. The tag bits would reduce the branching range, but that is probably not a big deal since branch ranges are generally small.
You can blame Wil Baden for proposing the idea of a comprehensive basis for control flow, and blame me for fleshing out Wil's idea to make it work for arbitrary flow graphs. The primitive basis is:
AHEAD - unconditional forward branch
IF - conditional forward
AGAIN - unconditional backward
UNTIL - conditional backward
BEGIN - backward target
THEN - forward target
CS-PICK, CS-ROLL - rearrange stacked control flow items
Everything else - both traditional Forth control structures and extensions to arbitrary flow graphs - can be build atop those primitives.
I use check-conditional for now.