Dartmouth BASIC reference
Every command, function and operator in Dartmouth BASIC — the first BASIC there was, and the ancestor of every other one on this site. Two machines ran it here: the GE-235, compiling the February 1965 language, and the GE-635, compiling the fourth edition of January 1968.
The GE-235 has nothing the GE-635 has not, so rows badged 4th edition only are what the later machine added — strings, matrices, ON, RESTORE, RANDOMIZE, TAB and the rest. Rows both machines have but read differently — INT, RND, FOR, PRINT, DATA — say how in the row itself.
In this reference: Hardware · Escape codes · File formats · Argument notation
Notes and caveats
Shared by both
LETis never optional. A line opening with a letter matches no statement, so10 A=1is rejected as a bad instruction. This is the single most common thing to trip on when bringing a program back to either machine.- One statement to a line: there is no
:separator and no shorthand for any keyword.ENDis mandatory and must be the highest-numbered line. - A variable name is one letter, optionally followed by one digit:
A,A1,Z9.A12is not a name. An array is named by a bare letter, soAandA(0)are two different places to put a number. - Blanks are deleted before a line is read, so
FORI=1TO10is a loop andP R I N TisPRINT. The usual companion trap does not arise: no name is long enough to contain a keyword. - A comparison is not a value. The six relations exist only between
IFandTHEN;=<and=>are refused.THENtakes a line number and nothing else, and there is noELSE. There is noAND,ORorNOTeither, no integer division and no remainder — writeA-B*INT(A/B). - Neither machine has a file statement of any kind, and neither can name an address: there is no
PEEK, noPOKEand noUSR.
On the GE-235
- There are no strings at all — no string variables, no
A$, no string functions, no string expressions. The only text a program can produce is a literal insidePRINT, and a literal is never a value. - Line numbers run 0 to 99999 and a program may be 240 lines long. There is no
RESTORE, so theDATApointer never rewinds, and noRANDOMIZE, so every run deals the same sequence. - Every fault stops the program. The compiler lists what is wrong with the whole program and refuses to run it; the run-time reports one fault, names the line, and stops. Nothing resumes — there is no
CONTand no error trapping. INTwalks towards zero from both sides, soINT(-2.35)is-2andINT(X+.5)trims rather than rounds.RNDrequires an argument and ignores it. AFORtests its limit at theNEXT, so the body always runs once.
On the GE-635
- Strings arrive, and almost nothing to do with them. There is no concatenation operator and no string function:
CHANGEmoves a string to a numeric vector of character codes and back, and that is the whole of the machinery. String vectors exist; string matrices do not. - Numeric and string
DATAare separate blocks, matched to variables by type. A string constant needs no quotes if it starts with a letter, and must have them otherwise or if it contains a comma. - Most run-time faults do not stop the program. A division by zero, an overflow, an underflow,
LOGorSQRof a negative number each print a message, supply a value and carry on, so a program can reach itsENDwith faults printed above the answers. Only running out ofDATA, a bad subscript, aGOSUBfault, a dimension clash and an out-of-rangeONstop the run. INTfloors, soINT(-2.35)is-3andINT(X+.5)rounds.RNDtakes no argument at all — writeINT(10*RND). AFORtests its limit on entry, soFOR Z = 2 TO -2with no negative step never runs its body.- An apostrophe at the end of a working line starts a remark — except on a line that ends inside a string, which swallows it.
Command Function Operator
| Syntax & description | |
|---|---|
- | <number> - <number>Subtract, and negate a single operand. |
* | <number> * <number>Multiply. |
/ | <number> / <number>Divide. There is no integer division and no remainder operator, so write A-B*INT(A/B). Division by zero stops the GE-235; the GE-635 prints the fault, supplies a very large number and carries on. |
↑ | <number> ↑ <number>Raises to a power, binding tighter than anything else and grouping left to right, so A↑B↑C raises A to the B and that result to the C. It is the up arrow printed on the Teletype Model 33 keyboard, where a later machine has ^; neither ^ nor ** exists here. The GE-235 stops for zero to a negative power or a negative number raised to anything; the GE-635 multiplies a negative base out when the exponent is a whole number, and otherwise prints a fault, uses the absolute value and carries on. |
+ | <number> + <number>Add. There is nothing else it can do on either machine: the GE-235 has no string type, and the GE-635 has strings but no concatenation operator to join them with. |
< | IF <expr> < <expr> THEN <line>Less than. On the GE-635 it also orders strings, where it means earlier in alphabetical order and trailing blanks do not count, so "YES" and "YES " are equal. |
<= | IF <expr> <= <expr> THEN <line>Less than or equal. The decoder reads the < first, so =< is not another spelling of it. |
<> | IF <expr> <> <expr> THEN <line>Not equal. There is no other spelling of it. |
= | LET <var> = <expr> | IF <expr> = <expr> THEN <line>Assignment in a LET, equality between IF and THEN. The two are separate jobs rather than one: a comparison is not a value here, so it cannot be assigned, printed or added to anything. |
> | IF <expr> > <expr> THEN <line>Greater than. |
>= | IF <expr> >= <expr> THEN <line>Greater than or equal, and as with <= only in that order — => is refused. |
ABS | ABS(<number>)The absolute value. The GE-235 has no SGN to pair it with, so the sign of X there is X/ABS(X), guarded against zero. |
ATN | ATN(<number>)Arctangent, in radians, between -π/2 and π/2. There is no two-argument form and no π constant — write 4*ATN(1). |
CHANGE4th edition only | CHANGE <strvar> TO <numvar> | CHANGE <numvar> TO <strvar>Takes a string apart into character codes, or builds one back out of them. Left to right it puts the length in the vector’s zero component and the code of each character in the components above; right to left it reads the length back out of the zero component and makes a string that long. This is the whole of the machine’s string machinery — there is no length function, no substring and no concatenation — so reaching one character means changing the string to a vector and back. |
CON4th edition only | MAT <letter> = CON[(<number>[, <number>])]Stands for an array of ones, and only inside a MAT. Given a size it redimensions the array it fills; given none it fills the array at whatever size it already has. |
COS | COS(<number>)Cosine of an angle given in radians. |
COT4th edition only | COT(<number>)Cotangent of an angle given in radians, which is 1/TAN(X) without the division. There is no SEC and no CSC to go with it. |
DATA | DATA <constant>[, <constant>]…Constants for READ to take in turn, gathered from the whole program in line order before it runs. On the GE-235 they are numbers and nothing else, the pointer only moves forwards, and a program may carry 128 of them in all. The GE-635 keeps two independent blocks, one numeric and one string, and matches each constant to the type of the variable reading it; a string there needs no quotes if it starts with a letter, and must have them if it starts with anything else or holds a comma. |
DEF | DEF FN<name>(<param>) = <number> | DEF FN<name>([<param>[, <param>]…])Defines a function. The name is FN followed by a letter, and unlike the later BASICs that copied it the definition need not have run before the call: every DEF is collected before anything executes, so a function may be defined at the foot of the program and used at the top. The GE-235 takes one parameter and one line. The GE-635 takes none, one or several, and a DEF written without the = runs on over as many lines as it likes to an FNEND, its value being whatever the body last assigned to the function’s own name. |
DET4th edition only | DETThe determinant of the matrix the last MAT INV inverted. It takes no argument and means nothing before an inversion has happened; a determinant of zero says the inverse it just produced is worthless. |
DIM | DIM <var>(<number>[, <number>])Declares an array bigger than the 11, or 11 by 11, any subscripted name gets for free. Subscripts count from 0, so DIM A(20) has twenty-one elements, and several arrays may be declared in one statement, separated by commas. On the GE-235 the bounds must be plain constants — nothing is evaluated there. The GE-635 dimensions a string vector the same way, which is the only kind of array a string may have: there are no string matrices. |
END | ENDEnds the program. It is not optional and it is not merely conventional: the compiler refuses a program without one, and refuses one whose END is not the highest-numbered line. |
EXP | EXP(<number>)e raised to the given power. Far enough either way and the result overflows or underflows: the GE-235 stops for it, while the GE-635 prints the fault, supplies a value and carries on. |
FN | FN<name>(<arg>)Calls a function DEF defined. The argument is substituted into the definition wherever its parameter appears; a name no DEF defines is a compile fault, not a run-time one. |
FNEND4th edition only | FNENDCloses a multiple-line DEF. The lines between the two are the body, and the function’s value is whatever was last assigned to its own name; nothing may jump into or out of the range, so the body is reached only by calling it. |
FOR | FOR <numvar> = <number> TO <number> [STEP <number>]Opens a counting loop that runs to the matching NEXT. STEP sets the increment, which may be negative or fractional; left out it is 1. The loop variable is a plain variable and keeps its value after the loop ends. The two machines test the limit at opposite ends: the GE-235 runs the body and then tests, so a loop always runs once, while the GE-635 tests on entry — written FOR Z = 2 TO -2 with no negative step, its body is never performed. Thirteen loops may be open at once on the GE-235. |
GOSUB | GOSUB <line>Calls a subroutine, remembering the line to come back to, and RETURN comes back. On the GE-235 calls may nest 162 deep — the return stack is whatever the run-time leaves free. The GE-635’s manual states no depth, and going too deep there is one of the few faults that stops the program outright. |
GOTO | GOTO <line>Jumps to a line number. Blanks are deleted before the line is read, so GO TO written as two words is the same statement. |
IDN4th edition only | MAT <letter> = IDNStands for the identity matrix — ones down the diagonal, zeros elsewhere — at the size the array already has. It is the matrix MAT A = B*INV(B) should give back. |
IF | IF <number> <relation> <number> THEN <line>Compares two values and jumps when the comparison holds. The line number is the whole of what THEN may take: there is no THEN followed by a statement and no ELSE, so a two-way choice is a jump over a jump. There is no AND, OR or NOT on either machine, so a compound test is a chain of IFs each jumping to the next. On the GE-635 the two sides may be strings, compared in alphabetical order with trailing blanks ignored. |
INPUT | INPUT <var>[, <var>]…Prints a question mark and waits for values to be typed at the teletype, one per variable, separated by commas. It takes no prompt string on either machine — PRINT the wording first, ending it with a semicolon to keep the question mark on the same line. The GE-235 reads numbers only. The GE-635 reads a string into a string variable, which is the only way a program there can read a letter. |
INT | INT(<number>)The whole-number part, and the one place the two machines disagree about arithmetic. The GE-635 floors, so INT(-2.35) is -3 and INT(X+.5) rounds; the GE-235 walks towards zero from both sides, so INT(-2.35) is -2 and the same expression trims rather than rounds. It is also the rule applied to an array subscript. |
INV4th edition only | MAT <letter> = INV(<letter>)The inverse of a square matrix, and only inside a MAT. DET afterwards gives the determinant of what was inverted, which is how a program tells a singular matrix from an invertible one. |
LET | LET <var> = <expr>Assigns a value, to a variable or to an array element. The keyword is mandatory on both machines and in no later BASIC: a line opening with a letter reaches no statement at all, so 10 A=1 is rejected as a bad instruction. The GE-635 allows the assignment to be chained — LET X = Y3 = A(3,1) = 1 gives the one value to all three. |
LOG | LOG(<number>)Natural logarithm. There is no LOG10, so divide by LOG(10). Zero and negative arguments each have a fault of their own, which stops the GE-235 and which the GE-635 prints before carrying on. |
MAT4th edition only | MAT <letter> = <expr> | MAT READ <letter> | MAT PRINT <letter>Operates on a whole vector or matrix in one statement. MAT READ, MAT PRINT and MAT INPUT move a whole array at a time; MAT B = A copies, and A+B, A-B, A*B, TRN(A), (K)*A and INV(A) build one. Naming a size — MAT READ M(17,30), MAT M = CON(7,3) — redimensions as it goes. Every array has a row and column 0 and MAT ignores them, so a MAT READ M(2,2) reads four elements and zeroes what row 0 held. |
NEXT | NEXT <numvar>Adds the step, tests the limit, and goes back to the FOR when the loop is not finished. The variable must be named and must be the innermost open loop, so loops cannot be closed out of order or several at once. |
NUM4th edition only | NUMHow many values the last MAT INPUT actually read. It takes no argument, and it is the only way to find out how long a typed list was: MAT INPUT accepts as many as the operator cares to type, up to the array’s size. |
ON4th edition only | ON <number> GO TO <line>[, <line>]…Jumps to the first line listed when the value is 1, the second when it is 2, and so on; the value is truncated to a whole number first. A value below 1 or past the end of the list stops the program. It is the machine’s only computed jump — there is no ON … GOSUB. |
PRINT | PRINT [<item>][;|,]…Prints values and quoted literals on the paper. A comma moves to the next of five fifteen-column zones; a semicolon packs items up, each number already carrying a leading sign-or-space and a trailing blank. Either one at the end of the statement holds the line open for the next PRINT. The line is 72 columns on the GE-235 and 75 on the GE-635, where TAB may also be used to place the carriage. |
RANDOM4th edition only | RANDOMThe manual’s own short spelling of RANDOMIZE, and the same statement. |
RANDOMIZE4th edition only | RANDOMIZEReseeds RND so that repeated runs differ. Without it the sequence is the same every time, which is what makes a program repeatable while it is being written — put the RANDOMIZE in last. |
READ | READ <var>[, <var>]…Takes the next constants from the DATA statements, one per variable. Reading past the last of them stops the program on both machines. On the GE-235 that is final — there is no RESTORE, so a list can be read once and once only; the GE-635 can wind either of its two blocks back and read them again. |
REM | REM <comment>A remark, ignored to the end of the line. It is a statement like any other, so it needs a line number of its own. The GE-635 has a second form for the same job: an apostrophe at the end of a working line starts a remark — except on a line ending inside a string, which swallows it. |
RESTORE4th edition only | RESTOREWinds both DATA pointers back to the first constant, so the whole list can be read again. Numeric and string DATA are separate blocks here, and this is the statement that restores them together. |
RESTORE*4th edition only | RESTORE*Winds only the numeric DATA back, leaving the string pointer where it stands. |
RESTORE$4th edition only | RESTORE$Winds only the string DATA back, leaving the numeric pointer where it stands. |
RETURN | RETURNReturns to the statement after the GOSUB that called this subroutine. Reaching one with no call outstanding stops the program. |
RND | RND(<number>) | RNDThe next number in a sequence between 0 and 1. The GE-235 requires an argument and ignores it, and its sequence is the same on every run — there is no RANDOMIZE, so a program wanting variety asks the user for a number and folds it in itself. The GE-635 takes no argument at all, which is why its own examples read INT(10*RND), and RANDOMIZE reseeds it. |
SGN4th edition only | SGN(<number>)The sign of the argument: 1 above zero, 0 at it, -1 below. It is what saves the GE-235’s X/ABS(X) and its guard against zero. |
SIN | SIN(<number>)Sine of an angle given in radians. |
SQR | SQR(<number>)Square root. A negative argument stops the GE-235; the GE-635 prints the fault, takes the root of the absolute value and carries on. |
STEP | FOR <numvar> = <number> TO <number> STEP <number>The amount a FOR loop adds each time round, which may be negative or fractional. Without it the step is 1. |
STOP | STOPHalts the program wherever it stands, exactly as reaching END would. Nothing resumes afterwards: neither machine has a CONT. |
TAB4th edition only | PRINT TAB(<col>)Moves the carriage to a column, counted from 0, and only inside a PRINT. The positions on a line are numbered 0 through 74 and 75 is position 0 of the next line; a TAB to a column the carriage is already past does nothing rather than starting a new line. |
TAN | TAN(<number>)Tangent of an angle given in radians. |
THEN | IF <number> <relation> <number> THEN <line>Introduces what an IF does, and all it may introduce is a line number to jump to. THEN followed by a statement is a later idea. |
TO | FOR <numvar> = <number> TO <number>The limit of a FOR loop. Because blanks are deleted before the line is read, a variable name cannot contain it — but no name here is long enough to, so the trap that catches TOTAL on later machines cannot arise. CHANGE borrows the word to separate its two variables. |
TRN4th edition only | MAT <letter> = TRN(<letter>)The transpose of a matrix — rows for columns — and only inside a MAT. The result is redimensioned to fit, so a 3 by 7 transposed gives a 7 by 3. |
ZER4th edition only | MAT <letter> = ZER[(<number>[, <number>])]Stands for an array of zeros, and only inside a MAT. Given a size it redimensions the array it clears, which is the usual way to set a working size before a MAT READ. |
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
<expr>- a value of either type, where the keyword takes both
<constant>- a literal number or string, not an expression
<var>- a variable of either type
<numvar>- a numeric variable
<strvar>- a string variable
<letter>- a single letter
<line>- a line number
<comment>- free text, to the end of the line
<name>- a name the program defines for a function or procedure
<param>- a parameter, where the definition introduces it
<arg>- a value, where the call passes it
<col>- a text column
<relation>- one of = < > <= >= <>, and only between IF and THEN
<item>- something to print: a number, a literal in quotes, or a string
Showing 60 of 60 keywords