This manual is for bas55 (ECMA-55 Minimal BASIC System) version 1.16 (updated 22 February 2018).
bas55
is an implementation of the Minimal BASIC programming
language as defined by the ECMA-55
standard.
bas55
provides an interpreter and an editor with line renumbering capabilities.
bas55
is free software.
The latest version of the program, source code and documentation can be found at http://jorgicor.sdfeu.org/bas55.
In these first sections we are going to see how to use bas55
and how to program in Minimal BASIC.
First, start bas55
by executing it at the command line.
You will see the program name and license, and then ‘Ready.’.
You have just started bas55
in editor mode.
Now, you can enter your program.
Start by typing these two lines:
10 print "Hello, world" 20 end
This is your first program.
A BASIC program is made by numbered lines, each line containing an statement.
The first line contains the ‘print’ statement followed by a string of characters between quotes.
With this line, we want to print on the screen the sentence ‘Hello, world’.
The second line (line number 20
) has an ‘end’ statement.
Every BASIC program must have one and only one line with an ‘end’ statement, and this line must be the last one.
Now that we have the program, let’s run it. Type ‘run’. The system will compile and run our program. We will see this result:
HELLO, WORLD Ready.
It is ok, but the first thing you notice is that the letters are all upper case.
This happens because every line you enter in bas55
are translated to upper case when you are in editor mode.
bas55
allows you to enter lines in lower case letters but only as a convenience.
A correct BASIC program must be always in upper case.
You can see your program source by typing ‘LIST’. You will see on the screen:
10 PRINT "HELLO, WORLD" 20 END
As you see, your program is all in upper case.
If you want to change a line, you type the line again starting with the same line number. For example, we want to print ‘GOODBYE, CRUEL WORLD’ instead of ‘HELLO, WORLD’. Just type the line:
10 PRINT "GOODBYE, CRUEL WORLD" LIST 10 PRINT "GOODBYE, CRUEL WORLD" 20 END
Now we want to print another line after the first.
We can add a new line to the program between the lines 10
and 20
.
For that, we can use any line number from 11
to 19
.
We choose 15
.
15 PRINT "GOODBYE" LIST 10 PRINT "GOODBYE, CRUEL WORLD" 15 PRINT "GOODBYE" 20 END
As you see, when using LIST
the lines appear ordered by line number.
Normally, the lines of a BASIC program are numbered 10, 20, 30, etc. so we can have space to insert a line between other two lines.
But this is up to you.
bas55
gives you the RENUM
command that you can use to renumber the lines of a program.
Let’s type it:
RENUM LIST 10 PRINT "GOODBYE, CRUEL WORLD" 20 PRINT "GOODBYE" 30 END
The lines have been renumbered.
To remove a line, simply type its number and press the ENTER key.
10 LIST 20 PRINT "GOODBYE" 30 END
And renumber if you like:
RENUM LIST 10 PRINT "GOODBYE" 20 END
You can list only one line:
LIST 10 10 PRINT "GOODBYE"
And you can list a range of lines:
5 PRINT "HELLO, WORLD" RENUM LIST 10 PRINT "HELLO, WORLD" 20 PRINT "GOODBYE" 30 END LIST 20-30 20 PRINT "GOODBYE" 30 END
Or the lines from one you specify to the last:
LIST 20- 20 PRINT "GOODBYE" 30 END
Or the lines from the first to one you specify:
LIST -20 10 PRINT "HELLO, WORLD" 20 PRINT "BYE"
To save our program on a file, use the SAVE
command and the name of the file between quotes.
SAVE "HELLO.BAS"
And your program will be saved as HELLO.BAS.
To start a new program and remove the one in memory, simply use NEW
.
NEW LIST
Now, if we want to load our previous saved program, we use the LOAD
command.
LOAD "HELLO.BAS" LIST 10 PRINT "HELLO, WORLD" 20 PRINT "GOODBYE" 30 END
You can use your favorite text editor to write a BASIC program and the load it into bas55
.
Only keep in mind that bas55
allows to enter a program using lower case letters in editor mode, but when you are loading a program using LOAD
the program bust be a valid BASIC program, that is, it must be all in upper case.
You can use the REM
statement to put comments in your program.
A line starting with a REM
statement is not executed, and you can put your comment after the REM
.
For example:
10 REM THIS PROGRAM IS A TEST 20 REM AND DOES NOTHING 30 END
You can ask the user of your program to enter numbers or text. For that, you have to store the user’s input into variables. A variable is a name we give to some data. This is an example:
10 PRINT "ENTER A NUMBER:" 20 INPUT A 30 PRINT "YOUR NUMBER IS:" 40 PRINT A 50 END
If you run this program, you will see:
ENTER A NUMBER: ?
The editing cursor will be after the question mark. This means that the system is waiting for you to enter some data. We can enter a number, for example ‘3.5’:
ENTER A NUMBER: ? 3.5 YOUR NUMBER IS: 3.5
When the user enters the number, ‘A’ will be equal to that number, so we can use it in another parts of the program.
In this case, we use it in a PRINT
statement to write back that number.
‘A’ is a numeric variable.
BASIC distinguish between variables whose value is a number (numeric variables) and variables whose value is text (string variables). For numeric variables you use the letters ‘A’ to ‘Z’, and also these letters followed by a number from 0 to 9. ‘A’, ‘B0’, ‘Z6’ are examples of numeric variables.
String variables consist of one letter from ‘A’ to ‘Z’ followed by the dollar sign ‘$’. ‘A$’, ‘B$’, ‘Z$’ are examples of string variables.
We can use INPUT
and PRINT
with these two types of variables.
10 PRINT "ENTER YOUR NAME:" 20 INPUT A$ 30 PRINT "WELCOME" 40 PRINT A$ 50 END
We can run this program and enter our name:
ENTER YOUR NAME: ? JAMES WELCOME JAMES
INPUT
can be used to ask the user to enter a list of numbers or character strings, separated by commas.
For example:
10 PRINT "ENTER YOUR NAME AND YOUR AGE, SEPARATED BY A COMMA:" 20 INPUT A$, A 30 PRINT "YOUR NAME IS" 40 PRINT A$ 50 PRINT "YOUR AGE IS" 60 PRINT A 70 END
Here you will have to enter your name first, a comma, and your age.
ENTER YOUR NAME AND YOUR AGE, SEPARATED BY A COMMA: ? JAMES, 33 YOUR NAME IS JAMES YOUR AGE IS 33
One way to make a variable equal to a value is by using INPUT
and let the user enter the value.
Another way is using LET
.
10 LET A$="PI" 20 LET A=3.1416 30 PRINT A$ 40 PRINT A 50 END
With this program, ‘A’ will be equal to ‘3.1416’, and ‘A$’ will be equal to the string ‘PI’.
You can change the value of a variable, simply by using LET
with another value.
Running this program:
10 LET A=3.1416 20 PRINT A 30 LET A=123456 40 PRINT A 50 END
You will get:
3.1416 123456
A variable can be made equal to the value of other variable.
10 LET A=1 20 LET B=A 30 PRINT B 40 END
This will print
1
The same can be done for string variables.
We can use mathematical expressions in a LET
or PRINT
statement:
10 PRINT "WRITE A NUMBER:" 20 INPUT N 30 LET N=N*N 40 PRINT N+1 50 END
If we run this program and input the number ‘2’, the response will be ‘5’:
WRITE A NUMBER: ? 2 5
In a numeric expression, we can use the operators ‘*’, ‘/’, ‘+’, ‘-’ and ‘^’ to multiply, divide, add, subtract or power. The power operator has the highest priority. Then multiplication and division. Then addition and subtraction. You can use parenthesis to change these priorities. Operations with the same priority are evaluated from left to right.
10 PRINT 5+3*2 20 PRINT (5+3)*2 30 END
This will print:
11 16
At line 10
, as multiplication has higher priority, ‘3*2’ is calculated first, and the addition of ‘5’.
At line 20
, we are using parenthesis to select which operation is calculated first.
If a numeric variable is used before any value has been assigned to it in the program, the value of the variable defaults to ‘0’. For a string variable, it defaults to the empty string. You can enable the debug mode if you want the interpreter to warn you about any variable that is used before any value has been assigned to it.
Numbers are written in your program following scientific notation. The general syntax is:
sd..drd..dEsd..d
Here, ‘s’ is an optional sign symbol (‘+’ or ‘-’), ‘d’ is a number digit and ‘r’ is a full-stop. Some parts of this general syntax are optional. These are the possibilities, which can precede an optional ‘Esd..d’ part.
sd..d sd..dr sd..drd..d srd..d
Example of numeric constants are:
1 500 -21. .255 1E10 5E-1 4.E+1
bas55
only uses the six first significant digits of a numeric constant.
A constant is rounded if it is written with more than six significant digits.
bas55
works internally IEEE double-precision floating-point numbers.
Numbers printed with the PRINT
statement use six significant digits.
You can use tables of one dimension or two dimensions. We call them arrays. To store a value in an array slot we use the name of the array (which must be one letter) and using parenthesis to specify the required slot index.
With this program we store ‘1’ and ‘2’ in the slots 0 and 1 of the one dimensional array ‘A’.
10 LET A(0)=1 20 LET A(1)=2 30 PRINT A(0) 40 PRINT A(1) 50 END
This will print ‘1’ and ‘2’. Once you use a variable name as an array, it cannot be used as a simple numeric variable. And once a variable has been used as a numeric variable, it cannot be used as an array. This program commits both mistakes and will not run.
10 LET A=1 20 LET A(0)=1 30 LET B(0)=1 40 LET B=1 50 END
The value of each array slot is ‘0’ if no other value has been assigned to it before.
10 PRINT A(0) 20 END
will print:
0
Note that this behavior ir not required by the standard, and other implementations may not initialize all variables to zero. You can enable the debug mode if you want the interpreter to warn you about variables that are used before any value has been assigned to them.
Arrays always have a size of 11 elements by default, from 0 to 10.
If you want to change this, you can use DIM
to define the highest index the array can accept.
This has to be done before any access to the array in your program.
This program
10 DIM A(100) 20 LET A(100)=5 30 PRINT A(100) 40 END
will define the array ‘A’ to have 101 elements, from 0 to 100, and will print the number ‘5’.
When you write an array index, any numeric expression whose value is within the range of the array indexes is allowed. For example:
10 LET A=5 20 LET B(A+A)=33 20 PRINT B(A+A) 30 END
This will print ‘33’, which is stored at index 10 in ‘B’.
You can use arrays of two dimensions as well:
10 DIM B(15,15) 20 LET B(15,15)=5 30 PRINT B(15,15) 40 END
Once an array has been used with one dimension, it cannot be used with two dimensions. And an array used with two dimensions, cannot be used with one.
The index of the first element of an array is always zero.
BASIC allows to change this and use arrays where the index of the first element starts at 1.
To allow this, we have to use the OPTION BASE 1
statement in our program, before using any array or any DIM
statement.
In that case, by default, the arrays will have 10 elements, indexed from 1 to 10.
10 OPTION BASE 1 20 REM USING LET A(0)=3 NOW IS AN ERROR, THE FIRST ELEMENT IS AT INDEX 1 30 LET A(1)=3 40 END
You can print more than one item using the PRINT
statement by separating the items by commas or semicolons.
Using commas will move the cursor to the next printing column.
Each line has a printing column every 15 characters.
10 PRINT "COLUMN 1", "COLUMN 2" 20 PRINT 5, 6 30 END
will print:
COLUMN 1 COLUMN 2 5 6
A semicolon will leave the cursor at the same position it is, that is, it is only used to separate items in a PRINT
statement.
10 PRINT "PI=";3.1416 20 END
will print:
PI= 3.1416
You can use TAB
to move the cursor to a specific character column in the line.
TAB
needs a numeric expression between parenthesis.
10 PRINT ,"A" 10 PRINT TAB(15);"A" 20 END
will print at character column 15:
A A
Note that expressions or TAB
specifiers must be separated by commas or semicolons, but commas or semicolons can appear one after the other several times.
Also, the PRINT
statement alone is correct and will pass to the next line.
10 PRINT "LINE 1" 20 PRINT 30 PRINT "LINE 3" 40 PRINT ,,"COLUMN 30" 60 END
This program prints:
LINE 1 LINE 3 COLUMN 30
BASIC allows some mathematical functions to be used in numeric expressions. For example, to calculate the square root of 4:
10 PRINT SQR(4) 20 END
Functions need an argument between parenthesis, which must be a numeric expression. The provided functions are:
ABS(X)
Absolute value of X.
ATN(X)
Arctangent of X in radians.
COS(X)
Cosine of X, where X is in radians.
EXP(X)
Exponential of X.
INT(X)
The largest integer not greater than X.
LOG(X)
The natural logarithm of X.
SGN(X)
1 if X is positive, -1 if it is negative, 0 if it is 0.
SIN(X)
Sine of X, X in radians.
SQR(X)
Square root of X.
TAN(X)
Tangent of X, X in radians.
You can use the function RND
without any argument, to get a random number in the range [0, 1[
.
RND
can be used in any numeric expression.
The sequence of numbers you will get by calling RND
will be always the same (given the same computer and operating system).
If you want the sequence to start randomly, you can use the statement RANDOMIZE
.
10 PRINT RND, RND 20 RANDOMIZE 30 PRINT RND, RND 40 END
When we run this program, we will get 4 numbers. If we run the program again, the we will see that the first two numbers are the same as in the previous execution, but not the last two.
Imagine we want to present a menu to the user, wait for input, and execute a different code depending on his response.
We can use the IF
statement to check for conditions and jump to a line of our program if the condition is true.
10 PRINT "1 - SAY HELLO" 20 PRINT "2 - SAY GOODBYE" 40 PRINT "3 - END" 50 PRINT "SELECT AND OPTION (1,2,3):" 60 INPUT N 70 IF N=1 THEN 130 80 IF N=2 THEN 150 90 IF N<>3 THEN 100 100 STOP 110 PRINT "ERROR" 120 GOTO 10 130 PRINT "HELLO" 140 GOTO 10 150 PRINT "GOODBYE" 160 GO TO 10 170 END
You can see the IF
statement at lines 70
, 80
and 90
.
Its basic form is IF condition THEN line
.
It tests the condition, and if it is true, then the program continues its execution at the line after the THEN
word.
If the condition is false, execution continues at the next line as usual.
In this program, if the user enters a ‘1’, line 70
will jump to the line 130
and ‘HELLO’ will be printed.
If the user enters ‘2’, the condition at line 70
will be false, so we will continue at line 80
.
Here, the condition will be true, so we will jump to the line 150
and ‘GOODBYE’ will be printed.
If the user enters a number different than 1, 2 or 3, we will jump to line 110
and print ‘ERROR’.
Otherwise the execution continues at line 100
.
The STOP
statement is used to stop a program before we reach the END
statement.
A program can only have one END
statement and must be at the last line, but can contain any number of STOP
statements.
The GOTO
statement followed by a line number, can be used to jump to a line without checking for any condition.
Note that GOTO
can be written using two words as well: GO TO
.
The conditions that we can test in an IF
statement are:
A=B
True if the numeric expression A is equal to the numeric expression B. True if the string constant or string variable A is equal to the string constant or string variable B.
A<>B
True if the numeric expression A is not equal to the numeric expression B. True if the string constant or string variable A is not equal to the string constant or string variable B.
A>B
True if the numeric expression A is greater than the numeric expression B.
A>=B
True if the numeric expression A is greater or equal than the numeric expression B.
A<B
True if the numeric expression A is less than the numeric expression B.
A<=B
True if the numeric expression A is less or equal than the numeric expression B.
With the ON
statement we can jump to a line in a line list depending on the value of a numeric expression.
The above program can be written this way:
10 PRINT "1 - SAY HELLO" 20 PRINT "2 - SAY GOODBYE" 40 PRINT "3 - END" 50 PRINT "SELECT AND OPTION (1,2,3):" 60 INPUT N 70 IF N<1 THEN 100 80 IF N>3 THEN 100 90 ON N GOTO 120, 140, 170 100 PRINT "ERROR" 110 GOTO 10 120 PRINT "HELLO" 130 GOTO 10 140 PRINT "GOODBYE" 150 GO TO 10 160 END
A numeric expression must follow the ON
word.
The expression is rounded to an integer and this number is used to select one of the lines in the line list after the GOTO
.
The number ‘1’ will select the first line in the list, ‘2’ the second, etc.
The program will stop with an error if the rounded integer is less than 1 or greater than the number of lines in the line list.
We check that at lines 70
and 80
.
Imagine that we want to calculate the roots of a second degree equation. We know the formula, for ‘ax^2 + bx + c’, the roots are given by the equations ‘(-b + SQR(b^2 - 4ac)) / 2a’ and ‘(-b - SQR(b^2 - 4ac)) / 2a’.
We can write this program if we want to calculate it for two different equations:
10 LET A=4 20 LET B=7 30 LET C=1 40 LET R0=(-B + SQR(B^2 - 4*A*C))/2*A 50 LET R1=(-B - SQR(B^2 - 4*A*C))/2*A 60 PRINT R0, R1 70 LET A=16 80 LET B=25 90 LET C=2 100 LET R0=(-B + SQR(B^2 - 4*A*C))/2*A 110 LET R1=(-B - SQR(B^2 - 4*A*C))/2*A 120 PRINT R0, R1 130 END
But in this example we are duplicating code.
What we want is to have the code to calculate the roots only once.
To achieve that, we can use a subroutine.
GOSUB
stands for ‘go to subroutine’.
We use it with a line number and the program will go to that line number and will continue the execution at that line.
We can then use the statement RETURN
to return to the line after the line with the GOSUB
.
For example, applied to the above program:
10 LET A=4 20 LET B=7 30 LET C=1 40 GOSUB 120 50 PRINT R0, R1 60 LET A=16 70 LET B=25 80 LET C=2 90 GO SUB 120 100 PRINT R0, R1 110 STOP 120 REM CALC ROOTS OF SECOND DEGREE EQUATION AX^2 + BX + C 130 ON ENTRY: A, B, C ARE THE COEFICIENTS 140 ON EXIT: R0, R1 ARE THE ROOTS 150 LET R0=(-B + SQR(B^2 - 4*A*C))/2*A 160 LET R1=(-B - SQR(B^2 - 4*A*C))/2*A 170 RETURN 180 END
Our subroutine starts at line 120
.
It needs the variables ‘A’, ‘B’ and ‘C’ to be defined, and will calculate the roots in ‘R0’ and ‘R1’.
You can call this subroutine by using GOSUB 120
.
The program will jump to that line and execute the next lines until a RETURN
is found.
When we reach the RETURN
we will return to the point of the call.
In this program, when we call the subroutine at line 40
and the subroutine ends with a RETURN
, the execution will continue at line 50
.
Note that we need a STOP
statement at line 110
to stop our program.
If not it will continue at line 120
, thus entering the subroutine and reaching the RETURN
statement.
This will be an error as we reach a RETURN
without having issued any GOSUB
.
Note that GOSUB
can be written with two words as well: GO SUB
.
BASIC allows to define your own functions by using ‘DEF FNX’, where ‘X’ is a letter. You can define functions with zero or one argument.
10 DEF FNA=2*X 20 LET X=3 30 PRINT FNA 40 END
This program will print ‘6’.
Every function have to be declared before being used. And a function declared with an argument cannot be redeclared without arguments, or vice versa.
If we define a function with an argument, the argument must be a letter. Once inside the function, when this argument is used, it takes the value we passed to the function, not the value of the variable of the same name in the program. For example:
10 DEF FNA(X)=X+Y 20 LET X=3 30 LET Y=4 30 PRINT FNA(5) 40 END
This program will print ‘9’. When the function ‘FNA’ is called, ‘X’ inside the function expression will take the value we have passed (‘5’ in this case and not the value ‘3’ of the variable in the program) and will take the value of ‘Y’ in the program (‘4’). That is, ‘FNA(5)=5+4=9’. The value of ‘X’ in the program will not change, it will be ‘3’.
Imagine that you want to print the values from 1 to 10. You can write something like this:
10 LET I=1 20 PRINT I 30 LET I=I+1 40 IF I<11 THEN 20 50 END
You can achieve a similar effect using the FOR
loop.
With the FOR
loop, you can forget about changing the value of the loop control variable (the variable ‘I’ in this case) and jumping back to the correct line (as we do at line 40
).
10 FOR I=1 TO 10 20 PRINT I 30 NEXT I 40 END
You can see here the general syntax.
The variable ‘I’ will have the value of ‘1’ at the beginning.
Then the next lines are executed until we reach a NEXT
statement followed by the variable we use in the FOR
.
When we reach the NEXT
we increment the loop variable ‘I’ by one.
Then we check if ‘I’ is greater equal to the limit specified in the FOR
statement after the word TO
.
If it is greater, the loop ends and the execution continues at the next line (at line 40
in this case).
If not, we jump back to the line after the FOR
.
This means that after exiting the loop, the variable has the next value not used, in this case, ‘11’.
It is possible to specify an increment value different than 1. This program prints 2, 4, 6, 8 and 10.
10 FOR I=2 TO 10 STEP 2 20 PRINT I 30 NEXT I 40 END
The step value can be negative and the start value greater than the limit. This program prints 10, 8, 6, 4, 2.
10 FOR I=10 TO 2 STEP -2 20 PRINT I 30 NEXT I 40 END
We can have a FOR
loop inside another FOR
loop:
10 FOR I=1 TO 5 20 FOR J=1 TO 5 30 PRINT I, J 40 NEXT J 50 NEXT I 60 END
We cannot have a nested FOR
loop inside another with the same control variable.
This program is incorrect:
10 FOR I=1 TO 5 20 FOR I=2 TO 3 30 PRINT I 40 NEXT I 50 NEXT I 60 END
Also, you cannot jump into a line inside a FOR
block from outside that block.
This program is incorrect:
10 FOR I=1 TO 5 20 PRINT I 30 NEXT I 40 GOTO 20 50 END
Line 40
is jumping inside the FOR
block and this is not allowed.
The same happens if we use a GOSUB
or an IF
statement jumping inside that block.
Note that if inside a FOR
block there is no other FOR
block, the control variable of that FOR
block must match the NEXT
control variable ending that block.
For example, this program is incorrect:
10 FOR I=1 TO 10 20 FOR J=1 TO 10 30 PRINT I 40 NEXT I 50 NEXT J 60 END
You can declare constants in your program by using the DATA
statement followed by a list of numbers, quoted strings or unquoted strings separated by commas.
You can then store this data in variables with the READ
statement, which has the same syntax as the INPUT
statement.
10 DATA 1, "HELLO" 20 FOR I=1 TO 4 30 READ A, B$ 40 PRINT A, B$ 50 NEXT I 60 DATA 2, BYE 70 END
This program prints:
1 HELLO 2 BYE
Note that in a DATA
statement, you can use character strings without starting and ending them with quotes, but in that case, you can only use letters, numbers, spaces, the plus and minus signs (‘+’, ‘-’) or a full stop (‘.’).
The READ
statement reads elements starting from the first DATA
statement in your program.
If you want to read again from the first element, you must use the RESTORE
statement.
This program prints ‘1’ and ‘2’, and then ‘1’ and ‘2’ again.
10 DATA 1, 2, 3, 4 20 READ A, B 30 PRINT A, B 40 RESTORE 50 READ A, B 60 PRINT A, B 70 END
A gift from Eratosthenes of Cyrene, 276 BC - 194 BC...
10 PRINT "FIND PRIMES FROM 2 TO N (N <= 1000). ENTER N: " 20 INPUT N 30 IF N<2 THEN 10 40 IF N>1000 THEN 10 50 DIM A(1000) 60 LET S=SQR(N) 70 FOR I=2 TO S 80 IF A(I)=1 THEN 130 90 LET D=N/I 100 FOR J=I TO D 110 LET A(I*J)=1 120 NEXT J 130 NEXT I 140 FOR I=2 TO N 150 IF A(I)=1 THEN 170 160 PRINT I 170 NEXT I 180 END
When bas55
is invoked without arguments, it starts in editor mode.
You can then write a BASIC program by entering lines beginning with a number.
The number will be used to order the lines in the program.
To delete a line, simply write the line number you want to delete and press the ENTER key.
To replace a line, rewrite the line with using the same line number as the line you want to substitute.
If you write a line that does not begin with a line number, it will be taken as an editor command. Available commands are:
HELP
Display the list of commands available.
COMPILE or C
Compile the current program to bytecode (in memory).
RUN
Compile (if needed) and run the current program.
LIST
List the current program lines. You can optionally pass a range of lines. ‘LIST n’ will only print line number ‘n’. ‘LIST a-n’ will print lines from line number ‘a’ to ‘b’. ‘LIST a-’ will print lines from line number ‘a’ to the last. ‘LIST -b’ will print lines from the first to the line number ‘b’.
NEW
Start editing a new program.
LOAD "program.bas"
Load the BASIC program in the file program.bas.
SAVE "program.bas"
Save the current program lines to the file program.bas.
RENUM
Renumber the lines of the current program.
SETGOSUB n
Allocate enough space so that, at maximum, ‘n’ GOSUB
statements can be executed without any RETURN
statement.
DEBUG ON/OFF
DEBUG ON
will enable the debug mode; DEBUG OFF
will disable it.
It is enabled by default in edit mode, and disabled in batch mode.
It will warn if a variable is used before a value is assigned to it.
LICENSE
Display the license text.
QUIT
Quit to the OS.
When running bas55
on Microsoft Windows in editor mode, you can use the up and down arrows on your keyboard to show the lines that you typed before.
For example, if you type:
10 PRINT "HELLO" 20 END
And the you press the up arrow, you will get:
20 END
If you press it again, you will get:
10 PRINT "HELLO"
If you press now the down arrow key you will get again:
20 END
When you get one of these lines that you typed previously, you can use the left and right arrows to move through the line and make any modifications that you wish. If you then press the ENTER key, the line will be saved with the modifications.
On GNU/Linux, BSD systems, etc, if bas55
has been compiled with ‘libedit’ support, when executing the program in editor mode you will something like:
bas55 1.13 (with libedit support)
In this case, you have the same editing enhancements as on Microsoft Windows, and some more.
For example, you can access any line of your BASIC program by writting its number and then pressing the TAB key. Then you will get the line and you will be able to edit it.
For example, if your program was:
10 PRINT "HELLO" 20 END
You can type 10
and then press the TAB key, and you will get
10 PRINT "HELLO"
and you can move through this line and edit it.
Another enhancement is that some commands can be autocompleted by pressing the TAB key. For example, if you type ‘10 PR’ and then you press TAB, ‘PR’ will be expanded to ‘PRINT’.
Finally, the names of the files provided to the LOAD
and SAVE
commands, will be autocompleted by using the TAB key with the files on your actual filesystem.
For example, if in your current directory there is a file called program.bas and you type ‘LOAD "pro’ and then you press TAB, you will get ‘LOAD "program.bas’.
To compile and run program.bas:
bas55 program.bas
To start bas55
in editor mode:
bas55
Additional command line options are:
-h, --help
Display usage information and exit.
-v, --version
Display version information and exit.
-l, --license
Show the license text and exit.
-g n, --gosub n
Allocate enough space so that, at maximum, ‘n’ GOSUB
statements can be executed without any RETURN
statement.
The default is 256.
-d, --debug
Enable debug mode. It will warn if a variable is used before a value is assigned to it.
The ECMA-55 Standard leaves some features to be defined by the implementor, given that the limits recommended by the standard are respected.
In bas55
they are:
bas55
is compiled or executed.
bas55
is compiled or executed.
bas55
zero divided by zero gives an undefined value (not-a-number or NAN), and not positive infinity.
A BASIC source code is stored as separated lines in line.c. The compiler translates those lines into opcodes (in code.c), string constants as they appear in the code (in str.c), DATA statements (in data.c), array descriptors (with info about arrays like their dimensions, in arraydsc.c) and some debug info (in dbg.c). If there are not compilation errors, then the program can be run by vm.c, which takes the generated program and starts interpreting the opcodes. During the program execution, probably new strings will be generated in str.c and others will be discarded (but not the ones defined in the program).
In both compilation and execution phases, memory is allocated at start and deallocated when the operation ends.
After compiling without errors, we know the amount of RAM for the virtual machine that the BASIC program will need for executing. This RAM is an an array of numbers, or indexes that point to strings in str.c. Every variable and array declared in the program will have one or more positions used in this array.
Moreover, the compiler can calculate the amount of stack required by all the program, as we can know the stack needed by each statement, and BASIC does not allow a user defined function to call itself or call another function defined after it.
But it can’t calculate the amount of stack needed for GOSUB calls.
If your program does more than 256 consecutive GOSUB calls without using any RETURN statement, you will need to raise the number of allowed calls by a command line option or by using SETGOSUB
in editor mode.
If we run out of memory while compiling or running the program, the operation will stop.
The program is compiled for a typical stack machine. The compilation generates a series of slots, each slot being an instruction opcode, an integer or a floating number. A typical expression like ‘3*2+5’ is translated to:
0: PUSH_NUM_OP 1: 3.0 2: PUSH_NUM_OP 3: 2.0 4: MUL_OP 5: PUSH_NUM_OP 6: 5.0 7: ADD_OP
When executing this code, the values are put on the stack until they are used by the operators.
For example, PUSH_OP
puts the next number on the top of the stack.
MUL_OP
takes the two numbers on the top of the stack and multiplies them, pops them from the stack, and puts the result back to the top of the stack.
For instance, when we execute the opcode at 0, we get this stack:
0: 3.0
After executing the opcode at 2:
1: 2.0 0: 3.0
After executing the opcode MUL_OP
at 4 we get this stack:
0: 6.0
In the following sections we describe how other more complex BASIC statements are translated.
10 LET A=B(1)+C(2,3)
is translated to:
0: PUSH_NUM_OP 1: 1.0 2: GET_LIST_OP 3: B 4: PUSH_NUM_OP 5: 2.0 6: PUSH_NUM_OP 7: 3.0 8: GET_TABLE_OP 10: C 11: LET_VAR_OP 12: address of A in RAM
For each variable A to Z that is an array, we maintain a descriptor that knows the position of the first element of the array in the virtual machine’s RAM.
The descriptor also stores the dimensions of the array, so we can check for out of range accesses.
When we find a GET_LIST_OP B
we go to the descriptor of B to get this information.
On the other hand, code like LET_VAR_OP
expects only the raw position in vm’s RAM that was allocated for the variable.
And
10 LET A(1,2)=3
is translated to:
0: PUSH_NUM_OP 1: 1.0 2: PUSH_NUM_OP 3: 2.0 4: PUSH_NUM_OP 5: 3.0 6: LET_TABLE_OP 7: A
10 ON A GOTO 100, 200
is translated to:
0: GET_VAR_OP 1: address of A 2: ON_GOTO_OP 3: 2 4: 100 5: 200
The number 2
at slot 3
is the number of elements in the GOTO
list; in this case 2: 100 and 200.
10 IF A>3 THEN 100
is translated to:
0: GET_VAR_OP 1: address of A 2: PUSH_NUM_OP 3: 3.0 4: GREATER_OP 5: GOTO_IF_TRUE 6: 100
10 FOR I=1 TO 10 STEP 2 15 LET A=I*2 20 NEXT I
is translated to:
0: PUSH_NUM_OP 1: 1.0 2: PUSH_NUM_OP 3: 10.0 4: PUSH_NUM_OP 5: 2.0 6: FOR_OP 7: address of temporary var (call it ‘vstep’) 8: address of temporary var (call it ‘vlimit’) 9: address of I 10: FOR_CMP_OP 11: 21 (index past NEXT) 12: GET_VAR_OP 13: address of I 14: PUSH_NUM_OP 15: 2.0 16: MUL_OP 17: LET_VAR_OP 18: address of A 19: NEXT_OP 20: 10 (index to FOR_CMP_OP) 21:
When executed, FOR_OP
takes the 3 values on top of the stack and sets ‘vstep’, ‘vlimit’ and the loop control variable (‘I’ in this case).
FOR_CMP_OP
checks for loop termination.
NEXT_OP
increments the loop variable by the loop step and returns to the FOR_CMP_OP
.
10 DEF FNA(X)=X*X 20 LET X=FNA(2)
is translated to:
0: GOTO_OP 1: 8 (index past RETURN_OP) 2: GET_VAR_OP 3: address of FNA's X 4: GET_VAR_OP 5: address of FNA's X 6: MUL_OP 7: RETURN_OP 8: PUSH_NUM_OP 9: 2.0 10: LET_VAR_OP 11: address of FNA's X 12: GOSUB_OP 13: 2 (index of FNA start code) 14: LET_VAR_OP 15: address of X
10 INPUT A, B(1), S$
is translated to:
0: INPUT_OP 1: INPUT_NUM_OP 2: 5 (index to the end of INPUT A) 3: LET_VAR_OP 4: address of A 5: INPUT_NUM_OP 6: 11 (index to the end of INPUT B(1)) 7: PUSH_NUM_OP 8: 1.0 9: INPUT_LIST_OP 10: B 11: INPUT_STR_OP 12: 15 (index to the end of INPUT S$) 13: LET_STRVAR_OP 14: address of S$ 15: INPUT_END_OP
10 PRINT "RESULT="; 2+3
is translated to:
0: PUSH_STR_OP 1: address of "RESULT=" 2: PRINT_STR_OP 3: PUSH_NUM_OP 4: 2.0 5: PUSH_NUM_OP 6: 3.0 7: ADD_OP 8: PRINT_NUM_OP
bas55
always guarantees that every variable and every array is filled with zeroes when the BASIC program is run, but this is not required by the standard.
If you want to make your program fully portable you have to assume that possibly variables are not initialized to zero in other implementations.
To assist you, when in debug mode, bas55
checks if any variable or array element has been assigned a value before being involved in any expression.
We issue a warning if the test fails.
Of course, this slows down the execution of the BASIC program.
By default, bas55
runs in debug mode only when started in editor mode.
You can set the debug mode on or off in the editor with the command DEBUG ON
or DEBUG OFF
, or you can start bas55
with the option -d (or --debug).
This manual is for bas55 (ECMA-55 Minimal BASIC System) version 1.16 (updated 22 February 2018).
Copyright © 2018 Jorge Giner Cordero
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.