Using Virtuoso Constructs [ VIRTUOSO CODE GENERATOR Reference Manual ] MPE/iX 5.0 Documentation
VIRTUOSO CODE GENERATOR Reference Manual
Using Virtuoso Constructs
This section illustrates the use of various Virtuoso constructs. These
constructs are described in detail in Chapter 3 of this manual. The
intent here is to introduce the constructs, giving some idea of their
function and purpose.
#let
The #let construct assigns a value to a keyword. If the keyword does not
already exist, the #let construct sets up the keyword. The keyword can
be any name satisfying the keyword naming conventions. It is not limited
to valid System Dictionary entity-types and attributes.
If the keyword is assigned a string value, the string must be enclosed in
quotes. Here are several examples of the #let construct:
#let image-database="ORDERS"
#let max-value=3
#let sp-string='the "next message"'
#if/#else/#endif
This construct is used for flow of control. The #if construct determines
which Virtuoso statements are executed, depending on the truth or falsity
of a relational statement.
Here are two examples of the #if construct:
#if element <> " "
MOVE !element TO !element!-BUFF
#endif
#if number1 > number2
# let largest-number = "!number1"
#else
# let largest-number = "!number2"
#endif
In the first example, the #if construct determines the conditional
generation of code. If the value of the keyword element is not a blank
(" "), then the user text is generated using the value of element.
In the second example, the #if/#else constructs determine the conditional
execution of Virtuoso Generator statements. If the value of the keyword
number1 is larger than that of number2, then that value is assigned to
the keyword largest-number. Otherwise, the value of number2 is assigned
to largest-number.
The construct #if is similar to the IF/ELSE/ENDIF in other computer
languages, but there are some important differences:
* There can be only one relational operator per #if.
* The expressions on either side of the relational operator must be the
same type, either numeric or string.
* The comparison is case sensitive. Remember this when comparing
strings!
* Blank characters are significant.
* The expressions can be a literal value in quotes, a number, or a
keyword.
* The valid relational operators are: =, <>, <, >, <=, >=, AND, OR.
The #if construct can be nested, but remember that there is no #else-if
construct in Virtuoso, only #else. Also, if you use nesting, be sure to
include the appropriate number of #endif's at the end.
Constructs Which Access the System Dictionary
There are three constructs which retrieve System Dictionary information:
* #getent
* #getrel
* #for/#endfor
The construct #getrel retrieves one relationship of a specified
relationship type from the System Dictionary. In contrast, #getent
retrieves the attributes of a specified entity of a specified entity type
from the System Dictionary. The construct #for/#endfor retrieves all of
the relationship occurrences of a specified relationship type from the
System Dictionary.
These three constructs create new keyword-value pairs with the
information retrieved from the System Dictionary.
#getent. The #getent construct is used to retrieve attributes from the
System Dictionary for a specified entity of a specified entity type. The
syntax of the construct is:
#getent entity-type-name="entity-name" &
# [attr=(attr1 attr2...)]
Here is an example of using #getent:
#getent element="ADDRESS" attr=(element-type byte-length)
In the first example, the attributes element-types and byte-length are
retrieved for the element ADDRESS. That is, two keyword-value pairs are
established, one with keyword element-type, and one with keyword
byte-length. The value of the keyword is the value of the attribute for
this occurrence of the element ADDRESS. These attribute values for the
element ADDRESS can now be included in generated text as !element-type
and !byte-length.
If the attr=() clause is omitted, all attributes are retrieved for the
specified entity. This can significantly reduce generation-time
performance. It is recommended that you specify only those attributes
which are needed.
#getrel. The construct #getrel retrieves a relationship of a particular
relationship type from the System Dictionary. It retrieves only one
relationship, although multiple relationships can exist for a
relationship type. Here is an example of this construct:
#getrel image-database="ORDERS" image-dataset="?" &
# relclass="contains"
This example retrieves the first entity of type image-dataset related to
the entity "ORDERS" of type image-database. A value is retrieved for the
keyword image-dataset, creating a new keyword-value pair. This value can
then be referenced as !image-dataset.
You can specify up to six entity types and one relationship class within
the #getrel construct. You can also use #getrel to retrieve attributes
of the relationship and the alias for the relationship.
The #getrel construct can include the clause seqno=value. If you omit
this, then #getrel retrieves the first occurrence of the specified
relationship type. If you want a different occurrence, then use seqno to
designate it. For example if you specify seqno=6, then the sixth
occurrence will be retrieved.
The system-supplied keyword numrels can be used to determine if #getrel
has retrieved any relationships. Immediately after #getrel has executed,
numrels contains the number of relationships which were retrieved. If it
is zero, then #getrel did not retrieve the relationship occurrence. If
numrels is one, then #getrel successfully retrieved the relationship.
#for/#endfor. Unlike the constructs #getrel and #getent, #for retrieves
more than one occurrence. It retrieves all relationship occurrences of a
specified relationship type from the System Dictionary, one at a time.
The generator sets up keyword-value pairs for each of the entity-types
and attributes included in the #for construct. The relationship
occurrences are retrieved one at a time and processed by the statements
contained within the #for/#endfor. The #endfor causes the next
relationship to be retrieved and processed. After all relationships have
been processed, the #endfor passes control to the statement immediately
after the #endfor. If there are no relationships, the statements between
the #for and #endfor are not executed.
An example of the #for construct appears in the first example of Virtuoso
source code in this chapter. It is repeated here, along with a list of
the keyword-value pairs generated for each loop:
#for record="ORDER-MAS-REC" element=? relclass="contains" &
# attr=(element-type)
# if element-type="X"
DISPLAY !element.
# endif
#endfor
System Dictionary Definitions:
RECORD contains ELEMENT
ORDER-MAS-REC contains ORDER-NUMBER
element-type="X"
ORDER-MAS-REC contains CUSTOMER
element-type="X"
ORDER-MAS-REC contains AMOUNT
element-type="9"
Keyword-Value Pairs Generated by Example:
Loop 1:
element="ORDER-NUMBER"
element-type="X"
Loop 2:
element="CUSTOMER"
element-type="X"
Loop 3:
element="AMOUNT"
element-type="9"
Output Generated by Example:
DISPLAY ORDER-NUMBER.
DISPLAY CUSTOMER.
There are two Virtuoso-supplied keywords which you can use with the #for
construct. The keyword loopcounter contains the number of times the #for
loop has executed. This keyword is accessible only within the loop. The
keyword numrels contains the number of relationship occurrences retrieved
during the #for/#endfor loop, and it is accessible after the #for/#endfor
has finished executing. These keywords are useful for loop control and
for checking on the success of the #for statement.
#comment
The #comment construct is used to add comments to Virtuoso source code.
These comments do not appear in the generated output, but they do appear
in the generator listing file of Virtuoso source code. Here is an
example:
#comment
#comment Open the database; then generate
#comment displays for all elements of type "X".
#comment
#printerror
The #printerror construct writes error/warning messages to the generator
listing file. This construct is often used to print messages if the
information retrieved from the System Dictionary does not match what is
expected. Here is an example:
#let record="MAILER"
#let element="ADDRESS"
#getrel record="!record" element="!element" relclass="contains"
#if numrels <> 1
# printerror message="No element defined for record !record" # type="ERROR"
#endif
If the expected relationship is not retrieved, then the following message
appears in the generator listing file:
**** ERROR # 1 User ERROR Message specified (VIR 1056)
**** USER ERROR : No element defined for record MAILER
#include
The #include construct allows you to merge a file into the current file
being processed. This construct is often used to include user-specific
code during generation. Such files are referred to as "include files."
Here is an example of the #include construct:
#include file="INCORE.MAC"
The above statement instructs the Virtuoso Generator to open and process
the file INCORE.MAC.
#section/#entry
The #entry/#endentry construct is used to reposition text to another
location defined by the #section construct. In this way, #entry blocks
from many sources can be gathered into one place. For example, #entry
constructs are frequently located within COBOL macros which may be placed
anywhere within a COBOL program's Procedure Division. The #entry
construct allows these macros to generate necessary COBOL Working-Storage
definitions which are then repositioned with an appropriate #section
construct in the Working-Storage Section of the COBOL program.
The following example illustrates the use of the #section and #entry
constructs to place portions of code in specific locations within the
generated code. See the description of the #entry construct in Chapter 3
for another illustration of the use of #section and #entry.
IDENTIFICATION DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
.
.
#section name="working-storage"
.
.
LINKAGE SECTION.
#section name="linkage-section"
.
.
PROCEDURE DIVISION.
.
.
GOBACK.
#entry name="TESTA" section="working-storage"
01 SALES-DATA.
05 NAME PIC X(30).
05 CODE PIC X(5).
#endentry
#entry name="TESTB" section="linkage-section"
01 SAMPLE1 PIC X(80).
#endentry
This generates the following code:
IDENTIFICATION DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
.
.
01 SALES-DATA.
05 NAME PIC X(30).
05 CODE PIC X(5).
.
.
LINKAGE SECTION.
01 SAMPLE1 PIC X(80).
.
.
PROCEDURE DIVISION.
.
.
GOBACK.
Extended Example
The following example shows how Virtuoso constructs can be combined to do
useful tasks. It generates the code to open all databases associated
with a module.
#let module="TEST1"
.
.
.
#for module="!module" image-database=? relclass="processes" &
# attr=(hp-open-mode)
MOVE SPACES TO !image-database!-BASE-ID
MOVE "!image-database" TO !image-database!-BASE-NAME
MOVE ";" TO DB-PASSWORD
MOVE "!hp-open-mode" TO DB-MODE
CALL "DBOPEN" USING !image-database!-DATA
DB-PASSWORD
DB-MODE
DB-STATUS
#endfor
.
.
.
System Dictionary Definitions:
MODULE processes IMAGE-DATABASE
TEST1 processes ACCOUNTS
hp-open-mode="5"
TEST1 processes ORDERS
hp-open-mode="5"
Output Generated by Example:
MOVE SPACES TO ACCOUNTS-BASE-ID
MOVE "ACCOUNTS" TO ACCOUNTS-BASE-NAME
MOVE ";" TO DB-PASSWORD
MOVE "5" TO DB-MODE
CALL "DBOPEN" USING ACCOUNTS-DATA
DB-PASSWORD
DB-MODE
DB-STATUS
MOVE SPACES TO ORDERS-BASE-ID
MOVE "ORDERS" TO ORDERS-BASE-NAME
MOVE ";" TO DB-PASSWORD
MOVE "5" TO DB-MODE
CALL "DBOPEN" USING ORDERS-DATA
DB-PASSWORD
DB-MODE
DB-STATUS
In this example, the #for construct retrieves the databases processed by
the module TEST1. The System Dictionary shows that there are two such
databases, ACCOUNTS and ORDERS. The name of the database and the value of
the attribute HP-Open-Mode are retrieved and substituted into the code to
be generated. The #for/#endfor loop executes twice, generating the code
to open the databases ACCOUNTS and ORDERS.
MPE/iX 5.0 Documentation