Our version of BASIC follows original versions of the language, but also includes some enhancements from later dialects. Particularly, line labels are not obligatory.
If you are familiar with Python
, you'll find BASIC similar, but much simpler. In any case you supposedly can
master it in 15 minutes
:)
Language is case-insensitive
. Through this instruction we shall use uppercase for language keywords, to
distinguish from variables etc. But you can write all uppercase or all lowercase as you would like.
If you would like to run interpreter on your own machine, source could be taken from the php-basic project's page. You'll need PHP installed to run it.
Most simple program is to output some message:
PRINT "I'm a fine message!"
Input needs to store data to some variable, so we mention this variable (e.g. name
):
INPUT name
It's ok to mention several variables, also quoted string could be used as a prompt for user. Later we can print those variables back:
INPUT "What is your name and surname?", name, surname
PRINT "Well, Hello then", name, surname, "!"
Note about formatting. PRINT
will normally insert space between values it outputs, and also put newline in
the end. Both of these could be suppressed if you use semicolon (;
) instead of comma (,
) as separator. To
suppress newline semicolon should be dangling in the end, e.g.
PRINT "NoSpace"; "InThisLineAndNoLineEnd";
Variables are represented by simple names starting with letter. Remaining characters could also include digits
and possibly one dollar sign ($
) in the end (for compatibility with older dialects, where it marked text
variables).
Variables can have numeric or text value. Assignment operator is just equals sign. It is allowed to use
"historical" LET
keyword in assignment statements, but not necessary:
x = 5
PRINT x, "squared is", x * x
LET fruit = "Mellon"
LET count = 5
PRINT fruit + " * " + count
this shall print 5 squared is 25
and Mellon * 5
.
Obviously variables can participate in expressions with the following operations:
+ - * / arithmetics (plus also concatenates text values)
^ MOD raising to power and calculating modulo (remainder)
> < = >= <= <> comparison operators return 1 (true) or 0 (false)
AND OR logical operators, use 0 (or empty text value "") as false
Precedence is standard, though feel free to use parentheses for clarity.
It's as easy as this:
FOR i = 1 TO 10
PRINT i, "squared is", i * i
NEXT i
You may see here that:
NEXT
keyword, mentioning the same variable which is used in the loop1
and 10
will be included)It is possible to increment variable in non-default step:
FOR i = 1 TO 7 STEP 2
PRINT i, "is odd"
NEXT i
Comments are statements with REM
keyword, which could be followed by anything else, which is ignored till
the end of line. Notably, comment can't simply start in the end of other statement.
However it is possible to have multiple statements in single line, separated with colon (:
)
REM program demonstrating comments
FOR i = 1 to 7 STEP 2 : PRINT i, "is odd" : NEXT i : REM "Printing 1, 3, 5, 7 here"
In this example we see the same loop as above, but written in single line, all 3 statements (and extra statement with comment).
There is only one conditional operator, it wors as you may expect:
INPUT "guess the number less than ten", x
IF x = 7 THEN PRINT "you are right!"
PRINT "good bye"
Notably, here is no ELSE
(this is generally provided by other ways).
Also note IF
executes (or skips) any remaining statements till the end of line, like this:
IF password = "secret" THEN PRINT "Hi boss" : money = money * 2 : PRINT "money doubled"
and nested if can be added among those statements:
IF temperature > 20 THEN PRINT "it's warm" : IF temperature > 30 THEN PRINT "even hot!"
To compensate for lack of different kinds of loops, we can simply mark some place in the code with the label and make a jump to this label:
x = 1
n = 0
repeat:
PRINT x
x = x * 1.3
n = n + 1
if x < 100 THEN GOTO repeat
PRINT "It took", n, "steps"
In this case we iterate multiplying variable by some value, but we don't know beforehand how many iterations
it will take to reach 100
.
Label is any name (like variable) followed by colon (:
) - it could prepend statement or be on separate line.
Numeric labels also works, see below.
Other obvious use is to compensate for the lack of ELSE
in conditional statement:
INPUT "What's your name?", name
IF name <> "John" THEN PRINT "you are not my friend" : GOTO goodbye
PRINT "Hi Friend"
goodbye: PRINT "see you later"
Original versions of BASIC used numeric labels preceding every line. Really labels were obligatory, code looked like this:
10 REM loop demonstration
20 LET x = 1
30 IF x MOD 3 = 0 THEN PRINT "fizz", x
40 IF x MOD 5 = 0 THEN PRINT "buzz", x
50 LET x = x + 1
60 IF x <= 100 THEN GOTO 30
Note here the condition at the end of the loop jumps to the line labeled 30
.
Our version of BASIC supports such numeric labels, though doesn't require them to be in order.
Special feature is that GOTO
argument could be expression! this is prohibited in many languages
(and even many BASIC dialects), but works in our version.
This could be used to create switch-like
statements, or for writing programs in fancy style.
For example, remember that comparison operators return 1
for true and 0
for false. Let's use it to create
loop without conditional statement!
x = 1
10 PRINT x
x = x + 1
GOTO 10 + (x > 10) * 20
30 END
here the GOTO
statement shall jump either back to loop body, or forward to END
statement.
Remember however that labels are global. However it is possible to use text values in calculated labels too,
so the resulting label is like calc10, calc20, calc30
etc.
Besides simple ("scalar") variables we also can use arrays. Array is first declared to have specific
size and then its elements could be used almost everywhere where plain variable is expected (except for loop
variable). Declaration is done using DIM
keyword:
DIM a(10), b(30, 3)
In this way we declare array a
for 10
elements and two-dimensional b
with size 30
by 3
.
It is allowed (in our dialect) to use expressions in DIM
so that real size is is not predetermined, but
calculated in runtime. Usage example could be like this:
INPUT "number of elements:", n
DIM a(n)
FOR i = 0 TO n - 1
INPUT a(i)
NEXT i
REM now array is filled from input...
Note that array indexes are zero-based
(some other dialects start with 1
).
Sometimes we need not only declare array, but also pre-fill it with some values. In BASIC such values could
be placed in DATA
statements everywhere in the program and then retrieved with READ
in the same manner
as INPUT
works. This also works for normal variables and text values.
READ pi, e
DIM cipherkey(16)
FOR i = 0 TO 15 : READ cipherkey(i) : NEXT i
DATA 3.14159265, 2.718281828, 97, 13, 24, 59, 71, 48, 50, 32
DATA 11, 85, 44, 26, 69, 30, 93, 15
Here we initialize variables pi
and e
with corresponding values, then initialize 16 elements of array
with values from 97
to 15
. All DATA
statements in the program are combined into single long list before
start and READ
just picks next from it every time.
So it doesn't matter where to put DATA
and whether execution shall reach it. Only the order matters.
Additionally keyword RESTORE
could be used to "rewind" all the data so that following reads shall continue
from beginning.
Subroutines are used to avoid copy-pasting the code when it should be used in several place. Also they
may help in splitting program into smaller yet meaningful parts. We simply use word GOSUB
with label,
similar to GOTO
to make a subroutine call.
It differs from simple jump (with GOTO
) because interpreter remembers the place from which we called
subroutine, and allows later to jump back with simple keyword RETURN
:
x = 5
GOSUB printstars
x = 9
GOSUB printstars
END
printstars:
FOR i = 1 TO x : PRINT "*"; : NEXT i
PRINT : REM empty print just makes newline
RETURN
Here we call subroutine 2 times to print a line made of stars, different length each time. Note that subroutines share variables with the remaining program so one should be careful not to reuse something unintentionally.
Also note it is useful (generally - even necessary) to finish the main body of the program with END
keyword,
otherwise execution would fall-through into the first subroutine following (and probably shall fail trying to
execute RETURN
since there was no preceding subroutine call).
In the expressions we can use a number of built-in functions, e.g.:
FOR i = 0 TO 20 : PRINT SIN(i / 10 * 3.14159) : NEXT i
Here SIN
is the function to calculate sine. There are other names:
ABS SGN INT - absolute value, signum and round-down
SIN COS TAN ATN - trigonometric functions
EXP SQR LOG - raising e to given power, getting square root and natural logarithm
RND - random value, requires argument but ignores it
Also up to 26 user-defined functions are allowed. They shall have names FNA
to FNZ
and are declared
this way:
DEF FNY(x) = x * x - 5 * x + 3
Variable (the argument) could be different. Currently only single argument is allowed.