When developing a large program, it is inefficient to repeatedly edit, list, and compile the entire program when all the changes are concentrated in one small area. To avoid this, procedures are broken off the main program and put into separate files. These are called "external procedures". They are compiled and assembled separately from the main program, and the resulting .OBJ files are combined using the linker.

Like all named things, external procedures must be declared before they can be called. The form is:

eprocedure NAME(COMMENT), ... NAME(COMMENT);

For example:

eprocedure Baker, Charlie;

This means that Baker and Charlie are procedures that are called from the present file, but they exist in another, external file.

The actual procedure in the external file must be prefixed by the command word "public". For example:

public procedure Baker;

begin

. . .

end;

"Eprocedure" and "public" declarations must be in scope with each other. This means that "eprocedure" declarations must be made at the beginning of the main program, typically right after the "code" declarations, and that "public procedure" declarations must not be nested inside other procedures (except, of course, the main procedure).

Functions also can be external. They are handled like procedures, but since they return a value, they must be identified as "integer", "real", or none. The form of the declaration is:

efunction TYPE NAME(COMMENT), ... NAME(COMMENT);

External procedures and functions handle local variables and argument passing just as you would expect, but global variables require special consideration. WARNING: Each file must declare global variables in the exact same order. This way the global variables correspond to the same memory locations for each file. A convenient way to make sure that each file has the exact same variable declarations is to use the "include" command.

Here is an example of a program that is divided into three files plus a common global variable file:

\GLOBALS.XPL -- COMMON GLOBALS --

code CrLf=9, Text=12;

code real RlOut=48;

int Flag;

real X;

\PARENT.XPL -- MAIN PROGRAM --

include GLOBALS;

efunc real Able; \External procedures & functions

eproc Baker;

begin \Main

X:= 0.0;

Flag:= false;

Text(0, "EXTERNAL EXAMPLE"); CrLf(0);

RlOut(0, Able(2.0)); CrLf(0);

Text(0, "Global X = "); RlOut(0, X); CrLf(0);

X:= X + 1.0;

Baker;

Text(0, "Global X = "); RlOut(0, X); CrLf(0);

end; \Main

\FILE1.XPL -- SECONDARY FILE --

include GLOBALS;

public func real Able(X);

real X; \Local variable

begin

Text(0, "This is Able"); CrLf(0);

if Flag then X:= X + 1.0;

Flag:= true;

return X * X;

end; \Able

\FILE2.XPL -- SECONDARY FILE --

include GLOBALS;

efunc real Able; \External function

public proc Baker;

begin

Text(0, "This is Baker"); CrLf(0);

RlOut(0, Able(3.0)); CrLf(0);

Text(0, "Baker's global X = "); RlOut(0, X); CrLf(0);

X:= X + 1.0;

end; \Baker

After these files are compiled and assembled, they are linked by the command:

LINK /SE:256 PARENT+FILE1+FILE2+NATIVE;

The program is executed by typing "PARENT", and it displays the following:

EXTERNAL EXAMPLE

This is Able

4.00000

Global X = 0.00000

This is Baker

This is Able

16.00000

Baker's global X = 1.00000

Global X = 2.00000

Several public procedures can be combined into a single file and used as a library. This is like having your own set of intrinsics, and it keeps you from compiling and debugging the same subroutines over and over.