Subroutines: Difference between revisions

From m204wiki
Jump to navigation Jump to search
m (add links)
 
(20 intermediate revisions by 7 users not shown)
Line 16: Line 16:
===Common elements===
===Common elements===
<p>
<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>
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===
===On units===
<p>
<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>
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==
==Simple subroutines==
Line 30: Line 30:
<tr class="head">
<tr class="head">
<th>Statement</th>
<th>Statement</th>
<th>Purpose</th>
<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>
<p>
The statements are coded in the following sequence, so they are described in order of usage.</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===
===SUBROUTINE statement===
<p>
<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>
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>
   
   
====Syntax====
====Syntax====
<p>
<p>
The format of the SUBROUTINE statement is:      </p>
The format of the <var>SUBROUTINE</var> statement is:      </p>
<p class="syntax"><span class="term">label</span>: SUBROUTINE
<p class="syntax"><span class="term">label</span>: SUBROUTINE
</p>
</p>
Line 84: Line 78:
<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>
<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>
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 117: Line 111:
<var class="product">Model&nbsp;204</var> compiles subroutines only after they are called, regardless of where they are in your program.</p>
<var class="product">Model&nbsp;204</var> compiles subroutines only after they are called, regardless of where they are in your program.</p>
<p>
<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>
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>
   
   
===RETURN statement===
===RETURN statement===
<p>
<p>
The RETURN statement returns control from the subroutine to the statement following the most recent CALL 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====
====Syntax====
<p>
<p>
The format of the RETURN statement is:   </p>
The format of the <var>RETURN</var> statement is: </p>
<p class="syntax">RETURN
<p class="syntax">RETURN
</p>
</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>
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 class="code">M204.1779 RETURN IS INVALID IN ON UNITS, USE BYPASS STATEMENT
</p>
</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>
<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>
For more information, see [[#ON units|ON units]] and [[#Passing control to and from ON units|Passing control to and from ON units]].</p>
Line 139: Line 133:
===END SUBROUTINE statement===
===END SUBROUTINE statement===
<p>
<p>
You can end a subroutine using an END SUBROUTINE statement or an END BLOCK statement. </p>
You can end a subroutine using an <var>END SUBROUTINE</var> statement or an <var>END BLOCK</var> statement. </p>
   
   
====Syntax====
====Syntax====
Line 149: Line 143:
===CALL statement===
===CALL statement===
<p>
<p>
The CALL statement transfers control to the subroutine. </p>
The <var>CALL</var> statement transfers control to the subroutine. </p>
   
   
====Syntax====
====Syntax====
<p>
<p>
The format of the CALL statement is:</p>
The format of the <var>CALL</var> statement is:</p>
<p class="syntax">CALL <span class="term">label</span>
<p class="syntax">CALL <span class="term">label</span>
</p>
</p>
Line 167: Line 161:
</p>
</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>
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>
<p>
<p>
Processing continues sequentially from that statement until another control transfer statement &mdash; a CALL, IF, JUMP TO, RETURN, or STOP statement &mdash; is encountered.   </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>
   
   
==Complex subroutines==
==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>
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 SUBROUTINE statement changes for a complex subroutine and the CALL statement is also more complex.</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===
===Symbolic parameter passing===
<p>
<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>
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>
   
   
Line 200: Line 191:
====OPEN statement within a complex subroutine====
====OPEN statement within a complex subroutine====
<p>
<p>
A User Language OPEN statement &mdash; an OPEN statement inside a BEGIN/END &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>
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 class="code">M204.1521: <i>entity-name</i> DOES NOT EXIST OR REQUESTED ACCESS NOT AUTHORIZED
</p>
</p>
Line 206: Line 197:
===SUBROUTINE statement for complex subroutines===
===SUBROUTINE statement for complex subroutines===
<p>
<p>
Complex subroutines begin with the following form of the SUBROUTINE statement:  </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>  
<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>
                   <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>
Where:
Where:
<p>
<var class="term">subname</var> is the name of the subroutine.</p>
<p>
<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.</p>
<p>
<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>
<ul>
<ul>
<li>Scalar (nonarray) %variable formatted as:</li>
<li><var class="term">subname</var> is the name of the subroutine.</li>
 
<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>
 
<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:
<ul>
<li>Scalar (nonarray) %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> | *}]  
<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]}
           <span class="squareb">|</span> [FIXED [DP <span class="term">n</span>] <span class="squareb">|</span> FLOAT]}
Line 231: Line 222:
</p></li>
</p></li>


<li>Array %variable formatted as:</li>
<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> | *}]
<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]  
  [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(* [,*[,*]])]]
  <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>
<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>
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 class="code">SUBROUTINE EXAMPLE(%ARR IS STRING LEN 10 - ARRAY(*,*))
</p></li>
</p></li>


<li>A list of records formatted as:</li>
<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 class="syntax">[LIST] <span class="term">listname</span> [IN [FILE | [PERM | TEMP] GROUP]] <span class="term">name</span>  
</p>
</p>
Line 251: Line 240:
</p></li>
</p></li>
</ul>
</ul>
<p>
<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:</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 class="head">
<tr class="head">
Line 263: Line 251:
<td>INPUT<br>
<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>


Line 273: Line 261:
<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>
Line 284: Line 270:
</td>
</td>
</tr>
</tr>
</table>
</table></li>
</ul>
   
   
===END SUBROUTINE statement===
===END SUBROUTINE statement===
<p>
<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>
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>
<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>
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>
   
   
===CALL 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>
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====
====Syntax====
<p>
<p>
A complex subroutine is invoked with this form of the CALL statement:</p>
A complex subroutine is invoked with this form of the <var>CALL</var> statement:</p>
<p class="code">CALL <span class="term">subname</span> [(<span class="term">actual-parameter</span> [, ...])]
<p class="syntax">CALL <span class="term">subname</span> [(<span class="term">actual-parameter</span> [, ...])]
</p>
</p>
Where:
Where:
<p>
<ul>
<var class="term">subname</var> is the name of the subroutine.</p>
<li><var class="term">subname</var> is the name of the subroutine.</li>
<p>
 
<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 SUBROUTINE statement to an actual-parameter in the CALL statement is by position rather than by name.</p>
<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.
<p>
<p>
An actual-parameter can be any of the following:</p>
An actual-parameter can be any of the following:</p>
<ul>
<ul>
<li>%variable or expression</li>
<li>%variable or expression
<p>
<p>
Expressions can contain field names, screen items, image items, and constants.</p>
Expressions can contain field names, screen items, image items, and constants.</p></li>
</li>
 
<li>Array %variable</li>
<li>Array %variable
<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>
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>
Line 332: Line 319:
</p>
</p>
<p>
<p>
The <var>[[$Arrsize|$Arrsize]]</var> function can be used to determine the number of elements in a particular dimension of an array. </p>  
The <var>[[$ArrSize]]</var> function can be used to determine the number of elements in a particular dimension of an array. </p></li>
</li>
 
<
<li>A list
li>A list</li>
<p>
<p>
An actual-parameter can be a list, optionally preceded by the word LIST to distinguish it from a field name. </p>
An actual-parameter can be a list, optionally preceded by the word LIST to distinguish it from a field name. </p>
</li>
</ul>
<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>
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 list has never been declared in the request, a compilation error results. </p>
</li></ul>
</li></ul>


====Additional rules for parameters====
====Additional rules for parameters====
Line 350: Line 336:
<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>


<li>The INPUT parameters of a %variable array requires that the type of the array &mdash; FLOAT, FIXED, or STRING &mdash; 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>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>


<li>The INPUT parameters of a list requires the same file or group context as the actual-parameter.</li>
<li>The INPUT parameters of a list requires the same file or group context as the actual-parameter.
</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>
<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.
<p>
<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>
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>
Line 369: Line 352:
</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 &mdash; FLOAT, FIXED, or STRING &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>:</li>
<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 class="code">M204.1725 PARAMETER NUMBER <i>n</i> IS TYPE INCOMPATIBLE
</p>
</p>
Line 387: Line 370:
===DECLARE SUBROUTINE statement===
===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>
The DECLARE statement for a complex subroutine is similar to the SUBROUTINE statement, except that the parameter names are omitted. </p>
   
   
====Syntax====
====Syntax====
<p class="code">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">]
The complete syntax for the DECLARE SUBROUTINE statement is:
</span>  </p>
<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:
Where:
<p>
<ul>
<var class="term">subname</var> is the name of the subroutine.</p>
<li><var class="term">subname</var> is the name of the subroutine.</li>
<p>
<var class="term">type</var> is one of the following:</p>


<li><var class="term">type</var> is one of the following:
<ul>
<ul>
<li>Scalar %variable of the following format:
<li>Scalar %variable of the following format:
Line 405: Line 387:
<li>Array %variable of the following format:
<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]]
<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(* [,*[,*]])]}
  | [FIXED [DP <span class="term">n</span>] | FLOAT] [ARRAY(* [,*[,*]])]}
</p></li>
</p></li>
Line 412: Line 393:
<p class="code">[LIST] [IN {FILE | [PERM | TEMP] GROUP} <span class="term">name</span>]
<p class="code">[LIST] [IN {FILE | [PERM | TEMP] GROUP} <span class="term">name</span>]
</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>
<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.  </p>
   
   
====Usage====
====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>
   
   
====Specifying a list of records====
====Specifying a list of records====
<p>
<p>
If you specify a LIST (of records), you must also specify FILE or GROUP. For example:</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
Line 447: Line 430:
</p>
</p>
<p>
<p>
If you do not specify FILE or GROUP in the code, you receive the following error message:</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>
   
   
====Example====
====DECLARE parameters and CALL parameters====
<p>
<p>
In the following example, note that the DECLARE statement lists the formal parameters, while the CALL statement lists the actual parameters:</p>
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, -
<p class="code">DECLARE SUBROUTINE SUB1(FLOAT, FIXED DP 2, STRING, STRING DP *)
STRING DP *)
     .
     .
     .
     .
Line 473: Line 455:
====Impact on CALL and SUBROUTINE statements====
====Impact on CALL and SUBROUTINE statements====
<p>
<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>
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>
<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>
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>
   
   
===Exiting the subroutine===
===Exiting the subroutine===
<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>
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>
<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>
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>
<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>
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===
===Examples using complex subroutines===
<p>
<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>
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 525: Line 507:
%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 535: Line 516:
   .
   .
   
   
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 550: Line 530:
END
END
</p>
</p>
 
==Sharing common elements==
==Sharing common elements==
<p>
<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>
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 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>
   
   
===Scope of elements===
===Scope of elements===
Line 559: Line 541:
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>
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>
<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>
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>
   
   
===Shareable elements===
===Shareable elements===
Line 567: Line 549:
====%variables and %variable arrays====
====%variables and %variable arrays====
<p>
<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>
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====
====Lists of records====
<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>
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====
====Found sets====
<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>
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>
<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>
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>
   
   
====Menus and screens====
====Menus and screens====
Line 587: Line 570:
You can share a menu or screen as common under the following conditions: </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>
<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>
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>
Line 601: Line 583:
====Images====
====Images====
<p>
<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>
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===
===DECLARE statement===
<p>
<p>
You can use the DECLARE statement to perform the following functions:   </p>
You can use the <var>Declare</var> statement to perform the following functions: </p>
<ul>
<ul>
<li>Specify subroutine formal parameter types.</li>
<li>Specify subroutine formal parameter types. </li>
</li>


<li>Specify variables, labels, lists, menus, screens, and images as COMMON.</li>
<li>Specify variables, labels, lists, menus, screens, and images as <var>Common</var>. </li>
</li>
</ul>
</ul>
<p>
<p>
Menus and screens are discussed in detail in [[Full-screen feature]]. </p>
Menus and screens are discussed in detail in [[Full-screen feature]]. </p>
<p>
<p>
Images are discussed in detail in [[Images]].</p>
Images are discussed in detail in [[Images]]. </p>
   
   
<ul>
<ul>
<li>To declare lists without having to use an <code>IN filename CLEAR LIST listname</code> clause. See [[Lists#Creating and clearing a list|Creating and clearing a list]].</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>To declare %variables, see [[Using variables and values in computation]]. </li>
<li>To declare %variables, see [[Using variables and values in computation#Declaring|Declaring %variables and %variable arrays]]. </li>
</ul>
</ul>
   
   
====Syntax====
====Syntax====
<p>
<p>
The format of the DECLARE statement is as follows:</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 class="syntax">DECLARE <span class="term">declaration</span>
</p>
<p class="syntax">Declare <span class="term">declaration</span>
</p>
</p>
<p>
<p>
where <span class="term">declaration</span> is one of the following:</p>
where <span class="term">declaration</span> is one of the following:</p>
<p class="syntax">LABEL <span class="term">label</span> COMMON
<p class="syntax">Label <span class="term">label</span> Common
 
[List] <span class="term">listname</span> [In [File [Perm | Temp] Group] <span class="term">name</span>] [Common]
 
Image <span class="term">imagename</span> Common
 
Menu <span class="term">menuname</span> Common
 
Screen <span class="term">screenname</span> Common
   
   
[LIST] <span class="term">listname</span> [IN [FILE [PERM | TEMP] GROUP] <span class="term">name</span>]
<span class="term">%variable</span> [Is] {Fixed [Dp <span class="term">n</span>] | Float}
                [COMMON]
[Array(<span class="term">d1</span> [,<span class="term">d2</span> [,<span class="term">d3</span>]])] [Common]
 
IMAGE <span class="term">imagename</span> COMMON
<span class="term">%variable</span> [Is] String [Len <span class="term">n</span>] [Dp {<span class="term">dn1</span> | *}]
  [Array(<span class="term">d1</span> [,<span class="term">d2</span> [,<span class="term">d3</span>]])] [No Field Save] [Common]
MENU <span class="term">menuname</span> 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]
   
   
<span class="term">%variable</span> [IS] STRING [LEN <span class="term">n</span>] [DP {<span class="term">dn1</span> | *}]
Subroutine <span class="term">subname</span>[(<span class="term">type</span> [<span class="term">inout-option</span>] [,...]) ]
[ARRAY(<span class="term">d1</span> [,<span class="term">d2</span> [,<span class="term">d3</span>]])] [NO FIELD SAVE] [COMMON]
SUBROUTINE <span class="term">subname</span>[(<span class="term">type</span> [<span class="term">inout-option</span>] [,...]) ]
</p>
</p>
 
====Example====
====Example====
<p>
<p>
For example, the DECLARE statement declares the list RECNAMES in the following request:</p>
For example, the <var>Declare</var> statement declares the list <code>RECNAMES</code> in the following request: </p>
<p class="code">BEGIN
<p class="code">BEGIN
DECLARE LIST RECNAMES
DECLARE LIST RECNAMES
Line 673: 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
R1: IN EMPLOYEE FIND ALL RECORDS FOR WHICH REGION = %REGION
      REGION = %REGION
R2: PLACE RECORDS IN R1 ON LIST RGNLIST
R2: PLACE RECORDS IN R1 ON LIST RGNLIST
END SUBROUTINE
END SUBROUTINE
Line 685: Line 661:
===Defining common variables===
===Defining common variables===
<p>
<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>
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>
<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>
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>
<p>
For example, </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
END SUBROUTINE
   
   
SUBROUTINE B
SUBROUTINE B
* But next line will fail compile since %X already exists
  * 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===
===Shared common element examples===
<p>
<p>
The following examples illustrate the differences between data that is locally scoped and data that is shared using the COMMON keyword. </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====
====Example 1====
<p>
<p>
In this example, the variable %I assumes different values depending upon which part of the request is being executed:</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 741: Line 719:
====Example 2====
====Example 2====
<p>
<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>
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 787: Line 765:
   
   
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 800: Line 778:
</p>
</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>
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>
   
   
<div id="On statement"></div> <!-- The two reasonable section names for ... -->
==<b id="On statement"></b>On units==   
==On units==  <!-- Be sure to keep with <div> tags preceding this -->
<p>
<p>
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>
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>
Line 830: Line 807:
<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]].   </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>
   
   
Line 865: Line 842:
<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===
===Body of an On unit===
<p>
<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>
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>
   
   
===Ending 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>
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>
Line 890: Line 867:
where <var class="term">label</var> is the label of the statement that began the ON statement. </p>
where <var class="term">label</var> is the label of the statement that began the ON statement. </p>
   
   
===Processing an ON unit===
===Processing an On unit===
<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>
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===
===Usage guidelines for On units===
<p>
<p>
Note the following considerations when using 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>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>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>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>You cannot jump into an ON unit.</li>
<li>You cannot jump into an <var>On</var> unit.</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>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 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>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 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>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>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><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>
<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>
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>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><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>
</ul>
</ul>
Line 927: Line 904:
====Example====
====Example====
<p>
<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>
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 946: Line 924:
</p>
</p>
   
   
===Only one ON unit at a time===
===Only one On unit at a time===
<p>
<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 <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>
   
   
===Passing control to and from ON units===
===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>
<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====
====BYPASS statement====
<p>
<p>
The BYPASS statement handles the various unittypes of an ON statement as follows:</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 975: Line 953:
ON FIND CONFLICT<br>
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>
Line 983: Line 961:
</p>
</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>
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>
   
   
====CONTINUE statement====
====CONTINUE statement====
Line 1,007: Line 985:
The STOP statement is used to end the request.        </p>
The STOP statement is used to end the request.        </p>
   
   
===Clearing ON units===
===Clearing On units===
<p>
<p>
You can issue the following statement to clear the definition of an ON unit:  </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 class="syntax">CLEAR ON <span class="term">unittype</span>
</p>
</p>
<p>
<p>
This statement clears any defined ON unit of the type specified. Clearing an ON unit produces the following results:</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>
Line 1,021: Line 999:
</ul>
</ul>
<p>
<p>
An ON unit can be defined, cleared, and then redefined. </p>
An <var>On</var> unit can be defined, cleared, and then redefined. </p>
   
   
===Pausing during the request===
===Pausing during the request===
<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>
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 -->
</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.