Advanced Language Features | ![]() |
The information in this chapter is designed to help you produce programs that run as efficiently as possible. It includes information on the following:
The information in this chapter applies to programs compiled to native code not intermediate code unless otherwise stated.
This section gives some guidelines which, if followed, enable your Server Express system to optimize fully the native code produced for your programs. This results in smaller and faster applications. Do remember that these are only guidelines; programs that do not conform to these guidelines still run correctly, just less efficiently.
Programs using Server Express can be moved to other systems provided certain portability rules are followed.
Using the correct data-type is important to get the greatest efficiency from operations, particularly arithmetic operations. For details of how each data-type is stored refer to your Language Reference.
Data-type
|
Speed/Description
|
---|---|
COMP-5 | Operations on
COMP-5 data items are performed as true native binary operations.
Fastest performance of COMP-5 is given using the Compiler directive COMP-5"2", the default. See the chapter Directives for Compiler in your Server Express User Guide for more details of this directive. |
COMP-X |
Operations on
COMP-X data items are performed as binary operations.
The data items are stored in COBOL order, which might not be the same as the native byte order. For example, on Intel 80x86 systems byte ordering is different to that on other processors. In this case, arithmetic on items longer than one byte involve operations to change the byte order before the arithmetic can be carried out, resulting in slightly slower arithmetic than on COMP-5 items. |
COMP | Operations on COMP data items, by default, operate as defined in the ANSI standard. This results in truncation of the result of operations before it is stored in a COMP item. This generally results in slower arithmetic than on COMP-X data items. However, if the directives COMP and NOTRUNC are used when the program is compiled, operations on COMP items behave exactly like operations on COMP-X items. |
COMP-3 | Arithmetic on COMP-3 data items is performed in packed decimal and is much slower than arithmetic on COMP items. It should be avoided. Arithmetic on COMP-3 data items is slower than DISPLAY items in intermediate code. |
DISPLAY | Arithmetic on
DISPLAY items is much slower than arithmetic on COMP items, and should be
avoided. However:
|
32-bit:
In 32-bit COBOL systems, the fastest and smallest code is produced for
operations on items that contain up to nine digits, or four bytes for binary
items.
Operations on numeric items containing more than nine digits, or more than four bytes for binary items, produces the slowest and largest code.
64-bit:
In 64-bit COBOL systems, the fastest and smallest code is produced for
operations on items that contain up to eighteen digits, or eight bytes for
binary items.
To ensure all items in a table are correctly aligned, check that the size of an occurrence in the table (the stride of the table) is a multiple of two or four bytes as required. Pad the table as necessary. For example:
01 a occurs 10. 03 b pic x(4) comp-5. 03 c pic x. 03 filler pic x(3).
A three-byte filler has been added to each occurrence in the table to ensure that the numeric data item is always aligned on a four-byte boundary.
The REF Compiler directive can be used to find out how data items are aligned.
This section identifies items in the Procedure Division which affect the size and performance of your program, and suggests the most efficient ways of using them.
As a general rule, the simpler the operation, the faster it executes and the smaller the compiled code. To get the best performance it is often better to use a number of simple operations rather than one complex operation. The following are general guidelines that result in the fastest and smallest possible code.
To get the best performance from arithmetic statements always use the simplest forms.
The following operations are optimized for COMP-5 and COMP-X data items up to four bytes long.
move a to b add a to b subtract a from b multiply a by b divide a into b if a condition b
where:
a
is a numeric literal or data item up to four bytes long
b
is a numeric data item up to four bytes long
On other data items, these simple operations result in faster code than more complex instructions, but the benefits are not so great as with COMP-5 or COMP-X items.
More complex forms of these instructions, involving more than two operands, might not produce code as efficient as the simple form.
Always use operands of the same type, preferably 4-byte comp-5. The following examples are fully optimised:
compute a = b * c + d compute a = b * 4 + 2 compute a = b + c - d + e
In comparisms, it is often better to use a temporary item rather than a computed IF such as:
if a + b > c
Intermediate code reports run-time error 163 ("Illegal character in
numeric field"). Generated code gives unpredictable results.
Results are unpredictable.
To avoid these problems, all numeric items should be initialized to numeric values before use.
The following list suggests the most efficient ways of using alphanumeric data manipulation:
item (literal:) item (literal:literal) item (literal:variable) item (variable:variable) item (variable + literal:literal) item (variable - literal:literal) item (variable + literal:variable) item (variable - literal:variable)
Other forms of reference modification are inefficient.
The following list suggests the most efficient ways of table handling:
01 a pic xx occurs 10. 01 b pic xx occurs 10. 01 c pic xx occurs 10. 01 d pic xx occurs 10. . . . move a(i) to b(i) if c(i) = d(i) display "pass" end-if
would result in the subscript i
being evaluated only once,
although it is used four times in two statements. The stride of each of these
tables is the same: two.
If you are using USAGE DISPLAY subscripts, the BOUNDOPT directive (also switched on by NOBOUND) can give performance improvements. For example:
. . . 01 array pic x occurs 20. 01 array-index pic 9(5) value 2. . . . move "a" to array(array-index). . . .
If the program is compiled without BOUNDOPT, all five digits of array-index
are used to evaluate the subscript. If BOUNDOPT is specified, only the last two
digits of array-index
are used, as only two digits are needed to
access all elements of a 20 element table.
The following list suggests the most efficient ways of using conditional statements:
A number of COBOL System Library Routines (call-by-name) are available to perform bit-wise logical operations on data items. These are described in the chapter Advanced Language Features. They perform operations such as bit-wise AND, OR and XOR.
The Compiler recognizes calls to these routines and, if possible, optimizes them to produce in-line code rather than calls to the run-time system. The calls are optimized if the length is specified as a literal. In-line code is native code which performs the function directly without making any calls. The alternative is a call to a generic run-time routine which must allow for many cases.
The calls are optimized if the length is specified as a literal.
Logical AND and logical OR operations can also be carried out using the VALUE clause. See your Language Reference for details.
Using PERFORM is generally very efficient, and is a very good way of keeping the size of your program down as well as giving it an easy-to-maintain structure. The following rules enable you to use it in the most efficient ways.
Apart from being good coding practice, this saves space. It is often beneficial even on single statements; for example, edited moves, subprogram calls or file I/O
The range of an out-of-line PERFORM statement should not contain the end of another perform range. If it does, the program is said to trickle ; that is execution is allowed to go past the end of a perform range. Applying the rule above ensures that this does not occur.
For example, the following produces very inefficient code for the first PERFORM because the end of the range of the second PERFORM lies within the range of the first PERFORM.
perform a thru e perform b thru d stop run a. . . . b. . . . c. . . . d. . . . e. . . .
The presence of an ALTER statement in a program prevents optimization of PERFORM statements.
The following list suggests the most efficient ways of using alphanumeric CALL statements:
Avoid making many references to linkage items. These include items defined in the Linkage Section, items set to CBL_ALLOC_MEM allocated memory, and items defined as EXTERNAL .
Accessing linkage items is always slower than accessing Working-Storage Section items. If a Linkage Section item is used frequently, it is faster to move it into a Working-Storage Section item when the program is entered and move it back to the Linkage Section if necessary before exiting to the calling program. The Working-Storage Section item should then be accessed throughout the program rather than the item in the Linkage Section.
If you use input and output procedures with a file sort in your program it is important that you write them efficiently as they are executed once for each record you are sorting. Inefficient input and output procedures can make the sort process appear to be very slow.
A number of Compiler directives can be used to make the native code for a program better optimized. Some of these directives must be used with care; ensure that the behavior you get with them is acceptable.
In general, always use the following directives when compiling your programs to native code:
NOALTER
ALIGN"4" (32-bit systems)
ALIGN"8" (64-bit systems)
COMP
NOBOUND
NOCHECK
NOCHECKDIV
NONESTCALL
NOODOSLIDE
NOQUAL
NOSEG
NOTRUNC
Other suggestions (to help prevent inefficient coding)
REMOVE "ROUNDED"
REMOVE "ERROR"
REMOVE "INITIALIZE"
REMOVE "CORRESPONDING"
REMOVE "THRU"
REMOVE "THROUGH"
By removing these reserved words you prevent the possibility that code using these inefficient constructs will be added to the program.
There are many directives you can use to optimize for speed. In some cases, the defaults for Compiler directives are the ones that provide speed optimization. This section points out directives that need to be changed from their default values to provide for speed optimization.
For efficiency reasons, you should not use ALTER statements in programs. It is recommended that you avoid them altogether, and compile with NOALTER, to prevent the Compiler from having to produce code to look for them.
The BOUND directive does boundary checking on table items.
Your applications can be made faster (and smaller) by compiling with NOBOUND. Otherwise, the Compiler inserts extra code to do boundary checking on all references to table items.
During testing, you should use the BOUND directive until you are satisfied that your program is not referencing data beyond your table limits. For production, NOBOUND gives you the desired efficiency.
The BOUNDOPT directive can be used to optimize your code if the following apply:
When BOUNDOPT is specified, digits in a USAGE DISPLAY subscript above the size of the table are ignored. For example, a PIC 9(3) subscript would be treated as PIC 9(2) for a table with less than 100 entries.
We recommend that you do not use USAGE DISPLAY subscripts.
The COMP directive prevents code checking for numeric overflow. This produces highly compact and efficient code.
COMP changes the behavior of arithmetic on data items defined as USAGE COMP. It produces more efficient code, but the behavior does not conform to the ANSI standard.
If used with the proper care, COMP can improve the speed of your programs.
The NESTCALL directive enables nested programs to appear in your program. If you know you have no nested calls in your program, specifying NONESTCALL enables the Compiler to generate slightly more efficient code.
The TRUNC directive causes the Compiler to create code to determine whether USAGE COMP data items need to be truncated or not.
If you are certain that you do not need truncation of USAGE COMP data items, NOTRUNC causes the creation of more efficient code.
There are many directives you can use to optimize for size. In some cases, the defaults for Compiler directives are the choices that provide size optimization. This section points out directives that need to be changed from their default values to provide for size optimization.
This directive specifies the boundary on which level-01 and level-77 items start. This boundary should always be a power of two, such as two, four or eight. For 32-bit COBOL systems use a minimum of ALIGN"4". Use ALIGN"8" if you are using a 64-bit operating system. Higher powers of two retain efficiency, but increase the amount of unused space between data records.
You might get unexpected results from arithmetical operations involving floating point calculations, as COBOL does not by default round numbers. For example, say WS02 is defined as a COMP-2 data item, and the following operations are performed:
accept ws02 compute ws02 = ws01 display ws01
If you enter a value of 2.3 when requested by the program, the value displayed will be 2.29.
If you want values to be rounded you must specify the ROUNDED clause. The example above would be rewritten as:
accept ws02 compute ws02 rounded = ws01 display ws01
You can specify that all data-items in a program are rounded or truncated using the Compiler directive FP-ROUNDING. See the chapter Directives for Compiler in your Server Express User Guide for more details of this directive.
Server Express provides IEEE floating-point support. The following sections describe the range of values and the accuracy available using floating-point support.
The range of values available with each of the two COBOL binary floating-point data types is as follows:
COMP-1 from | 8.43E-37 | through | 3.37E38 |
-8.43E-37 | through | -3.37E38 | |
COMP-2 from | 4.19E-307 | through | 1.67E308 |
-4.19E-307 | through | -1.67E308 |
Note: Although the underlying floating point support used by this COBOL system does support the above ranges, this COBOL system only supports 2 digit exponents.
The following table shows the relationship between storage size and significance.
Type
|
Size
|
Significant digits
|
---|---|---|
COMP-1 | 4 bytes | 6-7 |
COMP-2 | 8 bytes | 15-16 |
The compiler validates floating point literals to ensure their values are compatible with the mainframe environment. Literal values that do not lie within the following range will cause a compile-time error:
from | 0.54 E -78 | through | 0.72 E +76 |
and from | -0.54 E -78 | through | -0.72 E +76 |
All IEEE format binary floating-point values consist of:
If the value is non-zero, the exponent has a constant subtracted to give the starting value of the mantissa. Thus, the value of a double precision (COMP-2) item in terms of its mantissa (m) would be:
1*(2**m) + mb0*(2**(m-1)) + mb1*(2**(m-2)) + mb2*(2**(m-3)) + ... + 1*(2**(m-52))
where the mantissa bit (in this example, mb0 through mb51) can be 0 or 1. For COMP-1 (single precision) fields, this becomes an issue when the difference between the maximum and the minimum powers of 2 is greater than 23; for COMP-2 fields, the issue might arise when the difference between the maximum and minimum powers of 2 is greater than 52.
For example, if a COMP-2 field is expressed with one mantissa bit multiplied by 2**56, and another mantissa bit multiplied by 2**2, then the value in the field would need to be approximated, because 56 - 2 = 54, which is greater than 52. This would be true in any floating point implementation on any hardware platform. Additionally, the internal storage format of floating point numbers can differ from operating system to operating system; see page 2-40 of your Language Reference manual. These discrepancies can occur because of variations in the internal storage of floating point numbers between operating systems.
Binary floating point can only represent powers of 2 (both positive and negative), and combinations of these powers of 2. For example, a fractional decimal number is represented by adding together the combination of values from the sequence 1/2, 1/4, 1/8, 1/16, 1/32, and so on, that comes closest to the required value. Thus, a value such as 0.625 (i.e., 1/2 + 1/8) can be represented exactly, whereas other values are represented by an approximation (which might be slightly above or slightly below the true value). Similarly, an integer is represented by adding together the combination of values from the sequence 1, 2, 4, 8, 16, and so on, that comes closest to the required value. Thus, a value such as 625 (which can be made up from 1 + 16 + 32 + 64 + 512) can be represented exactly, whereas other values are represented by an approximation.
The Server Express system enables you to execute statically linked or dynamically loaded code. Statically linked code is embedded within the executable file. Dynamically loadable code is a COBOL callable shared object, or .int or .gnt file that is loaded and run only when the file is called. The code is held in a separate file to the executable file. The dynamic loader loads COBOL program overlays as needed.
When designing a COBOL application program that is to be dynamically loadable, you want it to make efficient use of the available memory. It is possible, using this COBOL system, to create and run programs that use more memory than is physically present in your computer. You can do this by separating the program into smaller programs and using the COBOL call mechanism (see the section Inter-program Communication (CALL) later in this chapter).
The run-time system also provides another method for creating and running programs that use more memory than is physically present in your computer. It enables you to segment one large COBOL program so that it holds on disk the code that is not being used.
This section looks at the inter-program communication (call) mechanism for creating large applications but avoiding large programs.
The COBOL system enables you to design applications as separate programs at source level. Each program can then be called dynamically from the main application program without first having to be linked dynamically with the other programs. Figure 1-3 shows an example of an application divided up in this way.
Figure 1-1: Application Divided Using CALL
The main program A, which is permanently resident in memory, calls B, C, or H, which are programs within the same suite. These programs call other specific functions as follows:
B | calls D, E and F |
C | calls X, Y, Z, L and K |
H | calls K |
K | calls M, N and O. |
Because the functions B, C and H are standalone they do not need to be permanently resident in memory together. You can call them as they are needed, using the same physical memory when they are called. The same applies to the lower functions at their level in the tree structure.
In the figure, you would have to plan the use of CALL and CANCEL operations so that a frequently called subprogram such as K would be kept in memory to avoid load time. On the other hand, because it is called by C or H, it cannot be initially called without C or H in memory; that is, the largest of C or H should call K initially so as to allow space. It is important also to avoid overflow of programs. At the level of X, Y and Z, the order in which they are loaded does not matter because they do not make calls at a lower level.
It is advantageous to leave called programs in memory if they open files, to avoid having to reopen them on every call. The EXIT statement leaves files open in memory. The CANCEL statement closes the files and releases the memory that the canceled program occupies, provided all other programs in the executable file have been canceled or never called.
If you use a tree structure of called, independent programs as shown earlier, each program can call the next dynamically by using the technique shown in the following sample coding:
working-storage section. 01 next-prog pic x(20) value spaces. 01 current-prog pic x(20) value "rstprg". procedure division. loop. call current-prog using next-prog cancel current-prog if next-prog = spaces stop run end-if move next-prog to current-prog move spaces to next-prog go to loop.
The programs to be run can then specify their successors as follows:
. . . . . . linkage-section. 01 next-prog pic x(20). . . .
. . . procedure division using next-prog. . . . . . . move "follow" to next-prog. exit program.
In this way, each independent segment or subprogram cancels itself and changes the name in the CALL statement to call the next one with the USING phrase.
Having decided to use the call mechanism for your application, the following sections look at some of the practical aspects of creating such applications.
The total number of programs which can be loaded in memory as the result of a call is not constant. The number depends on the amount of available memory in your computer and the size of the program being called.
Dynamically called programs have an advantage over programs that have been linked into a single executable file, in that dynamically called programs have their memory freed when they are canceled while the latter do not.
If a program is called and the program is dynamically loaded, the filename is used to identify it. If the program is statically linked then the Program-Id paragraph can be used. See the section Calling COBOL Subprograms for more details.
You can avoid many "program not found" errors by always using the filename without extensions as the program-name in the Program-Id paragraph. This enables flexibility in constructing your executable programs with statically or dynamically called programs.
For details on the Program-ID paragraph, see your Language Reference.
This section looks in more detail at how to call subprograms. It provides information on writing subprograms and passing parameters between them.
You can write subprograms or your main programs in the COBOL language or in some other language, such as C. You can mix these subprograms freely in an application. However, before you call a non-COBOL subprogram from a COBOL program, you must link it to either the dynamic loader run-time support module or to your statically or dynamically linked COBOL application.
A COBOL subprogram can be linked, or it can also be dynamically loaded at run time.
A linked program is an executable object module, while a dynamically loadable module is a COBOL intermediate code file (.int file), COBOL generated code file (.gnt file), or a COBOL callable shared object.
A COBOL program can call a COBOL subprogram by using one of the following formats of the CALL statement:
CALL "literal" USING ...
or:
CALL data-name USING ...
For any COBOL programs, the literal string or the contents of the alphanumeric data item must represent the Program-ID, the entry point name, or the basename of the source file (that is, the filename without any extension). The path and filename for a module can also be specified when referencing a COBOL program, but we do not recommend you do this, as unexpected results can occur where the referenced module exists in more than one file, or type of format, or if the application is ported to other environments. For statically linked modules, the native code generator converts calls with literal strings to subroutine calls which refer to external symbols. The Micro Focus COBOL system automatically creates a routine to define the symbol and to load the associated file if it is entered at run time.
Note: Programs that are called at link time must have names that the system assembler and linker can accept; that is, they must not contain characters other than 0-9, A-Z, a-z, underscore (_), or hyphen (-). You must correct any entry point names that use characters other than these so that they are acceptable to the system assembler and linker.
Use a CALL literal statement to call a linked program directly. If the program is not found a run-time system error is displayed unless the dynamic loader is present, in which case it will attempt to find a dynamically loadable version of the program.
Use either a CALL literal statement, or a CALL data-name statement, to call a dynamically loadable program, and make the dynamic loader run-time support module search for the called program.
You might need to load the dynamic loader using the cob utility.See the chapter COBOL System Interface (cob) in your Server Express User Guide for more details of this directive.
The dynamic loader run-time support module follows this search order to find the named file:
If the dynamic loader run-time support module has to search for a file on disk and no path-name has been specified on the call, the search order followed is:
[;] path-name [;path-name] ...
For example:
set COBDIR=d:/cobol/lbr;d:/cobol/exedll
If you include the optional semicolon (;) at the beginning of the string, the dynamic loader run-time support module assumes the current directory is the first one to be searched
If you specify a directory path on the call, the dynamic loader support module searches for the file only in the named directory.
If you specify a file extension, the dynamic loader run-time support module searches only for a file with a matching extension. However, we recommend that you do not include an explicit extension in the filenames you specify to the CALL statement. If you specify a file without an extension, the dynamic loader run-time support module adds the extension .so to the basename of the file, and searches the disk for the corresponding callable shared object file. If it cannot find the callable shared object the dynamic loader run-time support module adds the extension .int to the basename of the file, and searches the disk for the corresponding intermediate code file. If it cannot find the .int file, the dynamic loader run-time support module adds the extension .gnt to the basename of the file, and searches for the corresponding .gnt file.
The dynamic loader run-time support module always assumes that the first matching program name which it finds is the program you require to CALL.
If no matching program is found a run-time error occurs.
Note that if the first character of a filename which is to be dynamically loaded at run time is the dollar sign ($), the first element of the filename is checked for filename mapping. The first element of the filename consists of all the characters before the first slash character (/).
See your File Handling for details. For example, if the statement:
CALL "$MYLIB/A"
is found in the source program, the file A is loaded from the path as defined by the MYLIB environment variable at run time.
You can access non-COBOL subprograms using the standard COBOL CALL ... USING statement. The address of each USING BY REFERENCE or USING BY CONTENT parameter is passed to the argument in the non-COBOL subprogram which has the same ordinal position in the formal parameter declarations. You must thus ensure all formal parameter declarations are pointers.
Note that if you use the CALL...USING BY VALUE form of the CALL...USING statement, the USING parameter is not passed BY VALUE if it is larger than four bytes long. If it is larger than this, it can be passed BY REFERENCE, but no warning is output to inform you of this. If you specify a numeric literal with a CALL...USING BY VALUE statement, it is passed BY VALUE as though it were a four-byte COMP-5 item; that is, it appears in machine-order as a data item and not as a pointer to that data item. If you specify a data item with a CALL...USING BY VALUE statement it must be defined as COMP-5.
You might need to specify a particular calling convention when interfacing to non-COBOL programs - see the chapter The COBOL Interfacing Environment for more information.
The following example shows how C functions can be accessed from a COBOL program
$set rtncode-size"4" working-storage section. 01 str. 03 str-text pic x(10). 03 filler pic x value x"00". * Null terminate string for C function 01 counter pic 9(8) comp-5 value zero. procedure division. call-c section. call "cfunc" using str, counter if return-code not = zero * RETURN-CODE set from return () in C display "ERROR" else display "OK" end-if stop run. ------------------------------------------------
cfunc (st, c) char *st; int *c; { ... return(0); }
When you use the CALL statement from within a COBOL program to access a non-COBOL module as described above, you must ensure that the COBOL run environment is not accidentally damaged. This means you must ensure that:
The CANCEL statement has no effect when it references a non-COBOL program .
The Server Express system traps unexpected signals and returns run-time system errors:
114 Attempt to access item beyond bounds of memory
115 Unexpected signal
Where C and COBOL modules are linked, these error messages are usually due to an error in the C code which causes a hardware interrupt for such conditions as segmentation violation. If you do receive these run-time system errors, carefully check the C source routines using the system debugger, paying particular attention to the format and byte ordering of parameters passed between the COBOL and C modules.
COBOL programs can contain ENTRY statements. An ENTRY statement identifies a place where execution can begin as an alternative to the Procedure Division if a calling program so specifies.
COBOL fully supports entry points, but the dynamic call loader presents a potential problem. Because the run-time system typically defaults to looking for called programs dynamically, there is no way for the run-time system to locate a particular entry point embedded in a program on disk. When you execute a call statement like:
call "abc" using ...
the run-time
system first looks for a program or entry point called abc
in all of the programs and libraries that have already been loaded. If it does
not find the program, the run-time
system then looks for a file called abc.ext
where
.ext
is an executable file formats. For details of
executable file types see the section Executable
File Types in the chapter Packaging Applications in your Server
Express User Guide.
If abc
represents the name of an entry point contained in
another program, the run-time system
cannot locate the file on disk, and a "program not found" message is
issued. The run-time system
does not scan through every individual executable file on disk to locate an
entry point.
Therefore, you must load the program containing the called entry point into the run-time system.
One technique that you can use to do this is to create a .lbr file that contains any programs containing entry points that need to be preloaded. You can create the .lbr file (library file), using the Library facility. Once the .lbr file is created, you can issue a call to the .lbr file.
Note: When you call an .lbr file, the run-time system does not load every program in the .lbr into the run-time system. Instead, the run-time system registers the existence of all programs and entry points contained in the called .lbr file, for future reference. Later when one of these programs contained in the .lbr is called, the run-time system notes that it is contained in the .lbr and loads it at that point.
Once a program that contains the entry points is loaded into the run-time system, all entry points contained in the program are identified to the run-time system and are available to be called by any program loaded later. This means that if you need to call entry points in a particular program from another program, you must ensure that the program is loaded first, so the run-time system can register these entry points.
This section describes how you call a program and pass the command line to the main program as a parameter. The main program in a run unit is the first program within it; that is, the program which is called directly by the COBOL system.
As the maximum size, form and contents of the command line vary between operating systems, these issues need to be considered if you want to port your application between environments. For example, to ensure portability, a maximum command line size of 128 characters might be appropriate rather than the system limit. Similarly, only alphabetic and numeric characters with the equals sign (=) and space characters should be used for entering the command line for a program if you want to guarantee portability.
The command line can be accessed from:
The standard COBOL calling convention is:
call progname using ...
or:
call "progname" using ...
where progname
(without quotation marks) is a data item that
contains a valid program-name, and "progname"
(with
quotation marks) is the actual name of a valid program.
A program-name is a character string representing the program or subprogram to be called. In the run-time system, this name is treated as an implicit program-name; that is, there is no filename extension in the program-name.
This means the actual executable file being called might be in any of the following supported executable formats:
When progname.lbr is found, the run-time system opens the .lbr file and locates and loads an executable file with the same program-name, for example progname.gnt, progname.int, or progname (no extension) from the .lbr file.
An explicit program-name can be specified in the call statement as well:
call "progname.gnt" using ....
This forces the run-time system to look for the exact filename specified, in this case progname.gnt. If the exact program-name is not located a "program not found" error message is issued.
Once started, the run-time system sets up a 32-bit addressing virtual storage environment in which it loads and manages all called subprograms. When the run-time system locates and loads a called program, it assigns a unique run-time system identifier to the program. (This identifier is used internally in the run-time system.) The run-time system allocates memory (both real and virtual) for the program, and can swap portions of it out to disk as needed.
The run-time system records the actual location, drive and path-name as well. Once loaded into the run-time system, the run-time system uses the same copy of the program unless it is canceled and recalled.
Whenever a COBOL program running under the run-time system issues a call to a subprogram, the run-time system goes through the following steps:
As described above, the run-time system can search for multiple executable files, and can search for these program files in more than one directory.
Note: The search sequences described below apply to executable files (programs). It does not apply to other file types, for example data files and COBOL source files.
You do not need to be concerned about search conventions if you only have one executable version of your program on disk. This discussion only applies if you have multiple executable files available.
Whenever a COBOL program issues an explicit call to a subprogram, for example:
call "myprog.gnt" using ...
the run-time system searches for a file with the specified extension.
In this case, the run-time
system searches for myprog.gnt
. It does not search for
other valid executable formats with the same program-name but different
extensions.
When a program issues an implicit call, that is, a call to a program-name without specifying a file extension, the run-time system searches for the called program in the order listed below.
When a program issues a call like:
call "proga" using ...
the run-time system
searches through the following sequence looking for proga
:
1 | proga.so | |
2 | proga.gnt | |
3 | proga.int | |
4 | proga.lbr | The run-time system opens this .lbr file and searches it for an executable name |
5 | proga | No extension |
If none of the above are found, the run-time system issues the message, "program not found".
You can change the order in which the run-time system searches for files by setting the I1 run-time switch. This causes the run-time system to search for files in the order :
1 | proga.so |
2 | proga.int |
3 | proga.gnt |
4. | proga.lbr |
This is useful for testing when you are typically compiling only to intermediate (.int) code.
When the run-time system finds and loads a program, it records the location (drive and path) where the program was first found. If the program issues a later call to another program, the run-time system does not look in the current directory for the new program being called. Instead, it defaults back to the same directory where the calling program was first found.
If the run-time system cannot find the called program in the same directory that the calling program is in, the run-time system begins its standard search sequence to try to locate the called program. This technique, known as inheritance, is the default behavior for the run-time system.
It is also important to understand the way the run-time system searches for various executable files through the multiple directories that can be set in the COBDIR environment variable. For example, if your program issues a call to a program like:
call "myprog" using ...
the run-time system
initially searches its active directory to see if myprog
has
already been loaded (and not subsequently canceled).
If it has been loaded, the run-time
system passes control to myprog
. It does not refresh the
program's Data Division unless:
A later call then forces the run-time system to locate it again and load a fresh copy.
See your Language Reference for details on PROGRAM-ID .
Note: You should be aware of the impact of inheritance on the run-time system search sequence. If you have the same program-name in more than one directory, you can access the wrong version.
Copyright © 1999 MERANT International Limited. All rights reserved.
This document and the proprietary marks and names
used herein are protected by international law.
Advanced Language Features | ![]() |