Building Blocks of Command Files
Even if you aren't yet aware of it, just by creating a command file, you have, in fact, become a programmer. As you become more familiar with the Shark language, you'll be writing longer and more complex command files, and you'll find the methods described in this section essential.
What Are Modules?
Modules are not just a set of commands, but an approach to programming in general. Basically, a module is any command sequence that performs a well-defined task. Modular programming is a technique that is used in Shark (among other computer languages) to create large and powerful command files by breaking the job into smaller components.
These component modules can then be linked so as to be executed in a "chain," one after another. Or they may be called into execution by commands in a "main" module: for example, you might have the individual modules linked to a single command file that creates a "main menu" to let the user decide which task (module) is to be performed.
There are several advantages to this approach:
Keep in mind that these modular techniques will serve you best if you consider their use at the planning stage—before you actually start writing your command file.
Besides making the command files themselves more efficient, these techniques will make you a more efficient programmer. By breaking a long and complex job into smaller, more easily understood modules, you can even collect a library of command-file tools that you can use in many applications.
Chains, Procedures, and Subroutines:
There are three kinds of modules in Shark programming:
Environment:
The term environment refers to the current arrangement of data files, variables and other settings in Shark internal memory—its "workspace." This arrangement includes all of the data files opened and the memory variables being used and the order in which they are defined.
The environment changes when any of the following actions is performed:
Modular Programming Commands:
Each of the three modular techniques we've mentioned - chaining, procedures, and subroutines - affects the environment (and is affected by it) in different ways. Each has its own advantages and restrictions, and you should be aware of these differences in choosing which kind of module to use.
Chaining Command Files:
CHAIN
Leaves the current command file and starts running another. CHAIN clears the environment and replaces the command file in memory (the calling file) with the command file named (the chained file). CHAIN does not, by itself, return to the original command file (compare DO, below) but you can subsequently chain any number of other command files, including the original, calling file. A command file can even be chained to itself in order to start over from the beginning.
Environment:
In starting a new command file, CHAIN clears the environment - that is, it closes all currently open data files and releases all memory variables. If you want to continue to use the same data files, you'll have to reopen them in the new, chained command file.
To "carry over" a set of memory variables from the calling command file to the chained file, use the GLOBAL command at the beginning of both command files.
The maximum size for a single command file that Shark can run is about 15 to 20 thousand characters (in its text form). Chaining a series of command files as modules is a good strategy for overcoming this restriction because each command file called into a chain runs independently, in its own environment. To run a command file that is larger than 15 to 20K, break it into smaller files and use CHAIN to run the smaller files one at a time.
Example:
Here's an example of a "main-menu" command file (named, appropriately enough, "mainmenu.prg") that uses chained files as modules:
ERASE TEXT What do you want to do? 0. Quit this program 1. General Ledger 2. Accounts Payable 3. Accounts Receivable 4. Report ENDTEXT ACCEPT "Enter choice (0 - 4)" TO answer DO CASE CASE answer = "0" CLS ? "Program ended. Returning to Conversational Shark" CANCEL CASE answer = "l" CHAIN ledger CASE answer = "2" CHAIN acctpay CASE answer = "3" CHAIN acctrec CASE answer = "4" CHAIN acctrpt OTHERWISE ? "Incorrect entry. Press any key to try again." ok = INKEY() CHAIN mainmenu ENDCASE CHAIN mainmenu
Note that EACH of the four separate chained command files (ledger, acctpay, acctrec, and acctrpt) is a separate module for our purposes.
By typing a number from 1 to 4, the user activates the corresponding CHAIN command to call into execution the appropriate module. Each command file clears the existing environment and establishes its own. An error in one command file doesn't affect any of the others. The individual command files needn't be present at compile-time. When the main-menu command file is executed, however, a CPL or PRG version of each chained filed must be present where Shark expects to find it (usually with a \PRG or \CPL directory/folder) if its corresponding menu option is chosen. At the end of each of the module files is the command CHAIN mainmenu; thus, every module, including the main-menu module itself, eventually returns the user to this menu.
Procedures:
Modules within the Command File A procedure is a module that is stored in the same file as the command that calls for it. A procedure is defined by putting a command sequence in a PROCEDURE structure at the end of the command file. Once defined, it can be called for execution anywhere in the file by the PERFORM command. Whenever a particular command sequence is called for a number of times at different places in a command file, you should consider defining the sequence as a procedure. This helps to keep the command file as a whole smaller and thereby easier to read and debug. To define a procedure:
PROCEDURE <procedure name>
Introduces the command sequence to be used as a named procedure. The procedure name can be up to 10 characters long: it may include letters, numerals, underlines or colons, but it must begin with a letter.
ENDPROCEDURE
This is the end-command of a PROCEDURE structure. Ends the PROCEDURE command sequence; execution resumes with the line below the calling PERFORM command.
To call a procedure:
PERFORM <procedure name>
The procedure call within the main command file: executes the named procedure. A procedure can contain a PERFORM command to call yet another procedure in the same command file. No procedure can call itself, either directly or though another procedure.
Environment for a Procedure:
Unlike a chained-file module, a procedure doesn't clear the current environment and create its own. Instead, it uses the environment that's in effect when it's first called.
When Shark compiles a command file, each procedure within the command file is compiled only once—in the environment of the first PERFORM command that calls it.
This means that if a given procedure is "sensitive" to the environment—i.e., if it refers to any data files, fields or memory variables—then every time it is called into execution, it should find the same environment--•--the same data files and variables in use—as when it was first called for by PERFORM.
Be especially careful if the environment of the command file changes between calling PERFORM commands— for example, if data files are closed and new ones opened or if the order of the memory variable table is changed (by releasing some variables and creating new ones). In such a case, the called procedure should be "insensitive" to the changed environment it must not refer to any data files or variables.
Example:
Here's a procedure that pops a help screen in a window over the existing screen as needed throughout a command file. The procedure is called for by the PERFORM command—here, for instance, in a DO CASE menu:
DO CASE CASE answer = "B" PERFORM showhelp <command file continues>
At the end of the command file, the procedure is defined by a PROCEDURE structure:
PROCEDURE showhelp SCREEN 1,2 | Store the current screen WINDOW 1,1,9,75 DOUBLE | Draw a 10-line window box TEXT | Display the help screen This could be a demo help screen . . . Pressto continue ENDTEXT p=inkey() WINDOW SCREEN 2,1 | Restore previous screen contents ENDPROCEDURE | Continue main program
Note that this procedure is insensitive to the environment: it will work with whatever data file happens to be selected when the PERFORM showhelp command is executed, regardless of which data files are opened, closed or selected between PERFORM commands.
In some cases, where there are changes to the environment in the course of a command file, you can make a procedure environmentally insensitive. Do this by providing the procedure with its own set of memory variables. That way, the values to be processed by the procedure need only be stored to these variables before the PERFORM command is executed.
VARIABLE templ,temp2,tempsubttl,temptax,temptotaltemp1 = price temp2 = quantity PERFORM calc REPLACE REPLACE REPLACE calc amount. WITH tempsubttl sales:tax WITH temptax total WITH temptotal
At the end of the command file:
PROCEDURE calc tempsubttl = tempi * temp2 temptax = tempsubttl * .065 temptotal = tempsubttl + temptax ENDPROCEDURE
If you do use this method, be sure to define the variables to be used by the procedure at the start of the command file (we used the VARIABLE command for this) and to exempt them from any RELEASE commands.
SUBROUTINES - Modules in Separate Files:
DO:
The DO command — familiar to dBASE users — calls a module that's stored in a separate command file. In Shark, this kind of module is called a subroutine. Upon completing execution of the subroutine (or upon encountering a RETURN command), Shark returns execution to the next line after the DO command in the original, calling command file.
To create a subroutine:
The subroutine is a command file on disk, one with the extension PRG.
When the main command file is compiled, the subroutine is compiled within the calling command file.
To call a subroutine:
DO <command-file name>
Executes the named command file as a subroutine and, upon its completion, returns execution to the next command line in the current command file.
RETURN:
Used in the subroutine file to return command execution to the command line immediately following the calling DO command in the original command file. RETURN can be used to "break out" of the subroutine (e.g., in a branch structure) and resume the main command file.
If no RETURN command is provided in the subroutine, execution returns automatically to the calling command file upon completion of the subroutine.
Example:
In the main command file:
DO progl | Execute the instructions in the subroutine file <any command sequence> | Do this, then... RETURN | return to the main command file
DO commands can be nested: one subroutine file can call yet another; but nesting is limited to 6 levels.
Environment
Like chained command files, a subroutine is a command sequence that is stored in a separate command file on disk. Like procedures, a subroutine assumes the environment that's in effect when it is called, rather than creating its own.
There, however, the resemblance between subroutines and other modules ends. Here are the differences:
This last distinction highlights the major advantage and the major disadvantage of using subroutines. Because it is compiled every time it's called, a single subroutine can be called into many different environments in fact, it can be called by more than one command file.
Compiling subroutines adds to the overall size of your compiled command file, however, and may make the command file as a whole too large for a floppy disk. There is a simple remedy for this: where the subroutine is to be executed in the same environment, put the calling DO command within a procedure. For example, define the procedure like this:
PROCEDURE subl DO process ENDPROCEDURE
and then call the subroutine with the command PERFORM subl. Where the same subroutine is called for in a second environment, put it in another procedure -
PROCEDURE sub2 DO process ENDPROCEDURE
- and call it with PERFORM sub2.
You may want to "turn off" the automatic compiling of subroutines in order to debug them separately. To do this, use the SET DO switch. See the Alphabetical Command Reference for details.
Summary - When to Use PERFORM, DO, and CHAIN:
All three command file-module structures—procedures, subroutines, and chained command files—can be applied in more or less the same way. All three redirect the execution of a main command file in order to run a stored command sequence, either from another file (CHAIN, DO) or from elsewhere in the same file (PERFORM).
Keep in mind that each type of module is compiled differently. For more information about the environment and Shark's use of memory, see Appendix A.
Guidelines: