Copyright 2001 by Peter Flass. Permission is granted to distribute unmodified copies of this document. Please do not make local modifications. Suggest changes to the maintainer.
The first line of each program or package should be a comment containing the name and a short description of the program. Many compilers will display the first line in a heading on each page.
Each external procedure or package should begin with a comment block noting the purpose of the procedure and adding additional descriptive information. This description should be defined by installation standards and/or the intended use of the procedure, but may contain some or all of the following information:
Use the preprocessor %PAGE statement to force long procedures, DO and SELECT groups, etc. to begin on a new page set off by comments briefly describing the section. For easy reading a logical function should be no longer than about two pages (120 lines of code).
It is not necessary to code a comment per line as in assembler. Logical functions within the code should be indicated by appropriate comments and separated by whitespace. Comments should say what is being done, and not how it is done.
Label long DO and SELECT statements and terminate them with the END <label> form of the END statement. Alternatively, use comments on END statements to indicate what the END refers to. A loop headed
DO WHILE(a); could be ended END; /* DO WHILE */ or END; /* DO WHILE(a) */
When coding comments on the same line as code, try to maintain consistent column positions for the /* and the */ from line to line.
Each comment line should be self-contained - contain both /* and */.
Comment null statements used as actions in THEN, WHEN, or OTHERWISE to indicate that this is intended and not an error. (See Example).
Whitespace is vital to readability. Too much as well as too little whitespace can make a program difficult to read.
Some programmers like to use blank lines to delimit related sections of code. A DO group of more than a line or two could have blank lines before the DO and after the END.
Too much whitespace eats up screen real estate when editing a program or spreads a listing over too many printed pages to be easily followed.
The attached example illustrates a suggested use of comments and whitespace, as well as other style suggestions.
Some compilers use the first column of each line as a forms-control character for the program listing. This should be considered non-portable. Use of preprocessor listing control statements (%PAGE, %SKIP) is preferable.
Indentation helps to distinguish related sections of a program. Code only one statement per line. Use consistent indentation (e.g. four spaces, or one tab-stop) to identify nested control structures. If indentation becomes excessive this is an indication that structures are nested too deeply and some code should be moved to a procedure and called.
There are two systems for relating ENDs to block headers. The first system places the END in the same position on a line as the corresponding block header, with the body of the block indented. The second indents all of the block including the END, and places the first statement following the block in the same column as the block header (see Example). Whichever system is used should be used consistently.
Align IF to the same column as the associated THEN and ELSE . The exception to this is a "laddered" if statement:
IF condition1 THEN statement1; ELSE IF condition2 THEN statement2; ELSE ...which might be aligned with all the ELSEs in the same column as the IF and the initial THEN. Note that this statement is exactly the same as a SELECT:
SELECT; WHEN(condition1) statement1; WHEN(condition2) statement2; OTHERWISE ... END; /* select */which is preferable.
Indent WHEN and OTHERWISE from the SELECT. Place a short one-statement action on the same line as the WHEN or OTHERWISE, otherwise place it on the next line indented from the WHEN.
Comments describing a section of code should be indented to the same column position as the code.
Declare one structure element per line. Use indentation to show the structuring. Some programmers like to skip level numbers in declarations (1,5,10 instead of 1,2,3) to allow for future modifications.
Keep declarations simple; minimize factoring of attributes. Declare one variable or a set of variables with identical attributes per declaration statement.
Organize declarations. For example, code parameter declarations first, then file declarations followed by local DYNAMIC storage, with declarations of EXTERNAL items at the end. Using a consistent scheme makes it easy to locate information.
Use standard card columns for declarations. One possibility is to begin DCL in column 2, variable names in column 10, and attributes in column 30, aligned if more than one line is required for the attributes.
Declarations can be placed at the start or the end of a procedure. Wherever they are placed they should be grouped together and not scattered throughout the procedure. One exception to this is that some programmers like to declare "their" data at the start of a procedure and %INCLUDEs for standard data at the end. This has the advantage that the standard definitions are easy to bypass when looking at a listing.
Place ON statements at the beginning of the program following the declarations and immediately prior to the first other executable statement. If proper operation of the program requires a different placement, comments should be used to indicate this.
Do not use multiple block termination. Each block or group should have its own END statement.
Always include an OTHERWISE clause in a SELECT-group. The default system action is to issue a not-particularly-helpful error message and terminate the program. If nothing else you might want to print the value of the expression causing the error, or specify a null statement as the action.
%DECLARE array_size CHARACTER; %array_size='5'; DECLARE an_array (array_size) FIXED;will allow the compiler to generate the most efficient code for references to an_array, as opposed to declaring it CONTROLLED with dimension(*) and allocating it or passing array_size as a parameter.
It is obviously more efficient to select code to be generated at compile time rather than test at run-time:
%DECLARE debug CHARACTER; %debug='YES'; %IF debug='YES' %THEN %DO; Generate debug code here ... %END;
Declare and initialize all preprocessor variables before the start of the program if possible. Document the use of all preprocessor variables as program parameters.
IF denom=0 THEN DO; /* whatever is required */ END; ELSE result = num / denom;
Do the minimum possible processing in an ON-unit. Try to keep ON-units to a single statement:
ON ENDFILE(SYSIN) eof='1'b;Be sure to disable the condition being handled in an ON-unit to prevent recursive errors.
ON ERROR BEGIN; ON ERROR SYSTEM; /* blah, blah, blah */ END; /* ON ERROR */
/* Array size changed from 10 to 25 - 31 Dec 2001 */
Col: .........1.........2.........3.........4.........5.........6.........7.........8 /* EXAMP: This program illustrates style suggestions */ /********************************************************************/ /* */ /* Module: EXAMP */ /* Author: Peter Flass, 6 Jun 2001 */ /* Purpose: This is a do-nothing program that illustrates some*/ /* of the the style suggestions in this document. */ /* Modifications: */ /* V1.0 - 7 Jun 2001 - change for blah, blah, blah */ /* */ /********************************************************************/ EXAMP: procedure(parm) options(main); /********************************************************************/ /* Declare a major data structure like this */ /********************************************************************/ dcl 1 a_major_data_structure, 2 a_minor_structure, /*V1.0*/ dcl (name1,name2) fixed bin(15,0) based(a_very_very_long_data_name); dcl name3 fixed bin(15,0); ... %page; /********************************************************************/ /* Indicate a major program block like this */ /********************************************************************/ call initialize; if a=1 /* Comment null statements used as actions */ then /* do nothing */ ; else blah, blah, blah ... call process_the_data; call finish_up; return; %page; /********************************************************************/ /* Initialize: Describe the function of the 'initialize' */ /* procedure in this comment ... */ /********************************************************************/ initialize: procedure; /*---------------------------------*/ /* Use distinctive comments to set */ /* off smaller program sections. */ /*---------------------------------*/ do i=1 to 5; /* This illustrates one indentation scheme */ some stuff /* Use one or the other, not both */ some more stuff end; /* do i */ next statement... do j=1 to 5; /* This is the second indentation scheme */ some stuff some more stuff end; /* do j */ next statement... call scan_parms; Do some stuff here ... /*---------------------------------*/ /* Etc., etc. */ /*---------------------------------*/ Maybe do some more stuff ... call open_files; end initialize; end EXAMP;
Thomas, Edward J. and Oman, Paul W. | |
"A Bibliography of Programming Style" | |
ACM SIGPLAN Notices, Feb 1990; 7-16. |
Version 1.0b Sep 2009 (editorial changes) |