Manual |
|
Statements |
|
4. PREDEFINED STATEMENTS
The library contains several predefined statements: assignment, while-statement, repeat-statement, for-statement, if-statement, case-statement and procedure call.
- Syntax:
- statement ::=
- single_statement [ ';' [ statement ] ] .
- single_statement ::=
-
assignment_statement | while_statement | repeat_statement |
for_statement | for_step_statement | for_each_statement |
for_each_key_statement | for_key_statement | if_statement |
case_statement | procedure_call | empty_statement . - empty_statement ::=
- 'noop' .
The execution of a noop statement (short for NO OPeration) has no effect. Some places in a program require a statement. If nothing needs to be done in such a place a noop can be used.
Everywhere where one statement can be written a sequence of statements can also be used. The semicolon-operator concatenates two statements giving a new statement. The semicolon operator can also be used behind the last statement of a statement sequence. In this case the semicolon is just ignored.
$ syntax expr: .(). ; .() is <- 50; $ syntax expr: .(). ; is <- 50 [1]; const proc: (ref void: statement1) ; (ref void: statement2) is noop;
4.1 Assignment
For example:
minimum := maximum div 2;
- Semantics:
- The expression at the right side of the assignment symbol is evaluated and assigned to the variable at the left side.
- Syntax:
- assignment_statement ::=
- designator ':=' expression .
The assignment statement is defined for every standard type.
If an assignment for a new user defined type is needed it must be defined additionally.
$ syntax expr: .(). := .() is <-> 20; const proc: (inout type: dest) := (ref type: source) is action "TYP_CPY"; const proc: (inout proc: dest) := (ref proc: source) is action "PRC_CPY"; const proc: (inout func aType: dest) := (ref func aType: source) is action "PRC_CPY"; const proc: (inout varfunc aType: dest) := (ref varfunc aType: source) is action "PRC_CPY"; const proc: (inout ACTION: dest) := (in ACTION: source) is action "ACT_CPY"; const proc: (inout boolean: dest) := (in boolean: source) is action "BLN_CPY"; const proc: (inout integer: dest) := (in integer: source) is action "INT_CPY"; const proc: (inout bigInteger: dest) := (in bigInteger: source) is action "BIG_CPY"; const proc: (inout char: dest) := (in char: source) is action "CHR_CPY"; const proc: (inout string: dest) := (in string: source) is action "STR_CPY"; const proc: (inout bin64: dest) := (in bin64: source) is action "INT_CPY"; const proc: (inout bin32: dest) := (in bin32: source) is action "INT_CPY"; const proc: (inout bstring: dest) := (in bstring: source) is action "BST_CPY"; const proc: (inout reference: dest) := (in reference: source) is action "REF_CPY"; const proc: (inout ref_list: dest) := (in ref_list: source) is action "RFL_CPY"; const proc: (inout ptrType: dest) := (in ptrType: source) is action "REF_CPY"; const proc: (inout varptrType: dest) := (in varptrType: source) is action "REF_CPY"; const proc: (inout arrayType: dest) := (in arrayType: source) is action "ARR_CPY"; const proc: (inout bitset: dest) := (in bitset: source) is action "SET_CPY"; const proc: (inout structType: dest) := (in structType: source) is action "SCT_CPY"; const proc: (inout enumType: dest) := (in enumType: source) is action "ENU_CPY"; const proc: (inout clib_file: dest) := (in clib_file: source) is action "FIL_CPY"; const proc: (inout process: dest) := (in process: source) is action "PCS_CPY"; const proc: (inout interfaceType: dest) := (ref interfaceType: source) is action "ITF_CPY"; const proc: (inout interfaceType: dest) := (ref aType: source) is action "ITF_CPY2";
4.2 Ignoring values
Unused expression results are not implicitely discarded. Writing:
begin 1 + 1; writeln; end func;
results in a parsing error:
*** tst316.sd7(5):52: Match for {INT_ADD({1 + 1 }) ; writeln } failed 1 + 1;
An unused expression result must be explicitly ignored. E.g.:
ignore(getc(KEYBOARD));
This example waits for a character pressed on the KEYBOARD and then ignores that character. So all of the side effects of the expressions take place. It is just the result of the expression that is ignored.
The need to explicitly ignore unused expression results removes another possible source of errors.
4.3 while-statement
For example:
while maximum > minimum do minimum := 2 * minimum + stepValue; decr(stepValue); end while;
- Semantics:
- First the condition between while and do is evaluated. When this evaluation yields FALSE, the while-statement is finished. When the evaluation yields TRUE, the statement between do and end is executed and the whole while-statement is executed again.
- Syntax:
- while_statement ::=
-
'while' expression 'do'
statement
'end' 'while' .
The expression must be of type boolean.
$ syntax expr: .while.().do.().end.while is -> 25; const proc: while (in func boolean: condition) do (in proc: statement) end while is action "PRC_WHILE"; const proc: while (ref boolean: condition) do (in proc: statement) end while is action "PRC_WHILE";
Alternate declaration:
const proc: while (in func boolean: condition) do (in proc: statement) end while is func begin if condition then statement; while condition do statement; end while; end if; end func;
4.4 repeat-statement
For example:
repeat incr(minimum); maximum := maximum - stepValue; until 2 * minimum > maximum;
- Semantics:
- The statement between repeat and until is executed. Then the condition after until is evaluated. When this evaluation yields TRUE, the repeat-statement is finished. When the evaluation yields FALSE the repeat-statement is executed again.
- Syntax:
- repeat_statement ::=
-
'repeat'
statement
'until' expression .
The expression must be of type boolean.
$ syntax expr: .repeat.().until.() is -> 25; const proc: repeat (in proc: statement) until (in func boolean: condition) is action "PRC_REPEAT"; const proc: repeat (in proc: statement) until (ref boolean: condition) is action "PRC_REPEAT";
Alternate declaration:
const proc: repeat (in proc: statement) until (in func boolean: condition) is func begin statement; if not condition then repeat statement; until condition; end if; end func;
4.5 for-statement
For example:
for index range min_index to max_index do sumValue +:= field[index]; end for;
- Semantics:
- When the to symbol is used the for-statement is defined as follows:
- First the lower limit and the upper limit which stand behind range and to are evaluated. Then the lower limit is assigned to the control variable which stands behind for. If the value of the control variable is less than or equal the upper limit the statements behind do are executed. After that the control variable is incremented and compared with the upper limit again. This compare - execute - increment cycle is repeated until the control variable is greater than the upper limit.
- When the downto symbol is used the for-statement is defined as follows:
- First the upper limit and the lower limit which stand behind range and downto are evaluated. Then the upper limit is assigned to the control variable which stands behind for. If the value of the control variable is greater than or equal the lower limit the statements behind do are executed. After that the control variable is decremented and compared with the lower limit again. This compare - execute - increment cycle is repeated until the control variable is less than the lower limit.
- Syntax:
- for_statement ::=
-
'for' identifier 'range' expression [ 'to' | 'downto' ] expression 'do'
statement
'end' 'for' .
$ syntax expr: .for.().range.().to.().do.().end.for is -> 25; $ syntax expr: .for.().range.().downto.().do.().end.for is -> 25; const proc: for (inout integer: aVar) range (in integer: lowerLimit) to (in integer: upperLimit) do (in proc: statements) end for is action "PRC_FOR_TO"; const proc: for (inout integer: aVar) range (in integer: upperLimit) downto (in integer: lowerLimit) do (in proc: statements) end for is action "PRC_FOR_DOWNTO";
Declaration for non-integer types:
const proc: FOR_DECLS (in type: aType) is func begin const proc: for (inout aType: variable) range (in aType: lowerLimit) to (in aType: upperLimit) do (in proc: statements) end for is func local var boolean: continue is FALSE; begin variable := lowerLimit; continue := variable <= upperLimit; while continue do statements; if variable < upperLimit then incr(variable); else continue := FALSE; end if; end while; end func; const proc: for (inout aType: variable) range (in aType: upperLimit) downto (in aType: lowerLimit) do (in proc: statements) end for is func local var boolean: continue is FALSE; begin variable := upperLimit; continue := variable >= lowerLimit; while continue do statements; if variable > lowerLimit then decr(variable); else continue := FALSE; end if; end while; end func; end func; FOR_DECLS(char); FOR_DECLS(boolean); FOR_DECLS(bigInteger);
4.6 for-until-statement
For example:
for column range 1 to length(maxRow) until selectedColumn <> 0 do if maxRow[column] <> 0 then incr(numColumns); end if; if numColumns = selectedNum then selectedColumn := column; end if; end for;
- Semantics:
- When the to symbol is used the for-until-statement is defined as follows:
- First the lower limit and the upper limit which stand behind range and to are evaluated. Then the lower limit is assigned to the control variable which stands behind for. If the value of the control variable is less than or equal the upper limit the condition behind until is checked. If the condition is FALSE the statements behind do are executed. After that the control variable is incremented and compared with the upper limit again. This compare - check condition - execute - increment cycle is repeated until the control variable would become greater than the upper limit or the condition is TRUE.
- When the downto symbol is used the for-until-statement is defined as follows:
- First the upper limit and the lower limit which stand behind range and downto are evaluated. Then the upper limit is assigned to the control variable which stands behind for. If the value of the control variable is greater than or equal the lower limit the condition behind until is checked. If the condition is FALSE the statements behind do are executed. After that the control variable is decremented and compared with the lower limit again. This compare - check condition - execute - increment cycle is repeated until the control variable would become less than the lower limit or the condition is TRUE.
- Syntax:
- for_until_statement ::=
-
'for' identifier 'range' expression [ 'to' | 'downto' ] expression 'until' expression 'do'
statement
'end' 'for' .
$ syntax expr: .for.().range.().to.().until.().do.().end.for is -> 25; $ syntax expr: .for.().range.().downto.().until.().do.().end.for is -> 25; const proc: FOR_UNTIL_DECLS (in type: aType) is func begin const proc: for (inout aType: variable) range (in aType: lowerLimit) to (in aType: upperLimit) until (in func boolean: condition) do (in proc: statements) end for is func local var boolean: continue is FALSE; begin variable := lowerLimit; continue := variable <= upperLimit; while continue and not condition do statements; if variable < upperLimit then incr(variable); else continue := FALSE; end if; end while; end func; const proc: for (inout aType: variable) range (in aType: lowerLimit) downto (in aType: upperLimit) until (in func boolean: condition) do (in proc: statements) end for is func local var boolean: continue is FALSE; begin variable := upperLimit; continue := variable >= lowerLimit; while continue and not condition do statements; if variable > lowerLimit then decr(variable); else continue := FALSE; end if; end while; end func; end func; FOR_UNTIL_DECLS(integer); FOR_UNTIL_DECLS(char); FOR_UNTIL_DECLS(boolean); FOR_UNTIL_DECLS(bigInteger);
4.7 for-step-statement
For example:
for evenNumber range 0 to 10 step 2 do write(evenNumber); end for;
- Semantics:
- When the to symbol is used the for-statement is defined as follows:
- First the lower limit and the upper limit which stand behind range and to are evaluated. Then the lower limit is assigned to the control variable which stands behind for. If the value of the control variable is less than or equal the upper limit the statements behind do are executed. After that the control variable is incremented by the value behind step. Then the control variable is compared with the upper limit again. This compare - execute - increment cycle is repeated until the control variable is greater than the upper limit.
- When the downto symbol is used the for-statement is defined as follows:
- First the upper limit and the lower limit which stand behind range and downto are evaluated. Then the upper limit is assigned to the control variable which stands behind for. If the value of the control variable is greater than or equal the lower limit the statements behind do are executed. After that the control variable is decremented by the value behind step. Then the control variable is compared with the lower limit again. This compare - execute - increment cycle is repeated until the control variable is less than the lower limit.
- Syntax:
- for_step_statement ::=
-
'for' identifier 'range' expression [ 'to' | 'downto' ] expression 'step' expression 'do'
statement
'end' 'for' .
$ syntax expr: .for.().range.().to.().step.().do.().end.for is -> 25; $ syntax expr: .for.().range.().downto.().step.().do.().end.for is -> 25; const proc: FOR_STEP_DECLS (in type: aType) is func begin if getobj((inout aType: variable) +:= (in integer: delta)) <> NIL then const proc: for (inout aType: variable) range (in aType: lowerLimit) to (in aType: upperLimit) step (in integer: incr_step) do (in proc: statements) end for is func begin variable := lowerLimit; while variable <= upperLimit do statements; variable +:= incr_step; end while; end func; end if; if getobj((inout aType: variable) -:= (in integer: delta)) <> NIL then const proc: for (inout aType: variable) range (in aType: upperLimit) downto (in aType: lowerLimit) step (in integer: decr_step) do (in proc: statements) end for is func begin variable := upperLimit; while variable >= lowerLimit do statements; variable -:= decr_step; end while; end func; end if; end func; FOR_STEP_DECLS(integer); FOR_STEP_DECLS(bigInteger);
4.8 for-each-statement
A for-each-statement loops over the elements of a container (array, hash, set, string, bstring, ref_list). For example:
for currObject range element_list do writeln("element: " <& currObject); end for;
A for-each-statement can be combined with an until condition:
for currObject range element_list until found do if currObject = searched then writeln("found: " <& currObject); found := TRUE; end if; end for;
- Semantics:
- First the element list which stands behind range is evaluated. If the element list is empty the for-each-statement is finished. Otherwise the first element of the element list is assigned to the control variable which stands behind for. If there is an until part the condition behind until is checked and if it evaluates to TRUE the for-each-statement is finished. If the for-each-statement is not finished the statements behind do (loop body) are executed. If there is no next element in the element list the for-each-statement is finished. Otherwise the next element of the element list is assigned to the control variable. This check for next element - assign element - check possible until condition - execute loop body - cycle is repeated until there is no next element in the element list.
- Syntax:
- for_each_statement ::=
-
'for' identifier 'range' expression [ 'until' expression ] 'do'
statement
'end' 'for' .
$ syntax expr: .for.().range.().do.().end.for is -> 25; const proc: for (inout char: forVar) range (in string: stri) do (in proc: statement) end for is action "STR_FOR"; const proc: for (inout reference: variable) range (in ref_list: aRefList) do (in proc: statement) end for is action "RFL_FOR"; const proc: for (inout baseType: variable) range (in arrayType: arr_obj) do (in proc: statements) end for is func local var integer: number is 0; begin for number range minIdx(arr_obj) to maxIdx(arr_obj) do variable := arr_obj[number]; statements; end for; end func; const proc: for (inout baseType: forVar) range (in hashType: aHashMap) do (in proc: statements) end for is func begin FOR_DATA(forVar, aHashMap, statements, hashType.dataCopy); end func; const proc: for (inout baseType: variable) range (in setType: aSet) do (in proc: statements) end for is func local var baseType: upperBound is baseType.value; var boolean: leave is FALSE; begin if aSet <> setType.EMPTY_SET then variable := min(aSet); upperBound := max(aSet); repeat statements; if variable = upperBound then leave := TRUE; else variable := next(aSet, variable); end if; until leave; end if; end func; const proc: for (inout char: forVar) range (in bstring: bstri) do (in proc: statements) end for is func local var integer: number is 0; begin for number range 1 to length(bstri) do forVar := bstri[number]; statements; end for; end func;
4.9 for-each-key-statement
A for-each-key-statement loops over the elements and keys (indices) of a container (array, hash, string). For example:
for currObject key currIndex range element_list do writeln("key: " <& currIndex <& ", element: " <& currObject); end for;
A for-each-key-statement can be combined with an until condition:
for currObject key currIndex range element_list until found do if currObject = searched then writeln("found key: " <& currIndex <& ", element: " <& currObject); found := TRUE; end if; end for;
- Semantics:
- First the element list which stands behind range is evaluated. If the element list is empty the for-each-key-statement is finished. Otherwise the first element of the element list is assigned to the control variable which stands behind for and the index (key) of the first element is assigned to the key control variable which stands behind the keyword key. If there is an until part the condition behind until is checked and if it evaluates to TRUE the for-each-statement is finished. If the for-each-statement is not finished the statements behind do (loop body) are executed. If there is no next element in the element list the for-each-key-statement is finished. Otherwise the next element of the element list is assigned to the control variable and the index of the next element is assigned to the key control variable. This check for next element - assign index and element - check possible until condition - execute loop body - cycle is repeated until there is no next element in the element list.
- Syntax:
- for_each_key_statement ::=
-
'for' identifier 'key' identifier 'range' expression [ 'until' expression ] 'do'
statement
'end' 'for' .
$ syntax expr: .for.().key.().range.().do.().end.for is -> 25; const proc: for (inout char: forVar) key (inout integer: keyVar) range (in string: stri) do (in proc: statement) end for is action "STR_FOR_VAR_KEY"; const proc: for (inout baseType: forVar) key (inout integer: keyVar) range (in arrayType: arr) do (in proc: statement) end for is func begin for keyVar range minIdx(arr) to maxIdx(arr) do forVar := arr[keyVar]; statements; end for; end func; const proc: for (inout baseType: forVar) key (inout keyType: keyVar) range (in hashType: aHashMap) do (in proc: statements) end for is func begin FOR_DATA_KEY(forVar, keyVar, aHashMap, statements, hashType.dataCopy, hashType.keyCopy); end func;
4.10 for-key-statement
A for-key-statement loops over the keys (indices) of a container (array, hash, string). For example:
for key currIndex range element_list do writeln("key: " <& currIndex); end for;
A for-key-statement can be combined with an until condition:
for key currIndex range element_list until found do if element_list[currIndex] = searched then writeln("found key: " <& currIndex); found := TRUE; end if; end for;
- Semantics:
- First the element list which stands behind range is evaluated. If the element list is empty the for-key-statement is finished. Otherwise the index (key) of the first element is assigned to the key control variable which stands behind the keyword key. If there is an until part the condition behind until is checked and if it evaluates to TRUE the for-each-statement is finished. If the for-each-statement is not finished the statements behind do (loop body) are executed. If there is no next element in the element list the for-key-statement is finished. Otherwise the index of the next element is assigned to the key control variable. This check for next element - assign index - check possible until condition - execute loop body - cycle is repeated until there is no next element in the element list.
- Syntax:
- for_key_statement ::=
-
'for' 'key' identifier 'range' expression [ 'until' expression ] 'do'
statement
'end' 'for' .
$ syntax expr: .for.key.().range.().do.().end.for is -> 25; const proc: for key (inout integer: keyVar) range (in string: stri) do (in proc: statement) end for is action "STR_FOR_KEY"; const proc: for key (inout integer: keyVar) range (in arrayType: arr) do (in proc: statement) end for is func begin for keyVar range minIdx(arr) to maxIdx(arr) do statements; end for; end func; const proc: for key (inout keyType: keyVar) range (in hashType: aHashMap) do (in proc: statements) end for is func begin FOR_KEY(keyVar, aHashMap, statements, hashType.keyCopy); end func;
4.11 if-statement
For example:
if sumValue < minimum then factor := sumValue; sumValue := minimum; elsif sumValue > maximum then factor := -sumValue; sumValue := maximum; else factor := 0; end if;
- Semantics:
- The expressions before then are evaluated in row. When such an expression evaluates to TRUE the statements behind then are executed and the if-statement is finished. If all expressions before then evaluate to FALSE and an else-part is present the statements behind else are executed and the if-statement is finished. If all expressions before then evaluate to FALSE and no else-part is present the if-statement is finished.
- Syntax:
- if_statement ::=
-
'if' expression 'then'
statement
{ 'elsif' expression 'then'
statement }
[ 'else'
statement ]
'end' 'if' .
The expression must be of type boolean.
$ syntax expr: .if.().then.().end.if is -> 25; $ syntax expr: .if.().then.().().end.if is -> 25; $ syntax expr: .elsif.().then.() is <- 60; $ syntax expr: .elsif.().then.().() is <- 60; $ syntax expr: .else.() is <- 60; const type: ELSIF_RESULT is newtype; const proc: (ref ELSIF_RESULT: dest) ::= enumlit is action "ENU_GENLIT"; const ELSIF_RESULT: ELSIF_EMPTY is enumlit; const type: ELSIF_PROC is func ELSIF_RESULT; const proc: (ref ELSIF_PROC: dest) ::= (ref ELSIF_RESULT: source) is action "ENU_CREATE"; const proc: if (in boolean: condition) then (in proc: statements) end if is action "PRC_IF"; const proc: if (in boolean: condition) then (in proc: statements) (in ELSIF_PROC: elsifPart) end if is action "PRC_IF_ELSIF"; const ELSIF_PROC: elsif (in boolean: condition) then (in proc: statements) is action "PRC_IF"; const ELSIF_PROC: elsif (in boolean: condition) then (in proc: statements) (in ELSIF_PROC: elsifPart) is action "PRC_IF_ELSIF"; const ELSIF_PROC: else (in void: elsePart) is ELSIF_EMPTY;
4.12 case-statement
For example:
case currChar of when {'A' .. 'Z'} | {'a' .. 'z'}: characterClass := LETTER; when {'0' .. '9'}: characterClass := DIGIT; when {'!', '$', '%', '&', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '\', '^', '`', '|', '~'}: characterClass := SPECIAL; when {'(', ')', '[', ']', '{', '}'}: characterClass := PAREN; when {'"'}: # Also possible '\"' characterClass := APPOSTROPHE; when {'''}: # Also possible '\'' characterClass := QUOTE; otherwise: characterClass := ILLEGAL; end case;
Case statements work also for strings:
case elementName of when {"li"}: alternateEndTags := {"<li"}; when {"dt", "dd"}: alternateEndTags := {"<dt", "<dd"}; when {"td", "th"}: alternateEndTags := {"<td", "<th", "<tr", "<thead", "<tbody", "<tfoot"}; when {"tr"}: alternateEndTags := {"<tr", "<thead", "<tbody", "<tfoot"}; when {"thead", "tbody", "tfoot"}: alternateEndTags := {"<thead", "<tbody", "<tfoot"}; end case;
- Semantics:
- The expression between case and of is evaluated. When the resulting value is element of a set behind a when the statements behind the corresponding colon are executed and the case-statement is finished. If the value is not element of a set behind a when and an otherwise part is present the statements behind the colon of the otherwise are executed and the case-statement is finished. If the value is not element of a set behind a when and no otherwise part is present the case-statement is finished.
- Syntax:
- case_statement ::=
-
'case' expression 'of'
{ 'when' set_expression ':'
statement }
[ 'otherwise' ':'
statement ]
'end' 'case' . - set_expression ::=
- expression .
$ syntax expr: .case.().of.().end.case is -> 25; $ syntax expr: .case.().of.().otherwise. : .().end.case is -> 25; $ syntax expr: .case.().of.otherwise. : .().end.case is -> 25; $ syntax expr: .case.().of.end.case is -> 25; $ syntax expr: .when.(). : .().() is <- 60; $ syntax expr: .when.(). : .() is <- 60; const proc: CASE_DECLS (in type: aType) is func local var type: WHEN_RESULT is void; var type: WHEN_PROC is void; var type: SELECTOR_TYPE is void; begin WHEN_RESULT := newtype; WHEN_PROC := (func WHEN_RESULT); SELECTOR_TYPE := set of aType; const proc: case (ref aType: decisionValue) of end case is noop; const proc: case (ref aType: decisionValue) of otherwise : (ref proc: statements) end case is func begin statements; end func; if getobj(ord(ref aType: decisionValue)) <> NIL and getobj(ord(ref aType: decisionValue, mayRaiseRangeError)) = NIL then const proc: case (ref aType: decisionValue) of (ref WHEN_PROC: whenPart) end case is action "PRC_CASE"; const proc: case (ref aType: decisionValue) of (ref WHEN_PROC: whenPart) otherwise : (ref proc: statements) end case is action "PRC_CASE_DEF"; else const proc: case (ref aType: decisionValue) of (ref WHEN_PROC: whenPart) end case is action "PRC_CASE_HASHSET"; const proc: case (ref aType: decisionValue) of (ref WHEN_PROC: whenPart) otherwise : (ref proc: statements) end case is action "PRC_CASE_HASHSET_DEF"; end if; const proc: (ref WHEN_RESULT: dest) ::= enumlit is action "ENU_GENLIT"; const WHEN_RESULT: WHEN_EMPTY (attr aType) is enumlit; const proc: (ref WHEN_PROC: dest) ::= (ref WHEN_RESULT: source) is action "ENU_CREATE"; const WHEN_PROC: when (ref SELECTOR_TYPE: whenSet) : (ref proc: statement) is WHEN_EMPTY(aType); const WHEN_PROC: when (ref SELECTOR_TYPE: whenSet) : (ref proc: statement) (ref WHEN_PROC: whenPart) is WHEN_EMPTY(aType); end func; CASE_DECLS(integer); CASE_DECLS(char); CASE_DECLS(boolean); CASE_DECLS(string); CASE_DECLS(bigInteger);
|
|