COMAL for the C64 | |
---|---|
COMAL corner ! | : C64 section new at 4 mar 99 - see comal download page! 2/4/00 |
other sources of COMAL from http://www.macharsoft.demon.co.uk | : if you're interested in COMAL on other machines : new at 9th jan 2000 |
C64_COMAL_DOWNLOAD_INDEX_ PAGE | : All the C64 COMAL stuff I've got to hand , mostly in ZIPped LNX format - LYNX17 was used to create the LNX sections which were then PKZIP'd ,some archives are just ZIP'd ,there is a read me text file with info about some of what's available. these files are now on a new server 29/5/01 |
14 COMAL disks | : new at 15/4/99 - see comal download page! 2/4/00 |
A guide to COMAL | _ Roy Burford updated the guide and here's the result ! |
a guide to COMAL | _by brian Grainger _ taken from the pages of ICPUG journal |
from TRANSACTOR , vol6 , #3 - 1985 | Is IOK Enough? |
from TRANSACTOR , vol6 , #3 - 1985 | What is COMAL? |
from TRANSACTOR , vol6 , #3 - 1985 | An Introduction to COMAL: Better than BASIC |
Though available in many different formats, the most popular versions of COMAL are disk-loaded systems which reside in user memory. These releases of the language occupy space otherwise used by user programs. For example, a Commodore 64 running BASIC powers up with the message that there are about 38 kilobytes free, but when loaded with the COMAL system confesses to have only about 1Ok of free space remaining. This has been a source of consternation for those expecting 64k on their Commodores. But the real question is whether serious, sophisticated programs can be run in a small amount of user space like the 10k available with Commodore 64 COMAL.
I will admit at the outset that there are indeed some applications for which 10k is insufficient. It should come as little surprise, in fact, that there are applications for which the entire 64k of the Commodore 64 are to few, among them predicting the weather and flying a space shuttle. But within the domains for which we bought those machines, I have never found an instance in which I would prefer 38k of BASIC workspace over 1Ok of COMAL.
There's a certain elegance to doing a lot with a little. Countless hours
of mainframe use, with seemingly limitless megabytes of "virtual memory",
have not clouded the memories of coming home to my PET, powering up, and
seeing
COMMODORE BASIC
7167 BYTES FREE
proudly displayed on the screen. At the time, this was the big 8k machine; they were still taking orders for the short- lived 4k model as well, with its "3071 BYTES FREE" message. Though I dreamed of the day I could add another 8k chip to that early home computer, it was a needless lust; seldom did the small memory size limit my activities with that machine.
With many of your programs (for some of you, all of your programs), the straightforward technique of simply storing your entire program and all necessary data simultaneously in the 10 free kilobytes will work quite well. Just compute merrily onward, and forget that some people with other applications might be having difficulty fitting everything into their machines. The remainder of this article is not for you.
First you can regain some free memory by "cleaning out" your program's name table. COMAL keeps every variable, procedure, and function name in a table. Once the name is in the table, it stays there, even if the variable isn't used any more. Misspelled names remain in the table as well, even if they are corrected in the program. COMAL saves the name table along with the program when you issue a SAVE command. Thus the old name table is reloaded with each LOAD. But, if you LIST the program to disk (LIST" NAME.L " ), issue a NEW command, and then ENTER it back again (ENTER " NAME.L " ), COMAL will rebuild the name table. You should have more free memory now.
Another very simple and efficient way of regaining lost space with COMAL is to hone down the size of your DlMs to what you actually need. In the DlMensioning of strings, COMAL reserves space in memory for the full number of bytes requested. Thus "DIM ADDRESS$ OF 1000" would reserve the full 1000 bytes of memory (plus some for the name and pointers) for the variable ADDRESS$, rendering that space unusable by any other variable. Recall that BASIC, in contrast, simply reserves a few bytes for the name (AD$ is all it can keep) and pointers, then claims additional speed as it is required. Though space is not wasted, the disadvantages with BASIC's technique are its speed (COMAL is over 79 times as fast in some string manipulations), its need for garbage collection (sometimes requiring several minutes to reclaim lost space), and its possibility of run-time errors ("OUT OF MEMORY ERROR IN 1230"). Likewise, when DlMensioning arrays ("DIM RANGE(-5:5,1:25)"), use only the indices needed; more will rob you of potentially valuable space.
In BASIC, procedures (subroutines) are nameless creatures, identified only by their chance line number, and cannot receive parameters; functions are paltry one-line expressions identified by one letter and capable of handling only one true parameter and no decision logic. Both are consequently difficult to use and are avoided by legions of BASIC programmers. COMAL, in contrast, allows meaningful names to be assigned, parameters (even arrays) to be passed, and complex branching to be performed in both procedures and functions. This eliminates the need for the common variable reassignment necessary for most BASIC subroutines (eg. Xl=L: X2=BR: T%=3: GOSUB 4250: IM=X4: REM SET UP VARIABLES AND INTERPOLATE). The use of procedures and functions not only eases the task of programming and debugging while making your code easier to read and understand, it also saves considerable space by not requiring you to repeat blocks of similar code. And the set-up required in BASIC is not needed in COMAL, simply call the procedure or function with the variable you need (eg. INTERMEDIATE := INTERPOLATE(LOW, HIGH, ACCURACY) ). And each procedure or function call takes only one byte, plus the parameters. Long variable names also take only one byte whenever used in a program, regardless of how long the name is. And the future is even brighter; the cartridge version of COMAL, in addition to freeing far more of the machine's memory, will allow external procedures to be called in from disk as needed and discarded from memory when they complete execution. (The "future " is now here; the COMAL cartridge is available. See the "All about COMAL" article in this issue - TEd)
Those of you who have been using COMAL for graphics applications are aware that there is no comparison with BASIC when considering the space required to use the 64's graphics abilities. BASIC needs confusing, tedious, and spacious strings of POKEs buried in FOR NEXT loops, while COMAL is content with simple keywords like FORWARD, LEFT, DRAWTO, and PLOT. Sprites, too, can be defined, moved, manipulated, and detected with clear COMAL statements such as HIDESPRITE, PRIORITY, SPRITEPOS, etc. Again, BASIC programmers are mired in a series of PEEKs and POKEs, ideally peppered generously with copious REMarks (and each COMAL keyword takes up only one byte each time used). Plus COMAL has reserved space for your graphics screens and sprite images right from the start. BASIC does not, forcing you to allocate it from within your program, losing about 4k. In addition, sound commands are available on the COMAL cartridge, but you can write your own sound procedures for the disk-based COMAL and easily create music and sound effects. The best that can be hoped for with BASIC is repeated code or a series of GOSUBs. The use of all these features can save considerable memory over an equivalent BASIC program.
Common structures in BASIC require a copious amount of space. The decision structure, for example in this menu option acceptance routine, is a series of:
IF(Q$ = " A " 0RQ$ = " a " 0RQ$ = " 1 " )THEN GOSUB1000:GOT0999
IF(Q$ = " C " 0RQ$ = " c " 0RQ$ = " 2 " )THEN GOSUB1200:GOT0999
IF(Q$ = " D " 0RQ$ = " d " 0RQ$ = " 3 " )THEN GOSUB1450:GOT0999
ER=3:GOSUB 2280
COMAL, however, allows a simple CASE statement:
CASE RESPONSE$ OF
WHEN "A", "a", " 1 "
ADD
WHEN "C", "c", "2"
CHANGE
WHEN "D", "d", "3"
DELETE
OTHERWISE
SIGNAL'ERROR(3)
ENDCASE
Besides being simple and non line-number oriented, COMAL is able to save the programmer significant amounts of space with such programming. In this example the difference is a savings of 59 bytes; BASIC would require 55% more space. Other structures which save bytes by eliminating hard-coded IF tests and subsequent complex branching are the ELIF and ELSE options of IF, together with WHILE and REPEAT UNTIL structures.
Other built-in features, if used properly, can also save bytes. The
random number generator will provide you with integers within a specified
range if you so desire, freeing you from the steps of multiplying by a
range, adding one, and truncating (SHAKE: = RND(1,6) will assign the variable
SHAKE with an integer between I and 6 inclusive). The ZONE command
and PRINT USING will help you format a screen or printed page with far
less character counting (and fuss) than the fixed zones found in BASIC.
Another feature which saves space by eliminating a couple of IF THEN GOTOs
on ST is the EOF system variable, which becomes TRUE (1) at the end of
sequential files. Coupled with the UNTIL loop structure, it will save you
not only space but also heartache. COMAL has other similar features which
make programming not only compact but also quite straightforward. Further,
such techniques are so clear that programs are easier to read without requiring
nearly so much memory for REMarks - though do not neglect to comment (//)
even your COMAL programs.
A technique I would recommend if you work with large amounts of data is to design your programs such that not all of the data are resident in the computer at any given time. A mailing list, for example, would not exist in an array in the machine, but would be on disk in a random access file. You might keep the index (key) values, or at least their sequence, in memory for faster access, however. Then you'd need only one name and address resident at any given time; updates can be done on an individual record basis. Another example might be statistical calculations on large sample populations. Thousands of values could be on the disk in a sequential file, and you might read through them, summing samples, squares, cross-products, etc., retaining only those sums in memory. After a pass or two through the file, you'd have everything you need for all kinds of statistical calculations, yet very little need be kept in memory at once.
The time may come, despite all of the above-mentioned techniques, that you'll find yourself hemmed in by the 10k limit imposed by the disk-loaded version of COMAL. Are you doomed to return to programming in BASIC? Not at all. Your program and data size can be up to whatever you have available on disk(s), at least 170k. This is accomplished through a memory management technique known as over- lays. All that is required is that the currently executing program prepare any data necessary for the next program, then CHAIN the new program into the computer. This eliminates the program that did the CHAINing, and passes control of the system to the beginning of the new program. For example, a program called COMPUTE'MEANS could finish its task, and end up with a statement CHAIN " DO.DELTA.SQ" which would effectively LOAD the program DO.DELTA.SQ from disk and begin its execution.
This CHAINing technique is particularly easy to implement in a menu-driven system with clearly distinguishable subtasks. The menu programs need only display a menu on the screen and ask for a response through a GET or INPUT statement. The rest of the program might then say
REPEAT
CASE RESPONSE$ OF
WHEN " I"
CHAIN " INPUT'ROUTINE"
WHEN " F"
CHAIN " FIX'DATA'ROUTINE "
WHEN " C "
CHAIN " SCRATCH'FILE "
OTHERWISE
INPUT " Enter I, F, C or S: ": RESPONSE$
ENDCASE
UNTIL RESPONSE$ IN " IFCS"
Each CHAINed program would end with CHAIN " MASTER- 'MENU "
There is a potential problem with this chaining technique: it resets all user variables and DIM statements. At times this makes communication between CHAINed programs some- what difficult. Three techniques are fairly easy to use.
The first is simply to find some unused bytes in a safe place in memory (the home of an unused sprite is often handy) and POKE the values necessary into this sequence of bytes. This is quick and easy for small amounts of data, does not change the screen, and causes no l/O delays.
The second technique is to use the screen. You can either POKE to the screen as above, or you can PRINT to the screen, using cursor controls for positioning if needed. If you don't want the information seen, simply make your pencolour the same as the background colour; the information will be there, but will be hidden. The alternative, of course, is to make the information seen, making sure you put things where they'll look good. Here, getting the data back can be quite interesting. Of course you still have the alternative of PEEKing at what you want, but there's a far more enjoyable way. You can OPEN the screen (device 3) as an input file, then INPUT directly from the screen after positioning the cursor. This input from the screen technique is explained in the COMAL HANDBOOK, first edition, page 204 (UNIT) and 123 (OPEN), and in the first issue of COMAL TODAY newsletter. What happens is that COMAL treats the screen as a sequential file, with each line seen as a record. You merely INPUT FILE from the screen, getting any information you need.
A third technique for passing data between CHAINed programs is to use intermediate storage. The CHAINing program could OPEN a disk file, WRITE its parameters to that file, CLOSE the file, then CHAIN the next program. The CHAINed program, for its part, would DlMension whatever were necessary, OPEN the parameter file, READ the parameters, CLOSE the file, and perhaps even scratch (DELETE) it. Then it would get down to business as usual. This method has the least of the kludge in it, but requires some time consuming l/O. As always, there's a trade-off.
As I admitted in the beginning of this article, there are applications
for which 10k of user memory will be insufficient. But several techniques
have been presented which should help you pare down the size of your programs,
and, if necessary, overlay them with others. Though there is some cost
involved in the careful planning and space conscious programming of a COMAL
program, I find it far more pleasant and far less time-consuming than programming
in BASIC, despite the latter's 38k available.