LASER BASIC COMPILER
by Chris Melling

INTRODUCTION
The Laser BASIC Compiler is aimed at the user who has written a program with
Laser BASIC and wishes to produce a stand alone program that will run
independently of the extended interpreter. Programs compiled with this
compiler can be marketed in any way chosen and there are no restrictions or
royalties to pay.

The compiler can be used to compile normal Spectrum programs which do not
use any Laser BASIC commands but the increase in speed will probably only be
about a factor of 2 or less. The compiled code is more compact than the
BASIC source but there is an overhead due to the run-time code. Laser BASIC
programs which will run under the extended interpreter will never be too
large to compile.


TAPE MAP
	Filename	Loading Instructions
Side A:	"COMPCODE"	LOAD ""CODE
	"LOADER"	LOAD ""
	"RTCODE"	LOAD "RTCODE"CODE
Side B:	"DEMO"		LOAD ""


COMPILING A PROGRAM
To compile a program, only the Compiler and the program to be compiled need
to be in memory. Moreover, it is essential to ensure that Laser BASIC is not
resident at the time. Thus, if a Laser BASIC program has been typed in, then
it must first be saved, the machine re-set, and the program re-loaded.

N.B. No changes may be made to a line of a program containing Laser BASIC
commands, without the extended interpreter resident.

Before loading the Compiler, it is first necessary to force the top of BASIC
memory to below its loading position with the command:
	CLEAR 59799

The Compiler may then be loaded by typing:
	LOAD ""CODE
or	LOAD "COMPCODE"CODE
If the program to be compiled is not already in memory, then it must be
loaded in the normal way.

Compilation may then be initiated with the command:
	RANDOMIZE USR 59800

Whilst the Compiler is executing, erroneous lines and colours will appear on
the screen; this is designed to give you heart failure and to make you
believe that it has crashed! Not so. The effect is due to the Compiler using
screen pixel and attribute memory as temporary work space. When the process
is complete, the screen will clear and the familiar OK message will be
displayed, together with the last line and statement number which was
compiled.


THE FORM OF A COMPILED PROGRAM
As the Compiler runs, it over-writes your BASIC program with compiled code,
and upon successful completion of compilation the compiled code appears to
BASIC exactly like any other BASIC program. Thus it may be SAVEd and LOADed
in exactly the same way as any ordinary BASIC program.

Do not attempt to alter in any way a compiled program: by typing new lines,
deleting lines or editing lines; or by MERGEing two compiled programs - this
may be affected by MERGEing two BASIC programs, and compiling the whole. If
you try to LIST the compiled program, you will only see a few lines of BASIC
before the listing stops. The first two of these are inserted by the
Compiler, and appear irrespective of the program which was compiled. The
first should appear:
	0 PRINT 0

This statement, which is never executed, contains some hidden information
which the run-time package needs for the successful execution of your
program. The second line should appear:
	1 RANDOMIZE USR 59800
and is there to facilitate the automatic running of a compiled program -
more of which later.

If your program contained any user-defined functions, then you would observe
a list of them on a third line, numbered arbitrarily 0. They will be all
squashed together on the same line. Note that this does not apply to Laser
BASIC procedure definitions, which are compiled separately.

In addition, if your program contained any DATA statements, then these would
appear on a further line 0, after any user-defined functions. All DATA Items
are strung together as one large DATA statement, but note that this does not
affect the operation of any RESTORE statements, which will work as intended.


RUNNING THE COMPILED PROGRAM
With the compiled program still in memory (or it may be loaded now or
later), the Run-time package must now be loaded. Assuming the CLEAR 59799 is
still operative (do it now if in doubt), this is performed with:
	LOAD "RTCODE"CODE

At this stage, if the program requires any SPRITES to be pre-loaded, then
these should be LOADed exactly as would be done for a normal LASER BASIC
program.

If the compiled program is not already resident, then it should now be
loaded (exactly like a normal BASIC program).

The program is now ready to be executed. This is done with the command:
	RANDOMIZE USR 59800
or
	GOTO 1
remembering line 1 of the program mentioned above.

The program will now execute, but note that it cannot be broken into using
the BREAK key (apart from during a tape or microdrive operation).


PRODUCING A STAND-ALONE PROGRAM
If you wish to market a program which you have written in Laser BASIC then
it must be compiled. In addition, you would normally wish it to be a stand
alone program, so the end user just has to type LOAD "" or whatever, and the
whole things runs automatically.

This is achieved using a loader program (which auto-runs), which loads in
the run-time package, any sprites, and finally the compiled program, which
can also be made to auto-run.

Such a loader program, which you can use to build on, is included on side
one of the Compiler tape. It appears below:

	10 CLEAR 59799
	20 LET spst=
	30 LOAD "RTCODE"CODE
	40 LOAD "SPRITES"CODE spst
	50 LET t=INT (spst/256): POKE 62464,spst-256*t: POKE 62465,t
	80 POKE 62466,255: POKE 62467,220
	70 POKE 56575,0
	80 LOAD ""

Line 10: Executes the necessary CLEAR to make room for the run-time package.
Line 20: For you to set the appropriate value for the start of sprites, as
	 told by the sprite generator program.
Line 30: LOADs the run-time package.
Line 40: LOADs the sprites.
Line 50: POKEs in the start of sprites.
Line 80: POKEs in the end of sprites.	See Laser BASIC manual.
Line 70: POKEs in the end of sprites character.
Line 80: LOADs the final compiled program.

NOTE: If no sprites are used, then lines 20,40,50, 60 and 70 can be omitted.

It merely remains for you to fill in the correct value of spst, and to SAVE
the necessary set of files on the tape, ensuring that the loader and the
compiled program are SAVEd to auto-run. For the loader this will entail:
	SAVE "loader"LINE 10
and for the compiled program:
	SAVE "<compiled-program-name>" LINE 1
- you will recall that line 1 is the compiler generated line, which calls
the run-time package to start execution of the compiled program.

An example of this process appears later in the manual when instructions are
given for you to produce a compiled version of the Invader Cube game.

RESTRICTIONS ON THE BASIC TO BE COMPILED
The design of this Compiler has meant that certain restrictions have had to
be imposed, and some assumptions made. These are itemised below:

a)	Computed GOTO, GOSUB, RUN and RESTORE statements should not be
	attempted, as the following expression as evaluated at compile-time
	will be used. i.e. all numeric variables will have value zero. and
	all strings length zero.

b)	An attempt has been made to accommodate computed DIM statements,
	and those with dimensions which evaluate to zero (an impossible
	value under Sinclair BASIC) will not be declared until run-time.
	This means. however, that statements such as DIM a(n+12) will not be
	declared as might have been envisaged. as the dimension expression
	will be evaluated to 12 and hence the array will be declared as such.

c)	There is no restriction on the number of times an array may be
	redeclared, but you will appreciate that the first declaration is
	done during compilation, and therefore that statement is not copied
	to the compiled program. Thus if a jump is made back to the start of
	a program to before the place where your first DIM was, for a
	particular array, it will not be there to be executed on the second
	pass. This can be got round (if you must use array redeclaration) by
	having an extra declaration of that array right at the beginning of
	the program, before any "re-start" jumps.

d)	CLEAR statements are not allowed at all and produce a compiler error
	message - see below.

e)	RUN statements operate as in BASIC except that they do not clear
	the variables.

f)	MERGE, CONTINUE, LIST and LLIST commands are not allowed and 
	produce a Compiler error message - see below.

g)	Do not try and CONTINUE a crashed or STOPped compiled program.

h)	OPEN# and CLOSE#. These will only work to streams "S", "K" and "P".
	Microdrive datafile handling is not supported.

i)	LOAD, SAVE and VERIFY. These all work as normal, except if a BASIC
	program is LOADed then it is assumed that it will be a compiled
	program and the run-time package will attempt to execute it from the
	start.


USING THE COMPILER WITH MICRODRIVES
The Compiler and run-time package are both compatible with microdrives,
except that microdrive datafiles are not supported in compiled programs. All
the examples shown In this manual may be converted to microdrive just by
adding the infamous " *"m";<d>; " between the command and the filename.


ERROR MESSAGES

Illegal statement found
This is produced by the Compiler if one of the statements CLEAR, MERGE,
LIST, LLIST or CONTINUE is found.

Procedure definition nesting error
This is produced by the Compiler if two procedure definitions are found
without an intervening .RETN. You cannot nest procedure definitions.

.RETN without DEF FN #error
This is produced by the Compiler if a .RETN statement has been found without
a corresponding procedure definition.

Procedure not defined
This is produced by the compiler if a call is found to a procedure that has
not been defined. Note that you don't have to declare a procedure before it
is used.

Program not compiled
This is produced by the run-time package if, when it is first called, the
beginning of a program is not recognisable as a compiled program.

Execution of a compiled program is as susceptible to the normal run-time
errors as any BASIC program. However, the run-time package for the compiler
is unable to tell you where any such error occurs when it happens. Further,
you should ignore the numbers which appear alongside a Sinclair error
message. Thus you should ensure that a program is fully tested and debugged
before you compile it.

After receiving any error message, the program will be partially or
completely compiled, and so you must re-LOAD the original BASIC program to
make the necessary alterations before re-compiling.


MEMORY MAP
The Compiler and run-time package both LOAD in at 59800. The run-time
package occupies memory from that point right up to the top of memory, and
once you have LOADed it, you may SAVE it with:
	SAVE "RTCODE"CODE 59800,65536-59800

The Compiler ends at 62856, occupying some 3057 bytes, and you may re-SAVE
it with:
	SAVE "COMPCODE"CODE 59800,3057
Hence, when using either package, the need for the CLEAR 59799.

A compiled Laser BASIC program will appear in memory as follows:

+------------+--------------+- - - - -+------------+--------------+-----------+
|  Program   |  Variables   |         |  SPRITES   |  m/c stack   |  RTCODE   |
+------------+--------------+- - - - -+------------+--------------+-----------+
 PROG       VARS          ELINE     spst       spnd-56575      59800      65535

Note for machine code programmers
Simple arithmetic will tell you that the gap between the top of sprites and
the run-time code is some 3k or more. Now under normal circumstances the
stack will need less than 256 bytes, and so the rest of this space may be
used for machine code routines, either by working up from the top of
sprites, or by CLEARing nearer the sprites and using the area after that
point up to the run-time code. Obviously there is nothing to stop you from
CLEARing under the sprites and using the whole gap: and so on.


INSTRUCTIONS FOR PRODUCING A STAND-ALONE COMPILED PROGRAM
FOR THE INVADER CUBE GAME
On tape two side two of your Laser BASIC package is a game entitled Invader
Cube. Here follows the instructions for you to produce a compiled
stand-alone version.

The tape map of the standard game is as follows:
	The loader (to auto-run)
	The loading screen
	Three programs comprising Laser BASIC
	The sprites for the game
	The game program itself (to auto-run)

For a compiled version, the tape map will need to be:
	The loader (to auto-run)
	The loading screen
	The Run-time package
	The sprites
	The compiled game program (to auto-run)

To produce this you will need a blank side of a cassette.

First the loader program has to be designed. We will use the loader provided
as part of the compiler package as a starting point. At present it appears:

	10 CLEAR 59799
	20 LET spst=
	30 LOAD "RTCODE"CODE
	40 LOAD "SPRITES"CODE spst
	50 LET t=INT (spst/256): POKE 62464,spst-256*t: POKE 62465,t
	80 POKE 62466,255: POKE 62467,220
	70 POKE 56575,0
	80 LOAD ""

Now, the value of spst needs setting to that required for the game sprites
which is 53780. Also, an extra line needs to be inserted to LOAD the loading
screen:
	25 LOAD "scrn"CODE

In addition, to prevent the destruction of the screen whilst loading is in
progress, the following line needs to be added at the start:
	5 INK 0: PAPER 0: BORDER 0: CLS
and PRINT AT 0,0;: inserted before each of the load statements. As you are
altering the final line - that to load the game - you can insert the name
which it will be saved as, say "cgame":
	80 PRINT AT 0,0;: LOAD "cgame"

So the final loader appears:

	 5 INK 0: PAPER 0: BORDER 0: CLS
	10 CLEAR 59799
	20 LET spst=53780
	25 PRINT AT 0,0;: LOAD "scrn"CODE
	30 PRINT AT 0,0;: LOAD "RTCODE"CODE
	40 PRINT AT 0,0;: LOAD "SPRITES"CODE spst
	50 LET t=INT (spst/256): POKE 62464,spst-256*t: POKE 62465,t
	80 POKE 62466,255: POKE 62467,220
	70 POKE 56575,0
	80 PRINT AT 0,0;: LOAD "cgame"

This should now be saved on your new tape so that it will auto-run:
	SAVE "loader"LINE 5

From looking at the tape map above, and the loader which you have just
SAVEd, it is clear that the next thing which needs SAVEing after the loader
is the loading screen. This must be got from the original game tape. To do
this you must LOAD the second file, called "SCREEN":
	INK 0: PAPER 0: CLS
	LOAD "SCREEN"CODE

When it is in, and the OK message appears, type:
	SAVE "scrn"CODE 16384,6872
to SAVE the screen after the new loader on your new tape. STOP the tape when
the operation is complete, and reset the machine.

Referring again to the tape map, we see that the run-time code must now be
SAVEd. So this must be LOADed from the compiler tape - not forgetting the
CLEAR:
	CLEAR 59799
	LOAD "RTCODE"CODE

Now this may be SAVEd to the new tape after the screen with:
	SAVE "RTCODE"CODE 59800,65536-59800

STOP the tape when this is complete.

Back to the tape map, and we see that the sprites for the game must be next
SAVEd. Again these must be got from the original game tape, and you will see
from that map that they are situated after the three CODE files which
comprise Laser BASIC. The command:
	LOAD "SPRITES"CODE 53780
will skip through these and LOAD the sprites. Then SAVE them to your new
tape after the run-time code with:
	SAVE "SPRITES"CODE 53780,56576-53780

Finally, the game itself must be compiled, and SAVEd after the sprites.
Ensuring that Laser BASIC is not resident, LOAD the game with:
	LOAD "INVADER"

It will auto-run once it is in, but will soon crash out when it comes to a
Laser BASIC command, which of course it cannot understand without the
Extended BASIC resident. When this occurs, LOAD the Compiler in the normal
way:
	CLEAR 59799
	LOAD "COMPCODE"CODE

Compile the program with:
	RANDOMIZE USR 59800
and SAVE the result on your new tape with:
	SAVE "cgame" LINE 1
remembering the auto-run facility.

You can now rewind the tape, reset the machine, and type:
	LOAD ""
and the compiled version of Invader Cube will LOAD and RUN.

Microdrive users should note that this procedure will work equally well on
that media, just by changing all the SAVE commands to SAVE *"m";1; and the
LOADs in the loader program to LOAD *"m";1; .
