Writing a Subroutine

In this section:

You can write a subroutine in any language that supports subroutines. If you intend to make your subroutine available to other users, be sure to document what your subroutine does, what the arguments are, what formats they have, and in what order they must appear in the subroutine call.

When you write a subroutine you need to consider the requirements and limits that affect it. These are:

If you write a program named INTCOMP that calculates the amount of money in an account earning simple interest, the program reads a record, tests if the data is acceptable, and then calls a subroutine called SIMPLE that computes the amount of money. The program and the subroutine are stored together in the same file.

The program and the subroutine shown here are written in pseudocode (a method of representing computer code in a general way):

Begin program INTCOMP.
Execute this loop until end-of-file.
   Read next record, fields: PRINCPAL, DATE_PUT, YRRATE.
   If PRINCPAL is negative or greater than 100,000,
      reject record.
   If DATE_PUT is before January 1, 1975, reject record.
   If YRRATE is negative or greater than 20%, reject record.
   Call subroutine SIMPLE (PRINCPAL, DATE_PUT, YRRATE, TOTAL).
   Print PRINCPAL, YEARRATE, TOTAL.
End of loop.
End of program.
Subroutine SIMPLE (AMOUNT, DATE, RATE, RESULT).
Retrieve today's date from the system.
Let NO_DAYS = Days from DATE until today's date.
Let DAY_RATE = RATE / 365 days in a year.
Let RESULT = AMOUNT * (NO_DAYS * DAY_RATE + 1).
End of subroutine.

If you move the SIMPLE subroutine into a file separate from the main program and compile it, you can call the subroutine. The following report request shows how much money employees would accrue if they invested salaries in accounts paying 12%:

TABLE FILE EMPLOYEE
PRINT LAST_NAME DAT_INC SALARY AND COMPUTE
   INVESTED/D10.2 = SIMPLE(SALARY, DAT_INC, 0.12, INVESTED);
BY EMP_ID
END

Note: The subroutine is designed to return only the amount of the investment, not the current date because a subroutine can return only a single value each time it is called.

Naming a Subroutine

A subroutine name can be up to eight characters long unless the language you are using to write the subroutine requires a shorter name. A name must start with a letter and can consist of a combination of letters and/or numbers. Special symbols are not permitted.

Creating Arguments

When you create arguments for a subroutine, you must consider the following issues:

The lengths of the calling arguments as defined in WebFOCUS must match the lengths of the corresponding arguments defined in the subroutine.

Any deviation from these rules may result in problems in using the subroutine. Information Builders recommends that you modify the subroutine to conform to the stated rules and then link it above the line. In order to load subroutines above the line, the following are the required link-edit options for compiling and storing the subroutine:

Language Considerations

When writing a subroutine, you must consider the following language issues:

Language and memory. If you write a subroutine in a language that brings libraries into memory (for example, FORTRAN and COBOL), the libraries reduce the amount of memory available to the subroutine.

FORTRAN. TSO supports FORTRAN input/output operations.

COBOL. When writing a subroutine in COBOL:

PL/I. When writing a subroutine in PL/I:

C language. When writing a subroutine in C:

Programming a Subroutine

In this section:

Consider the following when planning your programming requirements:

You can add flexibility to your subroutine by using a programming technique. A programming technique can be one of the following:

Executing a Subroutine at an Entry Point

How to:

A subroutine is usually executed starting from the first statement. However, a subroutine can be executed starting from any place in the code designated as an entry point. This enables a subroutine to use one basic algorithm to produce different results. For example, the DOWK subroutine calculates the day of the week on which a date falls. By specifying the subroutine name DOWK, you obtain a 3-letter abbreviation of the day. If you specify the entry name DOWKL, you obtain the full name. The calculation, however, is the same.

Each entry point has a name. To execute a subroutine at an entry point, specify the entry point name in the subroutine call instead of the subroutine name. How you designate an entry point depends on the language you are using.

Syntax: How to Execute a Subroutine at an Entry Point

{subroutine|entrypoint}  (input1, input2,...outfield)

where:

subroutine

Is the name of the subroutine.

entrypoint

Is the name of the entry point to execute the subroutine at.

input1, input2,...

Are the subroutine's arguments.

outfield

Is the field that contains the result, or the format of the output value enclosed in single quotation marks.

In Dialogue Manager, you must specify the format. In Maintain Data, you must specify the name of the field.

Example: Executing a Subroutine at an Entry Point

The FTOC subroutine, written in pseudocode below, converts Fahrenheit temperature to Centigrade. The entry point FTOK (designated by the Entry command) sets a flag that causes 273 to be subtracted from the Centigrade temperature to find the Kelvin temperature. The subroutine is:

Subroutine FTOC (FAREN, CENTI).
Let FLAG = 0.
Go to label X.
Entry FTOK (FAREN, CENTI).
Let FLAG = 1.
Label X.
Let CENTI = (5/9) * (FAREN - 32).
If FLAG = 1 then CENTI = CENTI - 273.
Return.
End of subroutine.

The following is a shorter way to write the subroutine. Notice that the kelv output argument listed for the entry point is different from the centi output argument listed at the beginning of the subroutine:

Subroutine FTOC (FAREN, CENTI).
Entry FTOK (FAREN, KELV).
Let CENTI = (5/9) * (FAREN - 32).
KELV = CENTI - 273.
Return.
End of Subroutine.

To obtain the Centigrade temperature, specify the subroutine name FTOC in the subroutine call. The subroutine processes as:

CENTIGRADE/D6.2 = FTOC (TEMPERATURE, CENTIGRADE);

To obtain the Kelvin temperature, specify the entry name FTOK in the subroutine call. The subroutine processes as:

KELVIN/D6.2 = FTOK (TEMPERATURE, KELVIN);

Including More Than 200 Arguments in a Subroutine Call

How to:

A subroutine can specify a maximum of 200 arguments including the output argument. To process more than 200 arguments, the subroutine must specify two or more call statements to pass the arguments to the subroutine.

Use the following technique for writing a subroutine with multiple calls:

  1. Divide the subroutine into segments. Each segment receives the arguments passed by one corresponding subroutine call.

    The argument list in the beginning of your subroutine must represent the same number of arguments in the subroutine call, including a call number argument and an output argument.

    Each call contains the same number of arguments. This is because the argument list in each call must correspond to the argument list in the beginning of the subroutine. You may process some of the arguments as dummy arguments if you have an unequal number of arguments. For example, if you divide 32 arguments among six segments, each segment processes six arguments; the sixth segment processes two arguments and four dummy arguments.

    Subroutines may require additional arguments as determined by the programmer who creates the subroutine.

  2. Include a statement at the beginning of the subroutine that reads the call number (first argument) and branches to a corresponding segment. Each segment processes the arguments from one call. For example, number one branches to the first segment, number two to the second segment, and so on.
  3. Have each segment store the arguments it receives in other variables (which can be processed by the last segment) or accumulate them in a running total.

    End each segment with a command returning control back to the request (RETURN command).

  4. The last segment returns the final output value to the request.

You can also use the entry point technique to write subroutines that process more than 200 arguments. For details, see Executing a Subroutine at an Entry Point.

Syntax: How to Create a Subroutine With Multiple Call Statements

field = subroutine (1, group1, field)
;field = subroutine (2, group2, field);
   .
   .
   .outfield = subroutine (n, groupn, outfield);

where:

field

Is the name of the field that contains the result of the segment or the format of the field enclosed in single quotation marks. This field must have the same format as outfield.

Do not specify field for the last call statement; use outfield.

subroutine

Is the name of the subroutine up to eight characters long.

n

Is a number that identifies each subroutine call. It must be the first argument in each subroutine call. The subroutine uses this call number to branch to segments of code.

group1, group2,...

Are lists of input arguments passed by each subroutine call. Each group contains the same number of arguments, and no more than 26 arguments each.

The final group may contain dummy arguments.

outfield

Is the field that contains the result, or the format of the output value enclosed in single quotation marks.

In Dialogue Manager, you must specify the format. In Maintain Data, you must specify the name of the field.

Example: Creating a Subroutine Divided Into Segments

The ADD32 subroutine, written in pseudocode, sums 32 numbers. It is divided into six segments, each of which adds six numbers from a subroutine call. (The total number of input arguments is 36 but the last four are dummy arguments.) The sixth segment adds two arguments to the SUM variable and returns the result. The sixth segment does not process any values supplied for the four dummy arguments.

The subroutine is:

Subroutine ADD32 (NUM, A, B, C, D, E, F, TOTAL).
If NUM is 1 then goto label ONE
else if NUM is 2 then goto label TWO
else if NUM is 3 then goto label THREE
else if NUM is 4 then goto label FOUR
else if NUM is 5 then goto label FIVE
else goto label SIX.
 
Label ONE.
Let SUM = A + B + C + D + E + F.
Return.
 
Label TWO
Let SUM = SUM + A + B + C + D + E + F
Return
 
Label THREE
Let SUM = SUM + A + B + C + D + E + F
Return
 
Label FOUR
Let SUM = SUM + A + B + C + D + E + F
Return
 
Label FIVE
Let SUM = SUM + A + B + C + D + E + F
Return
 
Label SIX
LET TOTAL = SUM + A + B
Return
End of subroutine

To use the ADD32 subroutine, list all six call statements, each call specifying six numbers. The last four numbers, represented by zeros, are dummy arguments. The DEFINE command stores the total of the 32 numbers in the SUM32 field.

DEFINE FILE EMPLOYEE
DUMMY/D10 = ADD32 (1, 5, 7, 13, 9, 4, 2, DUMMY);
DUMMY/D10 = ADD32 (2, 5, 16, 2, 9, 28, 3, DUMMY);
DUMMY/D10 = ADD32 (3, 17, 12, 8, 4, 29, 6, DUMMY);
DUMMY/D10 = ADD32 (4, 28, 3, 22, 7, 18, 1, DUMMY);
DUMMY/D10 = ADD32 (5, 8, 19, 7, 25, 15, 4, DUMMY);
SUM32/D10 = ADD32 (6, 3, 27, 0, 0, 0, 0, SUM32);
END