BASIC

VirtualGS Book Now Available in iTunes Book Store

T. C. Lim has been working on a book about Pascal programming for the Apple II gs for the past several weeks, releasing preliminary versions along the way.  The book includes a number of programs his kids have developed for the Apple IIgs in Pascal, Orca Pascal, and GSoft BASIC.

The book was produced with iBooks Author and is the first Apple ][ series related book to be produced specifically for iBooks 2.0.  T.C. has announced the immediate availability of the VirtualGS book in the Apple iTunes Book Store.

VirtualGS for iBooks 2.0 is a free download.  To get your copy, go to:

http://itunes.apple.com/book/virtual-gs/id498416459?mt=11

Write Applesoft Basic in Virtual Basic

A new way of writing Applesoft Basic programs has been created by Andres Lozano, known in the Apple ][ world as Loz.  Virtual Basic is a complete BASIC with all of the same operators and commands as Applesoft, except that it is written in a style much like other high level languages of the modern era.

The entire system for Virtual Basic is a series of python scripts.   If you are writing Virtual Basic programs, they can written using an external editor such as Textedit or Espresso.   The Virtual Basic website has a complete Virtual Basic to Applesoft converter so you can write your Apple ][ program in Virtual Basic and drop the converted program right into an emulator or onto an actual Apple ][. The Virtual Basic Reference Manual and everything you need is on the site and all of the scripts are free to download, modify and even re-distribute under the copyleft status (Free Art License) of the program.

Examples, manual, and converter is available on the website at http://virtualbasic.org/

Three Ideas: Handy Tools for Business BASIC

Text by Dave. Lingwood
Programs by Brian Matthews (Action-Research NW)

BASIC COMPARISONS
Most Apple /// Business BASIC users also work with Applesoft, either from earlier ][ days, or through emulation mode. Business BASIC (hereafter “BB”) has all the professional features you need, but it lacks the flexibility provided by the openness of the ][. This article and attached programs recount some of the pitfalls we encountered and useful tricks devised in transferring a large statistical analysis package from Applesoft to BB. The tricks add back some of the flexibility of Applesoft.

1: ARRAY HANDLING AND REQUEST.INV
If you haven’t already discovered it, REQUEST.INV, provided with BB, contains very useful routines for rapid reading and saving of numeric data arrays. They are FILREAD and FILWRITE. FILREAD/FILWRITE do a read or save directly into/from a vector. The data are saved as a binary file on the disk. The PERFORM command tells the invokable the name of the array or vector, the file name, and the number of bytes to transfer. Let’s assume you have an array DIMensioned as DD%(N) which contains data you want to save save to disk, then re-fill with other data on the disk. Here are the appropriate BB statements to do it:
10 INVOKE”request.inv”:REM at beginning of program
20 DIM RW$(1): RW$(0)= “Read”: RW$(1)= “Writ”
100 filename$= “dataout”: RW= 1: REM write data
110 GOSUB 1000
200 filename$= “datain” RW= 0: REM read data
210 GOSUB 1000
1000 REM Subroutine for array read/write. RW=0 to read, =1 to write
1010 PRINT RW$(RW); “ing array DD%”
1020 nbytes%= (N+1) * 2:REM 2 since integer array
1030 datafile%= filenumb: REM # of data file
1040 DD$= “DD%”: REM name of array to transfer
1050 OPEN#datafile%,filename$
1060 IF RW THEN PERFORM FILWRITE(%datafile%,@DD$,%nbytes%)
1070 IF NOT RW THEN PERFORM FILREAD(%datafile%,@DD$,%nbytes%,@count%): IF nbytes%<>count% THEN PRINT “Err: Read file <> array length!”
1080 CLOSE#datafile%
1090 RETURN

The RW variable controls reading or writing. DD$ is the important value passed to FILREAD or FILWRITE which tells it the name of the array to find in memory, and from the beginning (0th cell) of which to begin reading or writing “nbytes%” bytes. The “count%” variable is returned after a read, containing the number of bytes actually read. The IF test after the read checks that this figure agrees with the number of bytes in the array (though you might want to read fewer bytes into an array, you should never read more!).

You could even put the names of various arrays into a string array, then assign DD$=ARRAY$(k), for example, or pass the array name into the subroutine as a parameter. There is a lot of flexibility here, and more importantly, a lot of SPEED. Data transfer is much faster than with INPUT/PRINT.

2: DIMENSIONS, STRINGS AND THE 256K ///
A problem we bumped into almost immediately with the stat package was the limit on array size, and the rule about string arrays in BB that affects the 256K machine.

Simply put:
a. No numeric array can be longer than 64K
b. Strings must be defined in the first 64K block of program memory.

The first, while a pain, you can live with by careful program design (especially with FILREAD/FILWRITE available). The second causes real speed problems if you have many string arrays. Being an interpreter, BB has to scan through the list of all arrays to find the one you want. Normally you’d define your fast numeric arrays first; but if your numeric array is a full 64K in size, that would force any string arrays subsequently defined to cross into the second 64K block, generating an error that is not mentioned anywhere handy:

Error code 21!
Variable/memory error
Again, it means you’ve accessed a string that crosses the block boundary on a 256K machine. It brings the program to a screeching halt! Once you know this, the cure is to dimension all the strings first. Uhg. Speed tumbles as the program wades through all the string arrays to find the numerics. The solution we came up with, though a bother, was to dimension just one string array, then store all the various command lists, etc., in it, using an offset variable to find the “base” of each list.

For example, if we had 10 commands, 6 options, and 20 error codes the master string array would look like this:

Cmdlist=0 strings cmdlist+1—cmdlist+10 are commands
Optlist=10 “ optlist+1—optlist+6 “ options
Errlist=16 “ errlist+1—errlist+20 “ error messages

What a classic pain. But, it works.

3: BLOAD+BSAVE+PEEK+POKE = PROGRAM OVERLAY
A heck of an equation. Why resurrect these commands we thought the superior design of the /// made unnecessary? The answer lies in the heart of our program design, and is related to disk space and speed.

The AIDA statistical package consists of a chunk of common code that is always used to process commands, read and save data, etc., plus specific code that is used depending on which command the user gives. The traditional way to handle this is to have a main “menu” program chain various separate programs depending on which command is given. The trouble with this is that the common code has to exist in each chained program. That means longer read time and disk space wasted through duplication of that code.

The ][ version already had solved this by inventing program overlay (see “Call-A.P.P.L.E.,” Nov., 1980). The various command-specific program segments were saved as binary files, then BLOADed quickly right into the middle of the running program, which never knew what had hit it. When we converted to the ///, the improved CHAIN was faster than would have been the case on the ][, but there just wasn’t enough disk space for the program!

Back to the drawingboard. The way overlay worked on the ][ was to find the RAM address of one line of the program: a simple subroutine peeked the Applesoft zero page locations containing the current line pointer — in effect the one-line subroutine found its own address in memory.

Then the code was BLOADed, the only trick being that each “module” so loaded must be shorter than the original “back end” of the program, so as not to overwrite the data.

Brian began to dig around in memory, and added a lot to what we had previously known about reserved locations in BB. Once he found the statement pointer he was able to create the needed “overlay” statements by peeking the counter, then BLOADing the module to that point — after creating PEEK, POKE, BLOAD, and BSAVE, of course!

First, let’s describe those four new commands, which are useful in their own right. Later we’ll combine them into the form needed for program overlay.

Peeking and Poking
Peek and Poke are defined in the AIDA.TOOLS invokable. Both routines are set up to peek or poke one- or two-byte values, and to use the “extend byte” for the RAM banks. The syntax is:

x = exfn%.peek(%address,%xtend,%length)
PERFORM poke(%address,%xtend,@VALUE%,%length)
where: address = address of low byte (0-65535)
xtend = extend byte (0-3)
length = 0 for onebyte, 1 for 2-byte
VALUE% = value to poke

For example:
VALUE%= exfn%.peek(%61,%0,%1)
VALUE%= VALUE% + 512: PERFORM poke(%61,%0,@VALUE%,%1)

The peek will set variable “VALUE%” equal to the two-byte data found at locations 61 (low byte) and 62 (high byte) decimal in the “true” (xtend=0) zero page. The poke will poke the two-byte value contained in “VALUE%” into 61 and 62. This would add 512 bytes onto the BB end of program pointer (clobbering variables, by the way). Careful: poking in particular assumes that you know WHAT you’re poking, and why. The list of zero-page and other BB locations found elsewhere on this disk provides valuable guidance.

Bload and Bsave
The syntax for these commands, set up as invokables, looks like this:
PERFORM bsave(@filename$,%address,%xtend,@savelength%)
PERFORM bload(@filename$,%address,%xtend,@foundlength%)

Before BSAVE the number of bytes to be written must be stored in the “savelentth%” variable. After a BLOAD this same variable will contain the number of bytes actually read from the disk.

All four of these commands are contained in the AIDA.TOOLS invokable described at the end of this article.

Overlay
This technique lets you break long programs into shorter pieces, where you don’t want to have to re-read (as with chain) extensive common code. The program must be laid out like this:

Common code (low line numbers)
Transition subroutine (finds its own RAM address)
Overlay “module” (high line numbers)

When the program is first loaded and run, initialization or startup code is contained in the overlay area. This initialization code MUST be longer than any later module will be, even if you must pad it out with long REM statements. Later this initialization code will be overwritten with the binary modules successively BLOADed.

There are a few other rules for writing the initialization code, based on the obvious fact that those lines of the program aren’t going to be there later. They are: a) no function statements may be defined there, no ONERR or ONEOF statements may be defined or have their destination there,  b) no common or module code may refer to any line number here after the first BLOAD, and c) any string assignments must force the string contents out of the program and into normal string storage. The approach below will do the latter:

READ A$: TITLE$= A$ + “”
B$= “This is a string” + “”

The string concatenation forces BB to move the string out of the program area. Any other string function, such as MID$, could also be used. In our program, the common code runs through line number 997. Line 998 is the transition subroutine, and code just above that point does the actual overlay. Each proto-module is created as a BB program. You may choose to write it following the common code to permit testing.

When ready to save the module as a binary module, SAVE the program first, then EXEC the following text file:

DEL 1, 998: REM Remember, modules can’t have these low line numbers
800 INPUT “MODULE NAME TO SAVE? “;A$: FILE$= “MODULE.”+A$
810 GOSUB 998: last%=exfn%.peek(%61,%0,%1): len%=last% - addr%
820 PERFORM bsave(@FILE$,%addr%,%xtend%,@len%)
830 PRINT FILE$;” contains “;len%;” bytes.”: END
998 addr%=exfn%.peek(%79,%0,%1): xtend%=exfn%.peek(%5712,%0,%0): addr%=addr%+exfn%.peek(%addr+1,%xtend,0): RETURN
RUN

Line 998 calculates the address of the line following it. The peek in line 810 reads the BB end of program pointer. Thus, each module will begin at the line following 998, and the length written is (as calculated in variable “len%”) the number of bytes between this point and the end of the program. In BB it does not matter (as it emphatically does in Applesoft) that the common code be in memory, and always of the same length, when the binary files are written or read. This is because BB uses relative next line pointers. That is, each line of BB code begins with a two-byte pointer containing the number of bytes to add to the line pointer in order to find the next line. In Applesoft this pointer contains the absolute address of the next line. The happy result of this design improvement in BB is that you may modify the common code to your heart’s content after the modules have been saved.

It is a help if the actual execution code in each module begins with the same line number. The common code can then execute that module by a simple GOSUB 1000, or whatever. If more than one command is contained in a module, then you’ll have to keep track of the beginning line numbers of each command, and use an ON k GOSUB ln1,ln2...,ln3 statement. Of course, you also have to know the name of the module in which each command was BSAVEd, and when a command is given by the user, BLOAD that module if it is not now present.

The module code must follow the rules given for the initialization code, above: no embedded strings that are used outside of the module, and no lines or functions called by other modules. The code to load in a module is similar to that above:

800 PRINT”LOADING MODULE “;A$: FILE$= “MODULE.”+A$
810 GOSUB 998
820 PERFORM bload(@FILE$,%addr,%xtend,@len%)
830 RETURN
998 addr%=exfn%.peek(%79,%0,%1): xtend%=exfn%.peek(%5712,%0,%0): addr%=addr%+exfn%.peek(%addr+1,%xtend,0): RETURN

When ready to load a module, GOSUB 800 with A$ equal to the last portion of the module file’s name. Then GOTO or GOSUB to the code in that module. In use, the modules load very quickly, and of course, there is much less space taken up by the program code. Try it.

THE AIDA.TOOLS INVOKABLE The assembler source code for AIDA.TOOLS is found in another file on this disk. The ready-to-use invokable is in its own file elsewhere on this disk. Note that the authors have provided AIDA.TOOLS for the individual use of our readers. Commercial rights are, however, reserved.

/// /// ///

Author Bibliograhies: Dave Lingwood sports the checkered career typical of many in microcomputing: a background in English and Journalism, PhD in Communication Research, and R & D work in technology transfer and marketing, before forming his own software/information service company. He is also Secretary of A.P.P.L.E..

Brian Matthews was one of the first Seattle /// devotees; and he is, as this disk goes to press (drive?), the proud holder of a new Computer Science B.S. from the U of Washington, which he is applying these days for the benefit of Motorola.

The Program They Said Couldn’t Be Written

The Aldrich brothers strike again.  Remember, folks, you read it first in Call-A.P.P.L.E..  “Convert”, by Ron Aldrich using the disk, will create a text file from an Integer BASIC program listing, call Applesoft, and presto, your program has been converted.   After Conversion, list it out and note all the lines that need to be changed to conform to the Applesoft format.

This means that the Integer commands that are not compatible with Applesoft must be changed.  For example:  TAB must be changed to HTAB and commas in INPUT statements must be changed to semicolons, etc.  The program listing is show below:

o REM “CONVERT” BY RON ALDRICH
1 REM PROGRAM LOADS INTEGER BASIC PROGRAM FROM DISK, SAVES TO A TEXT FILE ON DISK
2 REM THEN EXECUTES THAT FILE IN APPLESOFT
3 REM SOME COHMANDS WHICH ARE LEGAL IN INTEGER BASIC WILL NOT WORK IN APPLESOFT II (TAB,INPUT ••• )
10 POKE 76, PEEK (202): POKE 77, PEEK(203 )
20 DIM A$( 35 ):D$=”" : REM D$=”( CTRL) D”
30 PRINT D$;”NOMON C,I,O”
40 TEXT: CALL -936: VTAB 3: PRINT “A.P.P.L.E. PRESENTS:”: PRINT: PRINT “APPLE INTEGER BASIC – APPLESOFT II” : PRINT “CONVERSION PROGRAM”
50 PRINT: PRINT: INPUT “PROGRAM TO BE CONVERTED ?”,A$
60 PRINT D$;”LOAD “;A$
65 PRINT DS
70 POKE 33,33
80 PRINT D$;”OPEN “;A$;”FILE”: PRINT OS; -WRITE • ;A$; MFILEM
90 LIST
100 PRINT D$;”CLOSE “;A$;”FILE”
105 PRINT D$
110 PRINT D$;”OPEN I-A FILE”: PRINT D$;”WRITE I-A FILE”: PRINT “FP”: PRINT “EXEC “;A$;”FILE”
120 PRINT D$;”CLOSE I-A FILE” : PRINT D$;”EXEC I-A FILE”
130 END

WELL, RANDY???

A Disk Utility Program

By Val J. Golding

Perhaps this may be the first disk program published for Apple’s new Disk II. If so, a feather for our cap! The “SAVE” program, listed in column two will ask the user to input the file names of six disk programs, start recording on tape and hit return. SAVE will then consecutively load from disk and save to tape, in one operation, the six named programs. A neat way to make a tape for a friend from your disk collection.

Since this program uses the Basic SAVE command under program control, it is necessary to enter the SAVE commands as something else and then go into memory and change them to SAVEs. If you don’t know how to do this, here is another routine that will do it for you. Just substitute the command TEXT where you see SAVE in the program and then add lines 1100 to 1250 as given below and RUN 1100. This will convert the TEXT commands to SAVE. After this has run, you can DELete 1100 to 1250, as they are no longer required.

This routine can be modified to change any token or ASCII character in memory to another one, and of course, the program SAVE can be modified to save however many programs you would like in one operation by adding or taking away input statements and SAVE and LOAD statements.

Remember in line 1000, Z$=”Dc”. A Control D must be within the quotes for the DOS to recognize a Disk command.

>LIST
10 REM “SAVE” BY VAL GOLDING 7/23/78
20 REM THIS PROGRAM SAVES 6 NAMED DISK FILES TO TAPE IN ONE OPERATION
50 GOTO 1000
60 POKE 0, PEEK (76): POKE 1, PEEK (77 )
70 POKE 76, PEEK (202): POKE 77, PEEK (203)
90 PRINT Z$;”LOAD “;A$
100 SAVE
180 PRINT Z$
190 PRINT Z$;”LOAD “;B$
200 SAVE
280 PRINT Z$
290 PRINT Z$;”LOAD “;C$
300 SAVE
380 PRINT Z$
390 PRINT Z$;”LOAD “;D$
400 SAVE
480 PRINT Z$
490 PRINT Z$;”LOAD “;E$
500 SAVE
580 PRINT Z$
590 PRINT Z$;”LOAD “;F$
600 SAVE
649 REM INSERT 6 CONTROL G WITHIN QUOTES
650 CALL -936: VTAB 10: TAB 10: PRINT “FILES SAVED TO TAPE”
700 POKE 202, PEEK (76): POKE 203, PEEK (77): POKE 76, PEEK (0): POKE 77, PEEK (1): END
999 REM INSERT CONTROL D WITHIN QUOTES
1000 DIM A$( 36 ), B$( 36), C$( 36 ),D$( 36 ), E$(36),F$(36):Z$=”"
1010 TEXT : CALL -936: VTAB 4
1020 INPUT” FILE NAME? “,A$
1030 INPUT” FILE NAME? “,B$
1040 INPUT” FILE NAME? “,C$
1050 INPUT” FILE NAME? “,D$
1060 INPUT” FILE NAME? “,E$
1070 INPUT” FILE NAME? “,F$
1080 VTAB 20: PRINT “START RECORDING AND HIT RETURN TO SAVE THE ABOVE LISTED FILES TO TAPE”: CALL -676
1090 GOTO 60

1100 REM PRGM TO CHANGE TOKENS IN MEMORY
1150 REM EN=MEMORY RANGE TO BE SEARCHED
1200 LOCN= PEEK (202)+ PEEK (203)*256 :EN=LOCN+735
1210 REM PEEK AT VALUE OF ORIG TOKEN
1220 IF PEEK (lOCN)=75 THEN 1250:LOCN= LOCN+1: IF lOCN=EN THEN END: GOTO 1220
1240 REM POKE VALUE OF NEW TOKEN
1250 PRINT “CONVERTING “;LOCN: POKE LOCN,5: GOTO 1220

Program to Initialize a Diskette

100 CALL -93.6 :P RINT ” (insert your name, address and phone)”
200 PRINT “THIS DISK CONTAINS INTEGER BASIC PROGRAMS” (or game programs, etc.)
300 FOR 1=1 TO 1000:. NEXT I: CALL -936
400 PRINT “Dc CATALOG’:END
Note: In line 400 after the first quote, hit the Control key and the “D” key at the same time. This is how the disk system responds to commands within a Basic program, with Control D in a print statement.

A Patch For Double Loops

By Bob Huelsdonk

When inputting to a double loop by row, then jumping out to a double loop to total by column, it is necessary to revers the subscript order.

This will not work in Applesoft BASIC because the right counters do not reset.  The following simple example will demonstrate:

80 PRINT  “INPUT ‘-1′ TO TERMINATE INPUTS”
100 FOR R = 1 TO 3
120 FOR C = 1 TO 3
140 INPUT A(R,C)
160 IF A(R,C) = – 1 THEN 300
180 NEXT C
200 NEXT R
300 FOR C = 1 TO 3
320 FOR R = 1 TO 3
340 PRINT A(R,C)
360 NEXT R
380 NEXT C

If the following changes are made, this problem is overcome:

160 IF A(R,C)=-1 THEN 250
250 FOR R=0 TO 0 : NEXT R

The empty ‘R’ loop resets the counter.

Routine to Print Free Bytes

By Bob Huelsdonk

Only line 30001 is required for less than 32K of Memory.  The first GOTO 30000 shows result with  greater than 32K of Memory. The second GOTO 30000 shows the result with less than 32K of memory.

30000 IF PEEK (203)>128 THEN 30002
30001 PRINT PEEK (202)+ PEEK (203)*256- PEEK (204)- PEEK (205 )*256;” BYTES FREE”: END
30002 PRINT 32767-( PEEK (204)+ PEEK (205)*256);” BYTES + “; PEEK (202)+( PEEK< (203)-128)*256 +1;” BYTES FREE”: END

>GOTO 30000

30719 BYTES + 16226 BYTES FREE
>GOTO 30000

27193 BYTES FREE

Routine to find page length

This handy little subroutine can be used in two manners; to fill a screen page with repetitive material or to determine the length of a screen page of print statements. Assume line 100 is a print statement with which you wish to fill the page.

100 PRINT” “:GOSUB 400
400 IF PEEK(37) < 18 THEN RETURN
410 POP:PRINT “FOR NEW PAGE HIT ANY KEY”:CALL 756:GOTO 000

Line 400 reads the cursor and finds whereitis on the page. If less than 18 lines, print more lines. Line 410 “Pops” the return address from the stack. Instead of Call 756 you could use INPUT A$ or Call -676, all of which are a means of halting the program to await further instructions.

BASIC Programming Classes

Don Williams will be our instructor again for two levels of Integer Basic Programming classes available to our members.   Beginning and Intermediate classes will be available, with the beginning class starting sometime in August. Details will be available in the next issue of Call-A.P.P.L.E.