BASIC programs can use any BASIC-DOS command in combination with the BASIC statements described below, along with any of the BASIC Functions. See BASIC-DOS Programming for an overview of programs, variables, and expressions.
CHAIN [MERGE] file[,[line][,ALL]]
Replaces the running program with the specified BAS file and runs it, as in Microsoft BASIC. If the file isn’t in the current directory, and its name doesn’t include a drive or directory, the directories listed in PATH$ are searched, and if the name has no extension, .BAS is added (trailing spaces are ignored, so CHAIN "MARCH " loads MARCH.BAS).
The new program starts at line if one is given, otherwise at its first line. Its variables start out cleared, unless ALL is given, in which case all the variables (and arrays) of the old program are kept. Any GOSUBs, FOR and WHILE loops, and ON ERROR handler in progress are ended, and READ starts over at the first DATA item. Files that are open remain open.
With MERGE, the file’s numbered lines are added to the program instead of replacing it, and any line with the same number is replaced (as if typed at the prompt; see MERGE), so a program can load data or subroutines from other files. For example, the MUSIC.BAS sample loads each song (a file of DATA statements numbered 3000 and up) and then plays it with:
1770 PRINT " ";CMD$;"-";S$:CHAIN MERGE S$,1780,ALL
If the file can’t be found, the error is “File not found” (53), which an ON ERROR handler can catch. Any other error loading the file (eg, an unnumbered line in a MERGE file) ends the program. When the program ends, the chained program remains loaded (eg, for LIST or RUN).
COMMON and CHAIN’s DELETE option are not supported.
CLEAR [[n][,[m][,k]]]
Resets all numeric variables to zero and all string variables to empty strings, and erases all arrays. The values are accepted for compatibility with Microsoft BASIC, but are ignored.
CLOSE [[#]n[,[#]n]…]
Closes the specified files, or all files if none are specified (see OPEN). Closing a file that isn’t open does nothing. RESET is the same as CLOSE without file numbers.
A DOS close or metadata commit failure raises “Device I/O error” (57). The affected file is closed even when this error occurs.
DATA item[,item]…
Defines items for READ to assign to variables. DATA statements aren’t executed (but a DATA statement can be followed by other statements on the same line, after a colon), and READ uses their items in the order they appear in the program. An item can be a number or a string; a string can be in quotes (and can then contain commas and colons), and an unquoted string has any leading and trailing spaces removed.
READ NAME$, AGE
PRINT NAME$; " is"; AGE
DATA "SMITH, JOHN", 42
DEF function[(parameters)]=expression
Defines a function. See DEF.
DEF SEG[=segment]
Sets the segment that PEEK and POKE use. Without a segment, BASIC-DOS’s own data segment is used.
DEFDBL [letter(s)]
Defines the first letter(s) of variables that will default to double-precision (64-bit) floating-point values (eg, DEFDBL A-F,X). Variables default to double-precision unless DEFINT or DEFSTR is used (or floating-point support is disabled). Every program starts with these defaults, as in Microsoft BASIC, so DEFDBL, DEFINT, and DEFSTR statements from another program (or typed at the prompt) don’t carry over. The exception is a BAT file, which starts with an implied DEFINT A-Z (see DEFINT).
DEFINT [letter(s)]
Defines the first letter(s) of variables that will default to integer (32-bit) values (eg, DEFINT A-Z). Integer operations are much faster than floating-point operations, so programs that don’t need fractions should use DEFINT.
BAT files start with an implied DEFINT A-Z, since batch files rarely need fractions; a BAT file can still use suffixes (eg, X#) or DEFDBL for floating-point variables. Note that assigning a fraction to an integer variable rounds it (eg, A = 7/2 sets A to 4).
DEFSNG [letter(s)]
Same as DEFDBL, since all floating-point values are double-precision.
DEFSTR [letter(s)]
Defines the first letter(s) of variables that will default to string values. Unless DEFSTR is used, all string variables must be defined using the $ suffix.
DIM array(bounds)[,array(bounds)]…
Dimensions one or more arrays, with up to 255 dimensions each (eg, DIM A(10), B$(5,5)). Each bound is the largest subscript for that dimension. Arrays that are used without DIM have a largest subscript of 10.
Using a subscript outside an array’s bounds causes a “Subscript out of range” error, and dimensioning an array that’s already dimensioned causes a “Duplicate definition” error (use ERASE first).
DOS ax[,bx[,cx[,dx string]]]
Calls DOS (INT 21h) with the values in registers AX, BX, CX, and DX (omitted values are zero), so that a program can use DOS functions that BASIC-DOS has no statement for (eg, 43h, to get or set a file’s attributes). The last value can be a string instead, which DOS gets a null-terminated copy of in DS:DX (eg, a filename). The DOS function returns the registers that DOS returned.
A failure (ie, DOS returned with carry set) is a runtime error that ON ERROR can handle: “File not found” (53), “Path/File access error” (75), “Permission denied” (70), “Bad file number” (52), “Illegal function call” (5) for an invalid function, or one of the errors that IOCTL # reports.
DOS &H4300, 0, 0, F$ ' get the attributes of F$
DOS &H4301, 0, DOS(2) OR 1, F$ ' and make it read-only
END
STOP
SYSTEM
Ends the program. STOP and SYSTEM are currently the same as END.
ERASE array[,array]…
Erases the specified arrays, so that they can be dimensioned again. If the first name is not an array, ERASE is the same as DEL.
ERROR n
Simulates error n (1-255). If an ON ERROR handler is active, it’s called; otherwise, the program ends with an error message (eg, ERROR 5 displays “Illegal function call”), or “Unknown error (n)” if the error has no message of its own.
FIELD [#]n,width AS variable$[,width AS variable$]…
Divides each record of random access file n into fields (up to 16), which must fit in the record length (see OPEN), or it’s a “FIELD overflow” error (50). GET # then sets each variable to its part of the record, and PUT # writes each variable to its part of the record, padded with spaces (or truncated) to its width; use LSET or RSET to set the variables. Unlike Microsoft BASIC, the variables are ordinary string variables (assigning one with LET doesn’t detach it from its field), and only one FIELD statement per file is in effect at a time.
FOR variable=start TO limit [STEP step]
statement(s)
NEXT [variable[,variable]…]
Executes the statements up to the matching NEXT repeatedly, adding step (default 1) to the variable each time, until it passes the limit. If the start is already past the limit, the statements are skipped.
NEXT without a variable ends the innermost FOR loop; otherwise, it ends the FOR loop for each variable listed. FOR loops with integer variables (eg, after DEFINT A-Z) are much faster than those with floating-point variables.
FOR I = 10 TO 1 STEP -3:PRINT I;:NEXT
10 7 4 1
GET [#]n[,record]
Reads the specified record of random access file n (or the record after the last one used, if record is omitted) and sets each FIELD variable to its part of the record. Records are numbered from 1; any part of a record past the end of the file is zeros. An invalid record is a “Bad record number” error (63). GET (x1,y1)-(x2,y2),array is the graphics GET.
A DOS seek or read failure raises “Device I/O error” (57), preserving the FIELD variables and last completed record number.
GOSUB label
Calls the subroutine at the line with the specified label number; the subroutine ends with RETURN.
GOSUB 100
PRINT "Back"
END
100 PRINT "In subroutine"
RETURN
GOTO label
Transfers program control to the line with the specified label number. See GOTO.
IF expression THEN statement(s) [ELSE statement(s)]
Executes statements based on the value of an expression. See IF.
INPUT [prompt;|,]variable[,variable]…
INPUT #n,variable[,variable]…
Reads the next item of file n (which must be open for INPUT) into each variable, as READ does with DATA items. Leading spaces, tabs, and line breaks are skipped, and an item ends at a comma or line break, or for a numeric variable, at a space or tab, too. A quoted item ends at its closing quote, and can contain commas. This means INPUT # can read back what PRINT # (or WRITE) wrote. Reading past the end of the file is an “Input past end” error (see EOF).
Without #n, INPUT displays the prompt (if any), followed by “? “ (unless a comma follows the prompt), reads a line from the keyboard, and takes the items from that line the same way. Unlike Microsoft BASIC, missing items are simply empty (or zero), and extra items are ignored, instead of displaying “Redo from start”.
INPUT "Name and age"; N$, A
IOCTL [#]n,code[,value string[,value]]
Sends an IOCTL request (INT 21h function 44h) with the specified code to the device or volume open as file n: a numeric value is passed in CX (and a second value in DX), or a string’s data is passed with the request (with its length in CX). What each code does is up to the driver (see IOCTL Functions); for example, FORMAT.BAS gives a volume its parameters with the diskette driver’s IOCTL_SETPARMS (&HF1) request, and formats each track with IOCTL_FORMAT (&HF2).
A failure is a runtime error that ON ERROR can handle: “Illegal function call” (5) for a request the driver doesn’t support, “Permission denied” (70) for a write-protected diskette, “Disk not ready” (71), “Disk media error” (72), or “Device I/O error” (57). To receive data from a driver, use the IOCTL$ function.
OPEN "A:" FOR OUTPUT AS #1
IOCTL #1, &HF2, 0, 0 ' format cylinder 0, head 0
[LET] variable=expression
Assigns the value of an expression to a variable. See LET.
LINE INPUT [prompt;]variable$
LINE INPUT #n,variable$
Reads the next line of file n (which must be open for INPUT), or without #n, displays the prompt (if any) and reads a line from the keyboard, into the string variable. The line ends at a CR, LF, or CRLF, which isn’t included. A line longer than 255 characters is read 255 characters at a time.
LSET variable$=string
RSET variable$=string
Sets the variable to string, left-justified (LSET) or right-justified (RSET), padded with spaces or truncated to the variable’s FIELD width (or if it isn’t a FIELD variable, to its current length). Use MKI$, MKL$, and MKD$ to store numbers in fields, and CVI, CVL, and CVD to convert them back.
ON expression GOTO label[,label]…
ON expression GOSUB label[,label]…
Transfers program control to (or calls) the Nth label, where N is the value of the expression. If N is zero or greater than the number of labels, the program continues with the next statement.
ON ERROR GOTO label
ON ERROR GOTO 0
Transfers program control to the label when a runtime error occurs, where the ERR function returns the error number, and RESUME continues the program. ON ERROR GOTO 0 disables error handling. An error that occurs while the handler is running (ie, before RESUME) ends the program.
The handler starts with the stack as it was at the start of the statement with the error, so any GOSUBs that were active are still active, and after RESUME, RETURN returns from them as usual.
Error numbers are the same as Microsoft BASIC’s (eg, 5 for “Illegal function call”, 7 for “Out of memory”, and 9 for “Subscript out of range”).
ON ERROR GOTO 100
ERROR 5
END
100 PRINT "Error"; ERR
RESUME 200
200 PRINT "Done"
OPEN file [FOR INPUT OUTPUT APPEND RANDOM] AS [#]n [LEN=reclen]
Opens file as file number n (1-4): FOR INPUT reads an existing file, FOR OUTPUT creates the file (or truncates it if it exists), and FOR APPEND adds to the end of the file (creating it if necessary). FOR RANDOM (or no FOR at all) opens the file for random access (creating it if necessary), with records of reclen bytes (1-255; the default is 128), using FIELD, GET #, and PUT #; a device opened without FOR (see below) can be both read and written instead. A read-only file (see ATTRIB) can’t be opened FOR OUTPUT or APPEND (“Path/File access error”), but FOR RANDOM opens it for reading only, as MSBASIC does, so a PUT # to it is a “Permission denied” error (70). Files that a program leaves open are closed when it ends. A file can be open for INPUT more than once, but a file open for OUTPUT or APPEND can’t be opened again, in this session or any other (“File already open”).
A file that is only a drive letter and colon (eg, "C:") opens the drive’s entire volume, so that its sectors can be read (and written, FOR RANDOM) as records: with a record length of 128, for example, sector n begins at record n * 4 + 1. FOR OUTPUT opens the volume for writing as a stream, starting with its first sector (nothing is truncated), which is how FORMAT.BAS writes a new diskette’s boot sector, FATs, and root directory. A volume can be opened FOR INPUT only if no file on it is open for writing, and for writing only if no file on it is open at all; while the volume is open, conflicting opens, as well as creating, deleting, or renaming files and directories on it, fail. Since record numbers range from 1 to 65535, only the first 65535 records of a volume are accessible. A volume whose media is unknown (eg, an unformatted diskette) can still be opened (without a critical error prompt), with a size of zero until the driver is given its parameters (see IOCTL #).
A file can also be a device (eg, "LPT1:" or "CON"). As in Microsoft BASIC, "SCRN:" is the screen (the session’s console, CON), and a serial port’s name can be followed by its settings, baud[,parity[,data[,stop]]], which are set when the port is opened (eg, OPEN "COM1:300,E,7,1" AS #1; see MODE). A device opened without FOR can be used for both input and output: PRINT #, WRITE #, INPUT #, LINE INPUT #, and the INPUT$ function, and for a serial port, EOF is true if no characters are waiting, and LOC returns how many are waiting (up to 255). A device name (four letters and a colon, eg, "COM2:") that can’t be opened, because there’s no such device, is a “Device unavailable” error (68).
Errors are runtime errors that ON ERROR can handle: “FIELD overflow” (50), “Bad file number” (52) for a number other than 1-4 or a file that isn’t open, “File not found” (53), “Bad file mode” (54) for using a file in a way its mode doesn’t allow (eg, reading a file opened for output), “File already open” (55), “Input past end” (62), “Bad record number” (63), “Device unavailable” (68), and “Path/File access error” (75). An invalid record length is an “Illegal function call” (5).
OPEN "SCORES.DAT" FOR OUTPUT AS #1
PRINT #1, "Alice"; 90
CLOSE #1
OPEN "SCORES.DAT" FOR INPUT AS #1
WHILE NOT EOF(1)
INPUT #1, N$, S
PRINT N$, S
WEND
CLOSE
OPTION BASE 0 1
Sets the smallest subscript (0 or 1) of arrays dimensioned afterward. The default is 0.
POKE offset,value
Stores value (0-255) at offset in the segment set by DEF SEG.
PRINT #n,[expression][; ,][expression]…
Writes values to file n (which must be open for OUTPUT or APPEND, or be a device opened without FOR) exactly as PRINT would display them. As in Microsoft BASIC, the space before the # is optional (eg, PRINT#1,X), here and in the other file statements.
PRINTF #n,USING format;[value][, ;][value]…
Writes values to file n (which must be open for OUTPUT or APPEND) exactly as PRINTF would display them.
PUT [#]n[,record]
Writes each FIELD variable to its part of the specified record of random access file n (or the record after the last one used, if record is omitted), padded with spaces. PUT (x,y),array is the graphics PUT.
An incomplete write raises “Disk full” (61); a DOS seek or write failure raises “Device I/O error” (57). A failed PUT does not advance the last completed record number returned by LOC.
OPEN "PHONES.DAT" AS #1 LEN=30
FIELD #1, 20 AS N$, 10 AS P$
LSET N$ = "Alice" : LSET P$ = "555-1234"
PUT #1, 1
GET #1, 1
PRINT N$; P$
CLOSE
RANDOMIZE [seed]
Reseeds the random number generator (see RND), so that the same seed always produces the same sequence of numbers. Without a seed, the BIOS tick count is used (Microsoft BASIC would prompt for one instead).
READ variable[,variable]…
Assigns the next DATA item to each variable (or array element). A numeric variable gets the item’s numeric value (like VAL), rounded if the variable is an integer. Reading past the last item causes an “Out of DATA” error (error 4).
REM remark
‘ remark
Used for program remarks. The rest of the line is not executed. An apostrophe outside of quotes is the same as REM, and can follow other statements on the same line (eg, POKE 106,0 'CLEAR KEYBOARD BUFFER).
RESTORE [line]
Makes the first DATA item the next item that READ assigns, or with a line number, the first DATA item at or after that line (which must exist, or an “Undefined line number” error occurs). Every program starts with RESTORE in effect.
RESUME label
Ends the handling of a runtime error (see ON ERROR) and continues at the specified label. The handler can use ERR and ERL to find out which error occurred, and where. RESUME when no error is being handled is a “RESUME without error” error (20).
Unlike GOTO, RESUME ends the handling of the error, so that the handler can catch the next one. After a GOTO out of the handler, the program is still handling the error, so another error ends the program.
Microsoft BASIC’s RESUME without a label (or with 0) and RESUME NEXT, which continue at the start of the statement with the error or at the statement after it, aren’t supported. BASIC-DOS compiles programs (see BASIC Compilation), so when an error occurs, all it knows is where in a statement’s compiled code the error occurred, not where that statement (or the next one) begins, and recording that for every statement would make every such program larger. RESUME without a label is a syntax error. Instead, give the line to continue at a label, and RESUME to it; a handler for errors in more than one place can use ERL to choose the label (eg, IF ERL = 20 THEN RESUME 30).
ON ERROR GOTO 100
OPEN "DATA.TXT" FOR INPUT AS #1
10 IF E THEN PRINT "No DATA.TXT" : END
...
100 E = ERR : RESUME 10
RETURN [expression]
Returns from a GOSUB subroutine, or ends a function block and returns the specified expression. See RETURN.
SWAP variable1,variable2
Exchanges the values of two variables (or array elements) of the same type.
WHILE expression
statement(s)
WEND
Executes the statements up to the matching WEND repeatedly, as long as the expression is TRUE (non-zero).
LET I = 1
WHILE I < 100:PRINT I;:LET I = I * 2:WEND
1 2 4 8 16 32 64
WRITE [#n,][expression[,expression]…]
Prints the values (or with #n, writes them to file n), separated by commas, with strings in quotes and numbers without leading or trailing spaces, and then ends the line, so that INPUT # can read the values back (eg, WRITE #1, "Smith, Jo", 42 writes "Smith, Jo",42).
Copyright (c) 2020-2026 Jeff Parsons Released under MIT License