Classic Computer Magazine Archive COMPUTE! ISSUE 67 / DECEMBER 1985 / PAGE 114

Commodore Program Chaining

Orlando Lee Stevenson

Take advantage of Commodore's automatic chaining feature to link two or more BASIC programs together. The method illustrated here applies to all Commodore computers.

Program chaining is a method of linking separate programs together, making them run, in effect, as one large program. Why would you need to chain? Some BASIC programs simply grow too large to fit into memory: Chaining lets you break them into two or more program modules that work together as one. This method also lets you interconnect an entire group of programs, moving from one to another whenever you like.

LOAD In Program Mode

Let's say you have two programs you want to chain together. The solution can be as simple as placing LOAD "PROGRAM NAME",8 (disk) or LOAD "PROGRAM NAME" (tape) in place of an END statement. In Commodore BASIC, a LOAD command executed as part of a program automatically loads and runs the specified program. If the programs are completely unrelated, nothing more needs to be done.

However, if the programs are related, you'll probably want to pass variable values from one to the other as well—a procedure that requires some care. On all Commodore computers except the 128, variables and arrays are stored in memory immediately following the end of BASIC program text. Since different programs are of different lengths, the actual location of variables depends on the length of the program. The computer uses two-byte address pointers to keep track of where everything is stored, and updates the pointers as needed while the program runs. When you perform LOAD in program mode, the computer does not reset the pointers for variables, arrays, and strings. Thus, after it loads a second program, the computer still knows how to find and use all of the first program's variables.

The success of this procedure depends on the relative length of the chained programs. If the first program is longer than the second, all is well: When the second program loads in, its shorter program text doesn't extend as far as the area where variables are stored. (Remember, the first program's variables are still located in the same place). However, if the first program is shorter than the second, you have trouble. When the second program loads, its longer text overwrites the variables. Though the pointers still point to the right area, the variable data which used to be there has been replaced with program lines. Once that happens, the variables are lost.

This is not a problem with BASIC 7.0 on the Commodore 128, because it keeps variables in a separate 64K bank of memory. Thus, 128 programs can be chained freely without worrying about overwriting variables, and all the following discussion about preserving variables does not apply. However, you should still read the section entitled "Chain with Care." And don't forget that variables will be overwritten if you're running the 128 in 64 mode, just as they would be on a 64.

Changing The Signposts

The easiest solution is to make sure the first program in a chain is longer than all the rest. However, in many cases the first program in a chain is quite short. It may be a menu program—one that simply lets you choose among several programs to load and run.

Fortunately, there's an answer. By resetting the first program's pointers, you can make it store variables in an area that won't be disrupted by following programs in the chain. Here are the steps to follow (you can use any BASIC programs to practice this technique):

  1. First, find the length of every program in the chain. Load the program and type the appropriate line below in direct mode (without a line number), then press RETURN.
  2. For the VIC, 64,128 in 64 mode, Plus/4, and 16:

    PRINT PEEK(45) + PEEK(46) * 256
    

    For PET/CBM (Upgrade and 4.0 BASIC):

    PRINT PEEK(42) + PEEK(43) * 256
    
    This number is the location where the program's text ends and its variable storage begins. Write down the end-of-text number and note which program it belongs to, then repeat for every program in the chain.
  3. Scan the list of numbers to find the longest program: It's the one with the highest end-of-text number. Now reload that program and find the contents of the two addresses you PEEKed above. For the VIC, 64, Plus/4, or 16, type PRINT PEEK (45),PEEK(46) in direct mode; substitute the proper addresses if you are using a PET/CBM. Two numbers are printed. These are the actual pointer values for the longest program. Write them down, labeling the first number LO and the second HI. You now know the lowest safe storage address for variables in this chain.
  4. Reload the first program in the chain. Do not run it or enter any direct mode statements that would create variables. Enter the following lines, replacing LO and HI with the numbers you recorded in step 2. For instance, if LO is 20 and HI is 9, you would type the first line as POKE 45,20:POKE 46, 9 + 1. Don't forget to press RETURN after each line.
  5. For the VIC, 64, Plus/4, and 16:

    POKE 42,LO:POKE 43,HI + 1
    POKE 44,LO:POKE 45,HI + 1
    POKE 46,LO:POKE 47,HI + 1
    
  6. Finally, resave this program. Do not delete the original version (see explanation below). Step 3 sets the first program's end-of-text and variable pointers to an address 256 bytes above the end of the longest program (the extra bytes provide a margin for error). Though it artificially increases the length of the first program, this method lets you run the entire package without losing variables.

Chain With Care

This method of program chaining has limitations. User-defined functions—created with DEF FN()—cannot be passed at all, since their definitions are stored in program text, not as variables. Such functions must be redefined in every program that uses them.

Strings may cause problems as well. In the VIC, 64, and PET/CBM versions of BASIC dynamic strings (which result from a string operation such as A$ = "HELLO" + B$) are stored outside the program text, they can be passed like other variables. The same is not true of static strings. Like a function definition, a static string exists only in a program line (10 A$ = "HELLO"). If you need to pass a static string, simply add a null string to it (for instance, replace 10 A$ = "HELLO" with 10 A$= "HELLO" + ""). The string operation (+) turns it into a dynamic string, storing it outside the program. This is not a problem in the 128, Plus/4, and 16 versions of BASIC, where all strings are effectively dynamic.

Be careful when editing chained programs. If you lengthen a program, it may become the longest one in the chain and overwrite variables when it loads. Do not edit and resave a program after breaking out with RUN/STOP (since the pointers are set at artificially high locations, the program's length is abnormal). Instead, reload the program to set the pointers correctly, then make the changes and save it again. Whenever you edit any of the programs in the chain, you should also repeat steps 1-4, using the original version of the first program. It's critical that you know the true length of this program, not the inflated length it was given in steps 3 and 4.

There are other ways to pass variables while chaining, but they're inevitably cumbersome. One approach is to store variable data in a separate memory area while one program loads another. For instance, say that A = 10. Just before the first program loads the second, it POKEs the value of A into a safe memory location (say, 49152 for the Commodore 64). The first thing the second program does is retrieve A's value with a statement like A = PEEK(49152). Since a single memory location can hold only a number from 0-255, it requires multiple POKEs and PEEKs to pass larger numeric values. Passing arrays, strings, or more complex numbers (negative values, for instance) takes even more work and ingenuity.