rwh@aesat.UUCP (Russ Herman) (09/25/85)
Abacus BASIC 64 (BASIC Compiler) Russell Herman (utzoo!aesat!rwh) (c) 1985 _I_n_t_r_o_d_u_c_t_i_o_n I'd been considering getting a BASIC compiler for awhile. When Abacus came through with a $10 off coupon after reducing the compiler's price to $39.95, that was sufficient to toggle my 'purchase' line. _I_n_i_t_i_a_l _I_m_p_r_e_s_s_i_o_n_s As usual (I've bought by mail from them before), Abacus ships promptly, and doesn't rip off Canadians by charging "foreign" postal rates. The package consists of the usual Abacus binder and diskette. Checking over the registration card and seeing the $10 fee for a backup copy (a bit high for a $29.95 net product), I grab my trusty nibble copier and make my own. Uh-oh, won't load. This one belongs in the "heavily protected" category. Glancing at the title page, I notice that the copyright is held by Data Becker GMBH. They're the German outfit that supplies the _Anatomy of ..._ books (and others) that Abacus distributes in N. America. So the next thing to do is to boot up the program, and give it a try on one of the simple programs I've written, an _I CHING_ tosser, which "tosses the coins" and displays the two resulting hexagrams. Up comes the menu with a choice of compiler 1, compiler 2, adv. devel. system, and overlay generator. Leafing through the documentation, I see that the difference between compiler 1 and compiler 2 is that the latter is, in effect, an integer BASIC for higher efficiency. Well, that's just what I want. So I pump the program through the compiler and ... TYPE MISMATCH ... Try to stop the thing when the error message pops up, but no, grind, grind, grind, through all of pass 1 and pass 2. Finally I get back to a menu, and, NO WAY to LIST the program. Sigh. Reset the machine. Look at the offending lines FOR I=somethingTOsomethingSTEPsomething nothing wrong with that. Back to the manual. Aha! Here it is, mentioned in passing. To improve efficiency in the integer compiler, STEP is disallowed. If you need it, do the increment-and-test yourself. Oh, well. There goes the one bit of structuredness that BASIC has. So after rewriting the two lines, reload the compiler (another two minutes staring at the threat screen), turn on the ML output toggle this time. Reset the machine, load the program (now 42 blocks instead of 12), and voila! an observable, but unmeasurable, speed improvement. Whereas the BASIC version took a few hundred milliseconds to fill the screen, now it appears to be blinking the entire screenful up instantaneously. Thus heartened, now off to read the manual. _F_u_r_t_h_e_r _T_e_s_t_i_n_g The manual is terse, but appears complete. It describes options of the advanced development screen, and some REM@ toggles that allow setting some of the same compiler features. You can raise the bottom and lower the top of your program, declare variables as float for the integer BASIC compiler, access features of some BASIC extensions (most of SIMON's, some of MASTER-64). What they call "overlays" is little more than one program loading another, although only string variables get clobbered. The requirement that the first-loaded program be the largest still carries on. You can move the location of the symbol table (normally in the casette buffer). You can turn on the line-number/machine address listing option, needed since runtime errors give a machine address instead of a BASIC line number. Symbol tables can be saved and reloaded for use with the overlay feature, which gives the feature of separate compilation units for each program. A clever feature is the ability to force a symbol to be an address so you can access the SID and VIC chips (or any location in memory above 368) just by accessing a named variable. I'm not going to use any of this interesting stuff just yet, though. Going to work on a REAL program this time: a disk T/S editor published by RUN Magazine and slightly hacked to do a better job of handling disk errors and disk-chain following. Each sector is displayed in 2 128-byte screens that you just cursor over to and change, and dumping out each screen takes 22 seconds, which seems like forever. So make a few changes to get rid of some unnecessary INT calls, compile and run, and now, *6* seconds per screen. Very nice. One more to try, a version of a PD disassembler that has been adapted to take code from disk or core, and write assembler input, source listing, or both. This one has lots of INT statements for generating lo-byte, hi-byte address, and an opcode table that is stored in an index*100+optype format. Make appropriate changes, including generating a temp for inline INTs, compile, and RUNTIME ERROR ... How to debug this thing now. Well, there's no way to look around at anything of compiled code once you're back in the interpreter. So it's insert PRINT statements, recompile, insert more PRINT statements, more recompiling ... this is pretty tedious. Finally I discover that a subroutine is being called with a negative value that is being used as an index into MID$. But how is that value being generated??? Only thing I can think of doing is coming up with a version of the program where the BASIC source can be run directly, as well as compiled. This means that whereas I was relying on the integer nature of the compiler, now I've got to modify the program to use % variables. So I do this (a BASIC xref program comes in REALLY handy here), verify under the interpreter, run a compiled version, and NO MORE PROBLEM. So, somewhere, lurking in the compiler, is at least one bug. Performance, by the way, is 30 seconds for a disassembly that requires nearly 2 minutes in the interpreted version. Now for the hairiest test of them all - a primitive terminal program. Set up the menu parameters specified in the manual for RS-232 programs, compile, and try it out at 300 baud. Program hangs. Finally trace it down to within the GET# reading the port. Well, here I'm stuck. No way to determine what's going on inside. In desperation, I give Abacus a call; they DO advertise customer support for this product, and am quickly connected to someone who see the info on a certain manual page. I do, and unfortunately, it conflicts with the information on another manual page, but I'll try it anyway. Finally, after trying a number of combinatorials of changing the compiler's top of program, as well as FRETOP, MEMSIZ, and MEMTOP, it runs. No 1200 baud modem to *really* test it with, though. _C_o_n_c_l_u_s_i_o_n_s Not perfect, but certainly a winner. For complex programs accessing disk and doing extensive string manipulation, expect around 4X performance improvement. This is, of course, for the integer-BASIC compiled version. What the gains would be for programs making heavy use of floating point, trig functions, etc. I don't know, but since the native BASIC ROM routines are invoked, I wouldn't expect too much. You'd better thoroughly debug an interpreted BASIC version of the program before you compile it, or you're going to have a devil of a time trying to figure out what went wrong with only the machine address equivalent of the offending line as debugging info (table converting this to line number optionally available from the compilation phase). Documentation leaves something to be desired, but what else is new. The paranoia about protecting the compiler is annoying, as you have to reset the machine to get out of it. Compiled code can't be CONTed after STOPping either. On examination, the compiled code isn't very compiled: it's entirely a string of parameter setups and calls to the (3K) runtime package. Reminds me a mainframe COBOL I used to know. But the main thing is the achievement of very significant performance gains from running compiled versions. -- ______ Russ Herman / \ {allegra,ihnp4,linus,decvax}!utzoo!aesat!rwh @( ? ? )@ ( || ) The opinions above are strictly personal, and ( \__/ ) do not reflect those of my employer (or even \____/ possibly myself an hour from now.)