!pr2
!lm12
!rm75
REPEAT and UNTIL for Applesoft.....................Bobby Deen

The following program adds three statements to Applesoft:  &REPEAT, &UNTIL, and &POPR.  With these you can write Pascal-like loops in your Basic programs.

You start the loop with &REPEAT, and end it with &UNTIL <exp>.  The loop will be repeated until the <exp> evaluates to non-zero (true).  As long as the value of <exp> is zero (false), the loop will keep going.

I use the system stack for saving the line number and the program pointer, just like Applesoft does with FOR-NEXT loops.  A special code is used to identify the stuff on the stack, so you can have FOR-NEXT loops inside REPEAT-UNTIL loops and vice versa.

The statement &POPR removes one REPEAT block from the stack, in case you want to jump out of a loop rather than completing it.  (This is not generally a good practice, even with FOR-NEXT loops, but you can do it if you feel you must.)  The statement "&UNTIL 1" will do the same thing as &POPR, but &POPR takes less space and time.

If &POPR or &UNTIL is executed when there is not an UNTIL block on the top of the stack, you will get "NEXT WITHOUT FOR" error.

Applesoft parses the word "REPEAT" as four letters "REPE" and the token "AT".  This makes the listings look weird, but never mind.  Likewise, "UNTIL" looks like a variable name during tokenization, so the expression runs into the letter "L"; but at execution time all is understood.

Here is a sample program which shows a pair of REPEAT loops:

100  REM TEST REPEAT/UNTIL
110 D$ =  CHR$ (4): PRINT D$"BLOAD B.REPEAT/UNTIL": CALL 768
120 I = 0: & REPE AT
130 I = I + 1: PRINT I":  ";
135 J = 0: & REPE AT :J = J + 1: PRINT J" ";: & UNTILJ > 14:
    PRINT
140  & UNTILI = 10

Lines 1200-1250 install the ampersand vector.  I assumed the JMP opcode is already stored at $3F5, since DOS does that.  After BLOADing the file, CALL 768 will executed these lines.

When the "&" is executed, the 6502 jumps to AMPER.PARSE at line 1270.  Lines 1270-1420 search through a table of keywords, matching one if possible with the characters after the "&" in your Applesoft program.  This is a general routine, which you can use for any keywords, just by making the appropriate entries in the table (lines 1500-1590).

The table contains a string and an address for each keyword.  The string is shown as a hex string, and includes the exact hexadecimal values expected.  For example, for "REPEAT" I have entered the ASCII codes for "REPE" and the token value or "AT".  After the keyword there is a 00 byte to flag the end, and a two byte address.  The address will be pushed onto the stack so that an RTS instruction will branch to the processing program for that keyword.  Since RTS adds one, the address in the table have "-1" after them.

The last entry in the table has a null keyword, so it will match anything and everything.  If the search goes this far, we have a syntax error; therefore the branch address is to the Applesoft syntax error code.

When a keyword is matched, the Y-register contents need to be added to TXTPTR.  A subroutine in the Applesoft ROMs does this, called AS.ADDON.  Since both REPEAT and POPR require the next character to be end-of-line or a colon, a JMP to AS.CHRGOT gets the next character and tests it.  The RTS at the end of AS.CHRGOT actually branches to the processing code for the keyword.

Lines 1600-1840 process the REPEAT command.  A five-byte block is pushed onto the stack, consisting of the current line number, the TXTPTR, and a code value $B8.

Lines 1850-2070 process the UNTIL command.  First the expression is evaluated.  If the value turns out to be zero, the byte at FAC.EXP will be zero.  If it is zero, we need to keep looping; if non-zero, the loop is finished.  Looping involves copying the line number and text pointer from the stack back into CURLIN and TXTPTR, and then going to AS.NEWSTT.  The REPEAT block is left on the stack, and execution resumes just after the &REPEAT that started this loop.

If the expression is true (non-zero), the loop is terminated.  Termination is trivial:  just pop off the REPEAT block, and go to AS.NEWSTT to continue execution after the UNTIL statement.  I could pop the block off with seven PLA's, but I used the technique of adding 7 to the stack pointer instead.

Naturally, this package was assembled to sit in page 3, along with 99 other machine language things you use.  You can easily move it to another location, just by changing the origin (line 1180).  Or you can use the routines with Amper-Magic or the Routine Machine.  Note that the routines themselves are relocatable run-anywhere code (no data references, JSR's, or JMP's to points within the routines).  You will have to shorten the routine names to four or less characters to use them with Amper-Magic.

Pascal has some other looping constructs which you might like to see in Applesoft.  Now that you see how I did this one, why not try your hand at coding REPEAT WHILE?
