Subroutines: Difference between revisions

From m204wiki
Jump to navigation Jump to search
mNo edit summary
m (add links)
 
(28 intermediate revisions by 7 users not shown)
Line 1: Line 1:
===Overview===
<div class="toclimit-3">
<p>User Language lets you treat a single set of statements as a simple or complex subroutine. You can:</p>
 
==Overview==
<p>
User Language lets you treat a single set of statements as a simple or complex subroutine. You can:</p>
<ul>
<ul>
<li>Execute simple subroutines a number of times from different locations within a request.</li>
<li>Execute simple subroutines a number of times from different locations within a request.</li>
<li>Use complex subroutines as you would simple subroutines. In addition, you can:</li>
<li>Use complex subroutines as you would simple subroutines. </li>
</ul>
</ul>
<p>Pass parameters via parameter lists.</p>
In addition, you can:
<p>Declare variables locally.</p>
<ul>
====Common elements====
<li>Pass parameters via parameter lists.</li>
<p>An element that is not passed as a parameter can be shared between complex subroutines, or between a complex subroutine and the main request, when you declare that element as COMMON.</p>
<li>Declare variables locally.</li>
====ON units====
</ul>
<p>An ON unit specifies a response action to a triggering event: for example, the terminal operator pressing one of the ATTENTION identifier (AID) keys. ON units let an application override the normal system response.</p>
===Simple subroutines===
===Common elements===
====Outlining a simple subroutine====
<p>
<p>The following statements are used in simple subroutines within a request:</p>
An element that is not passed as a parameter can be shared between complex subroutines, or between a complex subroutine and the main request, when you declare that element as <var>COMMON</var>.</p>
===On units===
<p>
As [[#On statement|described later]], an <var>On</var> unit specifies a response action to a triggering event: for example, the terminal operator pressing one of the ATTENTION identifier (AID) keys. <var>On</var> units let an application override the normal system response.</p>
==Simple subroutines==
===Outlining a simple subroutine===
<p>
The following statements are used in simple subroutines within a request:</p>
<table>
<table>
<tr>
<tr class="head">
<td>Statement</td>
<th>Statement</th>
<td>Purpose</td>
<th>Purpose</th></tr>
</tr>
 
<tr>
<tr>
<td><var>CALL</var></td>
<td><var>CALL</var></td>
<td>Transfers control to the subroutine.</td>
<td>Transfers control to the subroutine.</td></tr>
</tr>
 
<tr>
<tr>
<td>END SUBROUTINE</td>
<td nowrap><var>END SUBROUTINE</var></td>
<td>Indicates the end of the subroutine.</td>
<td>Indicates the end of the subroutine.</td></tr>
</tr>
 
<tr>
<tr>
<td>JUMP TO</td>
<td><var>JUMP TO</var></td>
<td>Transfers control to another statement in the request.</td>
<td>Transfers control to another statement in the request.</td></tr>
</tr>
 
<tr>
<tr>
<td><var>RETURN</var></td>
<td><var>RETURN</var></td>
<td>Returns control to the statement immediately following the CALL statement. </td>
<td>Returns control to the statement immediately following the CALL statement. </td></tr>
</tr>
 
<tr>
<tr>
<td><var>SUBROUTINE</var></td>
<td><var>SUBROUTINE</var></td>
<td>Indicates the beginning of a subroutine. </td>
<td>Indicates the beginning of a subroutine. </td></tr>
</tr>
</table>
</table>
<p>The statements are coded in the following sequence, so they are described in order of usage.</p>
<p>
The statements are coded in the following sequence, so they are described in order of usage.</p>
<ol>
<ol>
<li>SUBROUTINE statement</li>
<li><var>SUBROUTINE</var> statement</li>
<li>JUMP TO and RETURN statements as appropriate</li>
<li><var>JUMP TO</var> and <var>RETURN</var> statements as appropriate</li>
<li>END SUBROUTINE statement</li>
<li><var>END SUBROUTINE</var> statement</li>
<li>CALL statement</li>
<li><var>CALL</var> statement</li>
</ol>
</ol>
====SUBROUTINE statement====
 
<p>A simple subroutine consists of a sequence of User Language statements that must begin with a SUBROUTINE statement. The body of the subroutine is composed of the statements immediately following the SUBROUTINE statement. </p>
===SUBROUTINE statement===
<b>Syntax</b>
<p>
<p>The format of the SUBROUTINE statement is:      </p>
A simple subroutine consists of a sequence of SOUL statements that must begin with a <var>SUBROUTINE</var> statement. The body of the subroutine is composed of the statements immediately following the <var>SUBROUTINE</var> statement. </p>
<p class="code">label: SUBROUTINE  
====Syntax====
<p>
The format of the <var>SUBROUTINE</var> statement is:      </p>
<p class="syntax"><span class="term">label</span>: SUBROUTINE
</p>
</p>
<p>A simple subroutine must be labeled; without a label it cannot be executed. You cannot use field names in the subroutine, except within a FOR loop, even if the subroutine is always called from within a record loop.</p>
<p>
<b>Example of a simple subroutine</b>
A simple subroutine must be labeled; without a label it cannot be executed. You cannot use field names in the subroutine, except within a FOR loop, even if the subroutine is always called from within a record loop.</p>
<p>The following request uses two subroutines. </p>
====Example of a simple subroutine====
<p>
The following request uses two subroutines. </p>
<p class="note"><b>Note:</b> Simple subroutine statements in the following example are described more fully after this example.</p>
<p class="note"><b>Note:</b> Simple subroutine statements in the following example are described more fully after this example.</p>
<p>The first subroutine, TOTAL, accumulates a total in the %variable named %TOTAL.MUSTANGS. The second subroutine, PRINT.TOTAL, prints a literal that varies depending on the total accumulated.     </p>
<p>
The first subroutine, <code>TOTAL</code>, accumulates a total in the %variable named <code>%TOTAL.MUSTANGS</code>. The second subroutine, <code>PRINT.TOTAL</code>, prints a literal that varies depending on the total accumulated. </p>
<p class="code">BEGIN
<p class="code">BEGIN
MUSTANGS:    FIND ALL RECORDS FOR WHICH
MUSTANGS:    FIND ALL RECORDS FOR WHICH
Line 83: Line 104:
                 RETURN
                 RETURN
             END SUBROUTINE PRINT.TOTAL
             END SUBROUTINE PRINT.TOTAL
END  
END
</p>
</p>
====JUMP TO statements====
<p><var class="product">Model&nbsp;204</var> compiles subroutines only after they are called, regardless of where they are in your program.</p>
===JUMP TO statements===
<p>If you use a JUMP TO statement, its destination must be within the same subroutine. You cannot jump into a subroutine from outside of a subroutine.</p>
<p>
====RETURN statement====
<var class="product">Model&nbsp;204</var> compiles subroutines only after they are called, regardless of where they are in your program.</p>
<p>The RETURN statement returns control from the subroutine to the statement following the most recent CALL statement. </p>
<p>
<b>Syntax</b>
If you use a <var>JUMP TO</var> statement, its destination must be within the same subroutine. You cannot jump into a subroutine from outside of a subroutine.</p>
<p>The format of the RETURN statement is:   </p>
<p class="code">RETURN  
===RETURN statement===
<p>
The <var>RETURN</var> statement returns control from the subroutine to the statement following the most recent <var>CALL</var> statement. </p>
====Syntax====
<p>
The format of the <var>RETURN</var> statement is: </p>
<p class="syntax">RETURN
</p>
</p>
<p>The RETURN statement can appear only within the body of a subroutine. Use of the RETURN statement inside of an ON unit terminates compilation, the procedure cannot run, and the following message is produced: </p>
<p>
<p class="code">M204.1779 RETURN IS INVALID IN ON UNITS, USE BYPASS STATEMENT  
The <var>RETURN</var> statement can appear only within the body of a subroutine. Use of the <var>RETURN</var> statement inside of an <var>ON</var> unit terminates compilation, the procedure cannot run, and the following message is produced: </p>
<p class="code">M204.1779 RETURN IS INVALID IN ON UNITS, USE BYPASS STATEMENT
</p>
</p>
<p><var class="product">Model&nbsp;204</var> automatically generates a return at the end of a subroutine, if you do not specify one.     </p>
<p>
<p>For more information see [[#ON units|ON units]] and [[#Passing control to and from ON units|Passing control to and from ON units]].</p>
<var class="product">Model&nbsp;204</var> automatically generates a return at the end of a subroutine, if you do not specify one. </p>
====END SUBROUTINE statement====
<p>
<p>You can end a subroutine using an END SUBROUTINE statement or an END BLOCK statement. </p>
For more information, see [[#ON units|ON units]] and [[#Passing control to and from ON units|Passing control to and from ON units]].</p>
<b>Syntax</b>
<p>The END SUBROUTINE statement is formatted as follows:            </p>
===END SUBROUTINE statement===
<p class="code">END SUBROUTINE <var>[</var>label<var>]</var>  
<p>
You can end a subroutine using an <var>END SUBROUTINE</var> statement or an <var>END BLOCK</var> statement. </p>
====Syntax====
<p>
The END SUBROUTINE statement is formatted as follows:            </p>
<p class="syntax">END SUBROUTINE <span class="squareb">[</span><span class="term">label</span><span class="squareb">]</span>
</p>
</p>
====CALL statement====
<p>The CALL statement transfers control to the subroutine. </p>
===CALL statement===
<b>Syntax</b>
<p>
<p>The format of the CALL statement is:</p>
The <var>CALL</var> statement transfers control to the subroutine. </p>
<p class="code">CALL label  
====Syntax====
<p>
The format of the <var>CALL</var> statement is:</p>
<p class="syntax">CALL <span class="term">label</span>
</p>
</p>
<b>Example</b>
<p>This statement:</p>
====Example====
<p class="code">CALL.SUB: CALL COMPUTE.PREMIUM  
<p>
This statement:</p>
<p class="code">CALL.SUB: CALL COMPUTE.PREMIUM
</p>
</p>
<p>transfers control to the following statement:</p>
<p>
transfers control to the following statement:</p>
<p class="code">COMPUTE.PREMIUM: SUBROUTINE
<p class="code">COMPUTE.PREMIUM: SUBROUTINE
</p>
</p>
<p>When you use a simple subroutine, no arguments are passed in subroutine calls. Instead, input and output values are implicitly passed in %variables or global variables. If you want field values as arguments, you must assign the values to %variables before the call, or the subroutine must contain its own FOR EACH RECORD loop on the set of records to be processed.</p>
<p>
<p>Processing continues sequentially from that statement until another control transfer statement--a CALL, IF, JUMP TO, RETURN, or STOP statement--is encountered.   </p>
When you use a simple subroutine, no arguments are passed in subroutine calls. Instead, input and output values are implicitly passed in %variables or global variables. If you want field values as arguments, you must assign the values to %variables before the call, or the subroutine must contain its own <var>FOR EACH RECORD</var> loop on the set of records to be processed.</p>
===Complex subroutines===
<p>
<p>Complex subroutines perform all the operations of a simple subroutine. In addition, a complex subroutine can pass parameters via parameter lists and can declare local variables. </p>
Processing continues sequentially from that statement until another control transfer statement &mdash; a <var>CALL</var>, <var>IF</var>, <var>JUMP TO</var>, <var>RETURN</var>, or <var>STOP</var> statement &mdash; is encountered. </p>
<p class="note"><b>Note:</b> The format of the SUBROUTINE statement changes for a complex subroutine and the CALL statement is also more complex.</p>
====Symbolic parameter passing====
==Complex subroutines==
<p>You can specify positional parameters on the CALL statement for a complex subroutine. These parameters are substituted for symbolic parameters used within the subroutine during execution. You can use the following elements as parameters to a complex subroutine:</p>
<p>
Complex subroutines perform all the operations of a simple subroutine. In addition, a complex subroutine can pass parameters via parameter lists and can declare local variables. </p>
<p class="note"><b>Note:</b> The format of the <var>SUBROUTINE</var> statement changes for a complex subroutine and the <var>CALL</var> statement is also more complex.</p>
===Symbolic parameter passing===
<p>
You can specify positional parameters on the <var>CALL</var> statement for a complex subroutine. These parameters are substituted for symbolic parameters used within the subroutine during execution. You can use the following elements as parameters to a complex subroutine:</p>
<ul>
<ul>
<li>Scalar %variables</li>
<li>Scalar %variables</li>
</li>
 
<li>%variable arrays</li>
<li>%variable arrays</li>
</li>
 
<li>Lists of records</li>
<li>Lists of records</li>
</li>
</ul>
</ul>
====Local variable declaration====
<p>Labels, %variables, and other elements in a complex subroutine are local to the subroutine; they do not conflict with elements of the same name in the request or in other complex subroutines. This allows the same element to be used in different portions of a request, and for the same name to describe different elements in each portion.</p>
===Local variable declaration===
====Processing====
<p>
<p>All data within the subroutine is statically allocated. When the subroutine is called, the values of all found sets, counts, noted values, and variables are as they were when the subroutine was last executed. Recursive calls to the same subroutine do not allocate separate storage for each subroutine local variable. Local variables are allocated only one time.</p>
Labels, %variables, and other elements in a complex subroutine are local to the subroutine; they do not conflict with elements of the same name in the request or in other complex subroutines. This allows the same element to be used in different portions of a request, and for the same name to describe different elements in each portion.</p>
<b>OPEN statement within a complex subroutine</b>
<p>A User Language OPEN statement--an OPEN statement inside a BEGIN/END--when used within a complex subroutine on a file that is not defined to the region produces the following counting error and the request is not compiled:</p>
===Processing===
<p class="code">M204.1521: entity-name DOES NOT EXIST OR REQUESTED ACCESS NOT AUTHORIZED
<p>
All data within the subroutine is statically allocated. When the subroutine is called, the values of all found sets, counts, noted values, and variables are as they were when the subroutine was last executed. Recursive calls to the same subroutine do not allocate separate storage for each subroutine local variable. Local variables are allocated only one time.</p>
====OPEN statement within a complex subroutine====
<p>
A SOUL <var>OPEN</var> statement &mdash; an <var>OPEN</var> statement inside a <var>BEGIN/END</var> &mdash; when used within a complex subroutine on a file that is not defined to the region produces the following counting error and the request is not compiled:</p>
<p class="code">M204.1521: <i>entity-name</i> DOES NOT EXIST OR REQUESTED ACCESS NOT AUTHORIZED
</p>
===SUBROUTINE statement for complex subroutines===
<p>
Complex subroutines begin with the following form of the <var>SUBROUTINE</var> statement:  </p>
<p class="syntax">SUBROUTINE <span class="term">subname</span> <span class="squareb">[</span>(<span class="term">formal-parameter</span>
                  <span class="squareb">[</span><span class="term">inout-option</span><span class="squareb">]</span> <span class="squareb">[</span>, ...<span class="squareb">]</span>)<span class="squareb">]</span>
</p>
</p>
====SUBROUTINE statement====
Where:
<p>Complex subroutines begin with the following form of the SUBROUTINE statement:        </p>
<ul>
<p class="code">SUBROUTINE subname <var>[</var>(formal-parameter
<li><var class="term">subname</var> is the name of the subroutine.</li>


<var>                   [</var>inout-option<var>]</var>  
<li><var class="term">formal-parameter</var> is the declaration of a symbolic parameter used within the subroutine. The parameter list is comprised of the <var class="term">formal-parameter</var> and subsequent input-options. The parameter list is enclosed in parentheses, and it contains declarations for each parameter separated by commas. The parameter list must be specified on one logical line. Null parameters are not allowed.</li>


<var>                   [</var>, ...<var>]</var>)<var>]</var>
<li><var class="term">formal-parameter</var> specifies the name and type of element to be used within the subroutine and can be any of the following:
</p>
<b>Where</b>
<p>subname is the name of the subroutine.</p>
<p>formal-parameter is the declaration of a symbolic parameter used within the subroutine. The parameter list is comprised of the formal-parameter and subsequent input-options. The parameter list is enclosed in parentheses, and it contains declarations for each parameter separated by commas. The parameter list must be specified on one logical line. Null parameters are not allowed.</p>
<p>A formal-parameter specifies the name and type of element to be used within the subroutine and can be any of the following:</p>
<ul>
<ul>
<li>Scalar (nonarray) %variable formatted as:</li>
<li>Scalar (nonarray) %variable formatted as:
<p class="code">%variable [IS] {[STRING] [LEN] n [DP {n | *}]
<p class="syntax"><span class="term">%variable</span> [IS] {[STRING] [LEN] <span class="term">n</span> [DP {<span class="term">n</span> | *}]  
 
          <span class="squareb">|</span> [FIXED [DP <span class="term">n</span>] <span class="squareb">|</span> FLOAT]}
|[FIXED [DP n] | FLOAT]}
</p>
</p>
<p>For example:</p>
<p>
For example:</p>
<p class="code">SUBROUTINE EXAMPLE (%W IS STRING DP *        -
<p class="code">SUBROUTINE EXAMPLE (%W IS STRING DP *        -
                     %X IS STRING LEN 40,      -
                     %X IS STRING LEN 40,      -
                     %Y IS STRING LEN 10 DP 2, -
                     %Y IS STRING LEN 10 DP 2, -
                     %Z IS FLOAT,              -
                     %Z IS FLOAT,              -
                     %A IS FIXED DP 4)  
                     %A IS FIXED DP 4)
</p></li>
</p></li>
<li>Array %variable formatted as:</li>
<p class="code">%variable [IS] [[STRING] [LEN n] [DP {n | *}]
[ARRAY(* [,*[,*]])] [NO FIELD SAVE]


  |{FIXED [DP n] | FLOAT} [ARRAY(* [,*[,*]])]]
<li>Array %variable formatted as:
<p class="syntax"><span class="term">%variable</span> [IS] [[STRING] [LEN <span class="term">n</span>] [DP {<span class="term">n</span> | *}]
[ARRAY(* [,*[,*]])] [NO FIELD SAVE]
  <span class="squareb">|</span> <span class="squareb">{</span>FIXED [DP <span class="term">n</span>] <span class="squareb">|</span> FLOAT<span class="squareb">}</span> [ARRAY(* [,*[,*]])]]
</p>
</p>
<p>The number of dimensions must be specified in the subroutine declaration, but the exact size of each dimension is not specified. An asterisk (*) is used instead of the dimension size. For example:</p>
<p>
<p class="code">SUBROUTINE EXAMPLE(%ARR IS STRING LEN 10 - ARRAY(*,*))  
The number of dimensions must be specified in the subroutine declaration, but the exact size of each dimension is not specified. An asterisk (<tt>*</tt>) is used instead of the dimension size. For example:</p>
<p class="code">SUBROUTINE EXAMPLE(%ARR IS STRING LEN 10 - ARRAY(*,*))
</p></li>
</p></li>
<li>A list of records formatted as:</li>
<p class="code">[LIST] listname [IN [FILE | [PERM | TEMP] GROUP]]


name
<li>A list of records formatted as:
<p class="syntax">[LIST] <span class="term">listname</span> [IN [FILE | [PERM | TEMP] GROUP]] <span class="term">name</span>
</p>
</p>
<p>The context of the list is restricted to a single file or group. For example:</p>
<p>
The context of the list is restricted to a single file or group. For example:</p>
<p class="code">SUBROUTINE GENERAL(LIST TOTRECS IN FILE VEHICLES)
<p class="code">SUBROUTINE GENERAL(LIST TOTRECS IN FILE VEHICLES)
</p></li>
</p></li>
</ul>
</ul>
<p>inout-option specifies whether a formal-parameter is to be used as input to the subroutine or passed as output from the subroutine. Options are as follows:</p>
 
<li><var class="term">inout-option</var> specifies whether a formal-parameter is to be used as input to the subroutine or passed as output from the subroutine. Options are as follows:
<table>
<table>
<tr>
<tr class="head">
<td>Option</td>
<th>Option</th>
<td>Data can be...</td>
<th>Data can be...</th>
</tr>
</tr>
<tr>
<tr>
<td>INPUT
<td>INPUT<br>
(the default)</td>
(the default)</td>
<td>Passed into, but not out of, a subroutine. In addition, data conversions are performed automatically, in the same manner as an assignment statement. All references to INPUT parameters that update the parameter, for example, assignment statements, result in compiler errors.</td>
<td>Passed into, but not out of, a subroutine. In addition, data conversions are performed automatically, in the same manner as an assignment statement. All references to <var>INPUT</var> parameters that update the parameter, for example, assignment statements, result in compiler errors.</td>
</tr>
</tr>
<tr>
<tr>
<td>INPUT OUTPUT</td>
<td nowrap>INPUT OUTPUT</td>
<td>This option is equivalent to the OUTPUT option. </td>
<td>This option is equivalent to the OUTPUT option. </td>
</tr>
</tr>
<tr>
<tr>
<td>OUTPUT</td>
<td>OUTPUT</td>
<td>
<td>Returned from a subroutine. No data conversions are performed.
<p>Returned from a subroutine. No data conversions are performed.</p>
<p>
<p>The lengths of complex subroutine string OUTPUT parameters are inherited from calling parameters. If the lengths are specified in the subroutine declaration, the following message is written to the audit trail: </p>
The lengths of complex subroutine string OUTPUT parameters are inherited from calling parameters. If the lengths are specified in the subroutine declaration, the following message is written to the audit trail: </p>
<p class="code">M204.1981 LENGTH IGNORED FOR OUTPUT PARAMETER
<p class="code">M204.1981 LENGTH IGNORED FOR OUTPUT PARAMETER
</p>
</p>
<p>Compilation and evaluation of the procedure continues, with the inherited length.</p>
<p>
Compilation and evaluation of the procedure continues, with the inherited length.</p>
</td>
</td>
</tr>
</tr>
</table>
</table></li>
====END SUBROUTINE statement====
</ul>
<p>Like simple subroutines, a complex subroutine ends with an END SUBROUTINE statement. However, unlike simple subroutines, you must not label the SUBROUTINE statement.  </p>
<p>All declarations and statements compiled after the SUBROUTINE statement become a part of the subroutine until the END SUBROUTINE statement is encountered or until the request is ended with the END statement.       </p>
===END SUBROUTINE statement===
====CALL statement====
<p>
<p>The execution of a CALL statement passes control to a complex subroutine. The first time a subroutine is called, all elements in the subroutine are initialized. Subsequently, each time the subroutine is called, all elements in the subroutine remain in the same state as they were when the subroutine was last exited. You are responsible for reinitializing the elements within the subroutine.</p>
Like simple subroutines, a complex subroutine ends with an <var>END SUBROUTINE</var> statement. However, unlike simple subroutines, you must not label the <var>SUBROUTINE</var> statement.  </p>
<b>Syntax</b>
<p>
<p>A complex subroutine is invoked with this form of the CALL statement:</p>
All declarations and statements compiled after the <var>SUBROUTINE</var> statement become a part of the subroutine until the <var>END SUBROUTINE</var> statement is encountered or until the request is ended with the <var>END</var> statement. </p>
<p class="code">CALL subname [(actual-parameter [, ...])]
===CALL statement===
<p>
The execution of a <var>CALL</var> statement passes control to a complex subroutine. The first time a subroutine is called, all elements in the subroutine are initialized. Subsequently, each time the subroutine is called, all elements in the subroutine remain in the same state as they were when the subroutine was last exited. You are responsible for reinitializing the elements within the subroutine.</p>
====Syntax====
<p>
A complex subroutine is invoked with this form of the <var>CALL</var> statement:</p>
<p class="syntax">CALL <span class="term">subname</span> [(<span class="term">actual-parameter</span> [, ...])]
</p>
</p>
<b>Where</b>
Where:
<p>subname is the name of the subroutine.</p>
<p>actual-parameter specifies the actual data that replaces the symbolic formal-parameter within the subroutine. At execution time, the value of each actual-parameter is substituted, based on the order in which it appears, for a formal-parameter declared for the subroutine. The correspondence of each formal-parameter in the SUBROUTINE statement to an actual-parameter in the CALL statement is by position rather than by name.</p>
<p>An actual-parameter can be any of the following:</p>
<ul>
<ul>
<li>%variable or expression</li>
<li><var class="term">subname</var> is the name of the subroutine.</li>
<p>Expressions can contain field names, screen items, image items, and constants.</p>
 
</li>
<li><var class="term">actual-parameter</var> specifies the actual data that replaces the symbolic formal-parameter within the subroutine. At execution time, the value of each actual-parameter is substituted, based on the order in which it appears, for a formal-parameter declared for the subroutine. The correspondence of each formal-parameter in the <var>SUBROUTINE</var> statement to an actual-parameter in the <var>CALL</var> statement is by position rather than by name.
<li>Array %variable</li>
<p>
<p>When an entire array is passed as a parameter, the %variable name is used with the percent (%) sign, but no parenthesis or subscript expressions follow it. For example:</p>
An actual-parameter can be any of the following:</p>
<ul>
<li>%variable or expression
<p>
Expressions can contain field names, screen items, image items, and constants.</p></li>
 
<li>Array %variable
<p>
When an entire array is passed as a parameter, the %variable name is used with the percent (%) sign, but no parenthesis or subscript expressions follow it. For example:</p>
<p class="code">BEGIN
<p class="code">BEGIN
%A IS FLOAT ARRAY(10,10)
%A IS FLOAT ARRAY(10,10)
Line 243: Line 316:
   PRINT %B(1,1)
   PRINT %B(1,1)
END SUBROUTINE
END SUBROUTINE
END  
END
</p>
</p>
<p>The $ARRSIZE function can be used to determine the number of elements in a particular dimension of an array. For more information on $ARRSIZE, see [[$ARRSIZE#$ARRSIZE|$ARRSIZE]].</p>
<p>
</li>
The <var>[[$ArrSize]]</var> function can be used to determine the number of elements in a particular dimension of an array. </p></li>
<li>A list</li>
 
<p>An actual-parameter can be a list, optionally preceded by the word LIST to distinguish it from a field name. </p>
<li>A list
</li>
<p>
</ul>
An actual-parameter can be a list, optionally preceded by the word LIST to distinguish it from a field name. </p>
<p>If the compiler already knows of the formal-parameter list because the subroutine is already compiled or declared, the LIST keyword is unnecessary. </p>
<p>
<p>If the list has never been declared in the request, a compilation error results. </p>
If the compiler already knows of the formal-parameter list because the subroutine is already compiled or declared, the LIST keyword is unnecessary. </p>
<b>Additional rules for parameters</b>
<p>
<p>The following additional rules apply to actual-parameters and parameter passing:</p>
If the list has never been declared in the request, a compilation error results. </p>
</li></ul>
</li></ul>
 
====Additional rules for parameters====
<p>
The following additional rules apply to actual-parameters and parameter passing:</p>
<ul>
<ul>
<li>The maximum number of parameters that can be passed in complex subroutines is 63.</li>
<li>The maximum number of parameters that can be passed in complex subroutines is 63.</li>
</li>
 
<li>If the formal-parameter is specified as an OUTPUT parameter, the corresponding actual-parameter must match type.</li>
<li>If the formal-parameter is specified as an OUTPUT parameter, the corresponding actual-parameter must match type.</li>
<li>The INPUT parameters of a %variable array requires that the type of the array &mdash; <var>FLOAT</var>, <var>FIXED</var>, or <var>STRING</var> &mdash; the <var>DP</var> specification, and the number of dimensions match the actual-parameter. In addition, if the <var>NO FIELD SAVE</var> (<var>NO FS</var>) option is specified for a <var>STRING</var> formal-parameter, it also must be specified for the corresponding actual-parameter and vice versa. All checking of array bounds within subroutines occurs during evaluation.</li>
<li>The INPUT parameters of a list requires the same file or group context as the actual-parameter.
</li>
</li>
<li>The INPUT parameters of a %variable array requires that the type of the array--FLOAT, FIXED, or STRING--the DP specification, and the number of dimensions match the actual-parameter. In addition, if the NO FIELD SAVE (NO FS) option is specified for a STRING formal-parameter, it also must be specified for the corresponding actual-parameter and vice versa. All checking of array bounds within subroutines occurs during evaluation.</li>
 
</li>
<li>An INPUT parameter of a scalar %variable can be called with an actual-parameter that is an expression or %variable of a differing type. <var class="product">Model&nbsp;204</var> converts the actual-parameter to the type required by the subroutine, according to the rules of the assignment statement. The converted value has a separate storage location from the original variable or expression.
<li>The INPUT parameters of a list requires the same file or group context as the actual-parameter.</li>
<p>
</li>
Passing arguments to INPUT parameters might involve truncation where the number of decimal places is different, or conversion to 0 for non-numeric strings.</p>
<li>An INPUT parameter of a scalar %variable can be called with an actual-parameter that is an expression or %variable of a differing type. <var class="product">Model&nbsp;204</var> converts the actual-parameter to the type required by the subroutine, according to the rules of the assignment statement. The converted value has a separate storage location from the original variable or expression.</li>
<p>Passing arguments to INPUT parameters might involve truncation where the number of decimal places is different, or conversion to 0 for non-numeric strings.</p>
</li>
</li>
<li>OUTPUT parameters of lists and %variable arrays follow the same rules as INPUT parameters for lists and %variable arrays.</li>
<li>OUTPUT parameters of lists and %variable arrays follow the same rules as INPUT parameters for lists and %variable arrays.</li>
</li>
</li>
<li>OUTPUT parameters of scalar %variables require that the actual-parameter supplied in the CALL statement be another scalar %variable (no constants or expressions) of the same type--FLOAT, FIXED, or STRING--and that the number of decimal places be the same, or the following message is issued by <var class="product">Model&nbsp;204</var>:</li>
 
<p class="code">M204.1725 PARAMETER NUMBER n IS TYPE INCOMPATIBLE
<li>OUTPUT parameters of scalar %variables require that the actual-parameter supplied in the <var>CALL</var> statement be another scalar %variable (no constants or expressions) of the same type &mdash; <var>FLOAT</var>, <var>FIXED</var>, or <var>STRING</var> &mdash; and that the number of decimal places be the same, or the following message is issued by <var class="product">Model&nbsp;204</var>:
<p class="code">M204.1725 PARAMETER NUMBER <i>n</i> IS TYPE INCOMPATIBLE
</p>
</p>
<p>Strings can be of any length. The length used is that of the actual input parameter. </p>
<p>
Strings can be of any length. The length used is that of the actual input parameter. </p>
</li>
</li>
</ul>
</ul>
====Processing complex subroutines====
<p>Checking for the validity of parameter lists occurs during compilation. When the SUBROUTINE statement is compiled, the types of parameters are saved by the compiler, and any subsequent CALL statements are verified as to whether the actual parameter is consistent with the type of formal parameter.</p>
===Processing complex subroutines===
<p>When a CALL statement is compiled and the subroutine to which it refers has not been compiled, the compiler verifies whether the actual parameter list is compatible with other CALL statements for the subroutine that it has already compiled. </p>
<p>
<p>The compiler cannot verify that the actual parameters are compatible with the SUBROUTINE statement until that SUBROUTINE statement is compiled. If the compiler then detects a CALL statement that is not compatible with the SUBROUTINE statement, an error is issued at that time. Checking is done at compile time, so a statement that is not executed during evaluation can still generate an error.    </p>
Checking for the validity of parameter lists occurs during compilation. When the SUBROUTINE statement is compiled, the types of parameters are saved by the compiler, and any subsequent CALL statements are verified as to whether the actual parameter is consistent with the type of formal parameter.</p>
====DECLARE SUBROUTINE statement====
<p>
<p>The DECLARE statement for a complex subroutine is similar to the SUBROUTINE statement, except that the parameter names are omitted. The complete syntax for the DECLARE SUBROUTINE statement is:</p>
When a CALL statement is compiled and the subroutine to which it refers has not been compiled, the compiler verifies whether the actual parameter list is compatible with other CALL statements for the subroutine that it has already compiled. </p>
<b>Syntax</b>
<p>
<p class="code">DECLARE SUBROUTINE subname
The compiler cannot verify that the actual parameters are compatible with the SUBROUTINE statement until that SUBROUTINE statement is compiled. If the compiler then detects a CALL statement that is not compatible with the SUBROUTINE statement, an error is issued at that time. Checking is done at compile time, so a statement that is not executed during evaluation can still generate an error.    </p>
<var>                  [</var>(type <var>[</var>inout option<var>]</var> <var>[</var>, ...<var>]</var>)<var>]
</var>
===DECLARE SUBROUTINE statement===
</p>
<p>
<b>Where</b>
The DECLARE statement for a complex subroutine is similar to the SUBROUTINE statement, except that the parameter names are omitted. </p>
<p>subname is the name of the subroutine.</p>
<p>type is one of the following:</p>
====Syntax====
The complete syntax for the DECLARE SUBROUTINE statement is:
<p class="syntax">DECLARE SUBROUTINE <span class="term">subname</span> <span class="squareb">[</span>(<span class="term">type</span> <span class="squareb">[</span><span class="term">inout-option</span><span class="squareb">]</span> <span class="squareb">[</span>, ...<span class="squareb">]</span>)<span class="squareb">]</span> </p>
Where:
<ul>
<ul>
<li>Scalar %variable of the following format:</li>
<li><var class="term">subname</var> is the name of the subroutine.</li>
<p class="code">{STRING [LEN] n [DP {n | *}] | [FIXED [DP n]


| FLOAT]}
<li><var class="term">type</var> is one of the following:
<ul>
<li>Scalar %variable of the following format:
<p class="syntax">{STRING [LEN] <span class="term">n</span> [DP {<span class="term">n</span> | *}] | [FIXED [DP <span class="term">n</span>] | FLOAT]}
</p></li>
</p></li>
<li>Array %variable of the following format:</li>
<p class="code">{STRING [LEN n] [DP [n | *}] [ARRAY(* [,*[,*]])


[NO FIELD SAVE]]
<li>Array %variable of the following format:
<p class="syntax">{STRING [LEN <span class="term">n</span>] [DP [<span class="term">n</span> | *}] [ARRAY(* [,*[,*]]) [NO FIELD SAVE]]
| [FIXED [DP <span class="term">n</span>] | FLOAT] [ARRAY(* [,*[,*]])]}
</p></li>


| [FIXED [DP n] | FLOAT] [ARRAY(* [,*[,*]])]}
<li>A list of records of the following format:
</p></li>
<p class="code">[LIST] [IN {FILE | [PERM | TEMP] GROUP} <span class="term">name</span>]
<li>A list of records of the following format:</li>
<p class="code">[LIST] [IN {FILE | [PERM | TEMP] GROUP} name]
</p></li>
</p></li>
</ul></li>
<li>
<var class="term">inout-option</var> specifies whether each formal parameter is to be used as input to the subroutine or passed as output from the subroutine. Options are the same as those that can be specified on the SUBROUTINE statement: INPUT, OUTPUT, or INPUT OUTPUT. </li>
</ul>
</ul>
<p>inout option specifies whether each formal parameter is to be used as input to the subroutine or passed as output from the subroutine. Options are the same as those that can be specified on the SUBROUTINE statement: INPUT, OUTPUT, or INPUT OUTPUT.  </p>
<b>Usage</b>
====DECLARE before CALL====
<p class="note"><b>Issue:</b> When a CALL statement refers to a subroutine that has not yet been compiled, the error checking capabilities of the compiler are limited, because the number and type of formal parameters are not known to the compiler. If the first CALL statement for a particular subroutine is not correctly coded, then a large number of error messages can be generated when compiling subsequent CALL statements, although these statements might be correctly coded.</p>
When a <var>CALL</var> statement refers to a subroutine that has not yet been compiled, the error checking capabilities of the compiler are limited, because the number and type of formal parameters are not known to the compiler. If the first <var>CALL</var> statement for a particular subroutine is not correctly coded, then a large number of error messages can be generated when compiling subsequent <var>CALL</var> statements, although these statements might be correctly coded.
<p class="note"><b>Solutions:</b> You can avoid this problem in one of the following ways:</p>
 
You can avoid this problem in one of the following ways:
<ul>
<ul>
<li>Declare the formal parameter list with the DECLARE statement. When the DECLARE statement precedes the first CALL, the compiler generates the correct error messages, if problems are encountered. </li>
<li>Declare the formal parameter list with the <var>DECLARE</var> statement. When the <var>DECLARE</var> statement precedes the first <var>CALL</var>, the compiler generates the correct error messages, if problems are encountered. </li>
</li>
 
<li>Place the subroutine before the first CALL statement.</li>
<li>Place the subroutine before the first <var>CALL</var> statement.</li>
</li>
</ul>
</ul>
<b>Specifying a list of records</b>
<p>If you specify a LIST (of records), you must also specify FILE or GROUP. For example:</p>
====Specifying a list of records====
<p>
If you specify a <var>LIST</var> (of records), you must also specify <var>FILE</var> or <var>GROUP</var>. For example:</p>
<p class="code">OPEN METADATA
<p class="code">OPEN METADATA
password
password
 
BEGIN
BEGIN
     DECLARE LIST ORIG IN METADATA
     DECLARE LIST ORIG IN METADATA
Line 335: Line 429:
END
END
</p>
</p>
<p>If you do not specify FILE or GROUP in the code, you receive the following error message:</p>
<p>
If you do not specify <var>FILE</var> or <var>GROUP</var> in the code, you receive the following error message:</p>
<p class="code">M204.1725: PARAMETER NUMBER n IS TYPE INCOMPATIBLE
<p class="code">M204.1725: PARAMETER NUMBER n IS TYPE INCOMPATIBLE
</p>
</p>
<b>Example</b>
<p>In the following example, note that the DECLARE statement lists the formal parameters, while the CALL statement lists the actual parameters:</p>
====DECLARE parameters and CALL parameters====
<p class="code">DECLARE SUBROUTINE SUB1(FLOAT, FIXED DP 2, STRING, -
<p>
STRING DP *)
In the following example, note that the <var>DECLARE</var> statement lists the formal parameters, while the <var>CALL</var> statement lists the actual parameters:</p>
<p class="code">DECLARE SUBROUTINE SUB1(FLOAT, FIXED DP 2, STRING, STRING DP *)
     .
     .
     .
     .
Line 354: Line 450:
     .
     .
     .
     .
END  
END
</p>
</p>
<b>Impact on CALL and SUBROUTINE statements</b>
<p>The CALL and SUBROUTINE statements are not overridden when a DECLARE SUBROUTINE statement is present. The DECLARE SUBROUTINE statement does not cause the compiler to use more table space, nor does it alter the way in which the compiler output is generated.</p>
====Impact on CALL and SUBROUTINE statements====
<p>Rocket Software recommends that you use a DECLARE SUBROUTINE statement before the CALL statement for a subroutine or that you place the subroutine itself before the CALL statement. Error reporting will be more complete and specific to the subroutine.</p>
<p>
====Exiting the subroutine====
The <var>CALL</var> and <var>SUBROUTINE</var> statements are not overridden when a <var>DECLARE SUBROUTINE</var> statement is present. The <var>DECLARE SUBROUTINE</var> statement does not cause the compiler to use more table space, nor does it alter the way in which the compiler output is generated.</p>
<p>The RETURN statement returns control to the statement immediately following the most recent CALL statement. If an END SUBROUTINE or END statement is encountered without a RETURN statement, RETURN processing is implied and automatically added by the compiler. More than one RETURN statement can be specified in a subroutine.</p>
<p>
<p>If a JUMP statement is used within a subroutine, its destination must be within the same subroutine. You cannot jump into a subroutine.   </p>
Rocket Software recommends that you use a <var>DECLARE SUBROUTINE</var> statement before the <var>CALL</var> statement for a subroutine or that you place the subroutine itself before the <var>CALL</var> statement. Error reporting will be more complete and specific to the subroutine.</p>
<p>A STOP statement, when executed inside a subroutine, terminates the request in the same manner as it does when executed outside a subroutine.   </p>
====Examples using complex subroutines====
===Exiting the subroutine===
<p>This section provides examples of complex subroutines. In the following example, an employee name with regular and overtime hours is passed to the subroutine CALC.WAGES. The total pay is returned and a list of records processed by the routine is updated.</p>
<p>
The <var>RETURN</var> statement returns control to the statement immediately following the most recent <var>CALL</var> statement. If an <var>END SUBROUTINE</var> or <var>END</var> statement is encountered without a <var>RETURN</var> statement, <var>RETURN</var> processing is implied and automatically added by the compiler. More than one <var>RETURN</var> statement can be specified in a subroutine.</p>
<p>
If a <var>JUMP</var> statement is used within a subroutine, its destination must be within the same subroutine. You cannot jump into a subroutine. </p>
<p>
A <var>STOP</var> statement, when executed inside a subroutine, terminates the request in the same manner as it does when executed outside a subroutine. </p>
===Examples using complex subroutines===
<p>
In the following example, an employee name with regular and overtime hours is passed to the subroutine <code>CALC.WAGES</code>. The total pay is returned and a list of records processed by the routine is updated.</p>
<p class="code">BEGIN
<p class="code">BEGIN
DECLARE SUBROUTINE CALC.WAGES(FIXED DP 2, -
DECLARE SUBROUTINE CALC.WAGES(FIXED DP 2, -
Line 382: Line 487:
                 %TOTAL IS FIXED DP 2 OUTPUT, -
                 %TOTAL IS FIXED DP 2 OUTPUT, -
                 LIST EMPLIST IN FILE EMPLOYEE INOUT)
                 LIST EMPLIST IN FILE EMPLOYEE INOUT)
 
%TEMP IS FIXED DP 2
%TEMP IS FIXED DP 2
 
WAGES1: IN EMPLOYEE FIND ALL RECORDS FOR WHICH
WAGES1: IN EMPLOYEE FIND ALL RECORDS FOR WHICH
           NAME = %E.NAME
           NAME = %E.NAME
Line 395: Line 500:
         RETURN
         RETURN
END SUBROUTINE
END SUBROUTINE
END  
END
</p>
</p>
<p>In the following example, an entire array is passed as a single subroutine parameter:</p>
<p>
In the following example, an entire array is passed as a single subroutine parameter:</p>
<p class="code">BEGIN
<p class="code">BEGIN
%NUMBERS IS FLOAT ARRAY(10,10)
%NUMBERS IS FLOAT ARRAY(10,10)
%MAX IS FLOAT
%MAX IS FLOAT
   DECLARE SUBROUTINE MAXIMUM(FLOAT ARRAY(*,*), -
   DECLARE SUBROUTINE MAXIMUM(FLOAT ARRAY(*,*), FLOAT OUTPUT)
    FLOAT OUTPUT)
   .
   .
   .
   .
Line 410: Line 515:
   .
   .
   .
   .
 
SUBROUTINE MAXIMUM(%ARR IS FLOAT ARRAY(*,*), -
SUBROUTINE MAXIMUM(%ARR IS FLOAT ARRAY(*,*), %M IS FLOAT OUTPUT)
          %M IS FLOAT OUTPUT)
%I IS FIXED
%I IS FIXED
%J IS FIXED
%J IS FIXED
   %M = 0
   %M = 0
   FOR %I FROM 1 TO $ARRSIZE('%ARR',1)
   FOR %I FROM 1 TO $arrsize('%ARR',1)
       FOR %J FROM 1 TO $ARRSIZE('%ARR',2)
       FOR %J FROM 1 TO $arrsize('%ARR',2)
         IF %ARR(%I,%J) GT %M THEN
         IF %ARR(%I,%J) GT %M THEN
             %M = %ARR(%I,%J)
             %M = %ARR(%I,%J)
Line 424: Line 528:
   END FOR
   END FOR
END SUBROUTINE
END SUBROUTINE
END  
END
</p>
</p>
===Sharing common elements===
 
<p>An element that is not passed as a parameter can be shared between complex subroutines, or between a complex subroutine and the main request, when it is declared as a common element. A common element is created by using the DECLARE statement or by using the COMMON keyword on a %variable IS declaration. For an element to be shared, it must be declared as common in every place (each separate scope) in which it is used.     </p>
==Sharing common elements==
====Scope of elements====
<p>
<p>The scope of an element refers to the area within a request in which an element has a particular meaning. In User Language, complex subroutines have a different scope than the remainder of the request (the elements of a complex subroutine differ from the elements outside the subroutine even when they have the same name). This concept applies to labels, lists, %variables and %variable arrays, menus, screens, and images.</p>
An element that is not passed as a parameter can be shared between complex subroutines, or between a complex subroutine and the main request, when it is declared as a common element. A common element is created by using the <var>Declare</var> statement or by using the <var>Common</var> keyword on a <var><i>%variable</i> Is</var> declaration. For an element to be shared, it must be declared as common in every place (each separate scope) in which it is used. </p>
<p>The elements of the main request (the statements not enclosed by any SUBROUTINE/END SUBROUTINE statements) and the elements of all simple subroutines share the same scope. Simple subroutines share the same elements with the main request and all other simple subroutines within the request.     </p>
 
====Shareable elements====
<p class="note"><b>Note:</b> In [[Object oriented programming in SOUL|SOUL OOP]], the <var>Common</var> keyword is used for non-class properties and subroutines, which are typically defined for more confined, special-purpose uses (such as migration from SOUL to object-oriented SOUL). See [[Local and Common entities#Common methods and aliases|Common methods and aliases]].</p>
<p>The following elements can be shared if they are declared as common:</p>
<b>%variables and %variable arrays</b>
===Scope of elements===
<p>You can share %variables if a DECLARE %variable or a %variable IS statement that declares the %variable as common is present in each portion of the request where you use the %variable. The %variable must have the same type, length, number of decimal places, and FIELD SAVE option in each declaration. </p>
<p>
<b>Lists of records</b>
The scope of an element refers to the area within a request in which an element has a particular meaning. In User Language, complex subroutines have a different scope than the remainder of the request (the elements of a complex subroutine differ from the elements outside the subroutine even when they have the same name). This concept applies to labels, lists, %variables and %variable arrays, menus, screens, and images.</p>
<p>You can share a list if a DECLARE statement that declares the list as common is contained in each place where you use the list. The declaration of the list must precede the first reference to that list, or <var class="product">Model&nbsp;204</var> declares the list implicitly without the common attribute.</p>
<p>
<b>Found sets</b>
The elements of the main request (the statements not enclosed by any <var>Subroutine</var>/<var>End Subroutine</var> statements) and the elements of all simple subroutines share the same scope. Simple subroutines share the same elements with the main request and all other simple subroutines within the request. </p>
<p>You can share found sets if the label of the FIND statement is declared as common. To effectively share a found set, follow these steps:</p>
===Shareable elements===
<p>
The following elements can be shared if they are declared as common:</p>
====%variables and %variable arrays====
<p>
You can share %variables if a <var>Declare <i>%variable</i></var> or a <var><i>%variable</i> Is</var> statement that declares the %variable as common is present in each portion of the request where you use the %variable. The %variable must have the same type, length, number of decimal places, and <var>Field Save</var> option in each declaration. </p>
====Lists of records====
<p>
You can share a list if a <var>Declare</var> statement that declares the list as common is contained in each place where you use the list. The declaration of the list must precede the first reference to that list, or <var class="product">Model&nbsp;204</var> declares the list implicitly without the common attribute.</p>
====Found sets====
<p>
You can share found sets if the label of the <var>Find</var> statement is declared as common. To effectively share a found set, follow these steps: </p>
<ol>
<ol>
<li>Add a DECLARE statement that declares the statement label as common before the actual label in the portion of the request where the FIND statement will be executed.</li>
<li>Add a <var>Declare</var> statement that declares the statement label as common before the actual label in the portion of the request where the <var>Find</var> statement will be executed. </li>
<li>Add a DECLARE statement that declares the label as common to any parts of the request that require access to that found set. These parts, however, cannot contain a label with the same name, or a compiler error occurs. </li>
 
<li>Add a <var>Declare</var> statement that declares the label as common to any parts of the request that require access to that found set. These parts, however, cannot contain a label with the same name, or a compiler error occurs. </li>
</ol>
</ol>
<p>After execution of the FIND statement, you can access the record set in any portion of the request that contains the proper DECLARE statement. </p>
<p>
<b>Menus and screens</b>
After execution of the <var>Find</var> statement, you can access the record set in any portion of the request that contains the proper <var>Declare</var> statement. </p>
<p>You can share a menu or screen as common under the following conditions: </p>
====Menus and screens====
<p>
You can share a menu or screen as common under the following conditions: </p>
<ul>
<ul>
<li>The first reference to the menu or screen must be the complete definition of the menu or screen, with the COMMON keyword following the MENU or SCREEN statement.</li>
<li>The first reference to the menu or screen must be the complete definition of the menu or screen, with the <var>Common</var> keyword following the <var>Menu</var> or <var>Screen</var> statement. </li>
</li>
 
<li>Other parts of the request can reference the same menu or screen by using an abbreviated declaration of the form:</li>
<li>Other parts of the request can reference the same menu or screen by using an abbreviated declaration of the form:
<p class="code">DECLARE [MENU menuname | SCREEN screenname] COMMON
<p class="code">Declare [Menu <i>menuname</i> | Screen <i>screenname</i>] Common </p>
</p>
<p>
<p>If the complete definition of the menu or screen exists, and if that definition was declared as common, the menu or screen is shared. If not, a compiler error results. Two or more complete menu or screen definitions with the COMMON keyword also result in a compiler error.</p>
If the complete definition of the menu or screen exists, and if that definition was declared as common, the menu or screen is shared. If not, a compiler error results. Two or more complete menu or screen definitions with the <var>Common</var> keyword also result in a compiler error. </p>
<p>If you use a menu or screen %variable (:%variable) within a complex subroutine to refer to a COMMON screen element, you must include a common declaration for each possible value of the menu or screen name. </p>
<p>
If you use a menu or screen %variable (:%variable) within a complex subroutine to refer to a <var>Common</var> screen element, you must include a <var>Common</var> declaration for each possible value of the menu or screen name. </p>
</li>
</li>
</ul>
</ul>
<b>Images</b>
<p>The sharing of images follows the same rules used for the sharing of menus and screens. If multiple images are contained within the same block, then the following rules also apply:</p>
====Images====
<p>
The sharing of [[Images|images]] follows the same rules used for the sharing of menus and screens. If multiple images are contained within the same block, then the following rules also apply: </p>
<ul>
<ul>
<li>You can use the COMMON keyword on only the first IMAGE statement of a block. All other images within the same block are automatically considered as candidates for sharing as common data.</li>
<li>You can use the <var>Common</var> keyword on only the first <var>Image</var> statement of an image block. All other images within the same block are automatically considered as candidates for sharing as common data.</li>
</li>
 
<li>All other parts of the request that access common images must contain the following abbreviated form of the DECLARE statement for each image to which access is required: </li>
<li>All other parts of the request that access common images must contain the following abbreviated form of the <var>Declare</var> statement for each image to which access is required:  
<p class="code">DECLARE IMAGE imagename COMMON
<p class="syntax">Declare Image <i>imagename</i> Common
</p></li>
</p></li>
</ul>
</ul>
===Declare statement===
<p>
You can use the <var>Declare</var> statement to perform the following functions: </p>
<ul>
<li>Specify subroutine formal parameter types. </li>


====DECLARE statement====
<li>Specify variables, labels, lists, menus, screens, and images as <var>Common</var>. </li>
<p>You can use the DECLARE statement to perform the following functions:  </p>
</ul>
<p>
Menus and screens are discussed in detail in [[Full-screen feature]]. </p>
<p>
Images are discussed in detail in [[Images]]. </p>
<ul>
<ul>
<li>Specify subroutine formal parameter types.</li>
<li>To declare lists without having to use an <code>In <i>filename</i> Clear List <i>listname</i></code> clause. See [[Lists#Creating and clearing a list|Creating and clearing a list]]. </li>
</li>
<li>Specify variables, labels, lists, menus, screens, and images as COMMON.</li>
</li>
</ul>
<p>Menus and screens are discussed in detail in [[Full-screen feature]]. </p>
<p>Images are discussed in detail in [[Images#Images|Images]].</p>


<ul>
<li>To declare %variables, see [[Using variables and values in computation#Declaring|Declaring %variables and %variable arrays]]. </li>
<li>To declare lists without having to use an IN filename CLEAR LIST listname clause. See [[Lists#Creating and clearing a list|Creating and clearing a list]].</li>
</li>v
<li>To declare %variables, see [[Using variables and values in computation]]. </li>
</li>
</ul>
</ul>
<b>Syntax</b>
<p>The format of the DECLARE statement is as follows:</p>
====Syntax====
<p class="code">DECLARE declaration  
<p>
In the context of sharable elements, the format of the <var>Declare</var> statement is shown below. For information about using <var>Declare</var> for global elements, see [[Global features#Global objects|Global objects]]. For the detailed syntax of <var>Declare</var>, see [[Statement syntax#Declare|Statement syntax]].
</p>
<p class="syntax">Declare <span class="term">declaration</span>
</p>
</p>
<p>where declaration is one of the following:</p>
<p>
<p class="code">LABEL label COMMON
where <span class="term">declaration</span> is one of the following:</p>
<p class="syntax">Label <span class="term">label</span> Common


[LIST] listname [IN [FILE [PERM | TEMP] GROUP] name]
[List] <span class="term">listname</span> [In [File [Perm | Temp] Group] <span class="term">name</span>] [Common]  
                [COMMON]


IMAGE imagename COMMON
Image <span class="term">imagename</span> Common


MENU menuname COMMON
Menu <span class="term">menuname</span> Common


SCREEN screenname COMMON
Screen <span class="term">screenname</span> Common
<span class="term">%variable</span> [Is] {Fixed [Dp <span class="term">n</span>] | Float}
[Array(<span class="term">d1</span> [,<span class="term">d2</span> [,<span class="term">d3</span>]])] [Common]


%variable [IS] {FIXED [DP n] | FLOAT}
<span class="term">%variable</span> [Is] String [Len <span class="term">n</span>] [Dp {<span class="term">dn1</span> | *}]
  [ARRAY(d1 [,d2 [,d3]])] [COMMON]
  [Array(<span class="term">d1</span> [,<span class="term">d2</span> [,<span class="term">d3</span>]])] [No Field Save] [Common]
 
   
%variable [IS] STRING [LEN n] [DP {n | *}]
Subroutine <span class="term">subname</span>[(<span class="term">type</span> [<span class="term">inout-option</span>] [,...]) ]
  [ARRAY(d1 [,d2 [,d3]])] [NO FIELD SAVE] [COMMON]
</p>


SUBROUTINE subname <var>[</var>(type <var>[</var>inout option<var>]</var> <var>[</var>,...<var>]</var>)<var> ]</var>
====Example====
</p>
<p>
<b>Example</b>
For example, the <var>Declare</var> statement declares the list <code>RECNAMES</code> in the following request: </p>
<p>For example, the DECLARE statement declares the list RECNAMES in the following request:</p>
<p class="code">BEGIN
<p class="code">BEGIN
DECLARE LIST RECNAMES
DECLARE LIST RECNAMES
Line 519: Line 651:
     .
     .
     .
     .
SUBROUTINE REGION(LIST RGNLST OUTPUT, -
SUBROUTINE REGION(LIST RGNLST OUTPUT, %REGION IS STRING)
                  %REGION IS STRING)
 
R1: IN EMPLOYEE FIND ALL RECORDS FOR WHICH REGION = %REGION
R1: IN EMPLOYEE FIND ALL RECORDS FOR WHICH
      REGION = %REGION
R2: PLACE RECORDS IN R1 ON LIST RGNLIST
R2: PLACE RECORDS IN R1 ON LIST RGNLIST
END SUBROUTINE
END SUBROUTINE
END  
END
</p>
</p>
====Defining common variables====
<p>You can define common variables at the beginning of all programs without later redefinitions. The syntax lets you use the %VAR IS COMMON clause without duplicating the previous attributes.</p>
===Defining common variables===
<p>However, if attributes, such as STRING or LEN, are included in the redefinition, which differ from those previously defined, a compilation error occurs. In addition, if the variable is not previously defined, it is allocated based on the current default variable definition. </p>
<p>
<p>For example, </p>
You can define common variables at the beginning of all programs without later redefinitions. The syntax lets you use the <var><i>%var</i> Is Common</var> clause without duplicating the previous attributes. </p>
<p>
However, if attributes, such as <var>String</var> or <var>Len</var>, are included in the redefinition, which differ from those previously defined, a compilation error occurs. In addition, if the variable is not previously defined, it is allocated based on the current default variable definition. </p>
<p>
For example: </p>
<p class="code">BEGIN
<p class="code">BEGIN
%X IS STRING LEN 3 INITIAL ('AAA') STATIC COMMON SUBROUTINE A
VARIABLES ARE STRING LEN 20
* full definition on next line no longer required
%X IS STRING LEN 3 INITIAL ('AAA') STATIC COMMON  
** %X IS STRING LEN 3 INITIAL ('AAA') STATIC COMMON
SUBROUTINE A
* new syntax on next line replaces previous line
  * full definition on next line no longer required
%X IS COMMON  /? defaults to previous %X definition ?/
  ** %X IS STRING LEN 3 INITIAL ('AAA') STATIC COMMON
  CALL B
  * new syntax on next line replaces previous line
END SUBROUTINE
  %X IS COMMON  /? defaults to previous %X definition ?/
 
  CALL B
SUBROUTINE B
END SUBROUTINE
* But next line will fail compile since %X already exists
SUBROUTINE B
  * But next line will fail compile since %X already exists
   %X IS STRING LEN 4 COMMON  /? compiler error ?/
   %X IS STRING LEN 4 COMMON  /? compiler error ?/
* And the next line will result in a default definition
  * And the next line will result in a default definition
* since %Y is not previously defined.
  * since %Y is not previously defined.
   %Y IS COMMON
   %Y IS COMMON
  END SUBROUTINE
END SUBROUTINE
  PRINT %X
PRINT %X
  CALL A
CALL A
  END
END
</p>
</p>
====Shared common element examples====
 
<p>The following examples illustrate the differences between data that is locally scoped and data that is shared using the COMMON keyword. </p>
===Shared common element examples===
<b>Example 1</b>
<p>
<p>In this example, the variable %I assumes different values depending upon which part of the request is being executed:</p>
The following examples illustrate the differences between data that is locally scoped and data that is shared using the <var>Common</var> keyword. </p>
====Example 1====
<p>
In this example, the variable <code>%I</code> assumes different values depending upon which part of the request is being executed: </p>
<p class="code">BEGIN
<p class="code">BEGIN
%I IS FIXED
%I IS FIXED
Line 574: Line 714:
   END FOR
   END FOR
END SUBROUTINE
END SUBROUTINE
END  
END
</p>
</p>
<b>Example 2</b>
<p>In this example, the screen EXAMPLE and the %A and %B variables retain the same values no matter which part of the request is being executed:</p>
====Example 2====
<p>
In this example, the screen <code>EXAMPLE</code> and the <code>%A</code> and <code>%B</code> variables retain the same values no matter which part of the request is being executed: </p>
<p class="code">BEGIN
<p class="code">BEGIN
SCREEN EXAMDEF COMMON
SCREEN EXAMDEF COMMON
Line 597: Line 739:
   .
   .
   .
   .
END  
END
</p>
</p>
<b>Example 3</b>
<p>In this example, the main request and the subroutine share the common data of an array and a found set:</p>
====Example 3====
<p>
In this example, the main request and the subroutine share the common data of an array and a found set:</p>
<p class="code">BEGIN
<p class="code">BEGIN
%COM.ARRAY IS STRING LEN 10 ARRAY(10,10) COMMON
%COM.ARRAY IS STRING LEN 10 ARRAY(10,10) COMMON
Line 619: Line 763:
           CALL EXAMPLE
           CALL EXAMPLE
           STOP
           STOP
 
SUBROUTINE EXAMPLE
SUBROUTINE EXAMPLE
%COM.ARRAY IS STRING LEN 10 ARRAY(10,10) COMMON
  %COM.ARRAY IS STRING LEN 10 ARRAY(10,10) COMMON
DECLARE LABEL ALL.RECS COMMON
  DECLARE LABEL ALL.RECS COMMON
%I IS FIXED
  %I IS FIXED
   %I = 0
   %I = 0
   %J = 2
   %J = 2
Line 631: Line 775:
   END FOR
   END FOR
END SUBROUTINE
END SUBROUTINE
END  
END
</p>
</p>
<p>In the preceding example, the main request updates column 1 of the array %COMM.ARRAY with the contents of FLD. The subroutine, EXAMPLE, updates column 2 of the same array with the contents of FLD2. Both the array %COM.ARRAY and the found set ALL.RECS are shared by using the COMMON keyword. %I and %J are both local variables. %I is local because it was declared without the COMMON keyword; %J is local because it was not declared at all.                       </p>
<p>
===ON units===
In the preceding example, the main request updates column 1 of the array <code>%COMM.ARRAY</code> with the contents of <code>FLD</code>. The subroutine, <code>EXAMPLE</code>, updates column 2 of the same array with the contents of <code>FLD2</code>. Both the array <code>%COM.ARRAY</code> and the found set <code>ALL.RECS</code> are shared by using the <var>Common</var> keyword. <code>%I</code> and <code>%J</code> are both local variables. <code>%I</code> is local because it was declared without the <var>Common</var> keyword; <code>%J</code> is local because it was not declared at all. </p>
<p>An ON unit lets you specify a course of action following a triggering event, such as the terminal operator pressing one of the ATTENTION identifier (AID) keys. The ON unit provides an application with a way to override the normal system response. </p>
<b>Syntax</b>
==<b id="On statement"></b>On units==
<p>To define an ON unit, use an ON statement in the following format:</p>
<p>
<p class="code">[label] ON unittype  
An <var>On</var> unit lets you specify a course of action following a triggering event, such as the terminal operator pressing one of the <var>Attention</var> identifier (AID) keys. The <var>On</var> unit provides an application with a way to override the normal system response. </p>
====Syntax====
<p>
To define an <var>On</var> unit, use an <var>On</var> block in the following format:</p>
<p class="syntax">[<span class="term">label</span>] On <span class="term">unittype</span>
  <span class="term">statement</span>
  <span class="literal">...</span>
End On
</p>
</p>
<p>where unittype is one of the following:</p>
<p>
where <var class="term">unittype</var> is one of the following:</p>
<table>
<table>
<tr class="head">
<tr class="head">
Line 646: Line 799:
<th>You can specify the course of action to take if...</th>
<th>You can specify the course of action to take if...</th>
</tr>
</tr>
<tr>
<tr>
<td>ATTENTION</td>
<td>ATTENTION</td>
<td>The end user invokes the attention feature (for example, presses the <var>BREAK, ATTN,</var> or <var>PA1</var> key, or enters <var>*CANCEL</var>).           </td>
<td>The end user invokes the attention feature (for example, presses the <var>BREAK, ATTN,</var> or <var>PA1</var> key, or enters <var>*CANCEL</var>).     </td>
</tr>
</tr>
<tr>
<tr>
<td>ERROR</td>
<td>ERROR</td>
<td><var class="product">Model&nbsp;204</var> cancels a request. Before a request is canceled or, for transaction backout files, after the current transaction is backed out, the ON ERROR unit is processed instead of returning control to the terminal command level. For more information on transaction backout files, see [[Data Recovery#Data Recovery|Data Recovery]].             </td>
<td><var class="product">Model&nbsp;204</var> cancels a request. Before a request is canceled or, for transaction backout files, after the current transaction is backed out, the ON ERROR unit is processed instead of returning control to the terminal command level. For more information on transaction backout files, see [[Data recovery]]. </td>
</tr>
</tr>
<tr>
<tr>
<td>FIELD CONSTRAINT  
<td nowrap>FIELD CONSTRAINT
CONFLICT (FCC)</td>
CONFLICT (FCC)</td>
<td>There are field level constraint conflicts. Violating the UNIQUE and AT-MOST-ONE attributes causes field-level conflicts.*</td>
<td>There are field level constraint conflicts. Violating the UNIQUE and AT-MOST-ONE attributes causes field-level conflicts.*</td>
</tr>
</tr>
<tr>
<tr>
<td>FIND CONFLICT</td>
<td>FIND CONFLICT</td>
<td>A conflict arises evaluating a FIND statement or a FOR EACH RECORD statement used for retrieval.</td>
<td>A conflict arises evaluating a FIND statement or a FOR EACH RECORD statement used for retrieval.</td>
</tr>
</tr>
<tr>
<tr>
<td>MISSING FILE</td>
<td>MISSING FILE</td>
<td>A remote file is no longer available.</td>
<td>A remote file is no longer available.</td>
</tr>
</tr>
<tr>
<tr>
<td>MISSING MEMBER</td>
<td>MISSING MEMBER</td>
<td>A remote optional member is no longer available.</td>
<td>A remote optional member is no longer available.</td>
</tr>
</tr>
<tr>
<tr>
<td>RECORD LOCKING CONFLICT</td>
<td>RECORD LOCKING CONFLICT</td>
Line 676: Line 836:
</tr>
</tr>
</table>
</table>
<p>*If you have procedures written for <var class="product">Model&nbsp;204</var> V2R1.0 that use ON FCC for UNIQUE fields, and you are planning to use ON FCC for AT-MOST-ONE fields, you might need to rewrite the ON FCC unit to take the new value of $UPDSTAT (2 for AT-MOST-ONE) into account. </p>
<p>
<p>Several $functions provide information about conflicts. They are:</p>
*If you have procedures written for <var class="product">Model&nbsp;204</var> V2R1.0 that use ON FCC for UNIQUE fields, and you are planning to use ON FCC for AT-MOST-ONE fields, you might need to rewrite the ON FCC unit to take the new value of $UPDSTAT (2 for AT-MOST-ONE) into account. </p>
<p>
Several $functions provide information about conflicts. They are:</p>
<table>
<table>
<tr>
<tr>
<td>[[$UPDFILE]]</td>
<td>[[$UpdFile]]</td>
<td>[[$UPDFLD]]</td>
<td>[[$UpdFld]]</td>
<td>[[$UPDOVAL]]</td>
<td>[[$UpdOval]]</td>
<td>[[$UPDREC]]</td>
<td>[[$UpdRec]]</td>
</tr>
</tr>
<tr>
<tr>
<td>[[$UPDSTAT]]</td>
<td>[[$UpdStat]]</td>
<td>[[$UPDSTMT]]</td>
<td>[[$UpdStmt]]</td>
<td>[[$UPDVAL]]</td>
<td>[[$UpdVal]]</td>
<td>[[$UNQREC]]</td>
<td>[[$UnqRec]]</td>
</tr>
</tr>
</table>
</table>
====Body of an ON unit====
<p>The body of the ON unit consists of statements immediately following the ON statement. Any User Language statement can appear within an ON unit except the SUBROUTINE statement.</p>
===Body of an On unit===
====Ending an ON unit====
<p>
<p>You must conclude an ON unit with either an END ON statement or an END BLOCK statement. The format of the END ON statement is as follows:</p>
The body of the <var>On</var> unit consists of statements immediately following the <var>On</var> statement. Any User Language statement can appear within an <var>On</var> unit except the SUBROUTINE statement.</p>
<p class="code">END ON <var>[</var>label<var>]</var>
===Ending an On unit===
<p>
You must conclude an ON unit with either an END ON statement or an END BLOCK statement. The format of the END ON statement is as follows:</p>
<p class="syntax">END ON [<span class="term">label</span>]
</p>
</p>
<p>where label is the label of the statement that began the ON statement.     </p>
<p>
====Processing an ON unit====
where <var class="term">label</var> is the label of the statement that began the ON statement. </p>
<p>When an ON statement is evaluated, <var class="product">Model&nbsp;204</var> remembers the location of the ON unit body (the statement after the ON statement and within the unit), but does not immediately evaluate the body. Instead, it passes control to the statement immediately following the ON unit. The ON unit body is evaluated only when the triggering event takes place.</p>
====Usage guidelines for ON units====
===Processing an On unit===
<p>Note the following considerations when using ON units:</p>
<p>
When an <var>On</var> statement is evaluated, <var class="product">Model&nbsp;204</var> remembers the location of the <var>On</var> unit body (the statement after the <var>On</var> statement and within the unit), but does not immediately evaluate the body. Instead, it passes control to the statement immediately following the <var>On</var> unit. The <var>On</var> unit body is evaluated only when the triggering event takes place.</p>
===Usage guidelines for On units===
<p>
Note the following considerations when using <var>On</var> units:</p>
<ul>
<ul>
<li>You must define the ON unit before it is invoked (that is, you should typically place the ON unit near the beginning of your procedure). </li>
<li>You must define the <var>On</var> unit before it is invoked (that is, you should typically place the <var>On</var> unit near the beginning of your procedure). </li>
</li>
 
<li>A subsequent definition of an ON unit of the same kind replaces the previous one. For example, if you define two ON ATTN units, the second one becomes the current one.</li>
<li>A subsequent definition of an <var>On</var> unit of the same kind replaces the previous one. For example, if you define two ON ATTN units, the second one becomes the current one.</li>
</li>
 
<li>You can jump to destinations within the same ON unit. </li>
<li>You can jump to destinations within the same <var>On</var> unit. </li>
</li>
 
<li>You can jump out of an ON unit only to unnested, labeled statements.</li>
<li>You can jump out of an <var>On</var> unit only to unnested, labeled statements.</li>
</li>
 
<li>You cannot jump into an ON unit.</li>
<li>You cannot jump into an <var>On</var> unit.</li>
</li>
 
<li>You can jump outside of an ON unit only if the ON unit is part of a main routine or part of a complex subroutine. </li>
<li>You can jump outside of an ON unit only if the <var>On</var> unit is part of a main routine or part of a complex subroutine. </li>
</li>
 
<li>You cannot jump out of an ON unit contained in a simple subroutine, regardless of whether the destination is within the subroutine or back in the mainline program, because ON units are part of the mainline program; hence, there is no scoping of ON units. This restriction ensures that the ON unit is executed and the control returned to the main routine.</li>
<li>You cannot jump out of an <var>On</var> unit contained in a simple subroutine, regardless of whether the destination is within the subroutine or back in the mainline program, because <var>On</var> units are part of the mainline program; hence, there is no scoping of ON units. This restriction ensures that the <var>On</var> unit is executed and the control returned to the main routine.</li>
<li>An <var>On</var> unit definition is not preserved when a request is continued with an END MORE statement and a MORE command. Each new request continuation must define its own <var>On</var> units. (See [[Large request considerations#Rules for request continuation|Rules for request continuation]].)</li>
 
<li>For complex subroutines, an active <var>On</var> unit is temporarily disabled when a subroutine is called that contains an <var>On</var> UNIT of the same type; it is restored when the subroutine returns. Any ON unit enabled during the execution of a subroutine is replaced by the active <var>On</var> unit at the time of the last CALL statement as soon as the RETURN statement is evaluated.</li>
 
<li><var>On</var> units coded inside complex subroutines can contain JUMP statements that specify a destination outside the <var>On</var> unit. The destination must be to an unnested labeled statement within the complex subroutine. Also, if the <var>On</var> unit is to be jumped out of, the condition that causes the <var>On</var> unit to be invoked must be raised in the subroutine that contains the <var>On</var> unit.
<p>
This prevents a lower level subroutine from returning inadvertently by raising a condition for which there is an <var>On</var> unit coded in a higher level subroutine. If the inadvertent return is attempted, the request is canceled. </p>
</li>
</li>


<li>An ON unit definition is not preserved when a request is continued with an END MORE statement and a MORE command. Each new request continuation must define its own ON units. (See [[Large request considerations#Rules for request continuation|Rules for request continuation]].)</li>
<li><var>On</var> units do not have their own local data and labels. They inherit the scope of the part of the program in which they are compiled. An <var>On</var> unit that is compiled within a complex subroutine is considered part of only that subroutine.  
</li>
<li>For complex subroutines, an active ON unit is temporarily disabled when a subroutine is called that contains an ON UNIT of the same type; it is restored when the subroutine returns. Any ON unit enabled during the execution of a subroutine is replaced by the active ON unit at the time of the last CALL statement as soon as the RETURN statement is evaluated.</li>
</li>
<li>ON units coded inside complex subroutines can contain JUMP statements that specify a destination outside the ON unit. The destination must be to an unnested labeled statement within the complex subroutine. Also, if the ON unit is to be jumped out of, the condition that causes the ON unit to be invoked must be raised in the subroutine that contains the ON unit.</li>
<p>This prevents a lower level subroutine from returning inadvertently by raising a condition for which there is an ON unit coded in a higher level subroutine. If the inadvertent return is attempted, the request is canceled. </p>
</li>
<li>ON units do not have their own local data and labels. They inherit the scope of the part of the program in which they are compiled. An ON unit that is compiled within a complex subroutine is considered part of only that subroutine.         </li>
</li>
</li>
</ul>
</ul>
<b>Example</b>
<p>In the following example, if the user presses the<var> ATTN</var> key instead of entering a response to the prompt in the GET.REC.TYPE statement, the ON ATTENTION unit sets %FLAG to 1. The FLAG.SET statement tests %FLAG. If %FLAG is set, the request branches to END.REQUEST and the FIND statement is not executed. </p>
====Example====
<p>
In the following example, if the user presses the<var> ATTN</var> key instead of entering a response to the prompt in the GET.REC.TYPE statement, the <code>ON ATTENTION</code> unit sets %FLAG to 1. The FLAG.SET statement tests %FLAG. If %FLAG is set, the request branches to END.REQUEST and the FIND statement is not executed. </p>
<p class="code">%FLAG=0
<p class="code">%FLAG=0
               ON ATTENTION
               ON ATTENTION
                 %FLAG=1
                 %FLAG=1
                BYPASS
               END ON
               END ON
GET.REC.TYPE: %TYPE=$READ('ENTER RECORD TYPE')
GET.REC.TYPE: %TYPE=$READ('ENTER RECORD TYPE')
Line 746: Line 921:
                 .
                 .
END.REQUEST:
END.REQUEST:
END  
END
</p>
</p>
====Only one ON unit at a time====
<p>Only one ON unit of each kind is active at a time. For example, the processing of a second ON ERROR statement resets the current ON ERROR unit, but does not affect the current ON ATTENTION unit. Thus, you can redefine what to do in a variety of cases by having several ON statements and units within a request. An ON unit can be redefined within another ON unit.</p>
===Only one On unit at a time===
====Passing control to and from ON units====
<p>
<p><var class="product">Model&nbsp;204</var> passes control to an ON unit when the triggering event occurs. For example, an ON ATTENTION unit receives control when a user presses one of the ATTENTION identifier (AID) keys at the terminal during the execution of a request. Use one of the following statements to return control to the body of the request.   </p>
Only one <var>On</var> unit of each kind is active at a time. For example, the processing of a second ON ERROR statement resets the current ON ERROR unit, but does not affect the current ON ATTENTION unit. Thus, you can redefine what to do in a variety of cases by having several ON statements and units within a request. An <var>On</var> unit can be redefined within another <var>On</var> unit.</p>
<b>BYPASS statement</b>
<p>The BYPASS statement handles the various unittypes of an ON statement as follows:</p>
===Passing control to and from On units===
<p>
<var class="product">Model&nbsp;204</var> passes control to an <var>On</var> unit when the triggering event occurs. For example, an ON ATTENTION unit receives control when a user presses one of the ATTENTION identifier (AID) keys at the terminal during the execution of a request. Use one of the following statements to return control to the body of the request. </p>
====BYPASS statement====
<p>
The BYPASS statement handles the various unittypes of an <var>On</var> statement as follows:</p>
<table>
<table>
<tr class="head">
<tr class="head">
Line 760: Line 941:
</tr>
</tr>
<tr>
<tr>
<td>ON MISSING FILE
<td>ON MISSING FILE<br>
ON MISSING MEMBER</td>
ON MISSING MEMBER</td>
<td>Returns control to the statement immediately after the END FOR statement that closes the current FOR loop. </td>
<td>Returns control to the statement immediately after the END FOR statement that closes the current FOR loop. </td>
Line 769: Line 950:
</tr>
</tr>
<tr>
<tr>
<td>ON ATTENTION
<td nowrap>ON ATTENTION<br>
ON FIND CONFLICT
ON FIND CONFLICT<br>
ON RECORD LOCKING CONFLICT</td>
ON RECORD LOCKING CONFLICT</td>
<td>Returns control to the statement immediately after the statement that invoked the ON unit.</td>
<td>Returns control to the statement immediately after the statement that invoked the <var>On</var> unit.</td>
</tr>
</tr>
</table>
</table>
<p>The format of the BYPASS statement is as follows:</p>
<p>
<p class="code">BYPASS <var>[</var>PENDING STATEMENT<var>]</var>
The format of the BYPASS statement is as follows:</p>
<p class="syntax">BYPASS [PENDING STATEMENT]
</p>
</p>
<p>where the PENDING STATEMENT keyword is optional. If the ON unit is not ended with a BYPASS statement, <var class="product">Model&nbsp;204</var> automatically generates a STOP statement at the end of the unit.   </p>
<p>
<b>CONTINUE statement</b>
where the PENDING STATEMENT keyword is optional. If the <var>On</var> unit is not ended with a BYPASS statement, <var class="product">Model&nbsp;204</var> automatically generates a STOP statement at the end of the unit. </p>
<p>The CONTINUE statement is supported only with the Parallel Query Option. If you lose access to a group member that is an optional file during FOR processing, the CONTINUE statement continues FOR processing with the next available file, and skips any other unavailable files.</p>
<b>JUMP TO statement</b>
====CONTINUE statement====
<p>The JUMP statement, when used to jump to a labeled statement outside the ON unit, causes the request to continue at that point. There are restrictions pertaining to jumps; see [[Flow of Control in User Language#Branching statements|Branching statements]] and [[#Simple subroutines|Simple subroutines]]. </p>
<p>
<b>RETRY statement</b>
The CONTINUE statement is supported only with the Parallel Query Option. If you lose access to a group member that is an optional file during FOR processing, the CONTINUE statement continues FOR processing with the next available file, and skips any other unavailable files.</p>
<p>The RETRY statement passes control to the statement that invoked the ON unit, thereby retrying that statement. The RETRY statement is not valid in an ON ERROR unit.</p>
<p>The format of the RETRY statement is as follows:</p>
====JUMP TO statement====
<p class="code">RETRY [PENDING STATEMENT]
<p>
The JUMP statement, when used to jump to a labeled statement outside the ON unit, causes the request to continue at that point. There are restrictions pertaining to jumps; see [[Flow of control in User Language#Branching statements|Branching statements]] and [[#Simple subroutines|Simple subroutines]]. </p>
====RETRY statement====
<p>
The RETRY statement passes control to the statement that invoked the ON unit, thereby retrying that statement. The RETRY statement is not valid in an ON ERROR unit.</p>
<p>
The format of the RETRY statement is as follows:</p>
<p class="syntax">RETRY [PENDING STATEMENT]
</p>
</p>
<p>where the PENDING STATEMENT keyword is optional.</p>
<p>
<b>STOP statement</b>
where the <var>PENDING STATEMENT</var> keyword is optional.</p>
<p>The STOP statement is used to end the request.        </p>
====Clearing ON units====
====STOP statement====
<p>You can issue the following statement to clear the definition of an ON unit:  </p>
<p>
<p class="code">CLEAR ON unittype  
The STOP statement is used to end the request.        </p>
===Clearing On units===
<p>
You can issue the following statement to clear the definition of an <var>On</var> unit:  </p>
<p class="syntax">CLEAR ON <span class="term">unittype</span>
</p>
</p>
<p>This statement clears any defined ON unit of the type specified. Clearing an ON unit produces the following results:</p>
<p>
This statement clears any defined <var>On</var> unit of the type specified. Clearing an ON unit produces the following results:</p>
 
<ul>
<ul>
<li>After a CLEAR ON ATTENTION, pressing one of the ATTENTION identifier (AID) keys at the terminal does not invoke the ON ATTENTION unit.</li>
<li>After a CLEAR ON ATTENTION, pressing one of the ATTENTION identifier (AID) keys at the terminal does not invoke the ON ATTENTION unit.</li>
</li>
 
<li>After a CLEAR ON ERROR, a request cancellation error does not invoke the ON ERROR unit. </li>
<li>After a CLEAR ON ERROR, a request cancellation error does not invoke the ON ERROR unit. </li>
</li>
</ul>
</ul>
<p>An ON unit can be defined, cleared, and then redefined. </p>
<p>
====Pausing during the request====
An <var>On</var> unit can be defined, cleared, and then redefined. </p>
<p>The PAUSE statement can be used with ON units to cause the request to wait a specified time and then to retry the statement that caused the evaluation of the ON unit. PAUSE is typically used with the other ON unit types (RECORD LOCKING CONFLICT and ON FIND CONFLICT) and is discussed in [[Record level locking and concurrency control]].         </p>
===Pausing during the request===
<p>
The <var>[[Pause statement|Pause]]</var> statement can be used with <var>On</var> units to cause the request to wait a specified number of seconds and then to retry the statement that caused the evaluation of the <var>On</var> unit. <var>Pause</var> is typically used with the other <var>On</var> unit types (<var>On Record Locking Conflict</var> and <var>On Find Conflict</var>) and is discussed in [[Record level locking and concurrency control]].   </p>
 
<p>The <var>[[$WakeUp]]</var> function is an alternative approach; it offers millisecond resolution pausing.</p>
 
</div> <!-- end of toc limit div -->


[[Category:SOUL]]
[[Category:SOUL]]

Latest revision as of 00:05, 30 May 2018

Overview

User Language lets you treat a single set of statements as a simple or complex subroutine. You can:

  • Execute simple subroutines a number of times from different locations within a request.
  • Use complex subroutines as you would simple subroutines.

In addition, you can:

  • Pass parameters via parameter lists.
  • Declare variables locally.

Common elements

An element that is not passed as a parameter can be shared between complex subroutines, or between a complex subroutine and the main request, when you declare that element as COMMON.

On units

As described later, an On unit specifies a response action to a triggering event: for example, the terminal operator pressing one of the ATTENTION identifier (AID) keys. On units let an application override the normal system response.

Simple subroutines

Outlining a simple subroutine

The following statements are used in simple subroutines within a request:

Statement Purpose
CALL Transfers control to the subroutine.
END SUBROUTINE Indicates the end of the subroutine.
JUMP TO Transfers control to another statement in the request.
RETURN Returns control to the statement immediately following the CALL statement.
SUBROUTINE Indicates the beginning of a subroutine.

The statements are coded in the following sequence, so they are described in order of usage.

  1. SUBROUTINE statement
  2. JUMP TO and RETURN statements as appropriate
  3. END SUBROUTINE statement
  4. CALL statement

SUBROUTINE statement

A simple subroutine consists of a sequence of SOUL statements that must begin with a SUBROUTINE statement. The body of the subroutine is composed of the statements immediately following the SUBROUTINE statement.

Syntax

The format of the SUBROUTINE statement is:

label: SUBROUTINE

A simple subroutine must be labeled; without a label it cannot be executed. You cannot use field names in the subroutine, except within a FOR loop, even if the subroutine is always called from within a record loop.

Example of a simple subroutine

The following request uses two subroutines.

Note: Simple subroutine statements in the following example are described more fully after this example.

The first subroutine, TOTAL, accumulates a total in the %variable named %TOTAL.MUSTANGS. The second subroutine, PRINT.TOTAL, prints a literal that varies depending on the total accumulated.

BEGIN MUSTANGS: FIND ALL RECORDS FOR WHICH MODEL = MUSTANG END FIND FOR EACH RECORD IN MUSTANGS CALL TOTAL END FOR CALL PRINT.TOTAL TOTAL: SUBROUTINE %TOTAL.MUSTANGS = %TOTAL.MUSTANGS + 1 RETURN END SUBROUTINE TOTAL PRINT.TOTAL: SUBROUTINE IF %TOTAL.MUSTANGS LE 10 THEN PRINT 'TOTAL MUSTANG POLICIES - NOT GREATER THAN 10' ELSEIF %TOTAL.MUSTANGS LE 50 THEN PRINT 'TOTAL MUSTANG POLICIES - NOT GREATER THAN 50' ELSEIF %TOTAL.MUSTANGS GT 50 THEN PRINT 'TOTAL MUSTANG POLICIES - GREATER THAN 50' END IF RETURN END SUBROUTINE PRINT.TOTAL END

JUMP TO statements

Model 204 compiles subroutines only after they are called, regardless of where they are in your program.

If you use a JUMP TO statement, its destination must be within the same subroutine. You cannot jump into a subroutine from outside of a subroutine.

RETURN statement

The RETURN statement returns control from the subroutine to the statement following the most recent CALL statement.

Syntax

The format of the RETURN statement is:

RETURN

The RETURN statement can appear only within the body of a subroutine. Use of the RETURN statement inside of an ON unit terminates compilation, the procedure cannot run, and the following message is produced:

M204.1779 RETURN IS INVALID IN ON UNITS, USE BYPASS STATEMENT

Model 204 automatically generates a return at the end of a subroutine, if you do not specify one.

For more information, see ON units and Passing control to and from ON units.

END SUBROUTINE statement

You can end a subroutine using an END SUBROUTINE statement or an END BLOCK statement.

Syntax

The END SUBROUTINE statement is formatted as follows:

END SUBROUTINE [label]

CALL statement

The CALL statement transfers control to the subroutine.

Syntax

The format of the CALL statement is:

CALL label

Example

This statement:

CALL.SUB: CALL COMPUTE.PREMIUM

transfers control to the following statement:

COMPUTE.PREMIUM: SUBROUTINE

When you use a simple subroutine, no arguments are passed in subroutine calls. Instead, input and output values are implicitly passed in %variables or global variables. If you want field values as arguments, you must assign the values to %variables before the call, or the subroutine must contain its own FOR EACH RECORD loop on the set of records to be processed.

Processing continues sequentially from that statement until another control transfer statement — a CALL, IF, JUMP TO, RETURN, or STOP statement — is encountered.

Complex subroutines

Complex subroutines perform all the operations of a simple subroutine. In addition, a complex subroutine can pass parameters via parameter lists and can declare local variables.

Note: The format of the SUBROUTINE statement changes for a complex subroutine and the CALL statement is also more complex.

Symbolic parameter passing

You can specify positional parameters on the CALL statement for a complex subroutine. These parameters are substituted for symbolic parameters used within the subroutine during execution. You can use the following elements as parameters to a complex subroutine:

  • Scalar %variables
  • %variable arrays
  • Lists of records

Local variable declaration

Labels, %variables, and other elements in a complex subroutine are local to the subroutine; they do not conflict with elements of the same name in the request or in other complex subroutines. This allows the same element to be used in different portions of a request, and for the same name to describe different elements in each portion.

Processing

All data within the subroutine is statically allocated. When the subroutine is called, the values of all found sets, counts, noted values, and variables are as they were when the subroutine was last executed. Recursive calls to the same subroutine do not allocate separate storage for each subroutine local variable. Local variables are allocated only one time.

OPEN statement within a complex subroutine

A SOUL OPEN statement — an OPEN statement inside a BEGIN/END — when used within a complex subroutine on a file that is not defined to the region produces the following counting error and the request is not compiled:

M204.1521: entity-name DOES NOT EXIST OR REQUESTED ACCESS NOT AUTHORIZED

SUBROUTINE statement for complex subroutines

Complex subroutines begin with the following form of the SUBROUTINE statement:

SUBROUTINE subname [(formal-parameter [inout-option] [, ...])]

Where:

  • subname is the name of the subroutine.
  • formal-parameter is the declaration of a symbolic parameter used within the subroutine. The parameter list is comprised of the formal-parameter and subsequent input-options. The parameter list is enclosed in parentheses, and it contains declarations for each parameter separated by commas. The parameter list must be specified on one logical line. Null parameters are not allowed.
  • formal-parameter specifies the name and type of element to be used within the subroutine and can be any of the following:
    • Scalar (nonarray) %variable formatted as:

      %variable [IS] {[STRING] [LEN] n [DP {n | *}] | [FIXED [DP n] | FLOAT]}

      For example:

      SUBROUTINE EXAMPLE (%W IS STRING DP * - %X IS STRING LEN 40, - %Y IS STRING LEN 10 DP 2, - %Z IS FLOAT, - %A IS FIXED DP 4)

    • Array %variable formatted as:

      %variable [IS] [[STRING] [LEN n] [DP {n | *}] [ARRAY(* [,*[,*]])] [NO FIELD SAVE] | {FIXED [DP n] | FLOAT} [ARRAY(* [,*[,*]])]]

      The number of dimensions must be specified in the subroutine declaration, but the exact size of each dimension is not specified. An asterisk (*) is used instead of the dimension size. For example:

      SUBROUTINE EXAMPLE(%ARR IS STRING LEN 10 - ARRAY(*,*))

    • A list of records formatted as:

      [LIST] listname [IN [FILE | [PERM | TEMP] GROUP]] name

      The context of the list is restricted to a single file or group. For example:

      SUBROUTINE GENERAL(LIST TOTRECS IN FILE VEHICLES)

  • inout-option specifies whether a formal-parameter is to be used as input to the subroutine or passed as output from the subroutine. Options are as follows:
    Option Data can be...
    INPUT
    (the default)
    Passed into, but not out of, a subroutine. In addition, data conversions are performed automatically, in the same manner as an assignment statement. All references to INPUT parameters that update the parameter, for example, assignment statements, result in compiler errors.
    INPUT OUTPUT This option is equivalent to the OUTPUT option.
    OUTPUT Returned from a subroutine. No data conversions are performed.

    The lengths of complex subroutine string OUTPUT parameters are inherited from calling parameters. If the lengths are specified in the subroutine declaration, the following message is written to the audit trail:

    M204.1981 LENGTH IGNORED FOR OUTPUT PARAMETER

    Compilation and evaluation of the procedure continues, with the inherited length.

END SUBROUTINE statement

Like simple subroutines, a complex subroutine ends with an END SUBROUTINE statement. However, unlike simple subroutines, you must not label the SUBROUTINE statement.

All declarations and statements compiled after the SUBROUTINE statement become a part of the subroutine until the END SUBROUTINE statement is encountered or until the request is ended with the END statement.

CALL statement

The execution of a CALL statement passes control to a complex subroutine. The first time a subroutine is called, all elements in the subroutine are initialized. Subsequently, each time the subroutine is called, all elements in the subroutine remain in the same state as they were when the subroutine was last exited. You are responsible for reinitializing the elements within the subroutine.

Syntax

A complex subroutine is invoked with this form of the CALL statement:

CALL subname [(actual-parameter [, ...])]

Where:

  • subname is the name of the subroutine.
  • actual-parameter specifies the actual data that replaces the symbolic formal-parameter within the subroutine. At execution time, the value of each actual-parameter is substituted, based on the order in which it appears, for a formal-parameter declared for the subroutine. The correspondence of each formal-parameter in the SUBROUTINE statement to an actual-parameter in the CALL statement is by position rather than by name.

    An actual-parameter can be any of the following:

    • %variable or expression

      Expressions can contain field names, screen items, image items, and constants.

    • Array %variable

      When an entire array is passed as a parameter, the %variable name is used with the percent (%) sign, but no parenthesis or subscript expressions follow it. For example:

      BEGIN %A IS FLOAT ARRAY(10,10) DECLARE SUBROUTINE FDO(FLOAT ARRAY(*,*)) . . . CALL FDO (%A) . . . SUBROUTINE FDO (%B IS FLOAT ARRAY(*,*)) PRINT %B(1,1) END SUBROUTINE END

      The $ArrSize function can be used to determine the number of elements in a particular dimension of an array.

    • A list

      An actual-parameter can be a list, optionally preceded by the word LIST to distinguish it from a field name.

      If the compiler already knows of the formal-parameter list because the subroutine is already compiled or declared, the LIST keyword is unnecessary.

      If the list has never been declared in the request, a compilation error results.

Additional rules for parameters

The following additional rules apply to actual-parameters and parameter passing:

  • The maximum number of parameters that can be passed in complex subroutines is 63.
  • If the formal-parameter is specified as an OUTPUT parameter, the corresponding actual-parameter must match type.
  • The INPUT parameters of a %variable array requires that the type of the array — FLOAT, FIXED, or STRING — the DP specification, and the number of dimensions match the actual-parameter. In addition, if the NO FIELD SAVE (NO FS) option is specified for a STRING formal-parameter, it also must be specified for the corresponding actual-parameter and vice versa. All checking of array bounds within subroutines occurs during evaluation.
  • The INPUT parameters of a list requires the same file or group context as the actual-parameter.
  • An INPUT parameter of a scalar %variable can be called with an actual-parameter that is an expression or %variable of a differing type. Model 204 converts the actual-parameter to the type required by the subroutine, according to the rules of the assignment statement. The converted value has a separate storage location from the original variable or expression.

    Passing arguments to INPUT parameters might involve truncation where the number of decimal places is different, or conversion to 0 for non-numeric strings.

  • OUTPUT parameters of lists and %variable arrays follow the same rules as INPUT parameters for lists and %variable arrays.
  • OUTPUT parameters of scalar %variables require that the actual-parameter supplied in the CALL statement be another scalar %variable (no constants or expressions) of the same type — FLOAT, FIXED, or STRING — and that the number of decimal places be the same, or the following message is issued by Model 204:

    M204.1725 PARAMETER NUMBER n IS TYPE INCOMPATIBLE

    Strings can be of any length. The length used is that of the actual input parameter.

Processing complex subroutines

Checking for the validity of parameter lists occurs during compilation. When the SUBROUTINE statement is compiled, the types of parameters are saved by the compiler, and any subsequent CALL statements are verified as to whether the actual parameter is consistent with the type of formal parameter.

When a CALL statement is compiled and the subroutine to which it refers has not been compiled, the compiler verifies whether the actual parameter list is compatible with other CALL statements for the subroutine that it has already compiled.

The compiler cannot verify that the actual parameters are compatible with the SUBROUTINE statement until that SUBROUTINE statement is compiled. If the compiler then detects a CALL statement that is not compatible with the SUBROUTINE statement, an error is issued at that time. Checking is done at compile time, so a statement that is not executed during evaluation can still generate an error.

DECLARE SUBROUTINE statement

The DECLARE statement for a complex subroutine is similar to the SUBROUTINE statement, except that the parameter names are omitted.

Syntax

The complete syntax for the DECLARE SUBROUTINE statement is:

DECLARE SUBROUTINE subname [(type [inout-option] [, ...])]

Where:

  • subname is the name of the subroutine.
  • type is one of the following:
    • Scalar %variable of the following format:

      {STRING [LEN] n [DP {n | *}] | [FIXED [DP n] | FLOAT]}

    • Array %variable of the following format:

      {STRING [LEN n] [DP [n | *}] [ARRAY(* [,*[,*]]) [NO FIELD SAVE]] | [FIXED [DP n] | FLOAT] [ARRAY(* [,*[,*]])]}

    • A list of records of the following format:

      [LIST] [IN {FILE | [PERM | TEMP] GROUP} name]

  • inout-option specifies whether each formal parameter is to be used as input to the subroutine or passed as output from the subroutine. Options are the same as those that can be specified on the SUBROUTINE statement: INPUT, OUTPUT, or INPUT OUTPUT.

DECLARE before CALL

When a CALL statement refers to a subroutine that has not yet been compiled, the error checking capabilities of the compiler are limited, because the number and type of formal parameters are not known to the compiler. If the first CALL statement for a particular subroutine is not correctly coded, then a large number of error messages can be generated when compiling subsequent CALL statements, although these statements might be correctly coded.

You can avoid this problem in one of the following ways:

  • Declare the formal parameter list with the DECLARE statement. When the DECLARE statement precedes the first CALL, the compiler generates the correct error messages, if problems are encountered.
  • Place the subroutine before the first CALL statement.

Specifying a list of records

If you specify a LIST (of records), you must also specify FILE or GROUP. For example:

OPEN METADATA password BEGIN DECLARE LIST ORIG IN METADATA DECLARE SUBROUTINE THE.SUB(LIST IN FILE METADATA INOUT) . . CALL THE.SUB (LIST ORIG) . . SUBROUTINE THE.SUB(LIST ORIG IN METADATA INOUT) . . END SUBROUTINE THE.SUB END

If you do not specify FILE or GROUP in the code, you receive the following error message:

M204.1725: PARAMETER NUMBER n IS TYPE INCOMPATIBLE

DECLARE parameters and CALL parameters

In the following example, note that the DECLARE statement lists the formal parameters, while the CALL statement lists the actual parameters:

DECLARE SUBROUTINE SUB1(FLOAT, FIXED DP 2, STRING, STRING DP *) . . CALL SUB1(%INCREASE,%WAGES,%NAME,%DEPT) . . SUBROUTINE SUB1(%A IS FLOAT, %B IS FIXED DP 2, %C IS STRING, %D IS STRING DP *) END SUBROUTINE . . END

Impact on CALL and SUBROUTINE statements

The CALL and SUBROUTINE statements are not overridden when a DECLARE SUBROUTINE statement is present. The DECLARE SUBROUTINE statement does not cause the compiler to use more table space, nor does it alter the way in which the compiler output is generated.

Rocket Software recommends that you use a DECLARE SUBROUTINE statement before the CALL statement for a subroutine or that you place the subroutine itself before the CALL statement. Error reporting will be more complete and specific to the subroutine.

Exiting the subroutine

The RETURN statement returns control to the statement immediately following the most recent CALL statement. If an END SUBROUTINE or END statement is encountered without a RETURN statement, RETURN processing is implied and automatically added by the compiler. More than one RETURN statement can be specified in a subroutine.

If a JUMP statement is used within a subroutine, its destination must be within the same subroutine. You cannot jump into a subroutine.

A STOP statement, when executed inside a subroutine, terminates the request in the same manner as it does when executed outside a subroutine.

Examples using complex subroutines

In the following example, an employee name with regular and overtime hours is passed to the subroutine CALC.WAGES. The total pay is returned and a list of records processed by the routine is updated.

BEGIN DECLARE SUBROUTINE CALC.WAGES(FIXED DP 2, - FIXED DP 2, STRING, FIXED DP 2 OUTPUT, - LIST IN FILE EMPLOYEE INOUT) . . . CALL CALC.WAGES(%R.HRS, %OT.HRS, %NAME, - %TOTAL.PAY, LIST EMPLST) . . . SUBROUTINE CALC.WAGES(%REG IS FIXED DP 2, - %OT IS FIXED DP 2, - %E.NAME IS STRING, - %TOTAL IS FIXED DP 2 OUTPUT, - LIST EMPLIST IN FILE EMPLOYEE INOUT) %TEMP IS FIXED DP 2 WAGES1: IN EMPLOYEE FIND ALL RECORDS FOR WHICH NAME = %E.NAME END FIND FOR EACH RECORD IN WAGES1 %TEMP = (RATE * %REG) %TOTAL = %TEMP + (RATE * 1.5 * %OT) END FOR PLACE RECORDS IN WAGES1 ON LIST EMPLIST RETURN END SUBROUTINE END

In the following example, an entire array is passed as a single subroutine parameter:

BEGIN %NUMBERS IS FLOAT ARRAY(10,10) %MAX IS FLOAT DECLARE SUBROUTINE MAXIMUM(FLOAT ARRAY(*,*), FLOAT OUTPUT) . . . CALL MAXIMUM(%NUMBERS,%MAX) . . . SUBROUTINE MAXIMUM(%ARR IS FLOAT ARRAY(*,*), %M IS FLOAT OUTPUT) %I IS FIXED %J IS FIXED %M = 0 FOR %I FROM 1 TO $arrsize('%ARR',1) FOR %J FROM 1 TO $arrsize('%ARR',2) IF %ARR(%I,%J) GT %M THEN %M = %ARR(%I,%J) END IF END FOR END FOR END SUBROUTINE END

Sharing common elements

An element that is not passed as a parameter can be shared between complex subroutines, or between a complex subroutine and the main request, when it is declared as a common element. A common element is created by using the Declare statement or by using the Common keyword on a %variable Is declaration. For an element to be shared, it must be declared as common in every place (each separate scope) in which it is used.

Note: In SOUL OOP, the Common keyword is used for non-class properties and subroutines, which are typically defined for more confined, special-purpose uses (such as migration from SOUL to object-oriented SOUL). See Common methods and aliases.

Scope of elements

The scope of an element refers to the area within a request in which an element has a particular meaning. In User Language, complex subroutines have a different scope than the remainder of the request (the elements of a complex subroutine differ from the elements outside the subroutine even when they have the same name). This concept applies to labels, lists, %variables and %variable arrays, menus, screens, and images.

The elements of the main request (the statements not enclosed by any Subroutine/End Subroutine statements) and the elements of all simple subroutines share the same scope. Simple subroutines share the same elements with the main request and all other simple subroutines within the request.

Shareable elements

The following elements can be shared if they are declared as common:

%variables and %variable arrays

You can share %variables if a Declare %variable or a %variable Is statement that declares the %variable as common is present in each portion of the request where you use the %variable. The %variable must have the same type, length, number of decimal places, and Field Save option in each declaration.

Lists of records

You can share a list if a Declare statement that declares the list as common is contained in each place where you use the list. The declaration of the list must precede the first reference to that list, or Model 204 declares the list implicitly without the common attribute.

Found sets

You can share found sets if the label of the Find statement is declared as common. To effectively share a found set, follow these steps:

  1. Add a Declare statement that declares the statement label as common before the actual label in the portion of the request where the Find statement will be executed.
  2. Add a Declare statement that declares the label as common to any parts of the request that require access to that found set. These parts, however, cannot contain a label with the same name, or a compiler error occurs.

After execution of the Find statement, you can access the record set in any portion of the request that contains the proper Declare statement.

Menus and screens

You can share a menu or screen as common under the following conditions:

  • The first reference to the menu or screen must be the complete definition of the menu or screen, with the Common keyword following the Menu or Screen statement.
  • Other parts of the request can reference the same menu or screen by using an abbreviated declaration of the form:

    Declare [Menu menuname | Screen screenname] Common

    If the complete definition of the menu or screen exists, and if that definition was declared as common, the menu or screen is shared. If not, a compiler error results. Two or more complete menu or screen definitions with the Common keyword also result in a compiler error.

    If you use a menu or screen %variable (:%variable) within a complex subroutine to refer to a Common screen element, you must include a Common declaration for each possible value of the menu or screen name.

Images

The sharing of images follows the same rules used for the sharing of menus and screens. If multiple images are contained within the same block, then the following rules also apply:

  • You can use the Common keyword on only the first Image statement of an image block. All other images within the same block are automatically considered as candidates for sharing as common data.
  • All other parts of the request that access common images must contain the following abbreviated form of the Declare statement for each image to which access is required:

    Declare Image imagename Common

Declare statement

You can use the Declare statement to perform the following functions:

  • Specify subroutine formal parameter types.
  • Specify variables, labels, lists, menus, screens, and images as Common.

Menus and screens are discussed in detail in Full-screen feature.

Images are discussed in detail in Images.

Syntax

In the context of sharable elements, the format of the Declare statement is shown below. For information about using Declare for global elements, see Global objects. For the detailed syntax of Declare, see Statement syntax.

Declare declaration

where declaration is one of the following:

Label label Common [List] listname [In [File [Perm | Temp] Group] name] [Common] Image imagename Common Menu menuname Common Screen screenname Common %variable [Is] {Fixed [Dp n] | Float} [Array(d1 [,d2 [,d3]])] [Common] %variable [Is] String [Len n] [Dp {dn1 | *}] [Array(d1 [,d2 [,d3]])] [No Field Save] [Common] Subroutine subname[(type [inout-option] [,...]) ]

Example

For example, the Declare statement declares the list RECNAMES in the following request:

BEGIN DECLARE LIST RECNAMES DECLARE SUBROUTINE REGION(LIST OUTPUT, STRING) . . . CALL REGION(LIST RECNAMES, 'NORTHEAST') . . . SUBROUTINE REGION(LIST RGNLST OUTPUT, %REGION IS STRING) R1: IN EMPLOYEE FIND ALL RECORDS FOR WHICH REGION = %REGION R2: PLACE RECORDS IN R1 ON LIST RGNLIST END SUBROUTINE END

Defining common variables

You can define common variables at the beginning of all programs without later redefinitions. The syntax lets you use the %var Is Common clause without duplicating the previous attributes.

However, if attributes, such as String or Len, are included in the redefinition, which differ from those previously defined, a compilation error occurs. In addition, if the variable is not previously defined, it is allocated based on the current default variable definition.

For example:

BEGIN VARIABLES ARE STRING LEN 20 %X IS STRING LEN 3 INITIAL ('AAA') STATIC COMMON SUBROUTINE A * full definition on next line no longer required ** %X IS STRING LEN 3 INITIAL ('AAA') STATIC COMMON * new syntax on next line replaces previous line %X IS COMMON /? defaults to previous %X definition ?/ CALL B END SUBROUTINE SUBROUTINE B * But next line will fail compile since %X already exists %X IS STRING LEN 4 COMMON /? compiler error ?/ * And the next line will result in a default definition * since %Y is not previously defined. %Y IS COMMON END SUBROUTINE PRINT %X CALL A END

Shared common element examples

The following examples illustrate the differences between data that is locally scoped and data that is shared using the Common keyword.

Example 1

In this example, the variable %I assumes different values depending upon which part of the request is being executed:

BEGIN %I IS FIXED DECLARE SUBROUTINE SUBR1(STRING) . . . FOR %I FROM 1 TO 10 CALL SUBR1(%ARR(%I)) END FOR . . . SUBROUTINE SUBR1(%A IS STRING) %I IS FIXED FOR %I FROM 1 TO 10 PRINT %I and %A END FOR END SUBROUTINE END

Example 2

In this example, the screen EXAMPLE and the %A and %B variables retain the same values no matter which part of the request is being executed:

BEGIN SCREEN EXAMDEF COMMON TITLE 'THIS IS A COMMON SCREEN DEFINITION' PROMPT 'ENTER VALUE' INPUT FLD1 AT 10 LEN 20 PAD '_' END SCREEN %A IS STRING LEN 10 COMMON %B IS FLOAT COMMON DECLARE SUBROUTINE SUBR1(STRING LEN 10) . . . SUBROUTINE SUBR1(%Z IS STRING LEN 10) DECLARE SCREEN EXAMDEF COMMON %A IS STRING LEN 10 COMMON %B IS FLOAT COMMON . . . END

Example 3

In this example, the main request and the subroutine share the common data of an array and a found set:

BEGIN %COM.ARRAY IS STRING LEN 10 ARRAY(10,10) COMMON DECLARE LABEL ALL.RECS COMMON %I IS FIXED DECLARE SUBROUTINE EXAMPLE . . . ALL.RECS: FIND ALL RECORDS END FIND %I = 0 %J = 1 FOR 10 RECORDS IN ALL.RECS %I = %I + 1 %COM.ARRAY(%I,%J) = FLD END FOR CALL EXAMPLE STOP SUBROUTINE EXAMPLE %COM.ARRAY IS STRING LEN 10 ARRAY(10,10) COMMON DECLARE LABEL ALL.RECS COMMON %I IS FIXED %I = 0 %J = 2 FOR 10 RECORDS IN ALL.RECS %I = %I + 1 %COM.ARRAY(%I,%J) = FLD2 END FOR END SUBROUTINE END

In the preceding example, the main request updates column 1 of the array %COMM.ARRAY with the contents of FLD. The subroutine, EXAMPLE, updates column 2 of the same array with the contents of FLD2. Both the array %COM.ARRAY and the found set ALL.RECS are shared by using the Common keyword. %I and %J are both local variables. %I is local because it was declared without the Common keyword; %J is local because it was not declared at all.

On units

An On unit lets you specify a course of action following a triggering event, such as the terminal operator pressing one of the Attention identifier (AID) keys. The On unit provides an application with a way to override the normal system response.

Syntax

To define an On unit, use an On block in the following format:

[label] On unittype statement ... End On

where unittype is one of the following:

unittype You can specify the course of action to take if...
ATTENTION The end user invokes the attention feature (for example, presses the BREAK, ATTN, or PA1 key, or enters *CANCEL).
ERROR Model 204 cancels a request. Before a request is canceled or, for transaction backout files, after the current transaction is backed out, the ON ERROR unit is processed instead of returning control to the terminal command level. For more information on transaction backout files, see Data recovery.
FIELD CONSTRAINT CONFLICT (FCC) There are field level constraint conflicts. Violating the UNIQUE and AT-MOST-ONE attributes causes field-level conflicts.*
FIND CONFLICT A conflict arises evaluating a FIND statement or a FOR EACH RECORD statement used for retrieval.
MISSING FILE A remote file is no longer available.
MISSING MEMBER A remote optional member is no longer available.
RECORD LOCKING CONFLICT A conflict arises during a record locking attempt.

  • If you have procedures written for Model 204 V2R1.0 that use ON FCC for UNIQUE fields, and you are planning to use ON FCC for AT-MOST-ONE fields, you might need to rewrite the ON FCC unit to take the new value of $UPDSTAT (2 for AT-MOST-ONE) into account.

Several $functions provide information about conflicts. They are:

$UpdFile $UpdFld $UpdOval $UpdRec
$UpdStat $UpdStmt $UpdVal $UnqRec

Body of an On unit

The body of the On unit consists of statements immediately following the On statement. Any User Language statement can appear within an On unit except the SUBROUTINE statement.

Ending an On unit

You must conclude an ON unit with either an END ON statement or an END BLOCK statement. The format of the END ON statement is as follows:

END ON [label]

where label is the label of the statement that began the ON statement.

Processing an On unit

When an On statement is evaluated, Model 204 remembers the location of the On unit body (the statement after the On statement and within the unit), but does not immediately evaluate the body. Instead, it passes control to the statement immediately following the On unit. The On unit body is evaluated only when the triggering event takes place.

Usage guidelines for On units

Note the following considerations when using On units:

  • You must define the On unit before it is invoked (that is, you should typically place the On unit near the beginning of your procedure).
  • A subsequent definition of an On unit of the same kind replaces the previous one. For example, if you define two ON ATTN units, the second one becomes the current one.
  • You can jump to destinations within the same On unit.
  • You can jump out of an On unit only to unnested, labeled statements.
  • You cannot jump into an On unit.
  • You can jump outside of an ON unit only if the On unit is part of a main routine or part of a complex subroutine.
  • You cannot jump out of an On unit contained in a simple subroutine, regardless of whether the destination is within the subroutine or back in the mainline program, because On units are part of the mainline program; hence, there is no scoping of ON units. This restriction ensures that the On unit is executed and the control returned to the main routine.
  • An On unit definition is not preserved when a request is continued with an END MORE statement and a MORE command. Each new request continuation must define its own On units. (See Rules for request continuation.)
  • For complex subroutines, an active On unit is temporarily disabled when a subroutine is called that contains an On UNIT of the same type; it is restored when the subroutine returns. Any ON unit enabled during the execution of a subroutine is replaced by the active On unit at the time of the last CALL statement as soon as the RETURN statement is evaluated.
  • On units coded inside complex subroutines can contain JUMP statements that specify a destination outside the On unit. The destination must be to an unnested labeled statement within the complex subroutine. Also, if the On unit is to be jumped out of, the condition that causes the On unit to be invoked must be raised in the subroutine that contains the On unit.

    This prevents a lower level subroutine from returning inadvertently by raising a condition for which there is an On unit coded in a higher level subroutine. If the inadvertent return is attempted, the request is canceled.

  • On units do not have their own local data and labels. They inherit the scope of the part of the program in which they are compiled. An On unit that is compiled within a complex subroutine is considered part of only that subroutine.

Example

In the following example, if the user presses the ATTN key instead of entering a response to the prompt in the GET.REC.TYPE statement, the ON ATTENTION unit sets %FLAG to 1. The FLAG.SET statement tests %FLAG. If %FLAG is set, the request branches to END.REQUEST and the FIND statement is not executed.

%FLAG=0 ON ATTENTION %FLAG=1 BYPASS END ON GET.REC.TYPE: %TYPE=$READ('ENTER RECORD TYPE') FLAG.SET: IF %FLAG=1 THEN JUMP TO END.REQUEST END IF FIND.RECS: FIND ALL RECORDS FOR WHICH TYPE = %TYPE END FIND . . . END.REQUEST: END

Only one On unit at a time

Only one On unit of each kind is active at a time. For example, the processing of a second ON ERROR statement resets the current ON ERROR unit, but does not affect the current ON ATTENTION unit. Thus, you can redefine what to do in a variety of cases by having several ON statements and units within a request. An On unit can be redefined within another On unit.

Passing control to and from On units

Model 204 passes control to an On unit when the triggering event occurs. For example, an ON ATTENTION unit receives control when a user presses one of the ATTENTION identifier (AID) keys at the terminal during the execution of a request. Use one of the following statements to return control to the body of the request.

BYPASS statement

The BYPASS statement handles the various unittypes of an On statement as follows:

For unittype... The BYPASS statement...
ON MISSING FILE
ON MISSING MEMBER
Returns control to the statement immediately after the END FOR statement that closes the current FOR loop.
ON ERROR Ends the request.
ON ATTENTION

ON FIND CONFLICT

ON RECORD LOCKING CONFLICT
Returns control to the statement immediately after the statement that invoked the On unit.

The format of the BYPASS statement is as follows:

BYPASS [PENDING STATEMENT]

where the PENDING STATEMENT keyword is optional. If the On unit is not ended with a BYPASS statement, Model 204 automatically generates a STOP statement at the end of the unit.

CONTINUE statement

The CONTINUE statement is supported only with the Parallel Query Option. If you lose access to a group member that is an optional file during FOR processing, the CONTINUE statement continues FOR processing with the next available file, and skips any other unavailable files.

JUMP TO statement

The JUMP statement, when used to jump to a labeled statement outside the ON unit, causes the request to continue at that point. There are restrictions pertaining to jumps; see Branching statements and Simple subroutines.

RETRY statement

The RETRY statement passes control to the statement that invoked the ON unit, thereby retrying that statement. The RETRY statement is not valid in an ON ERROR unit.

The format of the RETRY statement is as follows:

RETRY [PENDING STATEMENT]

where the PENDING STATEMENT keyword is optional.

STOP statement

The STOP statement is used to end the request.

Clearing On units

You can issue the following statement to clear the definition of an On unit:

CLEAR ON unittype

This statement clears any defined On unit of the type specified. Clearing an ON unit produces the following results:

  • After a CLEAR ON ATTENTION, pressing one of the ATTENTION identifier (AID) keys at the terminal does not invoke the ON ATTENTION unit.
  • After a CLEAR ON ERROR, a request cancellation error does not invoke the ON ERROR unit.

An On unit can be defined, cleared, and then redefined.

Pausing during the request

The Pause statement can be used with On units to cause the request to wait a specified number of seconds and then to retry the statement that caused the evaluation of the On unit. Pause is typically used with the other On unit types (On Record Locking Conflict and On Find Conflict) and is discussed in Record level locking and concurrency control.

The $WakeUp function is an alternative approach; it offers millisecond resolution pausing.