Specbas: Basic Interpreter User Guide
Specbas: Basic Interpreter User Guide
BASIC interpreter
User Guide
Introduction
There are many computer enthusiasts of a certain age who remember the
great revolution in home computing of the 1980s. Computer manufacturers
such as Commodore, Acorn and Sinclair made some of the most accessible and
friendly devices ever found in the field of computing, and their style of
Operating System has not been seen since, especially with the advent of multi-
gigahertz, multi-gigabyte memory PCs.
Part of the magic of those bygone machines was the fact that space and
resources available to the (single-core) CPUs was very restricted. It can be very
hard to imagine any operating system running in just 16 kilobytes of memory,
but that is exactly what they did. And they didn’t just provide an OS, they also
provided, in every case, a programming language with which the user could
experiment and tinker to their heart’s content.
The Sinclair Spectrum was the most widely owned of these computers in the
United Kingdom, and was graced with a fast 3.5mHz Z80 CPU and 64KB of
memory – 16KB of which was taken up by the ROM which provided the
operating system routines and the BASIC interpreter. Based in the Dartmouth
implementation of BASIC, it quickly gained a reputation as a very capable, if
slightly slow, programming environment.
To this end, this manual is intended for those that are familiar, if not with the
Sinclair Spectrum’s BASIC, then BASIC programming in general. There are
plenty of reference texts available which can teach this wonderful language,
and a course in programming is beyond the scope of this manual.
1. The BASICs
1.1 Line numbers and statements
SpecBAS is based around the concept of line numbers, which are generally not
seen anymore in programming. This is quite often of benefit in helping to
visualise the path the interpreter will take through your code.
Line numbers can be any from 1 to a very large number indeed, and you are
unlikely to encounter an end to the highest number you can use. Take our
word for it, it’s very big.
Line numbers are mandatory, and any line entered without them will be
executed immediately.
10 PRINT “Hello”
10 PRINT “Hello”: GO TO 10
Which illustrates the point quite nicely, but is a rather dull program to watch.
Lines that are entered with a line number but no statement following it will be
deleted from the program listing. You have been warned.
Related to the way line numbers are used, it’s worth mentioning how you can
interrupt the program flow and direct excution to the line you want. In Sinclair
BASIC, of course, this is achieved by using the GO TO and GO SUB commands,
and SpecBAS is no different. However, there are a few nice methods available
to you in SpecBAS which make things much more flexible.
It’s nice to take a jump to another region of your code only if a condition is
met. To that end, there is the DO...LOOP constructor. The syntax of this
command is:
So as you see, while a DO...LOOP structure will loop indefinitely, you can use
WHILE and UNTIL to determine if it should loop. Conditions attached to a
WHILE will be evaluated before the loop is run, whereas conditions attached to
an UNTIL will be evaluated after a loop is run. If the condition is false, of
course, then the loop will not run at all, and execution will resume at the
statement following the LOOP command.
Inequalities are the tests performed in the flow control structures mentioned
above – things like
Where the inequality is the “a<1” part. A logical operator is similar, and
consists of the AND and OR that is used. The problem with AND and OR is that
they work logically (ie, their results depend on either side being true or false,
or greater than zero and zero respectively). This is all very well when testing
the truth of an equation, but other languages use AND and OR in a “bitwise”
fashion – that is, they’re used to isolate and mask specific bits in a number.
In order to perform the same tasks, SpecBAS uses “&” and “|” for bitwise AND
and OR. They are written with special symbols to distinguish them from their
logical counterparts. The other bitwise operators (SHL, SHR, XOR) are written
as words.
Like AND/& and OR/|, the “shift” and XOR commands work like maths
operators – ie, their syntax is
The shift operators shift all the bits in a number left or right one place,
effectively doubling (SHL) or halving (SHR). Any bits shifted off the ends of the
number (this is probably only observable in cases using SHR, as numbers in
SpecBAS can get very large) will be lost.
The XOR command will “invert” all the bits in the first number where bits of
the second number are set. For instance, the number 128 consists of the
binary sequence
%10000000
%01111111
1E+3
1E-3
Constants are words built into SpecBAS which can be used to identify numbers.
The most obvious example of this is PI, which represents the number
3.1415926535897932385. There are others which represent TRUE (1), FALSE
(0) and even common keys on the keyboard – see the Appendices for the full
list. These words can be used in place of the numbers they represent, and do
not slow SpecBAS down at all when interpreting them.
1.4 Variables
Numeric variables are always floating point – with the use of built-in floating
point units on modern CPUs, there is little benefit to using integer maths.
Strings are always one byte per character, unless you are using UDGs (more on
those later) – there is no unicode in SpecBAS.
Arrays are handled as the original BASIC would. Numerics are the same as you
would expect from any other language. Strings variables are, when assigned to
an array with DIM, always fixed-width. This means that doing:
DIM a$(10,10)
Will make an array of ten strings, each of ten characters each. Variable width
string arrays are available with the DIM$ command – in which case the above
command would produce an array of one hundred strings, any one of which
could be any length.
Variables must be assigned with the LET command, which is not optional.
You can quickly increment a numeric variable with the INC and DEC
commands, which are quicker than
LET a=a+1
Or
LET a=a-1
But which will only work on numeric variables, not on strings, and only those
variables that have previously been declared with LET. You can also optionally
specify a range for the variable to be constrained to –
INC a,1,10 TO 50
Will ensure that when a overruns to 51, it will be “wrapped” back around to
10. This wrapping is in actual fact a modulus, so if a is incremented by 2, to
make 52, then it will wrap around to 11.
The SWAP command allows you to swap the contents of two variables of
common type, such as two numeric variables or two string variables.
Memory banks
Storing your stuff
Due to the fact that modern operating systems have nearly unlimited amounts
of memory available due to the use of virtual memory managers and large
hard drives for storing memory pages, SpecBAS has to provide a different
method of accessing regions of memory to the old methods of PEEK and POKE
which older computers used. This method is achieved using memory banks.
Memory banks chunks of memory that hold a particular data type, such as
screen or window data, or font information. SpecBAS provides two banks for
this purpose, and one general-purpose raw binary data bank type.
Which will create a new bank which holds 1,000 bytes and assign the ID
number of that bank to the variable newbnk. You should (and indeed, must)
supply a numeric variable when creating the bank, so that you can refer to that
bank later on.
You can read the bytes held in a bank by using the PEEK function:
PRINT PEEK(0,99)
Which will return the value of the 100th byte (0 is the first!) in Bank 0.
You can set the values held in a bank with the POKE command:
POKE 0,99,255
Will resize the bank’s memory area to the size you specify. This is non-
destructive when “growing” the memory area, but shrinking it will
unfortunately lose any data stored in the end of the bank that is lost after
shrinking.
BANK ERASE id
Will remove the specified bank. Attempting to access this bank without re-
creating it with BANK NEW will result in an error.
Which will duplicate the bank indicated by src_id in the bank specified by
dst_id.