HP 3000 Manuals

Additional Generator Concepts [ VIRTUOSO CODE GENERATOR Reference Manual ] MPE/iX 5.0 Documentation


VIRTUOSO CODE GENERATOR Reference Manual

Additional Generator Concepts 

This section includes a discussion of important generator concepts,
including scoping, multiple use of an entity type in a relationship type,
and formatting modes.

Scoping 

The "scope" of a keyword indicates the accessibility of the keyword.  For
example, a keyword introduced in a macro is not normally accessible
outside that particular macro.  Virtuoso's use of scoping allows the same
keyword to be used in different nested levels.  If all keywords were
considered global to the source, a nested #for might change the value of
a keyword which is still needed after the nested #for is complete.
Scoping eliminates this problem.  Another benefit of scoping is to reduce
the stack space usage of the generator.  This helps to reduce stack
overflow problems in large Virtuoso programs.

With scoping there may be a different value for a keyword such as
image-dataset in several different scoping levels.  The concept of
scoping is analogous to local variables in Pascal procedures.

There are three Virtuoso constructs that create a scope level:

 *  #for/#endfor

 *  macro calls

 *  #block/#endblock

Thus, when you nest #for constructs, you nest scoping levels as well.
The #block/#endblock construct can be used by programmers to create a
scope around any sequence of Virtuoso statements as long as it does not
overlap other constructs that define a scope.  However, #block/#endblock
can contain other scopes.  For example, you can nest a #for/#endfor
within a #block/#endblock.  You can use the #block and #endblock
constructs to define a scope for keywords and also to reduce the number
of active keywords.  Using these constructs provides control over space
allocation, so that keywords no longer active can have space
re-allocated.

When Virtuoso attempts to find the value of a keyword, it looks in the
current scope first, then in the immediate outer scope, and then in the
scopes beyond that.  Thus, a keyword can be read by all scopes which are
nested within its own scope, but the same keyword is unknown to outer
scopes.  For example, a #for can read the value of a keyword in an outer
scope.  Parameter replacement can do this also.  However, keywords
defined within a #for/#endfor loop are not known to the scopes outside
that loop.

Conversely, when Virtuoso assigns a value to a keyword, it affects only
the keyword in the current scope.  Thus, you can define the same keyword
in different scopes and each will have a distinct value.  For example,
the #let construct only affects keywords in the current scope.  If the
keyword does not already exist, it is created.  Otherwise, the value of
the keyword in the current scope is modified.

A keyword defined within an inner scope is not accessible to outer scopes
unless it is returned to the previous preceding scope through the
#returnvalue construct.  The #returnvalue construct is similar to a #let,
except that it acts in the immediately preceding outer scope.  If the
keyword does not already exist, it is created.  Otherwise,the value of
the keyword in the #returnvalue is modified in the outer scope.

The following example illustrates keyword scoping:

Generator Input: 

     #let image-dataset="PRODUCT"
          .
          .
     #for module="ORDCUST" image-dataset=? relclass="accesses"  }
                                                                } Inner Scope
          MOVE SPACES TO   !image-dataset!-DATA                 }
     #endfor                                                    }

          MOVE SPACES TO   !image-dataset!-DATA

     System Dictionary Definitions: 
     MODULE accesses IMAGE-DATASET 

     ORDCUST accesses CUSTOMER
     ORDCUST accesses SALES

     Generated Output: 

          MOVE SPACES TO   CUSTOMER-DATA

          MOVE SPACES TO   SALES-DATA

          MOVE SPACES TO   PRODUCT-DATA

The preceding example contains two scopes.  The keyword image-dataset is
defined in both scopes.  The inner scope is created by the #for/#endfor
constructs.  Within this scope, the value of image-dataset is that
retrieved from the System Dictionary.  In the outer scope, the #let
construct assigns the value "PRODUCT" to image-dataset.

The first output is generated by the inner scope.  In the first loop, the
value of image-dataset is "CUSTOMER"; in the second loop, the value is
"SALES".  When the #for loop completes, the inner scope vanishes, and the
code is now generated in the outer scope.  The value of image-dataset is
now "PRODUCT", since this was the value assigned before the execution of
the inner scope.

If a keyword must be known outside the level of scoping, use the
#returnvalue construct.  The following example shows the use of this
construct.  Note that this example uses the same System Dictionary
definitions shown in the previous example.

Generator Input: 

     #let image-dataset="PRODUCT"
          .
          .
     #for module="ORDCUST" image-dataset=? relclass="accesses"

          MOVE SPACES TO   !image-dataset!-DATA

     #    returnvalue image-dataset="!image-dataset"
     #endfor

          MOVE SPACES TO   !image-dataset!-DATA

     Generated Output: 

          MOVE SPACES TO  CUSTOMER-DATA

          MOVE SPACES TO  SALES-DATA

          MOVE SPACES TO  SALES-DATA

In the above example, the #let statement assigns the value PRODUCT to the
keyword image-dataset.  This is the first level of scoping.

The #for statement creates a second level of scoping.  The #for construct
retrieves all of the image-dataset values from the System Dictionary.  In
this case, there are two values, CUSTOMER and SALES. At the end of the
second loop, the value of image-dataset in the inner scope is SALES. The
#returnvalue construct assigns this value to the keyword image-dataset in
the outer scope, changing it from PRODUCT to SALES. Thus, the keyword
value is SALES for the last COBOL MOVE statement.

When there are many levels of scoping, it can be difficult to determine
which keywords are active in a particular scope.  The #printkeywords
construct can be used to print all currently active keyword-value pairs
defined for the current scope, as well as the keyword values of all outer
scopes.  This information is sent to the generator listing file.  See the
description of this construct in Chapter 3 for more information and an
example #printkeywords display.

More information on scoping as it pertains to specific constructs is
included in the descriptions of those constructs in Chapter 3.

Multiple Use of an Entity Type in a Relationship Type 

Some System Dictionary database relationships such as "chains" involve
identical entity types.  A chain includes a database, two datasets
(detail and master), and two elements (search and sort).  When the #for
construct retrieves such a relationship, there must be a way to
distinguish between identical entity types.  This is done by appending :n 
to the entity type keyword, where n is the order in which that particular
entity type appears in the construct.

The following example illustrates the use of #for with identical entity
types:

     #for image-dataset=? element=? element=? &
     #    image-dataset=? image-database="ORDERS" &
     #    relclass="chains"
           MOVE !element:1 TO !element:1!-DATA
           MOVE !element:2 TO !element:2!-SORT
     #endfor

Suppose the database ORDERS is in the following TurboIMAGE database
chain:

     image-dataset:1   (detail)           = ORDERS-DETAIL
     element:1         (search element)   = ORDERS-NUMBER
     element:2         (sort element)     = ORDERS-CODE
     image-dataset:2   (master)           = MAIN-DATASET
     image-database                       = ORDERS

Then the output would appear as follows:

           MOVE ORDERS-NUMBER TO ORDERS-NUMBER-DATA
           MOVE ORDERS-CODE TO ORDERS-CODE-SORT

Formatting Modes 

There are three formatting modes for code generated by Virtuoso:  COBOL,
TEXT and OVERLAY. The mode to be used can be specified in the #option
construct or in the :RUN command invoking the Virtuoso Generator.  COBOL
is the default mode, and it is used for generating COBOL code.  TEXT
provides line-level formatting, and it is commonly used to generate
documentation.  OVERLAY mode is intended for generating columnar type
reporting.

In COBOL textmode, spacing is preserved in parameter replacement, and
lines are wrapped if the text extends beyond column 72 after parameter
replacement.  Wrapped lines conform to COBOL syntax rules, and columns
1-6 contain generated COBOL sequence numbers.  Also, columns 73-80 are
preserved and are appended to any extra output lines generated due to
line wrapping.

TEXT textmode provides line wrap-around, and truncation of text is
avoided.  Input is not forced to align, and white space is preserved when
replacing parameters.

OVERLAY textmode truncates lines exceeding 80 columns.  Text from
parameter replacement is also truncated if it exceeds the space allowed
for it.

This section discusses all three textmodes and includes several examples
of each.

COBOL Textmode.  If textmode = COBOL, the number of spaces between words
is preserved during parameter replacement and lines extending past column
72 are wrapped to additional lines, indented by the value of the
cobolindent parameter in the #option construct.  All additional lines
conform to COBOL syntax specifications.

EXAMPLE 1

Generator Input: 

         01  !image-database!-NAME    PIC X(6) VALUE "!image-database".

Generated Output: 

         01  ORDERS-NAME    PIC X(6) VALUE "ORDERS".

The number of spaces between the 01 entry name and the PIC clause is
preserved.  If the quoted string is too long to fit within the column 72
limit, it is placed on a new line, indented by the value of cobolindent.
In the following example, cobolindent has the default value 4.

         01  ORDERS-NAME    PIC X(30) VALUE
             "A-VERY-VERY-LONG-DATABASE-NAME".

EXAMPLE 2

Generator Input: 

         CALL 'GETNAME' USING BASENAME, STATUS-ARRAY, BIG-COMAREA, !comm.

Generated Output: 

         CALL 'GETNAME' USING BASENAME, STATUS-ARRAY, BIG-COMAREA,
             BIGGER-COMAREA.

EXAMPLE 3

Generator Input: 

         MOVE "!description" TO DESCRIPTION-TEXT

Generated Output 

         MOVE "This is a maintenance screen for order processing" TO
             DESCRIPTION-TEXT

When textmode is COBOL and the complete quoted string does not fit on the
line, the quote begins on a new line.  This new line is indented by the
value of the cobolindent parameter and continues on subsequent lines,
according to the rules for COBOL quoted strings.  The generator only
recognizes double quotes as delimiters for quoted strings.

TEXT Textmode.  TEXT textmode provides line-level formatting.  In this
mode, truncation is avoided and line wrap-around is provided.  Input is
not forced to align; white space is preserved when replacing parameters,
and appropriate formatting is performed.  TEXT textmode is useful for
generating documentation or for generating code for languages other than
COBOL. For example, TEXT textmode can be used for Pascal programs.

EXAMPLE 1

Generator Input: 

     #option textmode="text"
     This transaction accesses !hp-script:1, !hp-script:2, !hp-script:3, and utilizes
     a single database, !image-database.  The transaction is designed to
     solve the orders-filled list problem.

     Generated Output: 

     This transaction accesses OrdCust, OrdSales, OrdMenu, and utilizes
     a single database, ORDERS.  The transaction is designed to
     solve the orders-filled list problem.

In the preceding example, the replacement text was approximately the same
length as the keywords it replaced, and so the output text is acceptable.
If the replacement text is considerably longer than the keyword, you
would want to use the #description construct to format the output, since
it would operate on the block of text as a whole, rather than on one line
at a time.  (Refer to Chapter 3 for more information on the #description
construct.)

The following example uses the #description construct, and it also
specifies the start, end, and continue parameters with the #description
construct to create a paragraph.

EXAMPLE 2

     Generator Input: 

     #option textmode="text"
     #description comment=  &
     #"This transaction accesses !hp-script:1, !hp-script:2, !hp-script:3 &
     #and utilizes a single data base, !image-database.  The transaction is &
     #designed to solve the orders-filled list problem." start=10 &
     #continue=5 end=70

     Generated Output: 

               This transaction accesses OrdCust, OrdSales, OrdMenu and
          utilizes a single database, ORDERS.  The transaction is designed
          to solve the orders-filled list problem.

Here is an example of TEXT textmode where the line is wrapped and spaces
are preserved:

EXAMPLE 3

     Generator Input: 

     #let name="a very very very long name that is too long to fit"
     #option textmode="text"
      TEXT LINE WHICH HAS "This is long: !name"
     Generated Output: 

      TEXT LINE WHICH HAS "This is long: a very very very long name that is too
      long to fit"

OVERLAY Textmode.  In OVERLAY textmode, the output is formatted in the
same columnar fashion as the input, and line-wrap never occurs.  The
replacement of substitution parameters begins in the same position as the
position of the !keyword.  This mode is used to ensure that the alignment
of text is correct.  Since the position where replacement occurs is the
same as the input position, truncation of replacement parameters can
occur if there is not enough space for the replacement text.  When a
parameter is truncated, a warning is issued.  OVERLAY textmode is useful
for creating reports or tables.

The length of the keyword value does not affect the placement of the text
that follows the keyword, and blank space is not preserved.  In the
following example, the dictionary is accessed to find all the data sets
used by a particular module.  Also retrieved are the related database and
copylib-member names for each data set.  Note that the keyword values are
placed in the same column as the keyword.  For example, CUSTOMER begins
in the same column as its corresponding keyword, image-dataset.

EXAMPLE 1

Generator Input: 

     #option textmode="overlay"
     #let module="ORDCUST"
           ---------------   !module   -------------------
      IMAGE-DATABASE         IMAGE-DATASET        COPYLIB-MEMBER

     #for module="!module" image-dataset=? relclass="processes"
     #  getrel image-database=? image-dataset="!image-dataset" relclass="contains"
     #  getrel image-dataset="!image-dataset" record=? relclass="contains"
     #  getrel hp-copylib-member=? record="!record" relclass="contains"
     #
        !image-database        !image-dataset       !hp-copylib-member
     #endfor

     Generated Output: 

           ---------------   ORDCUST   -------------------
      IMAGE-DATABASE         IMAGE-DATASET        COPYLIB-MEMBER

        ORDERS                 CUSTOMER             CUSTOMER
        ORDERS                 SALES                SALES
        ORDHIS                 ORDDATE              ORDDATE

If there is insufficient space for a replacement parameter, truncation
results.

EXAMPLE 2

     Generator Input: 

     #option textmode="overlay"
     #let module="ORDCUST"
           ---------------   !module   -------------------
      IMAGE-DATASET          DESCRIPTION

     #for module="!module" image-dataset=? relclass="processes"
     #  getent image-dataset="!image-dataset" attr=(description)
     #
        !image-dataset  !description

     #endfor

     Generated Output:  

           ---------------   ORDCUST   -------------------
      IMAGE-DATASET          DESCRIPTION

        CUSTOMER        The CUSTOMER dataset contains the mailing addresses for

        SALES           The SALES dataset contains all of the information for prod

        ORDDATE         The ORDDATE dataset keeps order information sorted by

The above description is truncated at column 80.  You can avoid
truncations by using the #description construct.  The following example
illustrates how to add the description to this example.

EXAMPLE 3

Generator Input: 

     #option  textmode="overlay"
     #let module="ORDCUST"
           ---------------   !module   -------------------
      IMAGE-DATABASE         IMAGE-DATASET/DESCRIPTION  COPYLIB-MEMBER

     #for module="!module" image-dataset=? relclass="processes"
     #getent image-dataset="!image-dataset" attr=(description)
     #getrel image-database=? image-dataset="!image-dataset" relclass="contains"
     #getrel image-dataset="!image-dataset" record=? relclass="contains"
     #getrel hp-copylib-member=? record="!record" relclass="contains"
     #
        !image-database !image-dataset            !hp-copylib-member
     #description comment="!description" start=18 continue=18

     #endfor

     Generated Output: 

           ---------------   ORDCUST   -------------------

      IMAGE-DATABASE  IMAGE-DATASET/DESCRIPTION   COPYLIB-MEMBER

        ORDERS          CUSTOMER                  CUSTOMER
                      The CUSTOMER dataset contains the mailing addresses for
                      all customers.  This is a master dataset and the key
                      is account name.

        ORDERS          SALES                     SALES
                      The SALES dataset contains all of the information for
                      products ordered by a customer.  This is a detail dataset
                      sorted on order number and chained to the CUSTOMER dataset
                      by account name.

        ORDHIS          ORDDATE                   ORDDATE
                      The ORDDATE dataset keeps order information sorted by
                      the date-shipped.  This is a detail dataset sorted
                      on date-shipped.

Notice that in some cases the keywords may be so long that their length
limits their placement in the user text.  This can be corrected by
assigning a shorter parameter name using the #let construct and using the
shorter name to signify placement of the value.

In the above example, !image-database is rather long, and this length
forces !image-dataset farther out on the line.  To move !image-dataset 
closer in, assign a shorter parameter name to !image-database with the
#let construct.  Of course, you must always leave enough room for the
substituted values themselves regardless of the length or brevity of the
keyword.  Otherwise the output will be truncated.

EXAMPLE 4

Generator Input: 

     #option textmode="overlay"
     #  let dbname="image-database"
        !dbname       !image-dataset              !hp-copylib-member
     #  description comment="!description"  start=18 continue=18

The above example moved the dataset name two spaces to the left.

Generated Output: 

        ORDERS        CUSTOMER                    CUSTOMER
                      The CUSTOMER dataset contains the mailing addresses for
                      .
                      .

Again, be careful to leave enough room so that truncation does not occur.
Note that the substitution character, "!", counts as a space.  In the
following example, the database name is truncated.  (Note that the
warning would actually appear in the generator listing file, not the
generated output.)

EXAMPLE 5

Generator Input: 

     #option textmode="overlay"
     #let db="!image-database"
     #let ds="!image-dataset"
     #let cm="!hp-copylib-member"

        !db  !ds      !cm

     Generated Output:  

        ORDERCUSTOMER CUSTOMER
          **** WARNING, Possible Truncation of Substitution Parameters(VIR 1065)

More Examples.  The following examples show how the output differs based
upon the textmode.

     EXAMPLE 1

     Generator Input: 
     #let entry-message="Enter the account Number and press f1."
                CALL 'PRINTMESSAGE' USING "!entry-message"

     Generated Output if Textmode is COBOL (and cobolindent=12):

               CALL 'PRINTMESSAGE' USING
                     "Enter the Account Number and press f1."

     Generated Output if Textmode is TEXT: 

                CALL 'PRINTMESSAGE' USING "Enter the Account Number and press
                f1"

     Generated Output if Textmode is OVERLAY: 

                CALL 'PRINTMESSAGE' USING "Enter the Account Number and press
                            ***  WARNING - TRUNCATION ***

     EXAMPLE 2

     Generator Input:

                MOVE "!description" TO DESCRIPTION-MESSAGE.

     Generated Output with textmode=COBOL:

                MOVE
                "This module performs the update of a Single Detail IMAGE
           -    "Dataset." TO DESCRIPTION-MESSAGE.

     Generated Output with textmode=TEXT:

                MOVE "This module performs the update of a Single Detail IMAGE
                Dataset." TO DESCRIPTION-MESSAGE.

     Generated Output with textmode=OVERLAY:

                MOVE "This module performs the update of a Single Detail IMAGE
                                   *** WARNING - TRUNCATION ***

Macro Indentation.  The macroformat parameter of the #option construct is
provided so that the macro text can be indented to align with the call to
the macro.  The macroformat parameter can have the values ON or OFF, and
the default is ON. This option is useful for causing code to line up.
When macroformat is ON, the code generated by the macro is indented by
the number of spaces between the "#" and the first character of the macro
name in the Virtuoso source code.  When macroformat is OFF, the macro
text will not be indented.  In other words, OFF specifies that the macro
text will appear in the columns where it appears in the macro.  That may
or may not coincide with the columns where the macro was called.

In Example 1 below, the code for MACRO1 will be indented two spaces from
the if, and the code for MACRO2 will be indented five spaces from the if 
in the generated output.

EXAMPLE 1

     Generator Input: 
               if image-database <> " "
               #  MACRO1
               #     MACRO2
               end-if

     Macro Code: 

       #MACRO1
        this is macro1

       #MACRO2
        this is macro2 line 1
           this is macro2 line2

     Generated Output: 

          if image-database <> " "
             this is macro1
                this is macro2 line1
                   this is macro2 line2
          end-if

Note that leading blanks in the macro are also reflected in the output.

The next example illustrates line wrapping in macro indentation.  If
indentation forces the line too far to the right (so that a complete word
will not fit in the output line), the indentation will be reset to the
left margin.

EXAMPLE 2

     Macro Code: 

     #macro Macro1
     #let DB="IMAGE-DATABASE-NAME"
      !DB goes on line1 of MACRO1
      This is line2 of MACRO1
     #endmacro

     Generator Input: 

     #Macro1

     #                        Macro1

     #                                             Macro1

Generated Output: 

      IMAGE-DATABASE-NAME goes on line1 of MACRO1
      This is line2 of MACRO1

                              IMAGE-DATABASE-NAME goes on line1 of MACRO1
                              This is line2 of MACRO1

                                                   IMAGE-DATABASE-NAME goes on
                                                   line1 of MACRO1
                                                   This is line2 of MACRO1



MPE/iX 5.0 Documentation