TRS-80 Model I Level 2 BASIC Language Reference
By Joe Ganley
The following is republished here, unchanged (other than this line), with permission of Ron Kneusel
This document is in beta release and has been discontinued by its prior author.
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 withI
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 isletter {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 Floating Point Numbers Are 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.
Clears the screen and returns the cursor to the upper left.
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
deletesI
characters. -
I
enters insert mode. In insert mode, characters are inserted as they are typed. -
SHIFT-[
leaves insert mode.
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.
Erases all program data and variables currently in memory.
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).
Runs the program starting with line L
, or starting
with the first line if L
is absent.
Turns tracing on or off, respectively. When tracing is on, the line numbers being executed are printed as they are run.
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.
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.
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.
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.
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.
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
.
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.
Stops the program just as if the user had hit BREAK
.
Stops the program like STOP
, but without the
“BREAK IN line
” message being printed.
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
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.
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.
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
Storage Access
Load a file named
Verifies that program S on tape matches the program in memory.
Keyword IndexUSR
, 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.
CLOAD S
CSAVE S
S
from or save it to cassette,
respectively.
?
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.Last Modified 23 April 1997
“TRS-80” is a trademark of the Tandy Corporation.
Copyright © 1996-97 J. L. Ganley. All rights reserved.
The TRS80 stuff looks great. I’m trying to get a program from 40 years ago into this but I am having some problems.
Using Windows 7 64 bit and the TRS80 emulator seems to work fine on command line.
I am trying to redo a very old program that I used on a very much computer (OSI C24P) and have used the Windows text editor to type in hundreds of lines of code. When I try to copy this code into TRS80 BASIC it looks like I’m trying to do this from a cassette at 300 baud.
The program isn’t all that important, but I would like to get it to work again. I am retired but in these days of pandemic I am trying to school some children in code writing. I thought that your BASIC from decades ago would be a good start.
I got the program from a book BUSINESS Programming Applications by William Barden. In the late 1970’s I was able to wright code for a spreadsheet that helped me with expense reports.
In the early 1980’s I was able to wright programs for other techs to deal with not only their expense reports but also with customer location and some customer ‘preferences’.
So sorry but just trying to get my chops back.
If I do a program in Windows Notepad and do a control a and then go to sdltrls and do a control z it takes absolutely forever to transfer the file. Once the file is there is there any way that I can capture the file so I don’t have to do the hours long transfer again?
There should be a way to mount disks and do a disk load and a disk save.
Loading from and saving to cassette is just too slow.
Use trs80gp and simply “Load…” the BASIC text file from the “File” menu.
You will need to select “All files” from the file-type dropdown for it to show .txt files, but that’s no problem.
It will load instantly, but with no feedback that it did!
FYI, there’s an error on this page when it compares Disk BASIC to Level III BASIC. They are NOT the same thing! Disk BASIC didn’t have the advanced graphics commands and worked in different ways.