Chapter
Eleven
The LIST and ENTER Statements
LIST can be used to store a program on an external
device and ENTER can retrieve it. The difference between LOAD-SAVE and LIST-ENTER
is that LOAD-SAVE deals with the tokenized program, while LIST-ENTER deals with the
program in its source (ATASCII) form. The ENTER Statement BASIC is in ENTER mode whenever a program is not RUNning.
By default the Program Editor looks for lines to be ENTERed from the keyboard, but
the editor handles all ENTERed lines alike, whether they come from the keyboard or
not. The Enter Device To accomplish transparency of all input data (not just
ENTERed lines), BASIC maintains an enter device indicator, ENTDTD ($B4). When a BASIC
routine (for example, the INPUT simulation routine) needs data, an I/O operation
is done to the IOCB specified in ENTDTD. When the value in ENTDTD is zero, indicating
IOCB 0, input will come from the keyboard. When data is to come from some other device,
ENTDTD contains a number indicating the corresponding IOCB. During coldstart initialization,
the enter device is set to IOCB 0. It is also reset to 0 at various other times.
XENTER ($BACB) The XENTER routine is called by Execution Control to simulate
the ENTER statement. XENTER opens IOCB 7 for input using the specified <filespec>,
stores a 7 in the enter device ENTDTD, and then jumps to the start of the editor.
Entering from a Device When the Program Editor asks GLGO, the get line routine
($BA92), for the next line, GLGO tells CIO to get a line from the 85
Chapter
Eleven
device spedified in ENTDTD - in this case, fr9m IOCB 7. The editor
continues to process lines from IOCB 7 until an end-of- file error occurs. The IOTEST
routine detects the EOF condition, sees thatwe are using IOCB 7 for ENTER, closes
device 7, and jumps to SNX2 to reset the enter device (ENTDTD) to 0 and print the
READY message before restarting at the beginning of the editor. The LIST Statement The routine which
simulates the LIST statement, XLIST, is actually another example of a language translator,
complete with symbols and symbol-combining rules. XLIST translates the tokens generated
by Atari BASIC back into the semi- English BASIC statements in ATASCII. This translation
is a much simpler task than the one done by the pre-compiler, since XLIST can assume
that the statement to be translated is syntactically correct. All that is required
is to translate the tokens and insert blanks in the appropriate places. The List
Device BASIC maintains a list device indicator, LISTDTD ($B5), similar to the
enter device indicator discussed earlier. When a BASIC routine wants to output some
data (an error message, for example), the I/O operation is done to the device (IOCB)
specified in LISTDTD. During coldstart initialization and at various other times,
LISTDTD is set to zero, representing IOCB 0, the editor, which will place the output
on the screen. Routines such as XPRINT or XLIST can change the LIST device to indicate
some other IOCB. Thus the majority of the BASIC routines need not be concerned about
the output's destination. Remember that IOCB 0 is always open to the editor, which
gets input from the keyboard and outputs to the screen. IOCB 6 is the S: device,
the direct access to graphics screen, which is used in GRAPHICS statements. Atari
BASIC uses IOCB 7 for I/O commands that allow different devices, like SAVE, LOAD,
ENTER, and LIST. XLIST ($B483) The XLIST routine considers the output's destination
in its initialization process and then forgets about it. It looks at the first expression
in the tokenized line. If it is the <filespec> 86
Chapter
Eleven
string, XLIST calls a routine to open the specified device using
IOCB 7 and to store a 7 in LISTDTD. All of XLIST's other processing is exactly the
same, regardless of the LISTed data's final destination. XLIST marks its place in
the Statement Table by calling a subroutine of XGOSUB to put a GOSUB type entry on
the Runtime Stack. Then XLIST steps through the Statement Table in the same way that
Execution Control does, using Execution Control's line parameters and subroutines.
When XLIST is finished, Execution Control takes the entry off the Runtime Stack and
continues. The XLIST routine, assuming it is to LIST all program statements, sets
default starting and ending line numbers of 0 (in TSLNUM) and $7FFF (in LELNUM).
XLIST then determines whether line numbers were specified in the tokenized line that
contained the LIST statement. XLIST compares the current index into the line (STINDEX)
to the displacement to the next statement (NXTSTD). If STINDEX is not pointing to
the next statement, at least one line number is specified. In this case, XLIST calls
a subroutine of Execute Expression to evaluate the line number and convert it to
a positive integer, which XLIST stores in TSLNUM as the starting line number. If
a second line number is specified, XLIST calls Execute Expression again and stores
the value in LELNUM as the final line to LIST. If there is no second line number,
then XLIST makes the ending line number equal to the starting line number, and only
one line will be LISTed. If no line numbers were present, then TSLNUM and LELNUM
still contain their default values, and all the program lines will be LISTed. XLIST
gets the first line to be LISTed by calling the Execution Control subroutine GETSTMT
to initialize the line parameters to correspond to the line number in TSLNUM. If
we are not at the end of the Statement Table, and if the current line's number is
less than or equal to the final line number to be LISTed, XLIST calls a subroutine
:LLINE to list the line. After LISTing the line, XLIST calls Execution Control's
subroutines to point to the next line. LISTing continues in this manner until the
end of the Statement Table is reached or until the final line specified has been
printed. When XLIST is finished, it exits via XRTN at $B719, which makes the LIST
statement the current statement again and then returns to Execution Control. 87
Chapter
Eleven
LIST Subroutines :LLINE ($BS5C) The LLINF routine LISTs the current
line (the line whose address is in STMCUR). :LLINE gets the line number from the
beginning of the tokenized line. The floating point package is called to convert
the integer to floating point and then to printable ATASCII. The result is stored
in the buffer indicated by INBUFF. :LLINE calls a subroutine to print the line number
and then a blank. For every statement in the line, :LLINE sets STINDEX to point to
the statement name token and calls the :LSTMT routine ($B590) to LIST the statement.
When all statements have been LISTed, :LLINE returns to its caller, XLIST. :LSTMT
($B590) The :LSTMT routine LISTs the statement which starts at the current displacement
(in INDEX) into the current line. This routine does the actual language translation
from tokens to BASIC statements. :LSTMT uses two subroutines, :LGCT and :LGNT, to
get the current and next token, respectively. If the end of the statement has been
reached, these routines both pull the return address of their caller off the 6502
CPU stack and return to :LSTMT's caller, :LLINE. Otherwise, they return the requested
token from the tokenized statement line. The first token in a statement is the statement
name token. :LSTMT calls a routine which prints the corresponding statement name
by calling :LSCAN to find the entry and :LPRTOKEN to print it. In the discussion
of the Program Editor we saw that an erroneous statement was given a statement name
of ERROR and saved in the Statement Table. If the current statement is this ERROR
statement or is REM or DATA, :LSTMT picks up each remaining character in the statement
and calls PRCHAR ($BA9F) to print the character. Each type of token is handled differently.
:LSTMT determines the type (variable, numeric constant, string constant, or operator)
and goes to the proper code to translate it. Variable Token. A variable token
has a value greater than or equal to $80. When :LSTMT encounters a variable token,
it 88
Chapter
Eleven
turns off the most significant bit to get an index into the Variable
Name Table. :LSTMT asks the :LSCAN routine to get the address of this entry. :LSTMT
then calls :LPRTOKEN ($B535) to print the variable name. If the last character of
the name is (, the next token is an array left parenthesis operator, and :LSTMT skips
it. Numeric Constant Token. A numeric constant is indicated by a token of
$0E. The next six bytes are a floating point number. :LSTMT moves the numeric constant
from the tokenized line to FRO ($D4) and asks the floating point package to convert
it to ATASCII. The result is in a buffer pointed to by INBUFF. :LSTMT moves the address
of the ATASCII number to SRCADR and tells :LPRTOKEN to print it. String Constant
Token. A string constant is indicated by a token of $0F. The next byte is the
length of the string followed by the actual string data. Since the double quotes
are not stored with a string constant, :LSTMT calls PRCHAR ($BA9F) to print the leading
double quote. The string length tells :LSTMT how many following characters to print
without translation. :LSTMT repeatedly gets a character and calls PRCHAR to print
it until the whole string constant has been processed. It then asks PRCHAR to print
the ending double quote. Operator Token. An operator token is any token greater
than or equal to $10 and less than $80. By subtracting $10 from the token value,
:LSTMT creates an index into the Operator Name Table. :LSTMT calls :LSCAN to find
the address of this entry. If the operator is a function (token value greater than
or equal to $3D), :LPROTOKEN is called to print it. If this operator is not a function
but its name is alphabetic (such as AND), the name is printed with a preceding and
following blank. Otherwise, :LPRTOKEN is called to print just the operator name.
:LSCAN ($B50C) This routine scans a table until it finds the translation of
a token into an ATASCII name. A token's value is based on its table entry number;
therefore, the entry number can be derived by modifying the token. For example, a
variable token is created by machine-language ORing the table entry number of the
variable name with $80. The entry number can be produced by ANDing out the high-order
bit of the token. It is this entry number, stored in SCANT, that the :LSCAN routine
uses. 89
Chapter
Eleven
The tables scanned by :LSCAN have a definite structure. Each entry
consists of a fixed length portion followed by a variable length ATASCII portion.
The last character in the ATASCII portion has the high-order bit on. Using these
facts, :LSCAN in 5 he entry corresponding to the entry number in SCANT and puts the
address of the ATASCII portion in SCRADR. :LPRTOKEN ($B535) This routine's
task is to print the string of ATASCII characters whose address is in SCRADR. :LPRTOKEN
makes sure the most significant bit is off (except for a carriage return) and prints
the characters one at a time until it has printed the last character in the string
(the one with its most significant bit on). 90
<-Chapter
10Chapter 12->