Parser Routines
This article is the third in a series discussing the ZX81 Parser. Since the first two articles (SYNC 2:3 and 2:4) may have been a bit too abstract for some readers, I hope this discussion will pull the previous articles together.
In the first article I covered the basic concepts common to all parsers, and in the second article I described the implementation of the parser in the 8K Basic ROM: the character fetch routines, the CLASS tables, and the executive routine that was responsible for controlling overall operations. In this article we will look at some of the routines that are called by the executive to perform actual operations. These operations include, but are not limited to, PLOTting a point on the screen, PRINTing a character on the screen, and executing a GOTO statement.

RUNning a Program in Basic
Before taking up the details of any particular command, let us review the method used by Basic to RUN a program. In the parser’s executive routine a pointer must be passed to the line it is to execute. This pointer is passed to the exec(utive) in the system variable CH-ADD. A loop (at 066Ch in the new ROM) is responsible for keeping track of what line in the program we are currently executing and where it is stored in the computer’s memory.
The way the computer stores a program in its memory is seen in Figure 1 which represents a single program line. The first two bytes of the line contain the line number of the represented line. These bytes are stored in MSB/LSB (Most/Least Significant Byte) order. This is the opposite of the standard practice with a Z80.
Figure 1: A Line Representation.
+---+---+---+---+--------------+-------+ | 1 | 2 | 3 | 4 | Text of Line | ENTER | +---+---+---+---+--------------+-------+
The next two bytes hold a standard Z80 LSB/MSB 16-bit representation of the length of the line, including the ENTER (NEWLINE) at the end. When the program has more than one line, the computer is responsible for keeping the records that represent each line of the program in numerical order.
With the information supplied with each line, the computer has enough data to effectively “walk” through the program from one line to the next. This is accomplished by adding to the address of the first byte of the text in the line, and the length of the line, as specified in the two length bytes. The result of this calculation is the address of the next line in the program. Thus, the Run-Executive, as it will be referred to later, must perform only simple operations such as addition to RUN a program. A basic outline of the operations performed by the Run-Executive is as follows:
1) Load a variable (called NXTLIN) with 16509. This is the address of the first line of the program.
2) Set CH-ADD equal to NXTLIN.
3) Call the parser to execute the line.
4) If there are any errors currently logged, then stop, and report them, else,
5) If the BREAK key is depressed, stop with a D report code, else,
6) Add to NXTLIN the length of the current line.
7) Go back to step 2.
Figure 2 gives the code for the Run Time Executive. Take a moment now to study it to get a general idea of what is transpiring. The essential facet of this routine is that, when a command handler is called by the parser, it can modify the NXTLIN pointer; this is, in fact, how a GOTO statement works. The destination of the line number (i.e., 100 in GOTO 100) is evaluated, the address of that line is found, and then the calculated address is loaded into NXTLIN.
Figure 2. Listing of the Run Time Executive.
NEXT-LINE:
LD (NXTLIN), HL
EX DE,HL
CALL TEMP-PTR ;$004D
CALL LINE-RUN ;$0CC1
RES 1,(FLAGS)
LD A, 11000000b
LD (X-PTR),a
CALL X-TEMP ;$14A3
RES 5,(FLAGX)
BIT 7,(ERR-NR)
JR Z,STOP-LINE
LD HL,(NXTLIN)
AND (HL)
JR NZ, STOP-LINE
LD D,(HL)
INC HL
LD E,(HL)
LD (PPC),DE
INC HL
LD E,(HL)
INC HL
LD D,(HL)
INC HL
EX DE,HL
CALL BREAK-1 ;$0F46
JR C,NEXT-LINE
LD HL,(ERR-NR)
BIT 7,(HL)
JR Z,STOP-LINE
LD (HL),$0C
STOP-LINE:
BIT 7,(PR-CC)
CALL Z,COPY-BUFF
LD BC,$0121
CALL LOC-ADDR ;$0918
LD A,(ERR-NR)
INC A
JR Z,REPORT
CP $09
JR NZ,CONTINUE
INC BC
CONTINUE:
LD (OLDPPC),BC
JR NZ,REPORT
DEC BC
CALL OUT-CODE ;$07EB
LD A,$18
RST 10
CALL OUT-NUM ;$0A98
CALL CURSOR-IN ;$14AD
JP DISPLAY-6 ;$04C1
STOP
The STOP command is, as far as the driver code is concerned, the most elementary of all commands. The command handler for STOP is:
STOP: RST 8
.byte $08
The RST 8 routine will, when called, simply load into ERR-NR the byte given after the RST 8 instruction. In this case, the byte is a 08h. This number is the number-of-the-error-to-cause -1. If you review the code for the Run-Executive, you will see that, at the end of every line, it checks the ERR-NR byte. If the byte is not FFh, then the Run Executive stops and reports an error.
NEW
The NEW command is also a very simple command. When the computer is powered on, the BC register pair is loaded with 7FFFh, and a jump is made to the initialization routine. The initialization routine then fills every byte of memory from BC down to 4000h with a 2. It then goes back and decrements by 1 each of the aforementioned memory locations. As the computer decrements each location, it checks to be sure that the value obtained after the decrement was a 1. If it was not, then the computer has found the end of available memory, and this address plus 1 is loaded into RAMTOP.
The effect of the NEW code is simply this: load BC with RAMTOP, decrement BC, and fall through to the initialization routine.
GOTO
As mentioned earlier, the only steps that the GOTO command handler must execute to accomplish its purpose are: 1) get the destination line number, 2) find the address of the specified line, and 3) load this value into NXTLIN. Let us examine each of these individually.
First, there is the matter of obtaining the line number specified as the argument to the GOTO. Reviewing Perceptions in the last issue of SYNC (which you, of course, have on the desk in front of you), find the entry for GOTO in the Offset Table SYNC 2:4, Listing 2). You will see that the first type specified was a CLASS-6 Entry and that CLASS-6 specifies an Integral-Expression.
As the parser examines the line in which the GOTO occurred, it called CLASS-6 to parse out the expression. CLASS-6 left the value of this expression on the calculator stack. A subroutine FIND-INT (at 0EA7 in the new ROM) will remove a value from the top of the calculator stack and round it down to 16-bit integer in the BC register pair. If the number is outside of the 0.65535 range, then the FIND-INT routine gives Report-B.
Now we have the required argument for the GOTO statement. Next we must, using this number, find the address of the Basic line that it specifies. This type of search routine is about as common as a parser, and the designers of the Sinclair ROM, fearing that they might fall short of expectations, decided to incorporate just such a routine into the 8K ROM. The routine, located at 09D8h, takes a line number in the HL register pair, and returns the line number in BC, and the address of the requested line (or that of the next one, if no such line exists) in HL.
Since the first two stages of the GOTO have been accomplished, the last stage would appear to be easy. Indeed it is. All we need do now is to take the address returned by the search routine in the HL register pair, and place it in NXTLIN. The GOTO command handler then returns, and the Run-Executive continues at the new line without even the slightest sound of discontent.
CONT
If you look at the code for the Run-Executive very closely, you will see that, when an error is encountered, the current line number is loaded into a system variable called OLDPPC. This is the line number to which CONT continues. There is only one detail. If we go back to the same line at which the error occurred, and the cause of the error was only a STOP statement, then as soon as we CONTinue, we will re-execute the STOP. The code in the Run-Executive is smart enough to detect this situation. Whenever an error is going to be reported, the error number is compared with 09 (STOP). If the error number is 09, then the current line number is incremented before it is saved in OLDPPC.
With that little detail out of the way, I can now tell you how CONT works: it loads HL with OLDPPC and jumps to step 2 of GOTO. Simplicity.
REM
Once again we find that the advantages of having a well-written parser at our disposal are incredible. The command handler for REM is simply a RETurn instruction. If you consider this for a moment, you will see the ease with which it works in this system. When the RET is executed, the Run-Executive simply continues by adding the length of the line with the REM in it to the address of said line. The Run-Exec then continues normally at the NXTLIN.
We hope that this discussion of a few of the concrete command handlers will help you to understand better the way a computer, your computer, operates.
Until next time, same relativistic time period, same non-Euclidian universe.