Advanced Application Development


Linking C And APL

Frank Cavallito


Frank Cavalito is a Computer Consultant living in Plano, Texas. Frank has been programming for 18 years, using APL, C and 80x86 Assembler. He served as Program Chair for the the APL87 Conference and is currently leader for the NTPCUG Assembler SIG. He can be reached on Compuserve at 76646,1411.

Why Mix APL And C?

The use of APL and C on platforms ranging from PCs to 3090s offers the programmer the best of both worlds — an interactive environment that allows rapid application development and the ability to use C to code performance-critical sections when needed.

APL (A Programming Language) is an interpretive, array-oriented general-purpose computer language that has been implemented on a wide range of hardware from PCs to 68000s to 3090s. The language is highly transportable across implementations. (Some of my utilities are 18 years old and have been run, without modification, on 360s, DEC 2060s, 68000s, PCs and 3090s.) APL is mature enough to have acquired an ISO standard. The interpreters currently available for the PC (8086 family) include two superb implementations from IBM and STSC, as well as public domain, shareware, and demo versions (albeit stripped down) of the commercial products. Additionally, there are two interpreters available for 386 machines from STSC and Dyalog. IBM includes a 386-only interpreter with its APL2/PC.

Some of the features of APL that will appeal to C programmers are bounds checking, dynamic arrays, and the lack of an operator hierarchy. APL statements are executed from right to left. Parenthesis are used to change the order of execution if required. The equal function in APL is a question rather than a statement of fact — there is a separate assignment operator that is not easily confused with the equal function. Variables do not have to be declared but they do have to be initialized before being referenced. Functions do not have to be explicitly prototyped. A function to calculate the average of its right argument can be written to work equally well with a vector of two integers or a 10x10 matrix of floating-point numbers.

While the symbols of APL may look confusing at first, I can guarantee that most programmers are familiar with the symbols of a significant number of APL functions. The plus, minus, divide, and times functions use the symbols most of us have used since grammar school (and before programming). The symbols (and their meanings) for the relational functions would be immediately recognizable. An additional benefit of the use of symbols in APL is that their use makes APL more of an international language. Unfortunately, most of these familiar symbols cannot be printed on a standard ASCII terminal.

STSC's APL*PLUS

This article will demonstrate the interface between C and STSC's APL*PLUS for the PC. I chose STSC's product because its external language interface is more flexible and cleaner (and easier to show to non-APLers) than is IBM's APL2/PC. One problem with APL*PLUS is that the external routine must be a .COM style program with zero offset (a limitation not found with IBM's product), which requires the use of a C compiler capable of generating tiny-model programs. Given these requirements, Borland's Turbo C++ and TASM are ideal for this application. Other compilers will work, such as Microsoft's C5.1, but may require hand-editing of an intermediate .ASM file.

APL*PLUS provides three facilities useful to the C programmer developing external functions. One is a software interrupt that I discuss below. The other two are APL QUAD functions (the QUAD symbol indicates an APL reserved name):

As an example, to call an external object, phoobah, with the AX register set to 0100h and the BX register pointing to the APL object FOO:

(256,QUADSTPTR' FO0') QUADCALL
   phoobah
All other registers are set to 0. The expression returns the status of the registers after the execution of phoobah, if that function ends with a far return.

Software Interrupt OC8h

The software interrupt 0C8h provides memory management facilities that are needed by an external routine. Services are available to create objects, assign objects to variables, determine available memory, check name status, etc. The service used in the example, with AL=0, allows the creation of an object of any type, rank, or shape and assignment of this object to a variable. The BX register is loaded with the STPTR of the variable (in this case the final APL result) and ES:SI is set to point to the requisite information:

ES:[SI] +0 byte- data type
      (1 = char,2 = int,8 = float)
   + 1 byte - rank of object
   +2 word - first dimension
   +4 word - second dimension
   .. .. nth ..
Note that this corresponds to the variable layout in
Listing 1 (lines 26-29): RES_TYPE, RES_RANK, RES_ROWS, and RES_COLS. After executing the interrupt, ES:DI is set to point to the start of data in the object.

Interfacing C To APL

The general strategy for designing an interface between APL and C is simple:

1. Name the interface module MAIN. This will satisfy the requirements of the C compiler for something named main.

2. APL objects can be of any type (single-byte character, two-byte integer, and eight-byte IEEE double-precision), any rank (the number of dimensions can range from 0 to 63), or any size (limited to 64k in early releases of APL*PLUS). Hence, the external routine must verify input as to type, rank, etc. (See lines 43-66 in Listing 1. ) While this checking can be handled in APL (one line of APL code would typically suffice to insure that the data met type and rank requirements of the external routine), STSC advises that this be explicitly checked in the external routine. If the data is not correct, the program should execute an INT 0, which will cause a return to APL with a DOMAIN error. This is the only type of error QUADCALL can signal that APL can trap and react to. (Most APL implementations include a form of error trapping that will transfer program control to a specific piece of code where the location and type of error can be determined. This facility allows one to adopt a strategy of reacting to an error after it has occurred rather than go through an exhaustive checklist prior to execution).

3. If a result is to be passed to APL other than through the register values, provide code to determine the size and shape of the result (see RESULT_SIZE module in Listing 2) and use INT 0C8h to create the result. (See lines 81-87 in Listing 1. ) The use of DOS memory-management facilities (such as malloc) is not recommended. INT 0C8h can be used to create and free temporary space if needed.

4. Pass the arguments required by the C program that will fill in the result. (See READ_SCREEN_BLOCKS module in Listing 2. ) Note that this program fills in the APL result in place.

5. Set up any returns to APL.

6. End the program with a far return. After compiling and linking, you must read the program into APL. Figure 1 details this process, as well as using an APL cover function to call the program.

Debugging

In programming these routines, I strongly recommend coding and debugging the C routines in a C environment, complete with a source-code debugger. I always write a C-based driver function that I use to test and debug the sub-routines before attempting to link with APL. The only change one would normally make to the tiny-model C sub-routines would be the use of far pointers, since APL data does not necessarily start on paragraph boundaries. With properly debugged C sub-routines, any problem found when linking to APL is probably in the interface.

While the interface can be coded in C, I have found that it is best coded in assembly language for a number of reasons. One is that important details can be hidden in a C implementation. The major reason, however, is that C code can be difficult to follow on the machine-code level.

Source-code information is not available when running under APL. External routines may be debugged by:

You will be left in the debugger at the statement following the INT 3, ready to step through the routine.

Uses For APL Plus C

The combination of APL and C can be used in a wide range of instances. It is especially productive in areas where rapid application development is important or where the C programmer needs access to sophisticated mathematical procedures or reporting facilities. I have used the C and APL combination in a number of these areas:

As I noted previously, there are a number of public domain, shareware, or demo versions of the PC interpreters available. One particularly attractive package is the free TryAPL2 from IBM. This is a stripped-down version of their APL2PC product that comes with some very interesting examples using APL in areas such as operations research, statistics, date manipulations, and expert systems. The character set will properly display on an EGA or VGA monitor. A keyboard map is provided.

Products Mentioned

APL*PLUS ($695) and APL*PLUS II for the 80386 ($1700): STSC, Inc. 2115 East Jefferson Street Rockville, MD 20852.

TryAPL2 (free), APL2PC ($500): APL Products IBM Santa Teresa Dept. M46/B25 P.O. Box 49023 San Jose, CA 95161-9023.

Dyalog APL ($1495): Dyadic Systems, Ltd. Riverside View, Basing Road Old Basing, Basingstoke Hants, RG23 OAL, England, UK. U.S. distributor: MIPS, 33493 W. 14 Mile Road, Farmington Hills, MI 48331.

I-APL (Public Domain), Documentation ($22.50) Edward Cherlin, I-APL Ltd, 6611 Linville Drive, Weed, CA 96094.

Books On APL

Rose Gilman, APL An Interactive Approach, Third Ed., John Wiley & Sons, Leonard Gilma, Allen J. Rose, 1984.

James A. Brown, Sandra Pakin and Raymond P. Polivka, APL2 at a Glance Brown, Prentice Hall, 1988.

Jerry R. Turner, APL is Easy, John Wiley & Sons, 1987 (included with STSC's APL*Plus).

Listing 3