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
..............
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 line170. 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!