              TRS-80 Model 1 Level 2 BASIC Language Reference
                                 Joe Ganley

----------------------------------------------------------------------------

This document is in beta release. I don't have a reference manual; the
contents of this document came from my memory, from a few BASIC source files
I have, by trial and error on David Gingold and Alec Wolman's XTRS emulator,
and from several helpful people. Sprinkled throughout are questions to which
I don't know the answers. Click on a question to send me mail if you know
the answer.

In addition, please let me know if you see any errors or omissions in this
document. As I said, the material here was determined in a rather
unscientific way, so some of it may be wrong.

----------------------------------------------------------------------------

Contents

  Basics
    Types and Notation
    Program Structure
    Variables
    Storage Representations
    Casting Rules
    Expressions
  Commands and Functions
    Utility Functions
    Assignment
    Input/Output
    Graphics
    Control Structures
    Error Handling
    Static Data
    Type Declarations
    String Functions
    Math Functions
    Random Number Generation
    Hardware/Assembly Access
    Storage Access
  Keyword Index
  Level 3 Keywords
  Acknowledgments

----------------------------------------------------------------------------

Basics

Types and Notation

Values in TRS-80 Level 2 BASIC may have one of four types: integer, single-
or double-precision floating point, or string. Throughout this document,
values beginning with I have integer type, values beginning with F have
single-precision floating point type, values beginning with D have
double-precision floating point type, and values beginning with S have
string type. Values beginning with N may have any of the three numeric
types. Values beginning with B have integer type and must be in the range 0
to 255, inclusive. Values beginning with L are line numbers, which are
integer literals (integer variables cannot be used). Prepending V to a value
notation indicates that the name of a variable with the corresponding type
is expected; V alone indicates a variable of any type, or of an unspecified
type.

The notation "[ stuff ]" indicates that stuff is optional. The notation "{ a
| b | ... }" indicates that any one of the values indicated is acceptable.
The notation * indicates that the quantity it follows can be repeated zero
or more times.

Program Structure

Each line in a BASIC program has a line number, which is an integer in the
range 0 to 65529, inclusive. The line number from 65530 to 65535 are
reserved for system use; e.g., 65535 is used internally to store a line
entered directly without a line number. The character "." gives the current
line, i.e. the line at which the program was stopped by a STOP or END
command, a user interrupt, or an error. The "." character can be used
anywhere a line number is expected. When a program is executed, its lines
are executed in line-number order unless a control command causes the
execution order to behave otherwise.

Multiple commands can appear on a single line; these commands are separated
from one another by the ":" character.

In addition, commands (or multiple commands separated by ":") can be entered
directly, without a line number. These commands are executed immediately, as
soon as the line is completed. Some commands have no effect (e.g. DATA) or
do not make sense (e.g. RETURN) when entered without a line number. Other
commands (e.g. NEW) are almost always used without a line number.

Variables

A numeric variable stores a numeric value of type integer, single, or
double. The lexical structure of a numeric variable name is letter {letter |
number}* [{ % | ! | # }]. However, only the first two characters of a
variable name are significant. Thus, AA, AAA, AAAA, etc. are all considered
to be the same variable. The suffix character "%" indicates an integer
value, "!" indicates a single, and "#" indicates a double. Variables are
dynamically typed unless their type is explicitly specified using one of
these suffix characters or a type declaration. Variable names cannot contain
any BASIC keyword as a substring. An uninitialized numeric variable is
considered to have value 0.

A string variable stores a string value. The lexical structure of a string
variable name is letter {letter | number}* $ (i.e. the same as a numeric
variable but with $ appended). Like numeric variable names, only the first
two characters are significant. As with numeric variables, string variable
names cannot contain any BASIC keyword as a substring. Strings are
implicitly dynamically allocated and their contents and length can be
changed at any time. String length cannot exceed 255. There is no character
type; a character is represented by a string of length 1. The empty string
"" is a valid string, and has length 0.

In the absence of any type declarations, the name spaces for the four types
are all separate, i.e. "A%", "A!", "A#", and "A$" can all have distinct
values. The default type of, e.g. "A", is single.

Storage Representations

Integers are stored in 16-bit, two's complement format; thus, their range is
-32768 to 32767. They are stored little-endian, i.e. the least significant
byte is at the lower memory address.

How are floating-point numbers represented?

String variables' values are allocated on a heap starting from the highest
available memory address and working backward. For each string variable, a
three-byte record is stored in the normal variable address space. The first
byte contains the length of the string. The second two bytes contain an
unsigned, little-endian integer specifying the address a containing the
first character in the actual string data. The remaining characters appear
contiguously in the next memory addresses above a.

Casting Rules

Casting only applies to numeric types. When a single or double is cast to an
integer, the fractional part of the number is truncated. When a double is
cast to a single, the value is rounded to the nearest single-precision value
(I think).

Expressions

Mathematical expressions on numeric types are like in most any programming
language, with the operators being "+" (addition), "-" (subtraction), "*"
(multiplication), "/" (division), and up-arrow, denoted "^" in this document
(exponentiation), as well as unary "+" and "-", which indicate a number's
sign.

The operators "AND", "OR", and "NOT" perform the corresponding bitwise
operations on their operands, which are cast to integers.

The relational operators are "<" (less than), "<=" (less than or equal to),
"=" (equal to), ">=" (greater than or equal to), ">" (greater than), and
"<>" (not equal to). These are boolean operators, but since there is no
boolean type, they return integer 0 (whose bit representation is hexadecimal
0000) for "false" and integer -1 (whose bit representation is hexadecimal
FFFF) for "true". Thus, the bitwise operators "AND", "OR", and "NOT" behave
as expected on the results of these "boolean" operators.

Finally, the "+" operator with string operands concatenates the right
operand onto the end of the left one.

The precedence of the operators is as follows (highest precedence first):
unary + - NOT
^
* / AND
binary + - OR
< <= = <> >= >

Commands and Functions

Utility Functions

AUTO [ L1 [ , L2 ] ]

Initiate automatic line numbering. Lines are numbered starting with L1, or
10 if it is absent, and incremented by L2, or 10 if it is absent. Once AUTO
has been started, the program produces the appropriate line numbers and
waits for the user to enter the code for each. Hitting BREAK on an empty
line terminates and returns to the READY prompt. If a line already exists,
its line number is followed by a "*"; hitting anything but BREAK at this
point replaces the existing line with whatever the user types. If the user
hits RETURN on a blank line, the line is deleted.

CLS

Clears the screen and returns the cursor to the upper left.

EDIT L

Enters edit mode for a particular line L. In edit mode, the following
keystroke commands are available:

   * SPACE moves the cursor one character to the right.
   * BACKSPACE moves the cursor one character to the left.
   * D deletes the character at the current position.
   * ID deletes I characters.
   * I enters insert mode. In insert mode, characters are inserted as they
     are typed.
   * SHIFT-[ leaves insert mode.

Pressing RETURN ends insert mode, enters the changes made, and returns to
the READY prompt. Other EDIT subcommands are under construction

LIST [ L1 ] [ - L2 ]
LLIST [ L1 ] [ - L2 ]

LIST prints the program lines to the screen. It lists line numbers from L1,
or the first line if L1 is absent, to L2, or the last line if L2 is absent.
LLIST is exactly the same except that the listing is sent to the printer
rather than the screen.

NEW

Erases all program data and variables currently in memory.

CLEAR [ I ]

Erases all variables currently in memory. If present, I indicates the amount
of space to be allocated for the string heap; otherwise, the default is 50
or 200 bytes (depending on ROM version).

RUN [ L ]

Runs the program starting with line L, or starting with the first line if L
is absent.

TRON
TROFF

Turns tracing on or off, respectively. When tracing is on, the line numbers
being executed are printed as they are run.

REM ...

Remark: everything from REM to the end of the line is ignored.

Assignment

[ LET ] VN = N
[ LET ] VS = S

Assigns N to VN, casting if necessary, or assigns S to VS.

Input/Output

{ PRINT | ? } { X | ; | , } *
LPRINT { X | ; | , } *

PRINT prints zero or more values to the screen. The values denoted X can be
anything at all: a variable or literal of any type. The tokens following
PRINT are handled in order. For values X, the value of X is printed. If
values are separated by ";" or by no separator at all, then the values are
printed right next to one another. Each time a "," is encountered, PRINT
tabs over to the next column evenly divisible by 16, moving to the next line
if necessary. If a PRINT command ends with ";" or ",", then the next PRINT
command will resume in the position where this one left off, just as though
its arguments were appended to the current PRINT command's arguments.
Otherwise, the line is ended by a carriage return, and the next PRINT
command will resume at the beginning of the next line. The character "?" can
be used as a shorthand for "PRINT". LPRINT works exactly the same as PRINT
except that output is directed to the printer rather than to the screen.

{ PRINT | ? } @ I { X | ; | , } *

Same as PRINT, but starts at screen position I. Screen positions are
numbered in row-major order, i.e. the upper left corner is 0, the leftmost
position in the second line is 64, and so forth, with the lower right corner
at 1023.

TAB ( I )

Tabs to position I on the current line (modulo 64). Has no effect if the
current cursor position is right of position I.

PRINT USING S ; { X | ; | , } *

Print the arguments using the format string S. Specifics of S are under
construction.

INPUT [ S ; ] V [ , Vn ] *

Prints the value of S, if present, and then prompts the user to enter
values, which are assigned to the remaining arguments in order. Multiple
values may be entered separated by commas, by hitting RETURN after each, or
in any combination of the two.

INKEY$ returns S

If a key is currently pressed, then INKEY$ returns a one-character string
containing that key's value; otherwise, it returns the empty string. The
keypress is stored in a buffer which is then flushed without repeat, so if a
key is held down, INKEY$ returns its value only once.

POS ( any ) returns I

Returns the current horizontal cursor position, between 0 and 63 inclusive.
The argument is ignored, and thus can be any pretty much anything.

Graphics

SET ( IX , IY )
RESET ( IX , IY )

SET turns on the pixel at position (IX,IY), where 0 <= IX <= 127 and 0 <= IY
<= 47. RESET turns off the pixel.

POINT ( IX , IY ) returns I

Returns a nonzero value if pixel (IX,IY) is on, or 0 if it is off.

Control Structures

GOTO L

Jumps to the first command on line L.

GOSUB L
RETURN

The GOSUB command jumps to the first command on line L. A subsequent RETURN
command then jumps back to the next command following the most recently
executed GOSUB. If at any point the number of RETURN commands executed
exceeds the number of GOSUB commands executed, a runtime error is thrown.

ON N GOTO L [ , Ln ] *
ON N GOSUB L [ , Ln ] *

Jumps, with either GOTO or GOSUB semantics, to a line number depending on
the value x of the greatest integer less than or equal to N. If x is 1, it
jumps to the first line in the list; if x is 2, it jumps to the second line,
and so on. If x is 0 or is greater than the length of the list of lines,
then the command has no effect and control continues to the next command. If
x is negative, then a runtime error is thrown.

IF I THEN commands [ ELSE commands ]

If I evaluates to a nonzero value, then the commands from after the THEN
statement to the end of the line or the ELSE keyword (if present) are
executed. If commands consists solely of a line number L, then it behaves as
if commands were "GOTO L". If I evaluates to 0, then the same action is
performed with the commands or line number from the ELSE to the end of the
line.

FOR VN = N1 TO N2 [ STEP N3 ]
NEXT [ VN [ , VNn ] * ]

The first time the FOR statement is hit, VN is set to N1. When the NEXT is
hit, the value of VN is incremented by N3, or by 1 if the STEP clause is
absent. If the resulting value is less than or equal to N2, then control is
transferred back to the statement following the FOR statement; otherwise,
control continues to the statement following the NEXT. If the NEXT has no
argument, then it is associated with the nearest matching FOR. NEXT VI,VJ is
equivalent to NEXT VI:NEXT VJ. It is permissible to modify VN inside the
loop. The looping happens at the NEXT, so a FOR with no matching NEXT is
equivalent to VN = N1. A NEXT without a matching FOR causes a runtime error.

STOP

Stops the program just as if the user had hit BREAK.

END

Stops the program like STOP, but without the "BREAK IN line" message being
printed.

CONT

After the user hits BREAK or a STOP or END command is executed, CONT
continues program execution. If CONT is executed when the program has not
been stopped in one of these ways, a runtime error is thrown.

Error Handling

ON ERROR GOTO L

Once this command is executed, if an error occurs, rather than stopping the
program and printing an error message, the interpreter executes a "GOTO L"
command. After the GOTO is executed, the variable ERL contains the line
number where the error occurred, and the variable ERR contains an integer
code for the type of error that occurred. The ERR error codes are as
follows: Make this a table?

Code Abbreviation Error
  1       NF      NEXT without FOR
  2       SN      Syntax error
  3       RG      RETURN without GOSUB
  4       OD      Out of data
  5       FC      Illegal function call (e.g. argument type mismatch)
  6       OV      Numeric overflow
  7       OM      Out of memory
  8       UL      Undefined line
  9       BS      Subscript out of range
 10       DD      Redimensioned array
 11       /0      Division by zero
 12       ID      Illegal direct (can't use INPUT at READY prompt)
 13       TM      Type mismatch
 14       OS      Out of string space
 15       LS      String too long
 16       ST      String formula too complex
 17       CN      Can't CONTinue
 18       NR      No RESUME
 19       RW      RESUME without error
 20       UE      Unprintable error (e.g. nested error)
 21       MO      Missing operand
 22       FD      Bad file data
 23       L3      Level 3 (disk) BASIC only

RESUME [ { NEXT | L } ]

After an error is caught, RESUME resumes execution of the program. RESUME
with no argument resumes starting with the offending command. RESUME NEXT
starts with the command following the offending command. RESUME L starts
with line L. A RESUME that is reached other than as the result of an ON
ERROR GOTO is an error.

Static Data

DATA value [ , values ] *
READ V , [ Vn } ] *
RESTORE

These commands are used for storing and retrieving static data stored as
part of a program's code. The values in the DATA statement are literals of
any type, though string values should be entered without quotation marks.
All of the DATA values in a program are indexed from left to right within
each statement, and in line-number order throughout the program, and a
pointer is maintained to the next item to be read (which is initially the
first item in the program). The READ command reads the next DATA item (or
items) into the variables specified, and increments the "next item" pointer
appropriately. If the variable specified in a READ is a string variable,
then the data is read as a string, regardless of its apparent type. If the
variable is numeric, then the data is read as a numeric value if possible;
if an attempt is made to read a non-numeric data value into a numeric
variable, then (rather cryptically) a syntax error is thrown at the line
number of the DATA statement. The RESTORE command reinitializes the "next
item" pointer to point to the first data item in the program.

Type Declarations

DEFINT V [ - V [ , V [ - V ] ] ] *
DEFSNG V [ - V [ , V [ - V ] ] ] *
DEFDBL V [ - V [ , V [ - V ] ] ] *
DEFSTR V [ - V [ , V [ - V ] ] ] *

Declares one or more variables to be of type integer, single, double, or
string, respectively. The hyphen is used for ranges of variables; e.g., A -
E is the variables A, B, C, D, and E. Separate variables or separate ranges
of variables are separated by commas. Once a variable has been declared to a
particular numerical type, assigning a value of another numerical type to it
causes the value to be cast to the variable's type. Ranges of variables only
work for single-letter variable names. A variable can be redeclared, but
doing so destroys the value it held before the redeclaration if the new type
is not the same as the old type. If a variable is declared to be of string
type, then the "$" following its name becomes implicit; i.e., If "DEFSTR A"
is executed, then henceforth "A" and "A$" both refer to the same string
variable.

DIM V ( I )

Declares an array variable V containing I number of elements, which are
indexed from 0 to I. The value of an array element is accessed as V(I). If
the argument is out of array bounds, a runtime error is thrown. Array
variables that are used without declaring them in a DIM statement have
dimension 10 by default.

String Functions

ASC ( S ) returns B

Returns the ASCII value of the first character in S.

CHR$ ( B ) returns S

Returns a string consisting of a single character whose ASCII value is B.

LEFT$ ( S1 , I ) returns S2
RIGHT$ ( S1 , I ) returns S2

Returns a string containing, respectively, the leftmost or rightmost I
characters in S1.

MID$ ( S1 , I1 , I2 ) returns S2

Returns substring of S1 that starts at index I1 and has length I2.

LEN ( S ) returns I

Returns the length of S.

STR$ ( N ) returns S

Returns the string representation of N, e.g. STR$(3.14) = "3.14".

VAL ( S ) returns N

Returns the value of S considered as a number, e.g. VAL("3.14") = 3.14. If S
does not contain a valid number, then VAL returns 0.

STRING$ ( I , S1 ) returns S2

Returns a string of length I, all of whose characters are the first
character of S1.

Math Functions

ABS ( N ) returns S

Returns the absolute value of N.

SIN ( N ) returns S
COS ( N ) returns S
TAN ( N ) returns S
ATN ( N ) returns S

Returns the sine, cosine, tangent, or arctangent, respectively, of N.

CINT ( N ) returns I
CSNG ( N ) returns F
CDBL ( N ) returns D

Casts N to integer, single, or double type, respectively (see above for
casting rules).

FIX ( N ) returns I

Returns N with the fractional portion truncated, i.e. returns the integer
highest in absolute value but nearer to 0 than N.

INT ( N ) returns I

Returns the greatest integer less than or equal to N.

EXP ( N ) returns S

Returns e (approximately 2.71828) raised to the N power.

LOG ( N ) returns S

Returns the natural (base-e) logarithm of N. A runtime error is thrown if N
is less than or equal to 0.

SQR ( N ) returns S

Returns the square root of N. A runtime error is thrown if N is less than 0.

Random Number Generation

RANDOM

Seeds the random number generator. The seed is based on the value of the R
(refresh) register, which is clocked at a higher rate than the CPU and thus
produces a more or less random value.

RND ( I1 ) returns I2 if I1 > 0
RND ( 0 ) returns S

RND(I1), for I1 > 0, returns a pseudorandom integer value I2 such that 1 <=
I2 <= I1.
RND(0) returns a pseudorandom single-precision floating-point value S such
that 0 < S < 1.
1. What's the generator algorithm?
2. Does HTML have a '<=' character?

Hardware/Assembly Access

POKE I, B
PEEK ( I ) returns B

POKE sets the value of memory location I to B. PEEK returns the value stored
in memory location I.

VARPTR ( V ) returns I

Returns the memory address of the variable V. For a numeric variable, this
is the actual address of the low-order byte of the number (see above for
details on how numbers are stored in memory). For a string variable, the
address returned by VARPTR is the address of the three-byte record
containing the string's length and a pointer to its data (see above for
details on how strings are stored in memory). Note that position (I - 3)
holds the variable's type (2 for integer, 3 for string, 4 for single, and 8
for double), and positions (I - 2) and (I - 1) hold the first two characters
in the variable's name.

MEM returns I

Returns the amount of memory currently available, in bytes.

FRE ( { V | S | N } ) returns I

Returns the amount of memory currently available for variables of the same
type as the argument. If the type of the argument is numeric, then this is
the same as MEM. If the type of the argument is string, then this indicates
the amount of string heap space available. (The amount of string heap space
available can be changed using the CLEAR command.)

SYSTEM

Puts the machine in monitor mode, giving a "*?" prompt, from which two
commands are available. Entering a filename loads the named
assembly-language file from cassette. Entering "/" executes an unconditional
jump to the starting address of the last program loaded, or entering "/"
followed by an integer I executes an unconditional jump to address I.

USR ( I1 ) returns I2

Calls an assembly-language routine. Prior to calling USR, the address of the
routine must be stored (using, e.g., POKE), little-endian, in addresses
16526 and 16527. Within the assembly-language program, "CALL 0A7FH" loads I1
into the HL register pair, and "JP 0A9AH" returns the HL register pair as
I2. Note that an assembly-language routine called by USR is only allocated 8
stack entries.

OUT B1 , B2
IN ( B1 ) returns B2

OUT sends the value B2 to expansion interface port number B1. IN returns the
value read from port B1 on the expansion interface.

Storage Access

CLOAD S
CSAVE S

Load a file named S from or save it to cassette, respectively.

CLOAD? S

Verifies that program S on tape matches the program in memory.

Keyword Index

? ABS AND ASC ATN AUTO CDBL CHR$ CINT CLEAR CLOAD CLOAD? CLS CONT COS CSAVE
CSNG DATA DEFDBL DEFINT DEFSNG DEFSTR DELETE DIM EDIT ELSE END ERL ERR ERROR
EXP FIX FOR FRE GOSUB GOTO IF INKEY$ INP INPUT INT LEFT$ LEN LET LIST LLIST
LOG LPRINT MEM MID$ NEW NEXT NOT ON OR OUT PEEK POINT POKE POS PRINT PRINT@
RANDOM READ REM RESET RESTORE RESUME RETURN RIGHT$ RND RUN SET SGN SIN SQR
STEP STOP STR$ STRING$ SYSTEM TAB TAN THEN TO TROFF TRON USING USR VAL
VARPTR

Level 3 Keywords

Disk systems enhanced the machine's BASIC to Level 3, storing the routines
in RAM and plugging their locations into the jump tables for the appropriate
keywords. Thus, a number of Level 3 BASIC keywords are reserved words in
Level 2 BASIC, but attempting to use them results in an error. These Level 3
keywords are:

CLOSE   CMD     CVD     CVI     CVS     DEF     EOF     FIELD   FN
GET     INSTR   KILL    LINE    LOAD    LOC     LOF     LSET    MERGE
MKD$    MKI$    MKS$    NAME    OPEN    PUT     RSET    SAVE    TIME$

Acknowledgments

I am grateful for contributions to this page from James Cameron, Pete
Cervasio, Jeff Hunsinger, Gary Katz, Don Moore, and Randy Williams.

Those of you whose name but not email address appears above: I have them,
but I won't put them on here unless you ask me to do so.

----------------------------------------------------------------------------
Email: ganley@cadence.com
Last Modified 22 February 1996
"TRS-80" is a trademark of the Tandy Corporation.
Copyright  1996 J. L. Ganley. All rights reserved.

