Basic Language Documentation
This page presents a summary of the Benton Harbor Basic programming language dialect. This material is believed to be correct and complete, if somewhat terse, but if you have additional material or notice an error in this material, please forward it to the author for inclusion in the next update.
Page Index | Commands | ||
Commands |
BYE BUILD FREE CLEAR SCRATCH LIST |
DELETE RUN CONTINUE STEP LOCK UNLOCK |
|
Source File Access |
OLD SAVE REPLACE |
UNSAVE FREEZE UNFREEZE |
|
Statements | |||
Program Statements |
REM LET IF FOR / NEXT GOTO GOSUB / RETURN ON INPUT LINE INPUT |
DATA READ RESTORE CHAIN END STOP PAUSE DIM DEF FN |
|
Operators |
+ ' * / ^ |
< > = <> |
|
Logical Operators |
AND OR NOT |
||
File Access Statements |
OPEN INPUT LINE INPUT |
CLOSE CIN() |
|
Hardware Access |
PIN() OUT PEEK() POKE |
CNTRL SEG() PAD() |
|
Functions | |||
Math Functions |
ABS() INT() MAX() MIN() RND() SGN() SQR() |
SIN() COS() TAN() ATN() LOG() EXP() |
|
String Functions |
LEFT$() MID$() RIGHT$() |
LEN() MATCH() |
|
Conversion Functions |
ASC() CHR$() VAL() |
STR$() LNO() |
|
Print Functions |
SPC() TAB() POS() |
Commands
The commands in this group are used to control the Basic interpreter itself and are not used as Basic program statements.
Exit the Basic interpreter. You will have to confirm that you want to leave by answering "y" to the prompt.
This is used to auto-number Basic programs when you are first building them. It takes two arguments: the first is the first line number to use, and the second is the line number increment.
Example:
BUILD 20,10You will be prompted for programs starting at line number 20, followed by 30, 40, 50, .etc. Use Ctl-C to return to a command prompt.
Displays various categories of memory usage statistics. The most important of these is the free memory byte count at the bottom of the list.
Throws away all dynamic variables and other work space, freeing memory. All that's left is the program text itself. If the optional variable name is included, only that variable is cleared.
Resets the workspace to its initial state as if you had just started the Basic interpreter. Use this command before starting a new program. You will need to confirm this command by answering "y" to the prompt.
List the program source. If entered without the optional argument, the entire program will be listed. You can enter one line number to list only that line, or two line numbers to list a block of statements.
Delete one program statement, or a block of program statements.
Run the program currently in the workspace. The program will continue to run until:
Stopping via STOP and Ctl-C allow you to continue execution where you left off, using the CONTINUE command.
If the running program stopped due to execution of a STOP statement, or because you pressed Ctl-C, this command will cause the program to continue operation where it left off. A CONTINUE command following a CLEAR command or an END statement is treated the same as a RUN command; the program is started at the first line.
Execute "n" statements of the program and then stop. This is very useful for debugging.
If the program has not been run, step will actually execute "n-1" statements the first time it's used. Each subsequent use will execute "n" statements.
Locks the program so that the text cannot be changed or deleted.
Unlocks the program so that changes can be made.
Source File Access Commands
These commands are used to read Basic programs from disk, save them to disk, and otherwise manage source program files.
In each of these commands, "filename" refers to a file on one of the H-17 disk drives. You may specify the drive ("sy1:myprog") or leave it off to read from sy0: ("myprog"). You may include the .bas file extension, but it is not necessary.
Opens the program file and reads it into memory. If a program was already in memory when this command was entered, the Basic interpreter will clear the workspace before reading the new program. You do not need to enter SCRATCH first.
Creates a new file and saves the Basic program text in it. If "filename" already exists, an error message will be displayed. The file will not be overwritten. See REPLACE and UNSAVE.
Overwrites "filename" with the Basic program currently in memory.
Deletes "filename" from disk. You will not be prompted to confirm the delete, so use care.
This command saves the entire Basic interpreter and its workspace, including variables, arrays, etc., to disk as filename.baf. This file can be unfrozen (see UNFREEZE below) to continue work.
This command allows you to stop the execution of a long-running program and resume execution at another date. It also allows you to stop a long debugging session and resume it at a later date.
Read in a frozen "filename.baf" file, including source code, variables, etc., and prepare to continue running the program.
(Note that the "filename.baf" file is in ABS file format. Instead of running Basic then using the UNFREEZE command, you can simply run "filename.baf" from an HDOS command prompt.)
Program Statements
Basic language statements start with a line number and contain one or more program statements.
You may place more than one statement on a line by separating them with a colon (":"). Example:
00010 PRINT "There is one statement on this line."Be aware that you can only GOTO or GOSUB to the beginning of a numbered line, so if a given statement is to be the target of a GOTO or GOSUB, it must be at the beginning of a line of code.
Variables are dynamically created when a value is first assigned to them. Variable names consist of a single letter or a letter and number. String variables add a "$" to the end of the name. Letter case is ignored.
These are all valid variable names:
a, a1, d7, b$, b9$See the DIM statement below for information on array variables.
This is a source comment. The remark continues to the end of the line. Examples:
00010 REM This is a commentThis optional keyword begins an assignment statement of the form "LET variable = expression". LET is assumed if it is omitted; the following two statements are equivalent:
00010 LET a = b * 10Prints output to the console. (See also File Access Statements below for the form of PRINT to write to files.)
One PRINT statement can print a number of variables, literals, expressions or strings. If the arguments are separated by commas, they will be printed in zones that are 14 print positions wide by default (see CNTRL 3 in Hardware Access Statements). If the arguments are separated by semicolons, they will be printed one after the other. Examples:
00010 PRINT "This is a string"Evaluate the expression and execute the statement if the condition is true. Examples:
00010 a=10If the conditional statement is a GOTO, as in line #40 above, you can omit the GOTO keyword:
00040 IF a = b THEN 100These statements provide a looping mechanism in Basic. The statements between FOR and NEXT are executed repeatedly while varying the value of a variable. Examples:
00010 FOR i=1 TO 10...will print a list of the integers 1 through 10. The variable is incremented by one on each pass through the loop.
If you want to increment by a value other than 1, or use a decrement instead of an increment, then add the STEP keyword:
00010 FOR i=100 TO 0 STEP -10...will print the numbers 100, 90, 80, etc. through 0 on the console.
FOR/NEXT loops can be nested. Make sure that you close the inner loop before closing the outer loop.
00010 FOR i=1 TO 5Use the GOTO statement to branch to a different line in the program. Example:
00010 PRINT "Infinite Loop!"Branch to a different line in the program and run that section of code as a subroutine. When a RETURN statement is executed, execution will continue at the statement following the GOSUB command. Example:
00010 a=1The ON command is a simple "computed GOTO/GOSUB" which will branch to one of a list of program statements depending on the value of a variable. (See also the LNO() function in Data Conversion Functions.) Example program fragment:
00110 GOSUB 1000 : REM print the menu on the consoleIf the user enters 4 at statement 120, the program will execute the subroutine starting at line 350, the fourth line number in the list.
Request input from the console. If the optional prompt is included, it will be printed on the console before waiting for input. If not, a "?" is used as a prompt.
The variable may be a numeric or string variable. If a string is entered into a numeric variable, an error message will be printed and the program will stop.
This statement is equivalent to 'INPUT "prompt";variable$' with one exception: LINE INPUT will accept a null entry and return a zero-length string, while INPUT will not..
This statement defines data to be stored as part of the program text. The data is read using the READ statement (below). This is typically used to initialize arrays.
Read data from the data table. Example:
00010 REM sum a list of numbersDATA can be numbers, strings, or a mix. Your program must be aware of the order of mixed data so that you don't try to read a string into a numeric variable.
If you need to read a list of data more than once, you use the RESTORE statement to reset the DATA pointer to the first DATA item.
Use CHAIN to read a new program off the disk and begin execution of that program. Any open files are still open; all defined variables are still defined. You can use CHAIN as a command; it's the same as using OLD followed by RUN.
Use END to end execution of a program.
Use STOP to stop execution of a program.
The only difference between STOP and END involves the CONTINUE statement. If you enter CONTINUE after a STOP, the program will continue operation with the statement following the STOP statement. If you enter CONTINUE after an END, the program will start at the top as if you had entered a RUN command.
Use PAUSE to pause execution. If you include the optional integer argument, the program will pause for "ticks" clock ticks (or ticks * 2 milliseconds). If this is omitted, the program will pause until the user presses the enter key.
DIM is used to define and dimension an array. Example:
00010 DIM m$(5)The value in parenthesis gives the highest valid index that can be used to access the array. The lowest valid index is zero, as shown in the example.
Arrays can be dimensioned with any reasonable number of indices. These are two and three dimensional tables:
00010 DIM a(5,5)Array b in the example above consists of 1,600 floating point numbers and uses 10,704 bytes of storage. Be careful with multidimensional arrays.
DEF FN is used to create user-defined functions. These functions can accept one or more arguments of either numeric or string type and can return a numeric or string value. The following program uses a function to convert degrees to radians for use with the SIN() function:
00010 DEF FN r(d) = d / 57.29578Here is an example using a mix of strings and numbers. A function is used to convert a number to a string exactly 6 characters long (including the trailing space).
00010 DEF FN s$(n) = right$(" "+str$(n),6)Operators
Add two numbers, or concatenate strings:
Subtract two numbers. 4-2 is 2.
Multiply two numbers. 2*3 is 6.
Divide two numbers 5/3 is 1.66667.
Raise a number to a power. 2^3 is 8. 2^.333333 is 1.25992 (the cube root of 2).
Used in IF statements to compare two values:
00120 IF a<b THEN GOTO 90Used in IF statements to compare two values:
00120 IF a$>b$ THEN GOTO 90Used in IF statements to compare two values:
00120 IF a=b THEN GOTO 90Used in IF statements to compare two values:
00120 IF a<>b THEN GOTO 90Note on operator precedence
The standard rules of algebra apply: multiply and divide operations are done before add and subtract. The expression 1+2*3 will evaluate to 7.
Parenthesis can be used to change the order of evaluation. (1+2)*3 will evaluate to 9. Parenthesis can be nested to any reasonable level. (If you think that 15 levels is "reasonable," the author suggests that you forget about Basic and switch to Lisp!)
go to topLogical Operators
These operators can be used to combine comparison operators in an IF statement, and to perform boolean operations on numeric values.
Perform a binary AND operation on two values, or combine comparison operators in an IF statement.
15 AND 19 evaluates to 3When used with an IF statement, both conditions must be true for the conditional statement to be executed:
00110 IF a<b AND $b="abc" THEN GOSUB 1200Perform a binary OR operation on two values, or combine comparison operators in an IF statement.
15 OR 19 evaluates to 31When used with an IF statement, if either condition is true the conditional statement will be executed:
00110 IF a<b OR $b="abc" THEN GOSUB 1200Perform a binary NOT operation on a single variable; flip the '1' bits to '0' and the '0' bits to '1'.
NOT 2 evaluates to 65533File Access Statements
These statements allow a Basic program to open data files on the H-17 disk system and read and write the files.
Opens a file for read or write access, and assigns a channel number to the file:
00010 OPEN "input.dat" FOR READ AS FILE #1This is the same input statement documented above. The channel number parameter is added to allow the data to be read from an open input file:
00010 OPEN "errormsg.sys" FOR READ AS FILE #1There is no end-of-file indication available; if you read past the end of the file, the next INPUT statement will cause an error and the program will end. You should include an end-of-data marker in the data, or see the CIN() function below for another approach.
This exactly duplicates the INPUT statement and has the same format. But LINE INPUT will accept null input and return a zero-length string, so LINE INPUT may be preferred, depending on what you are reading from the file.
Closes a file and frees the channel number. Output files must be closed for the output to be saved.
01230 CLOSE #1This function reads a single character from a file open for read access, and returns the ordinal value of the ASCII character. CIN returns the value -1 at end of file. This example reads and prints "errormsg.sys" one character at a time... slowly:
00010 OPEN "errormsg.sys" FOR READ AS FILE #1CIN can be used to solve the INPUT statement end-of-file problem discussed with the INPUT statement. Let's rewrite that program to eliminate the read error.
00010 OPEN "errormsg.sys" FOR READ AS FILE #1Hardware Access Statements
These statements and functions allow direct access to H8 hardware: I/O ports, memory, and the front panel.
Read a byte from the specified port. Example:
PRINT PIN(237)This reads the console UART's Line Status Register. The response should be 96 decimal (140 octal), which indicates that the transmitter holding register and the transmitter shift register are empty.
Write a byte to the named port. Example:
OUT 232,7This will write an ASCII BEL character to the console port (232 decimal = 350 octal), sounding the bell.
Read a byte from a memory address, expressed in decimal. See the RND() function below for an example.
Write a byte to memory address, both expressed in decimal. See the SEG() function below for an example.
This command has five options that allow you to access certain hardware functions and change certain options in the Basic interpreter itself.
All of these can be used as commands. All but CNTRL 4 can be used as program statements.
CNTRL 0,line
This specifies a line to go to when the user presses Ctl-B. Example:
00010 CNTRL 0,40While you can use it as in the preceding example, the function actually executes a GOSUB to the target line. Compare the program above with this one:
00010 CNTRL 0,40You might use this function to, say, report progress on demand in a long-running program.... "We are on loop 345 of 10,000. Be patient!" You can see an example of this in the RND() function example in Mathmatical Functions.
CNTRL 1,value
This sets the number of digits (1 to 6) to print to the left of the E in scientific format. If a number is too big to print in this many digits, it will be changed to scientific format. Example:
*PRINT 12345CNTRL 2,value
This controls the front panel LED display. A value of zero turns the display off (default condition after loading the Basic interpeter; the LEDs are normally off becaise updating the display takes up to 15% of the processor and you need all you can get to run Basic at a 2 mhz clock rate.)
A value of one turns the display on, but with update disabled. This allows you to write to the display yourself. See examples with the SEG() function below.
A value of two turns the display on with updates enabled, as it normally is when HDOS is running.
CNTRL 3,value
This command sets the width of the print zones. By default, the print zones are 14 columns wide, but they can be made larger or smaller with this command. Example:
*PRINT 1,2,3CNTRL 4,value
This command is used to load and unload the main HDOS overlay, HDOSOVL0. This is a command only; this cannot be used as a program statement. It should be used before a program is loaded into memory.
Normally, Basic allocates the maximum amount of available memory for your program, leaving the overlay on disk. This slows the execution of statements like OPEN and CLOSE, and slows the delivery of error messages, which are read from errormsg.sys. Loading the overlay into memory will reduce available memory by about 2.9 K/bytes, but will greatly speed the execution of your programs.
*CNTRL 4,1 - load the overlayThis command has no effect if you are running HDOS in stand-alone mode.
This function will take a decimal value from zero through nine and convert it to the binary pattern needed to display that value in the front-panel LEDs. The following example will put the digits 9 through 1 into the front panel LEDs:
00010 CNTRL 2,1 : REM turn on LEDs without updateRead a value from the H8 front panel keypad. Example:
00010 a=PAD(0)Click the keys to see what decimal value is assigned to each key. Click the "." key to quit. ("." gives the value 15 decimal.) Here's another example:
00005 PRINT "Click on the keypad; click '.' key to quit"Mathmatical Functions
Returns the absolute value (e.g., positive value) of the argument.
Returns the integer portion of the argument. INT(123.456) will return 123.
Returns the largest of a list of values or numeric variables.
Returns the smallest of a list of values or numeric variables.
This is the pseudo-random number function. "arg" has three possible value ranges:
If you start with the same seed value, you will get the same sequence of random numbers out of the generator. This can be good for testing but terrible for any real use, so the seed should be different from run to run. PAM/8's 16-bit .TICCNT is a reasonable source for a different number every time, as shown in this sample, which shows the average value of 10,000 random numbers. (The closer to .5, the better.)
00010 REM Randomize using .ticcntThis program will run quite a long time, so we included a line-of-dots progress indicator (one dot per 1000 generated numbers) and an on-demand progress report accessed by typing Ctl-B. (Refer to CNTRL 0 in Hardware Access Statements.)
Get the sign of the value. Returns 1 if the value is positive, and -1 if the value is negative.
Returns the square root of the value.
Returns the sine of the angle, which must be expressed in radians (degrees divided by 57.29578).
Returns the cosine of the angle, which must be expressed in radians.
Returns the tangent of the angle, which must be expressed in radians.
Returns the arctangent of the angle, which must be expressed in radians.
Returns the natural logarithm of the value.
Returns e raised to value power. EXP(LOG(10)) = 10.
String Functions
Returns the left-most 'len' characters of the passed string.
LEFT$("Hello there, Bob!",5) returns "Hello"
Returns a substring from the center of a string, starting at 'start' offset from the left and running for 'len' characters.
MID$("Hello there, Bob!",7,5) returns "there"
Returns the right-most 'len' characters of the passed string.
RIGHT$("Hello there, Bob!",4) returns "Bob!"
Returns the length of the string.
LEN("Hello there, Bob!") returns 17
This function searches 'stringa' for an occurrence of 'stringb', starting at 'start' offset into 'stringa'.
The following example looks for every occurrence of a given substring in a string, and prints the location where it is found, as well as the breakdown of the string to the left and right of the substring. This is a comprehensive example showing the use of MATCH, GOSUB, LEFT$(), MID$(), RIGHT$() and LEN().
*listData Conversion Functions
These functions all convert data from one form to another in interesting ways.
The ASCII function returns the ordinal value of the first character in the passed string. ASC("ABC") will return 65; upper-case 'A' is the 65th ASCII character.
This function returns the character that corresponds to the ordinal 'value' in the ASCII character set. CHR$(65) will return "A".
CHR$(ASC("A")) will return "A".
The value function will return the numeric value of the first numeric substring in the passed string. Evaluation starts with the first non-blank character in the string and ends with the first non-numeric character.
VAL("123.45") - returns the number 123.45This function returns a string containing the value of the passed expression, padded with spaces. STR$(123.45) returns " 123.45 " (note the leading and trailing spaces).
This is a different kind of conversion altogether: LNO() converts the passed expression into a Basic line number.
It's illegal to use a numeric variable as a GOTO or GOSUB target:
00010 REM This is not legalBut this can be made legal by using the LNO() function:
00010 REM LNO() function to the rescueLNO() gives us a very powerful computed-GOTO/GOSUB capability. To rewrite the ON ... GOSUB example from above:
00110 GOSUB 1000 : REM print the menu on the consolePrinting Functions
The first two functions in this group are only valid in a PRINT statement. The last one, POS(0), is related to print output.
Print 'count' spaces on the console. Rather than trying to count the blanks you are typing between quotes, you can use this function to output a precise number of spaces.
PRINT "Ten";SPC(10);"spaces"TAB moves the print cursor ahead to 'column'. Note the difference between TAB() and SPC(): the following example prints two identical lines of output.
00010 PRINT TAB(10);"a";TAB(20);"b";TAB(30);"c"POS(0) returns the postion of the cursor on the console, based on the number of characters printed with PRINT statements. If you move the cursor to the right by hand using the cursor keys or the space bar, POS() will not register the move. Example:
00010 INPUT "enter a number from 1 to 50: ";nOnly pass the value zero to the function, as shown. Other positive values will return a nonsense result.