Summary:
See also: Exceptions, Programs, Functions, Reports, Expressions
The CALL instruction invokes a specified function or method.
CALL [ prefix. ] function ( [ parameter [,...]
] ) [
RETURNING variable [,...] ]
If the IMPORT [FGL] instruction was used to import a module, function can be prefixed with the name of the module followed by a dot (i.e. module.function). The module prefix is required to fully-qualify the function in case of conflicts (i.e. when functions with the same name are defined in several modules).
The RETURNING clause assigns values returned by the function to variables in the calling routine. The RETURNING clause is only needed when the function returns parameters. If the function returns a unique parameter, the CALL func(...) RETURNING var instruction can be replaced by a LET var = function(...) statement. A function returning a single parameter can also be used in expressions.You can use a double-pipe operator ' || ' to pass the concatenation of character expressions as a parameter.
Note that the value of a receiving variable may be different from the value returned by the function, following the data conversion rules.01MAIN02DEFINE var1 CHAR(10)03DEFINE var2 CHAR(2)04LET var1 = foo()05DISPLAY "var1 = " || var106CALL foo() RETURNING var207DISPLAY "var2 = " || var208END MAIN0910FUNCTION foo()11RETURN "Hello"12END FUNCTION
01MAIN02DEFINE var1 CHAR(15)03DEFINE var2 CHAR(15)04CALL foo() RETURNING var1, var205DISPLAY var1, var206END MAIN0708FUNCTION foo()09DEFINE r1 CHAR(15)10DEFINE r2 CHAR(15)11LET r1 = "return value 1"12LET r2 = "return value 2"13RETURN r1, r214END FUNCTION
01MAIN02DEFINE r1 RECORD03id1 INTEGER,04id2 INTEGER,05name CHAR(30)06END RECORD07CALL get_name( NULL, NULL, NULL ) RETURNING r1.*08CALL get_name( NULL, r1.id2, r1.name ) RETURNING r1.*09CALL get_name( r1.* ) RETURNING r1.*10DISPLAY r1.name11CALL get_name( 1, 2, "John" ) RETURNING r1.id2, r1.id1, r1.name12DISPLAY r1.name13END MAIN1415FUNCTION get_name( code1, code2, name )16DEFINE code1 INTEGER17DEFINE code2 INTEGER18DEFINE name CHAR(30)19IF code1 IS NULL THEN20LET name = "ERROR:code1 is NULL"21LET code2 = NULL22ELSE23IF code2 IS NULL THEN24LET name = "ERROR:code2 is NULL"25LET code1 = NULL26ELSE27IF name IS NULL THEN28LET name = "SMITH"29END IF30END IF31END IF32RETURN code1, code2, name33END FUNCTION
The RETURN instruction transfers the control back from a function with optional return values.
RETURN [ value [,...] ]
value can be a variable, a literal, a constant or any valid expression.
Record members can be returned with the .* or THRU notation. Each member is returned as an independent variable.
A function may have several RETURN points (not recommended in structured programming) but they must all return the same number of values.
The number of returned values must correspond to the number of variables listed in the RETURNING clause of the CALL statement invoking this function.
A function cannot return an array.
01MAIN02DEFINE forname, surname CHAR(10)03CALL foo(NULL) RETURNING forname, surname04DISPLAY forname CLIPPED, " ", upshift(surname) CLIPPED05CALL foo(1) RETURNING forname, surname06DISPLAY forname CLIPPED, " ", upshift(surname) CLIPPED07END MAIN0809FUNCTION foo(code)10DEFINE code INTEGER11DEFINE person RECORD12name1 CHAR(10),13name2 CHAR(20)14END RECORD15IF code IS NULL THEN16RETURN NULL, NULL17ELSE18LET person.name1 = "John"19LET person.name2 = "Smith"20RETURN person.*21END IF22END FUNCTION
The CASE instruction specifies statement blocks that must be executed conditionally.
CASE expression-1
WHEN expression-2
{ statement | EXIT CASE }
[...]
[ OTHERWISE
{ statement | EXIT CASE }
[...]
]
END CASE
CASE
WHEN boolean-expression
{ statement | EXIT CASE }
[...]
[ OTHERWISE
{ statement | EXIT CASE }
[...]
]
END CASE
A NULL expression is considered as FALSE: When doing a CASE expr ... WHEN [NOT] NULL using the syntax 1, it always evaluates to FALSE. Use syntax 2 as CASE ... WHEN expr IS NULL to test if an expression is null.
Make sure that expression-2 is not a boolean expression when using the first syntax. The compiler will not raise an error in this case, but you might get unexpected results at runtime.
If there is more than one expression-2 matching expression-1 (syntax 1), or if two boolean expressions (syntax 2) are true, only the first matching WHEN block will be executed.01MAIN02DEFINE v CHAR(10)03LET v = "C1"04CASE v05WHEN "C1"06DISPLAY "Value is C1"07WHEN "C2"08DISPLAY "Value is C2"09WHEN "C3"10DISPLAY "Value is C3"11OTHERWISE12DISPLAY "Unexpected value"13END CASE14END MAIN
01MAIN02DEFINE v CHAR(10)03LET v = "C1"04CASE05WHEN ( v="C1" OR v="C2" )06DISPLAY "Value is either C1 or C2"06WHEN ( v="C3" OR v="C4" )07DISPLAY "Value is either C3 or C4"08OTHERWISE09DISPLAY "Unexpected value"10END CASE11END MAIN
The CONTINUE instruction transfers the program execution from a statement block to another location in the compound statement that is currently being executed.
CONTINUE { FOR | FOREACH | MENU |
CONSTRUCT | INPUT | WHILE }
CONTINUE instruction can only be used within the statement block specified by instruction. For example, CONTINUE FOR can only be used within a FOR ... END FOR statement block.
The CONTINUE FOR, CONTINUE FOREACH, or CONTINUE WHILE keywords cause the current FOR, FOREACH, or WHILE loop (respectively) to begin a new cycle immediately. If conditions do not permit a new cycle, however, the looping statement terminates.
The CONTINUE CONSTRUCT and CONTINUE INPUT statements cause the program to skip all subsequent statements in the current control block. The screen cursor returns to the most recently occupied field in the current form, giving the user another chance to enter data in that field.
The CONTINUE MENU statement causes the program to ignore the remaining statements in the current MENU control block and redisplay the menu. The user can then choose another menu option.
Note that CONTINUE INPUT is valid in INPUT and INPUT ARRAY statements.
01MAIN02DEFINE i INTEGER03LET i = 004WHILE i < 505LET i = i + 106DISPLAY "i=" || i07CONTINUE WHILE08DISPLAY "This will never be displayed !"09END WHILE10END MAIN
The FOR instruction executes a statement block a specified number of times.
FOR counter = start TO finish [
STEP value ]
{ statement | EXIT FOR | CONTINUE
FOR }
[...]
END FOR
counter is a variable of type INTEGER or SMALLINT that serves as an index for the FOR statement block.
start is an integer expression used to set an initial counter value.
finish is any valid integer expression used to specify an upper limit for counter.
value is any valid integer expression whose value is added to counter after each iteration of the statement block.
When the STEP keyword is not given, counter is incremented by 1.
The FOR instruction block executes the statements up to the END FOR keyword a specified number of times, or until EXIT FOR terminates the FOR statement. You can use the CONTINUE FOR instruction to skip the following statements and continue with the loop.
The runtime system maintains the counter, whose value changes on each pass through the statement block. On the first iteration through the loop, this counter is set to the initial expression at the left of the TO keyword. For all further iterations, the value of the increment expression in the STEP clause specification (1 by default) is added to the counter in each pass through the block of statements. When the sign of the difference between the values of counter and the finish expression at the right of the TO keyword changes, the runtime system exits from the FOR loop.
The FOR loop terminates after the iteration for which the left- and right-hand expressions are equal. Execution resumes at the statement following the END FOR keywords. If either expression returns NULL, the loop cannot terminate, because the Boolean expression "left = right" cannot become TRUE.
If the FOR loop includes one or more SQL statements that modify the database, then it is advisable that the entire FOR loop be within a transaction. You may also PREPARE the SQL statements before the loop to increase performance.value = 0 causes an unending loop unless there is an adequate EXIT FOR statement.
NULL for start, finish or value is treated as 0. There is no way to catch this as an error.
If statement modifies the value of counter, you might get unexpected results at runtime. In this case, it is recommended that you use a WHILE loop instead.
It is highly recommended that you ensure that statement does not modify the values of start, finish and/or value.01MAIN02DEFINE i, i_min, i_max INTEGER03LET i_min = 104LET i_max = 1005DISPLAY "Look how well I can count from " || i_min || " to " || i_max06DISPLAY "I can count forwards..."07FOR i = i_min TO i_max08DISPLAY i09END FOR10DISPLAY "... and backwards!"11FOR i = i_max TO i_min STEP -112DISPLAY i13END FOR14END MAIN
The GOTO instruction transfers program control to a labeled line within the same program block.
GOTO [ : ] label-id
The GOTO statement can be used in a WHENEVER statement to handle exceptions.
The LABEL jump point can be defined before or after the GOTO statement.
Note that the LABEL and GOTO statements must use the label-id within a single MAIN, FUNCTION, or REPORT program block.
01MAIN02DEFINE exit_code INTEGER03DEFINE l_status INTEGER04WHENEVER ANY ERROR GOTO _error05DISPLAY 1/006GOTO _noerror07LABEL _error:08LET l_status = STATUS09DISPLAY "The error number ", l_status, " has occurred."10DISPLAY "Description : ", err_get(l_status)11LET exit_code = -112GOTO :_exit13LABEL _noerror:14LET exit_code = 015GOTO _exit16LABEL _exit:17EXIT PROGRAM (exit_code)18END MAIN
The EXIT instruction transfers control out of a control structure (a block, a loop, a CASE statement, or an interface instruction).
EXIT { CASE | FOR | MENU | CONSTRUCT
| FOREACH | REPORT | DISPLAY | INPUT | WHILE
}
The EXIT instruction instruction must be used inside the control structure specified by instruction. For example, EXIT FOR can only appear inside a FOR ... END FOR program structure.
EXIT DISPLAY exits the DISPLAY ARRAY instruction and EXIT INPUT exits both INPUT and INPUT ARRAY blocks.
To exit a function, use the RETURN instruction. To exit a program, use the EXIT PROGRAM instruction.
01MAIN02DEFINE i INTEGER03LET i = 004WHILE TRUE05DISPLAY "This is an infinite loop. How would you get out of here ?"06LET i = i + 107IF i = 100 THEN08EXIT WHILE09END IF10END WHILE11DISPLAY "Well done."12END MAIN
The IF instruction executes a group of statements conditionally.
IF condition THEN
statement
[...]
[ ELSE
statement
[...]
]
END IF
condition is any boolean expression supported by the language.
If condition is TRUE, the runtime system executes the block of statements following the THEN keyword, until it reaches either the ELSE keyword or the END IF keywords and resumes execution after the END IF keywords.
If condition is FALSE, the runtime system executes the block of statements between the ELSE keyword and the END IF keywords. If ELSE is absent, it resumes execution after the END IF keywords.
To test the equality of integer expressions, both " = " and " == " operators may be used. IF 5 = 5 THEN ... can be written IF 5 == 5 THEN ...
Note that a NULL expression is considered as FALSE. Use the IS NULL keyword to test if an expression is null.
01MAIN02DEFINE name CHAR(20)03LET name = "John Smith"04IF name MATCHES "John*" THEN05DISPLAY "The first name is too common to be displayed."06IF name MATCHES "*Smith" THEN07DISPLAY "Even the last name is too common to be displayed."08END IF09ELSE10DISPLAY "The name is " || name || "."11END IF12END MAIN
The LABEL instruction declares a jump point in the program that can be reached by a GOTO.
LABEL label-id:
label-id is a unique identifier in a MAIN, REPORT, or FUNCTION program block.
The label-id must be followed by a colon (:).
The LABEL instruction declares a statement label, making the next statement one to which a GOTO statement can transfer program control.
01MAIN02DISPLAY "Line 2"03GOTO line504DISPLAY "Line 4"05LABEL line5:06DISPLAY "Line 6"07END MAIN
The SLEEP instruction causes the program to pause for the specified number of seconds.
SLEEP seconds
seconds is a valid integer expression.
If seconds < 0 or second IS NULL, the program does not stop.
01MAIN02DISPLAY "Please wait 5 seconds..."03SLEEP 504DISPLAY "Thank you."05END MAIN
The WHILE statement executes a block of statements while a condition that you specify in a boolean expression is true.
WHILE b-expression
{ statement | EXIT WHILE | CONTINUE
WHILE }
[...]
END WHILE
b-expression is any valid boolean expression.
If b-expression is TRUE, the runtime system executes the statements that follow it, down to the END WHILE keyword. The runtime system again evaluates the b-expression, and if it is still TRUE, the runtime system executes the same statement block. The runtime system usually stops when b-expression becomes FALSE or statement is EXIT WHILE. You can use the CONTINUE WHILE instruction to skip the following statements and continue with the loop.
If b-expression is FALSE, the runtime system passes control to the statement that follows END WHILE.
If b-expression is complex, it is much better to define a boolean [ INTEGER or CHAR(1) ] variable that takes the result of b-expression and use this variable for b-expression.
A WHILE loop can replace a FOR loop : FOR i = 1 TO 5 ; ... ; END FOR is equivalent to LET i = 1 ; WHILE i <= 5 ; ... ; LET i = i + 1 ; END WHILE
In order to avoid unending loops, make sure that either statement will cause b-expression to be FALSE, or that the EXIT WHILE statement will be executed.
01MAIN02DEFINE lval INTEGER03DEFINE lmin INTEGER04DEFINE lmax INTEGER05DEFINE lnb INTEGER06DEFINE lcnt INTEGER07DEFINE lguess INTEGER08DISPLAY "NumberGuess program"09LET lnb = 2010LET lmin = 011LET lmax = 100012LET lval = 753 --random value between lmin and lmax13DISPLAY "Guess a number between " || lmin || " and " || lmax14LET lguess = (lmax - lmin) / 215LET lcnt = 116WHILE lguess <> lval AND lcnt < lnb17DISPLAY "\n Attempt number " || lcnt18DISPLAY " Your guess is " || lguess || ", hopefully between " || lmin || " and " || lmax19IF lval > lguess THEN20DISPLAY " Try higher."21LET lmin = lguess22ELSE23DISPLAY " Try lower."24LET lmax = lguess25END IF26LET lguess = lmin + (lmax - lmin) / 227LET lcnt = lcnt + 128END WHILE29IF lcnt >= lnb THEN30DISPLAY "Sorry, the maximum number of attempts has been reached. The number was " || lval31ELSE32DISPLAY "Well done. You have found the number " || lval || " in " || lcnt || " attempts."33END IF34END MAIN