|
Routines |
Routines
There are three types of routines (subprograms): procedures, functions and traps.
Routine scope
The scope of a routine denotes the area in which the routine is visible. The optional local directive of a routine declaration classifies a routine as local (within the module), otherwise it is global.
Example: LOCAL PROC local_routine (...
PROC global_routine (...
The following scope rules apply to routines :
Example: The following routines can be called from Routine h:
Module1 - Routine c, d.
Module2 - All routines.
A routine may not have the same name as another routine or data in the same module.A global routine may not have the same name as a module or a global routine or global data in another module.
Parameters
The parameter list of a routine declaration specifies the arguments (actual parameters)that must/can be supplied when the routine is called.
There are four different types of parameters (in the access mode):
If an INOUT, VAR or PERS parameter is updated, this means, in actual fact, that the argument itself is updated, i.e. it makes it possible to use arguments to return values to the calling routine.
Example: PROC routine1 (num in_par, INOUT num inout_par,
VAR num var_par, PERS num pers_par)
A parameter can be optional and may be omitted from the argument list of a routine call. An optional parameter is denoted by a backslash "\" before the parameter.
Example: PROC routine2 (num required_par \num optional_par)
The value of an optional parameter that is omitted in a routine call may not be referenced. This means that routine calls must be checked for optional parameters before an optional parameter is used.Two or more optional parameters may be mutually exclusive (i.e. declared to exclude each other), which means that only one of them may be present in a routine call. This is indicated by a stroke "|" between the parameters in question.
Example: PROC routine3 (\num exclude1 | num exclude2)
The special type, switch, may (only) be assigned to optional parameters and provides a means to use switch arguments, i.e. arguments that are only specified by names (not values). A value cannot be transferred to a switch parameter. The only way to use a switch parameter is to check for its presence using the predefined function, Present.
Example: PROC routine4 (\switch on | switch off)
...
IF Present (off ) THEN
...
ENDPROC
Arrays may be passed as arguments. The degree of an array argument must comply with the degree of the corresponding formal parameter. The dimension of an array parameter is "conformant" (marked with "*"). The actual dimension thus depends on the dimension of the corresponding argument in a routine call. A routine can determine the actual dimension of a parameter using the predefined function, Dim.
Example: PROC routine5 (VAR num pallet{*,*})
Routine termination
The execution of a procedure is either explicitly terminated by a RETURN instruction or implicitly terminated when the end (ENDPROC, BACKWARD or ERROR) of the procedure is reached.The evaluation of a function must be terminated by a RETURN instruction.The execution of a trap routine is explicitly terminated using the RETURN instruction or implicitly terminated when the end (ENDTRAP or ERROR) of that trap routine is reached. Execution continues from the point where the interrupt occurred.
Routine declarations
A routine can contain routine declarations (including parameters), data, a body, a backward handler (only procedures) and an error handler . Routine declarations cannot be nested, i.e. it is not possible to declare a routine within a routine.
A routine can contain declarations, data, a body, a backward handler and an error handler.
Procedure declaration
Example: Multiply all elements in a num array by a factor;
PROC arrmul( VAR num array{*}, num factor)
FOR index FROM 1 TO dim( array, 1 ) DO
array{index} := array{index} * factor;
ENDFOR
ENDPROC
Function declaration
A function can return any data type value, but not an array value.
Example: Return the length of a vector;
FUNC num veclen (pos vector)
RETURN Sqrt(Pow(vector.x,2)+Pow(vector.y,2)+Pow(vector.z,2));
ENDFUNC
Trap declaration
Example: Respond to feeder empty interrupt;
TRAP feeder_empty
wait_feeder;
RETURN;
ENDTRAP
Procedure call
When a procedure is called, the arguments that correspond to the parameters of the procedure shall be used:
See the Chapter Using function calls in expressions on page 32 for more details.
The procedure name may either be statically specified by using an identifier (early binding) or evaluated during runtime from a string type expression (late binding). Even though early binding should be considered to be the "normal" procedure call form, late
binding sometimes provides very efficient and compact code. Late binding is defined
by putting percent signs before and after the string that denotes the name of the
procedure.
Example: ! early binding
TEST products_id
CASE 1:
proc1 x, y, z;
CASE 2:
proc2 x, y, z;
CASE 3:
...
! same example using late binding
% "proc" + NumToStr(product_id, 0) % x, y, z;
...
! same example again using another variant of late binding
VAR string procname {3} :=["proc1", "proc2", "proc3"];
...
% procname{product_id} % x, y, z;
...
Note that the late binding is available for procedure calls only, and not for function calls. If a reference is made to an unknown procedure using late binding, the system variable ERRNO is set to ERR_REFUNKPRC. If a reference is made to a procedure call error (syntax, not procedure) using late binding, the system variable ERRNO is set to ERR_CALLPROC.
Syntax
Routine declaration
<routine declaration> ::=
[LOCAL] ( <procedure declaration>
| <function declaration>
| <trap declaration> )
| <comment>
| <RDN>
Parameters
<parameter list> ::=<first parameter declaration> { <next parameter declaration> }
<first parameter declaration> ::=<parameter declaration>
| <optional parameter declaration>
| <PAR>
<next parameter declaration> ::=
, <parameter declaration>
| <optional parameter declaration>
| ,<optional parameter declaration>
| , <PAR>
<optional parameter declaration> ::=
\ ( <parameter declaration> | <ALT> )
{ | ( <parameter declaration> | <ALT> ) }
<parameter declaration> ::=
[ VAR | PERS | INOUT] <data type>
<identifier> [ { ( * { , * } ) | <DIM>] }
| switch <identifier>
Procedure declaration
<procedure declaration> ::=
PROC <procedure name>
( [ <parameter list> ] )
<data declaration list>
<instruction list>
[ BACKWARD <instruction list> ]
[ ERROR <instruction list> ]
ENDPROC
<procedure name> ::= <identifier>
<data declaration list> ::= {<data declaration>}
Function declaration
<function declaration> ::=
FUNC <value data type>
<function name>
( [ <parameter list> ] )
<data declaration list>
<instruction list>
[ ERROR <instruction list> ]
ENDFUNC
<function name> ::= <identifier>
Trap routine declaration
<trap declaration> ::=
TRAP <trap name>
<data declaration list>
<instruction list>
[ ERROR <instruction list> ]
ENDTRAP
<trap name> ::= <identifier>
Procedure call
<procedure call> ::= <procedure> [ <procedure argument list> ] ;
<procedure> ::=
<identifier>
| % <expression> %
<procedure argument list> ::= <first procedure argument> { <procedure argument> }
<first procedure argument> ::=
<required procedure argument>
| <optional procedure argument>
| <conditional procedure argument>
| <ARG>
<procedure argument> ::=
, <required procedure argument>
| <optional procedure argument>
| , <optional procedure argument>
| <conditional procedure argument>
| , <conditional procedure argument>
| , <ARG>
<required procedure argument> ::= [ <identifier> := ] <expression>
<optional procedure argument> ::= \ <identifier> [ := <expression> ]
<conditional procedure argument> ::= \ <identifier> ? ( <parameter> | <VAR> )