Learn how to make your COBOL programs smaller, faster, more portable, and more maintainable also!
Contents
-
Program Structure
- Data
-
Code
-
Directives
Program Structure
otherwise known as control flow
Your program should be considered as a collection of logically separate
procedures. Each procedure should be commented with respect to its input
and output and function. There is no trickle through - instead each procedure
is invoked using perform.
The section is the procedure, the section name the procedure name. If
you like, think of sections as Pascal procedures, or C void functions.
Paragraphs are internal labels that should be regarded as not visible
outside the section in which they are used. perform is the function/procedure
call.
To achieve this model there are some easy rules.
| Do use |
perform section
goback at end of first section - must be inline code |
| Do NOT use |
alter
perform thru
next sentence
segments
go to section-name
perform paragraph
go to paragraph outside current section |
| You may use |
go to paragraph within a section. |
Programs that follow these guidelines are known as well-behaved, or (well)
structured. Well-behaved programs are faster to generate, produce smaller
and faster code, and are easier to understand. A win-win-win situation.
It is vitally important to use goback [ returning ...
] or stop run as the last statement of the first section. This
makes it is impossible for control to trickle into subsequent sections,
which allows the ncg to generate smaller and faster code for performs.
Other miscellaneous control flow guidelines are
-
goto depending
-
Fast, efficient, but can be confusing. Ensure all targets are within the
section
-
evaluate
-
Do not use an expression in the evaluate clause. Use a temporary.
when
clauses should be ordered so that the most likely cases come first.
Data
Align, align, ALIGN !
On ALL chips, you must align 2 byte data items on 2 byte boundaries,
4 byte items on 4 byte boundaries. Increasingly, it pays to align larger
data items on 8 byte boundaries. Misaligned data takes longer to load and
store and may require more instructions. When a misaligned item is an operand
and the target of arithmetic (ie add a to b) then you get the penalty twice.
The situation will only get worse with new chips and new versions of existing
chips
| Chip |
Cycles to store pic x(4) comp-5 |
Additional Instructions for misaligned |
| aligned |
misaligned |
| Pentium |
1 |
4 |
| RS6000, PowerPC |
1 |
2 |
| MIPS |
1 |
2 |
1 |
| HP PA |
1 |
7 |
6 |
| Sparc, Alpha |
1 |
10 |
9 |
| Itanium |
1 |
4 |
8 |
Arrays
An array should have a stride (ie total length of 1 table item) that is
a multiple of 4 bytes. This means the alignment of all the subscripted
items can be calculated. Ideally the stride is a power of 2.
Arithmetic data
comp is slow on all lohi platforms. This includes all Windows and NT platforms.
The bytes need to be swapped. Use comp-5 for speed - comp-x for portable
data files. Use 1, 2 or 4 byte items. Use integers.
Alphanumeric
Alphanumeric items should be a multiple of 4 or 8 bytes where possible.
Code
Arithmetic
Try to use unsigned comp-5 items that are the same size. Add and subtracts
can have multiple sources, targets and giving clauses (beware of subscripted
items though). Add and subtract are always optimised in computes. The optimal
length is 4 bytes. Try to avoid conversions to/from display and comp-3
items.
Comparisms against the literal zero are usually the most efficient.
Comparisms for (in)equality are usually more efficient than compare for
ordering, particularly on lohi machines (ie Pentium).
Multiply is expensive - divide is exorbitant - divide remainder is prohibitive.
You have been warned. Multiply by small literal values however is usually
reasonable. Multiplication/division by powers of 2 is optimised.
The Cobol rules on the precision of intermediate results are why 2 operand
statements are in general better. In particular
if a + b > c
must be evaluated for 5 bytes (in effect 8) assuming that either a or b
is 4 bytes.
evaluate a + b
is evaluated for every single when clause. Use
compute c = a + b
evaluate c
Alphanumerics
Comparisms for (in)equality is faster than comparing for ordering, especially
on lohi chips such as Pentium. Alphanumeric items should be multiples of
4 bytes long, and be 4 byte aligned. Variable length moves (ie ref-mod
where the length is a variable) are slower than fixed length as they must
be done byte by byte. Also - there is no possibility of loop-unrolling
and an additional check must be done for 0 length moves.
Calls and files and environment variables
Be consistent in the case you use for calls, filenames and environment
variables. Unix and C are case-sensitive. Lower case is the norm for filenames
and upper case for environment names. Some modules are in upper case, such
as PANELS and FHREDIR. Be sure to use the correct case. Use call literal
in preference to call data name. The same applies to
set procedure-pointer to entry.
Do not include extensions or paths - use $COBPATH if files are not in the
same directory.
Do not use PC_ calls or call by number - use the appropriate CBL_ routines
which also use comp-5. This gives portability and better performance on
all platforms.
call on overflow implies that the called program may not be
there. Therefore in .o (.obj) a static reference cannot be produced. If
an
on overflow clause is there only for .int/gnt environments,
and you know the modules will be linked then use call convention 8.
Call parameters should be 01 level items, and subprograms generated
lnkalign. Do not rely on knowing how many parameters have been passed to
subprogram. This is very expensive. If different sub-functions have a different
number of parameters, determine this from a sub-function argument.
Entry points and parameters
Parameter processing is most efficient when a program is generated notypecheck nolnkcheck noparamcountcheck.
Better still - use nocheck.
Do not use
if address of <parameter> = NULL
which requires paramcountcheck
If you absolutely have to use this syntax, then any call that does not
supply this parameter should pass by value NULL instead.
Do not use by value parameters with length > 4 bytes. This is not portable.
Coding style
This is all subjective of course - but this works for me.
- Use all scope-delimiters.
Enforce by
$ set noimplicitscope change-message(1227 E)
The ANS85 scope-delimiters are optional. A construct, eg if, nested
inside another, ie evaluate, is terminated by end-evaluate
or when. This is confusing and potentially buggy. Use the delimiters.
-
Only use '.' to delimit paragraphs and sections
'.' can be the source of many and subtle and devious bugs. How many
times has an extra "." caused a compilation error (if you used scope delimiters)
or worse - a run time bug (if you did not). Have you ever added code to
the end of the section only to get a compilation error because you forgot
the '.' I use
. process-line section.
. proc-line-loop.
to declare sections and paragraphs. This keeps all the '.' on one line,
and neatly delineates the section name.
-
Avoid goto by using
-
in-line performs
-
exit section
-
exit perform
-
exit perform cycle
-
Replace multiple else if by evaluate true.
evaluate
true is just as efficient as if ... else if. It is more readable
, and your code does not inexorably creep across the page and off the right
margin.
-
align end-verb with verb, and when with evaluate
-
Use typedefs and call prototypes.
typedefs and call prototypes are used in almost all languages since
ALGOL 60. They enforce good coding style and eliminate a lot of bugs. Enforce
adherence to call prototypes by using
$set change-message(1056 E 1057 E 1058 E 1059 E)
If you need to override the prototype for some reason (eg the checker sometimes
does not accept value pointer as equivalent to
reference pointed-to
use
$set change-message(1057 N)
See also the checker directive PROTOTYPE.
Directives
| checker |
noalter |
improves checker speed |
| noseg |
improves checker speed |
| noqualproc |
improves checker speed
catch identical and confusing paragraph names |
| nocheck |
turn off run time checking |
| ncg |
nocheck |
turn off run time checking |
| opt |
turn on global optimisations |
| lnkalign |
guarantees linkage items are aligned |