Skip to content

Exidy Standard BASIC reference ​

Every command, function and operator in Exidy Standard BASIC, the 8K Microsoft BASIC the Exidy Sorcerer runs from its ROM PAC cartridge.

In this reference: Hardware · Escape codes · File formats · Argument notation

Notes and caveats ​

  • Spaces are thrown away outside strings, REM and DATA, so FORI=1TO10 is valid — and the other side of that rule is that a keyword is recognised inside a name. A variable called TOTAL contains TO and mis-runs without an error of its own; the editor's linter catches the common ones before you run.
  • Only the first two characters of a name are significant, so COUNT and COUNTER are the same variable. $ is the only type suffix: %, ! and # are later Microsoft additions, and X%=1 is a syntax error here.
  • GOTO is one word. GO TO with a space — accepted by several of this BASIC's relatives — answers ?SN ERROR.
  • ^ is the power operator, and it folds left to right, so 2^3^2 is 64. AND, OR and NOT combine their operands bit by bit over sixteen bits, and a true comparison answers -1. There is no integer-division, remainder or exclusive-OR operator: use INT(a/b) and a-b*INT(a/b).
  • PEEK, POKE, INP, OUT and WAIT all take a signed 16-bit number in decimal. Everything from 32768 up has to be written negative — screen RAM at 0xF080 is -3968 — and the positive form answers ?FC ERROR. There is no hexadecimal notation anywhere in this BASIC.
  • String space is 50 bytes until a program says CLEAR n. Assigning a literal (A$="*") costs nothing; joining strings does, and a string may be at most 255 characters long.
  • Several statements share a line with :, and ? is shorthand for PRINT that lists back as PRINT. There is no ' shorthand for REM.

Command Function Operator

Syntax & description
-<number> - <number> | -<number>
Subtracts, or negates a single operand.
*<number> * <number>
Multiplies.
/<number> / <number>
Divides, always in floating point — 7/2 is 3.5, and there is no integer-division operator. Dividing by zero answers ?/0 ERROR and stops the program.
^<number> ^ <number>
Raises to a power, folding left to right, so 2^3^2 is 64. This interpreter has no up-arrow spelling: the caret is the operator, and the caret key also carries a graphics character under GRAPHIC.
+<number> + <number> | <string> + <string>
Adds two numbers, or joins two strings. A joined string is built in the string pool, so concatenation in a loop is what exhausts it.
<<number> < <number> | <string> < <string>
Less than, comparing strings by character code as > does.
<=<number> <= <number> | <string> <= <string>
Less than or equal. Stored as two tokens rather than one, so =< is the same operator written the other way round.
<><number> <> <number> | <string> <> <string>
Not equal, stored as two tokens; >< is the same operator.
=<var> = <expr> | <number> = <number>
Assignment in a LET, and equality everywhere else. The interpreter tells them apart by position, which is why A=B=C assigns the comparison's -1 or 0.
><number> > <number> | <string> > <string>
Greater than. Strings compare by character code, left to right, so a shorter string that is otherwise equal is the smaller one.
>=<number> >= <number> | <string> >= <string>
Greater than or equal, stored as two tokens as <= is.
ABSABS(<number>)
The value without its sign.
AND<number> AND <number>
Combines two values bit by bit over sixteen bits. With comparisons, which answer -1 or 0, that is the logical AND; with other numbers it is a bit mask.
ASCASC(<string>)
The character code of the first character. An empty string answers ?FC ERROR.
ATNATN(<number>)
Arctangent, in radians, between -pi/2 and pi/2.
BYEBYE
Leaves the interpreter and drops into the Monitor, the machine's own firmware command line — where tapes are loaded, memory is examined and the baud rate is set. This is the one word Exidy added to the interpreter, and it is why every token above INPUT is one higher than the Altair's. PP returns to BASIC with the program intact.
CHR$CHR$(<number>)
The one-character string for a code from 0 to 255. Codes 128 to 191 are the standard graphics set and print as shapes; codes below 32 are control codes the screen driver acts on rather than characters it draws.
CLEARCLEAR [<number>]
Discards every variable and array. With a number it also sets the string pool to that many bytes, taken off the top of memory; without one the pool keeps the size it had, 50 bytes until a program says otherwise.
CLOADCLOAD <filename>
Loads a BASIC program from cassette. The name is quoted and only its first five characters are kept, which is all an Exidy tape header carries; the tape is read past until a record with that name is found.
CONTCONT
Resumes a program stopped by STOP or by CTRL-C, from where it left off. Editing any line makes the program uncontinuable and answers ?CN ERROR.
COSCOS(<number>)
Cosine of an angle in radians.
CSAVECSAVE <filename>
Saves the program to cassette as one Exidy record, named by the first five characters of the quoted name. The recorder has to be running before the statement is typed.
DATADATA <constant>[, <constant>]…
Inline constants for READ to consume in program order. Strings may be quoted; the rest of the statement is stored exactly as typed, spaces included.
DEFDEF FN<name>(<numvar>) = <expr>
Defines a one-line numeric function. The body is a single expression, the parameter is local to it, and the definition must have run before the function is called.
DIMDIM <var>(<number>[, <number>]…)
Declares an array and its bounds. Subscripts start at 0, so DIM A(10) has eleven elements; an undeclared array is created with bound 10 on first use, and re-declaring one answers ?DD ERROR.
ENDEND
Stops the program and returns to the READY prompt without printing a BREAK message. Unlike STOP, a program ended this way cannot be resumed with CONT.
EXPEXP(<number>)
e raised to the given power, the inverse of LOG.
FNFN<name>(<number>)
Calls a function made by DEF. The name follows FN with no space, and only its first two characters are significant — as with every other name here.
FORFOR <numvar> = <number> TO <number> [STEP <number>]
Opens a counting loop that runs up to the matching NEXT. STEP sets the increment (default 1, and it may be negative or fractional); the body always runs at least once, because the limit is tested at the NEXT.
FREFRE(<number>) | FRE(<string>)
With a number, the bytes left between the top of the variables and the bottom of the string pool. With a string argument it collects the string pool first and answers the bytes free in that instead, which is 50 on a program that has not said CLEAR.
GOSUBGOSUB <line>
Calls a subroutine, remembering where to come back to. The return addresses are stacked, and the stack shares its memory with the string pool.
GOTOGOTO <line>
Jumps to a line number. It is one word here — GO TO with a space answers ?SN ERROR, unlike the Microsoft BASICs that accept both — and a line that does not exist answers ?UL ERROR.
IFIF <expr> THEN <line> | <statement>
Runs the rest of the line when the value is non-zero. There is no ELSE in this interpreter, so the alternative branch is a separate line reached by falling through.
INPINP(<port>)
Reads a byte from a Z80 input port. Reading the control port at 254 gives the keyboard row last selected, with a pressed key reading 0.
INPUTINPUT [<prompt>;] <var>[, <var>]…
Prints the prompt (or ? when there is none) and waits for a whole line to be typed. This is the machine's only key read — there is no INKEY$ and no GET — so an interactive program takes one turn per typed line.
INTINT(<number>)
The largest whole number not above the value, so INT(-2.5) is -3. Rounding to nearest is INT(x+.5).
LEFT$LEFT$(<string>, <length>)
The leftmost n characters.
LENLEN(<string>)
How many characters a string holds. A string may be up to 255 characters long, whatever the pool has room for.
LET[LET] <var> = <expr>
Assigns a value. The keyword is optional and almost always left out; it costs a byte of program text and nothing else.
LISTLIST [<line>]
Lists the program to the screen, from the given line or from the start. Keywords come back in their canonical spelling, so a line typed with ? lists as PRINT.
LOGLOG(<number>)
Natural logarithm. Logarithms to another base are LOG(x)/LOG(base).
MID$MID$(<string>, <start>[, <length>])
The substring starting at position n, counting from 1, of the given length or to the end. It is a function only: unlike later Microsoft BASICs it cannot be assigned to, and trying answers ?SN ERROR.
NEWNEW
Erases the program and every variable with it, and resets the string pool to 50 bytes. There is no way back afterwards.
NEXTNEXT [<numvar>[, <numvar>]…]
Closes the innermost FOR loop and jumps back to it. Naming the variable closes that loop specifically, and several may be closed in one statement.
NOTNOT <number>
Inverts all sixteen bits of its operand, so NOT 0 is -1 and NOT -1 is 0. That makes it the logical negation of a comparison, which answers -1 for true and 0 for false.
NULLNULL <number>
Sets how many null bytes are sent after each line of output — padding for a printer or a punch that needed time to return the carriage. Nothing on the screen depends on it.
ONON <expr> GOTO | GOSUB <line>[, <line>]…
Jumps or calls the nth line in the list, counting from 1. A value of 0, or one past the end of the list, falls through to the next statement instead of failing.
OR<number> OR <number>
Combines two values bit by bit over sixteen bits, the counterpart of AND. There is no exclusive-OR operator.
OUTOUT <port>, <byte>
Writes a byte to a Z80 output port. The ports that matter here are 0xFC to 0xFF — the serial data, status and control registers and the parallel port — and the control port is also how the keyboard is scanned.
PEEKPEEK(<addr>)
Reads a byte of memory. The address is signed exactly as POKE's is, so reading the screen means PEEK(-3968) and upwards.
POKEPOKE <addr>, <byte>
Writes a byte to memory. The address is a signed 16-bit number, so everything from 32768 up is written negative — screen RAM at 0xF080 is -3968 — and the positive form answers ?FC ERROR.
POSPOS(<number>)
The column the next character will print in, counting from 0. The argument is ignored — it exists because the interpreter's function call always takes one.
PRINT?PRINT [<expr>][;|,]…
Prints to the screen. A semicolon runs the next item straight on, a comma moves to the next 14-column zone, and a trailing separator suppresses the newline. There is no PRINT AT: a position is reached with TAB( across a line, and with a POKE into screen RAM otherwise.
READREAD <var>[, <var>]…
Takes the next constant from the DATA statements, in program order. RESTORE winds the pointer back to the first; running past the last answers ?OD ERROR.
REMREM <comment>
A comment. Everything to the end of the line is stored exactly as typed and never executed, so a REM is the one place a reserved word may be written freely. There is no apostrophe shorthand.
RESTORERESTORE
Winds the DATA pointer back to the first constant in the program. It takes no line number: the whole pointer resets or none of it does.
RETURNRETURN
Returns to the statement after the most recent GOSUB. Without one outstanding it answers ?RG ERROR.
RIGHT$RIGHT$(<string>, <length>)
The rightmost n characters.
RNDRND(<number>)
A random number from 0 up to but not including 1. A positive argument gives the next number in the sequence, 0 repeats the one just given, and a negative argument reseeds from that value — so the same negative seed replays the same run.
RUNRUN [<line>]
Clears the variables and starts the program, from the given line or from the first. Because it clears, RUN 100 is not a way to resume — that is CONT.
SGNSGN(<number>)
-1, 0 or 1 according to the sign of the value.
SINSIN(<number>)
Sine of an angle in radians.
SPC(SPC(<number>)
Prints the given number of spaces. Unlike TAB( it is relative, so it always moves. Valid inside PRINT alone.
SQRSQR(<number>)
Square root. A negative argument answers ?FC ERROR.
STEPFOR <numvar> = <number> TO <number> STEP <number>
The amount a FOR loop adds each time round. It may be negative or fractional, and a step of 0 loops for ever.
STOPSTOP
Halts the program and prints BREAK IN <line>. CONT resumes from the statement after it, which is what separates STOP from END.
STR$STR$(<number>)
A number as the characters PRINT would have shown, leading space for the sign included.
TAB(TAB(<number>)
Moves the print position to the given column, counting from 0. It only ever moves forward: a column already passed is ignored rather than wrapping to the next line. Valid inside PRINT alone.
TANTAN(<number>)
Tangent of an angle in radians.
THENIF <expr> THEN <line> | <statement>
Introduces what an IF does when its value is non-zero. A bare line number after THEN means GOTO that line.
TOFOR <numvar> = <number> TO <number>
The limit of a FOR loop. It is a reserved word wherever it appears, which is why a variable named TOTAL contains a keyword and mis-runs.
USRUSR(<number>)
Calls machine code at one fixed vector, whose address is poked into 260 and 261 low byte first. The argument is not passed and the result is not returned — calling it before the vector is set answers ?FC ERROR — so a routine takes and gives back its values by poking bytes the program then PEEKs.
VALVAL(<string>)
The number at the front of a string, or 0 where there is none. It stops at the first character that cannot be part of a number.
WAITWAIT <port>, <mask>[, <mask>]
Spins until an input port, exclusive-ORed with the third argument and masked by the second, is non-zero. Nothing but a key or a hardware signal will end the wait, and CTRL-C cannot interrupt it.
Argument notation

Anything in <angle brackets> is a value you supply; everything else is typed exactly as shown. [square brackets] mark an optional part, | separates alternatives, and … means the part before it can repeat. The arguments on this page are:

<number>
a numeric expression
<string>
a string expression
<expr>
a value of either type, where the keyword takes both
<byte>
a value from 0 to 255
<constant>
a literal number or string, not an expression
<var>
a variable of either type
<numvar>
a numeric variable
<line>
a line number
<statement>
one BASIC statement
<comment>
free text, to the end of the line
<name>
a name the program defines for a function or procedure
<start>
the position something starts at, counting from 1
<length>
how many characters
<prompt>
text shown before the input; a literal, not an expression
<filename>
the name of a file on tape or disc
<addr>
a memory address
<port>
an input/output port, by number
<mask>
a bit mask, one bit per item

Showing 74 of 74 keywords

The ROM PAC ​

BASIC is not firmware on this machine. The Sorcerer's own 4 KB Monitor is what starts, and Exidy Standard BASIC arrives in a ROM PAC, an 8 KB cartridge the Monitor finds in the cartridge window and enters without being asked. That is why the machine signs on in BASIC, and why BYE has somewhere to go: it leaves the interpreter for the Monitor's own command line, and PP there comes back with the program intact.

The consequence for a program is the 4 KB of firmware underneath. Everything the screen does — the cursor moves, the clear, the scroll — is the Monitor's screen driver rather than the interpreter's, which is why those are control codes sent through PRINT and not keywords. The escape codes page lists each of them.

Released under GNU GPL v3.0. Some ROM images are third-party copyrighted works, separate to this project, strictly for personal/educational purposes.