To overcome this problem, we generate for a given grammar generic analysis and transformation functions [15] that can be specialized for different applications. For each sort in the grammar we generate a separate analysis and traversal function. The names of these functions are derived from the sort name used in the grammar. Here, again, we generate functionality that is as natural as possible for the people who need to work with these generated analysis and transformation functions in a renovation factory. As default behaviour, the generic analysis function performs a generic calculation for each subtree encountered, whereas the generic transformation function performs the identity transformation. This default behaviour can be easily redefined for each sort of subtree. In this way, it is only necessary to define what should happen for certain subtrees independently of where they occur.
An example may clarify the issues involved. Suppose we want to change
patterns of the form shown in Figure 3 into more
structured COBOL fragments not containing GO TO statements.
For this purpose we want to define a traversal function foo.
Our generator for analysis and transformation functions will produce
for each sort S in the COBOL grammar the syntax and
(transformation) semantics for the function foo_S
. Its default
behaviour is the identity transformation. In our example we only need
to specify the behaviour on COBOL paragraphs (e.g.,
foo_Paragraph
) as is done in Figure 4. This simple
transformation will transform all GO TO statements that are in
fact while loops. The idea is that only for the sort Paragraph
there is non-default behaviour: a change should only be made when this
specific GO TO pattern is matched. While loops are represented
in COBOL by way of the PERFORM UNTIL statement. Elimination
of GO TO statements in COBOL is further described
in [17].