                   MAKING COMPILED PROGRAMS SMALLER
                   --------------------------------


                           By Martin Cubitt


                          6th December 1993



    The compiled versions of a STOS program can be mammoth. Even the 
simplest of BASIC programs, when compiled, can produce 50 or 60K of 
compiled code.

    A compiled program can, of course, be compressed using one of the 
many packers around. Using the Atomik packer most STOS-compiled 
programs can be reduced to around 50%. Quite a saving when you are 
trying to get as much as possible onto a disc.

    Wouldn't it be nice, however, if you were able to reduce the size 
of the compiled code further, before it was compressed? Well the good 
news is that you can but the bad news is that the saving is quite small 
(depending on the size and complexity of your program).

    I have mentioned in a previous article that it is not, despite some 
suggestions to the contrary, advantageous to remove the original STOS 
supplied files which occupy the COMPILER folder. You do not use sprites 
in your program? Okay, delete SPRITExxx.BIN and try to compile your 
program. It will compile okay if it does not use ANY sprite function. 
However, bring back the SPRITExxx.BIN and compiler the program again. 
The object size will be the same. If your programs requires any traps 
from the STOS-supplied libraries it will load the entire library and 
use that but if it needs none of them it will not.

    So how CAN you make your compiled programs smaller? Well, the 
method I am going to describe will be considered (and quite rightly so) 
very mundane and some will ask "is it worth it?". It is up to the 
individual. If the size of the compiled object MUST be an absolute 
minimum then I suggest you spend time to make it so.

    The idea is to remove all 'rem' statements and pack as many 
commands onto one line as possible. Actually, it is the removing of 
unnecessary lines that save the space. Every line, even if it only has 
a rem statement on, takes up 6 bytes. Each one you can delete will save 
you 6 bytes from your compiled program. Wow! Six bytes from 60K? What a 
great saving!

    Hold on, the more lines you can delete the more you can save. 
Delete ten unnecessary lines and you have saved 60 bytes, one hundred 
lines and the saving is 600 bytes.

    The rem statement is not compiled and nor is the comment after the 
statement. SO the line

    10 rem A simple program for a start

    will only compile to 6 bytes, because it contains one line. (In 
fact the program will fail to compile because there are no line which 
can be compiled)

    A line such as

    10 mode 0 : rem Low res screen

    will compile to the exactly same size as

    10 mode 0

    but

    10 rem Low res screen
    20 mode 0

    will take up 6 more bytes!

    I would NEVER suggest when writing your program you do so with the 
compiled version in mind, keep any remarks or comments clear so that 
debugging is made easier for you. Put enough rem statements in the 
program, just prior to compiling THEN strip them out and economise the 
code. (Do not save the de-remmed version otherwise there was no point 
in putting them in initially!).

    As all good programmers know, writing clear code requires you to 
keep to a limit of one instructions (except where unavoidable although 
some suggest there is never such an occasion) per line.

    That is, rather than

    10 SC=0 : LI=3 : ROUND=1 : BONUS=500 : if mode=1 then mode=0

    you should use

    10 SC=0
    20 LI=3
    30 ROUND=1
    40 BONUS=500
    50 if mode<>1 then 70
    60 mode 0
    70 ...

    However, this is not a lesson in structured or clear programming. I 
am going to assume that your programs are fairly structured and well 
REMmed.


    Once you have finished your program and you have tested it you will 
be ready to compile it. Make sure you save the full BASIC version with 
the structured code and abundant comments.

    Now get ready to rip the program to pieces!

    To make things a little simpler I have written a small example 
program and show you one method to economise a program.

    This is the full program...

 10 rem Simple program to show how to
 20 rem make compiled programs slightly
 30 rem smaller.
100 mode 1
110 key off 
120 hide 
130 curs off 
140 flash off 
150 palette $0,$777
160 curs on 
170 rem Input person's name
180 print 
190 input "Enter your name (or QUIT):";NAME$
200 print 
210 if upper$(NAME$)="QUIT" then 900 : rem If QUIT then end
220 if NAME$<>"" then 260 : rem If not blank then skip error
230 rem Name is blank, print error and try again
240 print "You must have a name!"
250 goto 170
260 rem Valid name, ask their age
270 rem Input person's age
280 print 
290 input "Now tell me your age (-1 to quit):";AGE# : rem Allow decimal, eg for 11.5 for eleven and a half
300 print 
310 if AGE#=-1 then 900
320 if AGE#>0 then 360 : rem If greater than 0 then skip error
330 rem Age is 0 or below, print error and try again
340 print "You must be born to use this!"
350 goto 280
360 if AGE#<100 then 500 : rem If age less than 100 ignore anymore fancy validation
370 rem Age is at least 100. Check a few ranges and give appropriate messages.
380 if AGE#>120 then 420 : rem Age greater than 120, unlikely but poss
390 rem Age between 100 and 120 (good ages but possible)
400 print "Congratulations, that is quite an age!"
410 goto 500
420 rem Age is more than 120, check once more
430 if AGE#<150 then 470 : rem Age less than 150, maybe possible!
440 rem Age greater than or equal to 150, I don't think so!
450 print "What? You ARE joking. Be serious this time!"
460 goto 270
470 rem Age high but remotely possible
480 print "Many congratulations, that is an exceptional age!"
490 goto 500
500 WEEKS#=AGE#*52
510 clw 
520 print 
530 print "Now then ";NAME$;","
540 print "You tell me that you are";AGE#;" years"
550 print "old. Let me see how many weeks that is..."
560 wait 120
570 print 
580 print "Well, I make it";WEEKS#;" weeks!"
590 print 
600 print 
610 print 
620 print 
630 print 
640 print 
650 print 
660 print 
670 print 
680 print 
690 print 
700 print 
710 print 
720 print 
730 print 
740 print "  NEXT PERSON PLEASE..."
750 print 
760 goto 170
900 default
910 end 


    Okay, so it is not as small as I thought! Anyhow, let us start to 
economise...

    I happen to know that lines 10 - 30 are comment lines. I do not 
even need to check if there is a goto 10,20 or 30 because I know there 
is not. Therefore these lines can be deleted immediately saving exactly 
6 x 3 = 18 bytes!

    I also know that lines 100 - 160 can be merged so I enter

100 mode 1 : key off : hide : curs off : flash off : palette $0,$777 :
    curs on 

    after deleting 110 - 160 I have saved a further 6 x 6 = 36 bytes. 
That is 54 bytes so far!

    Line 170 is a simple rem line but I cannot just delete it. I have 
to check to see if any other line references it.

    Firstly I delete the line
           170
    I then enter
           search "170
    the computer returns
           250 goto 170

    Ah ha! I check the program and find the first 'real' line is at 180 
so I change line 250 to
           250 goto 180

    I check any more...
           search
    the computer returns
           760 goto 170

    I change this to
           760 goto 180

    more?
           search
    the computer returns
           search failed


    Basically I go through the entire program (quite a chore, even with 
a small program) economising. Try not to change the actual logic (what 
it does) unless it is a clear improvement. For example, with cunning 
use of the else command you can save many more lines. Any errors in 
your program (such as spelling) that you identify as you go through jot 
down so that you can apply the changes to the "real" source afterwards.

    After economising the above program I came up with...

100 mode 1 : key off : hide : curs off : flash off : palette $0,$777 :
 curs on 
180 print : input "Enter your name (or QUIT):";NAME$ : print :
 if upper$(NAME$)="QUIT" then end else if NAME$="" then
 print "You must have a name!" : goto 180
280 print : input "Now tell me your age (-1 to quit):";AGE# : print : 
 if AGE#=-1 then end else if AGE#<=0 then 
 print "You must be born to use this!" : goto 280
360 if AGE#<100 then 500 else if AGE#<=120 then 
 print "Congratulations, that is quite an age!" : goto 500
430 if AGE#>=150 then
 print "What? You ARE joking. Be serious this time!" : goto 280
 else print "Many congratulations, that is an exceptional age!"
500 WEEKS#=AGE#*52 : clw : print : print "Now then ";NAME$;"," : print
 "You tell me that you are";AGE#;" years" : print "old. Let me see how
 many weeks that is..." : wait 120 : print : print "Well, I make it";
 WEEKS#;" weeks!" : locate 0,21 : print "  NEXT PERSON PLEASE..." :
 print : goto 180


    Notice that I have deleted lines 900 and 910. I replaced the goto 
900 with straight 'end's and delete the 'default' completely. There is 
not need for default in a compiled program.

    All those prints have been replaced with one locate 0,21 a much 
better command in this instance.


    So how much space have I saved?

    Well, I compiled the original program as a .PRG and it totalled 
66,512 bytes. The economised program compiled to 65,797 bytes 
representing a saving of 716 bytes.

    Was it worth it? If I had originally been 716 bytes short when 
trying to save it to disc then yes! Seriously though you may consider 
economising your programs but be careful when changing a line of 
commands to another that you do not omit anything or incorrectly spell 
text from the original.


    Happy economising!
