In this white paper we describe CobolTransformer in more detail.
Also we provide a concrete example of CobolTransformer use:
(1) Specification for program transformation,
(2) C++ code that performs this transformation,
(3) Program and its expression tree before the transformation.
(4) Program and its source tree after the transformation.
Introduction
Language-wise, CobolTransformer is a C++ library.
This is because C++ is so far the most convenient language
for writing compilers, converters and related tools.
Let us know if you need interface to other languages,
and we will be glad to develop it.
As we said earlier, there are 3 major components in the CobolTransformer library:
(1) Cobol Parser,
(2) C++ library to manipulate the tree-based internal representation,
(3) PrettyPrinter that transforms tree-based Internal Representation
back into Cobol program.
For most Cobol projects you would need all 3 components:
you need to parse, you need to transform, and you need to generate code.
However, for some other projects you would need only 1 or 2 components.
Examples:
-
A tool that computes program metrics such as McCabe or Halstead metrics
would need only parser -- no transformation and no code generation is required.
-
A tool that generates Cobol code from some non-Cobol source
(for instance, from object code) would build a CobolTransformer tree and
will hand it over to the Code Generator.
Here only tree builder and Code Generator are required, and Cobol parser
is not necessary.
Program Representation: Expression Tree
To represent Cobol program, we use expression trees
that are more or less a standard way of representing programs in compilers.
Semantically, our expression trees are midway between
the original Cobol program and the low level assembly code or its varieties.
The design goals for CobolTransformer expression trees were:
-
Make it easy to get to any given part of the Cobol program.
For instance, finding whether Special-Names paragraph is present in the program
does not involve searching thru the multitude of trees.
This paragraph has a known position in the Program Tree.
-
Preserve as much of original program as possible.
For instance, we keep comments attached to the program tree.
Comments do not affect semantics of the program,
but since the user would like to see her comments preserved
in the converted program, we keep the comments intact.
These goals are somewhat contradictory.
For instance, in SCT data item description is represented
by a big node in which there is a slot for every
possible data description clause.
This makes getting to the desired clause easy.
But it violates original ordering of clauses in the source program.
We think that original ordering of the clauses is not that important,
but being able to get to the desired clause easily is important.
A different example: we think that preserving exact image of
Cobol values that appear in the program is important.
If Cobol programmer wrote H'80' in
his MicroFocus program instead of 128
then he did it for a reason (for instance,
he wanted to underscore that this value is a string of bits)
and he would like to see hexadecimal format of a constant preserved.
We think that we were able to achieve a right balance of
syntax and semantics in the design of our Program Tree.
You can get a better idea about CobolTransformer internals
by ordering CobolTransformer manual.
Without getting too deep into intricacies of Cobol tree representation,
we give an example of trees that we use.
Example: Cobol Source.
Consider the following MicroFocus Cobol program.
IDENTIFICATION DIVISION.
PROGRAM-ID. CV-TIME.
* === Data Division starts here ===
DATA DIVISION.
WORKING-STORAGE SECTION.
01 LOCALS.
05 WS-TIME PIC X(6) COMP-X.
05 WS-HRS PIC X(2) COMP-X.
05 WS-MINS PIC X(2) COMP-X.
78 CS-ONE VALUE 1.
78 CS-TWO VALUE 2.
05 WS-SECS PIC X(2) COMP-X VALUE CS-ONE.
05 ST-HRS PIC X(5).
* === Procedure Division starts here ===
PROCEDURE DIVISION.
TIME-CONV.
MOVE 100 to WS-TIME
DIVIDE 60 INTO WS-TIME
GIVING WS-MINS
REMAINDER WS-SECS.
* ++ At the critical juncture ++
IF WS-HRS = 1 MOVE " HR " TO ST-HRS
ELSE MOVE " HRS" TO ST-HRS.
Example: CobolTransformer Expression Tree.
This Cobol program is represented by the following expression tree
(first two numbers at every node line represent
depth of the node and its position as a child of its parent):
COBOL_FILE
1. 0. (NULL)
1. 1. (NULL)
1. 2. (NULL)
1. 3. (NULL)
1. 4. COBOL_PROGRAM_LIST
2. 0. . COBOL_PROGRAM
3. 0. . . DIVISION_IDENTIFICATION
4. 0. . . . PARA_PROGRAM_ID
5. 0. . . . . EX_NAMED_OBJ_DEF CV-TIME cat=program-name
5. 1. . . . . (NULL)
3. 1. . . (NULL)
3. 2. . . DIVISION_DATA Comments {
. . . .
. . . . * === Data Division starts here ===
. . . . } Comments
4. 0. . . . (NULL)
4. 1. . . . (NULL)
4. 2. . . . SECTION_WORKING_STORAGE
5. 0. . . . . DECL_DD_ENTRY_LIST
6. 0. . . . . . DECL_DD_ENTRY
7. 0. . . . . . . EX_INT_NUM_CONST image=01 value=1
7. 1. . . . . . . EX_NAMED_OBJ_DEF LOCALS cat=data-name
7. 2. . . . . . . (NULL)
7. 3. . . . . . . (NULL) children 3 to 14 are all NULL
7.15. . . . . . . EX_DD_CHILDREN
8. 0. . . . . . . . DECL_DD_ENTRY
9. 0. . . . . . . . . EX_INT_NUM_CONST image=05 value=5
9. 1. . . . . . . . . EX_NAMED_OBJ_DEF WS-TIME cat=data-name
9. 2. . . . . . . . . EX_DD_PICTURE
10. 0. . . . . . . . . . EX_CHAR_STRING X(6)
9. 3. . . . . . . . . EX_DD_USAGE
10. 0. . . . . . . . . . EX_DU_COMP_X
9. 4. . . . . . . . . (NULL)
9. 5. . . . . . . . . (NULL) children 5 to 15 are all NULL
8. 1. . . . . . . . DECL_DD_ENTRY
9. 0. . . . . . . . . EX_INT_NUM_CONST image=05 value=5
9. 1. . . . . . . . . EX_NAMED_OBJ_DEF WS-HRS cat=data-name
9. 2. . . . . . . . . EX_DD_PICTURE
10. 0. . . . . . . . . . EX_CHAR_STRING X(2)
9. 3. . . . . . . . . EX_DD_USAGE
10. 0. . . . . . . . . . EX_DU_COMP_X
9. 4. . . . . . . . . (NULL)
9. 5. . . . . . . . . (NULL) children 5 to 15 are all NULL
8. 2. . . . . . . . DECL_DD_ENTRY
9. 0. . . . . . . . . EX_INT_NUM_CONST image=05 value=5
9. 1. . . . . . . . . EX_NAMED_OBJ_DEF WS-MINS cat=data-name
9. 2. . . . . . . . . EX_DD_PICTURE
10. 0. . . . . . . . . . EX_CHAR_STRING X(2)
9. 3. . . . . . . . . EX_DD_USAGE
10. 0. . . . . . . . . . EX_DU_COMP_X
9. 4. . . . . . . . . (NULL)
9. 5. . . . . . . . . (NULL) children 5 to 14 are all NULL
9.15. . . . . . . . . EX_DD_CHILDREN
10. 0. . . . . . . . . . DECL_DD_ENTRY
11. 0. . . . . . . . . . . EX_INT_NUM_CONST image=78 value=78
11. 1. . . . . . . . . . . EX_NAMED_OBJ_DEF CS-ONE cat=data-name
11. 2. . . . . . . . . . . (NULL)
11. 3. . . . . . . . . . . (NULL) children 3 to 12 are all NULL
11.13. . . . . . . . . . . EX_DD_VALUE
12. 0. . . . . . . . . . . . EX_DD_VALUE_LIST
13. 0. . . . . . . . . . . . . EX_INT_NUM_CONST image=1 value=1
12. 1. . . . . . . . . . . . (NULL)
11.14. . . . . . . . . . . (NULL)
11.15. . . . . . . . . . . (NULL)
10. 1. . . . . . . . . . DECL_DD_ENTRY
11. 0. . . . . . . . . . . EX_INT_NUM_CONST image=78 value=78
11. 1. . . . . . . . . . . EX_NAMED_OBJ_DEF CS-TWO cat=data-name
11. 2. . . . . . . . . . . (NULL)
11. 3. . . . . . . . . . . (NULL) children 3 to 12 are all NULL
11.13. . . . . . . . . . . EX_DD_VALUE
12. 0. . . . . . . . . . . . EX_DD_VALUE_LIST
13. 0. . . . . . . . . . . . . EX_INT_NUM_CONST image=2 value=2
12. 1. . . . . . . . . . . . (NULL)
11.14. . . . . . . . . . . (NULL)
11.15. . . . . . . . . . . (NULL)
8. 3. . . . . . . . DECL_DD_ENTRY
9. 0. . . . . . . . . EX_INT_NUM_CONST image=05 value=5
9. 1. . . . . . . . . EX_NAMED_OBJ_DEF WS-SECS cat=data-name
9. 2. . . . . . . . . EX_DD_PICTURE
10. 0. . . . . . . . . . EX_CHAR_STRING X(2)
9. 3. . . . . . . . . EX_DD_USAGE
10. 0. . . . . . . . . . EX_DU_COMP_X
9. 4. . . . . . . . . (NULL)
9. 5. . . . . . . . . (NULL) children 5 to 12 are all NULL
9.13. . . . . . . . . EX_DD_VALUE
10. 0. . . . . . . . . . EX_DD_VALUE_LIST
11. 0. . . . . . . . . . . EX_NAMED_OBJ_USE cat=constant-name
12. 0. . . . . . . . . . . . EX_OF_IN
13. 0. . . . . . . . . . . . . EX_NAME_USE CS-ONE
10. 1. . . . . . . . . . (NULL)
9.14. . . . . . . . . (NULL)
9.15. . . . . . . . . (NULL)
8. 4. . . . . . . . DECL_DD_ENTRY
9. 0. . . . . . . . . EX_INT_NUM_CONST image=05 value=5
9. 1. . . . . . . . . EX_NAMED_OBJ_DEF ST-HRS cat=data-name
9. 2. . . . . . . . . EX_DD_PICTURE
10. 0. . . . . . . . . . EX_CHAR_STRING X(5)
9. 3. . . . . . . . . (NULL)
9. 4. . . . . . . . . (NULL) children 4 to 15 are all NULL
4. 3. . . . (NULL)
4. 4. . . . (NULL)
4. 5. . . . (NULL)
4. 6. . . . (NULL)
4. 7. . . . (NULL)
3. 3. . . DIVISION_PROCEDURE Comments {
. . . .
. . . . * === Procedure Division starts here ===
. . . . } Comments
4. 0. . . . (NULL)
4. 1. . . . (NULL)
4. 2. . . . (NULL)
4. 3. . . . SECTION_PROC_LIST
5. 0. . . . . SECTION_PROC
6. 0. . . . . . (NULL)
6. 1. . . . . . (NULL)
6. 2. . . . . . PARA_PROC_LIST
7. 0. . . . . . . PARA_PROC Comments {
. . . . . . . .
. . . . . . . . } Comments
8. 0. . . . . . . . EX_NAMED_OBJ_DEF TIME-CONV cat=para-name
8. 1. . . . . . . . SENTENCE_LIST
9. 0. . . . . . . . . SENTENCE
10. 0. . . . . . . . . . STMT_LIST
11. 0. . . . . . . . . . . STMT_MOVE
12. 0. . . . . . . . . . . . EX_INT_NUM_CONST image=100 value=100
12. 1. . . . . . . . . . . . EX_LIST_IDENTIFIERS
13. 0. . . . . . . . . . . . . EX_NAMED_OBJ_USE cat=data-name
14. 0. . . . . . . . . . . . . . EX_OF_IN
15. 0. . . . . . . . . . . . . . . EX_NAME_USE WS-TIME
11. 1. . . . . . . . . . . STMT_DIVIDE
12. 0. . . . . . . . . . . . EX_ARITH_DIV_INTO_GIVING
13. 0. . . . . . . . . . . . . EX_INT_NUM_CONST image=60 value=60
13. 1. . . . . . . . . . . . . EX_NAMED_OBJ_USE cat=data-name
14. 0. . . . . . . . . . . . . . EX_OF_IN
15. 0. . . . . . . . . . . . . . . EX_NAME_USE WS-TIME
13. 2. . . . . . . . . . . . . EX_LIST
14. 0. . . . . . . . . . . . . . EX_NAMED_OBJ_USE cat=data-name
15. 0. . . . . . . . . . . . . . . EX_OF_IN
16. 0. . . . . . . . . . . . . . . . EX_NAME_USE WS-MINS
13. 3. . . . . . . . . . . . . EX_NAMED_OBJ_USE cat=data-name
14. 0. . . . . . . . . . . . . . EX_OF_IN
15. 0. . . . . . . . . . . . . . . EX_NAME_USE WS-SECS
12. 1. . . . . . . . . . . . (NULL)
12. 2. . . . . . . . . . . . (NULL)
12. 3. . . . . . . . . . . . (NULL)
9. 1. . . . . . . . . SENTENCE
10. 0. . . . . . . . . . STMT_LIST
11. 0. . . . . . . . . . . STMT_IF Comments {
. . . . . . . . . . . . * ++ At the critical juncture ++
. . . . . . . . . . . . } Comments
12. 0. . . . . . . . . . . . EX_CMP_EQ
13. 0. . . . . . . . . . . . . EX_NAMED_OBJ_USE cat=data-name
14. 0. . . . . . . . . . . . . . EX_OF_IN
15. 0. . . . . . . . . . . . . . . EX_NAME_USE WS-HRS
13. 1. . . . . . . . . . . . . EX_INT_NUM_CONST image=1 value=1
12. 1. . . . . . . . . . . . STMT_LIST
13. 0. . . . . . . . . . . . . STMT_MOVE
14. 0. . . . . . . . . . . . . . EX_STR_CONST " HR "
14. 1. . . . . . . . . . . . . . EX_LIST_IDENTIFIERS
15. 0. . . . . . . . . . . . . . . EX_NAMED_OBJ_USE cat=data-name
16. 0. . . . . . . . . . . . . . . . EX_OF_IN
17. 0. . . . . . . . . . . . . . . . . EX_NAME_USE ST-HRS
12. 2. . . . . . . . . . . . EX_ELSE
13. 0. . . . . . . . . . . . . STMT_LIST
14. 0. . . . . . . . . . . . . . STMT_MOVE
15. 0. . . . . . . . . . . . . . . EX_STR_CONST " HRS"
15. 1. . . . . . . . . . . . . . . EX_LIST_IDENTIFIERS
16. 0. . . . . . . . . . . . . . . . EX_NAMED_OBJ_USE cat=data-name
17. 0. . . . . . . . . . . . . . . . . EX_OF_IN
18. 0. . . . . . . . . . . . . . . . . . EX_NAME_USE ST-HRS
12. 3. . . . . . . . . . . . (NULL)
3. 4. . . (NULL)
3. 5. . . (NULL)
3. 6. . . SYMBOL_TABLE_ELT_LIST
4. 0. . . . EX_SYMBOL_TABLE_ELT DEBUG-CONTENTS cat=special-register
4. 1. . . . special registers skipped
4.10. . . . EX_SYMBOL_TABLE_ELT CV-TIME cat=program-name
4.11. . . . EX_SYMBOL_TABLE_ELT LOCALS cat=data-name
4.12. . . . EX_SYMBOL_TABLE_ELT WS-TIME cat=data-name
4.13. . . . EX_SYMBOL_TABLE_ELT WS-HRS cat=data-name
4.14. . . . EX_SYMBOL_TABLE_ELT WS-MINS cat=data-name
4.15. . . . EX_SYMBOL_TABLE_ELT CS-ONE cat=constant-name
4.16. . . . EX_SYMBOL_TABLE_ELT CS-TWO cat=constant-name
4.17. . . . EX_SYMBOL_TABLE_ELT WS-SECS cat=data-name
4.18. . . . EX_SYMBOL_TABLE_ELT ST-HRS cat=data-name
4.19. . . . EX_SYMBOL_TABLE_ELT TIME-CONV cat=para-name
1. 5. END_OF_COBOL_FILE
1. 6. SYMBOL_TABLE_ELT_LIST
2. 0. . EX_SYMBOL_TABLE_ELT DEBUG-CONTENTS cat=special-register
2. 1. . special registers skipped
Browsing and Transforming Expression Trees
There is a number of functions available in CobolTransformer that let
you browse and transform expression tree:
-
Constructors and Destructors.
-
Tree browsing: children, parent; set, add, delete, insert, find a child.
-
Print indented view of a tree for debugging (like the one shown above).
-
Tree flattening (marshaling) and unflattening:
output tree to a file, or send it across the network.
-
Comments attached to tree nodes.
-
User-defined objects attached to the tree nodes.
-
Symbol Table for every Program.
List of all Definitions for a given Name.
-
Links from Use to Definition and from Definition to all Uses
for every Named Object.
-
Generate Fully Qualified Name for a given Definition,
or Shortest Unique Qualified Name for a given Definition.
-
Rename Named Object Definition and all its Uses.
With this seemingly simple set of functions you can perform
complicated transformations, as demonstrated in the following example
(this is a fragment of the actual working code that you can download
from the Free Evaluation Page).
Sample Transformation Spec.
Perform the following transformations
(these conversions are a part of MicroFocus to Fujitsu converter):
-
Move 78-level MF constant definitions to Symbolic Constant
clause of Special-Names paragraph (Fujitsu Cobol feature).
If Special-Names paragraph is not present, create it.
If Configuration section is not present, create it.
If Environment division is not present, create it.
-
Convert USAGE COMP-4 data items into USAGE BINARY data items,
-
Convert USAGE COMP-X data items into USAGE COMP-5 data items,
-
In USAGE COMP-5 data items convert PIC X(n) to PIC 9(2*n).
To be more exact, number of 9-s is computed from number of X-s
based on the following table:
conv_x_to_9[] = {0,2,4,7,9,12,14,16,18}
Example: Transformation in C++.
The following C++ program performs the above transformations
(not bad! : these non-trivial transformations are
expressed in only 130 lines of C++, including comments):
void ProcessProgram(SctExpr *const e, SctExpr *const) {
if(e->Oper()==COBOL_PROGRAM) {
psym_consts = NULL;
SctExpr *e1 = e;
void ProcessNode(SctExpr *&e, SctExpr *base);
WalkTheTreeModRoot(e1, e1, ProcessNode);
}
}
void ProcessNode(SctExpr *&e, SctExpr *base) {
if(e->Oper()==DECL_DD_ENTRY &&
e->Args(DD_LEVEL)->Value()=="78" &&
e->Args(DD_VALUE)!=NULL) {
if(conv_warn) {
PWarning(parser.curr_posn,
"Moved 78-level constant to Symbolic Constants");
}
SctExpr *ne = new SctExprOper(EX_SN_SYMB_CONST,
e->DelArg(DD_DATA_NAME,FALSE),
e->Args(DD_VALUE)->DelArg(0,FALSE));
ne->comments.merge_last(e->comments);
delete e;
e = NULL;
if(psym_consts==NULL) {
SctExpr *be;
if(base->Args(1)==NULL) {
base->SetArg(1, new SctExprOper(DIVISION_ENVIRONMENT,
ENULL,ENULL));
}
be = base->Args(1);
if(be->Args(0)==NULL) {
be->SetArg(0, new SctExprOper(SECTION_CONFIGURATION,
ENULL,ENULL,ENULL,ENULL));
}
be = be->Args(0);
if(be->Args(2)==NULL) {
be->SetArg(2, new SctExprOper(PARA_SPECIAL_NAMES,
0, SN_ARG_NO));
}
SctExpr *re = be->Args(2);
be = new SctExprOper(EX_SN_SYMBOLIC_CONSTANT, ENULL);
re->SetArgToList(SN_SYMBOLIC_CONSTANT, EX_LIST, be);
psym_consts = be;
}
psym_consts->SetArgToList(0, EX_SN_SYMB_CONST_LIST, ne);
return;
}
if(e->Oper()==DECL_DD_ENTRY) {
SctExpr *eusg = e->Args(DD_USAGE);
if(eusg && eusg->Args(0)) {
eusg = eusg->Args(0);
switch(eusg->Oper()) {
case EX_DU_COMP_4:
eusg->SetOper(EX_DU_BINARY);
break;
case EX_DU_COMP_X:
eusg->SetOper(EX_DU_COMP_5);
if(conv_warn) {
PWarning(parser.curr_posn, "Convert COMP-X to COMP-5");
}
/* FALL THRU to COMP_5 here */
case EX_DU_COMP_5:
{ SctExpr *epic = e->Args(DD_PICTURE);
if(epic==NULL) break;
epic = epic->Args(0);
int length = 0;
PicCategory pcat = ParsePicString(epic->Image(), length);
if(pcat==PIC_ALPHA_NUM && length>=1) {
int conv_x_to_9[] = {0,2,4,7,9,12,14,16,18};
int no_9 = conv_x_to_9[length];
VString ns = vfmt("9(%d)", no_9);
if(conv_warn) {
PWarning(parser.curr_posn,
vfmt("Convert COMP-5: PIC %s to PIC %s",
epic->Image().pchar(), ns.pchar()));
}
epic->Image() = ns;
}
}
break;
default:
break;
}
}
}
}
Externalizing Expression Trees
Sometimes you need to write expression trees to external media,
such as files, streams, strings, or read them back into
converter from external media.
For these purposes we have intermediate representation called
Transformer Intermediate Code (TIC).
TIC is a machine-readable platform-independent ASCII representation of
a CobolTransformer Expression Tree.
The TIC is based on postfix Polish notation.
Cobol Parser
CobolTransformer Parser is a fairly complicated function that
parses your Cobol source into Expression Tree.
If you think that your Program Trees are going to be so big that they
will not fit in memory, then you can define tree processing function
that will be called every time when parser finished parsing
a sizable fragment of a program (in procedure division this fragment would be a Section).
Your expression processing function is expected
to save this tree fragment to a file for later processing
and free memory that it occupies.
The combined Cobol grammar is 7,500 lines long and
it is written in BtYacc
-- Backtracking Yacc, developed by Chris Dodd from the regular Yacc
and enhanced by Siber Systems to work in production environment.
We decided to use BtYacc because Cobol grammar cannot be
fully described with LALR(1) grammar used by plain vanilla Yacc.
The following Cobol dialects are currently supported:
-
ANSI-74 Cobol
-
ANSI-85 Cobol
-
IBM OSVS Cobol
-
IBM Cobol/II
-
IBM Cobol SAA
-
Unix Cobol X/Open
-
MicroFocus Cobol
-
Microsoft Cobol
-
Ryan McFarland RM/COBOL
-
Ryan McFarland RM/COBOL-85
-
DOSVS Cobol
-
Wang (licensed separately).
We use the following documents as a source of Cobol definition:
-
ANSI X.23-1985 standard "Programming Language Cobol".
-
MicroFocus Cobol Language Reference. Issue 13, 1993.
-
IBM VS COBOL II Language Reference Manual.
-
Wang VS COBOL 85 Reference Manual.
-
Fujitsu Cobol 85 Reference Manual.
CobolTransformer and Cobol Compilers
CobolTransformer is based on compiler technology.
That is, techniques that we use in CobolTransformer are
generally accepted in compiler community.
However, CobolTransformer has several important features
that usually are not available in the standard compilers:
- Preserve Comments
-
Since CobolTransformer can be used for Cobol to Cobol
transformation, it is important to preserve comments
present in the original program.
It is achieved by attaching comments to the expression tree
representing the program.
- Preserve COPY statements
-
Standard compiler needs to visit all the COPYLIB files mentioned
in COPY statements in your Cobol program.
If one of the COPYLIBs cannot be found, standard compiler gets confused
and no object code is generated.
CobolTransformer can recover from un-inlined COPY statements.
Even more, it can preserve COPY statements on a program tree,
so that you can perform program transformation even if not
all COPYLIBs are available.
- Keep Token Text Positions
-
Every token in a Cobol program has a position in the text file.
Text position is identified by [file name, line number, column number]
triplet.
CobolTransformer has these positions available for every token,
which is convenient for error diagnostics and building
syntax-aware Cobol browsers and editors.
Other parser highlights:
-
Parsers for embedded languages:
DMS-80/1100 DML, EXEC SQL, EXEC CICS.
-
The parser is tested on millions of lines of Cobol code.
Extensive regression testing daily.
-
Full implementation of COPY REPLACING and REPLACE statements.
-
-INC statement implemented.
-
User-defined error diagnostics routines.
Cobol PrettyPrinter
When you finish transforming Cobol program expression tree,
you need to convert this tree back into Cobol source form.
This is when you call PrettyPrint function.
PrettyPrint function uses Code Generation table to print out
the expression tree.
There is an entry for every Cobol tree operation in this table.
The entry contains text that represents this operation.
In this text you can embed special characters that control
formatting and printing of operation and its arguments.
We supply default Cobol Code Generation table.
For your particular project you can override some entries in this table
with your own entries that print certain operations differently.
Sample Converted Cobol program.
Once transformations described in the previous section are
applied to the program tree, and the resulting tree is PrettyPrinted,
we get the following Cobol program:
@OPTIONS BINARY(BYTE)
IDENTIFICATION DIVISION.
PROGRAM-ID. CV-TIME.
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
SPECIAL-NAMES.
SYMBOLIC CONSTANT
CS-ONE IS 1
CS-TWO IS 2.
* === Data Division starts here ===
DATA DIVISION.
WORKING-STORAGE SECTION.
01 LOCALS.
05 WS-TIME PIC 9(14) COMP-5.
05 WS-HRS PIC 9(4) COMP-5.
05 WS-MINS PIC 9(4) COMP-5.
05 WS-SECS PIC 9(4) COMP-5
VALUE CS-ONE.
05 ST-HRS PIC X(5).
* === Procedure Division starts here ===
PROCEDURE DIVISION.
TIME-CONV.
MOVE 100 TO WS-TIME
DIVIDE 60 INTO WS-TIME GIVING WS-MINS REMAINDER WS-SECS.
* ++ At the critical juncture ++
IF WS-HRS = 1
MOVE " HR " TO ST-HRS
ELSE
MOVE " HRS" TO ST-HRS
END-IF.
Some of the code generation table entries that
were used in printing this program are:
_e(COBOL_PROGRAM, NULL,
"{$1?$1}{$2?$2}{$3?$3}{$4?$4}{$5?$5}{$6?$6}"),
_e(DIVISION_PROCEDURE, NULL,
"PROCEDURE DIVISION{$1? $1}{$2? $2}.\n\r$3$4"),
_e(SECTION_PROC_LIST, NULL, "\r@"),
_e(SECTION_PROC, NULL, "$1 SECTION{$2?|$2}.\n\r$3"),
_e(PARA_PROC_LIST, NULL, "\r@"),
_e(PARA_PROC, NULL, "$1.\n\r$2"),
_e(SENTENCE_LIST, NULL, "\r@"),
_e(SENTENCE, NULL, "\r\t$1.\b\n"),
_e(STMT_LIST, NULL, "\r@\n"),
_e(STMT_MOVE, ManyMoveArgs, "MOVE $1\n TO $2"),
_e(STMT_MOVE, NULL, "MOVE $1|TO $2"),
_e(STMT_MOVE_CORR, NULL, "MOVE CORRESPONDING $1|TO $2"),
_e(STMT_MULTIPLY, NULL,
"MULTIPLY $1{$2?\n$2}{$3?\n$3}{$4?\n$4}"),
_e(EX_ARITH_MUL_BY, NULL,
"$1|BY $2"),
_e(EX_ARITH_MUL_BY_GIVING, NULL,
"$1|BY $2|GIVING $3"),
_e(EX_END_MULTIPLY, NULL,
"END-MULTIPLY"),
_e(STMT_IF, NULL,
"IF $1{$2?\n\t$2\b}{$3?\n$3}{$4?\n$4}"),
_e(EX_ELSE, isElseIf, "ELSE \r$1"),
_e(EX_ELSE, NULL, "ELSE\n\t$1"),
_e(EX_END_IF, NULL, "END-IF"),
int ManyArgs(Expr *e) {
e = e->Args(0);
return e->Oper()==EX_LIST_IDENTIFIERS && e->ArgNo()>=2;
}
Proceed To
|