Seed7 is a general-purpose programming language. It is a higher level language compared to Ada, C++ and Java. In Seed7 new statements and operators can be defined easily. Functions with type results and type parameters are more elegant than the usual template or generics concept. Object orientation is used when it brings advantages and not in places when other solutions are more obvious. Although Seed7 contains several concepts of other programming languages it is generally not considered as a direct descendant of any other programming language.
The programmer should concentrate on problem solving instead of administration or the fulfillment of some paradigm. Therefore Seed7 allows programming in the "problem space" instead of bending everything into a small syntactic or semantic concept. The predefined constructs of Seed7 are defined in a way to be easy readable and understandable. This practical approach can be summarized as:
Programming should be fun |
Seed7 programs can be interpreted or compiled. Therefore Seed7 can be used for scripting and for "real" programs.
Conventional programming languages have a firmly given syntactic structure. The form of the statements, operators, declarations, procedures and functions is fixed in the language definition and cannot be changed by the user. It is only possible to declare new procedures, functions and in some languages also new operators. However the syntax of procedure, function and operator calls cannot be changed. Although this rigid pattern is favorable for the portability of programs, the improvement of the programming language is almost impossible. Extensions are however desirable, in order to repair existing weaknesses, to introduce new more obvious constructs and to adapt the programming language to different application areas. E.g.: In the area of mathematics the readability of a program can be substantially increased by the introduction of matrix and vector operators. After declaring an inner product and an outer (or cross) product for vectors it is possible to write e.g.
v1: = v2 cross v3; write(v1 * v2);
Programs which search for some data in a database can become more understandable by using a for statement to loop over the tables. A usage of such a for statement could be:
for person1, person2 where person1.age = person2.age and person1.mother = person2.mother and person1 <> person2 do writeln("Twins: " <& person1.name <& " and " <& person2.name); end for;
Such extensions make understanding, changing and debugging of a program easier.
Seed7 has the following features
But a new programming language differs not only from existing ones by new features. The real advantage comes from omitting features which are outdated.
Several concepts in use by other languages are not present
There are several concepts which are also used by other languages:
There are several concepts which are new
Several restrictions of other languages are released
You can have several views of the Seed7 programming language. Dependent on the view you can concentrate on specific chapters.
For example Seed7 can be used as conventional programming language. In this case you are interested in how the statements look like, which types are available, which operators are predefined, how to declare variables and procedures and other things like these. The statements and the predefined types are described in chapter 4 (Predefined statements) and chapter 5 (Predefined types) and the declaration mechanism is described in chapter 3 (Declarations).
But Seed7 is also an object oriented programming language. In this case you are interested in how to define new classes, how instances are generated, the method calling mechanism, the predefined class hierarchy and other things like these. The object orientation of Seed7 is described in chapter 7 (Object orientation). A good example for classes and instances is the file system which is described in chapter 8 (The file system).
And Seed7 is also an extensible programming language. In this case you are interested in how to declare new statements, how to define new operators, assigning a priority and an associativity to operators and other things like these. An overview about syntax declarations can be found in Chapter 3.2 (Syntax declarations). A detailed description of the Seed7 syntax definitions can be found in chapter 9 (Structured syntax definition). Chapter 4 (Predefined statements) contains various examples of syntax and semantic declarations. The basic parts of the syntax are described in chapter 10 (Tokens) and chapter 11 (Expressions).
Below is the hello world program of Seed7:
$ include "seed7_05.s7i"; const proc: main is func begin writeln("hello world"); end func;
Save this program to the file hello.sd7 and start it in a console with:
s7 hello
The Seed7 interpreter writes something like
SEED7 INTERPRETER Version 5.1.790 Copyright (c) 1990-2023 Thomas Mertes hello world
You get information about the Seed7 interpreter and the output of the hello.sd7 program:
hello world
The option -q can be used to suppress the information line of the Seed7 interpreter:
s7 -q hello
The first line of the program
$ include "seed7_05.s7i";
includes all definitions of the standard library. In contrast to other libraries the seed7_05.s7i library contains not only function declarations but also declarations of statements and operators. Additionally the seed7_05.s7i library defines the main function as entry point for a Seed7 program.
In the example above main is declared as constant and proc is the type of main. Declaring main with the type proc makes a procedure out of it. The object main gets a
func ... end func
construct as value. The 'func' construct is similar to begin ... end in PASCAL and { ... } in C. Inside the 'func' is a writeln statement with the "hello world" string. The writeln statement is used to write a string followed by a newline character.
The program below starts a little dialog:
$ include "seed7_05.s7i"; const proc: main is func local var string: name is ""; begin write("What's your name? "); readln(name); writeln("Hi " <& name <& "!"); end func;
Save this program to the file greeting.sd7 and start it in a console with:
s7 greeting
The program asks you for your name with:
What's your name?
After you entered your name and pressed enter it will greet you. This program uses the variable 'name' to store the name you entered. Variables must be defined. The place to to define and initialize all variables of a function is after the keyword local.
var string: name is "";
This defines the string variable 'name'. This definition assigns also the initial value "" to 'name'. The value "" is the empty string (it contains no characters). In Seed7 variables must be defined and always get an initial value.
The write statement is similar to writeln, but it does not write a newline character. The readln statement reads a line from the standard input file and assigns this line to the given variable. This function allows the usage of backspace to correct the input. By pressing enter the line is sent to the program. The final writeln statement contains the operator <& to concatenate strings. If necessary the <& operator converts values to string.
The greeting program above has a problem. If someone refuses to type his name and just presses enter the program writes:
Hi !
To avoid this we improve the program to check for special cases:
$ include "seed7_05.s7i"; const proc: main is func local var string: name is ""; begin write("What's your name? "); readln(name); if name = "" then writeln("Greetings to the person who pressed enter!"); elsif name = "name" then writeln("Interesting, your name is name."); else writeln("Hi " <& name <& "!"); end if; end func;
There can be zero or more elsif parts, and the else part is optional. As you can see the equality of strings is checked with =. The conditions of an if-statement decide what to do. By chance both conditions in the example above use the variable name. This special case opens the oportunity to use a case-statement instead:
$ include "seed7_05.s7i"; const proc: main is func local var string: name is ""; begin write("What's your name? "); readln(name); case name of when {""}: writeln("Greetings to the person who pressed enter!"); when {"name"}: writeln("Interesting, your name is name."); when {"Linus", "Torvalds"}: writeln("Are you the inventor of Linux?"); otherwise: writeln("Hi " <& name <& "!"); end case; end func;
As it can be seen, the keyword when is followed by a comma-separated list of values surrounded by braces. This is the set of values covered by this when-part. Depending on the value of 'name' one when-part is executed. If no when-part fits the otherwise-part is executed.
This is not the only way to improve the greeting program. Alternatively we can use a loop to insist on entering a name:
$ include "seed7_05.s7i"; const proc: main is func local var string: name is ""; begin repeat write("What's your name? "); readln(name); until name <> ""; writeln("Hi " <& name <& "!"); end func;
The repeat ... until loop repeats the statements between the two keywords until the condition name <> "" is TRUE. Note that the statements in the repeat loop are executed at least once. A solution with a while loop is:
$ include "seed7_05.s7i"; const proc: main is func local var string: name is ""; begin write("What's your name? "); readln(name); while name = "" do write("Just pressing enter is not okay. What's your name? "); readln(name); end while; writeln("Hi " <& name <& "!"); end func;
The while loop repeats the statements between the keywords do and end as long as the condition name = "" is TRUE. Note that the statements in a while loop might not be executed at all. In the example above this happens if a non-empty name is entered after the question: What's your name?
The following program writes the numbers from 1 to 10:
$ include "seed7_05.s7i"; const proc: main is func local var integer: count is 1; begin while count <= 10 do writeln(count); count := count + 1; end while; end func;
This program declares a local variable of the type integer:
var integer: count is 1;
The variable count above is initialized with 1. The value of a variable can be changed with an assignment (:=):
count := count + 1;
The expression at the right of the := symbol is evaluated and assigned to the variable left of the := symbol. In the case above the variable count is incremented by one. For this special case there is a shortcut that could be used instead of the assignment:
incr(count);
The output produced by this program is
1 2 3 4 5 6 7 8 9 10
What changes are necessary to count down from 10 to 0 instead?
To write a Fahrenheit to Celsius conversion table we use the following program:
(* Print a Fahrenheit-Celsius table for Fahrenheit values between 0 and 300 *) $ include "seed7_05.s7i"; const proc: main is func local const integer: upper is 300; const integer: increment is 20; var integer: fahr is 0; var integer: celsius is 0; begin while fahr <= upper do celsius := 5 * (fahr - 32) div 9; writeln(fahr <& " " <& celsius); fahr +:= increment; end while; end func;
Everything between (* and *) is a comment, which is ignored. This program contains local constants and variables of the type integer. Constant declarations are introduced with const:
const integer: upper is 300; const integer: increment is 20;
Like variables constants must be initialized with a value that is specified after the keyword is. Constants like upper cannot be changed. All constants just keep the initialization value. An attempt to change a constant results in a parsing error:
*** tst352.sd7(14):53: Variable expected in {lower := 10 } found constant integer: lower lower := 10;
Note that the error is reported before the program execution starts.
The program contains a while-statement and the expression to compute the 'celsius' value. The variable 'fahr' is incremented with the +:= operator. The statement:
fahr +:= increment;
is a shortcut for the statement:
fahr := fahr + increment;
The expression to compute the 'celsius' value uses an integer division (div). The output produced by this program is
0 -17 20 -6 40 4 60 15 80 26 100 37 120 48 140 60 160 71 180 82 200 93 220 104 240 115 260 126 280 137 300 148
An improved version of the program to write the Fahrenheit to Celsius conversion table is:
# Print a Fahrenheit-Celsius table with floating point numbers. $ include "seed7_05.s7i"; # This must be included first. include "float.s7i"; # Subsequent includes do not need a $. const proc: main is func local const integer: lower is 0; const integer: upper is 300; const integer: increment is 20; var integer: fahr is 0; var float: celsius is 0.0; begin for fahr range lower to upper step increment do celsius := flt(5 * (fahr - 32)) / 9.0; writeln(fahr lpad 3 <& " " <& celsius digits 2 lpad 6); end for; end func;
Everything between # the end of the line is a line comment, which is ignored. To use the type float it is necessary to include float.s7i. The float variable 'celsius' must be initialized with 0.0 (instead of 0). The for-loop executes the loop body with different values of fahr (0, 20, 40 .. 280, 300). Omitting the step part corresponds to a step of 1:
for fahr range lower to upper do celsius := flt(5 * (fahr - 32)) / 9.0; writeln(fahr lpad 3 <& " " <& celsius digits 2 lpad 6); end for;
The keyword downto can be used to run the for-loop backward:
for fahr range upper downto lower do celsius := flt(5 * (fahr - 32)) / 9.0; writeln(fahr lpad 3 <& " " <& celsius digits 2 lpad 6); end for;
Since Seed7 is strong typed integer and float values cannot be mixed in expressions. Therefore the integer expression '5 * (fahr - 32)' is converted to float with the function flt. For the same reason a '/' division and the value '9.0' must be used. The <& operator is used to concatenate elements before writing. If the right operand of the <& operator has not the type string it is converted to a string using the 'str' function. The lpad operator converts the value of 'fahr' to a string and pads spaces to the left until the string has length 3. The digits operator converts the value of 'celsius' to a string with 2 decimal digits. The resulting string is padded left up to a length of 6.
Arrays allow a variable to contain several values. E.g.: An array can be used to store a mapping from a day number to a day name:
$ include "seed7_05.s7i"; const proc: main is func local var array string: weekdayName is 7 times ""; var integer: number is 0; begin weekdayName[1] := "monday"; weekdayName[2] := "tuesday"; weekdayName[3] := "wednesday"; weekdayName[4] := "thursday"; weekdayName[5] := "friday"; weekdayName[6] := "saturday"; weekdayName[7] := "sunday"; for number range 1 to 7 do writeln(weekdayName[number]); end for; end func;
Since weekdayName is not changed after its values have been assigned, it can be declared as constant that is initialized with an array literal:
$ include "seed7_05.s7i"; const proc: main is func local const array string: weekdayName is [] ("monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"); var integer: number is 0; begin for number range 1 to 7 do writeln(weekdayName[number]); end for; end func;
The example above uses the array literal
[] ("monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday")
This array literal has the type array string and it is indexed beginning from 1. A corresponding array literal indexed beginning from 0 would be:
[0] ("monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday")
The for-loop above uses the literal 7 as upper bound. The function length can be used instead:
for number range 1 to length(weekdayName) do
This works as long as the array weekdayName is indexed beginning from 1. If this is not the case the functions minIdx and maxIdx can be used:
for number range minIdx(weekdayName) to maxIdx(weekdayName) do
For this case there is a convenient for-key-loop:
for key number range weekdayName do writeln(weekdayName[number]); end for;
This for-key-loop loops over the indices of the array weekdayName (from 1 to 7). In the loop body the index is just used to access an element from the array. For this case there is a convenient for-each-loop:
$ include "seed7_05.s7i"; const proc: main is func local const array string: weekdayName is [] ("monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"); var string: name is ""; begin for name range weekdayName do writeln(name); end for; end func;
A for-each-loop iterates over the elements of an array. Sometimes the elements and a corresponding index are needed. This is supported by the for-each-key-loop:
$ include "seed7_05.s7i"; const proc: main is func local const array string: weekdayName is [] ("monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"); var string: name is ""; var integer: index is 0; begin for name key index range weekdayName do writeln("day " <& index <& ": " <& name); end for; end func;
Another example of a for-each-loop is:
$ include "seed7_05.s7i"; const proc: main is func local var integer: number is 0; begin for number range [] (0, 1, 2, 3, 5, 8, 13, 20, 40, 100) do write(number <& " "); end for; writeln; end func;
The example above uses the array literal
[] (0, 1, 2, 3, 5, 8, 13, 20, 40, 100)
This array literal has the type array integer. The index type of an array is not restricted to integers. A type like char, that has a 1:1 mapping to integer, can also be used as index:
$ include "seed7_05.s7i"; const proc: main is func local const array [char] string: digitName is ['0'] ("zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"); var integer: number is 0; var char: ch is ' '; begin number := rand(1, 9999999); write(number <& ": "); for ch range str(number) do write(digitName[ch] <& " "); end for; writeln; end func;
The example above uses the array literal
['0'] ("zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine")
This array literal has the type array [char] string. The minimum index of this array is the character '0'.
A hash is similar to an array with the difference that the index can be any type (not just one that can be converted to integer). The type hash [string] integer defines a hash with a string as index and an integer as value. This type can be used in a type declaration:
const type: nameToDigitType is hash [string] integer;
A hash literal can be used to initialize hash constants or variables:
const nameToDigitType: nameToDigit is [] ( ["zero" : 0], ["one" : 1], ["two" : 2], ["three" : 3], ["four" : 4], ["five" : 5], ["six" : 6], ["seven" : 7], ["eight" : 8], ["nine" : 9]);
Like with arrays an element in the hash can be accessed with
nameToDigit[name]
The following example asks for digit names and writes the corresponding digit:
$ include "seed7_05.s7i"; const type: nameToDigitType is hash [string] integer; const proc: main is func local const nameToDigitType: nameToDigit is [] ( ["zero" : 0], ["one" : 1], ["two" : 2], ["three" : 3], ["four" : 4], ["five" : 5], ["six" : 6], ["seven" : 7], ["eight" : 8], ["nine" : 9]); var string: name is ""; begin write("Enter the name of a digit: "); readln(name); if name in nameToDigit then writeln("The value of " <& name <& " is " <& nameToDigit[name]); else writeln("You entered " <& name <& ", which is not the name of a digit."); end if; end func;
In the example above
name in nameToDigit
checks if the key name is in the hash table nameToDigit. This assures that getting the corresponding value with
nameToDigit[name]
succeeds. For-each loops can be used with hash tables as well. The example below uses keyDescription which is defined as hash [char] string in "keydescr.s7i". It contains descriptive texts for keyboard keys. A for-loop can loop over the values of a hash:
$ include "seed7_05.s7i"; include "keydescr.s7i"; const proc: main is func local var string: description is ""; begin for description range keyDescription do write(description <& " "); end for; writeln; end func;
A for-loop can also loop over the keys (indices) and values of a hash:
$ include "seed7_05.s7i"; include "keydescr.s7i"; const proc: main is func local var char: aChar is ' '; var string: description is ""; begin for description key aChar range keyDescription do writeln("const char: " <& description <& " is " <& literal(aChar)); end for; end func;
For-loops can also iterate over the elements of a set:
$ include "seed7_05.s7i"; const proc: main is func local var string: innerPlanet is ""; begin for innerPlanet range {"Mercury", "Venus", "Earth", "Mars"} do write(innerPlanet <& " "); end for; writeln; end func;
In the example above {"Mercury", "Venus", "Earth", "Mars"} is a set literal. The type of this literal is set of string. Other set literals are:
{1, 2} {'a', 'e', 'i', 'o', 'u'}
For-loops can iterate over the characters of a string:
$ include "seed7_05.s7i"; const proc: main is func local const set of char: vowels is {'a', 'e', 'i', 'o', 'u'}; var char: letter is ' '; begin for letter range "the quick brown fox jumps over the lazy dog" do if letter not in vowels then write(letter); end if; end for; writeln; end func;
A for-loop can loop over the keys (indices) and values of a array:
$ include "seed7_05.s7i"; const proc: main is func local var integer: number is 0; var string: name is ""; begin for name key number range [0] ("zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine") do writeln(number <& ": " <& name); end for; end func;
All loops that iterate over a container can be combined with an until condition:
$ include "seed7_05.s7i"; const proc: main is func local var string: testText is ""; var char: ch is ' '; var boolean: controlCharFound is FALSE; begin write("Enter text: "); readln(testText); for ch range testText until controlCharFound do controlCharFound := ord(ch) < 32; end for; if controlCharFound then writeln("The text contains control chars."); end if; end func;
The program below uses the function flipCoin to flip a coin until the result is heads:
$ include "seed7_05.s7i"; const func boolean: flipCoin is return rand(FALSE, TRUE); const proc: main is func local var boolean: heads is FALSE; begin repeat write("Press enter to flip the coin. "); readln; heads := flipCoin; writeln(heads ? "heads" : "tails"); until heads; end func;
In the example above, the function flipCoin is declared as constant. As const the code of flipCoin will not change during run-time. The type func boolean determines that the function returns a boolean value. The task of the function flipCoin is to return a random boolean value. This is done with:
return rand(FALSE, TRUE);
The actual random value is computed with the expression
rand(FALSE, TRUE);
The statement
heads := flipCoin;
assigns the result of flipCoin to heads. Afterwards heads is written with the ternary operator (?:). If heads is TRUE, it writes "heads" otherwise "tails".
The program below reads a multi-line paragraph:
$ include "seed7_05.s7i"; const func string: readMultiLineParagraph is func result var string: multiLineParagraph is ""; local var string: line is ""; begin repeat write("line: "); line := getln(IN); multiLineParagraph &:= line & "\n"; until line = ""; end func; const proc: main is func begin writeln("Enter a multi line paragraph. An empty line ends the paragraph."); writeln("\nThe paragraph is:\n" <& readMultiLineParagraph); end func;
The declaration of readMultiLineParagraph above contains the construct:
func ... end func
The function readMultiLineParagraph gets the func ... end func construct as value. This construct can be used to initialize functions and procedures. Note that proc is just a shortcut for func void and that void describes the empty type. Inside of the func ... end func construct are the keywords result, local and begin:
As can be seen from the function main above, the result and local parts are optional. If the function type is proc, the result part must be omitted. For all other functions the result part is mandatory.
Most parameters are not changed inside a function. Seed7 uses 'in' parameters to describe this situation:
const func integer: negate (in integer: num1) is return -num1; const func integer: fib (in integer: num1) is func result var integer: fib is 1; begin if num1 <> 1 and num1 <> 2 then fib := fib(pred(num1)) + fib(num1 - 2); end if; end func;
The functions above use 'in' parameters named 'num1'. An assignment to 'num1' is not allowed. A formal 'in' parameter like 'num1' behaves like a constant. Trying to change a formal 'in' parameter:
const proc: wrong (in integer: num2) is func begin num2 := 0; end func;
results in a parsing error:
*** tst77.sd7(5):53: Variable expected in {num2 := 0 } found parameter (in integer: num2) num2 := 0;
When a function wants to change the value of the actual parameter it can use an 'inout' parameter:
const proc: reset (inout integer: num2) is func begin num2 := 0; end func;
If you call this function with
reset(number);
the variable 'number' has the value 0 afterwards. Calling 'reset' with a constant instead of a variable:
reset(8);
results in a parsing error:
*** tst77.sd7(12):53: Variable expected in {8 reset } found constant integer: 8 reset(8);
Sometimes an 'in' parameter is needed, but you need to change the formal parameter in the function without affecting the actual parameter. In this case we use the 'in var' parameter:
const func string: oct_str (in var integer: number) is func result var string: stri is ""; begin if number >= 0 then repeat stri := str(number mod 8) & stri; number := number mdiv 8; until number = 0; end if; end func;
As you can see this works like a combination of an 'in' parameter with a local 'var'.
Conventionally there are two kinds of parameters: 'call by value' and 'call by reference'. When taking the access right (constant or variable) into account we get the following table:
parameter | call by | access right |
---|---|---|
val | value | const |
ref | reference | const |
in | val / ref | const |
in var | value | var |
inout | reference | var |
Additionally to the parameters we already know this table describes also 'val' and 'ref' parameters which use 'call by value' and 'call by reference' and have a constant formal parameter. The 'in' parameter is called by 'val / ref' in this table which is easily explained:
The parameter
in integer: number
is a 'val' parameter which could also be declared as
val integer: number
while the parameter
in string: stri
is a 'ref' parameter which could also be declared as
ref string: stri
The meaning of the 'in' parameter is predefined for most types. Usually types with small amounts of data use 'val' as 'in' parameter while types with bigger data amounts use 'ref'. Most of the time it is not necessary to care if an 'in' parameter is really a 'val' or 'ref' parameter.
In rare cases a 'ref' parameter would have undesired side effects with global variables or other 'ref' parameters. In these cases an explicit 'val' parameter instead of an 'in' parameter makes sense.
In all normal cases an 'in' parameter should be preferred over an explicit 'val' and 'ref' parameter.
Functions are not only identified by identifiers but also via the types of their parameters. So several versions of a function can be defined:
$ include "seed7_05.s7i"; include "float.s7i"; include "bigint.s7i"; include "bigrat.s7i"; const func float: tenPercent (in float: amount) is return amount / 10.0; const func float: tenPercent (in integer: amount) is return float(amount) / 10.0; const func bigRational: tenPercent (in bigInteger: amount) is return amount / 10_; const proc: main is func begin writeln(tenPercent(123)); writeln(tenPercent(123.0)); writeln(tenPercent(123_)); end func;
The example above defines the function tenPercent for the types float, integer and bigInteger. Two of these functions return a float and one returns a bigRational. This reuse of the same function name is called overloading. The literals 123, 123.0 and 123_ have the types float, integer and bigInteger respectively. This allows an easy identification of the tenPercent function used. Note that writeln is also overloaded. Otherwise writeln would not be able to accept float and bigRational arguments.
Overloading does not consider the result of a function. The following example attempts to overload addOne with the same parameter type and a different result type:
const func integer: addOne (in integer: num) is return num + 1; const func float: addOne (in integer: num) is return float(num) + 1.0;
Return type overloading is not supported. Therefore the attempt above results in the compile-time error:
*** tst344.sd7(5):34: Redeclaration of "addOne (val integer: num)" const func float: addOne (in integer: num) is return float(num) + 1.0; ------------------------------------------------------------------------^ *** tst344.sd7(4):35: Previous declaration of "addOne (val integer: num)" const func integer: addOne (in integer: num) is return num + 1;
The absence of return type overloading improves readability, since:
The type of every expression (and sub expression) is independent of the context. |
You don't need to look where an expression is used. The expression alone gives you enough information to determine the type of the expression.
Operators like + can be overloaded with:
$ include "seed7_05.s7i"; include "float.s7i"; const func float: (in integer: summand1) + (in float: summand2) is return float(summand1) + summand2; const func float: (in float: summand1) + (in integer: summand2) is return summand1 + float(summand2); const proc: main is func begin writeln(123 + 123.456); writeln(123.456 + 123); end func;
The definitions of the + operator above allow mixing of integer and float arguments. The overloaded + operators above are taken from the mixarith.s7i library.
Templates allow the declaration of functions where the actual types are specified later. The function declarations are done inside a procedure that has a type as parameter. The library integer.s7i defines the template DECLARE_MIN_MAX as:
const proc: DECLARE_MIN_MAX (in type: aType) is func begin const func aType: min (in aType: value1, in aType: value2) is return value1 < value2 ? value1 : value2; const func aType: max (in aType: value1, in aType: value2) is return value1 > value2 ? value1 : value2; end func;
The template procedure DECLARE_MIN_MAX uses the type parameter aType to declare the functions min and max. The template is instantiated for every actual type which needs min and max. E.g.:
DECLARE_MIN_MAX(integer); # Instantiated in the integer.s7i library DECLARE_MIN_MAX(bigInteger); # Instantiated in the bigint.s7i library DECLARE_MIN_MAX(float); # Instantiated in the float.s7i library
This allows for expressions like min(2, 5) or min(PI, E).
This example program writes its arguments
$ include "seed7_05.s7i"; # Standard Seed7 library const proc: main is func local var string: stri is ""; begin for stri range argv(PROGRAM) do write(stri <& " "); end for; writeln; end func;
The for-statement iterates over argv(PROGRAM). The function argv(PROGRAM) returns an array string (=array of string elements). The for-statement is overloaded for various collection types. In the standard Seed7 library seed7_05.s7i the for-statement for arrays is declared as follows:
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 1 to length(arr_obj) do variable := arr_obj[number]; statements; end for; end func;
The syntax of this for-statement is declared as:
$ syntax expr: .for.().range.().to.().do.().end.for is -> 25;
Additionally everybody can overload the for-statement also. Because of these powerful features Seed7 does not need iterators.
Templates are just normal functions with types as parameters. The following template function declares for-statements:
const proc: FOR_DECLS (in type: aType) is func begin const proc: for (inout aType: variable) range (in aType: low) to (in aType: high) do (in proc: statements) end for is func begin variable := low; if variable <= high then statements; while variable < high do incr(variable); statements; end while; end if; end func; end func; FOR_DECLS(char); FOR_DECLS(boolean);
The body of the 'FOR_DECLS' function contains a declaration of the for-statement for the type aType. Calling 'FOR_DECLS' with char and boolean as parameter creates corresponding declarations of for-statements. The example above is a simplified part of the library forloop.s7i.
A declaration specifies the identifier, type, and other aspects of language elements such as variables, constants and functions. In Seed7 everything must be declared before it is used. All declarations are introduced with a specific keyword and follow a common pattern. The keyword is followed by a type (in example code red is used for types). In the table below aType is a placeholder for any type.
Declaration | Comment |
---|---|
var aType: name is ... | A variable declaration |
const aType: name is ... | A constant declaration |
val aType: name | Declaration of a value-parameter |
ref aType: name | Declaration of a reference-parameter |
in aType: name | Declaration of an in-parameter |
in var aType: name | Declaration of an in-var-parameter |
inout aType: name | Declaration of an inout-parameter |
in func aType: name | Declaration of a call-by-name parameter |
const type: name is ... | A type declaration |
const proc: name is ... | A procedure declaration |
const func aType: name is ... | A function declaration |
const func type: name is ... | Declaration of an abstract data type |
const proc: name (in type: aType) is ... | Declaration of a template |
syntax expr: pattern is ... | A syntax declaration |
A variable is a named place for a value. The value of a variable can be changed with an assignment. Variables must be declared before they can be used. E.g.:
var integer: number is 0;
This declares the integer variable 'number'. The variable is initialized with the value 0. Later the value of the variable can be changed with e.g.:
number := 1;
Variables can only hold values of their type. An attempt to assign a value with the wrong type results in a compile error:
*** tst545.sd7(7):52: Match for {number := "hello" } failed number := "hello";
A constant is a named value that cannot change during run-time. Constants must be declared before they can be used. E.g.:
const integer: ONE is 1;
This declares the integer constant 'ONE' with the value 1. An attempt to change a constant results in an compile error:
*** tst544.sd7(7):53: Variable expected in {ONE := 2 } found constant integer: ONE ONE := 2;
Type declarations define a name for a type. Type declarations are done as constant declarations where the type of the declared constant is type. E.g.:
const type: myChar is char;
Afterwards the new type can be used in other declarations. E.g.:
var myChar: aChar is 'x';
The code of a procedure does not change at run-time. Thus procedures are declared with a constant declaration:
const proc: helloWorld is func begin writeln("hello world"); end func;
Local declarations can be added to a procedure with the keyword local. E.g.:
const proc: helloWorld is func local const string: greeting is "hello world"; begin writeln(greeting); end func;
A procedure with a parameter (greeting) is defined with:
const proc: hello (in string: greeting) is func begin writeln(greeting); end func;
Procedure and function parameters are explained in chapter 6 (PARAMETERS).
Like with procedures the code of a function does not change at run-time. Thus functions are also declared with a constant declaration:
const func boolean: flipCoin is return rand(FALSE, TRUE);
Note that return is not a statement. Instead return is a shortcut for a function declaration with a result variable:
const func boolean: flipCoin is func result var boolean: coinState is FALSE; begin coinState := rand(FALSE, TRUE); end func;
The keyword local allows the introduction of local declarations:
const func string: alphabet is func result var string: abc is ""; local var char: ch is ' '; begin for ch range 'a' to 'z' do abc &:= ch; end for; end func;
A function with a parameter (number) is defined with:
const func float: inverse (in float: number) is return 1 / number;Procedure and function parameters are explained in chapter 6 (PARAMETERS).
An abstract data type is a type that requires additional information. E.g.: The abstract data type array requires the type of the array elements as additional information. Predefined abstract data types are array, subtype, struct, subrange, hash, set, interface and enum. The definition of the predefined abstract data type array in the library array.s7i starts with:
const func type: array (in type: baseType) is ...
The parameter baseType specifies the type of the array elements. The abstract data type array can be used in declarations:
var array integer: numbers is [] (1);
Other abstract data types are declared similar to the declaration of array.
User defined abstract data types are also possible.
Templates do declarations for a given type. Templates are executed at compile-time. The function FOR_ENUM_DECLS from the library forloop.s7i defines a for-loop that loops over all values of a given enumeration type:
const proc: FOR_ENUM_DECLS (in type: aType) is func begin const proc: for (inout aType: variable) range (attr aType) do (in proc: statements) end for is func begin for variable range aType.first to aType.last do statements; end for; end func; end func;
The template FOR_ENUM_DECLS is invoked in the library enumeration.s7i with:
FOR_ENUM_DECLS(enumType);
Each object declared with a 'const' or 'var' declaration obtains an initial value. It is not possible to use 'const' or 'var' declarations without initial value. The type of the initial value must fit to the type of the variable or constant. A compile error is triggered if this is not the case:
*** tst546.sd7(3):52: Match for {number ::= ' ' } failed var integer: number is ' '; ---------------------------^ *** tst546.sd7(3):32: Declaration of "number" failed var integer: number is ' ';
Expressions can be used as initial value. E.g.:
var string: fileName is NAME & ".txt";
The expression is evaluated and the result is assigned to the new object. This is done at compile-time by the interpreter or compiler. The initialization expressions may contain any function (or operator) call. That way user defined functions can also be used to initialize a constant or variable:
const boolean: maybe is flipCoin;
The initialization of variables and constants is done at compile-time. The initialization uses the create statement ( ::= ). Note that ::= is used internally by the interpreter and compiler. Explicit calls of ::= in user programs are not needed. A create statement is similar to an assignment ( := ), but with two important differences:
The lifetime of an object goes like this:
The first three steps are usually hidden in the declaration statement. The declaration statement executes
ONE ::= 1
to assign 1 to the object ONE. The destroy statement is the opposite of the create statement. It is automatically executed at the end of the lifetime of an object. The run-time library executes
destroy(fileName)
to free the memory referred by the string variable fileName. For simple types such as integer the destroy statement does nothing.
The mechanism with create and destroy is also used for call-by-value parameters (val, in var and in if it uses call-by-value). When a function is called the call-by-value parameters are initialized with a create statement:
formalParameter ::= actualParameter
At the end of the function the destroy statement is executed:
destroy(formalParameter)
For all predefined types the create statement ( ::= ) and the destroy statement are already defined. To allow the declaration of objects of a new user defined type the create and destroy statements for this type must be defined.
Syntax declarations are used to specify the syntax, priority and associativity of operators, statements, declarations and other constructs. A syntax declaration which defines the '+' operator is:
$ syntax expr: .(). + .() is -> 7;
Most syntax definitions can be found in the file syntax.s7i. A detailed description of the syntax declarations can be found in chapter 9 (Structured syntax definition) There is also a hard coded syntax for function calls with a parenthesis enclosed parameter list where the parameters are separated by commas. The hard coded syntax is described in chapter 11 (Expressions). Here we use a more complex syntax description:
With system declarations the analyzer and the interpreter are informed about which objects should be used for various system internal purposes. An example of a system declaration is
$ system "integer" is integer;
This defines that the type of all integer literals is integer. Additionally integer is used as type for all integers generated by primitive actions. There are different objects which are defined by a system declaration
The following system declarations exist
$ system "expr" is expr; $ system "integer" is integer; $ system "bigInteger" is bigInteger; $ system "char" is char; $ system "string" is string; $ system "proc" is proc; $ system "float" is float; $ system "true" is TRUE; $ system "false" is FALSE; $ system "empty" is empty; $ system "memory_error" is MEMORY_ERROR; $ system "numeric_error" is NUMERIC_ERROR; $ system "overflow_error" is OVERFLOW_ERROR; $ system "range_error" is RANGE_ERROR; $ system "index_error" is INDEX_ERROR; $ system "file_error" is FILE_ERROR; $ system "database_error" is DATABASE_ERROR; $ system "graphic_error" is GRAPHIC_ERROR; $ system "illegal_action" is ILLEGAL_ACTION; $ system "assign" is := ; $ system "create" is ::= ; $ system "destroy" is destroy; $ system "ord" is ord; $ system "in" is in; $ system "prot_outfile" is PROT_OUTFILE; $ system "flush" is flush; $ system "write" is write; $ system "writeln" is writeln; $ system "main" is main;
Pragmas specify how a program is processed. Like system declarations pragmas are introduced with a dollar sign ($) followed by the name of the pragma. The following pragmas exist:
pragma | parameter | comment |
---|---|---|
$ library | string | Specify additional directory for *.s7i files. |
$ message | string | Writes a message during parsing. |
$ info | on or off | Switch compilation info on or off. |
$ trace | string | Sets compile-time tracing flags. |
$ decls | - | Traces the declarations. |
$ names | unicode or ascii | Allows Unicode (or Ascii) identifiers. |
An unknown pragma results in a parsing error:
*** pragma.sd7(1):7:Illegal pragma "unknownPragma" $ unknownPragma ---------------^ The pragma message can be used to write a message during parsing. To write "hello world" during parsing use:
$ message "hello world";The pragma info can be used to change the verbosity level of the parsing phase. This overrules the -vn option of the interpreter. With
$ info on;the parser writes information about library names and the number of the line currently processed. With
$ info off;no such information is written.
The pragma trace can be used to turn interpreter tracing on or off during the parsing of the program. This overrules the -dx option of the interpreter. The string parameter of the trace pragma allows a sequence of the characters +, -, a, c, d, e, h, m, u, s and *. These characters have the following meaning:
- + Turn the following flags on (default)
- - Turn the following flags off
- a Trace primitive actions
- c Do action check
- d Trace dynamic calls
- e Trace exceptions and handlers
- h Trace heap size (in combination with 'a')
- m Trace matching of expressions
- u Trace exec utility functions
- s Trace signals
- * All flags
The pragma names can be used to allow Unicode in name identifiers:
$ names unicode;This allows variables with e.g. German umlauts or Cyrillic letters. This way beginners can use variable and function names from their native language.
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:
In all cases the control variable never gets a value outside of the range lower limit .. upper limit.
- 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);5. PREDEFINED TYPES
In the following sub-chapters the predefined types of the standard library are introduced. The operators have, if not stated otherwise, the type described in the sub-chapter as parameter type and result type. The relations have also the type described in the sub-chapter as parameter type and a result of type boolean. In the descriptions ⇒ is used to show an equivalent expression.
5.1 boolean
The type boolean consists of the two truth values TRUE and FALSE. The boolean functions are defined in the library "boolean.s7i".
Constants: boolean.value Default value of boolean (FALSE) boolean.first Minimum value of boolean (FALSE) boolean.last Maximum value of boolean (TRUE) Prefix operators: not Negation ( not TRUE ⇒ FALSE, not FALSE ⇒ TRUE ) Infix operators: and Logical and ( TRUE and TRUE ⇒ TRUE, A and B ⇒ FALSE else ) or Inclusive logical or ( FALSE or FALSE ⇒ FALSE, A or B ⇒ TRUE else ) A ? B : C Ternary operator condition ? thenValue : elseValue ( TRUE ? a : b ⇒ a, FALSE ? a : b ⇒ b ) boolean conv A Conversion of integer to boolean ( Type of argument A: integer, boolean conv 0 ⇒ FALSE, boolean conv 1 ⇒ TRUE ) boolean parse A Conversion of string to boolean ( Type of argument A: string, boolean parse "FALSE" ⇒ FALSE, boolean parse "TRUE" ⇒ TRUE, boolean parse "TRUE " ⇒ EXCEPTION RANGE_ERROR, boolean parse "ASDF" ⇒ EXCEPTION RANGE_ERROR ) Relations: =, <>, <, <=, >, >= ( A relation B ⇒ ord(A) relation ord(B) ) Functions: ord(A) Ordinal number ( Type of result: integer, ord(FALSE) ⇒ 0, ord(TRUE) ⇒ 1 ) integer(A) Ordinal number ( Type of result: integer, integer(FALSE) ⇒ 0, integer(TRUE) ⇒ 1 ) succ(A) Successor ( succ(FALSE) ⇒ TRUE, succ(TRUE) ⇒ EXCEPTION RANGE_ERROR ) pred(A) Predecessor ( pred(FALSE) ⇒ EXCEPTION RANGE_ERROR ) pred(TRUE) ⇒ FALSE ) boolean(A) Convert an integer to a boolean value ( Type of argument A: integer, boolean(0) ⇒ FALSE, boolean(1) ⇒ TRUE, boolean(2) ⇒ EXCEPTION RANGE_ERROR, boolean(-1) ⇒ EXCEPTION RANGE_ERROR ) boolean(A) Conversion of string to boolean ( Type of argument A: string, boolean("FALSE") ⇒ FALSE, boolean("TRUE") ⇒ TRUE, boolean("TRUE ") ⇒ EXCEPTION RANGE_ERROR, boolean("true") ⇒ EXCEPTION RANGE_ERROR, boolean("ASDF") ⇒ EXCEPTION RANGE_ERROR ) str(A) Conversion to string ( Type of result: string, str(FALSE) ⇒ "FALSE", str(TRUE) ⇒ "TRUE" ) literal(A) Convert a boolean value to a boolean literal. ( Type of result: string, literal(FALSE) ⇒ "FALSE", literal(TRUE) ⇒ "TRUE" ) rand(A, B) Random value in the range [A, B] The random values are uniform distributed. ( rand(A, B) returns a random value such that A <= rand(A, B) and rand(A, B) <= B holds. rand(A, A) ⇒ A, rand(TRUE, FALSE) ⇒ EXCEPTION RANGE_ERROR ) compare(A, B) Compare function ( Type of result: integer, compare(FALSE, TRUE) ⇒ -1, compare(TRUE, TRUE) ⇒ 0, compare(TRUE, FALSE) ⇒ 1 ) hashCode(A) Hash function ( Type of result: integer ) Statements: incr(A) Increment ( incr(A) ⇒ A:=succ(A) ) decr(A) Decrement ( decr(A) ⇒ A:=pred(A) ) ignore(A) Ignore valueThe logical operators and and or work strictly left to right. First they evaluate the left operand and then the right operand. If the result of the operation can be determined after evaluation of the left operand the right operand is not evaluated. This can be used to check for a boundary in a boolean expression. Naturally side effects of the right operand of the and and or operator only take place when the operand is executed.
Table for the behavior of different boolean expressions:
Expression Result when the first operand evaluates to FALSE TRUE not A TRUE FALSE A and B respectively
not((not A)or(not B))FALSE B A or B respectively
not((not A)and(not B))B TRUE A > B respectively
A and(not B)FALSE not B A >= B respectively
A or(not B)not B TRUE A < B respectively
(not A)and BB FALSE A <= B respectively
(not A)or BTRUE B not (A and B) respectively
(not A)or(not B)TRUE not B not (A or B) respectively
(not A)and(not B)not B FALSE Optimizing boolean expressions:
If the result of a boolean expression can be determined at compile time, the expression can be replaced by a constant. Additionally the following equations can be used:
(A or B) and (A or C) = A or (B and C) (A and B) or (A and C) = A and (B or C)5.2 integer
The type integer consists of signed 64-bit integer numbers. An integer integer literal is a sequence of digits which is taken to be decimal. The sequence of digits may be followed by the letter E or e an optional + sign and a decimal exponent. Based numbers can be specified when the sequence of digits is followed by the # character and a sequence of extended digits. The decimal number in front of the # character specifies the base of the number which follows the # character. As base a number between 2 and 36 is allowed. As extended digits the letters A or a can be used for 10, B or b can be used for 11 and so on to Z or z which can be used as 35. Examples of integer literals are:
0 2147483647 1E6 2e+9 16#c0 16#FFFF 8#177777 2#1010101010If an integer operation overflows it raises the exception OVERFLOW_ERROR. The integer functions are defined in the library "integer.s7i".
Constants: integer.value Default value of integer (0) integer.first Minimum value of integer (-9223372036854775808) integer.last Maximum value of integer (9223372036854775807) Prefix operators: + Identity - Change sign ! Factorial Infix operators: + Addition - Subtraction * Multiplication div Integer division truncated towards zero ( A div B ⇒ trunc(flt(A) / flt(B)), A div 0 ⇒ EXCEPTION NUMERIC_ERROR ) rem Reminder of integer division div ( A rem B ⇒ A - (A div B) * B, A rem 0 ⇒ EXCEPTION NUMERIC_ERROR ) mdiv Integer division truncated towards negative infinity ( A mdiv B ⇒ round(floor(flt(A) / flt(B))), A mdiv 0 ⇒ EXCEPTION NUMERIC_ERROR ) mod Reminder of integer division mdiv ( A mod B ⇒ A - (A mdiv B) * B, A mod 0 ⇒ EXCEPTION NUMERIC_ERROR ) ** Power ( A ** B is okay for B >= 0, A ** 0 ⇒ 1 for every A, even for A = 0, 1 ** B ⇒ 1 for B >= 0, A ** B ⇒ -(-A) ** B for A <= 0 and B >= 0 and odd(B), A ** B ⇒ (-A) ** B for A <= 0 and B >= 0 and not odd(B), A ** -1 ⇒ EXCEPTION NUMERIC_ERROR ) A << B Shift left ( A << B is okay for B >= 0 and B <= 63, A << B ⇒ EXCEPTION OVERFLOW_ERROR for B < 0 or B >= 64, A << B ⇒ A * 2 ** B, A << 0 ⇒ A ) A >> B Arithmetic shift right ( A >> B is okay for B >= 0 and B <= 63, A >> B ⇒ EXCEPTION OVERFLOW_ERROR for B < 0 or B >= 64, A >> B ⇒ A mdiv 2 ** B for B <= 62, A >> 0 ⇒ A, A >> B ⇒ C for A >= 0 holds: C >= 0, A >> B ⇒ C for A < 0 holds: C < 0, A >> B ⇒ 0 for A >= 0 and B > ord(log2(A)), A >> B ⇒ -1 for A < 0 and B > ord(log2(-A)), 0 >> B ⇒ 0 ) ! Binomial coefficient ( n ! k ⇒ 0 for k < 0, n ! 0 ⇒ 1, n ! 1 ⇒ n, n ! k ⇒ 0 for n >= 0 and k > n, n ! k ⇒ !n div (!k * !(n - k)) for k >= 0 and k <= n, n ! k ⇒ (-1) ** k * (n + k - 1 ! k) for n < 0 and k >= 0 ) A ? B : C Ternary operator condition ? thenValue : elseValue ( Type of argument A: boolean, TRUE ? a : b ⇒ a, FALSE ? a : b ⇒ b ) A radix B Convert the integer A to a string. The conversion uses the numeral system with the base B. ( Type of result: string, 48879 radix 16 ⇒ "beef", -48879 radix 16 ⇒ "-beef", 123 radix 37 ⇒ EXCEPTION RANGE_ERROR ) A RADIX B Convert the integer A to a string. The conversion uses the numeral system with the base B. ( Type of result: string, 48879 RADIX 16 ⇒ "BEEF", -48879 RADIX 16 ⇒ "-BEEF", 123 RADIX 37 ⇒ EXCEPTION RANGE_ERROR ) lpad Left padding with spaces ( 123 lpad 8 ⇒ " 123", 123 lpad 4 ⇒ " 123", 123 lpad 3 ⇒ "123", 123 lpad 2 ⇒ "123", 123 lpad -8 ⇒ "123" ) -12 lpad 4 ⇒ " -12", -12 lpad 3 ⇒ "-12", -12 lpad 2 ⇒ "-12" ) lpad0 Left padding with zeros ( 123 lpad0 8 ⇒ "00000123", 123 lpad0 4 ⇒ "0123", 123 lpad0 3 ⇒ "123", 123 lpad0 2 ⇒ "123", 123 lpad0 -8 ⇒ "123", -12 lpad0 4 ⇒ "-012", -12 lpad0 3 ⇒ "-12", -12 lpad0 2 ⇒ "-12" ) rpad Right padding with spaces ( 123 rpad 8 ⇒ "123 ", 123 rpad 4 ⇒ "123 ", 123 rpad 3 ⇒ "123", 123 rpad 2 ⇒ "123", 123 rpad -8 ⇒ "123" ) -12 rpad 4 ⇒ "-12 ", -12 rpad 3 ⇒ "-12", -12 rpad 2 ⇒ "-12" ) sci Conversion to a string in scientific notation ( Type of result: string, 12345 sci 4 ⇒ "1.2345e+4", 12345 sci 3 ⇒ "1.235e+4", 12345 sci 2 ⇒ "1.23e+4", 3141592 sci 0 ⇒ "3e+6", 27182818 sci 0 ⇒ "3e+7", 2**62 sci 6 ⇒ "4.611686e+18", -1 sci 3 ⇒ "-1.000e+0", -0 sci 2 ⇒ "0.00e+0" ) integer conv A Identity ( integer conv A ⇒ A ) integer parse A Conversion of string to integer ( Type of argument A: string, integer parse "123" ⇒ 123, integer parse "-123" ⇒ -123, integer parse "+5" ⇒ 5, integer parse " 1" ⇒ EXCEPTION RANGE_ERROR, integer parse "10 " ⇒ EXCEPTION RANGE_ERROR, integer parse "ASDF" ⇒ EXCEPTION RANGE_ERROR ) Relations: =, <>, <, <=, >, >= Functions: ord(A) Identity succ(A) Successor ( succ(A) ⇒ A+1, succ(integer.last) ⇒ EXCEPTION OVERFLOW_ERROR ) pred(A) Predecessor ( pred(A) ⇒ A-1, pred(integer.first) ⇒ EXCEPTION OVERFLOW_ERROR ) abs(A) Absolute value ( abs(A) ⇒ A for A >= 0, ( abs(A) ⇒ -A for A < 0, ( abs(integer.first) ⇒ EXCEPTION OVERFLOW_ERROR ) odd(A) Odd value ( Type of result: boolean ) str(A) Conversion to string ( Type of result: string, str(12345) ⇒ "12345" ) literal(A) Conversion to a literal ( Type of result: string, literal(A) ⇒ str(A) ) integer(A) Conversion of string to integer ( Type of argument A: string, integer("123") ⇒ 123, integer("-123") ⇒ -123, integer("+5") ⇒ 5, integer(" 1") ⇒ EXCEPTION RANGE_ERROR, integer("10 ") ⇒ EXCEPTION RANGE_ERROR, integer("ASDF") ⇒ EXCEPTION RANGE_ERROR ) integer(A, B) Convert numeric string, with specified radix, to an integer ( Type of argument A: string, integer("beef", 16) ⇒ 48879, integer("-177", 8) ⇒ -127, integer("10101010", 2) ⇒ 170, integer("Cafe", 16) ⇒ 51966, integer("0", 1) ⇒ EXCEPTION RANGE_ERROR, integer("qwertyuiop", 37) ⇒ EXCEPTION RANGE_ERROR ) bytes(A, S, E) Convert an integer into a string of bytes ( Type of argument S: signedness (UNSIGNED and SIGNED), Type of argument E: endianness (LE and BE), Type of result: string, bytes(1413829460, SIGNED, BE) ⇒ "TEST", bytes(1497451343, SIGNED, LE) ⇒ "OKAY" ) bytes(A, S, E, len) Convert an integer into a string of len bytes ( Type of argument S: signedness (UNSIGNED and SIGNED), Type of argument E: endianness (LE and BE), Type of result: string, bytes(1413829460, SIGNED, BE, 5) ⇒ "\0;TEST" bytes(1413829460, SIGNED, BE, 4) ⇒ "TEST" bytes(1413829460, SIGNED, BE, 3) ⇒ EXCEPTION RANGE_ERROR ) bytes2Int(A, S, E) Convert a string of bytes to an integer ( Type of argument A: string, Type of argument S: signedness (UNSIGNED and SIGNED), Type of argument E: endianness (LE and BE), bytes2Int("\210;\2;\150;I", UNSIGNED, LE) ⇒ 1234567890 ) sqrt(A) Integer square root ( sqrt(A) is okay for A >= 0, sqrt(A) ⇒ trunc(sqrt(flt(A))), sqrt(-1) ⇒ EXCEPTION NUMERIC_ERROR ) log10(A) Truncated base 10 logarithm ( log10(A) is defined for A >= 0, log10(10 ** A) = A for A >= 0, log10(pred(10 ** A)) = pred(A) for A >= 0, log10(10) ⇒ 1, log10(1) ⇒ 0, log10(0) ⇒ -1, log10(-1) ⇒ EXCEPTION NUMERIC_ERROR ) log2(A) Truncated base 2 logarithm ( log2(A) returns the position of the highest bit set. It is defined for A >= 0 log2(2 ** A) = A for A >= 0, log2(pred(2 ** A)) = pred(A) for A >= 0, log2(2) ⇒ 1, log2(1) ⇒ 0, log2(0) ⇒ -1, log2(-1) ⇒ EXCEPTION NUMERIC_ERROR ) bitLength(A) Number of bits in the minimum two's-complement representation, excluding the sign bit. ( bitLength(A) ⇒ succ(log2(A)) for A >= 0, bitLength(A) ⇒ bitLength(pred(-A)) for A < 0, bitLength(0) ⇒ 0, bitLength(-1) ⇒ 0 ) lowestSetBit(A) Index of the lowest-order one bit For A <> 0 this is equal to the number of lowest-order zero bits. ( A >> B << B = A for A <> 0 and B = lowestSetBit(A), lowestSetBit(0) ⇒ -1, lowestSetBit(1) ⇒ 0, lowestSetBit(2) ⇒ 1 ) rand(A, B) Random number in the range [A, B] The random values are uniform distributed. ( rand(A, B) returns a random number such that A <= rand(A, B) and rand(A, B) <= B holds. rand(A, A) ⇒ A, rand(1, 0) ⇒ EXCEPTION RANGE_ERROR ) min(A, B) Minimum of two numbers. ( min(1, 2) ⇒ 1 ) max(A, B) Maximum of two numbers. ( max(1, 2) ⇒ 2 ) compare(A, B) Compare function ( compare(1, 2) ⇒ -1, compare(5, 5) ⇒ 0, compare(8, 7) ⇒ 1 ) hashCode(A) Hash function Statements: A +:= B Increment A by B ( A +:= B ⇒ A := A + B ) A -:= B Decrement A by B ( A -:= B ⇒ A := A - B ) A *:= B Multiplying copy ( A *:= B ⇒ A := A * B ) A <<:= B Shift left copy ( A <<:= B ⇒ A := A << B ) A >>:= B Shift right copy ( A >>:= B ⇒ A := A >> B ) incr(A) Increment with 1 ( incr(A) ⇒ A +:= 1, incr(A) ⇒ EXCEPTION OVERFLOW_ERROR for A = integer.last ) decr(A) Decrement with 1 ( decr(A) ⇒ A -:= 1, decr(A) ⇒ EXCEPTION OVERFLOW_ERROR for A = integer.first ) ignore(A) Ignore valueFor the operations div and rem holds for all A:
(A div B) * B + A rem B = A when B <> 0 -A div B = -(A div B) when B <> 0 -A rem B = -(A rem B) when B <> 0 A rem B >= 0 and A rem B < abs(B) when B <> 0 and A >= 0 A rem B <= 0 and A rem B > -abs(B) when B <> 0 and A <= 0For the operations mdiv and mod holds for all A:
(A mdiv B) * B + A mod B = A when B <> 0 -A mdiv B = A mdiv -B when B <> 0 -A mod -B = -(A mod B) when B <> 0 A mod B >= 0 and A mod B < B when B > 0 A mod B <= 0 and A mod B > B when B < 0For the operation mdiv holds:
A mdiv B = A div B - 1 when A and B have different signs and A rem B <> 0 holds. A mdiv B = A div B when A and B have the same sign or A rem B = 0 holds. A mdiv B = (A - 1) div B - 1 when A > 0 and B < 0 holds. A mdiv B = (A + 1) div B - 1 when A < 0 and B > 0 holds. A mdiv 2 ** B = A >> B when B >= 0 holdsFor the operation mod holds:
A mod B = A rem B + B when A and B have different signs and A rem B <> 0 holds. A mod B = A rem B when A and B have the same sign or A rem B = 0 holds.Tables for the behavior of div, rem, mdiv and mod:
A B A div B A rem B A mdiv B A mod B 5 3 1 2 1 2 4 3 1 1 1 1 3 3 1 0 1 0 2 3 0 2 0 2 1 3 0 1 0 1 0 3 0 0 0 0 -1 3 0 -1 -1 2 -2 3 0 -2 -1 1 -3 3 -1 0 -1 0 -4 3 -1 -1 -2 2 -5 3 -1 -2 -2 1
A B A div B A rem B A mdiv B A mod B 5 -3 -1 2 -2 -1 4 -3 -1 1 -2 -2 3 -3 -1 0 -1 0 2 -3 0 2 -1 -1 1 -3 0 1 -1 -2 0 -3 0 0 0 0 -1 -3 0 -1 0 -1 -2 -3 0 -2 0 -2 -3 -3 1 0 1 0 -4 -3 1 -1 1 -1 -5 -3 1 -2 1 -2 Tables for the behavior of ! (Binomial coefficient):
n ! k k -5 -4 -3 -2 -1 0 1 2 3 4 5 n -5 0 0 0 0 0 1 -5 15 -35 70 -126 -4 0 0 0 0 0 1 -4 10 -20 35 -56 -3 0 0 0 0 0 1 -3 6 -10 15 -21 -2 0 0 0 0 0 1 -2 3 -4 5 -6 -1 0 0 0 0 0 1 -1 -1 -1 -1 -1 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 2 0 0 0 0 0 1 2 1 0 0 0 3 0 0 0 0 0 1 3 3 1 0 0 4 0 0 0 0 0 1 4 6 4 1 0 5 0 0 0 0 0 1 5 10 10 5 1 For the sqrt function holds (when A >= 0):
sqrt(A) * sqrt(A) <= A and (sqrt(A) + 1) * (sqrt(A) + 1) > A
5.3 bigInteger
The type bigInteger describes signed integer numbers of unlimited size. A bigInteger literal is a sequence of digits followed by an underscore character (for example 1_ ). Based numbers can be specified when the sequence of digits is followed by the # character and a sequence of extended digits. The decimal number in front of the # character specifies the base of the number which follows the # character. As base a number between 2 and 36 is allowed. As extended digits the letters A or a can be used for 10, B or b can be used for 11 and so on to Z or z which can be used as 35. Like decimal bigInteger literals the extended digits must be followed by an underscore character. Examples of bigInteger literals are:
0_ 18446744073709551616_ 16#deadbeefcafe_Although bigInteger operations cannot overflow, it can happen that there is not enough memory to represent a bigInteger value. In this case the exception MEMORY_ERROR is raised. The bigInteger functions are defined in the library "bigint.s7i".
Constants: bigInteger.value Default value of bigInteger (0_) Prefix operators: + Identity - Change sign ! Factorial Infix operators: + Addition - Subtraction * Multiplication div Integer division truncated towards zero ( A div B ⇒ trunc(A / B), A div 0_ ⇒ EXCEPTION NUMERIC_ERROR ) rem Reminder of integer division div ( A rem B ⇒ A - (A div B) * B, A rem 0_ ⇒ EXCEPTION NUMERIC_ERROR ) mdiv Integer division truncated towards negative infinity ( A mdiv B ⇒ floor(A / B), A mdiv 0_ ⇒ EXCEPTION NUMERIC_ERROR ) mod Reminder of integer division mdiv ( A mod B ⇒ A - (A mdiv B) * B, A mod 0_ ⇒ EXCEPTION NUMERIC_ERROR ) A ** B Power ( Type of argument B: integer, A ** B is okay for B >= 0, A ** 0 ⇒ 1_ for every A, even for A = 0_, 1_ ** B ⇒ 1_ for B >= 0, A ** B ⇒ -(-A) ** B for A <= 0_ and B >= 0 and odd(B), A ** B ⇒ (-A) ** B for A <= 0_ and B >= 0 and not odd(B), A ** -1 ⇒ EXCEPTION NUMERIC_ERROR ) A << B Shift left ( Type of argument B: integer, A << B ⇒ A * 2_ ** B for B >= 0, A << B ⇒ A >> -B for B < 0, A << 0 ⇒ A, 0_ << B ⇒ 0_ for every B ) A >> B Arithmetic shift right ( Type of argument B: integer, A >> B ⇒ A mdiv 2_ ** B for B >= 0, A >> B ⇒ A << -B for B < 0, A >> 0 ⇒ A, A >> B ⇒ C for A >= 0_ holds: C >= 0_, A >> B ⇒ C for A < 0_ holds: C < 0_, A >> B ⇒ 0_ for A >= 0_ and B > ord(log2(A)), A >> B ⇒ -1_ for A < 0_ and B > ord(log2(-A)), 0_ >> B ⇒ 0_ for every B ) ! Binomial coefficient ( n ! k ⇒ 0_ for k < 0_, n ! 0_ ⇒ 1_, n ! 1_ ⇒ n, n ! k ⇒ 0_ for n >= 0_ and k > n, n ! k ⇒ !n div (!k * !(n - k)) for k >= 0_ and k <= n, n ! k ⇒ (-1) ** k * (n + k - 1 ! k) for n < 0_ and k >= 0_ ) A ? B : C Ternary operator condition ? thenValue : elseValue ( Type of argument A: boolean, TRUE ? a : b ⇒ a, FALSE ? a : b ⇒ b ) A radix B Convert the bigInteger A to a string. The conversion uses the numeral system with the base B. ( Type of result: string, 3735928559_ radix 16 ⇒ "deadbeef", -3735928559_ radix 16 ) ⇒ "-deadbeef", 123_ radix 37 ⇒ EXCEPTION RANGE_ERROR ) A RADIX B Convert the integer A to a string. The conversion uses the numeral system with the base B. ( Type of result: string, 3735928559_ RADIX 16 ⇒ "DEADBEEF", -3735928559_ RADIX 16 ) ⇒ "-DEADBEEF", 123_ RADIX 37 ⇒ EXCEPTION RANGE_ERROR ) sci Conversion to a string in scientific notation ( Type of right operand: integer, Type of result: string, 12345_ sci 4 ⇒ "1.2345e+4", 12345_ sci 3 ⇒ "1.235e+4", 12345_ sci 2 ⇒ "1.23e+4", 3141592_ sci 0 ⇒ "3e+6", 27182818_ sci 0 ⇒ "3e+7", 2_**62 sci 6 ⇒ "4.611686e+18", -1_ sci 3 ⇒ "-1.000e+0", -0_ sci 2 ⇒ "0.00e+0" ) bigInteger conv A Conversion of integer to bigInteger ( Type of argument A: integer, bigInteger conv 1 ⇒ 1_ ) bigInteger parse A Conversion of string to integer ( Type of argument A: string, bigInteger parse "123" ⇒ 123_, bigInteger parse "-123" ⇒ -123_, bigInteger parse "+5" ⇒ 5_, bigInteger parse " 1" ⇒ EXCEPTION RANGE_ERROR, bigInteger parse "10 " ⇒ EXCEPTION RANGE_ERROR, bigInteger parse "ASDF" ⇒ EXCEPTION RANGE_ERROR ) Relations: =, <>, <, <=, >, >= Functions: ord(A) Ordinal number ( Type of result: integer ) ord(99999999999999999999_) ⇒ EXCEPTION RANGE_ERROR ) integer(A) Ordinal number ( Type of result: integer ) integer(99999999999999999999_) ⇒ EXCEPTION RANGE_ERROR ) succ(A) Successor ( succ(A) ⇒ A+1_ ) pred(A) Predecessor ( pred(A) ⇒ A-1_ ) abs(A) Absolute value odd(A) Odd value ( Type of result: boolean ) str(A) Conversion to string ( Type of result: string, str(9876543210_) ⇒ "9876543210" ) literal(A) Convert a bigInteger number to a bigInteger literal. ( Type of result: string, literal(9876543210_) ⇒ "9876543210_" ) bigInteger(A) Convert an integer to a bigInteger ( Type of argument A: integer, bigInteger(1) ⇒ 1_ ) bigInteger(A) Convert a numeric string to a bigInteger ( Type of argument A: string, bigInteger("123") ⇒ 123_, bigInteger("-123") ⇒ -123_, bigInteger("+5") ⇒ 5_, bigInteger(" 1") ⇒ EXCEPTION RANGE_ERROR, bigInteger("10 ") ⇒ EXCEPTION RANGE_ERROR, bigInteger("ASDF") ⇒ EXCEPTION RANGE_ERROR ) bigInteger(A, B) Convert numeric string, with specified radix, to a bigInteger ( Type of argument A: string, Type of argument B: integer, bigInteger("deadbeef", 16) ⇒ 3735928559_, bigInteger("-77777777777", 8) ⇒ -8589934591_, bigInteger("10101010", 2) ⇒ 170_, bigInteger("Cafe", 16) ⇒ 51966_, bigInteger("0", 1) ⇒ EXCEPTION RANGE_ERROR, bigInteger("qwertyuiop", 37) ⇒ EXCEPTION RANGE_ERROR ) bytes(A, S, E) Convert a bigInteger into a string of bytes ( Type of argument S: signedness (UNSIGNED and SIGNED), Type of argument E: endianness (LE and BE), Type of result: string, bytes(1413829460_, SIGNED, BE) ⇒ "TEST", bytes(1497451343_, SIGNED, LE) ⇒ "OKAY" ) bytes(A, S, E, len) Convert a bigInteger into a string of len bytes ( Type of argument S: signedness (UNSIGNED and SIGNED), Type of argument E: endianness (LE and BE), Type of result: string, bytes(1413829460_, SIGNED, BE, 5) ⇒ "\0;TEST" bytes(1413829460_, SIGNED, BE, 4) ⇒ "TEST" bytes(1413829460_, SIGNED, BE, 3) ⇒ EXCEPTION RANGE_ERROR ) bytes2BigInt(A, S, E) Convert a string of bytes to a bigInteger ( Type of argument A: string, Type of argument S: signedness (UNSIGNED and SIGNED), Type of argument E: endianness (LE and BE), bytes2BigInt("\210;\2;\150;I", UNSIGNED, LE) ⇒ 1234567890_ ) sqrt(A) Integer square root ( sqrt(A) is okay for A >= 0_ sqrt(A) ⇒ trunc(sqrt(flt(A))), sqrt(-1_) ⇒ EXCEPTION NUMERIC_ERROR ) modInverse(A, B) Compute the modular multiplicative inverse of A modulo B modPow(A, B, C) Compute the modular exponentiation of A ** B log10(A) Truncated base 10 logarithm ( log10(A) is defined for A >= 0_ log10(10_ ** A) = A for A >= 0_, log10(pred(10_ ** A)) = pred(A) for A >= 0_, log10(10_) ⇒ 1_, log10(1_) ⇒ 0_, log10(0_) ⇒ -1_, log10(-1_) ⇒ EXCEPTION NUMERIC_ERROR ) log2(A) Truncated base 2 logarithm ( log2(A) returns the position of the highest bit set. It is defined for A >= 0 log2(2_ ** A) = A for A >= 0, log2(pred(2_ ** A)) = pred(A) for A >= 0, log2(2_) ⇒ 1_, log2(1_) ⇒ 0_, log2(0_) ⇒ -1_, log2(-1_) ⇒ EXCEPTION NUMERIC_ERROR ) gcd(A, B) Greatest common divisor of A and B. ( gcd(A, B) = gcd(B, A), gcd(A, B) = gcd(-A, B), gcd(A, 0) = abs(A) ) bitLength(A) Number of bits in the minimum two's-complement representation, excluding the sign bit. ( Type of result: integer, bitLength(A) ⇒ ord(succ(log2(A))) for A >= 0_, bitLength(A) ⇒ bitLength(pred(-A)) for A < 0_, bitLength(0_) ⇒ 0, bitLength(-1_) ⇒ 0 ) lowestSetBit(A) Index of the lowest-order one bit For A <> 0_ this is equal to the number of lowest-order zero bits. ( Type of result: integer, A >> B << B = A for A <> 0_ and B = lowestSetBit(A), lowestSetBit(0_) ⇒ -1, lowestSetBit(1_) ⇒ 0, lowestSetBit(2_) ⇒ 1 ) rand(A, B) Random number in the range [A, B] The random values are uniform distributed. ( rand(A, B) returns a random number such that A <= rand(A, B) and rand(A, B) <= B holds. rand(A, A) ⇒ A, rand(1_, 0_) ⇒ EXCEPTION RANGE_ERROR ) min(A, B) Minimum of two numbers. ( min(1_, 2_) ⇒ 1_ ) max(A, B) Maximum of two numbers. ( max(1_, 2_) ⇒ 2_ ) compare(A, B) Compare function ( Type of result: integer, compare(1_, 2_) ⇒ -1, compare(5_, 5_) ⇒ 0, compare(8_, 7_) ⇒ 1 ) hashCode(A) Hash function ( Type of result: integer ) Statements: A +:= B Increment A by B ( A +:= B ⇒ A := A + B ) A -:= B Decrement A by B ( A -:= B ⇒ A := A - B ) A *:= B Multiplying copy ( A *:= B ⇒ A := A * B ) A <<:= B Shift left copy ( A <<:= B ⇒ A := A << B ) A >>:= B Shift right copy ( A >>:= B ⇒ A := A >> B ) incr(A) Increment with 1 ( incr(A) ⇒ A +:= 1_ ) decr(A) Decrement with 1 ( decr(A) ⇒ A -:= 1_ ) ignore(A) Ignore valueFor the operations div and rem holds for all A:
(A div B) * B + A rem B = A when B <> 0_ -A div B = -(A div B) when B <> 0_ -A rem B = -(A rem B) when B <> 0_ A rem B >= 0_ and A rem B < abs(B) when B <> 0_ and A >= 0_ A rem B <= 0_ and A rem B > -abs(B) when B <> 0_ and A <= 0_For the operations mdiv and mod holds for all A:
(A mdiv B) * B + A mod B = A when B <> 0_ -A mdiv B = A mdiv -B when B <> 0_ -A mod -B = -(A mod B) when B <> 0_ A mod B >= 0_ and A mod B < B when B > 0_ A mod B <= 0_ and A mod B > B when B < 0_For the operation mdiv holds:
A mdiv B = A div B - 1_ when A and B have different signs and A rem B <> 0_ holds. A mdiv B = A div B when A and B have the same sign or A rem B = 0_ holds. A mdiv B = (A - 1_) div B - 1_ when A > 0_ and B < 0_ holds. A mdiv B = (A + 1_) div B - 1_ when A < 0_ and B > 0_ holds. A mdiv 2_ ** B = A >> B when B >= 0 holdsFor the operation mod holds:
A mod B = A rem B + B when A and B have different signs and A rem B <> 0_ holds. A mod B = A rem B when A and B have the same sign or A rem B = 0_ holds.Tables for the behavior of div, rem, mdiv and mod:
A B A div B A rem B A mdiv B A mod B 5_ 3_ 1_ 2_ 1_ 2_ 4_ 3_ 1_ 1_ 1_ 1_ 3_ 3_ 1_ 0_ 1_ 0_ 2_ 3_ 0_ 2_ 0_ 2_ 1_ 3_ 0_ 1_ 0_ 1_ 0_ 3_ 0_ 0_ 0_ 0_ -1_ 3_ 0_ -1_ -1_ 2_ -2_ 3_ 0_ -2_ -1_ 1_ -3_ 3_ -1_ 0_ -1_ 0_ -4_ 3_ -1_ -1_ -2_ 2_ -5_ 3_ -1_ -2_ -2_ 1_
A B A div B A rem B A mdiv B A mod B 5_ -3_ -1_ 2_ -2_ -1_ 4_ -3_ -1_ 1_ -2_ -2_ 3_ -3_ -1_ 0_ -1_ 0_ 2_ -3_ 0_ 2_ -1_ -1_ 1_ -3_ 0_ 1_ -1_ -2_ 0_ -3_ 0_ 0_ 0_ 0_ -1_ -3_ 0_ -1_ 0_ -1_ -2_ -3_ 0_ -2_ 0_ -2_ -3_ -3_ 1_ 0_ 1_ 0_ -4_ -3_ 1_ -1_ 1_ -1_ -5_ -3_ 1_ -2_ 1_ -2_ Tables for the behavior of ! (Binomial coefficient):
n ! k k -5_ -4_ -3_ -2_ -1_ 0_ 1_ 2_ 3_ 4_ 5_ n -5_ 0_ 0_ 0_ 0_ 0_ 1_ -5_ 15_ -35_ 70_ -126_ -4_ 0_ 0_ 0_ 0_ 0_ 1_ -4_ 10_ -20_ 35_ -56_ -3_ 0_ 0_ 0_ 0_ 0_ 1_ -3_ 6_ -10_ 15_ -21_ -2_ 0_ 0_ 0_ 0_ 0_ 1_ -2_ 3_ -4_ 5_ -6_ -1_ 0_ 0_ 0_ 0_ 0_ 1_ -1_ -1_ -1_ -1_ -1_ 0_ 0_ 0_ 0_ 0_ 0_ 1_ 0_ 0_ 0_ 0_ 0_ 1_ 0_ 0_ 0_ 0_ 0_ 1_ 1_ 0_ 0_ 0_ 0_ 2_ 0_ 0_ 0_ 0_ 0_ 1_ 2_ 1_ 0_ 0_ 0_ 3_ 0_ 0_ 0_ 0_ 0_ 1_ 3_ 3_ 1_ 0_ 0_ 4_ 0_ 0_ 0_ 0_ 0_ 1_ 4_ 6_ 4_ 1_ 0_ 5_ 0_ 0_ 0_ 0_ 0_ 1_ 5_ 10_ 10_ 5_ 1_ For the sqrt function holds (when A >= 0_):
sqrt(A) * sqrt(A) <= A and (sqrt(A) + 1_) * (sqrt(A) + 1_) > A
5.4 rational
The type rational consists of rational numbers represented with an integer numerator and an integer denominator. The values of the type rational are finite and periodical decimal numbers. Rational literals do not exist. If a rational operation overflows it raises the exception OVERFLOW_ERROR. In integer computations an overflow can only happen with very huge positive or negative numbers. In rational computations an overflow can happen with small numbers. Because of widening big denominators can be produced easily. E.g.: 1/1777 + 1/1999 = 3776/3552223 . The rational functions are defined in the library "rational.s7i".
Elements: var integer: numerator is 0; var integer: denominator is 1; Constants: rational.value Default value of rational (0/1) Prefix operators: + Identity - Change sign Infix operators: + Addition - Subtraction * Multiplication / Division / Create rational from numerator and denominator ( Type of left operand: integer, Type of right operand: integer ) ** Power ( rational ** integer ) A ? B : C Ternary operator condition ? thenValue : elseValue ( Type of argument A: boolean, TRUE ? a : b ⇒ a, FALSE ? a : b ⇒ b ) rational conv A Conversion of integer to rational ( Type of argument A: integer, rational conv 1 ⇒ 1 / 1 ) digits Conversion to string with specified precision ( Type of right operand: integer, Type of result: string, 1/64 digits 7 ⇒ "0.0156250", 1/64 digits 4 ⇒ "0.0156", 1/64 digits 2 ⇒ "0.02", 355/113 digits 6 ⇒ "3.141593", 22/7 digits 0 ⇒ "3", -1/2 digits 1 ⇒ "-1", 1/0 digits 5 ⇒ "Infinity", -1/0 digits 6 ⇒ "-Infinity", 0/0 digits 7 ⇒ "NaN", -1/2048 digits 3 ⇒ "0.000" ) sci Conversion to a string in scientific notation ( Type of right operand: integer, Type of result: string, 1/64 sci 4 ⇒ "1.5625e-2", 1/64 sci 3 ⇒ "1.563e-2", 1/64 sci 2 ⇒ "1.56e-2", 355/113 sci 6 ⇒ "3.141593e+0", 22/7 sci 0 ⇒ "3e+0", -1/2 sci 1 ⇒ "-5.0e-1", 1/0 sci 5 ⇒ "Infinity", -1/0 sci 6 ⇒ "-Infinity", 0/0 sci 7 ⇒ "NaN", -1/2048 sci 3 ⇒ "-4.883e-4", -0/1 sci 2 ⇒ "0.00e+0" ) rational parse A Conversion of string to rational ( Type of argument A: string, rational parse "3/5" ⇒ 3 / 5, rational parse "1.25" ⇒ 5 / 4, rational parse "0.(3)" ⇒ 1 / 3, rational parse "1.23(45)" ⇒ 679 / 550, rational parse "3.(142857)" ⇒ 22 / 7, rational parse "0.(846153)" ⇒ 11 / 13 ) Relations: =, <>, <, <=, >, >= Functions: abs(A) Absolute value rat(A) Conversion of integer to rational ( Type of argument A: integer, rat(1) ⇒ 1 / 1 ) rational(A) Conversion of integer to rational ( Type of argument A: integer, rational(1) ⇒ 1 / 1 ) rational(A) Conversion of string to rational ( Type of argument A: string, rational("3/5") ⇒ 3 / 5, rational("1.25") ⇒ 5 / 4, rational("0.(3)") ⇒ 1 / 3, rational("1.23(45)") ⇒ 679 / 550, rational("3.(142857)") ⇒ 22 / 7, rational("0.(846153)") ⇒ 11 / 13 ) floor(A) Truncation towards negative infinity ( Type of result: integer, floor(9/5) ⇒ 1, floor(1/1) ⇒ 1, floor(-1/1) ⇒ -1, floor(-9/5) ⇒ -2 ) ceil(A) Rounding up towards positive infinity ( Type of result: integer, ceil(6/5) ⇒ 2, ceil(1/1) ⇒ 1, ceil(-1/1) ⇒ -1, ceil(-6/5) ⇒ -1 ) trunc(A) Truncation towards zero ( Type of result: integer, trunc(9/5) ⇒ 1, trunc(1/1) ⇒ 1, trunc(-1/1) ⇒ -1, trunc(-9/5) ⇒ -1 ) round(A) Round towards zero ( Type of result: integer, round(1/2) ⇒ 1, round(-1/2) ⇒ -1, round(2/5) ⇒ 0, round(-2/5) ⇒ 0 ) round10(A, B) Round with a decimal precision towards zero ( Type of B: integer, round10(1/4, 1) ⇒ 3/10, round10(-1/4, 1) ⇒ -3/10, round10(2/5, 0) ⇒ 0/1, round(-2/5, 0) ⇒ 0/1 ) str(A) Convert to a string with a decimal representation ( Type of result: string, str(1/3) ⇒ "0.(3)" ) fraction(A) Convert to a string with a fraction ( Type of result: string, fraction(rational("0.(3)")) ⇒ "1/3" ) min(A, B) Minimum of two numbers. ( min(2/5, 1/2) ⇒ 2/5 ) max(A, B) Maximum of two numbers. ( max(2/5, 1/2) ⇒ 1/2 ) compare(A, B) Compare function ( Type of result: integer, compare(19/10, 2/1) ⇒ -1, compare(26/5, 26/5) ⇒ 0, compare(8/1, 79/10) ⇒ 1 ) hashCode(A) Hash function ( Type of result: integer ) Statements: A +:= B Increment A by B ( A +:= B ⇒ A := A + B ) A -:= B Decrement A by B ( A -:= B ⇒ A := A - B ) A *:= B Multiplying copy ( A *:= B ⇒ A := A * B ) A /:= B Dividing copy ( A /:= B ⇒ A := A / B ) ignore(A) Ignore valueAll calculations with rational numbers are done exact. (Without any rounding)
5.5 bigRational
The type bigRational consists of rational numbers represented with an bigInteger numerator and an bigInteger denominator. The values of the type bigRational are finite and periodical decimal numbers. BigRational literals do not exist. Although bigRational operations cannot overflow, it can happen that there is not enough memory to represent a bigRational value. In this case the exception MEMORY_ERROR is raised. The bigRational functions are defined in the library "bigrat.s7i".
Elements: var bigInteger: numerator is 0_; var bigInteger: denominator is 1_; Constants: bigRational.value Default value of bigRational (0_/1_) Prefix operators: + Identity - Change sign Infix operators: + Addition - Subtraction * Multiplication / Division / Create bigRational from numerator and denominator ( Type of left argument: bigInteger, Type of right argument: bigInteger ) ** Power ( bigRational ** integer ) A ? B : C Ternary operator condition ? thenValue : elseValue ( Type of argument A: boolean, TRUE ? a : b ⇒ a, FALSE ? a : b ⇒ b ) bigRational conv A Conversion of integer to bigRational ( Type of argument A: integer, bigRational conv 1 ⇒ 1_ / 1_ ) bigRational conv A Conversion of bigInteger to bigRational ( Type of argument A: bigInteger, bigRational conv 1_ ⇒ 1_ / 1_ ) digits Conversion to string with specified precision ( Type of right operand: integer, Type of result: string, 1_/64_ digits 7 ⇒ "0.0156250", 1_/64_ digits 4 ⇒ "0.0156", 1_/64_ digits 2 ⇒ "0.02", 355_/113_ digits 6 ⇒ "3.141593", 22_/7_ digits 0 ⇒ "3", -1_/2_ digits 1 ⇒ "-1", 1_/0_ digits 5 ⇒ "Infinity", -1_/0_ digits 6 ⇒ "-Infinity", 0_/0_ digits 7 ⇒ "NaN", -1_/2048_ digits 3 ⇒ "0.000" ) sci Conversion to a string in scientific notation ( Type of right operand: integer, Type of result: string, 1_/64_ sci 4 ⇒ "1.5625e-2", 1_/64_ sci 3 ⇒ "1.563e-2", 1_/64_ sci 2 ⇒ "1.56e-2", 355_/113_ sci 6 ⇒ "3.141593e+0", 22_/7_ sci 0 ⇒ "3e+0", -1_/2_ sci 1 ⇒ "-5.0e-1", 1_/0_ sci 5 ⇒ "Infinity", -1_/0_ sci 6 ⇒ "-Infinity", 0_/0_ sci 7 ⇒ "NaN", -1_/2048_ sci 3 ⇒ "-4.883e-4", -0_/1_ sci 2 ⇒ "0.00e+0" ) bigRational parse A Conversion of string to bigRational ( Type of argument A: string, bigRational parse "3/5"⇒ 3_ / 5_, bigRational parse "1.25" ⇒ 5_ / 4_, bigRational parse "0.(3)" ⇒ 1_ / 3_, bigRational parse "1.23(45)" ⇒ 679_ / 550_, bigRational parse "3.(142857)" ⇒ 22_ / 7_, bigRational parse "0.(846153)" ⇒ 11_ / 13_ ) Relations: =, <>, <, <=, >, >= Functions: abs(A) Absolute value rat(A) Conversion of bigInteger to bigRational ( Type of argument A: bigInteger, rat(1_) ⇒ 1_ / 1_ ) bigRational(A) Conversion of integer to bigRational ( Type of argument A: integer, bigRational(1) ⇒ 1_ / 1_ ) bigRational(A) Conversion of bigInteger to bigRational ( Type of argument A: bigInteger, bigRational(1_) ⇒ 1_ / 1_ ) bigRational(A) Conversion of string to bigRational ( Type of argument A: string, bigRational("3/5") ⇒ 3_ / 5_, bigRational("1.25") ⇒ 5_ / 4_, bigRational("0.(3)") ⇒ 1_ / 3_, bigRational("1.23(45)") ⇒ 679_ / 550_, bigRational("3.(142857)") ⇒ 22_ / 7_, bigRational("0.(846153)") ⇒ 11_ / 13_ ) floor(A) Truncation towards negative infinity ( Type of result: bigInteger, floor(9_/5_) ⇒ 1_, floor(1_/1_) ⇒ 1_, floor(-1_/1_) ⇒ -1_, floor(-9_/5_) ⇒ -2_ ) ceil(A) Rounding up towards positive infinity ( Type of result: bigInteger, ceil(6_/5_) ⇒ 2_, ceil(1_/1_) ⇒ 1_, ceil(-1_/1_) ⇒ -1_, ceil(-6_/5_) ⇒ -1_ ) trunc(A) Truncation towards zero ( Type of result: bigInteger, trunc(9_/5_) ⇒ 1_, trunc(1_/1_) ⇒ 1_, trunc(-1_/1_) ⇒ -1_, trunc(-9_/5_) ⇒ -1_ ) round(A) Round towards zero ( Type of result: bigInteger, round(1_/2_) ⇒ 1_, round(-1_/2_) ⇒ -1_, round(2_/5_) ⇒ 0_, round(-2_/5_) ⇒ 0_ ) round10(A, B) Round with a decimal precision towards zero ( Type of B: integer, round10(1_/4_, 1) ⇒ 3_/10_, round10(-1_/4_, 1) ⇒ -3_/10_, round10(2_/5_, 0) ⇒ 0_/1_, round(-2_/5_, 0) ⇒ 0_/1_ ) str(A) Convert to a string with a decimal representation ( Type of result: string, str(1_/3_) ⇒ "0.(3)" ) fraction(A) Convert to a string with a fraction ( Type of result: string, fraction(bigRational("0.(3)")) ⇒ "1/3" ) min(A, B) Minimum of two numbers. ( min(2_/5_, 1_/2_) ⇒ 2_/5_ ) max(A, B) Maximum of two numbers. ( max(2_/5_, 1_/2_) ⇒ 1_/2_ ) compare(A, B) Compare function ( Type of result: integer, compare(19_/10_, 2_/1_) ⇒ -1, compare(26_/5_, 26_/5_) ⇒ 0, compare(8_/1_, 79_/10_) ⇒ 1 ) hashCode(A) Hash function ( Type of result: integer ) Statements: A +:= B Increment A by B ( A +:= B ⇒ A := A + B ) A -:= B Decrement A by B ( A -:= B ⇒ A := A - B ) A *:= B Multiplying copy ( A *:= B ⇒ A := A * B ) A /:= B Dividing copy ( A /:= B ⇒ A := A / B ) ignore(A) Ignore valueAll calculations with bigRational numbers are done exact. (Without any rounding)
5.6 float
The type float consists of double precision floating point numbers. Float literals use base 10 and contain a decimal point. There must be at least one digit before and after the decimal point. An exponent part, which is introduced with E or e, is optional. The exponent can be signed, but the mantissa is not. A literal does not have a sign, + or - are unary operations. Examples of float literals are:
3.14159265358979 1.0E-12 0.1234The function str and the operators digits and parse create and accept float literals with sign. Basic float functions are defined in the library "float.s7i". Trigonometric- and other mathematical functions are defined in the library "math.s7i".
Constants: float.value Default value of float (0.0) Infinity Positive infinity NaN Not-a-Number PI Mathematical constant π E Euler's number Prefix operators: + Identity - Change sign Infix operators: + Addition - Subtraction * Multiplication / Division ( A / 0.0 ⇒ Infinity for A > 0.0, A / 0.0 ⇒ -Infinity for A < 0.0, 0.0 / 0.0 ⇒ NaN ) ** Power ( A ** B is okay for A > 0.0, A ** B is okay for A < 0.0 and B is integer, A ** B ⇒ NaN for A < 0.0 and B is not integer, A ** 0.0 ⇒ 1.0, NaN ** 0.0 ⇒ 1.0, NaN ** B ⇒ NaN for B <> 0.0, 0.0 ** B ⇒ 0.0 for B > 0.0, 0.0 ** 0.0 ⇒ 1.0, 0.0 ** B ⇒ Infinity for B < 0.0, (-0.0) ** B ⇒ -Infinity for B < 0.0 and odd(B), 1.0 ** B ⇒ 1.0, 1.0 ** NaN ⇒ 1.0, A ** NaN ⇒ NaN for A <> 1.0 ) ** Power ( Type of right operand: integer A ** B is okay for A > 0.0, A ** B is okay for A < 0.0, A ** 0 ⇒ 1.0, NaN ** 0 ⇒ 1.0, NaN ** B ⇒ NaN for B <> 0, 0.0 ** B ⇒ 0.0 for B > 0, 0.0 ** 0 ⇒ 1.0, 0.0 ** B ⇒ Infinity for B < 0, (-0.0) ** B ⇒ -Infinity for B < 0 and odd(B), A ** B ⇒ 1.0 / A ** (-B) for B < 0 ) A << B Shift left ( Type of argument B: integer A << B ⇒ A * 2.0 ** B, A << 0 ⇒ A, 0.0 << B ⇒ 0.0 ) A >> B Arithmetic shift right ( Type of argument B: integer, A >> B ⇒ A / 2.0 ** B, A >> 0 ⇒ A, 0.0 >> B ⇒ 0.0 ) A ? B : C Ternary operator condition ? thenValue : elseValue ( Type of argument A: boolean, TRUE ? a : b ⇒ a, FALSE ? a : b ⇒ b ) float conv A Conversion of integer to float ( Type of argument A: integer, float conv 1 ⇒ 1.0 ) digits Conversion to string with specified precision ( Type of right operand: integer, Type of result: string, 0.012345 digits 4 ⇒ "0.0123", 1.2468 digits 2 ⇒ "1.25", 0.125 digits 2 ⇒ "0.12", 0.375 digits 2 ⇒ "0.38", Infinity digits A ⇒ "Infinity", -Infinity digits A ⇒ "-Infinity", NaN digits A ⇒ "NaN" ) sci Conversion to a string in scientific notation ( Type of right operand: integer, Type of result: string, 0.012345 sci 4 ⇒ "1.2345e-2", 1.2468 sci 2 ⇒ "1.25e+0", 3.1415 sci 0 ⇒ "3e+0", 0.125 sci 1 ⇒ "1.2e-1", 0.375 sci 1 ⇒ "3.8e-1", Infinity sci 5 ⇒ "Infinity", -Infinity sci 6 ⇒ "-Infinity", NaN sci 7 ⇒ "NaN", -0.004 sci 2 ⇒ "-4.00e-3" ) exp Set the number of exponent digits in a scientific float notation. ( Type of left operand: string, Type of right operand: integer, Type of result: string, 0.012345 sci 4 exp 2 ⇒ "1.2345e-02", 1.2468e15 sci 2 exp 1 ⇒ "1.25e+15", 3.1415 sci 0 exp 3 ⇒ "3e+000", 0.125 sci 1 exp 2 ⇒ "1.2e-01", 0.375 sci 1 exp 2 ⇒ "3.8e-01", Infinity sci 5 exp 2 ⇒ "Infinity", -Infinity sci 6 exp 2 ⇒ "-Infinity", NaN sci 7 exp 2 ⇒ "NaN", -0.004 sci 2 exp 2 ⇒ "-4.00e-03" ) float parse A Conversion of string to float ( Type of argument A: string, float parse "1.2345" ⇒ 1.2345, float parse "1.2345e6" ⇒ 1234500.0, float parse "-1.0e-308" ⇒ -1.0e-308, float parse "1" ⇒ 1.0, float parse "2." ⇒ 2.0, float parse ".5" ⇒ 0.5, float parse "-.25" ⇒ -0.25, float parse "Infinity" ⇒ Infinity, float parse "-Infinity" ⇒ -Infinity, float parse "NaN" ⇒ NaN, float parse "3.14PI" ⇒ EXCEPTION RANGE_ERROR ) Relations: =, <>, <, <=, >, >= Functions: abs(A) Absolute value flt(A) Conversion of integer to float ( Type of argument A: integer, flt(1) ⇒ 1.0 ) float(A) Conversion of integer to float ( Type of argument A: integer, float(1) ⇒ 1.0 ) float(A) Conversion of string to float ( Type of argument A: string, float("1.2345") ⇒ 1.2345, float("1.2345e6") ⇒ 1234500.0, float("-1.0e-308") ⇒ -1.0e-308, float("1") ⇒ 1.0, float("2.") ⇒ 2.0, float(".5") ⇒ 0.5, float("-.25") ⇒ -0.25, float("Infinity") ⇒ Infinity, float("-Infinity") ⇒ -Infinity, float("NaN") ⇒ NaN, float("3.14PI") ⇒ EXCEPTION RANGE_ERROR ) floor(A) Truncation towards negative infinity ( floor( 1.8) ⇒ 1.0, floor( 1.0) ⇒ 1.0, floor(-1.0) ⇒ -1.0, floor(-1.2) ⇒ -2.0, floor( 0.9) ⇒ 0.0, floor(-0.1) ⇒ -1.0 ) ceil(A) Rounding up towards positive infinity ( ceil( 1.2) ⇒ 2.0, ceil( 1.0) ⇒ 1.0, ceil(-1.8) ⇒ -1.0, ceil(-1.0) ⇒ -1.0, ceil( 0.1) ⇒ 1.0, ceil(-0.9) ⇒ 0.0 ) trunc(A) Truncation towards zero ( Type of result: integer, trunc( 1.8) ⇒ 1, trunc( 1.0) ⇒ 1, trunc(-1.8) ⇒ -1, trunc(-1.0) ⇒ -1, trunc( 0.9) ⇒ 0, trunc(-0.9) ⇒ 0 ) round(A) Round towards zero ( Type of result: integer, round(1.5) ⇒ 2, round(-1.5) ⇒ -2, round(0.5) ⇒ 1, round(-0.5) ⇒ -1, round(0.4) ⇒ 0, round(-0.4) ⇒ 0 ) str(A) Conversion to string ( Type of result: string, str(Infinity) ⇒ "Infinity", str(-Infinity) ⇒ "-Infinity", str(NaN) ⇒ "NaN" ) isNaN(A) Check if A is Not-a-Number isNegativeZero(A) Check if A is negative zero (-0.0) isPositiveZero(A) Check if A is +0.0 sin(A) Sine cos(A) Cosine tan(A) Tangent exp(A) Exponential function expm1(A) Compute exp(x) - 1.0 log(A) Natural logarithm ( log(A) is okay for A > 0.0, log(1.0) ⇒ 0.0, log(0.0) ⇒ -Infinity, log(-1.0) ⇒ NaN ) log1p(A) Compute log(1.0 + x) ( log1p(A) is okay for A > -1.0, log1p(0.0) ⇒ 0.0, log1p(-1.0) ⇒ -Infinity, log1p(-2.0) ⇒ NaN ) log10(A) Base 10 logarithm ( log10(A) is okay for A > 0.0, log10(1.0) ⇒ 0.0, log10(0.0) ⇒ -Infinity, log10(-1.0) ⇒ NaN ) log2(A) Base 2 logarithm ( log2(A) is okay for A > 0.0, log2(1.0) ⇒ 0.0, log2(0.0) ⇒ -Infinity, log2(-1.0) ⇒ NaN ) sqrt(A) Square root ( sqrt(A) is okay for A >= 0.0, sqrt(-1.0) ⇒ NaN ) asin(A) Inverse sine ( asin(A) is okay for A >= -1.0 and A <= 1.0, asin(2.0) ⇒ NaN ) acos(A) Inverse cosine ( acos(A) is okay for A >= -1.0 and A <= 1.0, acos(2.0) ⇒ NaN ) atan(A) Inverse tangent atan2(A, B) Inverse tangent of A / B sinh(A) Hyperbolic sine cosh(A) Hyperbolic cosine tanh(A) Hyperbolic tangent rand(A, B) Random number in the range [A, B) The random values are uniform distributed. ( rand(A, B) returns a random number such that A <= rand(A, B) and rand(A, B) < B holds. rand(A, A) ⇒ EXCEPTION RANGE_ERROR, rand(1.0, 0.0) ⇒ EXCEPTION RANGE_ERROR ) min(A, B) Minimum of two numbers. ( min(2.5, 4.5) ⇒ 2.5 ) max(A, B) Maximum of two numbers. ( max(2.5, 4.5) ⇒ 4.5 ) compare(A, B) Compare function ( Type of result: integer, compare(1.9, 2.1) ⇒ -1, compare(5.3, 5.3) ⇒ 0, compare(7.8, 7.7) ⇒ 1 ) hashCode(A) Hash function ( Type of result: integer ) Statements: A +:= B Increment A by B ( A +:= B ⇒ A := A + B ) A -:= B Decrement A by B ( A -:= B ⇒ A := A - B ) A *:= B Multiplying copy ( A *:= B ⇒ A := A * B ) A /:= B Dividing copy ( A /:= B ⇒ A := A / B ) ignore(A) Ignore value5.7 complex
The type complex consists of complex numbers represented with a float real part and a float imaginary part. Complex literals do not exist. The complex functions are defined in the library "complex.s7i".
Elements: var float: re is 0.0; var float: im is 0.0; Constants: complex.value Default value of complex (complex(0.0)) Prefix operators: + Identity - Change sign conj Complex conjugate Infix operators: + Addition - Subtraction * Multiplication / Division ( A / complex(0.0) ⇒ complex(NaN, NaN) ) ** Power ( Type of right operand: integer A ** B is okay for A > complex(0.0), A ** B is okay for A < complex(0.0), A ** 0 ⇒ complex(1.0), complex(0.0) ** B ⇒ complex(0.0) for B > 0, complex(0.0) ** 0 ⇒ complex(1.0), complex(0.0) ** B ⇒ complex(Infinity, NaN) for B < 0 ) A ? B : C Ternary operator condition ? thenValue : elseValue ( Type of argument A: boolean, TRUE ? a : b ⇒ a, FALSE ? a : b ⇒ b ) complex conv A Conversion of integer to complex ( Type of argument A: integer, complex conv A ⇒ complex(flt(A)) ) complex conv A Conversion of float to complex ( Type of argument A: float, complex conv A ⇒ complex(A) ) digits Conversion to string with specified precision ( Type of right operand: integer, Type of result: string, complex(3.1415) digits 2 ⇒ "3.14+0.00i" ) sci Conversion to a string in scientific notation ( Type of right operand: integer, Type of result: string, complex(3.1415) sci 2 ⇒ "3.14e+0+0.00e+0i" ) complex parse A Conversion of string to complex ( Type of argument A: string ) Relations: =, <> Functions: abs(A) Absolute value ( Type of result: float ) sqrAbs(A) Square of absolute value ( Type of result: float ) arg(A) Argument (=angle of the polar form of A) ( Type of result: float ) complex(A, B) Return a complex number from its real and imaginary part ( Type of argument A: float, Type of argument B: float ) complex(A) Return a complex number from its real part ( Type of argument A: float ) complex(A) Return a complex number from its real part ( Type of argument A: integer ) polar(A, B) Return a complex number from polar coordinates ( Type of argument A: float, Type of argument B: float ) str(A) Conversion to string ( Type of result: string, str(complex(1.125)) ⇒ "1.125+0.0i" ) compare(A, B) Compare function ( Type of result: integer ) hashCode(A) Hash function ( Type of result: integer ) Statements: A +:= B Increment A by B ( A +:= B ⇒ A := A + B ) A -:= B Decrement A by B ( A -:= B ⇒ A := A - B ) A *:= B Multiplying copy ( A *:= B ⇒ A := A * B ) A /:= B Dividing copy ( A /:= B ⇒ A := A / B ) ignore(A) Ignore value5.8 char
The type char describes Unicode characters encoded with UTF-32. In the source file a character literal is written as UTF-8 encoded Unicode character enclosed in single quotes. In order to represent non-printable characters and certain printable characters the following escape sequences may be used.
audible alert BEL \a backspace BS \b escape ESC \e formfeed FF \f newline NL (LF) \n carriage return CR \r horizontal tab HT \t vertical tab VT \v backslash (\) \\ apostrophe (') \' double quote (") \" control-A \A ... control-Z \Z Additionally the following escape sequence can be used:
- A backslash followed by an integer literal and a semicolon is interpreted as character with the specified ordinal number. Note that the integer literal is interpreted decimal unless it is written as based integer.
Examples of character literals are:
'a' ' ' '\n' '!' '\\' '2' '"' '\"' '\'' '\8;'To use characters beyond ASCII (which is a subset of Unicode) in the source file make sure that the editor uses UTF-8 encoded characters. The char functions are defined in the library "char.s7i".
Constants: char.value Default value of char (' ') Infix operators: A ? B : C Ternary operator condition ? thenValue : elseValue ( Type of argument A: boolean, TRUE ? a : b ⇒ a, FALSE ? a : b ⇒ b ) char conv A Conversion of integer to char ( Type of argument A: integer, char conv 65 ⇒ 'A' ) char parse A Conversion of string to char ( Type of argument A: string ) Relations: =, <>, <, <=, >, >= Functions: ord(A) Ordinal number ( Type of result: integer ) integer(A) Ordinal number ( Type of result: integer ) chr(A) Conversion of integer to char ( Type of argument: integer ) char(A) Conversion of integer to char ( Type of argument: integer ) char(A) Conversion of string to char ( Type of argument A: string ) succ(A) Successor ( succ(A) ⇒ chr(succ(ord(A))) ) pred(A) Predecessor ( pred(A) ⇒ chr(pred(ord(A))) ) str(A) Conversion to string ( Type of result: string, str('A') ⇒ "A" ) literal(A) Conversion to a literal ( Type of result: string, literal('A') ⇒ "'A'" ) upper(A) Conversion to upper case character ( upper('A') ⇒ 'A', upper('z') ⇒ 'Z' ) lower(A) Conversion to lower case character ( lower('A') ⇒ 'a', lower('z') ⇒ 'z' ) isLetter Is it an alphabetic Unicode character ( isLetter('A') ⇒ TRUE, isLetter('\16#4e2d;') ⇒ TRUE, isLetter('4') ⇒ FALSE, isLetter('+') ⇒ FALSE, isLetter('\t') ⇒ FALSE, isLetter(KEY_LEFT) ⇒ FALSE, isLetter(EOF) ⇒ FALSE ) width Number of screen columns occupied by a Unicode character ( width('\n') ⇒ 0, width('\t') ⇒ 0, width(KEY_LEFT) ⇒ 0, width(EOF) ⇒ 0 ) width('A') ⇒ 1, width('\16#4e2d;') ⇒ 2 ) rand(A, B) Random character in the range [A, B] The random values are uniform distributed. ( rand(A, B) returns a random character such that A <= rand(A, B) and rand(A, B) <= B holds. rand(A, A) ⇒ A, rand('B', 'A') ⇒ EXCEPTION RANGE_ERROR ) compare(A, B) Compare function ( Type of result: integer, compare('A', 'B') ⇒ -1, compare('A', 'A') ⇒ 0, compare('B', 'A') ⇒ 1 ) hashCode(A) Hash function ( Type of result: integer ) Statements: incr(A) Increment ( incr(A) ⇒ A := succ(A) ) decr(A) Decrement ( decr(A) ⇒ A := pred(A) ) ignore(A) Ignore value5.9 string
The type string describes sequences of Unicode characters (including the empty string). The characters in the string use the UTF-32 encoding. Strings are not '\0;' terminated. Therefore they can also contain binary data. Although strings are allowed to grow very big, it can happen that there is not enough memory to represent a string value. In this case the exception MEMORY_ERROR is raised. In the source file a string literal is a sequence of UTF-8 encoded Unicode characters surrounded by double quotes.
To represent control characters and certain other characters in strings the same escape sequences as for character literals may be used. E.g.: Quotation characters (") inside strings can be represented by preceding them with a backslash ( \" ). Additionally there is the following possibility:
- Two backslashes with a sequence of blanks, horizontal tabs, carriage returns and new lines between them are completely ignored. The ignored characters are not part of the string. This can be used to continue a string in the following line. Note that in this case the leading spaces in the new line are not part of the string. Although this possibility exists also for character literals it is mentioned here, since it makes more sense to use it with string literals
Examples of string literals are:
"" " " "\"" "'" "Gold" "A\"B !" "Euro: \8364;" "CRLF\r\n"To use characters beyond ASCII (which is a subset of Unicode) in the source file make sure that the editor uses UTF-8 encoded characters. The string functions are defined in the library "string.s7i".
Constants: string.value Default value of string ("") Infix operators: & String concatenation ( "All " & "OK" ⇒ "All OK" ) <& String concatenation with weak priority Overloaded for various types with enable_output or enable_io ( write("i=" <& i digits 2 lpad 6 <& " $"); ) mult String multiplication ( Type of right operand: integer, "LA" mult 3 ⇒ "LALALA", "WORD" mult 0 ⇒ "", "ANY" mult -1 ⇒ EXCEPTION RANGE_ERROR ) A ? B : C Ternary operator condition ? thenValue : elseValue ( Type of argument A: boolean, TRUE ? a : b ⇒ a, FALSE ? a : b ⇒ b ) lpad Left padding with spaces ( Type of right operand: integer, "HELLO" lpad 8 ⇒ " HELLO", "HELLO" lpad 6 ⇒ " HELLO", "HELLO" lpad 5 ⇒ "HELLO", "HELLO" lpad 4 ⇒ "HELLO", "HELLO" lpad 0 ⇒ "HELLO", "HELLO" lpad -8 ⇒ "HELLO" ) lpad0 Left padding with zeroes ( Type of right operand: integer, "12" lpad0 5 ⇒ "00012", "12" lpad0 3 ⇒ "012", "12" lpad0 2 ⇒ "12", "12" lpad0 1 ⇒ "12", "12" lpad0 0 ⇒ "12", "12" lpad0 -5 ⇒ "12" ) rpad Right padding with spaces ( Type of right operand: integer, "HELLO" rpad 8 ⇒ "HELLO ", "HELLO" rpad 6 ⇒ "HELLO ", "HELLO" rpad 5 ⇒ "HELLO", "HELLO" rpad 4 ⇒ "HELLO", "HELLO" rpad 0 ⇒ "HELLO", "HELLO" rpad -8 ⇒ "HELLO" ) string parse A Identity Indices: [ A ] Access one character ( Type of argument A: integer, Type of result: char, "abcde"[1] ⇒ 'a', "abcde"[5] ⇒ 'e', "abcde"[0] ⇒ EXCEPTION INDEX_ERROR, "abcde"[6] ⇒ EXCEPTION INDEX_ERROR ) [ A .. B ] Access a substring from position A to B ( Type of arguments A and B: integer, S[A .. B] is okay for A >= 1 and B >= pred(A), "abcde"[2 .. 4] ⇒ "bcd", "abcde"[2 .. 7] ⇒ "bcde", "abcde"[4 .. 3] ⇒ "", "abcde"[4 .. 2] ⇒ EXCEPTION INDEX_ERROR, "abcde"[6 .. 8] ⇒ "", "abcde"[1 .. 3] ⇒ "abc", "abcde"[0 .. 3] ⇒ EXCEPTION INDEX_ERROR, "abcde"[1 .. 0] ⇒ "", "abcde"[1 .. -1] ⇒ EXCEPTION INDEX_ERROR ) [ A len B ] Access a substring from position A with length B ( Type of arguments A and B: integer, S[A len B] is okay for A >= 1 and B >= 0, "abcde"[2 len 3] ⇒ "bcd", "abcde"[2 len 5] ⇒ "bcde", "abcde"[3 len 0] ⇒ "", "abcde"[6 len 2] ⇒ "", "abcde"[3 len -1] ⇒ EXCEPTION INDEX_ERROR, "abcde"[1 len 2] ⇒ "ab", "abcde"[0 len 2] ⇒ EXCEPTION INDEX_ERROR ) [ A fixLen B ] Access a substring from position A with guaranteed length B ( Type of arguments A and B: integer, S[A fixLen B] is okay for A >= 1 and A <= length(S) and B >= 0 and pred(A + B) <= length(S), "abcde"[2 fixLen 3] ⇒ "bcd", "abcde"[2 fixLen 5] ⇒ EXCEPTION INDEX_ERROR, "abcde"[3 fixLen 0] ⇒ "", "abcde"[6 fixLen 2] ⇒ EXCEPTION INDEX_ERROR, "abcde"[3 fixLen -1] ⇒ EXCEPTION INDEX_ERROR, "abcde"[1 fixLen 2] ⇒ "ab", "abcde"[0 fixLen 2] ⇒ EXCEPTION INDEX_ERROR ) [ A .. ] Access a substring beginning at position A ( Type of argument A: integer, S[A ..] is okay for A >= 1, "abcde"[3 ..] ⇒ "cde", "abcde"[6 ..] ⇒ "", ""[1 ..] ⇒ "", "abcde"[1 ..] ⇒ "abcde", "abcde"[0 ..] ⇒ EXCEPTION INDEX_ERROR ) [ .. A ] Access a substring ending at position A ( Type of argument A: integer, S[.. A] is okay for A >= 0, "abcde"[.. 4] ⇒ "abcd", "abcde"[.. 6] ⇒ "abcde", ""[.. 5] ⇒ "", "abcde"[.. 0] ⇒ "", "abcde"[.. -1] ⇒ EXCEPTION INDEX_ERROR ) Relations: =, <>, <, <=, >, >= Functions: length(A) Length of string ( Type of result: integer, length("") ⇒ 0 ) pos(A,B) First position of char B in string A ( Type of argument B: char, Type of result: integer, pos("ABCABC",'B') ⇒ 2, pos("XYZ",'A') ⇒ 0 ) pos(A,B) First position of string B in string A ( Type of result: integer, pos("ABCDE ABCDE","BC") ⇒ 2, pos("XYZXYZ","ZYX") ⇒ 0, pos("123456789","") ⇒ 0 ) pos(A,B,C) First position of char B in string A The search starts at position C of string A ( Type of argument B: char, Type of argument C: integer, Type of result: integer, pos("ABCABC",'B', 3) ⇒ 5, pos("XYZYX",'Z', 4) ⇒ 0, pos("12345",'3', 7) ⇒ 0 ) pos(A,B,C) First position of string B in string A The search starts at position C of string A ( Type of argument C: integer, Type of result: integer, pos("ABCDE ABCDE","BC", 3) ⇒ 8, pos("XYZXYZ","ZXY", 4) ⇒ 0, pos("12345","34", 7) ⇒ 0 ) pos("123456789","", 2) ⇒ 0 ) rpos(A,B) Last position of char B in string A ( Type of argument B: char, Type of result: integer, rpos("ABCABC",'B') ⇒ 5, rpos("XYZ",'A') ⇒ 0 ) rpos(A,B) Last position of string B in string A ( Type of result: integer, rpos("ABCDE ABCDE","BC") ⇒ 8, rpos("XYZXYZ","ZYX") ⇒ 0, rpos("123456789","") ⇒ 0 ) rpos(A,B,C) Last position of char B in string A The search starts at position C of string A ( Type of argument B: char, Type of argument C: integer, Type of result: integer, rpos("ABCABC",'B', 4) ⇒ 2, rpos("XYZYX",'Z', 2) ⇒ 0, rpos("12345",'3', 5) ⇒ 3 ) rpos(A,B,C) Last position of char B in string A The search starts at position C of string A ( Type of argument C: integer, Type of result: integer, rpos("ABCABC","BC", 4) ⇒ 2, rpos("XYZYX","ZY", 2) ⇒ 0, rpos("12345","34", 5) ⇒ 3 ) startsWith(A,B) Determine if a string starts with a prefix. ( Type of result: boolean, startsWith("tmp_s7c.c", "tmp_") ⇒ TRUE, startsWith("example", "E") ⇒ FALSE ) endsWith(A,B) Determine if a string ends with a suffix. ( Type of result: boolean, endsWith("hello.sd7", ".sd7") ⇒ TRUE, endsWith("A string", "\0;") ⇒ FALSE ) equalAtIndex(A,B,C) Check if A has the searched characters B starting from C. ( Type of result: boolean, equalAtIndex("The quick brown fox", "quick", 5) ⇒ TRUE, equalAtIndex("axis", "xi", 3) ⇒ FALSE ) replace(A,B,C) Search A for occurrences of B and replace them with C ( replace("old gold", "old", "one") ⇒ "one gone" ) replace2(A,B,C,D) Search A for occurrences of B followed by C and replace them with D. ( replace2("x := (*ord*) y;", "(*", "*)", "") ⇒ "x := y;" ) split(A,B) Split A into strings delimited by B ( Type of argument B: char, Type of result: array string, split("", ':') ⇒ [](""), split(":", ':') ⇒ []("", ""), split("15:30", ':') ⇒ []("15", "30") ) split(A,B) Split A into strings delimited by B ( Type of result: array string, split("", "") ⇒ [](""), split("ABC", "") ⇒ []("ABC"), split("", "; ") ⇒ [](""), split("writeln; readln;", "; ") ⇒ []("writeln", "readln;") ) join(A,B) Join the elements of A together with B's between them ( Type of argument A: array string, Type of argument B: char, join([]("This", "is", "a", "test"), ' ') ⇒ "This is a test" ) join(A,B) Join the elements of A together with B's between them ( Type of argument A: array string, Type of argument B: string, join([]("pro", "gram"), "") ⇒ "program" ) trim(A) Removes leading and trailing spaces and control chars ( trim(" /n xyz /r") ⇒ "xyz" ) ltrim(A) Removes leading spaces and control chars ( ltrim(" /n xyz /r") ⇒ "xyz /r" ) rtrim(A) Removes trailing spaces and control chars ( rtrim(" /n xyz /r") ⇒ " /n xyz" ) str(A) Conversion to string ( str(A) ⇒ A ) literal(A) Conversion to a literal ( literal("ABC") ⇒ "\"ABC\"", literal("O' \"X\"") ⇒ "\"O\' \\\"X\\\"\"" ) upper(A) Conversion to upper case characters ( upper("Upper") ⇒ "UPPER" ) lower(A) Conversion to lower case characters ( lower("Lower") ⇒ "lower" ) compare(A, B) Compare function ( Type of result: integer, compare("ABC", "ABCD") ⇒ -1, compare("ABC", "ABC") ⇒ 0, compare("ABCD", "ABCC") ⇒ 1 ) hashCode(A) Hash function ( Type of result: integer ) Statements: A &:= B Append B to A ( A &:= B ⇒ A := A & B ) A &:= B Append B to A ( Type of argument B: char, A &:= B ⇒ A := A & str(B) ) A @:= [B] C Assign C to element B of string A ( Type of argument B: integer, Type of argument C: char, A @:= [B] C ⇒ A := A[..pred(B)] & str(C) & A[succ(B)..], A @:= [0] 'x' ⇒ EXCEPTION INDEX_ERROR, A @:= [succ(length(A))] 'x' ⇒ EXCEPTION INDEX_ERROR ) A @:= [B] C Assign C to the position B of string A ( Type of argument B: integer, A @:= [B] C ⇒ A := A[..pred(B)] & C & A[B+length(C)..], A @:= [0] "xyz" ⇒ EXCEPTION INDEX_ERROR, A @:= [pred(length(A))] "xyz" ⇒ EXCEPTION INDEX_ERROR ) ignore(A) Ignore value for forVar range aString do statements end for Loop over all elements of a string ( Type of argument forVar: char, Type of argument statements: proc ) for key keyVar range aString do statements end for Loop over all indices of a string ( Type of argument keyVar: integer, Type of argument statements: proc ) for forVar key keyVar range aString do statements end for Loop over all elements and indices of a string ( Type of argument forVar: char, Type of argument keyVar: integer, Type of argument statements: proc ) for forVar range aString until condition do statements end for Loop over all elements of a string until condition is TRUE Check the condition before the statements in the loop body are executed. ( Type of argument forVar: char, Type of argument condition: boolean, Type of argument statements: proc ) for key keyVar range aString until condition do statements end for Loop over all indices of a string until condition is TRUE Check the condition before the statements in the loop body are executed. ( Type of argument keyVar: integer, Type of argument condition: boolean, Type of argument statements: proc ) for forVar key keyVar range aString until condition do statements end for Loop over all elements and indices of a string until condition is TRUE Check the condition before the statements in the loop body are executed. ( Type of argument forVar: char, Type of argument keyVar: integer, Type of argument condition: boolean, Type of argument statements: proc )5.10 array
The type array baseType describes sequences of baseType elements (including the empty sequence). Examples of array type declarations are:
const type: striArrayType is array string; const type: structArrayType is array aStructType;This defines striArrayType as an array type with string elements. The second line defines structArrayType as an array type with aStructType elements. Variables of these types are declared with:
var striArrayType: striArr1 is striArrayType.value; # Empty array with starting index 1. var striArrayType: striArr2 is 0 times ""; # Empty array with starting index 1. var striArrayType: striArr4 is [0 .. -1] times ""; # Empty array with starting index 0. var striArrayType: striArr3 is [0 len 0] times ""; # Empty array with starting index 0. var striArrayType: striArr5 is [] ("one", "two"); # Array with two string elements and starting index 1. var striArrayType: striArr6 is [0] ("zero", "one"); # Array with two string elements and starting index 0. var structArrayType: structArr1 is structArrayType.value; var structArrayType: structArr2 is 10 times aStructType.value; var structArrayType: structArr3 is [42 .. 365] times aStructType.value;An element of an array can be accessed with an integer index. The minimum and maximum indices of an array are part of the value and can be obtained with the functions minIdx and maxIdx. There are functions which generate arrays with the default minimum index of 1 and other functions which generate arrays with the minimum index taken from a parameter. The array functions are defined in the library "array.s7i".
Arrays with non-integer index are defined in the library "idxarray.s7i". An array type with char index and bigInteger elements is defined as:
const type: charIndexArray is array [char] bigInteger;Variables of this type are declared with:
var charIndexArray: bigArr1 is charIndexArray.value; var charIndexArray: bigArr2 is char times 42_; var charIndexArray: bigArr3 is [char] (0_, 1_, 2_); var charIndexArray: bigArr4 is [' '] (32_, 33_, 34_);The definition of charIndexArray defines also the special times operator from above and the special possibilities to define literals of charIndexArray.
Literal: [] (elem1, elem2) Create an array with the given elements. Index type is integer and starting index is 1. [0] (elem1, elem2) Create an array with the given elements. Index type is integer and starting index is 0. [char] (elem1, elem2) Create an array with the given elements. Index type is char and starting index is char.value (' '). ['A'] (elem1, elem2) Create an array with the given elements. Index type is char and starting index is 'A'. Infix operators: & Array concatenation times Array generation ( Left operand: integer, Right operand: baseType, A times B Generates an array baseType with A elements of B, 3 times B ⇒ [] (B, B, B), 0 times B ⇒ empty array with starting index 1, (1 times B)[1] ⇒ B, (0 times B)[1] ⇒ EXCEPTION INDEX_ERROR, -1 times B ⇒ EXCEPTION RANGE_ERROR ) [ A .. B ] times C Array generation ( Type of arguments A and B: integer, Type of argument C: baseType, [ A .. B ] times C Generates an array baseType with pred(B - A) elements of C, [ -1 .. -2 ] times B ⇒ empty array with starting index -1, [ -1 .. -3 ] times B ⇒ EXCEPTION RANGE_ERROR ) [ A len L ] times C Array generation ( Type of arguments A and L: integer, Type of argument C: baseType, [ A len L ] times C Generates an array baseType with L elements of C, [ -1 len 0 ] times B ⇒ empty array with starting index -1, [ -1 len -1 ] times B ⇒ EXCEPTION RANGE_ERROR ) indexType times A Array generation for indices from indexType.first to indexType.last. ( Type of argument A: baseType, boolean times 5 ⇒ [FALSE] (5, 5) ) Indices: [ A ] Access one array element ( Type of argument A: integer, Type of result: baseType, A[minIdx(A)] ⇒ First element, A[maxIdx(A)] ⇒ Last element, A[pred(minIdx(A))] ⇒ EXCEPTION INDEX_ERROR, A[succ(maxIdx(A))] ⇒ EXCEPTION INDEX_ERROR ) [ A .. B ] Get a sub array from the position A to the position B ( Type of arguments A and B: integer, X[A .. B] is okay for A >= minIdx(X) and B >= pred(A), anArray[pred(minIdx(anArray)) .. n] ⇒ EXCEPTION INDEX_ERROR, anArray[n .. n - 2] ⇒ EXCEPTION INDEX_ERROR ) [ A len B ] Get a sub array from the position A with maximum length B ( Type of arguments A and B: integer, X[A len B] is okay for A >= minIdx(X) and B >= 0, anArray[pred(minIdx(anArray)) len n] ⇒ EXCEPTION INDEX_ERROR, anArray[n len -1] ⇒ EXCEPTION INDEX_ERROR ) [ A .. ] Get a sub array beginning at position A ( Type of argument A: integer, X[A ..] is okay for A >= minIdx(X), anArray[pred(minIdx(anArray)) ..] ⇒ EXCEPTION INDEX_ERROR ) [ .. A ] Get a sub array ending at position A ( Type of argument A: integer, X[.. A] is okay for A >= pred(minIdx(X)), anArray[.. minIdx(anArray) - 2] ⇒ EXCEPTION INDEX_ERROR ) Relations: =, <> Functions: length(A) Length of array ( Type of result: integer, length(A) = succ(maxIdx(A) - minIdx(A)), length([] (2, 3, 5)) ⇒ 3, length([0] (2, 3, 5)) ⇒ 3, length([2] (2, 3, 5)) ⇒ 3, length(['a'] (1, 2, 3)) ⇒ 3 length(0 times TRUE) ⇒ 0, length(5 times TRUE) ⇒ 5 ) minIdx(A) Minimum index of array ( Type of result: integer, minIdx([] (2, 3, 5)) ⇒ 1, minIdx([0] (2, 3, 5)) ⇒ 0, minIdx([2] (2, 3, 5)) ⇒ 2, minIdx(['a'] (1, 2, 3)) ⇒ 'a', minIdx(3 times TRUE) ⇒ 1, minIdx([-1 .. 4] times TRUE) ⇒ -1 ) maxIdx(A) Maximum index of array ( Type of result: integer, maxIdx([] (2, 3, 5)) ⇒ 3, maxIdx([0] (2, 3, 5)) ⇒ 2, maxIdx([2] (2, 3, 5)) ⇒ 4, maxIdx(['a'] (1, 2, 3)) ⇒ 'c', maxIdx(3 times TRUE) ⇒ 3, maxIdx([-1 .. 4] times TRUE) ⇒ 4 ) rand(A) Random element from an array The random elements are uniform distributed. ( Type of result: baseType ) remove(A,B) Remove element with index B from array A and return the removed element ( Type of argument B: integer, Type of result: baseType, remove(A,B) is okay for B >= minIdx(A) and B <= maxIdx(A), remove(anArray, 0) ⇒ EXCEPTION INDEX_ERROR for minIdx(anArray) = 1, remove(anArray, 5) ⇒ EXCEPTION INDEX_ERROR for maxIdx(anArray) = 4 ) remove(A,B,C) Remove the sub-array with with index B and length C from array A and return the removed sub-array ( Type of argument B: integer, Type of argument C: integer, remove(A,B,C) is okay for B >= minIdx(A) and B <= maxIdx(A) and C >= 0, remove(anArray, 0, 1) ⇒ EXCEPTION INDEX_ERROR for minIdx(anArray) = 1, remove(anArray, 6, 1) ⇒ EXCEPTION INDEX_ERROR for maxIdx(anArray) = 4, remove(anArray, 1, -1) ⇒ EXCEPTION INDEX_ERROR ) sort(A) Sort array using the compare(baseType, baseType) function Statements: A &:= B Append B to A ( A &:= B ⇒ A := A & B ) A &:= B Append element B to A ( Type of argument B: baseType, A &:= B ⇒ A := A & [] (B) ) insert(A,B,C) Insert element C into array A at index B ( Type of argument B: integer, Type of argument C: baseType, insert(A,B,C) is okay for B >= minIdx(A) and B <= succ(maxIdx(A)), insert(anArray, 0, anElement) ⇒ EXCEPTION INDEX_ERROR for minIdx(anArray) = 1, insert(anArray, 6, anElement) ⇒ EXCEPTION INDEX_ERROR for maxIdx(anArray) = 4 ) insert(A,B,C) Insert array C into array A at index B ( Type of argument B: integer, insert(A,B,C) is okay for B >= minIdx(A) and B <= succ(maxIdx(A)), insert(anArray, 0, anotherAnarry) ⇒ EXCEPTION INDEX_ERROR for minIdx(anArray) = 1, insert(anArray, 6, anotherAnarry) ⇒ EXCEPTION INDEX_ERROR for maxIdx(anArray) = 4 ) insert(A, B) Insert B into the sorted array A ( Type of argument B: baseType ) ignore(A) Ignore value for forVar range anArray do statements end for Loop over all elements of an array ( Type of argument forVar: baseType, Type of argument statements: proc ) for key keyVar range anArray do statements end for Loop over all indices of an array ( Type of argument keyVar: indexType, Type of argument statements: proc ) for forVar key keyVar range anArray do statements end for Loop over all elements and indices of an array ( Type of argument forVar: baseType, Type of argument keyVar: indexType, Type of argument statements: proc ) for forVar range anArray until condition do statements end for Loop over all elements of an array until condition is TRUE Check the condition before the statements in the loop body are executed. ( Type of argument forVar: baseType, Type of argument condition: boolean, Type of argument statements: proc ) for key keyVar range anArray until condition do statements end for Loop over all indices of an array until condition is TRUE Check the condition before the statements in the loop body are executed. ( Type of argument keyVar: indexType, Type of argument condition: boolean, Type of argument statements: proc ) for forVar key keyVar range anArray until condition do statements end for Loop over all elements and indices of an array until condition is TRUE Check the condition before the statements in the loop body are executed. ( Type of argument forVar: baseType, Type of argument keyVar: indexType, Type of argument condition: boolean, Type of argument statements: proc )5.11 hash
The type hash [keyType] baseType describes hash tables with elements of baseType. The elements can be accessed with an index of keyType. An example of a hash type declaration is:
const type: aHashType is hash [string] integer;This defines aHashType as a hash type with integer elements and string keys. Variables of this type are declared with:
var aHashType: aHashTable1 is aHashType.value; # Empty hash table. var aHashType: aHashTable2 is [] (["one" : 1], ["two" : 2]); # Hash with two elements which map strings to integers.The expressions aHashType.value and aHashType.EMPTY_HASH describe empty hash tables. Beside them there are no hash table literals. The keyType of a hash needs to provide the functions hashCode and compare. Besides this the keyType can be any type. The hash functions are defined in the library "hash.s7i".
Literal: [] ([key1 : value1], [key2 : value2]) Create a hash with the given keys and corresponding values. Constants: hashType.EMPTY_HASH Empty hash table Infix operators: in Element ( Left argument: baseType, Type of result: boolean ) not in Is not Element ( Left argument: baseType, Type of result: boolean ) Indices: [ A ] Access one hash table element ( Type of argument A: keyType, Type of result: baseType ) Relations: =, <> Functions: length(A) Number of elements in hash table A ( Type of result: integer, length(hashType.EMPTY_HASH) ⇒ 0 ) keys(A) Unsorted array of keys from hash table A ( Type of result: array keyType ) values(A) Unsorted array of values from hash table A ( Type of result: array baseType ) flip(A) Deliver a hash with keys and values flipped ( Type of result: hash [baseType] array keyType ) Statements: incl(A,B,C) Include element B to hash table A ( Type of argument B: keyType, Type of argument C: baseType ) excl(A,B) Exclude element B from hash table A ( Type of argument B: keyType ) A @:= [B] C Assign C to element B of hash table A ( Type of argument B: keyType, Type of argument C: baseType ) ignore(A) Ignore value for forVar range aHash do statements end for Unsorted loop over all values of a hash ( Type of argument forVar: baseType, Type of argument statements: proc ) for key keyVar range aHash do statements end for Unsorted loop over all keys of a hash ( Type of argument keyVar: keyType, Type of argument statements: proc ) for forVar key keyVar range aHash do statements end for Unsorted loop over all values and keys of a hash ( Type of argument forVar: baseType, Type of argument keyVar: keyType, Type of argument statements: proc )5.12 set
The type set of baseType describes a set of elements of a baseType. (including the empty set). An example of a set type declaration is:
const type: aSetType is set of integer;This defines aSetType as a set type with integer elements. Variables of this type are declared with:
var aSetType: aSet is aSetType.value; var aSetType: aSet is {1, 2, 3}; var aSetType: aSet is {1 .. 5};The type set of baseType is defined in the library "set.s7i". This abstract data type decides about the implementation of the set. When baseType values can be mapped to integer with the ord function and ord does never raise an exception the set is implemented as bitset(baseType) (defined in the library "bitsetof.s7i"), otherwise the set is implemented as hashset(baseType) (defined in the library "hashsetof.s7i"). The type set of integer is an alternate name for bitset, which is defined in the library "bitset.s7i".
Constants: {} Empty set of the type bitset EMPTY_SET Empty set of the type bitset {1, 2} Set with 1 and 2 (type: bitset) {'a', 'b', 'c'} Set with three characters. {"black", "white"} Set with two strings. bitset.value Default value of bitset ({}) setType.EMPTY_SET Empty set of the type setType setType.value Default value of setType (setType.EMPTY_SET) Infix operators: | Union ( {1, 2} | {1, 3} ⇒ {1, 2, 3}, {'a', 'b'} | {'a', 'c'} ⇒ {'a', 'b', 'c'}, {"one", "two"} | {"one", "three"} ⇒ {"one", "two", "three"} ) & Intersection ( {1, 2} & {1, 3} ⇒ {1}, {'a', 'b'} & {'a', 'c'} ⇒ {'a'}, {"one", "two"} & {"one", "three"} ⇒ {"one"} ) - Difference ( {1, 2} - {1, 3} ⇒ {2}, {'a', 'b'} - {'a', 'c'} ⇒ {'b'}, {"one", "two"} - {"one", "three"} ⇒ {"two"} ) >< Symmetric Difference ( {1, 2} >< {1, 3} ⇒ {2, 3}, {'a', 'b'} >< {'a', 'c'} ⇒ {'b', 'c'}, {"one", "two"} >< {"one", "three"} ⇒ {"two", "three"} ) in Element ( Left argument: baseType, Type of result: boolean, 2 in {2, 3, 5, 7} ⇒ TRUE, 4 in {2, 3, 5, 7} ⇒ FALSE, 'a' in {'a', 'c', 'd'} ⇒ TRUE, 'b' in {'a', 'c', 'd'} ⇒ FALSE, "one" in {"one", "three"}) ⇒ TRUE, "two" in {"one", "three"}) ⇒ FALSE ) not in Is not Element ( Left argument: baseType, Type of result: boolean, 2 not in {2, 3, 5, 7} ⇒ FALSE, 4 not in {2, 3, 5, 7} ⇒ TRUE, 'a' not in {'a', 'c', 'd'} ⇒ FALSE, 'b' not in {'a', 'c', 'd'} ⇒ TRUE, "one" not in {"one", "three"}) ⇒ FALSE, "two" not in {"one", "three"}) ⇒ TRUE ) Relations: =, <> Equal and not equal ( Type of result: boolean ) <= Subset ( Type of result: boolean, A <= B ⇒ TRUE when no element X exists for which X in A and X not in B holds. A <= B ⇒ FALSE when an element X exists for which X in A and X not in B holds. setType.EMPTY_SET <= A ⇒ TRUE, A <= setType.EMPTY_SET ⇒ FALSE for A <> EMPTY_SET, A <= B ⇒ B >= A ) < Proper subset ( Type of result: boolean, A < B ⇒ A <= B and A <> B, setType.EMPTY_SET < A ⇒ TRUE for A <> EMPTY_SET, A < setType.EMPTY_SET ⇒ FALSE, A < B ⇒ B > A ) >= Superset ( Type of result: boolean, A >= B ⇒ TRUE when no element X exists for which X in B and X not in A holds. A >= B ⇒ FALSE when an element X exists for which X in B and X not in A holds. A >= setType.EMPTY_SET ⇒ TRUE, setType.EMPTY_SET >= A ⇒ FALSE for A <> EMPTY_SET, A >= B ⇒ B <= A ) > Proper superset ( Type of result: boolean, A > B ⇒ A >= B and A <> B, A > setType.EMPTY_SET ⇒ TRUE for A <> EMPTY_SET, setType.EMPTY_SET > A ⇒ FALSE, A > B ⇒ B < A ) Functions: bitset(A) Convert an integer number to a bitset ( Type of argument A: integer, bitset(2220) ⇒ {2, 3, 5, 7, 11} ) bitset(A) Convert a string to a bitset ( Type of argumant A: string, bitset("{}") ⇒ {}, bitset("{2, 3, 5, 7}") ⇒ {2, 3, 5, 7} ) integer(A) Convert a bitset to an integer ( Type of result: integer, integer({2, 3, 5, 7, 11}) ⇒ 2220 ) card(A) Cardinality of a set ( Type of result: integer, card({2, 3, 5, 7, 11}) ⇒ 5, card({'a', 'b', 'c'}) ⇒ 3, card({"one", "two", "three"}) ⇒ 3 card(setType.EMPTY_SET) ⇒ 0 ) min(A) Minimum element ( Type of result: baseType, Delivers the element from the set for which the following condition holds: Element <= X for all X which are in the set. min({2, 3, 5, 7, 11}) ⇒ 2, min({'a', 'b', 'c'}) ⇒ 'a', min(setType.EMPTY_SET) ⇒ EXCEPTION RANGE_ERROR ) max(A) Maximum element ( Type of result: baseType, Delivers the element from the set for which the following condition holds: Element >= X for all X which are in the set. max({2, 3, 5, 7, 11}) ⇒ 11, max({'a', 'b', 'c'}) ⇒ 'c', max(setType.EMPTY_SET) ⇒ EXCEPTION RANGE_ERROR ) next(A, B) Minimum element of set A that is larger than B ( Type of argument B: baseType, Type of result: baseType, next({2, 3, 5, 7, 11}, 2) ⇒ 3, next({2, 3, 5, 7, 11}, 3) ⇒ 5, next({2, 3, 5, 7, 11}, 7) ⇒ 11, next({2, 3, 5, 7, 11}, 11) ⇒ EXCEPTION RANGE_ERROR, next({}, 1) ⇒ EXCEPTION RANGE_ERROR, next(A, max(A)) ⇒ EXCEPTION RANGE_ERROR ) str(A) Conversion to string ( Type of result: string, str(setType.EMPTY_SET) ⇒ "{}", str({}) ⇒ "{}", str({1, 2}) ⇒ "{1, 2}" ) rand(A) Random element from a set The random elements are uniform distributed. ( Type of result: baseType, rand(setType.EMPTY_SET) ⇒ EXCEPTION RANGE_ERROR ) compare(A, B) Compare function ( Type of result: integer ) hashCode(A) Hash function ( Type of result: integer ) toArray(A) Obtain an array containing all the values in A ( Type of result: array baseType, toArray({2, 3, 5}) ⇒ [](2, 3, 5), toArray({'a', 'b', 'c'}) ⇒ []('a', 'b', 'c') ) Statements: A |:= B Assign the union of A and B to A A &:= B Assign the intersection of A and B to A A -:= B Assign the difference of A and B to A A @:= [B] C Add or remove B to respectively from A ( Type of argument B: baseType, Type of argument C: boolean, A @:= [B] TRUE ⇒ incl(A,B), A @:= [B] FALSE ⇒ excl(A,B) ) incl(A,B) Include element B to set A ( Type of argument B: baseType ) excl(A,B) Exclude element B from set A ( Type of argument B: baseType ) ignore(A) Ignore value for forVar range aSet do statements end for Loop over all elements of a set ( Type of argument forVar: baseType, Type of argument statements: proc )5.13 struct
The type struct describes all structured types. An example of a struct type declaration is:
const type: aStructType is new struct var string: name is ""; end structVariables of this type are declared with:
var aStructType: aStructVariable is aStructType.value;In aStructType.value all elements have the initialisation values from the struct declaration of aStructType. Besides aStructType.value there are no struct literals.
Type generators: new struct var aType: name is value; ... end struct Create new structure type new metaType struct var aType: name is value; ... end struct Create new structure type as subtype of metaType, which is not a structure sub metaType struct var aType: name is value; ... end struct Create new structure type as subtype of metaType, which is a structure type. The new structure type inherits all elements of the structure type metaType. var aType: name is value Declare structure element 'name' with 'value' Infix operators: . Access Element of STRUCT ( example.element ) -> Access Element of ptr STRUCT ( example->element ) Relations: =, <> Statements: ignore(A) Ignore value5.14 enumeration
With
const type: anEnumType is new enum enum_literal1, enum_literal2 end enum;a new enumeration type is declared. The values of this type are:
enum_literal1 and enum_literal2For an enumeration type only few operations are predefined. Additional operations must be defined separately. So it is necessary to define the functions str and parse in order to do I/O for a new enumeration type. E.g.:
const func string: str (in anEnumType: enumValue) is return literal(enumValue); enable_output(anEnumType);The need to define str opens the oportunity to convert to strings, that differ from the original literals.
Constants: anEnumType.value Default value of anEnumType (enum_literal1) anEnumType.first Minimum value of anEnumType (enum_literal1) anEnumType.last Maximum value of anEnumType (enum_literal2) Infix operators: A ? B : C Ternary operator condition ? thenValue : elseValue ( Type of argument A: boolean, TRUE ? a : b ⇒ a, FALSE ? a : b ⇒ b ) anEnumType conv A Conversion from integer A to anEnumType ( Type of argument A: integer, anEnumType conv 0 ⇒ enum_literal1, anEnumType conv 1 ⇒ enum_literal2, anEnumType conv 2 ⇒ EXCEPTION RANGE_ERROR, anEnumType conv (-1) ⇒ EXCEPTION RANGE_ERROR ) integer conv A Conversion from anEnumType A to integer ( Type of result: integer, integer conv enum_literal1 ⇒ 0, integer conv enum_literal2 ⇒ 1 ) Relations: =, <>, <, <=, >, >= Functions: ord(A) Ordinal number ( Type of result: integer, ord(enum_literal1) ⇒ 0, ord(enum_literal2) ⇒ 1 ) integer(A) Ordinal number ( Type of result: integer, integer(enum_literal1) ⇒ 0, integer(enum_literal2) ⇒ 1 ) succ(A) Successor ( succ(A) ⇒ enumType conv succ(ord(A)), succ(enum_literal1) ⇒ enum_literal2, succ(anEnumType.last) ⇒ EXCEPTION RANGE_ERROR ) pred(A) Predecessor ( pred(A) ⇒ enumType conv pred(ord(A)), pred(enum_literal2) ⇒ enum_literal1, pred(anEnumType.first) ⇒ EXCEPTION RANGE_ERROR ) literal(A) Conversion to a literal ( Type of result: string, literal(enum_literal1) ⇒ "enum_literal1", literal(enum_literal2) ⇒ "enum_literal2" ) rand(A, B) Random value in the range [A, B] The random values are uniform distributed. ( rand(A, B) returns a random enumeration value such that A <= rand(A, B) and rand(A, B) <= B holds. rand(A, A) ⇒ A, rand(enum_literal2, enum_literal1) ⇒ EXCEPTION RANGE_ERROR ) compare(A, B) Compare function ( Type of result: integer, compare(enum_literal1, enum_literal2) ⇒ -1, compare(enum_literal1, enum_literal1) ⇒ 0, compare(enum_literal2, enum_literal1) ⇒ 1 ) hashCode(A) Hash function ( Type of result: integer ) Statements: incr(A) Increment ( incr(A) ⇒ A:=succ(A) ) decr(A) Decrement ( decr(A) ⇒ A:=pred(A) ) ignore(A) Ignore value5.15 bin64
The type bin64 describes bit-patterns with 64 bits. It uses the same representation as an integer. There is a division of responsibility. The type bin64 is for bitwise operations and the type integer is for arithmetic operations. In compiled programs conversions between bin64 and integer have no overhead.
Constants: bin64.value Default value of bin64 (bin64(0)) Prefix operators: ~ Bitwise not Infix operators: & Bitwise and | Bitwise inclusive or >< Bitwise exclusive or (xor) A << B Shift left ( Type of argument B: integer, A << B is okay for B >= 0 and B <= 63, A << B ⇒ EXCEPTION OVERFLOW_ERROR for B < 0 or B >= 64, A << 0 ⇒ A, bin64(16#1234567890abcde0) << 4 ⇒ bin64(16#234567890abcde00) ) A >> B Shift right ( Type of argument B: integer, A >> B is okay for B >= 0 and B <= 63, A >> B ⇒ EXCEPTION OVERFLOW_ERROR for B < 0 or B >= 64, A >> 0 ⇒ A, bin64(16#1234567890abcde0) >> 4 ⇒ bin64(16#1234567890abcde) ) A ? B : C Ternary operator condition ? thenValue : elseValue ( Type of argument A: boolean, TRUE ? a : b ⇒ a, FALSE ? a : b ⇒ b ) A radix B Convert to a string using a radix ( Type of result: string, Type of argument B: integer ) A RADIX B Convert to a string using a radix ( Type of result: string, Type of argument B: integer ) integer conv A Convert to integer ( Type of result: integer ) bin64 conv A Convert to bin64 ( Type of argument A: integer ) Relations: =, <> Functions: bin64(A) Conversion of integer to bin64 ( Type of argument: integer ) bin64(A) Conversion of bigInteger to bin64 ( Type of argument: bigInteger ) bin64(A) Conversion of char to bin64 ( Type of argument: char ) bin64(A) Get bits in IEEE 754 double-precision representation from a float ( Type of argument: float, bin64(1.0) ⇒ bin64(16#3ff0000000000000) ) ord(A) Ordinal number ( Type of result: integer ) integer(A) Ordinal number ( Type of result: integer ) big(A) Conversion to bigInteger ( Type of result: bigInteger ) bigInteger(A) Conversion to bigInteger ( Type of result: bigInteger ) float(A) Get float from bits in IEEE 754 double-precision representation ( Type of result: float, float(bin64(16#3ff0000000000000)) ⇒ 1.0 ) compare(A, B) Compare function ( Type of result: integer ) hashCode(A) Hash function ( Type of result: integer ) bitLength(A) Number of bits in the minimum binary representation. ( Type of result: integer, bitLength(bin64(0)) ⇒ 0, bitLength(bin64(1)) ⇒ 1, bitLength(bin64(4)) ⇒ 3 ) lowestSetBit(A) Number of lowest-order zero bits in the binary representation. ( Type of result: integer, A >> B << B = A for A <> bin64(0) and B = lowestSetBit(A), lowestSetBit(bin64(0)) ⇒ -1, lowestSetBit(bin64(1)) ⇒ 0, lowestSetBit(bin64(2)) ⇒ 1 ) rand(bin64) Random bin64 value The random values are uniform distributed. ( rand(bin64) ⇒ bin64(rand(integer.first, integer.last)) ) str(A) Conversion to string ( Type of result: string, str(bin64(18446744073709551615_)) ⇒ "18446744073709551615" ) bytes(aBin64, BE, len) Convert into a string of bytes with big-endian encoding ( Type of result: string ) bytes(aBin64, LE, len) Convert into a string of bytes with little-endian encoding ( Type of result: string ) rotLeft(A, B) Rotate the bits of a A left by B bits ( rotLeft(bin64(16#76543210fedcba98), 12) ⇒ bin64(16#43210fedcba98765) ) rotRight(A, B) Rotate the bits of a A right by B bits ( rotRight(bin64(16#76543210fedcba98), 40) ⇒ bin64(16#10fedcba98765432) ) getBinary(aBitset, lowestBitNum) Get 64 bits from aBitset starting with lowestBitNum ( Type of argument aBitset: bitset, Type of argument lowestBitNum: integer ) float2MbfBits(aFloat, DOUBLE) Get bits in MBF double-precision representation from aFloat Microsoft Binary Format (MBF) is a format for floating point numbers. ( Type of argument aFloat: float, float2MbfBits(1.0, DOUBLE) ⇒ bin64(16#8100000000000000_) ) mbfBits2Float(bits) Get a float from bits in MBF double-precision representation Microsoft Binary Format (MBF) is a format for floating point numbers. ( Type of result: float, mbfBits2Float(bin64(16#8100000000000000_)) ⇒ 1.0 ) bin64(bytes, LE) Convert string of little-endian bytes to bin64 ( Type of argument bytes: string ) bin64(bytes, BE) Convert string of big-endian bytes to bin64 ( Type of argument bytes: string ) Statements: A &:= B Bitwise and copy ( A &:= B ⇒ A := A & B ) A |:= B Bitwise inclusive or copy ( A |:= B ⇒ A := A | B ) A ><:= B Bitwise exclusive or (xor) copy ( A ><:= B ⇒ A := A >< B ) A <<:= B Shift left copy ( A <<:= B ⇒ A := A << B ) A >>:= B Shift right copy ( A >>:= B ⇒ A := A >> B ) ignore(A) Ignore value5.16 bin32
The type bin32 describes bit-patterns with 32 bits. It uses the same representation as an integer. There is a division of responsibility. The type bin32 is for bitwise operations and the type integer is for arithmetic operations. In compiled programs conversions between bin32 and integer have no overhead.
Constants: bin32.value Default value of bin32 (bin32(0)) Prefix operators: ~ Bitwise not Infix operators: & Bitwise and | Bitwise inclusive or >< Bitwise exclusive or (xor) A << B Shift left ( Type of argument B: integer, A << B is okay for B >= 0 and B <= 63, A << B ⇒ EXCEPTION OVERFLOW_ERROR for B < 0 or B >= 64, A << 0 ⇒ A, bin32(16#abcdef) << 4 ⇒ bin32(16#abcdef0) ) A >> B Shift right ( Type of argument B: integer, A >> B is okay for B >= 0 and B <= 63, A >> B ⇒ EXCEPTION OVERFLOW_ERROR for B < 0 or B >= 64, A >> 0 ⇒ A, bin32(16#abcdef) >> 4 ⇒ bin32(16#abcde) ) A ? B : C Ternary operator condition ? thenValue : elseValue ( Type of argument A: boolean, TRUE ? a : b ⇒ a, FALSE ? a : b ⇒ b ) A radix B Convert to a string using a radix ( Type of result: string, Type of argument B: integer ) A RADIX B Convert to a string using a radix ( Type of result: string, Type of argument B: integer ) integer conv A Convert to integer ( Type of result: integer ) bin32 conv A Convert to bin32 ( Type of argument A: integer ) Relations: =, <> Functions: bin32(A) Conversion of integer to bin32 ( Type of argument: integer ) bin32(A) Conversion of char to bin32 ( Type of argument: char ) bin32(A) Get bits in IEEE 754 single-precision representation from a float ( Type of argument: float, bin32(1.0) ⇒ bin32(16#3f800000) ) ord(A) Ordinal number ( Type of result: integer ) integer(A) Ordinal number ( Type of result: integer ) float(A) Get float from bits in IEEE 754 single-precision representation ( Type of result: float, float(bin32(16#3f800000)) ⇒ 1.0 ) compare(A, B) Compare function ( Type of result: integer ) hashCode(A) Hash function ( Type of result: integer ) bitLength(A) Number of bits in the minimum binary representation. ( Type of result: integer, bitLength(bin32(0)) ⇒ 0, bitLength(bin32(1)) ⇒ 1, bitLength(bin32(4)) ⇒ 3 ) lowestSetBit(A) Number of lowest-order zero bits in the binary representation. ( Type of result: integer, A >> B << B = A for A <> bin32(0) and B = lowestSetBit(A), lowestSetBit(bin32(0)) ⇒ -1, lowestSetBit(bin32(1)) ⇒ 0, lowestSetBit(bin32(2)) ⇒ 1 ) rand(bin32) Random bin32 value The random values are uniform distributed. ( rand(bin32) ⇒ bin32(rand(0, 4294967295)) ) str(A) Conversion to string ( Type of result: string, str(bin32(4294967295)) ⇒ "4294967295" ) bytes(aBin32, BE, len) Convert into a string of bytes with big-endian encoding ( Type of result: string ) bytes(aBin32, LE, len) Convert into a string of bytes with little-endian encoding ( Type of result: string ) rotLeft(A, B) Rotate the bits of a A left by B bits ( rotLeft(bin32(16#12345678), 8) ⇒ bin32(16#34567812) ) rotRight(A, B) Rotate the bits of a A right by B bits ( rotRight(bin32(16#12345678), 8) ⇒ bin32(16#78123456) ) float2MbfBits(aFloat, SINGLE) Get bits in MBF single-precision representation from aFloat Microsoft Binary Format (MBF) is a format for floating point numbers. ( Type of argument aFloat: float, float2MbfBits(1.0, SINGLE) ⇒ bin32(16#81000000) ) mbfBits2Float(bits) Get a float from bits in MBF single-precision representation Microsoft Binary Format (MBF) is a format for floating point numbers. ( Type of result: float mbfBits2Float(bin32(16#81000000)) ⇒ 1.0 ) bin32(bytes, LE) Convert string of little-endian bytes to bin32 ( Type of argument bytes: string ) bin32(bytes, BE) Convert string of big-endian bytes to bin32 ( Type of argument bytes: string ) Statements: A &:= B Bitwise and copy ( A &:= B ⇒ A := A & B ) A |:= B Bitwise inclusive or copy ( A |:= B ⇒ A := A | B ) A ><:= B Bitwise exclusive or (xor) copy ( A ><:= B ⇒ A := A >< B ) A <<:= B Shift left copy ( A <<:= B ⇒ A := A << B ) A >>:= B Shift right copy ( A >>:= B ⇒ A := A >> B ) ignore(A) Ignore value5.17 bstring
The type bstring describes strings of bytes. It is used to store binary data.
Constants: bstring.value Default value of bstring (bstring("")) Infix operators: A ? B : C Ternary operator condition ? thenValue : elseValue ( Type of argument A: boolean, TRUE ? a : b ⇒ a, FALSE ? a : b ⇒ b ) bstring parse A Conversion of string to bstring ( Type of argument A: string ) Indices: [ A ] Access one character ( Type of argument A: integer, Type of result: char ) Functions: str(A) Conversion to string ( Type of result: string ) literal(A) Conversion to a literal ( Type of result: string ) string(A) Conversion to string ( Type of result: string ) bstring(A) Conversion to bstring ( Type of argument A: string ) length(A) Length of bstring ( Type of result: integer ) compare(A, B) Compare function ( Type of result: integer ) hashCode(A) Hash function ( Type of result: integer ) bStriBe2BigInt(A, isSigned) Convert a bstring (interpreted as big-endian) to a bigInteger ( Type of argument isSigned: boolean, Type of result: bigInteger ) bStriLe2BigInt(A, isSigned) Convert a bstring (interpreted as little-endian) to a bigInteger ( Type of argument isSigned: boolean, Type of result: bigInteger ) bStriBe(A, isSigned) Convert a bigInteger into a big-endian bstring ( Type of argument A: bigInteger, Type of argument isSigned: boolean ) bStriLe(A, isSigned) Convert a bigInteger into a little-endian bstring ( Type of argument A: bigInteger, Type of argument isSigned: boolean ) Relations: =, <> Statements: ignore(A) Ignore value for forVar range bstri do statements end for Loop over all elements of a bstring ( Type of argument forVar: char, Type of argument statements: proc )5.18 color
The type color describes colors. It uses the additive color model with red, green and blue lights. The red, green and blue lights are specified with integer values in the range 0 .. 65535. The color functions are defined in the library "color.s7i".
Elements: var integer: redLight is 0; var integer: greenLight is 0; var integer: blueLight is 0; Constants: color.value Default value of color (black) black color(0, 0, 0); dark_red color(32768, 0, 0); dark_green color(0, 32768, 0); brown color(32768, 16384, 0); dark_blue color(0, 0, 32768); dark_magenta color(32768, 0, 32768); dark_cyan color(0, 65535, 65535); light_gray color(49152, 49152, 49152); dark_gray color(16384, 16384, 16384); light_red color(65535, 0, 0); light_green color(0, 65535, 0); yellow color(65535, 65535, 0); light_blue color(0, 0, 65535); light_magenta color(65535, 0, 65535); light_cyan color(32768, 65535, 65535); white color(65535, 65535, 65535); orange color(65535, 32768, 0); amber color(49152, 32768, 16384); pink color(65535, 32768, 32768); Infix operators: + Add two colors in an additive color system A ? B : C Ternary operator condition ? thenValue : elseValue ( Type of argument A: boolean, TRUE ? a : b ⇒ a, FALSE ? a : b ⇒ b ) Relations: =, <> Functions: color(R,G,B) Creates a color from Red, Green and Blue ( Type of argument R: integer, Type of argument G: integer, Type of argument B: integer ) gray(BR) Create a gray color value from BR ( Type of argument BR: integer ) compare(A, B) Compare function ( Type of result: integer ) hashCode(A) Hash function ( Type of result: integer ) Statements: clear(A) Clear current window ignore(A) Ignore value5.19 time
The type time describes times and dates. For dates the proleptic Gregorian calendar is used (which assumes that the Gregorian calendar was even in effect at dates preceding its official introduction). This convention is used according to ISO 8601 which also defines that positive and negative years exist and that the year preceding 1 is 0. Time is measured in hours, minutes, seconds and micro seconds. Additionally information about the difference to UTC and a flag indicating daylight saving time is maintained also. The time functions are defined in the library "time.s7i".
Elements: var integer: year is 0; var integer: month is 1; var integer: day is 1; var integer: hour is 0; var integer: minute is 0; var integer: second is 0; var integer: micro_second is 0; Constants: time.value Default value of time (time(0, 1, 1, 0, 0, 0)) Infix operators: A ? B : C Ternary operator condition ? thenValue : elseValue ( Type of argument A: boolean, TRUE ? a : b ⇒ a, FALSE ? a : b ⇒ b ) time parse A Conversion of string to time ( Type of argument A: string, time parse "2005-02-28 12:00:01" ⇒ 2005-02-28 12:00:01, time parse "2005-02-29 12:00:01" ⇒ EXCEPTION RANGE_ERROR ) Relations: =, <>, <, <=, >, >= Functions: time(NOW) Gets the current time time(A) Conversion of string to time ( Type of argument A: string, time("2005-02-28 12:00:01") ⇒ 2005-02-28 12:00:01, time("2005-02-29 12:00:01") ⇒ EXCEPTION RANGE_ERROR ) str(A) Conversion to string ( Type of result: string ) strDate(A) Conversion of the date to string with ISO 8601 YYYY-MM-DD date format ( Type of result: string ) strTime(A) Conversion of the daytime to string with ISO 8601 hh:mm:ss time format ( Type of result: string ) strDateTime(A) Conversion of date and time to string with ISO 8601 YYYY-MM-DD hh:mm:ss format ( Type of result: string ) strTimeZone(A) Conversion of the time zone to string ( Type of result: string ) truncToSecond(A) Truncate a time to a second truncToMinute(A) Truncate a time to a minute truncToHour(A) Truncate a time to a hour truncToDay(A) Truncate a time to a day truncToMonth(A) Truncate a time to a month truncToYear(A) Truncate a time to a year isLeapYear(A) Determine if a given year is a leap year ( Type of argument A: integer ) ( Type of result: boolean ) daysInYear(Y) Calculate the number of days in a year ( Type of argument Y: integer, Type of result: integer ) daysInMonth(Y, M) Calculate the number of days in a month ( Type of argument Y: integer, Type of argument M: integer, Type of result: integer ) daysInMonth(A) Calculate the number of days in a month ( Type of result: integer ) dayOfWeek(A) Day of the week with Monday as 1 ( Type of result: integer ) dayOfYear(A) Day of the year with 1 January as 1 ( Type of result: integer ) weekOfYear(Y, D) Compute the week number of a year (0 to 53). According to ISO 8601: Week number 1 of every year contains the 4. of january. ( Type of argument Y: integer, Type of argument D: integer, Type of result: integer ) weekOfYear(A) Compute the week number of a year (0 to 53). According to ISO 8601: Week number 1 of every year contains the 4. of january. ( Type of result: integer ) weekDateYear(A) Compute the year of the ISO 8601 week date ( Type of result: integer ) weekDateWeek(A) Compute the week of the ISO 8601 week date ( Type of result: integer ) toUTC(A) Conversion to Coordinated Universal Time (UTC) toLocalTZ Convert given time to a time in the local time zone. setLocalTZ Sets timeZone and daylightSavingTime for a given time. julianDayNumber(A) Number of days that have elapsed since January 1, 4713 BC in the proleptic Julian calendar ( Type of result: integer ) julianDayNumToTime(A) Convert julian day number to time ( Type of argument A: integer ) timestamp1970(A) Time expressed in seconds since the Unix epoch (1970-01-01 00:00:00 UTC) ( Type of result: integer ) timestamp1970ToTime(A) Convert a Unix timestamp into a time from the local time zone ( Type of argument A: integer ) timestamp1601(A) 100-nanosecond intervals since the Windows epoch (1601-01-01 00:00:00 UTC) ( Type of result: integer ) timestamp1601ToTime(A) Convert a FILETIME into a time from the local time zone ( Type of argument A: integer ) compare(A, B) Compare function ( Type of result: integer ) hashCode(A) Hash function ( Type of result: integer ) Statements: await(A) Wait until the given time ignore(A) Ignore value5.20 duration
The type duration describes time and date durations. The duration functions are defined in the library "duration.s7i".
Constants: duration.value Default value of duration (duration("P0D")) Prefix operators: + Identity - Change sign Infix operators: + Add two durations - Subtract two durations * Multiply a duration by an integer ( Type of left operand: integer ) * Multiply a duration by an integer ( Type of right operand: integer ) + Add a duration to a time ( Type of left operand: time, Type of result: time ) - Subtract a duration from a time ( Type of left operand: time, Type of result: time ) - Subtract two times ( Type of left operand: time, Type of right operand: time ) A ? B : C Ternary operator condition ? thenValue : elseValue ( Type of argument A: boolean, TRUE ? a : b ⇒ a, FALSE ? a : b ⇒ b ) duration parse A Conversion of string to duration ( Type of argument A: string, duration parse "P2M28DT12H1S" ⇒ P2M28DT12H1S, duration parse "P13M28DT12H1S" ⇒ EXCEPTION RANGE_ERROR ) Relations: =, <>, <, <=, >, >= Functions: duration(A) Conversion of string to duration ( Type of argument A: string, duration("P2M28DT12H1S") ⇒ P2M28DT12H1S, duration("P13M28DT12H1S") ⇒ EXCEPTION RANGE_ERROR ) getYears(A) Obtains the years of a duration ( Type of result: integer ) getMonths(A) Obtains the months of a duration ( Type of result: integer ) getDays(A) Obtains the days of a duration ( Type of result: integer ) getHours(A) Obtains the hours of a duration ( Type of result: integer ) getMinutes(A) Obtains the minutes of a duration ( Type of result: integer ) getSeconds(A) Obtains the seconds of a duration ( Type of result: integer ) getMicroSeconds(A) Obtains the micro seconds of a duration ( Type of result: integer ) toYears(A) Return the duration in years ( Type of result: integer ) toMonths(A) Return the duration in months ( Type of result: integer ) toDays(A) Return the duration in days ( Type of result: integer ) toHours(A) Return the duration in hours ( Type of result: integer ) toMinutes(A) Return the duration in minutes ( Type of result: integer ) toSeconds(A) Return the duration in seconds ( Type of result: integer ) toMicroSeconds(A) Return the duration in micro seconds ( Type of result: integer ) str(A) Conversion to string ( Type of result: string ) compare(A, B) Compare function ( Type of result: integer ) hashCode(A) Hash function ( Type of result: integer ) Statements: A +:= B Increment A by B ( A +:= B ⇒ A := A + B ) A -:= B Decrement A by B ( A -:= B ⇒ A := A - B ) A +:= B Increment time A by B ( Type of argument A: time, A +:= B ⇒ A := A + B ) A -:= B Decrement time A by B ( Type of argument A: time, A -:= B ⇒ A := A - B ) wait(A) Wait for given duration ignore(A) Ignore valueFor the operations - (negate a duration) and - (subtract two time values) holds:
(tim1 - tim2) = - (tim2 - tim1)For the operations + (add a duration to a time) and - (subtract two time values) holds:
tim2 + (tim1 - tim2) = tim1For the operations - (subtract a duration from a time) and - (subtract two time values) holds:
tim1 - (tim1 - tim2) = tim25.21 file
The type file is the interface type for sequential files. The file functions are defined in the library "file.s7i".
Constants: file.value Default value of file (STD_NULL) Variables: STD_NULL Standard null file STD_IN Standard input of the operating system STD_OUT Standard output of the operating system STD_ERR Standard error output of the operating system IN Standard input file used for file input operations when no file is specified ( IN is initialized with STD_IN ) OUT Standard output file used for file output operations when no file is specified ( OUT is initialized with STD_OUT ) CONSOLE_KEYBOARD Keyboard file describing the console keyboard. GRAPH_KEYBOARD Keyboard file describing the graphic keyboard. KEYBOARD Variable describing the keyboard. ( KEYBOARD is initialized with CONSOLE_KEYBOARD ) Implementation types of the file interface: null_file Base implementation type for the file interface external_file Files of the operating system utf8File UTF-8 encoded files of the operating system utf16File UTF-16 encoded files of the operating system utf16leFile UTF-16LE encoded files of the operating system utf16beFile UTF-16BE encoded files of the operating system dirFile Read the contents of a directory echoFile Generate an echo of the input lineFile Read a baseFile line-wise editLineFile Support line-wise editing with history gzipFile Read decompressed data from a GZIP file gzipWriteFile Write compressed data into a GZIP file bufferFile Buffer (cache) data based on the given base file lzmaFile Read decompressed data from a LZMA file popenFile Operating system pipes popen8File UTF-8 encoded operating system pipes socket Sockets of the operation system tlsFile Transport Layer Security (TLS/SSL) sockets striFile Files stored in a string teeFile File that writes to several destination files at once moreFile Filter file which shows another file screenwise lowerFile Filter file which turns characters to lower case upperFile Filter file which turns characters to upper case subFile Read access to the sub segment of a base file xzFile Read decompressed data from a XZ file zstdFile Read decompressed data from a Zstandard file Relations: =, <> Functions to open a file: open(path, mode) Open external file ( Type of argument path: string, Type of argument mode: string, Type of result: file, Returns STD_NULL if open was not possible ) openUtf8(path, mode) Open external UTF-8 encoded file ( Type of argument path: string, Type of argument mode: string, Type of result: file, Returns STD_NULL if open was not possible ) openUtf16(path, mode) Open existing UTF-16LE or UTF-16BE encoded file ( Type of argument path: string, Type of argument mode: string, Type of result: file, Returns STD_NULL if open was not possible ) openUtf16le(path, mode) Open UTF-16LE encoded file ( Type of argument path: string, Type of argument mode: string, Type of result: file, Returns STD_NULL if open was not possible ) openUtf16be(path, mode) Open UTF-16BE encoded file ( Type of argument path: string, Type of argument mode: string, Type of result: file, Returns STD_NULL if open was not possible ) openStriFile(content) Open a striFile with the given string content ( Type of argument content: string ) openStriFile Open a striFile with an empty string content openTee(destFiles) Open a tee file to write to the given destination files ( Type of argument destFiles: array string ) openTee(dest1, dest2) Open a tee file to write to the two destination files openMore(dest, cmds, pageSize) Open a more filter file for viewing a file page by page ( Type of argument pageSize: integer ) openLower(dest) Open a filter file which turns characters to lower case openUpper(dest) Open a filter file which turns characters to upper case openGzipFile(compressed, READ) Open a GZIP file for reading (decompression) ( Returns STD_NULL if the file is not in GZIP format ) openGzipFile(destFile, WRITE) Open a GZIP file for writing (compression) The data written to this file is compressed with GZIP and written to destFile. openLzmaFile(compressed) Open a LZMA file for reading (decompression) ( Returns STD_NULL if the file is not in LZMA format ) openXzFile(compressed) Open a XZ file for reading (decompression) ( Returns STD_NULL if the file is not in XZ format ) openZstdFile(compressed) Open a Zstandard file for reading (decompression) ( Returns STD_NULL if the file is not in Zstandard format ) popen(A, B) Open a pipe to a process ( Type of argument A: string, Type of argument B: string, Type of result: file, Returns STD_NULL if popen was not possible ) popen8(A, B) Open a UTF-8 pipe to a process ( Type of argument A: string, Type of argument B: string, Type of result: file, Returns STD_NULL if popen8 was not possible ) openInetSocket(port) Open local Internet client socket ( Type of argument port: integer, Type of result: file, Returns STD_NULL if open was not possible ) openInetSocket(addr, port) Open Internet client socket ( Type of argument addr: string, Type of argument port: integer, Type of result: file, Returns STD_NULL if open was not possible ) openTlsSocket(addr, port) Open TLS socket ( Type of argument addr: string, Type of argument port: integer, Type of result: file, Returns STD_NULL if open was not possible ) openDir(directoryPath) Open a directory file ( Type of argument directoryPath: string ) openEcho(inFile, outFile) Open an echo file openLine(aFile) Open a lineFile to filter aFile line-wise openEditLine(inFile, outFile) Open a Unicode filter file for line-wise editing with history openEditLineLatin1(inFile, outFile) Open a Latin-1 filter file for line-wise editing with history Functions: length(A) Length of file A ( Type of result: integer ) tell(A) Return the actual file position ( Type of argument: file, The first position in the file is 1 ) seekable(A) Determine if file A is seekable getc(A) Get one character from file A ( Type of result: char ) gets(A, B) Get string with maximum length B from file A ( Type of argument A: integer, Type of argument B: file, Type of result: string, gets(A, -1) ⇒ EXCEPTION RANGE_ERROR ) getwd(A) Get one word from file A ( Type of result: string ) getln(A) Get one line from file A ( Type of result: string ) eoln(A) End of line ( Type of result: boolean ) eof(A) End of file ( Type of result: boolean ) hasNext(A) A call of getc would not return the EOF character ( Type of result: boolean ) inputReady(A) At least one character can be read without blocking. ( Type of result: boolean ) compare(A, B) Compare function ( Type of result: integer ) hashCode(A) Hash function ( Type of result: integer ) Statements: write(A, B) Write string B to file A ( Type of argument B: string ) writeln(A) Write a new line to file A writeln(A, B) Write string B and new line to file A ( Type of argument B: string ) read(A, B) Read a word from file A into string B ( Type of argument B: string ) read(A, B, C) Read a word from file A into B or use default value C ( Type of argument B: string, Type of argument C: string ) readln(A) Read a line from file A readln(A, B) Read a line from file A into the string B ( Type of right operand: string ) readln(A, B, C) Read a line from file A into B or use default value C ( Type of argument B: string, Type of argument C: string ) skip(A, B) Skip B characters from file A backSpace(A) Write backspace to file A close(A) Close file A flush(A) Flush file A seek(A, B) Set actual file position of file A to B ( Type of argument B: integer, seek(A, 1) ⇒ Set to file begin, seek(A, length(A)) ⇒ Set to last position, seek(A, length(A) + 1) ⇒ Set to end of file, seek(A, 0) ⇒ EXCEPTION RANGE_ERROR ) truncate(A, B) Truncate file A to length B ( Type of argument B: integer ) ignore(A) Ignore value5.22 text
The type text is the interface type for two dimensional files. These files consist of lines with columns in them. The text functions are defined in the library "text.s7i".
Variables: STD_CONSOLE Standard console file of the current process. Implementation types of the text interface: console_file Write to the text console/window graph_file Write to a graphic window with the system font window_file Write to a rectangular area in another text pixmapFontFile Write to a graphic window with a pixmap font striText Text file stored in an array of strings Relations: =, <> Functions to open a text: open(CONSOLE) Creates console_file at the upper left corner of the console/window. open(graphWin) Creates a graph_file at the upper left corner of graphWin ( Type of argument graphWin: PRIMITIVE_WINDOW ) open(graphWin, minX, minY) Creates a graph_file at (minX, minY) in graphWin ( Type of argument graphWin: PRIMITIVE_WINDOW, Type of argument minX: integer, Type of argument minY: integer ) open(graphWin, minX, minY, width, height) Creates a graph_file at (minX, minY) in graphWin ( Type of argument graphWin: PRIMITIVE_WINDOW, Type of argument minX: integer, Type of argument minY: integer, Type of argument width: integer, Type of argument height: integer ) openWindow(outText, upper, left, height, width) Creates a window_file at (left, upper) in outText ( Type of argument upper: integer, Type of argument left: integer, Type of argument height: integer, Type of argument width: integer ) openPixmapFontFile(win) Creates a pixmapFontFile at the upper left corner of win ( Type of argument win: PRIMITIVE_WINDOW ) openPixmapFontFile(win, minX, minY) Creates a pixmapFontFile at (minX, minY) in win ( Type of argument win: PRIMITIVE_WINDOW, Type of argument minX: integer, Type of argument minY: integer ) openStriText(content) Open a striText with the given content ( Type of argument content: array string ) Functions: height(A) Height of the text ( Type of result: integer ) width(A) Width of the text ( Type of result: integer ) line(A) Current line of the text ( Type of result: integer ) column(A) Current column of the text ( Type of result: integer ) Statements: write(A, B) Write string B to text A ( Type of argument B: string ) writeln(A) Write a new line to text A writeln(A, B) Write string B and new line to text A ( Type of argument B: string ) read(A, B) Read a word from text A into string B ( Type of right operand: string ) readln(A) Read a line from text A readln(A, B) Read a line from text A into the string B ( Type of right operand: string ) backSpace(A) Write backspace to text A close(A) Close text A flush(A) Flush text A clear(A) Clear the window clear(A, UP, LO, LE, RI) Clear an area of the window ( Type of argument UP: integer Type of argument LO: integer Type of argument LE: integer Type of argument RI: integer ) v_scroll(A) Scroll the window vertical h_scroll(A) Scroll the window horizontal color(A, B) Set foreground color of the text A ( Type of argument B: color ) color(A, B, C) Set foreground and background color of the text A ( Type of argument B: color, Type of argument C: color ) setPos(A, B, C) Set the current position of the text A ( Type of argument B: integer Type of argument C: integer ) setLine(A, B) Set the current line of the text A ( Type of argument B: integer ) setColumn(A, B) Set the current column of the text A ( Type of argument B: integer ) box(A) Write a box around the window clear_box(A) Clear the box around the window cursor_on(A) Make the cursor visible cursor_off(A) Make the cursor invisible ignore(A) Ignore value5.23 fileSys
The type fileSys is the interface type for file systems. The files of the operating system and the contents of an archive file are both organized as file systems. The connection to files stored at a remote computer can also use the fileSys interface.
Constants: fileSys.value Default value of fileSys (emptyFileSys.value) Variables: osFiles File system of the operating system files Implementation types of the fileSys interface: emptyFileSys Empty file system (used as default value) osFileSys File system to access operating system files arArchive Access to an AR archive cpioArchive Access to a CPIO archive rpmArchive Access to a RPM archive tarArchive Access to a TAR archive zipArchive Access to a ZIP archive ftpConnection Connection to a FTP server Functions to open a fileSys: openAr(arFile) Open a AR archive with the given arFile ( Type of argument arFile: file, Returns fileSys.value if open was not possible ) openAr(arFileName) Open a AR archive with the given arFileName ( Type of argument arFileName: string, Returns fileSys.value if open was not possible ) openCpio(cpioFile) Open a CPIO archive with the given cpioFile ( Type of argument cpioFile: file, Returns fileSys.value if open was not possible ) openCpio(cpioFileName) Open a CPIO archive with the given cpioFileName ( Type of argument cpioFileName: string, Returns fileSys.value if open was not possible ) openRpm(rpmFile) Open a RPM archive with the given rpmFile ( Type of argument rpmFile: file, Returns fileSys.value if open was not possible ) openRpm(rpmFileName) Open a RPM archive with the given rpmFileName ( Type of argument rpmFileName: string, Returns fileSys.value if open was not possible ) openTar(tarFile) Open a TAR archive with the given tarFile ( Type of argument tarFile: file, Returns fileSys.value if open was not possible ) openTar(tarFileName) Open a TAR archive with the given tarFileName ( Type of argument tarFileName: string, Returns fileSys.value if open was not possible ) openZip(zipFile) Open a ZIP archive with the given zipFile ( Type of argument zipFile: file, Returns fileSys.value if open was not possible ) openZip(zipFileName) Open a ZIP archive with the given zipFileName ( Type of argument zipFileName: string, Returns fileSys.value if open was not possible ) openFtp(hostName, user, password, ftpControlPort) Open a FTP file system ( Type of argument hostName: string, Type of argument user: string, Type of argument password: string, Type of argument ftpControlPort: integer ) openFtp(hostName, user, password) Open a FTP file system ( Type of argument hostName: string, Type of argument user: string, Type of argument password: string ) openFtp(connectStri, ftpControlPort) Open a FTP file system ( Type of argument connectStri: string, Type of argument ftpControlPort: integer ) openFtp(connectStri) Open a FTP file system ( Type of argument connectStri: string ) Functions: close(aFileSys) Close a file system readDir(aFileSys, dirPath) Read the file names of a directory ( Type of argument dirPath: string, Type of result: array string ) readDir(aFileSys, dirPath, RECURSIVE) Read the file paths of a directory recursively ( Type of argument dirPath: string, Type of result: array string ) readDir(aFileSys) Read the file names of the root directory ( Type of result: array string ) readDir(aFileSys, RECURSIVE) Read the file paths of the root directory recursively ( Type of result: array string ) fileType(aFileSys, path) Get the type of a file ( Type of argument path: string, Type of result: fileType ) fileTypeSL(aFileSys, path) Get the type of a file (do not follow symbolic links) ( Type of argument path: string, Type of result: fileType ) getFileMode(aFileSys, path) Get the file mode (permissions) of a file ( Type of argument path: string, Type of result: fileMode ) fileSize(aFileSys, path) Get the size of a file ( Type of argument path: string, Type of result: integer ) bigFileSize(aFileSys, path) Get the size of a file ( Type of argument path: string, Type of result: bigInteger ) getMTime(aFileSys, path) Get the modification time of a file ( Type of argument path: string, Type of result: time ) getOwner(aFileSys, path) Get the name of the owner (UID) of a file ( Type of argument path: string, Type of result: string ) getGroup(aFileSys, path) Get the name of the group (GID) to which a file belongs ( Type of argument path: string, Type of result: string ) open(aFileSys, filePath, mode) Open a file with filePath and mode ( Type of argument filePath: string, Type of argument mode: string, Type of result: file ) getFile(aFileSys, filePath) Get the contents of file filePath ( Type of argument filePath: string, Type of result: string ) readLink(aFileSys, path) Reads the destination of a symbolic link ( Type of argument path: string, Type of result: string ) Statements: setFileMode(aFileSys, path, mode) Change the file mode (permissions) of a file ( Type of argument path: string, Type of argument mode: fileMode ) setMTime(aFileSys, path, modificationTime) ( Type of argument path: string, Type of argument modificationTime: time ) setOwner(aFileSys, path, owner) Set the owner of a file ( Type of argument path: string, Type of argument owner: string ) setGroup(aFileSys, path, group) Set the group of a file ( Type of argument path: string, Type of argument group: string ) putFile(aFileSys, filePath, stri) Write stri to the file filePath using the file system ( Type of argument filePath: string, Type of argument stri: string ) removeFile(aFileSys, path) Remove a file (except a nonempty directory) ( Type of argument path: string ) removeTree(aFileSys, path) Remove a file of any type inclusive a directory tree ( Type of argument path: string ) moveFile(aFileSys, sourcePath, destPath) Move and rename a file or directory tree ( Type of argument sourcePath: string, Type of argument destPath: string ) makeDir(aFileSys, dirPath) Create a directory ( Type of argument dirPath: string ) makeLink(aFileSys, symlinkPath, targetPath) Create a symbolic link ( Type of argument symlinkPath: string, Type of argument targetPath: string ) rmdir(aFileSys, dirPath) Delete an empty directory ( Type of argument dirPath: string ) getcwd(aFileSys) Determine the current working directory chdir(aFileSys, dirPath) Change the current working directory ( Type of argument dirPath: string ) ignore(A) Ignore value5.24 database
The type database describes database connections. The library "sql_base.s7i" defines functions to manage database connections.
Constants: database.value Default value of database (empty database) Relations: =, <> Functions: openDatabase(driver, host, port, dbName, user, password) Open database ( Type of argument driver: dbCategory, Type of argument host: string, Type of argument port: integer, Type of argument dbName: string, Type of argument user: string, Type of argument password: string ) openDatabase(DB_ODBC, odbcDriver, server, dbName, user, password) Open ODBC database ( Type of argument odbcDriver: string, Type of argument server: string, Type of argument dbName: string, Type of argument user: string, Type of argument password: string ) openDatabase(DB_INFORMIX, host, port, server, dbName, user, password) Open Informix database ( Type of argument host: string, Type of argument port: integer, Type of argument server: string, Type of argument dbName: string, Type of argument user: string, Type of argument password: string ) openDatabase(driver, dbPath, user, password) Open the database dbPath with the specified user and password ( Type of argument driver: dbCategory, Type of argument dbPath: string, Type of argument user: string, Type of argument password: string ) openDatabase(driver, connectStri) Open a database with the specified driver and connectStri ( Type of argument driver: dbCategory, Type of argument connectStri: string ) close(db) Close the specified database db getAutoCommit(db) Get the current auto-commit mode of db ( Type of result: boolean ) Statements: setAutoCommit(db, autoCommit) Set the auto-commit mode for db. ( Type of argument autoCommit: boolean ) commit(db) Execute a commit statement for db rollback (db) Execute a rollback statement for db5.25 sqlStatement
The type sqlStatement describes prepared sql statements.
Constants: sqlStatement.value Default value of sqlStatement Relations: =, <> Functions: prepare(db, sqlStatementStri) Create a prepared statement for db ( Type of argument db: database Type of argument sqlStatementStri: string ) fetch(statement) Fetch a row from the result data of an executed statement ( Type of result: boolean ) column(statement, column, bigInteger) Get the specified column of fetched data as bigInteger ( Type of argument column: integer, Type of result: bigInteger ) column(statement, column, bigRational) Get the specified column of fetched data as bigRational ( Type of argument column: integer, Type of result: bigRational ) column(statement, column, boolean) Get the specified column of fetched data as booleaninteger, Type of result: boolean ) column(statement, column, bstring) Get the specified column of fetched data as bstring ( Type of argument column: integer, Type of result: bstring ) column(statement, column, duration) Get the specified column of fetched data as duration ( Type of argument column: integer, Type of result: duration ) column(statement, column, float) Get the specified column of fetched data as float ( Type of argument column: integer, Type of result: float ) column(statement, column, integer) Get the specified column of fetched data as integer ( Type of argument column: integer, Type of result: integer ) column(statement, column, string) Get the specified column of fetched data as string ( Type of argument column: integer, Type of result: string ) column(statement, column, time) Get the specified column of fetched data as time ( Type of argument column: integer, Type of result: time ) isNull(statement, column) Determine if the specified column of fetched data is NULL ( Type of argument column: integer, Type of result: boolean ) columnCount(statement) Return the number of columns in the result data of a statement ( Type of result: integer ) columnName(statement, column) Return the name of a column in the result data of a statement ( Type of argument column: integer, Type of result: string ) Statements: bind(statement, pos, num) Bind a bigInteger parameter to a prepared SQL statement ( Type of argument pos: integer, Type of argument num: bigInteger ) bind(statement, pos, bigRatData) Bind a bigRational parameter to a prepared SQL statement ( Type of argument pos: integer, Type of argument bigRatData: bigRational ) bind(statement, pos, flag) Bind a boolean parameter to a prepared SQL statement ( Type of argument pos: integer, Type of argument flag: boolean ) bind(statement, pos, bstri) Bind a bstring parameter to a prepared SQL statement ( Type of argument pos: integer, Type of argument bstri: bstring ) bind(statement, pos, number) Bind a float parameter to a prepared SQL statement ( Type of argument pos: integer, Type of argument number: float ) bind(statement, pos, number) Bind an integer parameter to a prepared SQL statement ( Type of argument pos: integer, Type of argument number: integer ) bind(statement, pos, NULL) Bind a NULL parameter to a prepared SQL statement. ( Type of argument pos: integer ) bind(statement, pos, stri) Bind a string parameter to a prepared SQL statement ( Type of argument pos: integer, Type of argument : string ) bind(statement, pos, timeData) Bind a time parameter to a prepared SQL statement ( Type of argument pos: integer, Type of argument timeData: time ) bind(statement, pos, durationData) Bind a duration parameter to a prepared SQL statement ( Type of argument pos: integer, Type of argument durationData: duration ) execute(statement) Execute the specified prepared SQL statement5.26 process
The type process describes processes of the operating system. The library "process.s7i" defines functions to create and manage processes.
Constants: process.value Default value of process (process.EMPTY) Relations: =, <> Functions: startProcess(command, parameters) Start a new process ( Type of argument command: string, Type of argument parameters: array string ) startProcess(cmdAndParams) Start a new process ( Type of argument cmdAndParams: string ) pipe2(command, parameters, childStdin, childStdout) Start a process Connect pipes to its standard I/O files. ( Type of argument command: string, Type of argument parameters: array string, Type of argument childStdin: file, Type of argument childStdout: file ) childStdIn(process) The standard input file of process ( Type of result: file ) childStdOut(process) The standard output file of process ( Type of result: file ) childStdErr(process) The standard error file of process ( Type of result: file ) isAlive(process) Test whether the specified process is alive ( Type of result: boolean ) exitValue(process) The exit value of process ( Type of result: integer ) compare(A, B) Compare function ( Type of result: integer ) hashCode(A) Hash function ( Type of result: integer ) str(process) Get the process identifier (PID) getSearchPath The search path of the operating system ( Type of result: array string ) commandPath(command) Search for an executable in the directories of the search path ( Type of argument command: string, Type of result: string ) commandDir(command) Search for the directory of an executable in the search path ( Type of argument command: string, Type of result: string ) Statements: kill(process) Kill process waitFor(process) Wait until process has terminated setSearchPath(searchPath) Set the search path of the current process ( Type of argument searchPath: array string ) ignore(A) Ignore value5.27 category
The type category describes the category of a reference. The category functions are defined in the library "category.s7i".
Literals: SYMBOLOBJECT, DECLAREDOBJECT, FORWARDOBJECT, FWDREFOBJECT, BLOCKOBJECT, CALLOBJECT,MATCHOBJECT, TYPEOBJECT, FORMPARAMOBJECT, INTOBJECT, BIGINTOBJECT, CHAROBJECT, STRIOBJECT, BSTRIOBJECT, ARRAYOBJECT, HASHOBJECT, STRUCTOBJECT, CLASSOBJECT, INTERFACEOBJECT, SETOBJECT, FILEOBJECT, SOCKETOBJECT, LISTOBJECT, FLOATOBJECT, WINOBJECT, ENUMLITERALOBJECT, CONSTENUMOBJECT, VARENUMOBJECT, REFOBJECT, REFLISTOBJECT, EXPROBJECT, ACTOBJECT, VALUEPARAMOBJECT, REFPARAMOBJECT, RESULTOBJECT, LOCALVOBJECT, PROGOBJECT Constants: category.value Default value of category (SYMBOLOBJECT) Infix operators: A ? B : C Ternary operator condition ? thenValue : elseValue ( TRUE ? a : b ⇒ a, FALSE ? a : b ⇒ b ) category conv A Conversion of integer to category ( Type of argument A: integer, category conv ord(INTOBJECT) ⇒ INTOBJECT ) category parse A Conversion of string to category ( Type of argument A: string, category parse "FLOATOBJECT" ⇒ FLOATOBJECT, category parse "does not exist" ⇒ EXCEPTION RANGE_ERROR ) Relations: =, <> Functions: ord(A) Ordinal number ( Type of result: integer ) category(A) Conversion of integer to category ( Type of argument A: integer, category(ord(INTOBJECT)) ⇒ INTOBJECT ) str(A) Conversion to string ( Type of result: string, str(CHAROBJECT) ⇒ "CHAROBJECT" ) category(A) Conversion of string to category ( Type of argument A: string, category("FLOATOBJECT") ⇒ FLOATOBJECT, category("does not exist") ⇒ EXCEPTION RANGE_ERROR ) Statements: ignore(A) Ignore value for A range B to C do D end for Loop over all categories from B to C ( Type of argument D: proc ) for A range B downto C do D end for Loop over all categories from B down to C ( Type of argument D: proc )5.28 reference
The type reference describes a reference to an object in the abstract syntax tree (AST) of a program. You cannot access the AST of the program that currently runs. Instead you can parse a program and access its AST. The reference functions are defined in the library "reference.s7i".
Constants: NIL Reference to no element. reference.value Default value of reference (NIL) Relations: =, <> Functions: category(A) Get the category of the referenced object ( Type of result: category, category(NIL) ⇒ EXCEPTION RANGE_ERROR ) str(A) Conversion to string ( Type of result: string ) getType(A) Get the type of the referenced object ( Type of result: type, getType(NIL) ⇒ EXCEPTION RANGE_ERROR ) objNumber(A) Delivers an unique number for each object ( Type of result: integer, objNumber(NIL) ⇒ 0 ) isVar(A) Reference to a variable object ( Type of result: boolean, isVar(NIL) ⇒ EXCEPTION RANGE_ERROR ) formalParams(A) Gets the formal parameters of a function ( Type of result: ref_list, formalParams(NIL) ⇒ EXCEPTION RANGE_ERROR ) localVars(A) Gets the local variables of a function ( Type of result: ref_list, localVars(NIL) ⇒ EXCEPTION RANGE_ERROR, localVars(A) ⇒ EXCEPTION RANGE_ERROR for category(A) <> BLOCKOBJECT ) localConsts(A) Gets the local constants of a function ( Type of result: ref_list, localConsts(NIL) ⇒ EXCEPTION RANGE_ERROR, localConsts(A) ⇒ EXCEPTION RANGE_ERROR for category(A) <> BLOCKOBJECT ) body(A) Gets the body of a function ( body(NIL) ⇒ EXCEPTION RANGE_ERROR, body(A) ⇒ EXCEPTION RANGE_ERROR for category(A) <> BLOCKOBJECT ) resultVar(A) Gets the result variable of a function ( resultVar(NIL) ⇒ EXCEPTION RANGE_ERROR, resultVar(A) ⇒ EXCEPTION RANGE_ERROR for category(A) <> BLOCKOBJECT ) resultInitValue(A) Gets the initialization value of the result object of a function ( resultInitValue(NIL) ⇒ EXCEPTION RANGE_ERROR, resultInitValue(A) ⇒ EXCEPTION RANGE_ERROR for category(A) <> BLOCKOBJECT ) arrayToList(A) Return the array elements as list ( Type of result: ref_list, arrayToList(NIL) ⇒ EXCEPTION RANGE_ERROR, arrayToList(A) ⇒ EXCEPTION RANGE_ERROR for category(A) <> ARRAYOBJECT ) arrayMinIdx(A) Return the minimum index of an array ( Type of result: integer, arrayMinIdx(NIL) ⇒ EXCEPTION RANGE_ERROR, arrayMinIdx(A) ⇒ EXCEPTION RANGE_ERROR for category(A) <> ARRAYOBJECT ) arrayMaxIdx(A) Return the maximum index of an array ( Type of result: integer, arrayMaxIdx(NIL) ⇒ EXCEPTION RANGE_ERROR, arrayMaxIdx(A) ⇒ EXCEPTION RANGE_ERROR for category(A) <> ARRAYOBJECT ) structToList(A) Return the struct elements as list ( Type of result: ref_list, structToList(NIL) ⇒ EXCEPTION RANGE_ERROR, structToList(A) ⇒ EXCEPTION RANGE_ERROR for category(A) <> STRUCTOBJECT ) interfaceToStruct(A) Return the struct to which the interface object points. ( interfaceToStruct(NIL) ⇒ EXCEPTION RANGE_ERROR, interfaceToStruct(A) ⇒ EXCEPTION RANGE_ERROR for category(A) <> INTERFACEOBJECT ) file(A) File name of the referenced object ( Type of result: string, file(NIL) ⇒ EXCEPTION RANGE_ERROR ) line(A) Line number of the referenced object ( Type of result: integer, line(NIL) ⇒ EXCEPTION RANGE_ERROR ) alloc(A) Create a copy of the object referenced by A The object value of the copy is set to NULL getValue(A, reference) Dereference as reference ( Type of result: reference, getValue(NIL, reference) ⇒ EXCEPTION RANGE_ERROR, getValue(A, reference) ⇒ EXCEPTION RANGE_ERROR for category(A) not in {FWDREFOBJECT, REFOBJECT, REFPARAMOBJECT, RESULTOBJECT, LOCALVOBJECT, ENUMLITERALOBJECT, CONSTENUMOBJECT, VARENUMOBJECT} ) getValue(A, ref_list) Dereference as ref_list ( Type of result: ref_list, getValue(NIL, ref_list) ⇒ EXCEPTION RANGE_ERROR, getValue(A, ref_list) ⇒ EXCEPTION RANGE_ERROR for category(A) not in {MATCHOBJECT, CALLOBJECT, REFLISTOBJECT} ) getValue(A, boolean) Dereference as boolean ( Type of result: boolean, getValue(NIL, boolean) ⇒ EXCEPTION RANGE_ERROR, getValue(A, boolean) ⇒ EXCEPTION RANGE_ERROR if A does not refer to FALSE or TRUE ) getValue(A, integer) Dereference as integer ( Type of result: integer, getValue(NIL, integer) ⇒ EXCEPTION RANGE_ERROR, getValue(A, integer) ⇒ EXCEPTION RANGE_ERROR for category(A) <> INTOBJECT ) getValue(A, bigInteger) Dereference as bigInteger ( Type of result: bigInteger, getValue(NIL, bigInteger) ⇒ EXCEPTION RANGE_ERROR, getValue(A, bigInteger) ⇒ EXCEPTION RANGE_ERROR for category(A) <> BIGINTOBJECT ) getValue(A, float) Dereference as float ( Type of result: float, getValue(NIL, float) ⇒ EXCEPTION RANGE_ERROR, getValue(A, float) ⇒ EXCEPTION RANGE_ERROR for category(A) <> FLOATOBJECT ) getValue(A, char) Dereference as char ( Type of result: char, getValue(NIL, char) ⇒ EXCEPTION RANGE_ERROR, getValue(A, char) ⇒ EXCEPTION RANGE_ERROR for category(A) <> CHAROBJECT ) getValue(A, string) Dereference as string ( Type of result: string, getValue(NIL, string) ⇒ EXCEPTION RANGE_ERROR, getValue(A, string) ⇒ EXCEPTION RANGE_ERROR for category(A) <> STRIOBJECT ) getValue(A, bstring) Dereference as bstring ( Type of result: bstring, getValue(NIL, bstring) ⇒ EXCEPTION RANGE_ERROR, getValue(A, bstring) ⇒ EXCEPTION RANGE_ERROR for category(A) <> BSTRIOBJECT ) getValue(A, bitset) Dereference as bitset ( Type of result: bitset, getValue(NIL, bitset) ⇒ EXCEPTION RANGE_ERROR, getValue(A, bitset) ⇒ EXCEPTION RANGE_ERROR for category(A) <> SETOBJECT ) getValue(A, clib_file) Dereference as clib_file ( Type of result: clib_file, getValue(NIL, clib_file) ⇒ EXCEPTION RANGE_ERROR, getValue(A, clib_file) ⇒ EXCEPTION RANGE_ERROR for category(A) <> FILEOBJECT ) getValue(A, program) Dereference as program ( Type of result: program, getValue(NIL, program) ⇒ EXCEPTION RANGE_ERROR, getValue(A, program) ⇒ EXCEPTION RANGE_ERROR for category(A) <> PROGOBJECT ) getValue(A, ACTION) Dereference as ACTION ( Type of result: ACTION, getValue(NIL, ACTION) ⇒ EXCEPTION RANGE_ERROR, getValue(A, ACTION) ⇒ EXCEPTION RANGE_ERROR for category(A) <> ACTOBJECT ) getValue(A, type) Dereference as type ( Type of result: type, getValue(NIL, type) ⇒ EXCEPTION RANGE_ERROR, getValue(A, type) ⇒ EXCEPTION RANGE_ERROR for category(A) <> TYPEOBJECT ) compare(A, B) Compare function ( Type of result: integer ) hashCode(A) Hash function ( Type of result: integer ) Statements: setVar(A, B) Set var flag of referenced object A to B ( Type of argument B: boolean, setVar(NIL, B) ⇒ EXCEPTION RANGE_ERROR ) setCategory(A, B) Set the category of the referenced object A to B ( Type of argument B: category, setCategory(NIL, B) ⇒ EXCEPTION RANGE_ERROR ) setType(A, B) Set the type of the referenced object A to B ( Type of argument B: type, setType(NIL, B) ⇒ EXCEPTION RANGE_ERROR ) setValue(A, B) Set the value of the referenced object A to B ( Type of argument B: ref_list ) setFormalParams(A, B) Set the formal parameters of a function ( Type of argument B: ref_list, setFormalParams(NIL, B) ⇒ EXCEPTION RANGE_ERROR ) ignore(A) Ignore value5.29 ref_list
The type ref_list describes a list of reference objects. The ref_list functions are defined in the library "ref_list.s7i".
Constants: ref_list.EMPTY Empty reference list. ref_list.value Default value of ref_list (ref_list.EMPTY) Infix operators: & Ref_list list concatenation A in B Is element in ref_list ( Type of argument A: reference, Type of result: boolean ) A not in B Is element not in ref_list ( Type of argument A: reference, Type of result: boolean ) Indices: [ A ] Access one ref_list element ( Type of argument A: integer, Type of result: reference, A[1] ⇒ First element, A[length(A)] ⇒ Last element, A[0] ⇒ EXCEPTION INDEX_ERROR, A[succ(length(A))] ⇒ EXCEPTION INDEX_ERROR ) [ A .. B ] Access a sub list ( Type of arguments A and B: integer ) [ A .. ] Access a sub list beginning at position A ( Type of argument A: integer ) [ .. A ] Access a sub list ending at position A ( Type of argument A: integer ) Relations: =, <> Functions: length(A) Length of ref_list ( Type of result: integer, length(ref_list.EMPTY) ⇒ 0 ) make_list(A) Create ref_list with element A ( Type of argument A: reference ) pos(A,B) First position of reference B in ref_list A ( Type of argument B: reference, Type of result: integer ) pos(A,B,C) First position of reference B in ref_list A The search starts at position C of ref_list A ( Type of argument B: reference, Type of argument C: integer, Type of result: integer ) incl(A, B) Include element in list ( Type of argument B: reference ) excl(A, B) Exclude element from list ( Type of argument B: reference ) Statements: A &:= B Append B to A ( A &:= B ⇒ A := A & B ) A @:= [B] C Assign C to element B of ref_list A ( Type of argument B: integer, Type of argument C: reference, A @:= [B] C ⇒ A := A[..pred(B)] & make_list(C) & A[succ(B)..], A @:= [0] C ⇒ EXCEPTION INDEX_ERROR, A @:= [succ(length(A))] C ⇒ EXCEPTION INDEX_ERROR ) ignore(A) Ignore value for forVar range aRefList do statements end for Loop over all elements of a ref_list ( Type of argument forVar: reference, Type of argument statements: proc ) for forVar range aRefList until condition do statements end for Loop over all elements of a ref_list until condition is TRUE Check the condition before the statements in the loop body are executed. ( Type of argument forVar: reference, Type of argument condition: boolean, Type of argument statements: proc )5.30 program
The type program describes a Seed7 program. You cannot access the program that currently runs. Instead you can parse a program and access its data. The program functions are defined in the library "progs.s7i".
Constants: program.EMPTY Empty program. program.value Default value of program (program.EMPTY) Relations: =, <> Functions: name(A) Name of program A without path and extension path(A) Absolute path of program A parseFile(A) Parse the file with the name A ( Type of argument A: string ) parseStri(A) Parse the string A ( Type of argument A: string ) evaluate(A, B) Evaluate the expression B which is part of program A ( Type of result: reference, Type of argument B: reference ) sysVar(A, B) Return a reference of the system var B of program A ( Type of result: reference, Type of argument B: string ) errorCount(A) Number of errors in the program A ( Type of result: integer ) globalObjects(A) List of global defined objects in the program A ( Type of result: ref_list ) syobject(A, B) Return object with name B in program A ( Type of result: reference, Type of argument B: string ) match(A, B) Return object from program A which matches B ( Type of result: reference, Type of argument B: ref_list ) Statements: execute(A) Execute the program referred by A ignore(A) Ignore value5.31 ptr
The type ptr baseType describes a pointer to an object of a baseType. With
const type: ptrType is ptr baseType;a new pointer type ptrType is declared.
Constants: ptrType.NIL Reference to no element Prefix operators: & Address of ( Type of operand: baseType ) Postfix operators: ^ Dereference ( Type of result: baseType ) Infix operators: ptrType conv A Conversion from reference A to ptrType reference conv A Conversion from ptrType A to reference Relations: =, <> Functions: base_type(ptrType) Gets the baseType of a ptrType ( Type of argument ptrType: type )5.32 func
The type func baseType describes functions which return a baseType. For example: func integer describes an integer function.
Values: ord, str, abs, sqrt, rand, A + B, A * B, A ** B, trunc, round, sin, cos, compare, hashCode, pos, replace, trim, length, keys, color, dayOfWeek, ... Every function declared with const func ... is a value Prefix operators: func result var baseType: resultVariable is baseType.value; begin statements end func Create a baseType function ( Type of 'statements': proc, Type of result: func baseType ) func result var baseType: resultVariable is baseType.value; local declarations begin statements end func Create a baseType function with local variables ( Type of 'declarations': proc, Type of 'statements': proc, Type of result: func baseType ) return value Create a function with the result type of value ( Type of value: anyType - which means: any type, Type of result: func anyType )Functions are declared as constants with a func type and are initialized with a func result ... or return ... operator. For example:
const func integer: tak (in integer: x, in integer: y, in integer: z) is func result var integer: tak is 0; begin if y >= x then tak := z; else tak := tak(tak(pred(x), y, z), tak(pred(y), z, x), tak(pred(z), x, y)); end if; end funcAnother example using the return function:
const func float: convertRadianToDegree (in float: x) is return x * 57.295779513082320876798154814114;This return function should not be confused with a return statement. It is important to note that no return statement exists. The declaration for the return function is as follows:
const func func aType: return (ref func aType param) is action "PRC_RETURN"; const func func aType: return (ref aType param) is action "PRC_RETURN";The func types can also be used for parameters. Functions which use a func parameter do not evaluate this parameter before the function call. Instead this parameter can be evaluated zero or more times inside the function. For example:
const func boolean: (in boolean: first) and (in func boolean: second) is func result var boolean: conjunction is FALSE; begin if first then conjunction := second; end if; end func;Here the second parameter is only evaluated if the first parameter is TRUE.
5.33 varfunc
The type varfunc baseType describes functions which return a baseType variable. For example: A function which returns an integer variable is described with varfunc integer. A call of a varfunc can be used at the left side of an assignment. Generally a varfunc can be used at places where an inout parameter requests a variable.
Prefix operators: return var value; Create a varfunc which returns the variable 'value' ( Type of value: anyType - which means: any type, Accessright of value: var = A variable, an inout parameter or a varfunc Type of result: varfunc anyType )Varfunctions are used to express array, hash and struct accesses which can be used at the left and right side of an assignment. The access function for a hash is defined as:
const func baseType: (in hashType: aHash) [ (in keyType: aKey) ] is return INDEX(aHash, aKey, hashCode(aKey), hashType.keyCompare); const varfunc baseType: (inout hashType: aHash) [ (in keyType: aKey) ] is return var INDEX(aHash, aKey, hashCode(aKey), hashType.keyCompare);The example above shows that functions with in and inout parameters can be overloaded. At the right side of an assignment the func is called, while at the left side the varfunc is called. That way the access functions of arrays, hashes and structs can be used in the usual way.
5.34 void
The type void describes the empty type.
Value: empty This is the only value of the type void. Constants: void.value Default value of void (empty)
5.35 proc
The type proc describes procedures. The type proc is defined as func void.
Values: noop; while ... do ... end while; repeat ... until ... ; writeln( ... ); A := B; incr(A); ... Every procedure declared with const proc: ... is a value The procedure 'noop' does nothing and is used as empty procedure. Prefix operators: func begin statements end func Create a procedure ( Type of 'statements': proc, Type of result: proc ) func local declarations begin statements end func Create a procedure with local variables ( Type of 'declarations': proc, Type of 'statements': proc, Type of result: proc )5.36 type
The type type describes all types. Examples of type declarations are:
const type: intArrayType is array integer; const type: arrayIndexChar is array [char] string; const type: hashType is hash [string] intArrayType; const type: setType is set of char;Note that type declarations should always be made at the top level. E.g.:
$ include "seed7_05.s7i"; const type: intArrayType is array integer; const proc: main is func local var intArrayType: arr is [](1, 2); begin writeln(length(arr)); end func;If the type declaration of intArrayType would be inside of the local declaration block you would receive a parsing error:
*** tst249.sd7(6):52: Match for {var intArrayType : {arr } is {[ ] {1 , 2 } } } failed var intArrayType: arr is [](1, 2);A local declaration block is parsed completely before it is executed. This causes that intArrayType is not defined during the parsing.
Values: void, boolean, integer, rational, float, char, string, reference, ref_list, color, time, duration file, proc, type, ... Every type declared with const type: ... is a value The type void is used as empty type. Constants: type.value Default value of type (void) Prefix operators: func Function type ( func char ⇒ Function which returns a char ) varfunc Varfunc type ( varfunc char ⇒ Function which returns a char variable ) ptr Pointer type ( ptr bitset ⇒ Pointer to bitset ) array Array type ( array string ⇒ Array of strings ) set of Set type ( set of integer ⇒ Set of integer ) subtype Create subtype of existing type ( subtype char ⇒ Subtype of char ) Infix operators: A ? B : C Ternary operator condition ? thenValue : elseValue ( TRUE ? a : b ⇒ a, FALSE ? a : b ⇒ b ) Relations: =, <> Functions: str(A) Conversion to string ( Type of result: string ) newtype Create a new type gentype Generate a type gensub(A) Generate a subtype typeof(A) Get the type of an expression ( Type of argument A: Defined for all types, typeof(1) ⇒ integer, typeof("asdf") ⇒ string ) isFunc(A) Is this type a func type ( Type of result: boolean, isFunc(func char) ⇒ TRUE, isFunc(varfunc char) ⇒ FALSE ) isFunc(char) ⇒ FALSE ) isVarfunc(A) Is this type a varfunc type ( Type of result: boolean, isVarfunc(func char) ⇒ FALSE, isVarfunc(varfunc char) ⇒ TRUE, isVarfunc(char) ⇒ FALSE ) resultType(A) Get the result type of a func or varfunc type ( resultType(func char) ⇒ char, resultType(proc) ⇒ void, resultType(integer) ⇒ EXCEPTION RANGE_ERROR ) isDerived(A) Is this type derived from another type ( Type of result: boolean, isDerived(subtype char) ⇒ TRUE ) meta(A) Get the type from which type A is derived ( meta(subtype char) ⇒ char ) base_type(A) Get the base type of an array, pointer or set type ( base_type(array char) ⇒ char, base_type(ptr string) ⇒ string, base_type(set of integer) ⇒ integer ) typeNumber(A) Get an unique number for a type ( Type of result: integer ) typeObject(A) Get a unique object (match object) of a type ( Type of result: reference ) compare(A, B) Compare function ( Type of result: integer ) hashCode(A) Hash function ( Type of result: integer ) Statements: addInterface(A, B) Adds the interface type B to the implementation type A const aType: name is value Declare constant 'name' with 'value' var aType: name is value Declare variable 'name' with 'value' ignore(A) Ignore value5.37 object
The type object is used as meta type for various types. This allows defining common operations for all this types. The type object is not used as element type for container classes since this can be done much better and type safe with abstract data types like array, set, hash and others.
Functions: TRACE_OBJ(A) Write internal information5.38 expr
The type expr is used to describe unmatched expressions. These are expressions where the recognizing of the functions and the type check is not done yet. This is used for example in the definition of function bodies.
Functions: WRITE_EXPR(A) Write expr A to FILE OUT6. PARAMETERS
The following sub-chapters introduce the parameter types of Seed7.
Parameter Evaluation strategy Assignment to formal parameter val aType: name call-by-value forbidden ref aType: name call-by-reference forbidden in aType: name depends on the type forbidden in var aType: name call-by-value allowed (no effect on actual parameter) inout aType: name call-by-reference allowed (changes actual parameter) in func aType: name call-by-name forbidden 6.1 'val' parameter
Value parameters are introduced with the keyword 'val' (e.g.: val string: stri). A value parameter copies the value of the actual parameter. The formal 'val' parameter cannot be changed inside the function. Value parameters are used, when copying is cheap or when copying is necessary for the correct behavior. The function below appends a comma and a string to the variable 'globalStri':
const proc: appendStri (val string: stri) is func begin globalStri &:= ","; globalStri &:= stri; end func;After doing
globalStri &:= "a"; appendStri(globalStri);
the variable globalStri contains the value "a,a". If the function header would be
const proc: appendStri (in string: stri) is functhe variable globalStri would contain the value "a,a,". This difference is because of the following reasons:
For arrays 'in' parameters are equal to 'ref' parameters. When appendStri is called with globalStri as parameter an unwanted side effect takes place: Every change of globalStri changes also the 'ref' parameter stri. Changes to the 'ref' parameter would also change the global variable. Such unwanted side effects can also take place between parameters (when at least one parameter is an 'inout' parameter).
In most cases such unwanted side effects are impossible or can be avoided easily. An 'in' parameter should be preferred over an 'val' parameter, when possible.
- Semantics:
- When calling a function a formal 'val' parameter gets its value from the corresponding actual parameter. This is done with a create procedure ( ::= ). Inside the function it is only possible to read a formal 'val' parameter. Changing a formal 'val' parameter is not possible. When a function is left a 'destr' procedure is called for every 'val' parameter. Formal 'val' parameters have the access right 'const'.
- Syntax:
- val_parameter ::=
- 'val' type_expression ':' identifier_declaration |
'val' type_expression 'param' .Declaration:
$ syntax expr: .val.().param is -> 40; $ syntax expr: .val.(). : .(expr) is -> 40; const func f_param: val (ref type param) param is action "DCL_VAL1"; const func f_param: val (ref type param) : (ref expr param) is action "DCL_VAL2";6.2 'ref' parameter
Reference parameters are introduced with the keyword 'ref' (e.g.: ref array string: arr). A reference parameter refers to the value of the actual parameter. The formal 'ref' parameter cannot be changed inside the function. Reference parameters are used, when copying is expensive and referring to the value does not change the correct behavior. The function below defines the primitive action for the semicolon operator:
const proc: (ref void: statement1) ; (ref void: statement2) is noop;In this definition and other definitions of primitive actions 'ref' parameters are used. For normal functions usually 'in' parameters are used instead of 'ref' parameters:
const func integer: total_length (in array string: arr) is func result var integer: lengthSum is 0; local var integer: index is 0; begin for index range 1 to length(arr) do lengthSum +:= length(arr[index]); end for; end func;Above function could also be defined with the following function head:
const func integer: total_length (ref array string: arr) is funcSince for array types (and also for struct types) 'in' parameters are defined to act as 'ref' parameters both definitions are equal. An 'in' parameter should be preferred over an 'ref' parameter, when possible.
- Semantics:
- When calling a function a formal 'ref' parameter is set to refer to the corresponding actual parameter. Inside the function it is only possible to read a formal 'ref' parameter. Changing a formal 'ref' parameter is not possible. Formal 'ref' parameters have the access right 'const'.
- Syntax:
- ref_parameter ::=
- 'ref' type_expression ':' identifier_declaration |
'ref' type_expression 'param' .Declaration:
$ syntax expr: .ref.().param is -> 40; $ syntax expr: .ref.(). : .(expr) is -> 40; const func f_param: ref (ref type param) param is action "DCL_REF1"; const func f_param: ref (ref type param) : (ref expr param) is action "DCL_REF2";6.3 'in' parameter
Input parameters are introduced with the keyword 'in' (e.g.: in integer: number). Depending on the type an input parameter is either a value or a reference parameter. The formal 'in' parameter cannot be changed inside the function. The function below checks if a given number is a prime number:
const func boolean: is_prime (in integer: number) is func result var boolean: prime is FALSE; local var integer: count is 2; begin if number = 2 then prime := TRUE; elsif number >= 3 then while number rem count <> 0 and count * count <= number do incr(count); end while; prime := number rem count <> 0; end if; end func;The following function defines the ex (outer) product:
const func array array integer: (in array integer: a) ex (in array integer: b) is func result var array array integer: product is 0 times 0 times 0; local var integer: index1 is 1; begin product := length(a) times length(b) times 0; for index1 range 1 to length(a) do for index2 range 1 to length(b) do product[index1][index2] := a[index1] * b[index2]; end for; end for; end func;Although both examples use 'in' parameters the parameter in the first example is actually a 'val' parameter while the parameters in the second example are actually 'ref' parameters. When a new type is created with the 'newtype' function it is necessary to specify the meaning of the 'in' parameter. This is done with a call of the IN_PARAM_IS_VALUE or the IN_PARAM_IS_REFERENCE function with the new generated type as parameter. If a new type is created with the 'subtype' function this specification is optional since the base type has already a specification of the 'in' parameter.
- Semantics:
- Depending on the type an 'in' parameter is equivalent to an 'val' (call by value) parameter or to an 'ref' (call by reference) parameter. Formal 'in' parameters have the access right 'const'.
- Syntax:
- in_parameter ::=
- 'in' type_expression ':' identifier_declaration .
Declaration:
$ syntax expr: .in.().param is -> 40; $ syntax expr: .in.(). : .(expr) is -> 40; const func f_param: in (ref type param) param is action "DCL_IN1"; const func f_param: in (ref type param) : (ref expr param) is action "DCL_IN2"; const proc: IN_PARAM_IS_VALUE (ref type: aType) is action "TYP_SET_IN_PARAM_VALUE"; const proc: IN_PARAM_IS_REFERENCE (ref type: aType) is action "TYP_SET_IN_PARAM_REF";6.4 'in var' parameter
Value parameters that can be changed inside the function are introduced with the keywords 'in var' (e.g.: in var integer: a). The value of the actual parameter is copied. Changes to the formal 'in var' parameter have no effect outside the function. The function below computes the greatest common divisor:
const func integer: gcd (in var integer: a, in var integer: b) is func result var integer: gcd is 0; local var integer: help is 0; begin while a <> 0 do help := b rem a; b := a; a := help; end while; gcd := b; end func;
- Semantics:
- When calling a function a formal in var parameter gets its value from the corresponding actual parameter. This is done with a create procedure ( ::= ). Inside the function it is possible to read and change a formal in var parameter. Changing a formal in var parameter has no effect on the actual parameter. When a function is left a 'destr' procedure is called for every in var parameter. Formal in var parameters have the access right var.
- Syntax:
- in_var_parameter ::=
- 'in var' type-expression ':' identifier_declaration .
Declaration:
$ syntax expr: .in.var.().param is -> 40; $ syntax expr: .in.var.(). : .(expr) is -> 40; const func f_param: in var (ref type param) param is action "DCL_IN1VAR"; const func f_param: in var (ref type param) : (ref expr param) is action "DCL_IN2VAR";6.5 'inout' parameter
Reference parameters, that can be changed inside the function, are introduced with the keyword 'inout' (e.g.: inout integer: number). A reference parameter refers to the value of the actual parameter. Changes to the formal 'inout' parameter effect also the actual parameter. The procedure below doubles the given parameter 'number':
const proc: double (inout integer: number) is func begin number := 2 * number; end func;
- Semantics:
- When calling a function a formal 'inout' parameter is set to refer to the corresponding actual parameter. Inside the function it is possible to read and change a formal 'inout' parameter. Changing a formal 'inout' parameter changes the actual parameter as well. Formal 'inout' parameters have the access right 'var'.
- Syntax:
- inout_parameter ::=
- 'inout' type_expression ':' identifier_declaration .
Declaration:
$ syntax expr: .inout.().param is -> 40; $ syntax expr: .inout.(). : .(expr) is -> 40; const func f_param: inout (ref type param) param is action "DCL_INOUT1"; const func f_param: inout (ref type param) : (ref expr param) is action "DCL_INOUT2";6.6 Call-by-name parameter
Call-by-name is an evaluation strategy for parameters. Call-by-name parameters are not introduced with a keyword. All parameters with a function type like func boolean or proc are a call-by-name parameters. The actual call-by-name parameter is not evaluated before the function is called. When the function is executed the call-by-name parameter might be executed once, many times or not at all.
For normal (not call-by-name) parameters the following holds: When the function is called the actual parameter expressions are evaluated and the results of the evaluation are forwarded to the function. Assume number has the value 12 and the following statement is executed:
seek(aFile, number + 5);The expression number + 5 is evaluated to 17 before seek is called. The statement actually executed is:
seek(aFile, 17);
The definition of seek requests that its 2nd parameter must be an integer and not an integer expression:
const proc: seek (inout file: aFile, in integer: position) is ...This triggers the evaluation of number + 5. Compare this to:
while number > 0 do number -:= 5; end while;The while-statement is not called with the result of number > 0. This would not work for the loop condition. The while-statement receives the expression number > 0 instead. This way the while-statement can decide how often number > 0 is evaluated. This contradicts the claim from above that actual parameter expressions are evaluated before the function is called. Obviously the condition parameter behaves different. This behavior is triggered by the declaration of the while-statement:
const proc: while (in func boolean: condition) do (in proc: statement) end while is ...The parameter condition has the type func boolean which is exactly the type of the expression number > 0. For this reason number > 0 is forwarded to the while-statement without evaluating it. All parameters with a func type have this behavior. The common name for all of them is call-by-name parameter. All call-by-name parameters are not evaluated before the function is called.
Examples of normal and call-by-name parameters:
Normal parameter Call-by-name parameter in boolean: name in func boolean: name in integer: name in func integer: name in string: name in func string: name The type proc can also be used to define a call-by-name parameter:
const proc: possiblyDo (in proc: statement) is func begin if flipCoin then statement; end if; end func;The function possiblyDo can be called with any statement (procedure):
possiblyDo(writeln("hello world"));
6.7 Symbol parameter
Some functions need symbols at fixed places in the parameter list. The following IF-statement requests the keywords 'THEN', 'END' and 'IF' at specific places:
IF condition THEN statement END IF;After defining the syntax of this IF-statement with
$ syntax expr: .IF.().THEN.().END.IF is -> 25;the semantic can be defined with:
const proc: IF (in boolean: condition) THEN (in proc: statement) END IF is func begin case condition of when {TRUE}: statement; end case; end func;The symbol parameters are just written outside the parentheses. A call of this statement could be:
IF value < maximum THEN write(value) END IF;
- Semantics:
- Symbol parameters must be defined in a syntax definition and in a corresponding semantic definition. In the semantic definition symbol parameters are written outside of the parentheses. In the actual parameter list the corresponding symbol of the formal parameter list must be written.
- Syntax:
- symbol_parameter ::=
- name_identifier | special_identifier .
6.8 'attr' parameter
This declaration associates a name to the type 'char':
const string: name (attr char) is "char";This 'name' can be used as follows:
writeln(name(char));It is possible to overload such declarations:
const string: name (attr boolean) is "boolean"; const string: name (attr float) is "float";An 'attr' parameter can be used in a function also:
const func char: (attr char) parse (in string: stri) is return stri[1];
- Semantics:
- The actual parameter which corresponds to an 'attr' parameter must be the type mentioned in the declaration of the 'attr' parameter. An 'attr' parameter does not declare a formal parameter variable which could be used inside a function.
- Syntax:
- attr_parameter ::=
- 'attr' type_expression .
7. OBJECT ORIENTATION
Many people will be familiar with object-orientation from languages like C++, Smalltalk, and Java. Seed7 follows the route of declaring "interfaces". An interface is a common set of operations supported by an object. For instance cars, motorcycles, lorries and vans can all accelerate or brake, if they are legal to drive on the road they can all indicate right and left.
This view isn't new. C provides a primitive form of interfacing. When you write to a 'file' in C you use the same interface ('fprintf') for hard disk files, console output and printer output. The implementation does totally different things for these files. Unix has used the "everything is a file" philosophy for ages (even network communication uses the 'file' interface (see sockets)).
For short: An interface defines which methods are supported while the implementation describes how this is done. Several types with different method implementations can share the same interface.
7.1 Interface and implementation
Seed7 uses interface types and implementation types. Objects declared with an interface type refer to a value which has an implementation type. This situation is described with the following picture:
+----------------+ declared | interface |<--- interface type object: | object | (known at compile-time) +----------------+ | | refer to value V +----------------+ value: | implementation |<--- implementation type | object | (unknown at compile-time) +----------------+The interface type of an object can always be determined at compile-time. Several implementation types can belong to one interface type (they implement the interface type). E.g.: The types null_file, external_file and socket implement the file interface. On the other hand: An implementation type can also implement several interface types. An interface object can only refer to a value with an implementation type that implements the interface. E.g.: A shape variable cannot refer to a socket.
A new interface type is declared with:
const type: shape is new interface;Interface (DYNAMIC) functions describe what can be done with objects of an interface type. An interface function for a shape could be:
const proc: draw (in shape: aShape, inout window: aWindow) is DYNAMIC;Now we know that it is possible to 'draw' a shape to a window. How this drawing is done is described in the implementation type. An implementation type for shape is:
const type: circle is new struct var integer: radius is 0; end struct;The fact that the type circle is an implementation type of shape is described with:
type_implements_interface(circle, shape);The function which implements 'draw' for circles is:
const proc: draw (in circle: aCircle, inout window: aWindow) is func begin circle(aWindow.win, aWindow.currX, aWindow.currY, aCircle.radius, aWindow.foreground); end func;In the classic OOP philosophy a message is sent to an object. To express this situation classic OO languages use the following method call syntax:
param1.method(param2, param3)In the method the receiving object is referred with 'self' or 'this'. The other parameters use the same mechanisms as in procedural programming languages (value or reference parameter). Seed7 uses a different approach: Instead of an implicit defined 'self' or 'this' parameter, all formal parameters get a user defined name. To reflect this symmetric approach a Seed7 method call looks like a normal function call:
method(param1, param2, param3)The definition of the 'draw' function above uses the formal parameter 'aCircle' in the role of a 'self' or 'this' parameter. Formal parameters which have an implementation type are automatically in the role of a 'self' or 'this' parameter.
A function to create new circle objects can also be helpful:
const func circle: circle (in integer: radius) is func result var circle: aCircle is circle.value; begin aCircle.radius := radius; end func;Now we can draw a circle object with:
draw(circle(50), aWindow);Although the statement above does exactly what it should do and the separation between interface and implementation is obvious, most OO enthusiasts would not be thrilled. All decisions which implementation function should be called can be made at compile time. To please the OO fans such decisions must be made at runtime. This decision process is called dynamic dispatch.
7.2 Dynamic dispatch
When the implementation types have different implementations of the same function (method) a dynamic dispatch is necessary. The type of the value, referred by an interface object, is not known at compile-time. In this case the program must decide at runtime which implementation of the function should be invoked. This decision is based on the implementation type of the value (referred by the interface object). A dynamic dispatch only takes place when a DYNAMIC (or interface) function is called. When the program is analyzed (in the interpreter or compiler) the interface functions take precedence over normal functions when both are to be considered.
To demonstrate the dynamic dispatch we define the type line which also implements a shape:
const type: line is new struct var integer: xLen is 0.0; var integer: yLen is 0.0; end func; type_implements_interface(line, shape); const proc: draw (in line: aLine, in window: aWindow) is func begin line(aWindow.win, aWindow.currX, aWindow.currY, aLine.xLen, aLine.yLen, aWindow.foreground); end func; const func line: line (in integer: xLen, in integer: yLen) is func result var line: aLine is line.value; begin aLine.xLen := xLen; aLine.yLen := yLen; end func;In addition we define a normal (not DYNAMIC) function which draws shapes to the 'currWindow':
const proc: draw (in shape: aShape) is func begin draw(aShape, currWindow); end func;In the example above the call of the (DYNAMIC) interface function is 'draw(aShape, currWindow)'. The interface function declared with
const proc: draw (in shape: aShape, inout window: aWindow) is DYNAMIC;decides which implementation function has to be called. The dynamic dispatch works as follows:
- For all parameters which have an interface type the parameter is replaced with its value. In this case the parameter 'aShape' is replaced by a value of type circle or line.
- The same logic as in the analyze part of the compiler is used to find the matching function. In this search normal functions take precedence over interface functions.
- When a matching function is found it is called.
This process describes the principal logic of the dynamic dispatch. In practice it is not necessary to execute the analyze part of the compiler during the runtime. It is possible to simplify this process with tables and function pointers.
7.3 Inheritance
When a new struct type is defined it is possible to inherit from an existing struct type. E.g.:
const type: external_file is sub null_file struct var clib_file: ext_file is PRIMITIVE_NULL_FILE; var string: name is ""; end struct;That way the type external_file inherits the fields and methods of null_file, which is declared as:
const type: null_file is new struct var char: bufferChar is '\n'; end struct;In most situations it makes sense when the implementation types inherit from a basic implementation type such as null_file. That way it is possible to define functions which are inherited by all derived implementation types. In the standard library getln is such a function:
const func string: getln (inout null_file: aFile) is func result var string: stri is ""; local var string: buffer is ""; begin buffer := gets(aFile, 1); while buffer <> "\n" and buffer <> "" do stri &:= buffer; buffer := gets(aFile, 1); end while; aFile.bufferChar := buffer[1]; end func;All inherited types of null_file inherit the function getln, but they are also free to redefine it. In the getln function above the function call 'gets(aFile, 1)' uses the (DYNAMIC) interface function:
const func string: gets (inout file: inFile, in integer: maxLength) is DYNAMIC;In other OO languages the distinction between interface type and basic implementation type is not done. Such languages either use a dynamic dispatch for every method call (as Java does) or need a keyword to request a dynamic dispatch (as C++ does with the 'virtual' keyword).
When assignments take place between inherited implementation types it is important to note that structure assignments are done with (deep) copies. Naturally such assignments can only copy the elements that are present in both structures. In the following example just the null_file elements are copied from 'anExternalFile' to 'aNullFile':
const proc: example is func local var null_file: aNullFile is null_file.value; var external_file: anExternalFile is external_file.value; begin aNullFile := anExternalFile; write(aNullFile, "hello"); end func;Although the variable 'anExternalFile' is assigned to 'aNullFile', the statement 'write(aNullFile, "hello")' calls the write function (method) of the type null_file.
A new interface type can also inherit from an existing interface type:
const type: shape is sub object interface;Although inheritance is a very powerful feature it should be used with care. In many situations it makes more sense that a new type has an element of another type (so called has-a relation) instead of inheriting from that type (so called is-a relation).
7.4 Class methods
Many object-oriented programming languages support methods that are associated with a class instead of an instantiated object. Such methods are called class methods or static methods. Seed7 supports class methods via attribute ('attr') parameters which allow that a function is attached to a type:
const func circle: create (attr circle, in integer: radius) is return circle(radius);This 'create' function is attached to the type circle and can be called with
create(circle, 10)
Many languages require that the class name must precede the method name when a class method is called (E.g. 'circle::create(10)' in C++). In contrast to that 'attr' parameters are not restricted to a specific parameter position. They can be used in any parameter position as in the following example:
const func circle: create (in integer: radius, attr circle) is return circle(radius);This function can be called with
create(10, circle)
Attribute parameters can be used for any type not just for interface and implementation types. Objects which do not have a function type such as a character constant can also be attached to a type:
const char: (attr char) . value is ' ';This way attributes can be used to specify properties of a type such as its default 'value'. Programming languages such as Seed7 which support function definitions outside a class can also use normal functions instead of class methods. It is a matter of taste if a function should be grouped to a type or if it should exist stand alone and is called with:
circle(10)
7.5 Multiple dispatch
The Seed7 object system allows multiple dispatch (not to be confused with multiple inheritance). The methods are not assigned to one type (class). The decision which function (method) is called at runtime is done based upon the types of several arguments. The classic object orientation is a special case where a method is connected to one class and the dispatch decision is done based on the type of the 'self' or 'this' parameter. The classic object orientation is a single dispatch system.
In the following example the type Number is introduced which is capable to unify numerical types. The type Number is an interface type which defines the interface function for the '+' operation:
const type: Number is sub object interface; const func Number: (in Number: a) + (in Number: b) is DYNAMIC;The interface type Number can represent an 'Integer' or a 'Float':
const type: Integer is new struct var integer: data is 0; end struct; type_implements_interface(Integer, Number); const type: Float is new struct var float: data is 0.0; end struct; type_implements_interface(Float, Number);The declarations of the converting '+' operators are:
const func Float: (in Integer: a) + (in Float: b) is func result var Float: sum is Float.value; begin sum.data := flt(a.data) + b.data; end func; const func Float: (in Float: a) + (in Integer: b) is func result var Float: sum is Float.value; begin sum.data := a.data + flt(b.data); end func;The declarations of the normal '+' operators (which do not convert) are:
const func Integer: (in Integer: a) + (in Integer: b) is func result var Integer: sum is Integer.value; begin sum.data := a.data + b.data; end func; const func Float: (in Float: a) + (in Float: b) is func result var Float: sum is Float.value; begin sum.data := a.data + b.data; end func;The type Number can be extended to support other operators and there can be also implementations using complex, bigInteger, bigRational, etc. . That way Number can be used as universal type for math calculation. Further extending can lead to a universal type. Such a universal type is loved by proponents of dynamic typed languages, but there are also good reasons to have distinct types for different purposes.
7.6 Replacing pointers with interface types
Many languages have the concept of a pointer. It is possible to implement data structures, such as lists and trees, with pointers. Although Seed7 supports the concept of a pointer, they are not well suited to describe such data structures. Instead of pointers interface types can be used. This way list, trees and other advanced data structures can be defined.
The following example shows how to do this: The interface type element will be used as "pointer":
const type: element is new interface;An implementation type for the empty element (emptyElement) can be used as basic implementation type from which other implementation types can inherit:
const type: emptyElement is new struct end struct;That the implementation type emptyElement implements the interface type element is described with:
type_implements_interface(emptyElement, element);Since every Seed7 expression has exactly one type, it is necessary to define a special 'NIL' value (used with 'element.NIL') for the type element:
const element: (attr element) . NIL is emptyElement.value;Now the struct with two "pointers" and an integer can be declared:
const type: treeElement is sub emptyElement struct var element: left is element.NIL; var element: right is element.NIL; var integer: item is 0; end struct;Finally the type treeElement is defined as implementation of the type element:
type_implements_interface(treeElement, element);To allow the direct access to the structure elements 'left', 'right' and 'item' for objects of type element the following declarations are necessary:
const func element: (ref element: anElem).left is DYNAMIC; const varfunc element: (inout element: anElem).left is DYNAMIC; const func element: (ref element: anElem).right is DYNAMIC; const varfunc element: (inout element: anElem).right is DYNAMIC; const func integer: (ref element: anElem).item is DYNAMIC; const varfunc integer: (inout element: anElem).item is DYNAMIC;When all this was declared the following code is possible:
const proc: addItem (inout element: anElem, in integer: item) is func begin if anElem = element.NIL then anElem := xalloc(treeElement.value); anElem.item := item; elsif item < anElem.item then addItem(anElem.left, item); elsif item > anElem.item then addItem(anElem.right, item); end if; end func; const proc: listItems (in element: anElem) is func begin if anElem <> element.NIL then listItems(anElem.left); write(" " <& anElem.item); listItems(anElem.right); end if; end func; const func integer: sum (in element: anElem) is func result var integer: sum is 0; begin if anElem <> element.NIL then sum := anElem.item + sum(anElem.left) + sum(anElem.right); end if; end func;New elements can be created with the function 'xalloc'. This way interface and implementation types help to provide the pointer functionality.
Pointers and interface types are not always the best solution. Abstract data types like dynamic arrays, hash tables, struct types and set types can also be used to declare data structures.
8. FILE INPUT AND OUTPUT
Files are used for communication in various ways. For example: To write strings on the screen we use the following statements:
write("hello world"); writeln;The procedure write writes a given string and writeln means: Write newline. We can also write data of various types with 'write':
write("result = "); write(number div 5); write(" "); writeln(not error);The 'writeln' above writes data and then terminates the line. This is equal to a 'write' followed by a 'writeln'. Instead of multiple write statements the <& operator can be used to concatenate the elements to be written:
writeln("result = " <& number div 5 <& " " <& not error);The <& operator is overloaded for various types and is present it three variants:
- string <& otherType: In this case the right operand is converted to a string before the concatenation takes place.
- otherType <& string: In this case the left operand is converted to a string before the concatenation takes place.
- string <& string: In this case the two operands are concatenated.
This allows chaining concatenations like in:
write(next_time <& " is " <& booleanExpression);Several objects can be concatenated in a chain, if the first or the second object is a string.
We can also read data from the keyboard:
write("Amount? "); read(amount);
The user is allowed to use Backspace and sends the input to the program with the Return key. To let the user respond with the Return key we can write:
writeln("Type RETURN"); readln;
To read a line of data we can use 'readln':
write("Your comment? "); readln(user_comment_string);
In the previous examples all 'read' statements read from the file IN and all 'write' statements write to the file OUT. The files IN and OUT are initialized with STD_IN and STD_OUT which are the stdin and stdout files of the operating system. (Usually the keyboard and the screen). If we want to write to other files we use write statements with the file as first parameter. To write a line of text to the file "info.fil" we use the following statements:
info_file := open("info.fil", "w"); writeln(info_file, "This is the first line of the info file."); close(info_file);First the external file is opened for writing and then it is used. To read the file back in the string 'stri' we write:
info_file := open("info.fil", "r"); readln(info_file, stri); close(info_file);It is also possible to write values of other types to 'info_file':
writeln(info_file, number);Here the 'number' is converted to a string which is written to the file. A 'number' is read back with:
readln(info_file, number);For doing I/O to a window on the screen we write:
window1 := openWindow(screen, 10, 10, 5, 60); box(window1); setPos(window1, 3, 1); write(window1, "hello there");
This opens the window 'window1' on the 'screen' at the position 10, 10. This window has 5 lines and 60 columns. A box (of characters: - | + ) is written to surround the 'window1' and finally the string "hello there" is written in the window 'window1' at Position 3, 1. If we want to clear the 'window1' we write:
clear(window1);Files can be used for much more things. Here is a list of goals for an input/output system:
- A concept which provides conversions from arbitrary types to strings and back.
- Basic input and output operations to process a file character wise, word wise or line wise.
- Input and output statements which combine input with conversion respectively conversion with output.
- Simple read and write statements for standard input and output for arbitrary types.
- Standard input and output files and the possibility to route the standard I/O to any file.
- Access to operating system files and devices.
- An interface which allows the user to define his own file types.
In the following sub-chapters we discuss each of these goals.
8.1 Conversion to strings and back
We archive the goal of doing I/O for arbitrary types with two conversion functions. In order to do I/O with a type the str and parse functions must be defined for that type. As an example we show the conversion functions for the type boolean:
const func string: str (in boolean: aBool) is func result var string: stri is ""; begin if aBool then stri := "TRUE"; else stri := "FALSE"; end if; end func; const func boolean: (attr boolean) parse (in string: stri) is func result var boolean: aBoolean is FALSE; begin if stri = "TRUE" then aBoolean := TRUE; elsif stri = "FALSE" then aBoolean := FALSE; else raise RANGE_ERROR; end if; end func;The str function must deliver a corresponding string for every value of the type. The parse operator parses a string and delivers the converted value as result. If the conversion is not successful the exception RANGE_ERROR is raised. The attribute used with parse allows that it is overloaded for different types.
After defining the str and parse functions for a type the enable_io function can be called for this type as in:
enable_io(boolean);
The enable_io template declares various io functions like 'read', 'write' and others for the provided type (in this example boolean). If only output (or only input) is needed for a type it is possible to define just str (or parse) and activate just enable_output (or enable_input).
There is also a formatting operator called lpad which is based on the str function. The statements
write(12 lpad 6); write(3 lpad 6); writeln(45 lpad 6); write(678 lpad 6); write(98765 lpad 6); writeln(4321 lpad 6);produce the following output:
12 3 45 678 98765 4321As we see the lpad operator can be used to produce right justified output. There is also rpad operator to produce left justified output. The basic definitions of the lpad and rpad operators work on strings and are as follows:
const func string: (ref string: stri) lpad (in integer: leng) is func result var string: padded is ""; begin if leng > length(stri) then padded := " " mult leng - length(stri) & stri; else padded := stri; end if; end func; const func string: (ref string: stri) rpad (in integer: leng) is func result var string: padded is ""; begin if leng > length(stri) then padded := stri & " " mult leng - length(stri); else padded := stri; end if; end func;The enable_io template contains definitions of lpad and rpad to work on the type specified with enable_io:
const func string: (in aType: aValue) lpad (in integer: leng) is return str(aValue) lpad leng; const func string: (in aType: aValue) rpad (in integer: leng) is return str(aValue) rpad leng;Values of type integer and bigInteger can be written in a numeral system with a radix (base) other than 10. The operators radix and RADIX can be used for this purpose. E.g. the statements
writeln(48879 radix 16); writeln(3735928559_ RADIX 16);produce the following output:
beef DEADBEEFFor float values exist additional ways to convert them to strings. The digits operator allows the specification of a precision. E.g. the statements
writeln(3.1415 digits 2); writeln(4.0 digits 2);produce the following output:
3.14 4.00A combination with the lpad operator as in
writeln(3.1415 digits 2 lpad 6); writeln(99.9 digits 2 lpad 6);is also possible and produces the following output:
3.14 99.90Scientific notation for float is supported with the conversion operator sci. The statements
writeln(0.012345 sci 4); writeln(1.2468 sci 2 ); writeln(3.1415 sci 0); writeln(0.125 sci 1); writeln(0.375 sci 1);produce the following output:
1.2345e-2 1.25e+0 3e+0 1.2e-1 3.8e-1The operator exp is used to specify the number of exponent digits. The statements
writeln(0.012345 sci 4 exp 2); writeln(1.2468e15 sci 2 exp 1); writeln(3.1415 sci 0 exp 3); writeln(0.125 sci 1 exp 2); writeln(0.375 sci 1 exp 2);produce the following output:
1.2345e-02 1.25e+15 3e+000 1.2e-01 3.8e-018.2 Basic input and output operations
To allow arbitrary user defined file-types beside the operating system files we chose a model in which the I/O methods are assigned to the type of the file-value and not to the type of the file-variable. This allows a file variable to point to any file-value. The file-variables have the type file, which is the interface type for sequential files. For the operating system files and for each user defined file a file-type must be declared which has the I/O methods defined. These file-types are derived (direct or indirect) from the type null_file for which all I/O methods are defined upon a base of basic string I/O methods. So for a new user defined file-type only the basic string I/O methods must be defined.
The two basic I/O methods defined for null_file are
const proc: write (in null_file: aFile, in string: stri) is noop; const func string: gets (in null_file: inFile, in integer: maxLength) is func result var string: striRead is ""; begin if maxLength < 0 then raise RANGE_ERROR; end if; end func;A write to null_file with any string has no effect. Reading any number of characters with gets from null_file delivers the empty string. When a user defined file type is declared these are the two methods, which must be redefined, for the new file-type. Based upon these two methods three more methods are defined for null_file, named getc, getwd and getln. These methods get a character, a word and a line respectively. A word is terminated by a space, a tab or a linefeed. A line is terminated by a linefeed. This methods need not to be redefined for a user defined file type but for performance reasons they can also be redefined. The definitions for getc, getwd and getln for null_file are
const func char: getc (inout null_file: aFile) is func result var char: ch is ' '; local var string: buffer is ""; begin buffer := gets(aFile, 1); if buffer = "" then ch := EOF; else ch := buffer[1]; end if; end func; const func string: getwd (inout null_file: aFile) is func result var string: stri is ""; local var string: buffer is ""; begin repeat buffer := gets(aFile, 1); until buffer <> " " and buffer <> "\t"; while buffer <> " " and buffer <> "\t" and buffer <> "\n" and buffer <> "" do stri &:= buffer; buffer := gets(aFile, 1); end while; if buffer = "" then aFile.bufferChar := EOF; else aFile.bufferChar := buffer[1]; end if; end func; const func string: getln (inout null_file: aFile) is func result var string: stri is ""; local var string: buffer is ""; begin buffer := gets(aFile, 1); while buffer <> "\n" and buffer <> "" do stri &:= buffer; buffer := gets(aFile, 1); end while; if buffer = "" then aFile.bufferChar := EOF; else aFile.bufferChar := buffer[1]; end if; end func;Note that getwd skips leading spaces and tabs while getc and getln do not. If getc, getwd or getln is not defined for a new user defined file type the declarations from the null_file are used instead. These declarations are based on the method gets which must be defined for every new user defined file-type.
Note that there is an assignment to the variable 'bufferChar'. This variable is an element of null_file and therefore also an element of all derived file types. This allows an 'eoln' function to test if the last getwd or getln reach the end of a line. Here is a definition of the 'eoln' function:
const func boolean: eoln (in null_file: inFile) is return inFile.bufferChar = '\n';Besides assigning a value to 'bufferChar' in getwd and getln and using it in 'eoln' the standard file functions do nothing with 'bufferChar'. The functions of the "scanfile.s7i" library use the 'bufferChar' variable as current character in the scan process. As such all functions of the "scanfile.s7i" library assume that the first character to be processed is always in 'bufferChar'. Since the standard file functions do not have this behavior, care has to be taken if mixing scanner and file functions.
The type null_file provides default functions to write end-of-line:
const proc: writeln (inout null_file: outFile) is func begin write(outFile, "\n"); end func; const proc: writeln (inout null_file: outFile, in string: stri) is func begin write(outFile, stri); writeln(outFile); end func;The next declarations allow various I/O operations for strings:
const proc: read (inout file: aFile, inout string: stri) is func begin stri := getwd(aFile); end func; const proc: readln (inout file: aFile, inout string: stri) is func begin stri := getln(aFile); end func;8.3 Input and output with conversion
Normally we need a combination of an I/O operation with a conversion operation. There are several functions which are based on the str and parse conversions and on the basic I/O-functions. The declaration of this functions is done by the templates enable_io, enable_input and enable_output. The templates enable_io and enable_output define the following write function:
const proc: write (in file: aFile, in aType: aValue) is func begin write(aFile, str(aValue)); end func;The templates enable_io and enable_input define the following read and readln functions:
const proc: read (inout file: aFile, inout aType: aValue) is func begin aValue := aType parse getwd(aFile); end func; const proc: readln (inout file: aFile, inout aType: aValue) is func begin aValue := aType parse trimValue(aType, getln(aFile)); end func;The function trimValue is used to trim the string retrieved by getln. This adjusts the string before the parse operator is applied. There are 3 cases:
- Trimming of a string with trimValue(string, aString): This leaves the string unchanged.
- Trimming of a char with trimValue(char, aString): For "" it returns "". In all other cases it returns a trimmed string of length 1.
- Trimming of all other types with trimValue(aType, aString): This removes leading and trailing spaces.
The next declaration defines 'backSpace':
const proc: backSpace (ref external_file: aFile) is func begin write(aFile, "\b \b"); end func;8.4 Simple read and write statements
The simple input/output for the standard I/O-files are 'read' and 'write' which are defined with enable_io. Simple I/O may look like:
write("Amount? "); read(amount);
'read' and 'write' use the files IN and OUT, which are described in the next chapter. Here is the definition of the 'read' and 'write' procedures done with enable_io:
const proc: read (inout aType: aValue) is func begin read(IN, aValue); end func; const proc: readln (inout aType: aValue) is func begin readln(IN, aValue); end func; const proc: write (in aType: aValue) is func begin write(OUT, aValue); end func; const proc: writeln (in aType: aValue) is func begin writeln(OUT, aValue); end func;Additional procedures defined outside of enable_io are:
const proc: readln is func local var string: stri is ""; begin stri := getln(IN); end func; const proc: writeln is func begin writeln(OUT); end func;As an example, when you call
readln(number);
the readln(number) function of the type integer calls
readln(IN, number);which executes
number := integer parse trimValue(integer, getln(IN));The file IN may have its own implementation of getln (e.g. as getln of external_file). The default implementation of getln (in null_file) calls gets(IN, 1) in a loop. For the type integer the function trimValue removes leading and trailing spaces. Finally the parse operator converts the string read into an integer which is assigned to 'number'.
8.5 Standard input and output files
The standard I/O files are IN for input and OUT for output. IN and OUT are file variables, which are defined as follows:
var file: IN is STD_IN; var file: OUT is STD_OUT;The files STD_IN and STD_OUT are the standard input and output files of the operating system (Usually the keyboard and the screen). Because IN and OUT are variables redirection of standard input or standard output can be done easily by assigning a new value to them:
IN := OTHER_FILE;
After that all 'read' statements refer to OTHER_FILE. Most operating systems have also a stderr file which can be accessed via the name STD_ERR. If you want to write error messages to the screen even if stdout is redirected elsewhere you can write:
writeln(STD_ERR, "ERROR MESSAGE");To redirect the standard output to STD_ERR you can write:
OUT := STD_ERR;There is also a file STD_NULL defined. Anything written to it is ignored. Reading from it does deliver empty strings. This file can be used to initialize file variables as in:
var file: MY_FILE is STD_NULL;It is also used to represent an illegal file value, if for example an attempt to open a file fails.
8.6 Access to operating system files
The interface type file is also used to access operating system files. Usually a file variable is defined
var file: my_out is STD_NULL;and the result of the open function is assigned to this file variable
my_out := open("my_file", "w");The first parameter of open is the path of the file to be opened. The path must use the standard path representation. This means that a slash ('/') is used as path delimiter. A path with a backslash or a drive letter may raise the exception RANGE_ERROR. The second parameter of open specifies the mode:
- Binary mode:
"r" ... Open file for reading. "w" ... Open or create file for writing and truncate to zero length. "a" ... Open or create file for appending (writing at end-of-file). "r+" ... Open file for update (reading and writing). "w+" ... Open or create file for update and truncate to zero length. "a+" ... Open or create file for appending and reading. - Text mode:
"rt" ... Open file for reading. "wt" ... Open or create file for writing and truncate to zero length. "at" ... Open or create file for appending (writing at end-of-file). "rt+" ... Open file for update (reading and writing). "wt+" ... Open or create file for update and truncate to zero length. "at+" ... Open or create file for appending and reading. Note that Seed7 defines the modes "r", "w", "a", "r+", "w+" and "a+" as binary modes. If open is called, with a mode not listed in the table above, the exception RANGE_ERROR is raised. If there is not enough memory to convert 'path' to the system path type the exception MEMORY_ERROR is raised. If open fails for other reasons it returns STD_NULL. E.g.: It is not allowed to open a directory. An attempt to open a directory returns STD_NULL. It is recommended to check the file variable after opening a file:
if my_out <> STD_NULL thenAfter that output to 'my_out' is possible with
writeln(my_out, "hi there");
When processing of a file has finished it should be closed
close(my_out);Writing to a file after it has been closed results in the exception FILE_ERROR. The following program writes "hi there" to the file "my_file":
$ include "seed7_05.s7i"; const proc: main is func local var file: my_out is STD_NULL; begin my_out := open("my_file", "w"); if my_out <> STD_NULL then writeln(my_out, "hi there"); close(my_out); end if; end func;Note that open opens BYTE files. Writing a character with an ordinal >= 256 such as
writeln(my_out, "illegal char: \256;");
results in the exception RANGE_ERROR. To write Unicode characters other file types must be used. The libraries "utf8.s7i" and "utf16.s7i" provide access to UTF-8 and UTF-16 files. The function openUtf8 can be used the same way as open:
my_out := openUtf8("utf8_file", "w");An UTF-8 file accepts all Unicode characters. That way
writeln(my_out, "Unicode char: \256;");
works without problems. UTF-8 files are byte order independent. Therefore they do not need a byte order mark (BOM). In case a BOM is required it can be written by the user program:
my_out := openUtf8("utf8_file", "w"); write("\16#feff;");The following example expects a mandatory BOM at the beginning of an UTF-8 file:
my_out := openUtf8("utf8_file", "r"); if getc(my_file) <> '\16#feff;' then writeln("The BOM is missing""); else ... end if;Accepting an optional BOM at the beginning of an UTF-8 file is done with:
my_out := openUtf8("utf8_file", "r"); if getc(my_file) <> '\16#feff;' then # This is a file without BOM (the first character will be read later). seek(my_file, 1); end if; ...UTF-16 comes in two flavors UTF-16LE and UTF-16BE. To support both flavors the "utf16.s7i" library defines several functions.
The function openUtf16 opens a Unicode file which uses the UTF-16LE or UTF-16BE encoding. The function openUtf16 checks for a BOM and depending on that it opens an UTF-16LE or UTF-16BE file.
The functions openUtf16le and openUtf16be open Unicode files with the UTF-16LE and UTF-16BE encoding respectively. If the file is opened with one of the modes "w", "w+", "wt" or "wt+" an appropriate BOM is created. If the file is opened with any other mode the application program is in charge to handle optional BOM markers. This way openUtf16le and openUtf16be can be used to open existing files without BOM.
External BYTE files use the implementation type external_file. The type external_file is defined as:
const type: external_file is sub null_file struct var clib_file: ext_file is CLIB_NULL_FILE; var string: name is ""; end struct;This means that every data item of the type external_file has the elements from null_file and additionally the elements 'ext_file' and 'name'. The type clib_file points directly to an operating system file. Objects of type clib_file can only have operating system files as values while objects of type file can also have other files as values. To allow the implementation of the type external_file several operations for the type clib_file are defined. But outside external_file the type clib_file and its operations should not be used.
There are three predefined external files STD_IN, STD_OUT and STD_ERR which have the following declarations:
const func external_file: INIT_STD_FILE (ref clib_file: primitive_file, in string: file_name) is func result var external_file: standardFile is external_file.value; begin standardFile.ext_file := primitive_file; standardFile.name := file_name; end func; var external_file: STD_IN is INIT_STD_FILE(CLIB_INPUT, "STD_IN"); var external_file: STD_OUT is INIT_STD_FILE(CLIB_OUTPUT, "STD_OUT"); var external_file: STD_ERR is INIT_STD_FILE(CLIB_ERROR, "STD_ERR");It is possible to do I/O directly with them, but it is more wisely to use them only to initialize user defined file variables as in:
var file: err is STD_ERR;In the rest of the program references to such a variable can be used:
writeln(err, "Some error occurred");
In this case redirection of the file 'err' can be done very easy. Another way to access external files is to use the function open. The modes used by open differ from those used by the 'fopen' function in the C library. The following table compares the file modes of Seed7 and C:
Seed7 'open' mode C 'fopen' mode "r" "rb" "w" "wb" "a" "ab" "r+" "rb+" "w+" "wb+" "a+" "ab+" "rt" "r" "wt" "w" "at" "a" "rt+" "r+" "wt+" "w+" "at+" "a+" The difference between binary and text mode is as follows:
- Binary mode provides an implementation independent behavior on all operating systems. In binary mode no conversion to and from the line end character ('\n') is done. This has the advantage that an external_file written in binary mode is identical on all operating systems. Reading files with different line endings ("\n" and "\r\n") is supported by every external_file: The functions getwd, getln, read and readln, of external_file skip a carriage return ('\r') if it is just before a linefeed ('\n'). The rest of the external_file functions like getc and gets deliver line endings unchanged.
- The behavior of an external_file in text mode is implementation dependent. Under Unix/Linux/Bsd text and binary modes are identical. Other operating systems prefer to do some line end conversions in text mode: When reading a file all occurrences of "\r\n" are converted to '\n'. When writing to a file all occurrences of '\n' are converted to "\r\n". Note that text mode cannot be used to automatically create files with "\r\n" line endings under Unix/Linux/Bsd.
The library "utf8.s7i" defines the implementation type utf8File as
const type: utf8File is sub external_file struct end struct;8.7 Keyboard file
As stated earlier STD_IN provides an interface to the keyboard which is line buffered and echoed on STD_OUT. This means that you can see everything you typed. Additionally you can correct your input with Backspace until you press Return. But sometimes an unbuffered and unechoed input is needed. This is provided in the library "keybd.s7i", which defines the type keyboard_file and the file KEYBOARD. Characters typed at the keyboard are queued (first in first out) and can be read directly from KEYBOARD without any possibility to correct. Additionally KEYBOARD does not echo the characters. Reading from KEYBOARD delivers normal Unicode characters or special codes (which may be or may not be Unicode characters) for function and cursor keys. Unicode characters and special codes both are char values. The library "keybd.s7i" defines char constants for various keys:
Key character constant Description KEY_CTL_A to KEY_CTL_Z The control keys ctrl-a to ctrl-z KEY_ALT_A to KEY_ALT_Z The alternate keys alt-a to alt-z KEY_CTL_0 to KEY_CTL_9 The control keys ctrl-0 to ctrl-9 KEY_ALT_0 to KEY_ALT_9 The alternate keys alt-0 to alt-9 KEY_F1 to KEY_F10 Function keys F1 to F10 KEY_SFT_F1 to KEY_SFT_F10 Shifted function keys F1 to F10 KEY_CTL_F1 to KEY_CTL_F10 Control function keys F1 to F10 KEY_ALT_F1 to KEY_ALT_F10 Alternate function keys F1 to F10 KEY_LEFT Cursor left KEY_RIGHT Cursor right KEY_UP Cursor up KEY_DOWN Cursor down KEY_HOME Home key KEY_END End key KEY_PGUP Page up KEY_PGDN Page down KEY_INS Insert key KEY_DEL Delete key KEY_PAD_CENTER Numeric keypad center key KEY_SFT_LEFT Shifted cursor left KEY_SFT_RIGHT Shifted cursor right KEY_SFT_UP Shifted cursor up KEY_SFT_DOWN Shifted cursor down KEY_SFT_HOME Shifted home key KEY_SFT_END Shifted end key KEY_SFT_PGUP Shifted page up KEY_SFT_PGDN Shifted page down KEY_SFT_INS Shifted insert key KEY_SFT_DEL Shifted delete key KEY_SFT_PAD_CENTER Shifted numeric keypad center key KEY_CTL_LEFT Control cursor left KEY_CTL_RIGHT Control cursor right KEY_CTL_UP Control cursor up KEY_CTL_DOWN Control cursor down KEY_CTL_HOME Control home key KEY_CTL_END Control end key KEY_CTL_PGUP Control page up KEY_CTL_PGDN Control page down KEY_CTL_INS Control insert key KEY_CTL_DEL Control delete key KEY_CTL_PAD_CENTER Control numeric keypad center key KEY_ALT_LEFT Alt cursor left KEY_ALT_RIGHT Alt cursor right KEY_ALT_UP Alt cursor up KEY_ALT_DOWN Alt cursor down KEY_ALT_HOME Alt home key KEY_ALT_END Alt end key KEY_ALT_PGUP Alt page up KEY_ALT_PGDN Alt page down KEY_ALT_INS Alt insert key KEY_ALT_DEL Alt delete key KEY_ALT_PAD_CENTER Alt numeric keypad center key KEY_NL Newline/enter/return key (equal to KEY_CTL_J) KEY_BS Backspace (equal to KEY_CTL_H) KEY_TAB Horizontal tab (equal to KEY_CTL_H) KEY_CR Carriage return (equal to KEY_CTL_M) KEY_ESC Escape key KEY_MENU Menu key KEY_PRINT Print key KEY_PAUSE Pause key KEY_SFT_NL Shift newline/enter/return key KEY_SFT_BS Shift backspace KEY_SFT_TAB Shift tab (same as KEY_BACKTAB) KEY_BACKTAB Shift tab (same as KEY_SFT_TAB) KEY_SFT_ESC Shift escape KEY_SFT_MENU Shift menu KEY_SFT_PRINT Shift print KEY_SFT_PAUSE Shift pause KEY_CTL_NL Control newline/enter/return key KEY_CTL_BS Control backspace KEY_CTL_TAB Control tab KEY_CTL_ESC Control escape KEY_CTL_MENU Control menu KEY_CTL_PRINT Control print KEY_CTL_PAUSE Control pause KEY_ALT_NL Alt newline/enter/return key KEY_ALT_BS Alt backspace KEY_ALT_TAB Alt tab KEY_ALT_ESC Alt escape KEY_ALT_MENU Alt menu KEY_ALT_PRINT Alt print KEY_ALT_PAUSE Alt pause KEY_SCRLUP Scroll up key KEY_SCRLDN Scroll down key KEY_INSLN Insert line key KEY_DELLN Delete line key KEY_ERASE Erase key KEY_NULCHAR Nul character key KEY_NULLCMD Null command of window manager KEY_REDRAW Redraw command of window manager KEY_MOUSE1 Mouse button 1 (counted from left) KEY_MOUSE2 Mouse button 2 (counted from left) KEY_MOUSE3 Mouse button 3 (counted from left) KEY_MOUSE4 Mouse wheel scroll up KEY_MOUSE5 Mouse wheel scroll down KEY_MOUSE_FWD Mouse forward button KEY_MOUSE_BACK Mouse back button KEY_SFT_MOUSE1 Shift mouse button 1 (counted from left) KEY_SFT_MOUSE2 Shift mouse button 2 (counted from left) KEY_SFT_MOUSE3 Shift mouse button 3 (counted from left) KEY_SFT_MOUSE4 Shift mouse wheel scroll up KEY_SFT_MOUSE5 Shift mouse wheel scroll down KEY_SFT_MOUSE_FWD Shift mouse forward button KEY_SFT_MOUSE_BACK Shift mouse back button KEY_CTL_MOUSE1 Control mouse button 1 (counted from left) KEY_CTL_MOUSE2 Control mouse button 2 (counted from left) KEY_CTL_MOUSE3 Control mouse button 3 (counted from left) KEY_CTL_MOUSE4 Control mouse wheel scroll up KEY_CTL_MOUSE5 Control mouse wheel scroll down KEY_CTL_MOUSE_FWD Control mouse forward button KEY_CTL_MOUSE_BACK Control mouse back button KEY_ALT_MOUSE1 Alt mouse button 1 (counted from left) KEY_ALT_MOUSE2 Alt mouse button 2 (counted from left) KEY_ALT_MOUSE3 Alt mouse button 3 (counted from left) KEY_ALT_MOUSE4 Alt mouse wheel scroll up KEY_ALT_MOUSE5 Alt mouse wheel scroll down KEY_ALT_MOUSE_FWD Alt mouse forward button KEY_ALT_MOUSE_BACK Alt mouse back button KEY_CLOSE The close button of the window has been pressed KEY_RESIZE The window has been resized KEY_UNDEF Undefined key KEY_NONE No key pressed (returned by getc(KEYBOARD, NO_WAIT)) The following example uses the char constant KEY_UP:
$ include "seed7_05.s7i"; include "keybd.s7i"; const proc: main is func begin writeln("Please press cursor up"); while getc(KEYBOARD) <> KEY_UP do writeln("This was not cursor up"); end while; writeln("Cursor up was pressed"); end func;Programs should use the char constants defined in "keybd.s7i" to deal with function and cursor keys, since the special key codes may change in future versions of Seed7.
Note that getc(KEYBOARD) works synchronous. This means that it might wait (block) until a key has been pressed. Blocking can be avoided with the following functions:
- inputReady, which returns TRUE if a character can be read without blocking and FALSE otherwise.
- getc(KEYBOARD, NO_WAIT), which delivers the next character from the keyboard or KEY_NONE if no key has been pressed.
Note that inputReady does not actually read a character. Reading must be done with with a different function (e.g. getc) after inputReady returns TRUE. The program below writes a sequence of # characters. If any key is pressed it starts a new line. Pressing Return (or Enter) terminates the program:
$ include "seed7_05.s7i"; include "keybd.s7i"; include "duration.s7i"; const proc: main is func begin repeat while not inputReady(KEYBOARD) do write("#"); flush(OUT); wait(30000 . MICRO_SECONDS); end while; writeln; until getc(KEYBOARD) = KEY_NL; end func;Both functions (getc(KEYBOARD, NO_WAIT) and inputReady) are useful when user input is allowed while some processing takes place. The following program uses getc(KEYBOARD, NO_WAIT) to display the time until a key is pressed:
$ include "seed7_05.s7i"; include "time.s7i"; include "keybd.s7i"; const proc: main is func begin writeln; while getc(KEYBOARD, NO_WAIT) = KEY_NONE do write(time(NOW) <& "\r"); flush(OUT); end while; writeln; writeln; end func;Seed7 programs can run in two modes:
- Console mode, where the program runs in a console/terminal window (the default).
- Graphics mode, where the program has its own graphic window.
These two modes are supported with two basic keyboard files:
- CONSOLE_KEYBOARD, which uses a terminfo or console driver.
- GRAPH_KEYBOARD, which uses a X11 or GDI driver.
The file KEYBOARD is actually a variable which refers to one of the two basic keyboard files. The declaration of the type keyboard_file and the file KEYBOARD in "keybd.s7i" is:
const type: keyboard_file is subtype file; var keyboard_file: KEYBOARD is CONSOLE_KEYBOARD;Graphic programs switch to to the GRAPH_KEYBOARD driver with:
KEYBOARD := GRAPH_KEYBOARD;A GRAPH_KEYBOARD additionally provides the following functions:
- buttonPressed, which determines if a given button is currently pressed.
- clickedXPos, which returns the X position of the mouse cursor when a button was pressed.
- clickedYPos, which returns the Y position of the mouse cursor when a button was pressed.
Modifier keys such as shift, control, super and alt do not send key/button down or up events. The function buttonPressed can be used to determine if a modifier has been pressed. The program below displays blue and red squares depending on the state of the left and right shift keys. The program is terminated by pressing any non-modifier key:
$ include "seed7_05.s7i"; include "keybd.s7i"; include "draw.s7i"; include "duration.s7i"; const proc: main is func begin screen(640, 480); KEYBOARD := GRAPH_KEYBOARD; repeat rect( 85, 190, 100, 100, buttonPressed(KEYBOARD, KEY_LEFT_SHIFT) ? light_blue : light_red); rect( 270, 190, 100, 100, buttonPressed(KEYBOARD, KEY_SHIFT) ? light_blue : light_red); rect( 455, 190, 100, 100, buttonPressed(KEYBOARD, KEY_RIGHT_SHIFT) ? light_blue : light_red); flushGraphic; wait(30000 . MICRO_SECONDS); until inputReady(KEYBOARD); end func;Note that buttonPressed does not process key/button events. This must be done with inputReady or getc.
The library "keybd.s7i" provides definitions for modifier keys:
Key character constant Description KEY_SHIFT Left or right shift is pressed KEY_LEFT_SHIFT Left shift is pressed KEY_RIGHT_SHIFT Right shift is pressed KEY_CONTROL Left or right control is pressed KEY_LEFT_CONTROL Left control is pressed KEY_RIGHT_CONTROL Right control is pressed KEY_ALT Left or right alt is pressed KEY_LEFT_ALT Left alt is pressed KEY_RIGHT_ALT Right alt is pressed KEY_SUPER Left or right super is pressed KEY_LEFT_SUPER Left super is pressed KEY_RIGHT_SUPER Right super is pressed KEY_SHIFT_LOCK Shift lock is pressed KEY_SHIFT_LOCK_ON Shift lock is currently on KEY_NUM_LOCK Num lock is pressed KEY_NUM_LOCK_ON Num lock is currently on KEY_SCROLL_LOCK Scroll lock is pressed KEY_SCROLL_LOCK_ON Scroll lock is currently on The functions clickedXPos and clickedYPos can be used to determine which position was "clicked". The program below uses clickedXPos and clickedYPos to produce a dot for each keypress.
$ include "seed7_05.s7i"; include "keybd.s7i"; include "draw.s7i"; const proc: main is func local var char: command is ' '; begin screen(640, 480); KEYBOARD := GRAPH_KEYBOARD; command := getc(KEYBOARD); while command = KEY_MOUSE1 do fcircle(clickedXPos(KEYBOARD), clickedYPos(KEYBOARD), 4, light_red); command := getc(KEYBOARD); end while; end func;The current position of the mouse cursor, which is independent from key presses can be retrieved with the following functions:
- pointerXPos, which returns the actual X position of the mouse pointer.
- pointerYPos, which returns the actual Y position of the mouse pointer.
The functions pointerXPos and pointerYPos can be used to move something with the cursor (e.g.: drag and drop). The program below uses buttonPressed to determine how long the mouse button is pressed. This is used together with pointerXPos and pointerYPos to draw along the mouse cursor while the mouse button is pressed:
$ include "seed7_05.s7i"; include "keybd.s7i"; include "draw.s7i"; const proc: main is func local var char: command is ' '; begin screen(640, 480); KEYBOARD := GRAPH_KEYBOARD; command := getc(KEYBOARD); while command = KEY_MOUSE1 do while buttonPressed(KEYBOARD, KEY_MOUSE1) do fcircle(pointerXPos(curr_win), pointerYPos(curr_win), 4, light_red); end while; command := getc(KEYBOARD); end while; end func;Some keys are not delivered to the program by default. By default the close button of the window (often marked with X) just exits the program. By default resizing a window is also not communicated to the program. These two events can be activated with selectInput. This way a program can also receive KEY_CLOSE and KEY_RESIZE:
$ include "seed7_05.s7i"; include "keybd.s7i"; include "draw.s7i"; const proc: main is func local var char: command is ' '; begin screen(640, 480); KEYBOARD := GRAPH_KEYBOARD; selectInput(curr_win, KEY_CLOSE, TRUE); # Enable the program to get KEY_CLOSE without closing the window. selectInput(curr_win, KEY_RESIZE, TRUE); # Enable the program to get KEY_RESIZE. command := getc(KEYBOARD); while command <> KEY_CLOSE do if command = KEY_RESIZE then lineTo(0, 0, width(curr_win), height(curr_win), white); end if; command := getc(KEYBOARD); end while; end func;Some file types are defined to support the KEYBOARD. One such file type is echoFile, which is defined in the library "echo.s7i". An echoFile file can be used to write input characters to an output file. This is useful since KEYBOARD does not echo its input, but echoFile is not restricted to support KEYBOARD. The following program writes echoes of the keys typed and exits as soon as a '!' is encountered:
$ include "seed7_05.s7i"; include "keybd.s7i"; include "echo.s7i"; const proc: main is func local var char: ch is ' '; begin IN := openEcho(KEYBOARD, OUT); repeat ch := getc(IN); until ch = '!'; writeln; end func;An echoFile checks also for control-C (KEY_CTL_C). If control-C is typed an echoFile asks if the program should be terminated:
terminate (y/n)?Answering 'y' or 'Y' is interpreted as 'yes' and the program is terminated with the following message:
*** PROGRAM TERMINATED BY USERAny other input removes the question and the program continues to read input.
Another helpful file type is lineFile, which is defined in the library "line.s7i". A lineFile allows to correct the input with Backspace until a Return (represented with '\n') is encountered. In contrast to this editing feature the possibility to edit a line of STD_IN is provided by the operating system. The following program uses echoFile and lineFile to simulate input line editing:
$ include "seed7_05.s7i"; include "keybd.s7i"; include "echo.s7i"; include "line.s7i"; const proc: main is func local var char: ch is ' '; begin IN := openEcho(KEYBOARD, OUT); IN := openLine(IN); repeat ch := getc(IN); write(ch); until ch = '!'; end func;This program terminates if a line containing '!' is confirmed with Return.
There is also the editLineFile, which is defined in the library "editline.s7i". An editLineFile provides more than a combination of an echoFile with a lineFile. An editLineFile allows editing with Backspace, Delete, ←, →, Home and End. The vertical curser keys can be used to get previous input lines. Like an echoFile it checks also for control-C (KEY_CTL_C).
$ include "seed7_05.s7i"; include "keybd.s7i"; include "console.s7i"; include "editline.s7i"; const proc: main is func local var string: command is ""; begin OUT := STD_CONSOLE; IN := openEditLine(KEYBOARD, OUT); writeln("Use the command quit to exit the program."); repeat write("command> "); readln(command); until command = "quit"; end func;8.8 Files with line structure
The library "text.s7i" defines the type text, which is a subtype of file. The type text adds a line structure and other features such as scrolling and color to file. The lines and columns of a text start with 1 in the upper left corner and increase downward and rightward. The function setPos sets the current line and column of a text:
setPos(aText, 10, 20);The functions setLine and setColumn set just the line and column respectively:
setLine(aText, 2); setColumn(aText, 72);The current line and column of a text file can be retrieved with line and column:
writeln("The current line is: " <& line(aText)); writeln("The current column is: " <& column(aText));The current height and width of a text file can be retrieved with height and width:
writeln("The height is: " <& height(aText)); writeln("The width is: " <& width(aText));To allow random access output to a text console (or text window) the library "console.s7i" defines the type console_file. The function
open(CONSOLE)returns a console_file.
8.9 Sockets
The library "socket.s7i" defines types and functions to access sockets. The implementation type for sockets is socket. As interface type file is used:
var file: clientSocket is STD_NULL;With openInetSocket an Internet client socket can be opened:
clientSocket := openInetSocket("www.google.com", 80);The function openInetSocket creates and connects a socket. Opening an Internet socket at the local host is also done with a variant of openInetSocket:
clientSocket := openInetSocket(1080);
Since sockets use the file interface functions like writeln and getln can be used:
$ include "seed7_05.s7i"; include "socket.s7i"; const proc: main is func local const string: serverName is "www.google.com"; var file: aSocket is STD_NULL; begin aSocket := openInetSocket(serverName, 80); if aSocket <> STD_NULL then writeln(aSocket, "GET / HTTP/1.1"); writeln(aSocket, "Host: " <& serverName); writeln(aSocket, "User-Agent: BlackHole"); writeln(aSocket); writeln(getln(aSocket)); end if; end func;The example above sends a HTTP request to a server and gets the status code from the response. The example above consists of code from the library "gethttp.s7i".
Server sockets are supported with the type listener. A listener is defined with:
var listener: myListener is listener.value;The library "listener.s7i" defines the function openInetListener, which opens a listener:
aListener := openInetListener(1080);
The function listen is used to listen for incoming socket connections of a listener, and to limit the incoming queue:
listen(aListener, 10);
The function accept returns the first connected socked of the listener:
serverSocket := accept(aListener);
Together the functions above can be use to process requests without sessions:
aListener := openInetListener(1080); listen(aListener, 10); while TRUE do sock := accept(aListener); # Read and process the request from sock. close(sock); end while;A similar loop is used in the Comanche web server (see main function). The function waitForRequest can be used to process requests with session:
aListener := openInetListener(2021); listen(aListener, 10); while TRUE do waitForRequest(aListener, existingConnection, newConnection); if existingConnection <> STD_NULL then # Read and process the request from existingConnection. end if; if newConnection <> STD_NULL then # Send welcome message to newConnection. end if; end while;Similar code is used in the program "ftpserv.sd7". The implementation of waitForRequest is based on pollData, which is defined in "poll.s7i".
8.10 Transport Layer Security
Transport Layer Security (TLS) is the successor of the Secure Sockets Layer (SSL). It provides secure communication over a computer network. The library "tls.s7i" defines types and functions for TLS sockets. The implementation type for sockets is tlsFile. As interface type file is used:
var file: aTlsSocket is STD_NULL;With openTlsSocket a TLS socket can be opened:
aTlsSocket := openTlsSocket("www.google.com", 443);The function openTlsSocket opens a TLS socket. Since TLS sockets use the file interface functions like writeln and getln can be used:
$ include "seed7_05.s7i"; include "tls.s7i"; const proc: main is func local const string: serverName is "www.google.com"; var file: aTlsSocket is STD_NULL; begin aTlsSocket := openTlsSocket(serverName, 443); if aTlsSocket <> STD_NULL then writeln(aTlsSocket, "GET / HTTP/1.1"); writeln(aTlsSocket, "Host: " <& serverName); writeln(aTlsSocket, "User-Agent: BlackHole"); writeln(aTlsSocket); writeln(getln(aTlsSocket)); end if; end func;The example above sends a HTTPS request to a server and gets the status code from the response. The example above consists of code from the library "gethttps.s7i".
The function openServerTls can be used to open a TLS socket at the server side. The library "x509cert.s7i" defines the self signed certificate stdCertificate. This certificate can be used to open a TLS server socket:
$ include "seed7_05.s7i"; include "socket.s7i"; include "listener.s7i"; include "tls.s7i"; const proc: main is func local var listener: aListener is listener.value; var file: sock is STD_NULL; var file: tlsSock is STD_NULL; var string: line is ""; begin aListener := openInetListener(11111); listen(aListener, 10); while TRUE do sock := accept(aListener); tlsSock := openServerTls(sock, stdCertificate); if tlsSock <> STD_NULL then writeln("Success"); repeat line := getln(tlsSock); writeln(line <& " received"); until line = ""; close(tlsSock); else writeln(" *** Cannot open TLS connection."); end if; end while; end func;8.11 User defined file types
In addition to the predefined file types it is often necessary to define a new type of file. Such a new file has several possibilities:
- It could store its contents in a string (not only to be faster but also to provide additional file operations)
- The information can be processed (e.g. to upper case) and sent to another file.
- It could work just like an Unix utility (Think of more, sort, tee, uniq ...)
- It could provide a file-like interface for something with an other interface. (e.g. The contents of a directory, or random access I/O to the screen)
With the following declaration we define a new file type:
const type: my_file_type is sub null_file struct ... (* Local data *) ... end struct;It is not necessary to derive the type my_file_type directly from null_file. The type my_file_type may also be an indirect descendant of null_file. So it is possible to create file type hierarchies. The interface implemented by the new file needs also to be specified:
type_implements_interface(my_file_type, file);
The type file is not the only interface type which can be used. There is also the type text which is derived from file. The type text describes a line oriented file which allows setPos (which moves the current position to the line and column specified) and other functions. It is also possible to define new interface types which derive from file or text.
As next an open function is needed to open a my_file_type file:
const func file: open_my_file ( (* Parameters *) ) is func result var file: newFile is STD_NULL; local var my_file_type: new_file is my_file_type.value; begin ... (* Initialization of the data elements of new_file *) newFile := toInterface(new_file); ... end func;Note that the function 'toInterface' is used to generate a new file object. Now only the two basic I/O operations must be defined:
const proc: write (inout my_file_type: new_fil, in string: stri) is func begin ... (* Statements that do the output *) ... end func; const proc: gets (inout my_file_type: new_fil, in integer: leng) is func result var string: stri is ""; begin ... (* Statements that do the input *) ... end func;8.12 Scanning a file
The I/O concept introduced in the previous chapters separates the input of data from its conversion. The read, readln, getwd and getln functions are designed to read whitespace separated data elements. If the data elements are not separated by whitespace characters this I/O concept is not possible. Instead the functions which read from the file need some knowledge about the type which they intend to read. Fortunately this is a well researched area. The lexical scanners used by compilers solve exactly this problem.
Lexical scanners read symbols from a file and use the concept of a current character. A symbol can be a name, a number, a string, an operator, a bracket or something else. The current character is the first character to be processed when scanning a symbol. After a scanner has read a symbol the current character contains the character just after the symbol. This character could be the first character of the next symbol or some whitespace character. If the set of symbols is chosen wisely all decisions about the type of the symbol and when to stop reading characters for a symbol can be done based on the current character.
Every file contains a 'bufferChar' variable which is used as current character by the scanner functions defined in the "scanfile.s7i" library. The "scanfile.s7i" library contains skip... and get... functions. The skip... procedures return void and are used to skip input while the get... functions return the string of characters they have read. The following basic scanner functions are defined in the "scanfile.s7i" library:
- skipComment
- Skips a possibly nested Seed7 comment from a file.
- getComment
- Reads a possibly nested Seed7 comment from a file.
- skipClassicComment
- Skips a classic C comment from a file.
- skipLineComment
- Skips a line comment from a file.
- getLineComment
- Reads a line comment from a file.
- getDigits
- Reads a sequence of digits from a file.
- getInteger
- Reads a decimal integer with optional sign from a file.
- getNumber
- Reads a numeric literal (integer, bigInteger or float literal) from a file.
- getNonDigits
- Reads a sequence of non digits from a file.
- getQuotedText
- Reads a text quoted with " or ' from a file.
- getSimpleStringLiteral
- Read a simple string literal from a file.
- getCharLiteral
- Reads a character literal from a file.
- getStringLiteral
- Reads a string literal from a file.
- getName
- Reads an alphanumeric name from a file.
Contrary to read and getwd basic scanner functions do not skip leading whitespace characters. To skip whitespace characters one of the following functions can be used:
- skipSpace
- Skips space characters from a file.
- skipSpaceOrTab
- Skips space and tab characters from a file.
- skipWhiteSpace
- Skips whitespace characters from a file.
- getWhiteSpace
- Reads whitespace characters from a file.
- getWord
- Reads a white space delimited word from a file.
- skipLine
- Skips a line from a file.
- getLine
- Reads a line from a file.
The advanced scanner functions do skip whitespace characters before reading a symbol:
- getSymbolOrComment
- Reads a symbol or a comment from a file.
- getSymbol
- Reads a symbol from a file.
- getSymbolWithHtmlEntities
- Reads a symbol, where html entities are allowed, from a file.
- getHtmlTagSymbolOrComment
- Reads a HTML tag, a symbol or a comment from a file.
- skipXmlComment
- Skips a XML comment from a file.
- getXmlTagOrContent
- Reads a XML/HTML tag or the XML/HTML content text from a file.
- getXmlCharacterReference
- Reads a predefined XML entity from a file.
- getXmlCdataContent
- Read the content text of a CDATA section from a file.
- getXmlTagHeadOrContent
- Reads a XML/HTML tag head or a XML/HTML content from a file.
- getSymbolInXmlTag
- Reads a symbol which can appear inside a XML/HTML tag from a file.
- skipXmlTag
- Skips beyond an XML Tag in a file.
- getNextXmlAttribute
- Reads name and value of an attribute inside a XML tag from file.
- getHtmlAttributeValue
- Reads a HTML tag attribute value from a file.
- getNextHtmlAttribute
- Reads name and value of an attribute inside a HTML tag from a file.
- getSimpleSymbol
- Reads a simple symbol from a file.
All scanner functions assume that the first character to be processed is in 'bufferChar' and after they are finished the next character which should be processed is also in 'bufferChar'. To use scanner functions for a new opened file it is necessary to assign the first character to the 'bufferChar' with:
myFile.bufferChar := getc(myFile);In most cases whole files are either processed with normal I/O functions or with scanner functions. If normal I/O functions need to be combined with scanner functions care has to be taken:
- If the last function which read from a file was one of read, readln, getwd or getln the 'bufferChar' already contains the character which should be processed next and therefore subsequent scanner functions can be used.
- Other I/O functions like getc and gets do not assign something to 'bufferChar'. In this case something should be assigned to 'bufferChar'.
- Switching back from scanner functions to normal I/O functions is best done when the content of 'bufferChar' is known. For example at the end of the line.
Scanner functions are helpful if it is necessary to read numeric input without failing if no digits are present:
skipWhiteSpace(IN); if eoln(IN) then writeln("empty input"); elsif IN.bufferChar in {'0' .. '9'} then number := integer parse getDigits(IN); skipLine(IN); writeln("number " <& number); else stri := getLine(IN); writeln("command " <& literal(stri)); end if;The function getSymbol is designed to read Seed7 symbols. When the end of the file is reached it returns "". With getSymbol name-value pairs can be read:
name := getSymbol(inFile); while name <> "" do if name <> "#" and getSymbol(inFile) = "=" then aValue = getSymbol(inFile); if aValue <> "" then if aValue[1] = '"' then keyValueHash @:= [name] aValue[2 ..]; elsif aValue[1] in {'0' .. '9'} then keyValueHash @:= [name] aValue; end if; end if; end if; end while;The following loop can be used to process the symbols of a Seed7 program:
inFile.bufferChar := getc(inFile); currSymbol := getSymbol(inFile); while currSymbol <> "" do ... process currSymbol ... currSymbol := getSymbol(inFile); end while;Whitespace and comments are automatically skipped with the function getSymbol. If comments should also be returned the function getSymbolOrComment can be used. Together with the function getWhiteSpace it is even possible to get the whitespace between the symbols:
const func string: processFile (in string: fileName) is func result var string: processed is ""; local var file: inFile is STD_NULL; var string: currSymbol is ""; begin inFile := open(fileName, "r"); if inFile <> STD_NULL then inFile.bufferChar := getc(inFile); processed := getWhiteSpace(inFile); currSymbol := getSymbolOrComment(inFile); while currSymbol <> "" do processed &:= currSymbol; processed &:= getWhiteSpace(inFile); currSymbol := getSymbolOrComment(inFile); end while; end if; end func;In the example above the function 'processFile' gathers all symbols, whitespace and comments in the string it returns. The string returned by 'processFile' is equivalent to the one returned by the function 'getf'. That way it is easy to test the scanner functionality.
The logic with getWhiteSpace and getSymbolOrComment can be used to add HTML tags to comments and literals. The following function colors comments with green, string and char literals with maroon and numeric literals with purple:
const proc: sourceToHtml (inout file: inFile, inout file: outFile) is func local var string: currSymbol is ""; begin inFile.bufferChar := getc(inFile); write(outFile, "<pre>\n"); write(outFile, getWhiteSpace(inFile)); currSymbol := getSymbolOrComment(inFile); while currSymbol <> "" do currSymbol := replace(currSymbol, "&", "&"); currSymbol := replace(currSymbol, "<", "<"); if currSymbol[1] in {'"', '''} then write(outFile, "<font color=\"maroon\">"); write(outFile, currSymbol); write(outFile, "</font>"); elsif currSymbol[1] = '#' or startsWith(currSymbol, "(*") then write(outFile, "<font color=\"green\">"); write(outFile, currSymbol); write(outFile, "</font>"); elsif currSymbol[1] in digit_char then write(outFile, "<font color=\"purple\">"); write(outFile, currSymbol); write(outFile, "</font>"); else write(outFile, currSymbol); end if; write(outFile, getWhiteSpace(inFile)); currSymbol := getSymbolOrComment(inFile); end while; write(outFile, "</pre>\n"); end func;The functions skipSpace and skipWhiteSpace are defined in the "scanfile.s7i" library as follows:
const proc: skipSpace (inout file: inFile) is func local var char: ch is ' '; begin ch := inFile.bufferChar; while ch = ' ' do ch := getc(inFile); end while; inFile.bufferChar := ch; end func; const proc: skipWhiteSpace (inout file: inFile) is func begin while inFile.bufferChar in white_space_char do inFile.bufferChar := getc(inFile); end while; end func;The functions skipComment and skipLineComment, which can be used to skip Seed7 comments, are defined as follows:
const proc: skipComment (inout file: inFile) is func local var char: character is ' '; begin character := getc(inFile); repeat repeat while character not in special_comment_char do character := getc(inFile); end while; if character = '(' then character := getc(inFile); if character = '*' then skipComment(inFile); character := getc(inFile); end if; end if; until character = '*' or character = EOF; if character <> EOF then character := getc(inFile); end if; until character = ')' or character = EOF; if character = EOF then inFile.bufferChar := EOF; else inFile.bufferChar := getc(inFile); end if; end func; # skipComment const proc: skipLineComment (inout file: inFile) is func local var char: character is ' '; begin repeat character := getc(inFile); until character = '\n' or character = EOF; inFile.bufferChar := character; end func; # skipLineComment9. STRUCTURED SYNTAX DEFINITION
Most programming languages have only predefined constructs like statements and operators. Seed7, on the other hand, additionally allows user defined constructs. This chapter introduces the Seed7 Structured Syntax Description (S7SSD) which is used to define the syntax of new constructs. The syntax of predefined constructs is also defined with S7SSD.
The syntax descriptions used in manuals of conventional programming languages have no relationship to the approach used by the syntax analysis of the corresponding interpreters/compilers. S7SSD is a simple syntax description that can be used by humans and compilers/interpreters. Although compiler-compilers follow the path of machine readable syntax descriptions, they use much more complicated syntax and semantic descriptions and do not allow users of the language to define new constructs.
There are different existing notations to specify the syntax of programming languages. Backus-Naur Form (BNF) and its variants like Extended Backus-Naur Form (EBNF) are examples of such syntax specifications. Since it is easier to understand new concepts if they are compared to well known concepts, EBNF will be used as a base to explain S7SSD.
9.1 The Extended Backus-Naur Form
As the name says the Extended Backus-Naur Form is an extension of BNF. The extension allows the definition of repetitions and optional parts without the use of recursion. EBNF has the following elements:
- Nonterminal symbols are described with identifiers. An identifier consist of lower case letters and underline characters.
- Terminal symbols are quoted strings or names in upper case characters, which describe unprintable characters (control characters).
- The concatenation of nonterminal and/or terminal symbols is described by writing them in sequence.
- With | two alternatives can be separated.
- Expressions of the extended Backus-Naur form can be put within parentheses ( ... ) .
- If an expression is optional it is enclosed in square brackets [ ... ] .
- If an expression may be omitted or repeated it is enclosed in curly braces { ... } .
The syntax of the extended Backus-Naur form can be described in extended Backus-Naur form:
- syntax_description ::=
- { ebnf_statement } .
- ebnf_statement ::=
- identifier '::=' ebnf_expression '.' .
- ebnf_expression ::=
- term { '|' term } .
- term ::=
- factor { factor } .
- factor ::=
- identifier | string | control_character_description |
'(' ebnf_expression ')' | '[' ebnf_expression ']' |
'{' ebnf_expression '}' .9.2 The Seed7 Structured Syntax Description
The Seed7 Structured Syntax Description is abbreviated with S7SSD. The S7SSD can describe most but not all of the syntax of a programming language. The syntax of identifiers, literals and comments is not described with S7SSD. S7SSD views a program as a big typeless expression. The syntax of this expression is described with prefix, infix and postfix operators. The operators have a priority and an associativity. Operators can have one or more operator symbols. The operator symbols of an operator can be adjacent or they can have parameters in between. The S7SSD of an infix + is:
$ syntax expr: .(). + .() is -> 7;This defines the + as left associative infix operator with priority 7. The actual syntax is described with:
. () . + . ()The dots are used to create a list of elements. For the purpose of the syntax description we can just remove the dots, which gives:
() + ()The place of the parameters is specified with (). The + operator is an infix operator, because the + is preceded and succeeded by a (). Any expression can be used as () parameter. The type of the () parameters and the type of the result of + is not specified by the S7SSD. Checks for the correct type are not done at the syntactic level. This way S7SSD allows syntax that would not be allowed in a corresponding EBNF description. S7SSD considers just operator symbols and their priority and associativity.
9.3 The syntax of a statement
To explain the Seed7 Structured Syntax Description we design a new statement, the loop-statement. The loop-statement should be similar to while- and repeat-loops but instead of having the conditional exit at the beginning or at the end, it should have a conditional exit in the middle of the loop. This middle conditional exit should be part of the loop-statement. Note that the break-statement, which exists in some programming languages, is a statement on its own and is not part of the loop which it leaves. Therefore the middle conditional exit should not be confused with a break-statement. An example of the new loop-statement is:
loop ch := getc(inFile); until ch = '\n' do stri &:= ch; end loop;The 'loop' example above reads characters from a file and concatenates them to a string until the character '\n' is read. The '\n' ends the loop. Hence it is not added to the string. An equivalent solution without the usage of the loop-statement would be:
repeat ch := getc(inFile); if ch <> '\n' then stri &:= ch; end if; until ch = '\n';The S7SSD of the loop-statement is:
$ syntax expr: .loop.().until.().do.().end.loop is -> 25;The details of the S7SSD 'syntax' definition will be explained later. For now we concentrate at the heart of the S7SSD, the expression:
.loop.().until.().do.().end.loopFor the purpose of the syntax description we can just remove the dots, which gives:
loop () until () do () end loopThis are the keywords used in a loop-statement. The symbol () acts as placeholder for an expression. With EBNF the loop-statement can be described as:
- loop_statement ::=
- 'loop'
statement
'until' expression 'do'
statement
'end' 'loop' .An EBNF description may use many nonterminal symbols such as 'statement' or 'expression'. S7SSD does not distinguish between different nonterminal symbols. Instead S7SSD only knows one nonterminal symbol: ()
Therefore S7SSD cannot distinguish between 'statement', 'expression' or something else. At the syntax level any kind of expression can by substituted for a S7SSD nonterminal symbol (). With EBNF it is possible to describe constraints such as the type of an expression. S7SSD relies on semantic checks to verify such constraints. Given the S7SSD of the loop-statement an expression like
loop "X" until 1+2 do integer end loopwould be legal as it contains the required keywords
loop until do end loopand the expressions
"X" 1+2 integer
at the places of the () symbols. This is exactly what the syntax definition specifies, but it would be not be considered correct given the description of the loop-statement at the beginning of the chapter. To determine which types of expressions are allowed at the places of the () symbol, a semantic definition of the loop-statement is necessary. A semantic definition is just a function definition which uses the keywords and parameters from the syntax definition. The definition of the 'loop' function (semantic definition of the loop-statement) is:
const proc: loop (in proc: statements1) until (in func boolean: condition) do (in proc: statements2) end loop is func local var boolean: exitLoop is FALSE; begin repeat statements1; if not condition then statements2; else exitLoop := TRUE; end if; until exitLoop; end func;This definition determines the types of the expressions accepted between the keywords. Besides that the semantic definition of the loop-statement is just a normal function definition. Note that the sequence of keywords and parameters in the header of this function definition is determined by the corresponding syntax definition.
The parameters 'statements1', 'condition' and 'statements2' are call-by-name parameters. A call-by-name parameter is a function without parameters. Function types such as proc or func boolean are used as type of formal call-by-name parameters. An expression with the correct type is allowed as actual call-by-name parameter. This actual parameter expression is not evaluated when the function is called. Instead the expression is evaluated every time the formal call-by-name parameter is used. This way 'statements1', 'condition' and 'statements2' are not executed when the 'loop' function is called. Inside the body of the 'loop' function the call-by-name parameters are executed at some places.
The 'loop' function uses a repeat- and an if-statement to implement the desired behavior. If necessary the call-by-name parameters are executed several times.
For the 'loop' example with the semantic errors (see above) we would get an error message like:
*** chkloop.sd7(35):51: Match for {loop "X" until {1 + 2 } do integer end loop } failed9.4 Priority and associativity
If a syntax construct has parameters before the first symbol or after the last symbol the priority and the associativity of the construct are significant. Constructs with stronger priority bind their parameters earlier than constructs with weaker priority. The priority is described by a natural number (inclusive 0). The strongest priority is 0. Weaker priorities are described by larger numbers. What bind means is can be explained with an example:
= A = B + C * D / \ A + * priority 6 / \ + priority 7 B * = priority 12 / \ C DThe * operator has the strongest priority (6) of all operators involved. Therefore the * takes its parameters first. Then the + (with priority 7) and at last the = (with priority 12) follows. This leads to the following interpretation of the expression:
A = (B + (C * D))The associativity describes, in which order constructs with equal priority bind their parameters. For example
A - B - Ccan be interpreted in two ways:
(A - B) - C or A - (B - C)The first interpretation is usually preferred by mathematicians and is described with the associativity -> . Generally four associativities are possible:
Associativity Symbol Binding from left to right -> Binding from right to left <- Neither the left nor the right parameter are allowed to have the same priority <-> At the left side there is a binding from left to right and at the right side there is a binding from right to left -><- The last two possibilities give no legal interpretation in the subtraction example. The third kind of associativity ( <-> ) is used by the equal operator ( = ) of Pascal because there an expression like
A = B = Cis not legal.
There is a second way to describe the associativity. The associativity describes, if an operand must have a stronger priority than the priority of the operator. For example:
- 7 A - B - C / \ / \ / \ <=7 / \ <7 - priority 7 -> / \ / \ - C 7 0 / \ / \ / \ <=7 / \ <7 / \ / \ A B 0 0The numbers in the nodes of the right tree show the priority of each sub expression (sub tree). With < and <= the required condition for the priority of an operand is described. An interpretation is legal if all this conditions are met. If there are more than one legal interpretations or no legal interpretation the expression is illegal.
Table for the possibilities of associativity:
associativity The priority of the left operand must be right operand must be -> <= < <- < <= <-> < < -><- <= <= than that of the operator The parameter before the operator symbol is called left operand. The parameter after the last symbol of a construct is called right operand. In case of normal operators the last symbol of a construct and the operator symbol are identical. If this is not the case there is a third kind of operand. Between the operator symbol and the last symbol of a construct are the middle operands. Middle operands can have any priority.
9.5 The syntax of operators
A syntax definition specifies the way a usage of a statement or operator must be written. For example a call of the not operator looks like:
not okay
To describe the syntax of the not operator we write:
$ syntax expr: .not.() is <- 13;This means that a not expression is constructed with the symbol not followed by a parameter. The place of the parameter is marked with the () sign. The syntax description contains no information about the types of the parameters. At the syntax level a parameter may be anything. With <- the associativity of the not operator is specified as right associative. This means that the right operand is allowed to have the same priority as the operator symbol. So the expression
not not okayis legal and means
not (not okay)If the associativity of the not operator is specified with -> instead of <- the 'not not' expression above is not legal. With 13 the priority of the whole not operator is determined. As convention priorities from 1 to 20 are used by operators and priority 25 is used by statements. Arithmetic operators have priorities from 1 to 11 and comparisons have priority 12.
To define the not operator completely there must be also a semantic definition which is as follows:
const func boolean: not (in boolean: aBool) is func result var boolean: negation is TRUE; begin if aBool then negation := FALSE; end if; end func;In the declaration the not operator is written exactly in the same way it is written when it is called. The syntax definition is used at both places: declaration and call. The syntax and semantic declarations define precisely how the not operator works.
As next example we try an infix operator like the and operator. A call of the and operator may look like:
okay and not errorTo describe the syntax of the and operator we write:
$ syntax expr: .().and.() is -> 14;This means that an and expression is constructed with the symbol and surrounded by parameters. The -> defines the and operator as left associative. This means that an expression like
A and B and Cis interpreted as
(A and B) and CWith 14 the priority of the whole and operator is determined. Since priority 14 is weaker than the priority of the not operator which is 13 the example expression is evaluated as:
okay and (not error)Note that the expression
okay and not errormakes no sense if the and operator has priority 12 instead of 14.
S7SSD treats everything as operator description. Operators have priority and associativity. The priority and associativity determine in which succession S7SSD syntax rules get applied. To explain priority and associativity we use the basic arithmetic operations (+,-,*,/). To describe them with EBNF we can write:
- factor ::=
- number | name .
- expression_5 ::=
- factor | ( '+' expression_5 ) |
( '-' expression_5 ) .- expression_6 ::=
- expression_5 |
( expression_6 '*' expression_7 ) |
( expression_6 '/' expression_7 ) .- expression_7 ::=
- expression_6 |
( expression_7 '+' expression_6 ) |
( expression_7 '-' expression_6 ) .This describes the following things:
- The operators have different priorities:
- Plus and minus signs are executed first
- Multiplication and division are executed second.
- Addition and subtraction are executed last.
- These priorities are exactly what we expect from an arithmetic expression.
- Additionally we see that ++2 is allowed and interpreted as +(+(2)) which means that the plus sign is a right-associative operator.
- We can also see that a*b*c is allowed and interpreted as (a*b)*c which means that the multiplication is a left-associative operator.
All this things can also be described with S7SSD:
$ syntax expr: . + .() is <- 5; $ syntax expr: . - .() is <- 5; $ syntax expr: .(). * .() is -> 6; $ syntax expr: .(). / .() is -> 6; $ syntax expr: .(). + .() is -> 7; $ syntax expr: .(). - .() is -> 7;As we can see S7SSD is shorter as the description with EBNF. A syntax statement is explained as follows:
- The $ is used to introduce all hard coded statements.
- The keyword 'syntax' introduces a structured syntax description.
- The result of the recognized expression will have the type expr. The type expr is used between the syntax and the semantic analysis. The type expr describes expressions which are syntactically analyzed but not semantically analyzed. After the semantic analysis (and during the runtime) the type expr is not used.
- The colon ':' is used as separator between type and syntax description.
- A dot expression like '.(). * .()' is introduced (as can probably be guessed by the name) with a dot. For the purpose of the syntax description we can just remove the dots in our mind: '() * ()'
- The symbol 'is' is used in all Seed7 declarations as separator between the name and the value.
- The associativity is described with one of the symbols -> (left-associative), <- (right-associative), <-> (not associative) and -><- (both associativities). If there are no left or right operands, as it is the case for the loop-statement, the associativity is irrelevant.
- Finally the priority of the syntax construct is defined with a integer literal like '6'. The priority '6' is used for the operators *, /, div, rem, mdiv and mod.
9.6 Syntax of predefined statements
Predefined statements can also be defined with S7SSD. E.g.: The while-statement. A use of the while-statement is:
while element_index > 0 and okay do processElement; write("."); end while;To describe the syntax of the while-statement we write:
$ syntax expr: .while.().do.().end.while is -> 25;This means that the while-statement is an expression with the symbols 'while', 'do', 'end' and 'while'. With -> the associativity of the while-statement is specified as left associative. The associativity has no meaning for the while-statement since there is no parameter before the first symbol or after the last symbol. The priority of the whole while-statement is 25.
The semantic definition of the while-statement is as follows:
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;The syntax definition is used for the declaration and for the call. This declaration defines precisely how the while-statement works. It is based on the if-statement and uses recursion to emulate the repetition of the loop body. Another example for a syntax description is the repeat-statement
repeat processElement; write("."); until element_index = 0 or not okay;which has the following syntax description:
$ syntax expr: .repeat.().until.() is -> 25;This means that the repeat-statement is an expression with the symbols 'repeat' and 'until' and a parameter between 'repeat' and 'until' and after 'until'. With 25 the priority of the whole repeat-statement is determined. With -> the associativity of the repeat-statement is specified as left associative. This allows priorities from 0 to 24 for the parameter after 'until'. Since statements have priority 25 it is not possible to write a statement direct behind 'until'.
A simple if-statement, without 'elsif' part, is the next example. A usage of this if-statement might be:
if okay then writeln("okay"); else writeln("not okay"); end if;As syntax description we use
$ syntax expr: .if.().then.().end.if is -> 25; $ syntax expr: .if.().then.().else.().end.if is -> 25;Note that this description allows if-statements with and without 'else' parts. As semantic description we use
const proc: if (in boolean: condition) then (in proc: statement) end if is func begin case condition of when {TRUE}: statement; end case; end func; const proc: if (in boolean: condition) then (in proc: statement1) else (in proc: statement2) end if is func begin case condition of when {TRUE}: statement1; when {FALSE}: statement2; end case; end func;The two forms of the if-statement are based on the case-statement. A more complex if-statement with 'elsif' parts can be:
if number < 0 then write("less"); elsif number = 0 then write("equal"); else write("greater"); end if;How to define the syntax and the semantic for this statement is described in the next chapter.
9.7 Advanced syntax definitions
If we want to use some special syntax which should be only allowed at some place we do the following:
- Define the special syntax with S7SSD in a way that does not contradict with the rest of the syntax definitions.
- Use semantic definitions to make sure that this syntax construct can only be used at the place desired.
The EBNF of the if-statement with 'elsif' parts is:
- if_statement ::=
- 'if' expression 'then'
statement
{ 'elsif' expression 'then'
statement }
[ 'else'
statement ]
'end' 'if' .The S7SSD of this if-statement is:
$ 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;Instead of one rule (as EBNF does) the rule is broken into several S7SSD rules. This is necessary because S7SSD does not support the [ ] and { } notations. They are not supported for good reasons: They complicate the parameter lists and they are also not so easy to implement. On the other hand, the BNF like rules of S7SSD lead to semantic constructs which are easy to parse and easy to compile. The broken down S7SSD rules of the if-statement corresponds to the following EBNF description:
- if_statement ::=
- 'if' expression 'then'
statement
'end' 'if' .- if_statement ::=
- 'if' expression 'then'
statement
elseif_or_else_part
'end' 'if' .- elseif_or_else_part ::=
- 'elsif' expression 'then'
statement .- elseif_or_else_part ::=
- 'elsif' expression 'then'
statement
elseif_or_else_part .- elseif_or_else_part ::=
- 'else'
statement .Since S7SSD uses only one nonterminal symbol '()' it is the job of the semantic level to make sure that only the right nonterminal symbol can be used. This is done by introducing the type ELSIF_PROC (which corresponds to the nonterminal symbol 'elseif_or_else_part' of the EBNF) and the type ELSIF_RESULT (which is the result of the ELSIF_PROC).
Normally a syntax declaration can be used in many semantic declarations. E.g.: The syntax of the '+' operator is defined once and the semantic of the '+' operator is defined for the types integer, bigInteger, float, complex, ... This possibility is not needed for the if-statement. For each of the five S7SSD syntax rules of the if-statement just one corresponding semantic declaration is done:
# Semantic for the syntax: .if.().then.().end.if const proc: if (in boolean: condition) then (in proc: statements) end if is func begin case condition of when {TRUE}: statements; end case; end func; # Semantic for the syntax: .if.().then.().().end.if const proc: if (in boolean: condition) then (in proc: statements) (in ELSIF_PROC: elsifPart) end if is func begin case condition of when {TRUE}: statements; when {FALSE}: elsifPart; end case; end func; # Semantic for the syntax: .elsif.().then.() const ELSIF_PROC: elsif (in boolean: condition) then (in proc: statements) is func begin case condition of when {TRUE}: statements; end case; end func; # Semantic for the syntax: .elsif.().then.().() const ELSIF_PROC: elsif (in boolean: condition) then (in proc: statements) (in ELSIF_PROC: elsifPart) is func begin case condition of when {TRUE}: statements; when {FALSE}: elsifPart; end case; end func; # Semantic for the syntax: .else.() const ELSIF_PROC: else (ref void: voidValue) is ELSIF_EMPTY;Since no other functions of type 'ELSIF_PROC' are defined only legal if-statements can be written.
9.8 Comparison of EBNF and S7SSD
In the S7SSD of the loop-statement
$ syntax expr: .loop.().until.().do.().end.loop is -> 25;are no nonterminal expressions '()' before the first keyword or after the last keyword. Therefore the associativity does not play any role. The nonterminal expressions '()' of the loop-statement are all surrounded by keywords and therefore they can have any priority. As priority of the 'loop' 25 is chosen just because most other statements have also priority 25. The assignments (:= +:= *:= ...) have priority 20 and all operators used in arithmetic, boolean and string expressions have priorities less than 20. BTW: The semicolon operator (;) is defined with the priority 50. Operators with a priority of 0 get their parameters before operators with priority 1 and so on.
The corresponding EBNF description of the loop-statement would be:
- expression_25 ::=
- 'loop'
expression_127
'until' expression_127 'do'
expression_127
'end' 'loop' .We must keep in mind that alternative rules for expression_25 are also possible and that for every priority level a rule like
- expression_127 ::=
- expression_126 .
is defined. Additionally the following rules are defined:
- expression_0 ::=
- token | parentheses_expression |
call_expression | dot_expression .- token ::=
- identifier | literal .
- parentheses_expression ::=
- '(' expression_127 ')' .
- call_expression ::=
- expression_127 [ '('
[ expression_127 { ',' expression_127 } ]
')' ] .- dot_expression ::=
- [ '.' ] call_expression { '.' call_expression } .
The EBNF description can become long if many priority levels exist, as it is the case in Seed7.
There are some things which are out of the scope of S7SSD. The syntax of comments, tokens (identifiers and literals) and expressions (parentheses, function calls and dot expressions) is hard coded. The hard coded constructs are described in chapter 10 (Tokens) and chapter 11 (Expressions).
For the reasons mentioned above it is not possible to transform every EBNF syntax description into S7SSD. Transforming S7SSD descriptions to EBNF is always possible.
The advantage of S7SSD lies in its simplicity and that a fast automated syntax recognition algorithm can be easily implemented. It is exactly the combination of hard coded syntax recognition and flexible syntax rules that make it successful.
10. TOKENS
A program consists of a sequence of tokens which may be delimited by white space. There are two types of tokens:
- identifiers
- literals
- Syntax:
- program ::=
- { white_space | token } .
- token ::=
- identifier | literal .
Characters that introduce neither white_space nor a token trigger a parsing error:
*** tst255.sd7(1):5: Illegal character in text "\8;" (U+0008) (* Illegal character *) \b ------------------------^10.1 White space
There are three types of white space
- spaces
- comments
- line comments
White space always terminates a preceding identifier, integer, bigInteger or float literal. Some white space is required to separate otherwise adjacent tokens.
- Syntax:
- white_space ::=
- ( space | comment | line_comment )
{ space | comment | line_comment } .10.1.1 Spaces
There are several types of space characters which are ignored except as they separate tokens:
- blanks, horizontal tabs, carriage returns and new lines.
- Syntax:
- space ::=
- ' ' | TAB | CR | NL .
10.1.2 Comments
Comments are introduced with the characters (* and are terminated with the characters *) . For example:
(* This is a comment *)
Comments can span over multiple lines and comment nesting is allowed:
(* This is a comment that continues in the next line (* and has a nesting comment inside *) *)
This allows commenting out a larger section of the program, which itself contains comments. Comments cannot occur within string and character literals.
- Syntax:
- comment ::=
- '(*' { any_character } '*)' .
- any_character ::=
- simple_literal_character | apostrophe | '"' | '\' |
control_character .- control_character ::=
- NUL | SOH | STX | ETX | EOT | ENQ | ACK | BEL |
BS | TAB | LF | VT | FF | CR | SO | SI |
DLE | DC1 | DC2 | DC3 | DC4 | NAK | SYN | ETB |
CAN | EM | SUB | ESC | FS | GS | RS | US |
DEL .If a comment is not closed at the end of the main file a parsing error is triggered:
*** tst256.sd7(2):6: Unclosed comment (* Unclosed comment10.1.3 Line comments
Line comments are introduced with the character # and are terminated with the end of the line.
For example:# This is a comment
Comments cannot occur within string, character and numerical literals.
- Syntax:
- line_comment ::=
- '#' { any_character } NL .
10.2 Identifiers
There are three types of identifiers
- name identifiers
- special identifiers
- bracket
Identifiers can be written adjacent except that between two name identifiers and between two special identifiers white space must be used to separate them.
- Syntax:
- identifier ::=
- name_identifier | special_identifier | bracket .
10.2.1 Name identifiers
A name identifier is a sequence of letters, digits and underscores ( _ ). The first character must be a letter or an underscore. Examples of name identifiers are:
NUMBER integer const if UPPER_LIMIT LowerLimit x5 _endUpper and lower case letters are different. Name identifiers may have any length and all characters are significant. The name identifier is terminated with a character which is neither a letter (or _ ) nor a digit. The terminating character is not part of the name identifier.
- Syntax:
- name_identifier ::=
- ( letter | underscore ) { letter | digit | underscore } .
- letter ::=
- upper_case_letter | lower_case_letter .
- upper_case_letter ::=
- 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' |
'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' |
'U' | 'V' | 'W' | 'X' | 'Y' | 'Z' .- lower_case_letter ::=
- 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' |
'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' |
'u' | 'v' | 'w' | 'x' | 'y' | 'z' .- digit ::=
- '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' .
- underscore ::=
- '_' .
10.2.2 Special identifiers
A special identifier is a sequence of special characters. Examples of special identifiers are:
+ := <= * -> , &Here is a list of all special characters:
! $ % & * + , - . / : ; < = > ? @ \ ^ ` | ~Special identifiers may have any length and all characters are significant. The special identifier is terminated with a character which is not a special character. The terminating character is not part of the special identifier.
- Syntax:
- special_identifier ::=
- special_character { special_character } .
- special_character ::=
- '!' | '$' | '%' | '&' | '*' | '+' | ',' | '-' | '.' | '/' |
':' | ';' | '<' | '=' | '>' | '?' | '@' | '\' | '^' | '`' |
'|' | '~' .10.2.3 Brackets
A bracket is one of the following characters:
( ) [ ] { }Note that a bracket consists of only one character. Except for the character sequence (* (which introduces a comment) a bracket is terminated with the next character.
- Syntax:
- bracket ::=
- '(' | ')' | '[' | ']' | '{' | '}' .
10.3 Literals
There are several types of literals
- integer literals
- biginteger literals
- float literals
- character literals
- string literals
- Syntax:
- literal ::=
- integer_literal | biginteger_literal | float_literal |
character_literal | string_literal .10.3.1 Integer literals
An integer literal is a sequence of digits which is taken to be decimal. The sequence of digits may be followed by the letter E or e an optional + sign and a decimal exponent. Based numbers can be specified when the sequence of digits is followed by the # character and a sequence of extended digits. The decimal number in front of the # character specifies the base of the number which follows the # character. As base a number between 2 and 36 is allowed. As extended digits the letters A or a can be used for 10, B or b can be used for 11 and so on to Z or z which can be used as 35.
- Syntax:
- integer_literal ::=
- decimal_integer [ exponent | based_integer ] .
- decimal_integer ::=
- digit { digit } .
- exponent ::=
- ( 'E' | 'e' ) [ '+' ] decimal_integer .
- based_integer ::=
- '#' extended_digit { extended_digit } .
- extended_digit ::=
- letter | digit .
If an integer literal cannot be read a parsing error is triggered:
*** tst256.sd7(2):10: Integer "12345678901234567890" too big const integer: tooBig is 12345678901234567890; ---------------------------------------------^ *** tst256.sd7(3):11: Negative exponent in integer literal const integer: negativeExponent is 1e-1; -------------------------------------^ *** tst256.sd7(4):12: Digit expected found ";" const integer: digitExpected is 1e; ----------------------------------^ *** tst256.sd7(5):13: Integer "1E20" too big const integer: integerWithExponentTooBig is 1e20; ------------------------------------------------^ *** tst256.sd7(6):14: Integer base "37" not between 2 and 36 const integer: baseNotBetween2To36 is 37#0; ----------------------------------------^ *** tst256.sd7(7):15: Extended digit expected found ";" const integer: extendedDigitExpected is 16#; -------------------------------------------^ *** tst256.sd7(8):16: Illegal digit "G" in based integer "16#G" const integer: illegalBasedDigit is 16#G; ----------------------------------------^ *** tst256.sd7(9):17: Based integer "16#ffffffffffffffff" too big const integer: basedIntegerTooBig is 16#ffffffffffffffff; --------------------------------------------------------^10.3.2 BigInteger literals
A bigInteger literal is a sequence of digits followed by the underline character. The sequence of digits is taken to be decimal. Based numbers can be specified when a sequence of digits is followed by the # character, a sequence of extended digits and the underline character. The decimal number in front of the # character specifies the base of the number which follows the # character. As base a number between 2 and 36 is allowed. As extended digits the letters A or a can be used for 10, B or b can be used for 11 and so on to Z or z which can be used as 35.
- Syntax:
- biginteger_literal ::=
- decimal_integer [ based_integer ] '_' .
10.3.3 Float literals
A float literal consists of two decimal integer literals separated by a decimal point. The basic float literal may be followed by the letter E or e an optional + or - sign and a decimal exponent.
- Syntax:
- float_literal ::=
- decimal_integer '.' decimal_integer [ float_exponent ] .
- float_exponent ::=
- ( 'E' | 'e' ) [ '+' | '-' ] decimal_integer .
10.3.4 String literals
A string literal is a sequence of UTF-8 encoded Unicode characters surrounded by double quotes. For example:
"" " " "\"" "'" "\'" "String" "ch=\" " "\n\n" "Euro: \8364;" "\16#ff;"In order to represent non-printable characters and certain printable characters the following escape sequences may be used.
audible alert BEL \a backspace BS \b escape ESC \e formfeed FF \f newline NL (LF) \n carriage return CR \r horizontal tab HT \t vertical tab VT \v backslash (\) \\ apostrophe (') \' double quote (") \" control-A \A ... control-Z \Z Additionally there are the following possibilities:
- Two backslashes with a sequence of blanks, horizontal tabs, carriage returns and new lines between them are completely ignored. The ignored characters are not part of the string. This can be used to continue a string in the following line. Note that in this case the leading spaces in the new line are not part of the string.
- A backslash followed by an integer literal and a semicolon is interpreted as character with the specified ordinal number. Note that the integer literal is interpreted decimal unless it is written as based integer.
Strings are implemented with length field and UTF-32 encoding. Strings are not '\0;' terminated and therefore can also contain binary data.
- Syntax:
- string_literal ::=
- '"' { string_literal_element } '"' .
- string_literal_element ::=
- simple_literal_character | escape_sequence | apostrophe .
- simple_literal_character ::=
- letter | digit | bracket | special_literal_character |
utf8_encoded_character .- special_literal_character ::=
- ' ' | '!' | '#' | '$' | '%' | '&' | '*' | '+' | ',' | '-' |
'.' | '/' | ':' | ';' | '<' | '=' | '>' | '?' | '@' | '^' |
'_' | '`' | '|' | '~' .- escape_sequence ::=
- '\a' | '\b' | '\e' | '\f' | '\n' | '\r' | '\t' | '\v' |
'\\' | '\''' | '\"' | '\' upper_case_letter |
'\' { space } '\' | '\' integer_literal ';' .- apostrophe ::=
- ''' .
If a string literal cannot be read a parsing error is triggered:
*** tst256.sd7(2):20: Use \" instead of "" to represent " in a string const string: wrongQuotationRepresentation is "double "" quotations"; -------------------------------------------------------^ *** tst256.sd7(3):21: Illegal string escape "\z" const string: illegalStringEscape is "\z"; ---------------------------------------^ *** tst256.sd7(4):22: Numerical escape sequences should end with ";" not "x" const string: wrongNumericEscape is "\1234xyz"; ------------------------------------------^ *** tst256.sd7(5):23: The numerical escape sequence "\1234678123467892346;" is too big const string: numericEscapeTooBig is "asd\1234678123467892346;dfdfg"; -------------------------------------------------------------^ *** tst256.sd7(6):24: String continuations should end with "\" not "c" const string: backslashExpected is "string \ continuation"; --------------------------------------------------^ *** tst256.sd7(7):25: String literal exceeds source line const string: exceedsSourceLine is "abc ---------------------------------------^ *** tst256.sd7(8):27: Integer literal expected found "1.5" const string: integerExpected is "\1.5;"; --------------------------------------^10.3.5 Character literals
A character literal is an UTF-8 encoded Unicode character enclosed in apostrophes. For example:
'a' ' ' '\n' '!' '\\' '2' '"' '\"' '\'' '\8;'To represent control characters and certain other characters in character literals the same escape sequences as for string literals may be used.
- Syntax:
- character_literal ::=
- apostrophe char_literal_element apostrophe .
- char_literal_element ::=
- simple_literal_character | escape_sequence | apostrophe | '"' .
If a char literal cannot be read a parsing error is triggered:
*** tst256.sd7(2):18: "'" expected found ";" const char: apostropheExpected is 'x; ------------------------------------^ *** tst256.sd7(3):19: Character literal exceeds source line const char: charExceeds is ' ----------------------------^10.4 Unicode characters
Seed7 source code may contain UTF-8 encoded Unicode characters. Unicode is allowed in string and char literals. The pragma names can be used to allow Unicode in name identifiers:
$ names unicode;Comments and line comments may also contain Unicode, but they are not checked for valid UTF-8. This way code parts with invalid UTF-8 can be commented out. Invalid UTF-8 encodings in identifiers and literals trigger a parsing error:
*** err.sd7(90):58: Overlong UTF-8 encoding used for character "\0;" (U+0000) ignore("\0;"); -----------^ *** err.sd7(91):59: UTF-16 surrogate character found in UTF-8 encoding "\55296;" (U+d800) ignore("\55296;"); ---------------^ *** err.sd7(92):60: Non Unicode character found "\1114112;" (U+110000) "\1114112;"); ----------^ *** err.sd7(93):61: UTF-8 continuation byte expected found "A" ignore("Ã\128;A"); --------------^ *** err.sd7(94):62: Unexpected UTF-8 continuation byte found "\128;" (U+0080) ignore("\128;"); --------^ *** err.sd7(95):63: Solitary UTF-8 start byte found "\237;" (U+00ed) ignore("ÃA"); ---------^ *** bom16(1):64: UTF-16 byte order mark found "\65279;" (U+feff) þÿ -^11. EXPRESSIONS
There are two types of expressions. On one side there so called simple expressions, which are constructed using fixed predefined syntax rules. On the other side there are expressions which are constructed according to syntax rules. Syntax rules are defined with syntax declarations. How syntax declarations work is described in Chapter 3.2 (Syntax declarations) and chapter 9 (Structured syntax definition). The syntax declarations support the extensible syntax of Seed7. A simplified description of user defined expressions, which does not take priority levels into account, is:
- expression ::=
- prefix_expression | infix_expression | simple_expression .
- prefix_expression ::=
- identifier { identifier | expression } .
- infix_expression ::=
- expression identifier { identifier | expression } .
- simple_expression ::=
- dot_expression | call_expression .
The chapters below describe the predefined syntax rules of simple expressions.
11.1 Parentheses
Parentheses can be used to override any precedence rules of predefined and user defined syntax constructs. For example
2 * (3 + 4)specifies that the + operator gets his parameters first.
- Syntax:
- parentheses_expression ::=
- '(' expression ')' .
11.2 Call expressions
Call expressions can also be used to form a list. For example
writeln("hello world")
forms a list expression with the elements
- "hello world"
- writeln
The type of this list is specified with the system-declaration "system expr", which is defined in the include file "syntax.s7i" included from "seed7_05.s7i" as
$ system "expr" is expr;A call expression with two parameters as
pos("Scotty! Beam me up.", "am")forms a list expression with the elements
- "Scotty! Beam me up."
- "am"
- pos
- Syntax:
- call_expression ::=
- primary_expression [ '(' parameter_list ')' ] .
- primary_expression ::=
- parentheses_expression | token .
- parameter_list ::=
- expression { ',' expression } .
11.3 Dot expressions
Dot expressions start with a dot and have dots as separator between the elements of the list. For example
.not.TRUE
and
.OKAY.and.GO_ON
form list expressions with the elements
- not
- TRUE
and
- OKAY
- and
- GO_ON
The type of this list is specified with the system-declaration "system expr", which is defined in the include file "syntax.s7i" included from "seed7_05.s7i" as
$ system "expr" is expr;Dot expressions override the priority of the elements. Dot expressions are used in syntax-declarations.
- Syntax:
- dot_expression ::=
- '.' dot_subexpression { '.' dot_subexpression } .
- dot_subexpression ::=
- empty_parentheses | parentheses_expression | call_expression .
- empty_parentheses ::=
- '(' ')' .
12. OPERATING SYSTEM ACCESS
Seed7 provides a portable access to the services provided by an operating system. This interface is oriented towards Posix and Unix. The functions in this chapter are defined in the libraries "osfiles.s7i", "dir.s7i" and "environment.s7i".
12.1 Standard path representation
A path specifies the location of a file in a file system. Operating systems have different concepts how a path should look like. Seed7 compensates this differences with a standard path representation. Standard paths are used by all Seed7 functions dealing with paths. The standard path representation uses strings with the following properties to describe paths:
- The slash ('/') is used as path delimiter.
- Drive letters are not allowed, but there is a solution to replace them.
- Except for the path "/" a standard path is not allowed to end with a slash.
When a function like open is called with a path that is not "/", but ends with a slash, the exception RANGE_ERROR is raised. Under Windows a standard path like "/c" is mapped to the drive "C:". Reading the directory "/" under Windows returns a list of available drives. A path with a backslash or with a drive letter may raise the exception RANGE_ERROR, when a function like open is called.
An absolute path specifies an unique location in the file system. Absolute paths always start with a slash. A relative path specifies a location relative to the current working directory of the program. Although standard paths are defined in a portable way, an absolute path will usually not be portable.
12.2 File properties
Files have properties like type, size, mode (permissions), several timestamps, owner and group. Properties like type and size cannot be changed directly. Other properties may be changed. For these properties getters and setters are provided.
Property Getter Setter Comment file type fileType
fileTypeSLFor possible values see function fileType
Among others FILE_REGULAR and FILE_DIR are file typessize fileSize
bigFileSizeThe size of a file in bytes mode getFileMode setFileMode Permissions. For possible values see function getFileMode aTime getATime setATime Time of last access cTime getCTime Time of last status change mTime getMTime setMTime Time of last modification of content owner getOwner setOwner The user name of the file owner group getGroup setGroup The name of the group the file belongs to 12.2.1 fileType
The type of a file can determined with fileType or fileTypeSL:
const func integer: fileType (in string: filePath) is ... const func integer: fileTypeSL (in string: filePath) is ...The function fileType does follow symbolic links. The function fileTypeSL does not follow symbolic links. A return value of FILE_ABSENT does not imply that a file with this name can be created, since missing directories and invalid file names will also cause FILE_ABSENT.
Returns:
- FILE_ABSENT
- A component of path does not exist.
- FILE_UNKNOWN
- The file exists but has an unknown type.
- FILE_REGULAR
- The file is a regular file.
- FILE_DIR
- The file is a directory.
- FILE_CHAR
- The file is a character special file.
- FILE_BLOCK
- The file is a block special file.
- FILE_FIFO
- The file is a pipe or FIFO special file.
- FILE_SYMLINK
- The file is a symbolic link.
- FILE_SOCKET
- The file is a socket.
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'filePath' to the system path type.
- RANGE_ERROR
- 'filePath' does not use the standard path representation.
- FILE_ERROR
- The system function returns an error other than ENOENT, ENOTDIR, ENAMETOOLONG or EACCES.
12.2.2 fileSize
The size of a file can be determined with fileSize and bigFileSize:
const func integer: fileSize (in string: filePath) is ... const func bigInteger: bigFileSize (in string: filePath) is ...The functions follow symbolic links.
Returns:
For directories a size of 0 is returned. For other file types the operating system functions 'stat()' and 'seek()' are used to determine the size of a file. The functions fileSize and bigFileSize succeed when at least one strategy to determine the file size succeeds.
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'filePath' to the system path type.
- RANGE_ERROR
- 'filePath' does not use the standard path representation or it cannot be converted to the system path type.
- RANGE_ERROR
- The file size is not representable as integer (this exception is not raised by bigFileSize).
- FILE_ERROR
- It was not possible to determine the file size.
12.2.3 getFileMode
The file mode (permissions) of a file can determined with getFileMode:
const func fileMode: getFileMode (in string: filePath) is ...The function follows symbolic links. The type fileMode is defined as 'set of filePermission'.
Returns:
The fileMode which is defined as set of filePermission.
The literal values of filePermission are:
- EXEC_OTHER
- others have execute permission
- WRITE_OTHER
- others have write permission
- READ_OTHER
- others have read permission
- EXEC_GROUP
- group has execute permission
- WRITE_GROUP
- group has write permission
- READ_GROUP
- group has read permission
- EXEC_USER
- owner has execute permission
- WRITE_USER
- owner has write permission
- READ_USER
- owner has read permission
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'filePath' to the system path type.
- RANGE_ERROR
- 'filePath' does not use the standard path representation, or it cannot be converted to the system path type.
- FILE_ERROR
- The file described with 'filePath' does not exist, or a system function returns an error.
12.2.4 setFileMode
The permissions of a file can be changed with setFileMode:
const proc: setFileMode (in string: filePath, in fileMode: newFileMode) is ...The function follows symbolic links. The type fileMode is defined as 'set of filePermission'.
The literal values of filePermission are:
- EXEC_OTHER
- others have execute permission
- WRITE_OTHER
- others have write permission
- READ_OTHER
- others have read permission
- EXEC_GROUP
- group has execute permission
- WRITE_GROUP
- group has write permission
- READ_GROUP
- group has read permission
- EXEC_USER
- owner has execute permission
- WRITE_USER
- owner has write permission
- READ_USER
- owner has read permission
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'filePath' to the system path type.
- RANGE_ERROR
- 'filePath' does not use the standard path representation or it cannot be converted to the system path type.
- FILE_ERROR
- The file described with 'filePath' does not exist, or a system function returns an error.
12.2.5 getATime
The access time of a file is returned by the function getATime:
const func time: getATime (in string: filePath) is ...The function follows symbolic links.
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'filePath' to the system path type.
- RANGE_ERROR
- 'filePath' does not use the standard path representation or it cannot be converted to the system path type.
- FILE_ERROR
- The file described with 'filePath' does not exist, or a system function returns an error.
12.2.6 setATime
The function setATime sets the access time of a file:
const proc: setATime (in string: filePath, in time: aTime) is ...The function follows symbolic links.
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'filePath' to the system path type.
- RANGE_ERROR
- 'filePath' does not use the standard path representation or it cannot be converted to the system path type, or 'aTime' is invalid, or 'aTime' cannot be converted to the system file time.
- FILE_ERROR
- The file described with 'filePath' does not exist, or a system function returns an error.
12.2.7 getCTime
The status change time of a file is returned by the function getCTime:
const func time: getCTime (in string: filePath) is ...The function follows symbolic links.
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'filePath' to the system path type.
- RANGE_ERROR
- 'filePath' does not use the standard path representation or it cannot be converted to the system path type.
- FILE_ERROR
- The file described with 'filePath' does not exist, or a system function returns an error.
12.2.8 getMTime
The modification time of a file is returned by the function getMTime:
const func time: getMTime (in string: filePath) is ...The function follows symbolic links.
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'filePath' to the system path type.
- RANGE_ERROR
- 'filePath' does not use the standard path representation or it cannot be converted to the system path type.
- FILE_ERROR
- The file described with 'filePath' does not exist, or a system function returns an error.
12.2.9 setMTime
The function setMTime sets the modification time of a file:
const proc: setMTime (in string: filePath, in time: aTime) is ...The function follows symbolic links.
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'filePath' to the system path type.
- RANGE_ERROR
- 'filePath' does not use the standard path representation or it cannot be converted to the system path type or 'aTime' is invalid, or 'aTime' cannot be converted to the system file time.
- FILE_ERROR
- The file described with 'filePath' does not exist, or a system function returns an error.
12.2.10 getOwner
The owner of a file is returned by the function getOwner:
const func string: getOwner (in string: filePath) is ...The function follows symbolic links.
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'filePath' to the system path type.
- RANGE_ERROR
- 'filePath' does not use the standard path representation or it cannot be converted to the system path type.
- FILE_ERROR
- The file described with 'filePath' does not exist, or a system function returns an error.
12.2.11 setOwner
The function setOwner sets the owner of a file:
const proc: setOwner (in string: filePath, in string: owner) is ...The function follows symbolic links.
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'filePath' to the system path type.
- RANGE_ERROR
- 'filePath' does not use the standard path representation or it cannot be converted to the system path type or 'aTime' is invalid, or 'aTime' cannot be converted to the system file time.
- FILE_ERROR
- The file described with 'filePath' does not exist, or a system function returns an error.
12.2.12 getGroup
The group of a file is returned by the function getGroup:
const func string: getGroup (in string: filePath) is ...The function follows symbolic links.
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'filePath' to the system path type.
- RANGE_ERROR
- 'filePath' does not use the standard path representation or it cannot be converted to the system path type.
- FILE_ERROR
- The file described with 'filePath' does not exist, or a system function returns an error.
12.2.13 setGroup
The function setGroup sets the group of a file:
const proc: setGroup (in string: filePath, in string: group) is ...The function follows symbolic links.
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'filePath' to the system path type.
- RANGE_ERROR
- 'filePath' does not use the standard path representation or it cannot be converted to the system path type or 'aTime' is invalid, or 'aTime' cannot be converted to the system file time.
- FILE_ERROR
- The file described with 'filePath' does not exist, or a system function returns an error.
12.3 Symbolic links
Symbolic links (symlinks) are files pointing to a target file or directory. They specify a relative or absolute path to the target (destination). Relative symbolic links are relative to their location in the file system and not relative to the current working directory. The target of a symbolic link may not exist. In this case it is a dangling symbolic link. Many file functions follow symbolic links. Following means: For a symbolic link the function follows the symbolic link chain until the path is not a symbolic link again. Afterwards the function is applied to this final path.
Functions that follow symlinks Functions that work only on symlinks and don't follow them A dangling symlink raises FILE_ERROR. FILE_ERROR is raised if 'path' is not a symlink. fileSize(path) bigFileSize(path) getFileMode(path) setFileMode(path, mode) getFileMode(path, SYMLINK) getATime(path) setATime(path, time) getATime(path, SYMLINK) getCTime(path) getMTime(path) setMTime(path, time) getMTime(path, SYMLINK) setMTime(path, time, SYMLINK) getOwner(path) setOwner(path, name) getOwner(path, SYMLINK) setOwner(path, name, SYMLINK) getGroup(path) setGroup(path, name) getGroup(path, SYMLINK) setGroup(path, name, SYMLINK) readLink(path) readLink(path, ABSOLUTE) Functions that do not follow symbolic links:
Function Comment removeFile(path) Can be used to remove a symbolic link removeTree(path) Can be used to remove a symbolic link cloneFile(source, dest) Can be used to copy a symbolic link moveFile(source, dest) Can be used to rename a symbolic link 12.3.1 readLink
The functions readLink(path) and readLink(path, ABSOLUTE) read the destination of a symbolic link:
const func string: readLink (in string: filePath) is ... const func string: readLink (in string: filePath, ABSOLUTE) is ...The function readLink(path) reads the link destination stored in the file system. Symbolic links can be relative or absolute. Relative symbolic links are relative to their location in the file system and not relative to the current working directory. The function readLink(path, ABSOLUTE) always returns an absolute path. It leaves absolute symbolic links unchanged and converts relative symbolic links to an absolute path.
Returns:
The symbolic link referred by 'filePath'.
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'filePath' to the system path type or not enough memory to represent the result string.
- RANGE_ERROR
- 'filePath' does not use the standard path representation or it cannot be converted to the system path type.
- FILE_ERROR
- The file described with 'filePath' does not exist, or it is not a symbolic link, or a system function returns an error.
12.3.2 finalPath
The function finalPath returns the final path that functions like getMTime and open would use. If filePath is not a symbolic link it is returned. For a symbolic link the function follows the symbolic link chain until the path is not a symbolic link again. The final path may refer to a non-existing file.
const func string: finalPath (in string: filePath) is ...
Parameters:
- filePath
- Relative or absolute path.
Returns:
The final path after possibly following a symbolic link chain.
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'filePath' to the system path type or not enough memory to represent the result string.
- RANGE_ERROR
- 'filePath' does not use the standard path representation or it cannot be converted to the system path type.
- FILE_ERROR
- The file described with 'filePath' does not exist or a system function returns an error.
12.3.3 makeLink
The function makeLink creates a symbolic link at symlinkPath that contains the string referred by targetPath. The function does not follow symbolic links.
const proc: makeLink (in string: symlinkPath, in string: targetPath) is ...
Parameters:
- symlinkPath
- Name of the symbolic link to be created.
- targetPath
- String to be contained in the symbolic link.
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'symlinkPath' or 'targetPath' to the system path type.
- RANGE_ERROR
- 'symlinkPath' or 'targetPath' does not use the standard path representation, or one of them cannot be converted to the system path type.
- FILE_ERROR
- The file ''dirPath'' already exists, or a system function returns an error.
12.3.4 Symbolic link getFileMode
The file mode (permissions) of a symbolic link can determined with getFileMode(path, SYMLINK):
const func fileMode: getFileMode (in string: filePath, SYMLINK) is ...The function only works for symbolic links and does not follow the symbolic link.
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'filePath' to the system path type.
- RANGE_ERROR
- 'filePath' does not use the standard path representation, or it cannot be converted to the system path type.
- FILE_ERROR
- The file described with 'filePath' does not exist, or it is not a symbolic link, or a system function returns an error.
12.3.5 Symbolic link getATime
The access time of a symbolic link is returned by the function getATime(path, SYMLINK):
const func time: getATime (in string: filePath, SYMLINK) is ...The function only works for symbolic links and does not follow the symbolic link.
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'filePath' to the system path type.
- RANGE_ERROR
- 'filePath' does not use the standard path representation, or it cannot be converted to the system path type.
- FILE_ERROR
- The file described with 'filePath' does not exist, or it is not a symbolic link, or a system function returns an error.
12.3.6 Symbolic link getMTime
The modification time of a symbolic link is returned by the function getMTime(path, SYMLINK):
const func time: getMTime (in string: filePath, SYMLINK) is ...The function only works for symbolic links and does not follow the symbolic link.
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'filePath' to the system path type.
- RANGE_ERROR
- 'filePath' does not use the standard path representation, or it cannot be converted to the system path type.
- FILE_ERROR
- The file described with 'filePath' does not exist, or it is not a symbolic link, or a system function returns an error.
12.3.7 Symbolic link setMTime
The function setMTime(path, time, SYMLINK) sets the modification time of a symbolic link:
const proc: setMTime (in string: filePath, in time: aTime, SYMLINK) is ...The function only works for symbolic links and does not follow the symbolic link.
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'filePath' to the system path type.
- RANGE_ERROR
- 'filePath' does not use the standard path representation or it cannot be converted to the system path type or 'aTime' is invalid, or 'aTime' cannot be converted to the system file time.
- FILE_ERROR
- The file described with 'filePath' does not exist, or it is not a symbolic link, or a system function returns an error.
12.3.8 Symbolic link getOwner
The owner of a symbolic link is returned by the function getOwner(path, SYMLINK):
const func string: getOwner (in string: filePath, SYMLINK) is ...The function only works for symbolic links and does not follow the symbolic link.
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'filePath' to the system path type.
- RANGE_ERROR
- 'filePath' does not use the standard path representation or it cannot be converted to the system path type.
- FILE_ERROR
- The file described with 'filePath' does not exist, or it is not a symbolic link, or a system function returns an error.
12.3.9 Symbolic link setOwner
The function setOwner(path, owner, SYMLINK) sets the owner of a symbolic link:
const proc: setOwner (in string: filePath, in string: owner, SYMLINK) is ...The function only works for symbolic links and does not follow the symbolic link.
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'filePath' to the system path type.
- RANGE_ERROR
- 'filePath' does not use the standard path representation or it cannot be converted to the system path type or 'aTime' is invalid, or 'aTime' cannot be converted to the system file time.
- FILE_ERROR
- The file described with 'filePath' does not exist, or it is not a symbolic link, or a system function returns an error.
12.3.10 Symbolic link getGroup
The group of a symbolic link is returned by the function getGroup(path, SYMLINK):
const func string: getGroup (in string: filePath, SYMLINK) is ...The function only works for symbolic links and does not follow the symbolic link.
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'filePath' to the system path type.
- RANGE_ERROR
- 'filePath' does not use the standard path representation or it cannot be converted to the system path type.
- FILE_ERROR
- The file described with 'filePath' does not exist, or it is not a symbolic link, or a system function returns an error.
12.3.11 Symbolic link setGroup
The function setGroup(path, group, SYMLINK) sets the group of a symbolic link:
const proc: setGroup (in string: filePath, in string: group, SYMLINK) is ...The function only works for symbolic links and does not follow the symbolic link.
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'filePath' to the system path type.
- RANGE_ERROR
- 'filePath' does not use the standard path representation or it cannot be converted to the system path type or 'aTime' is invalid, or 'aTime' cannot be converted to the system file time.
- FILE_ERROR
- The file described with 'filePath' does not exist, or it is not a symbolic link, or a system function returns an error.
12.4 Directory functions
Directories are a special kind of file. They contain references to other files. Some functions work only on directories (e.g.: readDir) while other functions (e.g.: getMTime) will work on any kind of file. Since directories are files they are not mentioned specifically in the description of such generic functions.
12.4.1 readDir
The function readDir provides a portable access to the contents of directories in the file system. It reads the specified directory and the filenames are stored in the string-array result. The files "." and ".." are excluded from the result. Note that the strings contain only the filenames. Additional information must be obtained using other calls.
const func array string: readDir (in string: dirPath) is ...
Returns:
An array of strings containing the names of all files in the specified directory, except "." and ".."
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'dirPath' to the system path type or not enough memory to represent the result array string.
- RANGE_ERROR
- 'dirPath' does not use the standard path representation or it cannot be converted to the system path type.
- FILE_ERROR
- The file described with 'dirPath' does not exist, or it is not a directory, or a system function returns an error.
Examples:
After the declaration
var array string: dir_array is 0 times "";the statement
dir_array := readDir(".");
reads the current working directory and stores it into the string-array 'dir_array'. The components of the directory can now be accessed via indexing:
for index range 1 to length(dir_array) do writeln(dir_array[index]); end for;12.4.2 openDir
The function openDir opens the specified directory as file. Each line in this directory file contains the filename of a file present in the directory. The files "." and ".." are left out from the directory file. Note that only filenames can be read from the directory file. Additional information must be obtained with other calls.
const func file: openDir (in string: dirPath) is ...
Returns:
The directory file of the specified directory.
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'dirPath' to the system path type or not enough memory to represent the result array string.
- RANGE_ERROR
- 'dirPath' does not use the standard path representation or it cannot be converted to the system path type.
- FILE_ERROR
- A system function returns an error.
12.4.3 getcwd
The function getcwd returns the current working directory of the calling process as absolute path.
const func string: getcwd is ...
Returns:
The absolute path of the current working directory.
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to represent the result string.
- FILE_ERROR
- The system function returns an error.
Examples:
The statement
my_dir := getcwd;assigns the full path of the current working directory to the string variable 'my_dir'.
12.4.4 chdir
The function chdir changes the current working directory of the calling process to the specified directory.
const proc: chdir (in string: name) is ...
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'name' to the system path type.
- RANGE_ERROR
- 'name' does not use the standard path representation or it cannot be converted to the system path type.
- FILE_ERROR
- A system function returns an error.
Examples:
The statement
chdir("/usr/bin");
changes the current working directory to "/usr/bin".
12.4.5 makeDir
The function makeDir creates a new directory. The function does not follow symbolic links.
const proc: makeDir (in string: dirPath) is ...
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'dirPath' to the system path type.
- RANGE_ERROR
- 'dirPath' does not use the standard path representation or it cannot be converted to the system path type.
- FILE_ERROR
- The file ''dirPath'' already exists, or a system function returns an error.
Examples:
The statement
makeDir("my_dir");
creates the directory "my_dir".
12.4.6 homeDir
The function homeDir returns the home directory of the user as absolute path.
const func string: homeDir is ...This function should be preferred over the use of an environment variable such as $HOME. $HOME is not supported under all operating systems and it is not guaranteed, that it uses the standard path representation.
Returns:
The absolute path of the home directory.
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to represent the result string.
- FILE_ERROR
- Not able to determine the home directory.
Examples:
The statement
my_dir := homeDir;assigns the full path of the home directory to the string variable 'my_dir'.
12.5 Maintenance functions
12.5.1 removeFile
The function removeFile removes a file of any type unless it is a directory that is not empty. An attempt to remove a directory that is not empty triggers FILE_ERROR.
const proc: removeFile (in string: filePath) is ...
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'filePath' to the system path type.
- RANGE_ERROR
- 'filePath' does not use the standard path representation, or it cannot be converted to the system path type.
- FILE_ERROR
- The file does not exist or a system function returns an error.
12.5.2 removeTree
The function removeTree removes a file of any type inclusive a directory tree:
const proc: removeTree (in string: filePath) is ...
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'filePath' to the system path type.
- RANGE_ERROR
- 'filePath' does not use the standard path representation or it cannot be converted to the system path type.
- FILE_ERROR
- The file does not exist or a system function returns an error.
12.5.3 copyFile
The function copyFile copies a file or directory tree:
const proc: copyFile (in string: sourcePath, in string: destPath) is ...Permissions/mode, ownership and timestamps of the destination file are determined independent of the corresponding source properties. The destination file gets the permissions/mode defined by umask. The user executing the program is the owner of the destination file. The timestamps of the destination file are set to the current time. Symbolic links in sourcePath are always followed. Therefore copyFile will never create a symbolic link. Note that copyFile does not preserve hard links (they are resolved to distinct files).
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'sourcePath' or 'destPath' to the system path type.
- RANGE_ERROR
- 'sourcePath' or 'destPath' does not use the standard path representation or one of them cannot be converted to the system path type.
- FILE_ERROR
- Source file does not exist, destination file already exists or a system function returns an error.
12.5.4 cloneFile
The function cloneFile clones a file or directory tree:
const proc: cloneFile (in string: sourcePath, in string: destPath) is ...Permissions/mode, ownership and timestamps of the original are preserved. Symlinks are not followed. Instead the symlink is copied. Note that cloneFile does not preserve hard links (they are resolved to distinct files).
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'sourcePath' or 'destPath' to the system path type.
- RANGE_ERROR
- 'sourcePath' or 'destPath' does not use the standard path representation or one of them cannot be converted to the system path type.
- FILE_ERROR
- Source file does not exist, destination file already exists or a system function returns an error.
12.5.5 moveFile
The function moveFile moves and/or renames a file or directory tree:
const proc: moveFile (in string: sourcePath, in string: destPath) is ...The function uses the C 'rename()' function. When 'rename()' fails the file (or directory tree) is cloned with cloneFile (which preserves permissions/mode, ownership and timestamps) to the new place and with the new name. When cloneFile succeeds the original file is deleted. When cloneFile fails (no space on device or other reason) all remains of the failed clone are removed. Note that cloneFile works for symbolic links but does not preserve hard links (they are resolved to distinct files).
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'sourcePath' or 'destPath' to the system path type.
- RANGE_ERROR
- 'sourcePath' or 'destPath' does not use the standard path representation or one of them cannot be converted to the system path type.
- FILE_ERROR
- Source file does not exist, destination file already exists or a system function returns an error.
12.6 Environment
12.6.1 argv(PROGRAM)
The function argv(PROGRAM) returns the argument vector of the program as array of strings. The name of the program is not part of the argument vector.
const func array string: argv (PROGRAM) is ...
Returns:
An array of strings containing the argument vector.
12.6.2 name(PROGRAM)
The function name(PROGRAM) returns the name of the program without path and extension. The name returned by name(PROGRAM) is the same for interpreted and compiled programs. The function name(PROGRAM) does not follow symbolic links. It determines, with which name a program was called. When several symbolic links refer to one program name(PROGRAM) returns the name of the symbolic link.
const func string: name (PROGRAM) is ...
Returns:
The name of the program.
12.6.3 path(PROGRAM)
The function path(PROGRAM) returns the absolute path of the program. For an interpreted program this is the absolute path of the source file. For a compiled program this is the absolute path of the executable. The function path(PROGRAM) does follow symbolic links.
const func string: path (PROGRAM) is ...
Returns:
The absolute path of the program.
12.6.4 dir(PROGRAM)
The function dir(PROGRAM) returns the absolute path of the directory containing the program. The function dir(PROGRAM) allows placing configuration data in the directory of the program. dir(PROGRAM) is based on path(PROGRAM).
const func string: dir (PROGRAM) is ...
Returns:
The absolute path of the directory containing the program.
12.6.5 file(PROGRAM)
The function file(PROGRAM) returns the filename of the program without path. file(PROGRAM) is based on path(PROGRAM).
const func string: file (PROGRAM) is ...
Returns:
The filename of the program.
12.6.6 getenv
The function getenv determines the value of an environment variable.
const func string: getenv (in string: name) is ...The function getenv searches the environment for an environment variable with the given 'name'. When such an environment variable exists the corresponding string value is returned.
Returns:
The value of an environment variable or "" when the requested environment variable does not exist.
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'name' to the system string type or not enough memory to represent the result string.
- RANGE_ERROR
- 'name' cannot be converted to the system string type or a system function returns an error.
12.6.7 setenv
The function setenv adds or changes an environment variable.
const proc: setenv (in string: name, in string: value) is ...The function setenv searches the environment for an environment variable with the given 'name'. When such an environment variable exists the corresponding value is changed to 'value'. When no environment variable with the given 'name' exists a new environment variable 'name' with the value 'value' is created.
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'name' or 'value' to the system string type.
- RANGE_ERROR
- 'name' or 'value' cannot be converted to the system string type or a system function returns an error.
12.6.8 unsetenv
The function unsetenv removes an environment variable.
const proc: unsetenv (in string: name) is ...The function unsetenv searches the environment for an environment variable with the given 'name'. When such an environment variable exists it is removed from the environment. When no environment variable with the given 'name' exists the function succeeds, and the environment is unchanged.
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to convert 'name' to the system string type.
- RANGE_ERROR
- 'name' cannot be converted to the system string type or a system function returns an error.
12.6.9 environment
The function environment returns the list of environment variable names as array of strings.
const func array string: environment is ...
Returns:
The list of environment variable names.
Possible exceptions:
- MEMORY_ERROR
- Not enough memory to create the result.
13. DATABASE ABSTRACTION API
Seed7 provides an abstraction layer for database access. There is an application programming interface (API), which defines how a client may access a database. Seed7 accomplishes database independence by using database drivers as abstraction layers between the application and the database. There are database drivers for MySQL, MariaDB, SQLLite, PostgreSQL, Oracle, Firebird, Interbase, Db2, Informix and SQL Server databases. Databases can also be accessed via the ODBC interface. The following example uses the database abstraction API:
const proc: dbDemo is func local var database: currDb is database.value; var sqlStatement: statement is sqlStatement.value; var integer: index is 0; begin currDb := openDatabase(DB_MYSQL, "testDb", "testUser", "testPassword"); if currDb <> database.value then statement := prepare(currDb, "SELECT * FROM testTable"); execute(statement); while fetch(statement) do for index range 1 to columnCount(statement) do write(column(statement, index, string) <& ", "); end for; writeln; end while; close(currDb); end if; end func;13.1 Opening a database connection
To open a database connection you need to provide several things:
- The database type used.
- The host where the database is running. An empty host name ("") specifies the local machine ("localhost").
- The port to access the database. A port of 0 specifies the default port of the database.
- The name of the database.
- A database user name.
- The password of the database user.
Depending on the database a corresponding database driver must be used:
Database Type Driver Default port Comment MySQL DB_MYSQL 3306 MariaDB DB_MYSQL 3306 SQLLite DB_SQLITE Host must be "" and port must be 0. PostgreSQL DB_POSTGRESQL 5432 Oracle DB_OCI 1521 Firebird DB_FIRE Interbase DB_FIRE Db2 DB_DB2 50000 Informix DB_INFORMIX 1526 SQL Server DB_SQL_SERVER 1433 various DBs DB_ODBC Needs an ODBC driver to connect to a database. Sybase based DB_TDS 1433 Supports SQL Server and Sybase. A basic function to open a database is:
const func database: openDatabase (in dbCategory: driver, in string: host, in integer: port, in string: dbName, in string: user, in string: password)The following statements each open a database:
currDb := openDatabase(DB_MYSQL, "www.example.org", 0, "testDb", "testUser", "testPassword"); currDb := openDatabase(DB_MYSQL, "192.0.2.235", 0, "testDb", "testUser", "testPassword"); currDb := openDatabase(DB_POSTGRESQL, "1234:feed::dead:beef", 0, "testDb", "testUser", "testPassword"); currDb := openDatabase(DB_POSTGRESQL, "localhost", 0, "testDb", "testUser", "testPassword"); currDb := openDatabase(DB_OCI, "", 0, "aServiceName", "testUser", "testPassword"); currDb := openDatabase(DB_OCI, "www.example.org", 2345, "aServiceName", "testUser", "testPassword"); currDb := openDatabase(DB_OCI, "192.0.2.235", 0, "aSid", "testUser", "testPassword"); currDb := openDatabase(DB_DB2, "www.example.org", 0, "testDb", "testUser", "testPassword"); currDb := openDatabase(DB_SQL_SERVER, "192.168.1.13", 0, "testDb", "testUser", "testPassword"); currDb := openDatabase(DB_TDS, "192.168.1.13", 0, "testDb", "testUser", "testPassword");The host can be specified by name (e.g.: "www.example.org"), by an IPv4 address (e.g.: "192.0.2.235") or by an IPv6 address in colon notation (e.g.: "1234:feed::dead:beef"). Specifying "" as host means "localhost".
13.1.1 Opening an Oracle database connection
When using the DB_OCI driver you can either supply a net_service_name from tnsnames.ora or a service_name or a sid as dbName. If tnsnames.ora is used the parameter host must be "" and the parameter port must be 0.
currDb := openDatabase(DB_OCI, "", 0, "tnsnamesOraEntryName", "testUser", "testPassword");13.1.2 Opening a Db2 database connection
When using the DB_DB2 driver you can either supply a DSN (data source name) from db2cli.ini (or db2dsdriver.cfg) or a database name as dbName. If a DSN is used the parameter host must be "" and the parameter port must be 0.
currDb := openDatabase(DB_DB2, "", 0, "databaseAlias", "testUser", "testPassword");13.1.3 Opening a SQL Server database connection
When using the DB_SQL_SERVER driver you can either supply a database name from the local machine or a database that can be accessed via TCP/IP. To access a database at the local machine the parameter host must be "" and the parameter port must be 0. If TCP/IP is used it must be enabled in the database.
currDb := openDatabase(DB_SQL_SERVER, "", 0, "localDb", "testUser", "testPassword");13.1.4 Opening a SQLite database connection
A SQLite database can be opened with:
currDb := openDatabase(DB_SQLITE, "", 0, "aDir/dbName", "", ""); currDb := openDatabase(DB_SQLITE, "", 0, "aDir/dbName.db", "", ""); currDb := openDatabase(DB_SQLITE, "", 0, "/c/Users/JohnSmith/dbName", "", "");The path to the database file (in the example above "aDir/dbName") must use the Seed7 standard path representation. If the database file is specified with a relative path it is searched relative to the current working directory. The database file name can be specified with or without the extension ".db". For a SQLite database host must be "" and port must be 0. Since SQLite works without user and password the parameters user and password are always ignored.
13.1.5 Opening an Informix database connection
When using the DB_INFORMIX driver you need to specify also a server:
const func database: openDatabase (DB_INFORMIX, in string: host, in integer: port, in string: server, in string: dbName, in string: user, in string: password)A Informix database can be opened with:
currDb := openDatabase(DB_INFORMIX, "", 0, "serverName", "databaseName", "testUser", "testPassword"); currDb := openDatabase(DB_INFORMIX, "www.example.org", 0, "testServer", "testDb", "testUser", "testPassword");13.1.6 Opening an ODBC database connection
The Seed7 database driver DB_ODBC is special, as the ODBC interface itself allows connecting to several database types. The ODBC interface library accomplishes this by using ODBC drivers. Unfortunately these drivers do come in varying quality. Accessing a database directly via the Seed7 driver should be the preferred method. For SQL Server ODBC is the only connection interface. Opening an ODBC database can be done with the following function:
const func database: openDatabase (DB_ODBC, in string: odbcDriver, in string: server, in string: dbName, in string: user, in string: password)A SQL Server can be opened with:
currDb := openDatabase(DB_ODBC, "sqlserver", "", "", "testUser", "testPassword"); currDb := openDatabase(DB_ODBC, "sqlserver", "", "", "", "");If server or dbName are empty ("") the default values of the ODBC driver are used. The ODBC driver may provide also default values for user and password.
ODBC uses also data source names (DSNs) to specify possible database connections. It is possible to open an ODBC database by specifying the data source name (DSN) in the parameter dbName. In this case the parameters odbcDriver and server must be "".
currDb := openDatabase(DB_ODBC, "", "", "dsnName", "testUser", "testPassword"); currDb := openDatabase(DB_ODBC, "", "", "dsnName", "", "");When opening using a DSN succeeds, the parameters odbcDriver and server are ignored. A DSN might also specify user and password. In this case this parameters can be left empty, when openDatabase() is called.
When using windows the DSNs and the ODBC drivers can be managed with:
- Start -> Control Panel -> Administrative Tools -> Data Sources (ODBC).
The data source names (DSNs) of unixODBC are specified in the file odbc.ini. The ODBC drivers of unixODBC are specified in the file odbcinst.ini.
13.2 Other ways to open a database connection
There is another variant of opening a database:
const func database: openDatabase (in dbCategory: driver, in string: dbPath, in string: user, in string: password)The dbPath can be given in one of these forms:
- host:port/dbName
- host/dbName
- dbName
The host can be specified by name (e.g.: "www.example.org"), or by IPv4 address (e.g.: "192.0.2.235") or by IPv6 address in colon notation (e.g.: "[1234:feed::dead:beef]"). Note that an IPv6 address must be enclosed in brackets. If host is not specified the default host ("localhost") will be used. If port is not specified the default port of the driver will be used. The following statements each open a database:
currDb := openDatabase(DB_MYSQL, "www.example.org:1234/testDb", "testUser", "testPassword"); currDb := openDatabase(DB_MYSQL, "[1234:feed::dead:beef]:1234/testDb", "testUser", "testPassword"); currDb := openDatabase(DB_POSTGRESQL, "192.0.2.235/testDb", "testUser", "testPassword"); currDb := openDatabase(DB_POSTGRESQL, "testDb", "testUser", "testPassword"); currDb := openDatabase(DB_OCI, "sidOrServiceName", "testUser", "testPassword"); currDb := openDatabase(DB_OCI, "tnsnamesOraEntryName", "testUser", "testPassword");If driver is DB_ODBC the dbPath can be specified in one of these forms:
- odbcDriver:dbServer/dbName
- odbcDriver:dbServer
- dbServer/dbName
- odbcDataSourceName
Use a value like "sqlserver" for odbcDriver.
If driver is DB_SQLITE then dbPath is the path of a database file:
- sqlitePath
The sqlitePath uses the Seed7 standard path representation. If sqlitePath is a relative path the database file is searched relative to the current working directory. The database file name can be specified with or without the extension ".db". The following statements each open a SQLite database:
currDb := openDatabase(DB_SQLITE, "aDir/dbName", "", ""); currDb := openDatabase(DB_SQLITE, "aDir/dbName.db", "", ""); currDb := openDatabase(DB_SQLITE, "/c/Users/JohnSmith/dbName", "", "");It is also possible ot open a database with a connect string:
const func database: openDatabase (in dbCategory: driver, in string: connectStri)The connectStri must be in one of the forms
- user:password@dbPath
- user@dbPath
- dbPath
If no user is specified the user "guest" will be used. If no password is specified the password "guest" will be used. The dbPath is specified as before.
13.3 Prepared statements
All SQL statements (e.g. SELECT, CREATE, INSERT, UPDATE) can be executed by using prepared statements. The database abstraction API does not provide a way to execute SQL without a prepared statement. After a prepared statement has been created it can be executed multiple times. Databases usually optimize prepared statements for fast execution. Prepared statements are created with the following function:
const func sqlStatement: prepare (in database: db, in string: sqlStatementStri)Regarding the parameter sqlStatementStri some things must be considered:
- A question mark (?) will be used as placeholder for bind variables.
- Strings in a SQL statement are enclosed in apostrophes (e.g. 'abc').
- A string consists of all characters between the enclosing apostrophes.
- Apostrophe characters (') in a string must be doubled to get one apostrophe character in the string.
- Comments in a SQL statement start with /* and end with */.
- Line comments in a SQL statement start with -- and end with a newline character ('\n').
- Table and field names can be enclosed in double quotes (e.g. "aTable").
- This way a table or field name may contain spaces or other characters, that are normally not allowed.
- Double quotes in a quoted name must be doubled (be aware that several databases do not allow double quotes in names).
The following statements each create a prepared SQL statement:
statement := prepare(currDb, "CREATE TABLE customers (name CHAR(128), area CHAR(128))"); statement := prepare(currDb, "SELECT * FROM customers"); statement := prepare(currDb, "SELECT * FROM customers /* comment */ WHERE name = 'adam'"); statement := prepare(currDb, "SELECT * FROM customers -- Comment\n WHERE name != 'adam'"); statement := prepare(currDb, "SELECT * FROM customers WHERE name = ?"); statement := prepare(currDb, "SELECT * FROM customers WHERE name LIKE '%''%'"); statement := prepare(currDb, "SELECT \"a field\" FROM \"a table\"");Preparing a statement fails with a RANGE_ERROR, if the database is not open. This is checked by the driver. Other things are checked by the database. The database might raise the exception DATABASE_ERROR. Note that some databases do not check everything, when preparing the statement. So an invalid SQL statement might be accepted by prepare(), but executing the prepared statement later will fail.
Executing a prepared statement that neither has bind variables nor returns a result is quite simple:
statement := prepare(currDb, "CREATE TABLE customers (name CHAR(128), area CHAR(128))"); execute(statement);13.4 Bind values to placeholders
Question marks (?) in a prepared statement string are used as placeholder for bind variables. Before a prepared statement is executed it is necessary to bind values to the placeholders (?). Prepared statements without placeholders do not need a binding. It is possible to bind the same placeholder as often as you like. even with values from different types. This can be used to execute the same prepared statement multiple times with different values. The binding is done with a bind() function. For several types bind() functions are defined:
const proc: bind (inout sqlStatement: statement, in integer: pos, in bigInteger: num) const proc: bind (inout sqlStatement: statement, in integer: pos, in bigRational: num) const proc: bind (inout sqlStatement: statement, in integer: pos, in boolean: flag) const proc: bind (inout sqlStatement: statement, in integer: pos, in bstring: bstri) const proc: bind (inout sqlStatement: statement, in integer: pos, in float: number) const proc: bind (inout sqlStatement: statement, in integer: pos, in integer: number) const proc: bind (inout sqlStatement: statement, in integer: pos, NULL) const proc: bind (inout sqlStatement: statement, in integer: pos, in string: stri) const proc: bind (inout sqlStatement: statement, in integer: pos, in time: timeData) const proc: bind (inout sqlStatement: statement, in integer: pos, in duration: durationData)Binding fails with a RANGE_ERROR, if the statement has not been prepared. Binding is done by position. Position numbers start with 1. To bind the integer 12345 to the third placeholder (?) of a prepared statement do:
bind(statement, 3, 12345);
The bind() functions check the given position (pos) and raise the exception RANGE_ERROR, if no corresponding placeholder (?) is found. This happens if pos <= 0 holds or if pos is greater than the number of placeholders. The bind() functions check also, if the type of the given value fits to the database column. If the type does not fit the exception RANGE_ERROR is raised.
Another example with binding is:
write("name? "); readln(name); statement := prepare(currDb, "SELECT name, area FROM customers WHERE name = ?"); bind(statement, 1, name); execute(statement); . . . Write a list of names and areas.Binding protects against SQL injection. SQL injection is a technique to attack applications. SQL injection is possible, if the SQL statement is build from user input. Suppose we do the example above without binding:
write("name? "); readln(name); statement := prepare(currDb, "SELECT name, area FROM customers WHERE name = '" <& name <& "'"); execute(statement); . . . Write a list of names and areas.Suppose the user enters (when asked for the name):
' UNION SELECT login, password FROM user --This would prepare and execute the SQL statement:
SELECT name, area FROM customers WHERE name = '' UNION SELECT login, password FROM user --'The result would additionally contain secret data you certainly would not like to be displayed.
13.5 Execute a prepared statement
To make a prepared statement run it must be executed. Prepared statements are executed with the following function:
const proc: execute (inout sqlStatement: statement)The following statement executes a prepared SQL statement:
execute(statement);
Executing fails with a RANGE_ERROR, if the statement has not been prepared. Executing fails with a DATABASE_ERROR, if not all parameters have been bound. If the database returns an error the exception DATABASE_ERROR gets also raised. Note that invalid SQL statements might raise a DATABASE_ERROR in prepare() or in execute(). When the exception is raised depends on the database.
There are prepared statements, that return a result set of records (e.g.: SELECT) and others that do not return data (e.g.: UPDATE). After executing a prepared statement the number of columns in a record (row) of the result set can be retrieved with the following function:
const func integer: columnCount (in sqlStatement: statement)If a prepared statement does not return data columnCount() returns 0. The names of the columns in a record (row) of the result set can be obtained with the function:
const func string: columnName (in sqlStatement: statement, in integer: column)These functions can be combined to write the column names of a prepared statement:
execute(statement); for columnNum range 1 to columnCount(statement) do write(columnName(statement, columnNum) <& " "); end for; writeln;13.6 Fetch records from the result set
After executing a prepared statement that returns data (e.g.: SELECT), the records (rows) can be fetched one by one with fetch(). After executing a prepared statement returning no data fetching is not necessary. Fetching is done with the following function:
const func boolean: fetch (in sqlStatement: statement)The function returns TRUE, if a record of the result set could be fetched successfully. The function returns FALSE, if there is no data (e.g.: UPDATE) or no more row (record) to fetch. The following example shows how fetch() is usually used:
execute(statement); while fetch(statement) do . . . Process a record from the result set. end while;13.7 Get columns from fetched records
After a record (row) has been fetched from a result set individual column data can be retrieved with a column() function. For several types column() functions are defined:
const func bigInteger: column (in sqlStatement: statement, in integer: column, attr bigInteger) const func bigRational: column (in sqlStatement: statement, in integer: column, attr bigRational) const func boolean: column (in sqlStatement: statement, in integer: column, attr boolean) const func bstring: column (in sqlStatement: statement, in integer: column, attr bstring) const func duration: column (in sqlStatement: statement, in integer: column, attr duration) const func float: column (in sqlStatement: statement, in integer: column, attr float) const func integer: column (in sqlStatement: statement, in integer: column, attr integer) const func string: column (in sqlStatement: statement, in integer: column, attr string) const func time: column (in sqlStatement: statement, in integer: column, attr time)Getting a column fails with a RANGE_ERROR, if no record has been fetched from the result set. Column numbers start with 1. To get column number four from the current result record (row) as integer do:
column(statement, 4, integer);
The column() functions check the given position (column) and raise the exception RANGE_ERROR, if no corresponding column exists in the result record. This happens if column <= 0 is TRUE or if column is greater than the number of columns (which can be obtained with columnCount()). Database columns can be NULL. This can be checked with the following function:
const func boolean: isNull (in sqlStatement: statement, in integer: column)The function isNull() returns TRUE, if the specified column is NULL. Otherwise isNull() returns FALSE. The column() functions return a default value, if a column is NULL. The following default values are used:
Type Default value bigInteger 0_ bigRational 0_/1_ boolean FALSE bstring bstring("") duration duration.value float 0.0 integer 0 string "" time time.value 14. GRAPHIC LIBRARY
Seed7 provides a portable graphics library. Below is the graphic "hello world" program:
$ include "seed7_05.s7i"; include "dialog.s7i"; const proc: main is func begin messageWindow("hello world"); end func;This program displays a popup window with the message "hello world". In the popup window there is an OK button, which ends the program. A program that creates an empty window and a message popup is:
$ include "seed7_05.s7i"; include "dialog.s7i"; const proc: main is func begin screen(640, 480); messageWindow("hello world"); end func;The function screen(640, 480) opens window with a width of 640 and a height of 480. The window is assigned to the variable curr_win, which is used as default window by drawing functions.
Displaying an empty window without message box is done with:
$ include "seed7_05.s7i"; include "draw.s7i"; include "keybd.s7i"; const proc: main is func begin screen(640, 480); ignore(getc(GRAPH_KEYBOARD)); end func;This program waits until a key is pressed. The key is read from GRAPH_KEYBOARD Without reading from GRAPH_KEYBOARD the program would terminate immediately. Regarding the keyboard:
- In graphic programs the keyboard is connected to GRAPH_KEYBOARD.
- In console programs the keyboard is connected to CONSOLE_KEYBOARD.
For that reason a graphic program should do the following assignment:
KEYBOARD := GRAPH_KEYBOARD;Afterwards it should just use the variable KEYBOARD.
The program below clears the window with a color computed from the keys pressed:
$ include "seed7_05.s7i"; include "draw.s7i"; include "keybd.s7i"; const proc: main is func local var char: command is ' '; begin screen(640, 480); KEYBOARD := GRAPH_KEYBOARD; repeat command := getc(KEYBOARD); clear(color(1009 * ord(command) mod 65536, 4999 * ord(command) mod 65536, 9973 * ord(command) mod 65536)); until command = KEY_ESC; end func;The function color creates a color from red, green and blue lights in the additive color model. The red, green and blue lights are specified by integer values in the range 0 .. 65535.
Below is a "hello world" program that uses a Seed7 font:
$ include "seed7_05.s7i"; include "draw.s7i"; include "keybd.s7i"; include "text.s7i"; include "stdfont24.s7i"; const proc: main is func local var text: textWindow is text.value; begin screen(203, 45); textWindow := openPixmapFontFile(curr_win); setFont(textWindow, stdFont24); writeln(textWindow, " hello world"); ignore(getc(GRAPH_KEYBOARD)); end func;The function screen opens a window with a width of 203 pixels and a height of 45 pixels. The window is stored in the global variable curr_win. The function openPixmapFontFile opens a pixmapFontFile for curr_win. Everything written to textWindow is displayed in the current window. The function setFont defines which font should be used. The font stdfont24.s7i is a bitmapFont with a cap-height of 24 pixels. The function writeln displays hello world to the current window with the specified font.
Seed7 fonts are not as perfect as professional fonts. They have the following properties:
- They are open source.
- They are implemented in Seed7.
- No external library is needed.
- Seed7 programs can use them always.
- There are bitmap and vector fonts.
15. PRIMITIVE ACTIONS
Not all functions can be described by calling other functions of the same language. For this reason and for performance reasons several functions are defined using a mechanism called action. For example: It is easy to define the while-statement by using recursion. But this would hurt performance and it would also use a huge amount of memory for the runtime stack. In practice an implementation of the while-statement can use a conditional jump instead of a subroutine call. Since Seed7 has no goto statement, this is not an option. Instead the primitive action PRC_WHILE can be used. The while-statement is defined in the basic Seed7 library "seed7_05.s7i" with:
const proc: while (in func boolean param) do (in proc param) end while is action "PRC_WHILE";This declaration shows the types and the position of the parameters of a while-statement. Such an action declaration contains enough information to use the defined construct. The semantic of all primitive actions is hard coded in the interpreter and in the compiler. The parameters of the hard coded actions and the corresponding definitions in Seed7 must match. If you are interested in the Seed7 definitions of primitive actions just look into the file "seed7_05.s7i".
Currently there are several hundred primitive actions predefined in the interpreter. They all have names in upper case characters which have the form:
TYPE_ACTIONWhich means that for example all integer actions start with INT_ and all assignment actions end with _CPY . The following list shows actions which are used with more than one type:
_ABS Absolute value _ADD Addition _CAT Concatenation _CMP Compare _CPY Copy (Assignment) _CREATE Initialize (Construct) _DESTR Destroy (Destruct) _DECR Decrement _DIV Division _EQ Equal _GE Greater equal _GETC Get one character from a file _GETS Get string with maximum length from a file _GT Greater than _HASHCODE Compute a hashCode _HEAD Head of string, array or ref_list _ICONV Conversion of integer to another type _IDX Index (Element) of string, array or ref_list _INCR Increment _IPOW Power with integer exponent _LE Less equal _LNG Length _LOG2 Base 2 logarithm _LOWER Convert to lower case _LSHIFT Shift left _LT Less than _MDIV Modulo division (Integer division truncated towards negative infinity) _MOD Modulo (Reminder of _MDIV integer division) _MULT Multiply _NE Not equal _NEGATE Change sign _ODD Odd number _ORD Ordinal number _PARSE Conversion of string to another type _PLUS Positive sign (noop) _POW Power _PRED Predecessor _RAND Random value _RANGE Range of string, array or ref_list _REM Remainder (Reminder of _DIV integer division) _RSHIFT Arithmetic shift right _SBTR Subtract _SCAN Convert from string to another type _SEEK Set actual file position of a file _SQRT Square root _STR Convert to string _SUCC Successor _TAIL Tail of string, array or ref_list _TELL Return the actual file position _UPPER Convert to upper case _VALUE Dereference a reference _WRITE Write string to file Primitive actions are defined for many types. The functions which implement the primitive actions are grouped together in *lib.c files. The following list contains the action prefix, the file containing the functions and a description:
ACT_ actlib.c ACTION operations ARR_ arrlib.c array operations BIG_ biglib.c bigInteger operations BIN_ binlib.c bin32 and bin64 operations BLN_ blnlib.c boolean operations BST_ bstlib.c Operations for byte strings CHR_ chrlib.c char operations CMD_ cmdlib.c Various directory, file and other commands CON_ conlib.c console_file operations DCL_ dcllib.c Declaration operations DRW_ drwlib.c Drawing operations ENU_ enulib.c Enumeration operations FIL_ fillib.c clib_file operations FLT_ fltlib.c float operations HSH_ hshlib.c hash operations INT_ intlib.c integer operations ITF_ itflib.c Operations for interface types KBD_ kbdlib.c Keyboard operations LST_ lstlib.c List operations PCS_ pcslib.c process operations POL_ pollib.c pollData operations PRC_ prclib.c proc operations and statements PRG_ prglib.c Program operations REF_ reflib.c reference operations RFL_ rfllib.c ref_list operations SCT_ sctlib.c struct operations SET_ setlib.c set operations SOC_ soclib.c PRIMITIVE_SOCKET operations SQL_ sqllib.c database operations STR_ strlib.c string operations TIM_ timlib.c time and duration operations TYP_ typlib.c type operations UT8_ ut8lib.c utf8File operations The C functions which implement primitive actions have lowercase names. E.g.: The action 'PRC_WHILE' is implemented with the C function 'prc_while()' in the file "prclib.c". The parameter list for all C action functions is identical. Every *lib.c file has a corresponding *lib.h file which contains the prototypes for the action functions.
In a Seed7 program the operator + is used to add two integer values. The primitive action, which describes the addition of two integers, is 'INT_ADD'. The connection between + and 'INT_ADD' is done in the library "integer.s7i" with the definition:
const func integer: (in integer: summand1) + (in integer: summand2) is action "INT_ADD";To execute an action a corresponding C function must be present in the s7 interpreter. The function for the action 'INT_ADD' is int_add(). The function int_add() is defined in the file "intlib.c" with:
objectType int_add (listType arguments) { /* int_add */ isit_int(arg_1(arguments)); isit_int(arg_3(arguments)); return bld_int_temp( take_int(arg_1(arguments)) + take_int(arg_3(arguments))); } /* int_add */The function int_add() adds the first and the third argument (the second argument contains the + symbol. The file "objutl.h" contains several macros and functions which help to handle the arguments (parameter list) of a C primitive action function.
- The macros arg_1, arg_2, arg_3, etc. can be used to get an individual argument (E.g.: arg_3(arguments) ).
- The macros isit_int, isit_stri, isit_file, etc. can be used to check for the correct category of an argument (E.g.: isit_int(arg_1(arguments)) ).
- The macros take_char, take_float, take_bigint, etc. can be used to get the corresponding value of an argument (E.g.: take_int(arg_1(arguments)) ).
- The functions bld_int_temp, bld_array_temp, bld_win_temp, etc. can be used to create the (objectType) result of a primitive action (E.g.: return bld_int_temp(0); ).
The file "intlib.h" contains the prototype for the int_add() function:
objectType int_add (listType arguments);Additionally every primitive action is registered in the file "primitive.c". The line which incorporates 'INT_ADD' is:
{ "INT_ADD", int_add, },
The entries of the primitive action in the file "primitive.c" are sorted alphabetically. With this definitions the s7 interpreter understands a primitive action.
To allow a primitive function in a compiled Seed7 program the Seed7 compiler (s7c) needs to know the action also. The compiler function which creates code for the 'INT_ADD' action is:
const proc: process (INT_ADD, in reference: function, in ref_list: params, inout expr_type: c_expr) is func begin c_expr.expr &:= "("; process_expr(params[1], c_expr); c_expr.expr &:= ") + ("; process_expr(params[3], c_expr); c_expr.expr &:= ")"; end func;This function is defined in "seed7/lib/comp/int_act.s7i" and called from the function process_action with:
elsif action_name = "INT_ADD" then process(INT_ADD, function, params, c_expr);Some primitive actions are more complicated and inline code would not be the best solution for it. In this case an additional helper function is used. The action 'INT_LOG2' is such an action. The definition of the function int_log2() in the file "intlib.c" is:
objectType int_log2 (listType arguments) { /* int_log2 */ isit_int(arg_1(arguments)); return bld_int_temp( intLog2(take_int(arg_1(arguments)))); } /* int_log2 */The main work for the primitive action 'INT_LOG2' is done in the helper function intLog2(). The helper function intLog2() can be found in the file "int_rtl.c":
/** * Compute the truncated base 2 logarithm of an integer number. * @return the truncated base 2 logarithm. * @exception NUMERIC_ERROR The number is negative. */ intType intLog2 (intType number) { int result; /* intLog2 */ if (unlikely(number < 0)) { raise_error(NUMERIC_ERROR); result = 0; } else { result = uintMostSignificantBit((uintType) number); } /* if */ return result; } /* intLog2 */The file "int_rtl.h" contains a prototype definition for the intLog2() helper function:
intType intLog2 (intType number);The helper functions are also used in the code generated by the Seed7 compiler:
const proc: process (INT_LOG2, in reference: function, in ref_list: params, inout expr_type: c_expr) is func begin c_expr.expr &:= "intLog2("; process_expr(params[1], c_expr); c_expr.expr &:= ")"; end func;The compiler writes a prototype of intLog2() in the function write_prototypes:
declareExtern("intType intLog2 (intType);");
All the *lib.c files containing primitive actions and various other files with their functions are grouped together in the "s7_comp.a" library (Licensed under GPL). Furthermore the C primitive action functions (E.g.: int_parse) of the *lib.c files may use corresponding functions (E.g.: intParse) which can be found in *_rtl.c files (E.g.: "int_rtl.c"). The *_rtl.c files are grouped together in the "seed7_05.a" library (Licensed under LGPL). When a Seed7 program is compiled with the Seed7 compiler (s7c) inline code is generated for many primitive actions. To implement the remaining primitive actions the functions of the "seed7_05.a" library are used.
14.1 Actions for the type ACTION
Action name actlib.c function act_comp.c function ACT_ILLEGAL act_illegal ACT_CPY act_cpy = ACT_CREATE act_create ACT_EQ act_eq == ACT_GEN act_gen ACT_ICONV1 act_iconv1 actIConv ACT_ICONV3 act_iconv3 actIConv ACT_NE act_ne != ACT_ORD act_ord actOrd ACT_STR act_str actStr ACT_VALUE act_value actValue 14.2 Actions for array types
Action name arrlib.c function arr_rtl.c function ARR_APPEND arr_append arrAppend ARR_ARRLIT arr_arrlit arrArrlit ARR_ARRLIT2 arr_arrlit2 arrArrlit2 ARR_BASELIT arr_baselit arrBaselit ARR_BASELIT2 arr_baselit2 arrBaselit2 ARR_CAT arr_cat arrCat ARR_CONV arr_conv (noop) ARR_CPY arr_cpy cpy_ ... ARR_CREATE arr_create create_ ... ARR_DESTR arr_destr destr_ ... ARR_EMPTY arr_empty ARR_EXTEND arr_extend arrExtend ARR_GEN arr_gen arrGen ARR_HEAD arr_head arrHead ARR_IDX arr_idx a->arr[b-a->min_position] ARR_INSERT arr_insert arrInsert ARR_INSERT_ARRAY arr_insert_array arrInsertArray ARR_LNG arr_lng a->max_position-a->min_position + 1 ARR_MAXIDX arr_maxidx a->max_position ARR_MINIDX arr_minidx a->min_position ARR_PUSH arr_push arrPush ARR_RANGE arr_range arrRange ARR_REMOVE arr_remove arrRemove ARR_REMOVE_ARRAY arr_remove_array arrRemoveArray ARR_SORT arr_sort arrSort ARR_SORT_REVERSE arr_sort_reverse arrSortReverse ARR_SUBARR arr_subarr arrSubarr, arrSubarrTemp ARR_TAIL arr_tail arrTail ARR_TIMES arr_times times_ ... 14.3 Actions for the type bigInteger
Action name biglib.c function big_rtl.c function BIG_ABS big_abs bigAbs BIG_ADD big_add bigAdd, bigAddTemp BIG_ADD_ASSIGN big_add_assign bigAddAssign, bigAddAssignSignedDigit BIG_BIT_LENGTH big_bit_length bigBitLength BIG_CMP big_cmp bigCmp BIG_CONV big_conv (noop) BIG_CPY big_cpy bigCpy BIG_CREATE big_create bigCreate BIG_DECR big_decr bigDecr BIG_DESTR big_destr bigDestr BIG_DIV big_div bigDiv BIG_DIV_REM big_div_rem bigDivRem BIG_EQ big_eq bigEq BIG_FROM_BSTRI_BE big_from_bstri_be bigFromBStriBe BIG_FROM_BSTRI_LE big_from_bstri_le bigFromBStriLe BIG_GCD big_gcd bigGcd BIG_GE big_ge bigCmp >= 0 BIG_GT big_gt bigCmp > 0 BIG_HASHCODE big_hashcode bigHashCode BIG_ICONV1 big_iconv1 bigIConv BIG_ICONV3 big_iconv3 bigIConv BIG_INCR big_incr bigIncr BIG_IPOW big_ipow bigIPow BIG_LE big_le bigCmp <= 0 BIG_LOG10 big_log10 bigLog10 BIG_LOG2 big_log2 bigLog2 BIG_LOWEST_SET_BIT big_lowest_set_bit bigLowestSetBit BIG_LSHIFT big_lshift bigLShift BIG_LSHIFT_ASSIGN big_lshift_assign bigLShiftAssign BIG_LT big_lt bigCmp < 0 BIG_MDIV big_mdiv bigMDiv BIG_MOD big_mod bigMod BIG_MULT big_mult bigMult BIG_MULT_ASSIGN big_mult_assign bigMultAssign BIG_NE big_ne bigNe BIG_NEGATE big_negate bigNegate BIG_ODD big_odd bigOdd BIG_ORD big_ord bigOrd BIG_PARSE1 big_parse1 bigParse BIG_PARSE_BASED big_parse_based bigParseBased BIG_PLUS big_plus (noop) BIG_PRED big_pred bigPred BIG_RADIX big_RADIX bigRadix BIG_RAND big_rand bigRand BIG_REM big_rem bigRem BIG_RSHIFT big_rshift bigRShift BIG_RSHIFT_ASSIGN big_rshift_assign bigRShiftAssign BIG_SBTR big_sbtr bigSbtr, bigSbtrTemp BIG_SBTR_ASSIGN big_sbtr_assign bigSbtrAssign, bigAddAssignSignedDigit BIG_STR big_str bigStr BIG_SUCC big_succ bigSucc BIG_TO_BSTRI_BE big_to_bstri_be bigToBStriBe BIG_TO_BSTRI_LE big_to_bstri_le bigToBStriLe BIG_VALUE big_value bigValue BIG_radix big_radix bigRadix 14.4 Actions for the types bin32 and bin64
Action name blnlib.c function bln_rtl.c function BIN_AND bin_and & BIN_AND_ASSIGN bin_and_assign &= BIN_BIG bin_big bigFromUInt64 BIN_BINARY bin_binary bigToUInt64 BIN_CARD bin_card uintCard BIN_CMP bin_cmp uintCmp BIN_GET_BINARY_FROM_SET bin_get_binary_from_set setToUInt BIN_LSHIFT bin_lshift (intType)((uintType)(a<<b)) BIN_LSHIFT_ASSIGN bin_lshift_assign a=(intType)((uintType)(a<<b)) BIN_N_BYTES_BE bin_n_bytes_be uintNBytesBe BIN_N_BYTES_LE bin_n_bytes_le uintNBytesLe BIN_OR bin_or | BIN_OR_ASSIGN bin_or_assign |= BIN_RADIX bin_RADIX uintRadix BIN_RSHIFT bin_rshift (intType)((uintType)(a>>b)) BIN_RSHIFT_ASSIGN bin_rshift_assign a=(intType)((uintType)(a>>b)) BIN_STR bin_str uintStr BIN_XOR bin_xor ^ BIN_XOR_ASSIGN bin_xor_assign ^= BIN_radix bin_radix uintRadix 14.5 Actions for the type boolean
Action name blnlib.c function bln_rtl.c function BLN_AND bln_and && BLN_CPY bln_cpy blnCpy BLN_CREATE bln_create blnCreate BLN_EQ bln_eq == BLN_GE bln_ge >= BLN_GT bln_gt > BLN_ICONV1 bln_iconv1 & 1 BLN_ICONV3 bln_iconv3 & 1 BLN_LE bln_le <= BLN_LT bln_lt < BLN_NE bln_ne != BLN_NOT bln_not ! BLN_OR bln_or || BLN_ORD bln_ord (intType) BLN_PRED bln_pred -1 BLN_SUCC bln_succ +1 BLN_TERNARY bln_ternary ((cond)?(thenExpr):(elseExpr)) BLN_VALUE bln_value blnValue 14.6 Actions for byte strings
Action name bstlib.c function bst_rtl.c function BST_APPEND bst_append bstAppend BST_CAT bst_cat bstCat BST_CMP bst_cmp bstCmp BST_CPY bst_cpy bstCpy BST_CREATE bst_create bstCreate BST_DESTR bst_destr bstDestr BST_EMPTY bst_empty BST_EQ bst_eq a->size==b->size && memcmp(a,b,a->size*sizeof(unsigned char))==0 BST_HASHCODE bst_hashcode bstHashCode BST_IDX bst_idx a->mem[b-1] BST_LNG bst_lng a->size BST_NE bst_ne a->size!=b->size || memcmp(a,b,a->size*sizeof(unsigned char))!=0 BST_PARSE1 bst_parse1 bstParse BST_STR bst_str bstStr BST_VALUE bst_value bstValue 14.7 Actions for the type char
Action name chrlib.c function chr_rtl.c function CHR_CLIT chr_clit chrCLit CHR_CMP chr_cmp chrCmp CHR_CPY chr_cpy chrCpy CHR_CREATE chr_create chrCreate CHR_DECR chr_decr -- CHR_EQ chr_eq == CHR_GE chr_ge >= CHR_GT chr_gt > CHR_HASHCODE chr_hashcode (intType)((scharType)a) CHR_ICONV1 chr_iconv1 (charType) CHR_ICONV3 chr_iconv3 (charType) CHR_INCR chr_incr ++ CHR_IS_LETTER chr_is_letter chrIsLetter CHR_LE chr_le <= CHR_LOW chr_low chrLow CHR_LT chr_lt < CHR_NE chr_ne != CHR_ORD chr_ord (intType) CHR_PRED chr_pred -1 CHR_STR chr_str chrStr CHR_SUCC chr_succ +1 CHR_UP chr_up chrUp CHR_VALUE chr_value chrValue CHR_WIDTH chr_width chrWidth 14.8 Actions for various directory, file and other commands
Action name cmdlib.c function cmd_rtl.c function CMD_BIG_FILESIZE cmd_big_filesize cmdBigFileSize CMD_CHDIR cmd_chdir cmdChdir CMD_CLONE_FILE cmd_clone_file cmdCloneFile CMD_CONFIG_VALUE cmd_config_value cmdConfigValue CMD_COPY_FILE cmd_copy_file cmdCopyFile CMD_ENVIRONMENT cmd_environment cmdEnvironment CMD_FILESIZE cmd_filesize cmdFileSize CMD_FILETYPE cmd_filetype cmdFileType CMD_FILETYPE_SL cmd_filetype_sl cmdFileTypeSL CMD_FINAL_PATH cmd_final_path cmdFinalPath CMD_GETCWD cmd_getcwd cmdGetcwd CMD_GETENV cmd_getenv cmdGetenv CMD_GET_ATIME cmd_get_atime cmdGetATime CMD_GET_ATIME_OF_SYMLINK cmd_get_atime_of_symlink cmdGetATimeOfSymlink CMD_GET_CTIME cmd_get_ctime cmdGetCTime CMD_GET_FILE_MODE cmd_get_file_mode cmdGetFileMode CMD_GET_FILE_MODE_OF_SYMLINK cmd_get_file_mode_of_symlink cmdGetFileModeOfSymlink CMD_GET_GROUP cmd_get_group cmdGetGroup CMD_GET_GROUP_OF_SYMLINK cmd_get_group_of_symlink cmdGetGroupOfSymlink CMD_GET_MTIME cmd_get_mtime cmdGetMTime CMD_GET_MTIME_OF_SYMLINK cmd_get_mtime_of_symlink cmdGetMTimeOfSymlink CMD_GET_OWNER cmd_get_owner cmdGetOwner CMD_GET_OWNER_OF_SYMLINK cmd_get_owner_of_symlink cmdGetOwnerOfSymlink CMD_GET_SEARCH_PATH cmd_get_search_path cmdGetSearchPath CMD_HOME_DIR cmd_home_dir cmdHomeDir CMD_MAKE_DIR cmd_make_dir cmdMakeDir CMD_MAKE_LINK cmd_make_link cmdMakeLink CMD_MOVE cmd_move cmdMove CMD_READ_DIR cmd_read_dir cmdReadDir CMD_READ_LINK cmd_read_link cmdReadLink CMD_READ_LINK_ABSOLUTE cmd_read_link_absolute cmdReadLinkAbsolute CMD_REMOVE_FILE cmd_remove_file cmdRemoveFile CMD_REMOVE_TREE cmd_remove_tree cmdRemoveTree CMD_SETENV cmd_setenv cmdSetenv CMD_SET_ATIME cmd_set_atime cmdSetATime CMD_SET_FILEMODE cmd_set_filemode cmdSetFileMode CMD_SET_GROUP cmd_set_group cmdSetGroup CMD_SET_GROUP_OF_SYMLINK cmd_set_group_of_symlink cmdSetGroupOfSymlink CMD_SET_MTIME cmd_set_mtime cmdSetMTime CMD_SET_MTIME_OF_SYMLINK cmd_set_mtime_of_symlink cmdSetMTimeOfSymlink CMD_SET_OWNER cmd_set_owner cmdSetOwner CMD_SET_OWNER_OF_SYMLINK cmd_set_owner_of_symlink cmdSetOwnerOfSymlink CMD_SET_SEARCH_PATH cmd_set_search_path cmdSetSearchPath CMD_SHELL cmd_shell cmdShell CMD_SHELL_ESCAPE cmd_shell_escape cmdShellEscape CMD_TO_OS_PATH cmd_to_os_path cmdToOsPath CMD_UNSETENV cmd_unsetenv cmdUnsetenv 14.9 Actions for text (console) screen output
Action name scrlib.c function con_inf.c/con_rtl.c/con_win.c function CON_CLEAR con_clear conClear CON_COLUMN con_column conColumn CON_CURSOR con_cursor conCursor CON_FLUSH con_flush conFlush CON_HEIGHT con_height conHeight CON_H_SCL con_h_scl conHScroll CON_LINE con_line conLine CON_OPEN con_open conOpen CON_SETPOS con_setpos conSetpos CON_V_SCL con_v_scl conVScroll CON_WIDTH con_width conWidth CON_WRITE con_write conWrite 14.10 Actions for declarations
Action name dcllib.c function DCL_ATTR dcl_attr DCL_CONST dcl_const DCL_ELEMENTS dcl_elements DCL_FWD dcl_fwd DCL_FWDVAR dcl_fwdvar DCL_GETFUNC dcl_getfunc DCL_GETOBJ dcl_getobj DCL_GLOBAL dcl_global DCL_IN1 dcl_in1 DCL_IN1VAR dcl_in1var DCL_IN2 dcl_in2 DCL_IN2VAR dcl_in2var DCL_INOUT1 dcl_inout1 DCL_INOUT2 dcl_inout2 DCL_PARAM_ATTR dcl_param_attr DCL_REF1 dcl_ref1 DCL_REF2 dcl_ref2 DCL_SYMB dcl_symb DCL_SYNTAX dcl_syntax DCL_VAL1 dcl_val1 DCL_VAL2 dcl_val2 DCL_VAR dcl_var 14.11 Actions to do graphic output
Action name drwlib.c function drw_rtl.c/drw_x11.c/drw_win.c function DRW_ARC drw_arc drwArc DRW_ARC2 drw_arc2 drwArc2 DRW_BACKGROUND drw_background drwBackground DRW_BORDER drw_border drwBorder DRW_CAPTURE drw_capture drwCapture DRW_CIRCLE drw_circle drwCircle DRW_CLEAR drw_clear drwClear DRW_CMP drw_cmp uintCmpGeneric((genericType)(a)) DRW_COLOR drw_color drwColor DRW_CONV_POINT_LIST drw_conv_point_list drwConvPointList DRW_COPYAREA drw_copyarea drwCopyArea DRW_CPY drw_cpy drwCpy DRW_CREATE drw_create drwCreate DRW_DESTR drw_destr drwDestr DRW_EMPTY drw_empty DRW_EQ drw_eq == DRW_FARCCHORD drw_farcchord drwFArcChord DRW_FARCPIESLICE drw_farcpieslice drwFArcPieSlice DRW_FCIRCLE drw_fcircle drwFCircle DRW_FELLIPSE drw_fellipse drwFEllipse DRW_FLUSH drw_flush drwFlush DRW_FPOLY_LINE drw_fpoly_line drwFPolyLine DRW_GEN_POINT_LIST drw_gen_point_list drwGenPointList DRW_GET_IMAGE_PIXEL drw_get_image_pixel drwGetImagePixel DRW_GET_PIXEL drw_get_pixel drwGetPixel DRW_GET_PIXEL_ARRAY drw_get_pixel_array drwGetPixelArray DRW_GET_PIXEL_DATA drw_get_pixel_data drwGetPixelData DRW_GET_PIXMAP drw_get_pixmap drwGetPixmap DRW_GET_PIXMAP_FROM_PIXELS drw_get_pixmap_from_pixels drwGetPixmapFromPixels DRW_HASHCODE drw_hashcode (intType)(((memSizeType)a)>>6) DRW_HEIGHT drw_height drwHeight DRW_LINE drw_line drwLine DRW_NE drw_ne != DRW_NEW_PIXMAP drw_new_pixmap drwNewPixmap DRW_OPEN drw_open drwOpen DRW_OPEN_SUB_WINDOW drw_open_sub_window drwOpenSubWindow DRW_PARC drw_parc drwPArc DRW_PCIRCLE drw_pcircle drwPCircle DRW_PFARC drw_pfarc drwPFArc DRW_PFARCCHORD drw_pfarcchord drwPFArcChord DRW_PFARCPIESLICE drw_pfarcpieslice drwFArcPieSlice DRW_PFCIRCLE drw_pfcircle drwPFCircle DRW_PFELLIPSE drw_pfellipse drwPFEllipse DRW_PIXEL_TO_RGB drw_pixel_to_rgb drwPixelToRgb DRW_PLINE drw_pline drwPLine DRW_POINT drw_point drwPoint DRW_POINTER_XPOS drw_pointer_xpos drwPointerXpos DRW_POINTER_YPOS drw_pointer_ypos drwPointerYpos DRW_POLY_LINE drw_poly_line drwPolyLine DRW_PPOINT drw_ppoint drwPPoint DRW_PRECT drw_prect drwPRect DRW_PUT drw_put drwPut DRW_PUT_SCALED drw_put_scaled drwPutScaled DRW_RECT drw_rect drwRect DRW_RGBCOL drw_rgbcol drwRgbColor DRW_SCREEN_HEIGHT drw_screen_height drwScreenHeight DRW_SCREEN_WIDTH drw_screen_width drwScreenWidth DRW_SET_CLOSE_ACTION drw_set_close_action drwSetCloseAction DRW_SET_CONTENT drw_set_content drwSetContent DRW_SET_CURSOR_VISIBLE drw_set_cursor_visible drwSetCursorVisible DRW_SET_POINTER_POS drw_set_pointer_pos drwSetPointerPos DRW_SET_POS drw_set_pos drwSetPos DRW_SET_TRANSPARENT_COLOR drw_set_transparent_color drwSetTransparentColor DRW_SET_WINDOW_NAME drw_set_window_name drwSetWindowName DRW_TEXT drw_text drwText DRW_TO_BOTTOM drw_to_bottom drwToBottom DRW_TO_TOP drw_to_top drwToTop DRW_VALUE drw_value drwValue DRW_WIDTH drw_width drwWidth DRW_XPOS drw_xpos drwXPos DRW_YPOS drw_ypos drwYPos 14.12 Actions for enumeration types
Action name enulib.c function ENU_CONV enu_conv (noop) ENU_CPY enu_cpy = ENU_CREATE enu_create ENU_EQ enu_eq == ENU_GENLIT enu_genlit ENU_ICONV2 enu_iconv2 (noop) ENU_NE enu_ne != ENU_ORD2 enu_ord2 (noop) ENU_VALUE enu_value enuValue 14.13 Actions for the type clib_file
Action name fillib.c function fil_rtl.c function FIL_BIG_LNG fil_big_lng filBigLng FIL_BIG_SEEK fil_big_seek filBigSeek FIL_BIG_TELL fil_big_tell filBigTell FIL_CLOSE fil_close fclose FIL_CPY fil_cpy fltCpy FIL_CREATE fil_create fltCreate FIL_DESTR fil_destr filDestr FIL_EMPTY fil_empty FIL_EOF fil_eof feof FIL_EQ fil_eq == FIL_ERR fil_err stderr FIL_FLUSH fil_flush fflush FIL_GETC fil_getc fgetc FIL_GETS fil_gets filGets FIL_HAS_NEXT fil_has_next filHasNext FIL_IN fil_in stdin FIL_INPUT_READY fil_input_ready filInputReady FIL_LINE_READ fil_line_read filLineRead FIL_LIT fil_lit filLit FIL_LNG fil_lng filLng FIL_NE fil_ne != FIL_OPEN fil_open filOpen FIL_OPEN_NULL_DEVICE fil_open_null_device filOpenNullDevice FIL_OUT fil_out stdout FIL_PCLOSE fil_pclose filPclose FIL_POPEN fil_popen filPopen FIL_PRINT fil_print filPrint FIL_SEEK fil_seek filSeek FIL_SETBUF fil_setbuf filSetbuf FIL_TELL fil_tell filTell FIL_TRUNCATE fil_truncate filTruncate FIL_VALUE fil_value filValue FIL_WORD_READ fil_word_read filWordRead FIL_WRITE fil_write filWrite 14.14 Actions for the type float
Action name fltlib.c function flt_rtl.c function FLT_ABS flt_abs fabs FLT_ACOS flt_acos acos FLT_ADD flt_add + FLT_ADD_ASSIGN flt_add_assign += FLT_ASIN flt_asin asin FLT_ATAN flt_atan atan FLT_ATAN2 flt_atan2 atan2 FLT_BITS2DOUBLE flt_bits2double (x.bits=a, x.aDouble) FLT_BITS2SINGLE flt_bits2single (x.bits=a, x.aSingle) FLT_CEIL flt_ceil ceil FLT_CMP flt_cmp fltCmp FLT_COS flt_cos cos FLT_COSH flt_cosh cosh FLT_CPY flt_cpy fltCpy FLT_CREATE flt_create fltCreate FLT_DECOMPOSE flt_decompose frexp FLT_DGTS flt_dgts fltDgts FLT_DIV flt_div / FLT_DIV_ASSIGN flt_div_assign /= FLT_DOUBLE2BITS flt_double2bits (x.aDouble=a, x.bits) FLT_EQ flt_eq == FLT_EXP flt_exp exp FLT_EXPM1 flt_expm1 expm1 FLT_FLOOR flt_floor floor FLT_GE flt_ge >= FLT_GT flt_gt > FLT_HASHCODE flt_hashcode (x.floatValue=a, x.intValue) FLT_ICONV1 flt_iconv1 (float) FLT_ICONV3 flt_iconv3 (float) FLT_IPOW flt_ipow fltIPow FLT_ISNAN flt_isnan isnan FLT_ISNEGATIVEZERO flt_isnegativezero fltIsNegativeZero FLT_LE flt_le <= FLT_LOG flt_log log FLT_LOG10 flt_log10 log10 FLT_LOG1P flt_log1p log1p FLT_LOG2 flt_log2 log2 FLT_LSHIFT flt_lshift ldexp FLT_LT flt_lt < FLT_MOD flt_mod fltMod FLT_MULT flt_mult * FLT_MULT_ASSIGN flt_mult_assign *= FLT_NE flt_ne != FLT_NEGATE flt_negate - FLT_PARSE1 flt_parse1 fltParse FLT_PLUS flt_plus (noop) FLT_POW flt_pow pow FLT_RAND flt_rand fltRand FLT_REM flt_rem fmod FLT_ROUND flt_round a<0.0?-((intType)(0.5-a)):(intType)(0.5+a) FLT_RSHIFT flt_rshift ldexp FLT_SBTR flt_sbtr - FLT_SBTR_ASSIGN flt_sbtr_assign -= FLT_SCI flt_sci fltSci FLT_SIN flt_sin sin FLT_SINGLE2BITS flt_single2bits (x.aSingle=a, x.bits) FLT_SINH flt_sinh sinh FLT_SQRT flt_sqrt sqrt FLT_STR flt_str fltStr FLT_TAN flt_tan tan FLT_TANH flt_tanh tanh FLT_TRUNC flt_trunc (intType) FLT_VALUE flt_value fltValue 14.15 Actions to support the graphic keyboard
Action name drwlib.c function kbd_rtl.c/drw_x11.c/drw_win.c function GKB_BUTTON_PRESSED gkb_button_pressed gkbButtonPressed GKB_CLICKED_XPOS gkb_clicked_xpos gkbClickedXpos GKB_CLICKED_YPOS gkb_clicked_ypos gkbClickedYpos GKB_GETC gkb_getc gkbGetc GKB_GETS gkb_gets gkbGets GKB_INPUT_READY gkb_input_ready gkbInputReady GKB_LINE_READ gkb_line_read gkbLineRead GKB_RAW_GETC gkb_raw_getc gkbRawGetc GKB_SELECT_INPUT gkb_select_input gkbSelectInput GKB_WINDOW gkb_window gkbWindow GKB_WORD_READ gkb_word_read gkbWordRead 14.16 Actions for hash types
Action name hshlib.c function hsh_rtl.c function HSH_CONTAINS hsh_contains hshContains HSH_CPY hsh_cpy hshCpy HSH_CREATE hsh_create hshCreate HSH_DESTR hsh_destr hshDestr HSH_EMPTY hsh_empty hshEmpty HSH_EXCL hsh_excl hshExcl HSH_FOR hsh_for for HSH_FOR_DATA_KEY hsh_for_data_key for HSH_FOR_KEY hsh_for_key for HSH_IDX hsh_idx hshIdx, hshIdxAddr HSH_IDX2 hsh_idx2 HSH_INCL hsh_incl hshIncl HSH_KEYS hsh_keys hshKeys HSH_LNG hsh_lng a->size HSH_RAND_KEY hsh_rand_key hshRand HSH_REFIDX hsh_refidx HSH_UPDATE hsh_update hshUpdate HSH_VALUES hsh_values hshValues 14.17 Actions for the type integer
Action name intlib.c function int_rtl.c function INT_ABS int_abs labs INT_ADD int_add + INT_ADD_ASSIGN int_add_assign += INT_BINOM int_binom intBinom INT_BIT_LENGTH int_bit_length intBitLength INT_BYTES_BE_2_INT int_bytes_be_2_int intBytesBe2Int INT_BYTES_BE_2_UINT int_bytes_be_2_uint intBytesBe2UInt INT_BYTES_BE_SIGNED int_bytes_be_signed intBytesBe INT_BYTES_BE_UNSIGNED int_bytes_be_unsigned intBytesBe INT_BYTES_LE_2_INT int_bytes_le_2_int intBytesLe2Int INT_BYTES_LE_2_UINT int_bytes_le_2_uint intBytesLe2UInt INT_BYTES_LE_SIGNED int_bytes_le_signed intBytesLe INT_BYTES_LE_UNSIGNED int_bytes_le_unsigned intBytesLe INT_CMP int_cmp intCmp INT_CPY int_cpy intCpy INT_CREATE int_create intCreate INT_DECR int_decr -- INT_DIV int_div / INT_EQ int_eq == INT_FACT int_fact fact[a] INT_GE int_ge >= INT_GT int_gt > INT_HASHCODE int_hashcode (noop) INT_ICONV1 int_iconv1 (noop) INT_ICONV3 int_iconv3 (noop) INT_INCR int_incr ++ INT_LE int_le <= INT_LOG10 int_log10 intLog10 INT_LOG2 int_log2 intLog2 INT_LOWEST_SET_BIT int_lowest_set_bit intLowestSetBit INT_LPAD0 int_lpad0 intLpad0 INT_LSHIFT int_lshift << INT_LSHIFT_ASSIGN int_lshift_assign <<= INT_LT int_lt < INT_MDIV int_mdiv a>0&&b<0 ? (a-1)/b-1 : a<0&&b>0 ? (a+1)/b-1 : a/b INT_MOD int_mod c=a%b, ((a>0&&b<0) || (a<0&&b>0)) && c!=0 ? c+b : c INT_MULT int_mult * INT_MULT_ASSIGN int_mult_assign *= INT_NE int_ne != INT_NEGATE int_negate - INT_N_BYTES_BE_SIGNED int_n_bytes_be_signed intNBytesBeSigned INT_N_BYTES_BE_UNSIGNED int_n_bytes_be_unsigned intNBytesBeUnsigned INT_N_BYTES_LE_SIGNED int_n_bytes_le_signed intNBytesLeSigned INT_N_BYTES_LE_UNSIGNED int_n_bytes_le_unsigned intNBytesLeUnsigned INT_ODD int_odd &1 INT_PARSE1 int_parse1 intParse INT_PLUS int_plus (noop) INT_POW int_pow intPow INT_PRED int_pred -- INT_RADIX int_RADIX intRadix INT_RAND int_rand intRand INT_REM int_rem % INT_RSHIFT int_rshift a>>b /* C with arithmetic shift */
a<0?~(~a>>b):a>>b /* C with logical shift */INT_RSHIFT_ASSIGN int_rshift_assign a>>=b /* C with arithmetic shift */
if (a<0) a= ~(~a>>b); else a>>=b; /* C with logical shift */INT_SBTR int_sbtr - INT_SBTR_ASSIGN int_sbtr_assign -= INT_SQRT int_sqrt intSqrt INT_STR int_str intStr INT_SUCC int_succ +1 INT_VALUE int_value intValue INT_radix int_radix intRadix 14.18 Actions for interface types
Action name itflib.c function ITF_CMP itf_cmp uintCmpGeneric ITF_CONV2 itf_conv2 (noop) ITF_CPY itf_cpy = ITF_CPY2 itf_cpy2 = ITF_CREATE itf_create ITF_CREATE2 itf_create2 ITF_DESTR itf_destr itfDestr ITF_EQ itf_eq == ITF_HASHCODE itf_hashcode (intType)(((memSizeType)a)>>6) ITF_NE itf_ne != ITF_SELECT itf_select ITF_TO_INTERFACE itf_to_interface 14.19 Actions to support the text (console) screen keyboard
Action name kbdlib.c function kbd_rtl.c/kbd_inf.c function KBD_GETC kbd_getc kbdGetc KBD_GETS kbd_gets kbdGets KBD_INPUT_READY kbd_input_ready kbdInputReady KBD_LINE_READ kbd_line_read kbdLineRead KBD_RAW_GETC kbd_raw_getc kbdRawGetc KBD_WORD_READ kbd_word_read kbdWordRead 14.20 Actions for the list type
Action name lstlib.c function LST_CAT lst_cat LST_CPY lst_cpy LST_CREATE lst_create LST_DESTR lst_destr LST_EMPTY lst_empty LST_EXCL lst_excl LST_HEAD lst_head LST_IDX lst_idx LST_INCL lst_incl LST_LNG lst_lng LST_RANGE lst_range LST_TAIL lst_tail 14.21 Actions for the type process
Action name pcslib.c function pcs_rtl.c function PCS_CHILD_STDERR pcs_child_stderr pcsChildStdErr PCS_CHILD_STDIN pcs_child_stdin pcsChildStdIn PCS_CHILD_STDOUT pcs_child_stdout pcsChildStdOut PCS_CMP pcs_cmp pcsCmp PCS_CPY pcs_cpy pcsCpy PCS_CREATE pcs_create pcsCreate PCS_DESTR pcs_destr pcsDestr PCS_EMPTY pcs_empty PCS_EQ pcs_eq pcsEq PCS_EXIT_VALUE pcs_exit_value pcsExitValue PCS_HASHCODE pcs_hashcode pcsHashCode PCS_IS_ALIVE pcs_is_alive pcsIsAlive PCS_KILL pcs_kill pcsKill PCS_NE pcs_ne !pcsEq PCS_PIPE2 pcs_pipe2 pcsPipe2 PCS_PTY pcs_pty pcsPty PCS_START pcs_start pcsStart PCS_STR pcs_str pcsStr PCS_VALUE pcs_value pcsValue PCS_WAIT_FOR pcs_wait_for pcsWaitFor 14.22 Actions for the type pollData
Action name pollib.c function pol_unx.c/pol_sel.c function POL_ADD_CHECK pol_add_check polAddCheck POL_CLEAR pol_clear polClear POL_CPY pol_cpy polCpy POL_CREATE pol_create polCreate POL_DESTR pol_destr polDestr POL_EMPTY pol_empty polEmpty POL_GET_CHECK pol_get_check polGetCheck POL_GET_FINDING pol_get_finding polGetFinding POL_HAS_NEXT pol_has_next polHasNext POL_ITER_CHECKS pol_iter_checks polIterChecks POL_ITER_FINDINGS pol_iter_findings polIterFindings POL_NEXT_FILE pol_next_file polNextFile POL_POLL pol_poll polPoll POL_REMOVE_CHECK pol_remove_check polRemoveCheck POL_VALUE pol_value polValue 14.23 Actions for proc operations and statements
Action name prclib.c function PRC_ARGS prc_args arg_v PRC_BEGIN prc_begin PRC_BEGIN_NOOP prc_begin_noop PRC_BLOCK prc_block PRC_BLOCK_CATCH_ALL prc_block_catch_all PRC_BLOCK_OTHERWISE prc_block_otherwise PRC_CASE prc_case switch PRC_CASE_DEF prc_case_def switch PRC_CASE_HASHSET prc_case_hashset switch (hshIdxDefault0(...) PRC_CASE_HASHSET_DEF prc_case_hashset_def switch (hshIdxDefault0(...) PRC_CPY prc_cpy PRC_CREATE prc_create PRC_DECLS prc_decls PRC_DYNAMIC prc_dynamic PRC_EXIT prc_exit exit PRC_FOR_DOWNTO prc_for_downto for PRC_FOR_DOWNTO_STEP prc_for_downto_step for PRC_FOR_TO prc_for_to for PRC_FOR_TO_STEP prc_for_to_step for PRC_HEAPSTAT prc_heapstat PRC_HSIZE prc_hsize heapsize PRC_IF prc_if if PRC_IF_ELSIF prc_if_elsif if PRC_IF_NOOP prc_if_noop if PRC_INCLUDE prc_include PRC_LOCAL prc_local PRC_NOOP prc_noop prcNoop PRC_RAISE prc_raise raise_error PRC_REPEAT prc_repeat do {stmts} while (!(cond)); PRC_REPEAT_NOOP prc_repeat_noop do {} while (!(cond)); PRC_RES_BEGIN prc_res_begin PRC_RES_LOCAL prc_res_local PRC_RETURN prc_return PRC_RETURN2 prc_return2 PRC_SETTRACE prc_settrace PRC_TRACE prc_trace PRC_VARFUNC prc_varfunc PRC_VARFUNC2 prc_varfunc2 PRC_WHILE prc_while while (cond) {stmts} PRC_WHILE_NOOP prc_while_noop while (cond) {} 14.24 Actions for the type program
Action name prglib.c function prg_comp.c function PRG_CPY prg_cpy prgCpy PRG_CREATE prg_create PRG_DESTR prg_destr PRG_EMPTY prg_empty PRG_EQ prg_eq == PRG_ERROR_COUNT prg_error_count prgErrorCount PRG_EVAL prg_eval prgEval PRG_EXEC prg_exec prgExec PRG_FIL_PARSE prg_fil_parse prgFilParse PRG_GLOBAL_OBJECTS prg_global_objects prgGlobalObjects PRG_MATCH prg_match prgMatch PRG_MATCH_EXPR prg_match_expr prgMatchExpr PRG_NAME prg_name arg_0 PRG_NE prg_ne != PRG_OWN_NAME prg_own_name programName PRG_OWN_PATH prg_own_path programPath PRG_PATH prg_path programPath PRG_STR_PARSE prg_str_parse prgStrParse PRG_SYOBJECT prg_syobject prgSyobject PRG_SYSVAR prg_sysvar prgSysvar PRG_VALUE prg_value prgValue 14.25 Actions for the type reference
Action name reflib.c function ref_data.c function REF_ADDR ref_addr & REF_ALLOC ref_alloc refAlloc REF_ALLOC_INT ref_alloc_int refAllocInt REF_ALLOC_STRI ref_alloc_stri refAllocStri REF_ALLOC_VAR ref_alloc_var refAllocVar REF_ARRMAXIDX ref_arrmaxidx refArrmaxidx REF_ARRMINIDX ref_arrminidx refArrminidx REF_ARRTOLIST ref_arrtolist refArrtolist REF_BODY ref_body refBody REF_CAST ref_cast REF_CATEGORY ref_category refCategory REF_CAT_PARSE ref_cat_parse refCatParse REF_CAT_STR ref_cat_str refCatStr REF_CMP ref_cmp refCmp REF_CONTENT ref_content REF_CPY ref_cpy refCpy REF_CREATE ref_create refCreate REF_DEREF ref_deref REF_EQ ref_eq == REF_FILE ref_file refFile REF_GETREF ref_getref refGetRef REF_HASHCODE ref_hashcode (intType)(((memSizeType)a)>>6) REF_HSHDATATOLIST ref_hshdatatolist refHshDataToList REF_HSHKEYSTOLIST ref_hshkeystolist refHshKeysToList REF_HSHLENGTH ref_hshlength refHshLength REF_ISSYMB ref_issymb REF_ISTEMP ref_istemp refIsTemp REF_ISVAR ref_isvar refIsvar REF_ITFTOSCT ref_itftosct refItftosct REF_LINE ref_line refLine REF_LOCAL_CONSTS ref_local_consts refLocalConsts REF_LOCAL_VARS ref_local_vars refLocalVars REF_MKREF ref_mkref REF_NE ref_ne != REF_NIL ref_nil REF_NUM ref_num refNum REF_PARAMS ref_params refParams REF_PROG ref_prog REF_RESINI ref_resini refResini REF_RESULT ref_result refResult REF_SCAN ref_scan REF_SCTTOLIST ref_scttolist refScttolist REF_SELECT ref_select a->stru[b] REF_SETCATEGORY ref_setcategory refSetCategory REF_SETPARAMS ref_setparams refSetParams REF_SETTYPE ref_settype refSetType REF_SETVAR ref_setvar refSetVar REF_STR ref_str refStr REF_SYMB ref_symb REF_TRACE ref_trace printf REF_TYPE ref_type refType REF_VALUE ref_value refValue 14.26 Actions for the type ref_list
Action name rfllib.c function rfl_data.c function RFL_APPEND rfl_append rflAppend RFL_CAT rfl_cat rflCat RFL_CPY rfl_cpy rflCpy RFL_CREATE rfl_create rflCreate RFL_DESTR rfl_destr rflDestr RFL_ELEM rfl_elem rflElem RFL_ELEMCPY rfl_elemcpy rflElemcpy RFL_EMPTY rfl_empty RFL_EQ rfl_eq rflEq RFL_EXCL rfl_excl RFL_EXPR rfl_expr RFL_FOR rfl_for for RFL_FOR_UNTIL rfl_for_until for RFL_HEAD rfl_head rflHead RFL_IDX rfl_idx rflIdx RFL_INCL rfl_incl rflIncl RFL_IPOS rfl_ipos rflIpos RFL_LNG rfl_lng rflLng RFL_MKLIST rfl_mklist rflMklist RFL_NE rfl_ne rflNe RFL_NOT_ELEM rfl_not_elem !rflElem RFL_POS rfl_pos rflPos RFL_RANGE rfl_range rflRange RFL_SET_VALUE rfl_set_value rflSetValue RFL_TAIL rfl_tail rflTail RFL_TRACE rfl_trace RFL_VALUE rfl_value rflValue 14.27 Actions for struct types
Action name sctlib.c function SCT_ALLOC sct_alloc SCT_CAT sct_cat SCT_CONV sct_conv SCT_CPY sct_cpy cpy_ ... SCT_CREATE sct_create create_ ... SCT_DESTR sct_destr destr_ ... SCT_EMPTY sct_empty SCT_INCL sct_incl SCT_LNG sct_lng SCT_REFIDX sct_refidx SCT_SELECT sct_select a->stru[b] 14.28 Actions for set types
Action name setlib.c function set_rtl.c function SET_ARRLIT set_arrlit setArrlit SET_BASELIT set_baselit setBaselit SET_CARD set_card setCard SET_CMP set_cmp setCmp SET_CONV1 set_conv1 (noop) SET_CONV3 set_conv3 (noop) SET_CPY set_cpy setCpy SET_CREATE set_create setCreate SET_DESTR set_destr setDestr SET_DIFF set_diff setDiff SET_DIFF_ASSIGN set_diff_assign setDiffAssign SET_ELEM set_elem setElem SET_EMPTY set_empty SET_EQ set_eq setEq SET_EXCL set_excl setExcl SET_GE set_ge setIsSubset(b, a) SET_GT set_gt setIsProperSubset(b, a) SET_HASHCODE set_hashcode setHashCode SET_ICONV1 set_iconv1 setIConv SET_ICONV3 set_iconv3 setIConv SET_INCL set_incl setIncl SET_INTERSECT set_intersect setIntersect SET_INTERSECT_ASSIGN set_intersect_assign setIntersectAssign SET_LE set_le setIsSubset SET_LT set_lt setIsProperSubset SET_MAX set_max setMax SET_MIN set_min setMin SET_NE set_ne setNe SET_NEXT set_next setNext SET_NOT_ELEM set_not_elem !setElem SET_RAND set_rand setRand SET_RANGELIT set_rangelit setRangelit SET_SCONV1 set_sconv1 setSConv SET_SCONV3 set_sconv3 setSConv SET_SYMDIFF set_symdiff setSymdiff SET_UNION set_union setUnion SET_UNION_ASSIGN set_union_assign setUnionAssign SET_VALUE set_value setValue 14.29 Actions for the type PRIMITIVE_SOCKET
Action name strlib.c function str_rtl.c function SOC_ACCEPT soc_accept socAccept SOC_ADDR_FAMILY soc_addr_family socAddrFamily SOC_ADDR_NUMERIC soc_addr_numeric socAddrNumeric SOC_ADDR_SERVICE soc_addr_service socAddrService SOC_BIND soc_bind socBind SOC_CLOSE soc_close socClose SOC_CONNECT soc_connect socConnect SOC_CPY soc_cpy = SOC_CREATE soc_create SOC_EMPTY soc_empty SOC_EQ soc_eq == SOC_GETC soc_getc socGetc SOC_GETS soc_gets socGets SOC_GET_HOSTNAME soc_get_hostname socGetHostname SOC_GET_LOCAL_ADDR soc_get_local_addr socGetLocalAddr SOC_GET_PEER_ADDR soc_get_peer_addr socGetPeerAddr SOC_HAS_NEXT soc_has_next socHasNext SOC_INET_ADDR soc_inet_addr socInetAddr SOC_INET_LOCAL_ADDR soc_inet_local_addr socInetLocalAddr SOC_INET_SERV_ADDR soc_inet_serv_addr socInetServAddr SOC_INPUT_READY soc_input_ready socInputReady SOC_LINE_READ soc_line_read socLineRead SOC_LISTEN soc_listen socListen SOC_NE soc_ne != SOC_ORD soc_ord (intType) SOC_RECV soc_recv socRecv SOC_RECVFROM soc_recvfrom socRecvfrom SOC_SEND soc_send socSend SOC_SENDTO soc_sendto socSendto SOC_SET_OPT_BOOL soc_set_opt_bool socSetOptBool SOC_SOCKET soc_socket socSocket SOC_WORD_READ soc_word_read socWordRead SOC_WRITE soc_write socWrite 14.30 Actions for the types database and sqlStatement
Action name sqllib.c function sql_rtl.c function SQL_BIND_BIGINT sql_bind_bigint sqlBindBigInt SQL_BIND_BIGRAT sql_bind_bigrat sqlBindBigRat SQL_BIND_BOOL sql_bind_bool sqlBindBool SQL_BIND_BSTRI sql_bind_bstri sqlBindBStri SQL_BIND_DURATION sql_bind_duration sqlBindDuration SQL_BIND_FLOAT sql_bind_float sqlBindFloat SQL_BIND_INT sql_bind_int sqlBindInt SQL_BIND_NULL sql_bind_null sqlBindNull SQL_BIND_STRI sql_bind_stri sqlBindStri SQL_BIND_TIME sql_bind_time sqlBindTime SQL_CLOSE sql_close sqlClose SQL_CMP_DB sql_cmp_db ptrCmp SQL_CMP_STMT sql_cmp_stmt ptrCmp SQL_COLUMN_BIGINT sql_column_bigint sqlColumnBigInt SQL_COLUMN_BIGRAT sql_column_bigrat sqlColumnBigRat SQL_COLUMN_BOOL sql_column_bool sqlColumnBool SQL_COLUMN_BSTRI sql_column_bstri sqlColumnBStri SQL_COLUMN_DURATION sql_column_duration sqlColumnDuration SQL_COLUMN_FLOAT sql_column_float sqlColumnFloat SQL_COLUMN_INT sql_column_int sqlColumnInt SQL_COLUMN_STRI sql_column_stri sqlColumnStri SQL_COLUMN_TIME sql_column_time sqlColumnTime SQL_COMMIT sql_commit sqlCommit SQL_CPY_DB sql_cpy_db sqlCpyDb SQL_CPY_STMT sql_cpy_stmt sqlCpyStmt SQL_CREATE_DB sql_create_db sqlCreateDb SQL_CREATE_STMT sql_create_stmt sqlCreateStmt SQL_DESTR_DB sql_destr_db sqlDestrDb SQL_DESTR_STMT sql_destr_stmt sqlDestrStmt SQL_DRIVER sql_driver sqlDriver SQL_EMPTY_DB sql_empty_db SQL_EMPTY_STMT sql_empty_stmt SQL_EQ_DB sql_eq_db == SQL_EQ_STMT sql_eq_stmt == SQL_ERR_CODE sql_err_code sqlErrCode SQL_ERR_DB_FUNC sql_err_db_func sqlErrDbFunc SQL_ERR_LIB_FUNC sql_err_lib_func sqlErrLibFunc SQL_ERR_MESSAGE sql_err_message sqlErrMessage SQL_EXECUTE sql_execute sqlExecute SQL_FETCH sql_fetch sqlFetch SQL_GET_AUTO_COMMIT sql_get_auto_commit sqlGetAutoCommit SQL_IS_NULL sql_is_null sqlIsNull SQL_NE_DB sql_ne_db != SQL_NE_STMT sql_ne_stmt != SQL_OPEN_DB2 sql_open_db2 sqlOpenDb2 SQL_OPEN_FIRE sql_open_fire sqlOpenFire SQL_OPEN_INFORMIX sql_open_informix sqlOpenInformix SQL_OPEN_LITE sql_open_lite sqlOpenLite SQL_OPEN_MY sql_open_my sqlOpenMy SQL_OPEN_OCI sql_open_oci sqlOpenOci SQL_OPEN_ODBC sql_open_odbc sqlOpenOdbc SQL_OPEN_POST sql_open_post sqlOpenPost SQL_OPEN_SQLSRV sql_open_sqlsrv sqlOpenSqlServer SQL_OPEN_TDS sql_open_tds sqlOpenTds SQL_PREPARE sql_prepare sqlPrepare SQL_ROLLBACK sql_rollback sqlRollback SQL_SET_AUTO_COMMIT sql_set_auto_commit sqlSetAutoCommit SQL_STMT_COLUMN_COUNT sql_stmt_column_count sqlStmtColumnCount SQL_STMT_COLUMN_NAME sql_stmt_column_name sqlStmtColumnName 14.31 Actions for the type string
Action name strlib.c function str_rtl.c function STR_APPEND str_append strAppend STR_CAT str_cat strConcat, strConcatTemp STR_CHIPOS str_chipos strChIpos STR_CHPOS str_chpos strChPos STR_CHSPLIT str_chsplit strChSplit STR_CLIT str_clit strCLit STR_CMP str_cmp strCompare STR_CPY str_cpy strCopy STR_CREATE str_create strCreate STR_DESTR str_destr strDestr STR_ELEMCPY str_elemcpy a->mem[b-1]=c STR_EQ str_eq a->size==b->size && memcmp(a,b,a->size*sizeof(strElemType))==0 STR_FOR str_for for STR_FOR_KEY str_for_key for STR_FOR_VAR_KEY str_for_var_key for STR_FROM_UTF8 str_from_utf8 strFromUtf8 STR_GE str_ge strGe STR_GT str_gt strGt STR_HASHCODE str_hashcode strHashCode STR_HEAD str_head strHead STR_IDX str_idx a->mem[b-1] STR_IPOS str_ipos strIpos STR_LE str_le strLe STR_LIT str_lit strLit STR_LNG str_lng a->size STR_LOW str_low strLow, strLowTemp STR_LPAD str_lpad strLpad STR_LPAD0 str_lpad0 strLpad0, strLpad0Temp STR_LT str_lt strLt STR_LTRIM str_ltrim strLtrim STR_MULT str_mult strMult STR_NE str_ne a->size!=b->size || memcmp(a,b,a->size*sizeof(strElemType))!=0 STR_POS str_pos strPos STR_POSCPY str_poscpy memcpy STR_PUSH str_push strPush STR_RANGE str_range strRange STR_RCHIPOS str_rchipos strRChIpos STR_RCHPOS str_rchpos strRChPos STR_REPL str_repl strRepl STR_RIPOS str_ripos strRIPos STR_RPAD str_rpad strRpad STR_RPOS str_rpos strRpos STR_RTRIM str_rtrim strRtrim STR_SPLIT str_split strSplit STR_STR str_str (noop) STR_SUBSTR str_substr strSubstr STR_SUBSTR_FIXLEN str_substr_fixlen strSubstrFixLen STR_TAIL str_tail strTail STR_TO_UTF8 str_to_utf8 strToUtf8 STR_TRIM str_trim strTrim STR_UP str_up strUp, strUpTemp STR_VALUE str_value strValue 14.32 Actions for the type time
Action name timlib.c function tim_unx.c/tim_win.c function TIM_AWAIT tim_await timAwait TIM_FROM_TIMESTAMP tim_from_timestamp timFromTimestamp TIM_NOW tim_now timNow TIM_SET_LOCAL_TZ tim_set_local_tz timSetLocalTZ 14.33 Actions for the type type
Action name typlib.c function typ_data.c function TYP_ADDINTERFACE typ_addinterface TYP_CMP typ_cmp typCmp TYP_CPY typ_cpy typCpy TYP_CREATE typ_create typCreate TYP_DESTR typ_destr typDestr TYP_EQ typ_eq == TYP_FUNC typ_func typFunc TYP_GENSUB typ_gensub TYP_GENTYPE typ_gentype TYP_HASHCODE typ_hashcode (intType)(((memSizeType)a)>>6) TYP_ISDECLARED typ_isdeclared TYP_ISDERIVED typ_isderived typIsDerived TYP_ISFORWARD typ_isforward TYP_ISFUNC typ_isfunc typIsFunc TYP_ISVARFUNC typ_isvarfunc typIsVarfunc TYP_MATCHOBJ typ_matchobj typMatchobj TYP_META typ_meta typMeta TYP_NE typ_ne != TYP_NUM typ_num typNum TYP_RESULT typ_result typResult TYP_SET_IN_PARAM_REF typ_set_in_param_ref TYP_SET_IN_PARAM_VALUE typ_set_in_param_value TYP_STR typ_str typStr TYP_VALUE typ_value typValue TYP_VARCONV typ_varconv TYP_VARFUNC typ_varfunc typVarfunc 14.34 Actions for the type utf8File
Action name ut8lib.c function ut8_rtl.c function UT8_GETC ut8_getc ut8Getc UT8_GETS ut8_gets ut8Gets UT8_LINE_READ ut8_line_read ut8LineRead UT8_SEEK ut8_seek ut8Seek UT8_WORD_READ ut8_word_read ut8WordRead UT8_WRITE ut8_write ut8Write 16. FOREIGN FUNCTION INTERFACE
Foreign functions cannot be called directly. It is necessary to write wrapper functions. Several things must be done to call a foreign function:
- The C types used by Seed7 must be converted to the C types used by the foreign function (E.g.: string and path conversions). The result of the foreign function and parameters, which return a value, must be converted back. This conversions are usually done in a wrapper function.
- A function with the action prototype (a function with a listType parameter and an objectType result) must be defined. Predefined macros help to access the action arguments and to create result values. The action function must be registered in the file "primitiv.c".
- The new action must be introduced to Seed7. This is usually done in an *.s7i library file, which introduces an action definition.
In general two functions are needed: A wrapper function and an action function. The corresponding function definitions can be placed in two *.c files. Corresponding *.h files contain prototypes. Assume, we have the library "superlib" and the function doWurx1 from "superlib" should be called from a Seed7 program. The three letter abbreviation sup is used to determine the file and function names for wrapper and action. The following files and functions are used:
File Function Comment superlib.a doWurx1 External library (the extension may vary) superlib.h doWurx1 Prototype of the external C function sup_rtl.c supDoWurx1 Wrapper function sup_rtl.h supDoWurx1 Prototype of the wrapper function suplib.c sup_doWurx1 Action function suplib.h sup_doWurx1 Prototype of the action function primitiv.c Alphabetical list of all primitive actions makefile Makefile name depends on operating system and C compiler superlib.s7i doWurx1 Introduces the external function to a Seed7 program The C prototype of doWurx1 is defined in the file "superlib.h":
int doWurx1 (char *name);This function accepts an UTF-8 'name' and it returns 0 on success. Every other return value indicates that the string is too long. In this case the exception RANGE_ERROR should be raised. The wrapper function is defined in the file "sup_rtl.c" with:
#include "version.h" #include "stdio.h" #include "superlib.h" #include "common.h" #include "striutl.h" #include "rtl_err.h" void supDoWurx1 (const striType name) { cstriType cName; errInfoType err_info = OKAY_NO_ERROR; int wurxResult; cName = stri_to_cstri8(name, &err_info); if (cName == NULL) { raise_error(err_info); } else { wurxResult = doWurx1(cName); free_cstri8(cName, name); if (wurxResult != 0) { raise_error(RANGE_ERROR); } } }The prototype of supDoWurx1 is defined in the file "sup_rtl.h" with:
void supDoWurx1 (const striType name);The action function for supDoWurx1 is defined in the file "suplib.c" with:
#include "version.h" #include "stdio.h" #include "common.h" #include "data.h" #include "syvarutl.h" #include "objutl.h" #include "sup_rtl.h" objectType sup_doWurx1 (listType arguments) { isit_stri(arg_1(arguments)); supDoWurx1(take_stri(arg_1(arguments))); return SYS_EMPTY_OBJECT; }The prototype of sup_doWurx1 is defined in the file "suplib.h" with:
objectType sup_doWurx1 (listType arguments);The action is introduced to the interpreter, by changing the file "primitiv.c". An include directive for "suplib.h" must be added:
#include "strlib.h" #include "suplib.h" #include "timlib.h"The file "primitiv.c" contains a list of alphabetically sorted primitive actions. Each action entry takes a line. It is important to add the new action "SUP_DO_WURX" at the correct place:
{ "STR_VALUE", str_value, }, { "SUP_DO_WURX", sup_doWurx1, }, { "TIM_AWAIT", tim_await, },The new files must be added to the makefile. Depending on C compiler and operating system Seed7 uses several makefiles. In the correct "makefile" suplib and sup_rtl must be added to lists of source and object files. Adding the suplib object file results in:
LOBJ = actlib.o arrlib.o biglib.o blnlib.o bstlib.o chrlib.o cmdlib.o conlib.o dcllib.o drwlib.o \ enulib.o fillib.o fltlib.o hshlib.o intlib.o itflib.o kbdlib.o lstlib.o pollib.o prclib.o \ prglib.o reflib.o rfllib.o sctlib.o setlib.o soclib.o strlib.o suplib.o timlib.o typlib.o ut8lib.oAdding the "suplib" source file results in:
LSRC = actlib.c arrlib.c biglib.c blnlib.c bstlib.c chrlib.c cmdlib.c conlib.c dcllib.c drwlib.c \ enulib.c fillib.c fltlib.c hshlib.c intlib.c itflib.c kbdlib.c lstlib.c pollib.c prclib.c \ prglib.c reflib.c rfllib.c sctlib.c setlib.c soclib.c strlib.c suplib.c timlib.c typlib.c ut8lib.cand object files. Adding the sup_rtl object file results in:
ROBJ = arr_rtl.o bln_rtl.o bst_rtl.o chr_rtl.o cmd_rtl.o con_rtl.o dir_rtl.o drw_rtl.o fil_rtl.o \ flt_rtl.o hsh_rtl.o int_rtl.o set_rtl.o soc_rtl.o str_rtl.o sup_rtl.o tim_rtl.o ut8_rtl.o \ heaputl.o striutl.oAdding the "sup_rtl" source file results in:
RSRC = arr_rtl.c bln_rtl.c bst_rtl.c chr_rtl.c cmd_rtl.c con_rtl.c dir_rtl.c drw_rtl.c fil_rtl.c \ flt_rtl.c hsh_rtl.c int_rtl.c set_rtl.c soc_rtl.c str_rtl.c sup_rtl.c tim_rtl.c ut8_rtl.c \ heaputl.c striutl.cThe external library "superlib" itself is added with:
SYSTEM_LIBS = -lm superlib.aThe interpreter must be compiled, so the changes can take effect. To actually call the new function it must be introduced in a Seed7 library. This is done with the library "super.s7i":
const proc: doWurx1 (in string: name) is action "SUP_DO_WURX";15.1 C types used by the implementation
Several Seed7 types correspond to simple C types, which are defined in "common.h":
Seed7 type C type Comment boolean boolType _Bool, bool or int integer intType 64-bit signed int float floatType 64-bit double char charType 32-bit unsigned int clib_file fileType FILE * PRIMITIVE_SOCKET socketType int or unsigned int Other Seed7 types correspond to C pointers, which point to a struct. Some of this structs are used in all situations: In the interpreter and in the compiler and under different operation systems and with different runtime libraries. This invariant structs are defined in "common.h" and in "data.h":
Seed7 type C type C struct Comment string striType struct striStruct UTF-32 encoded, can contain null chars set setType struct setStruct bstring bstriType struct bstriStruct Byte sequence, can contain null bytes reference objectType struct objectStruct Interpreter type for Seed7 objects ref_list listType struct listStruct Interpreter type for Seed7 object lists Other Seed7 types also correspond to struct pointers, but the structs are different in interpreted and compiled Seed7 programs. The structs for interpreted programs are defined in "data.h" and the structs for compiled programs are defined in "data_rtl.h":
Seed7 type C type (interpreted) C struct (interpreted) C type (compiled) C struct (compiled) array arrayType struct arrayStruct rtlArrayType struct rtlArrayStruct hash hashType struct hashStruct rtlHashType struct rtlHashStruct struct structType struct structStruct rtlStructType struct rtlStructStruct Because interpreter and compiler use different structs the functions from e.g. "arrlib.c" cannot use functions from "arr_rtl.c".
Some Seed7 types depend on the operating system or runtime library used:
Seed7 type C type Defined as Sourcefile Comment bigInteger bigIntType struct bigIntStruct * big_rtl.c The built-in bigInteger library bigIntType mpz_ptr big_gmp.c The GNU Multiple Precision Arithmetic Library pollData pollType struct select_based_pollStruct * pol_sel.c Functions cast it to implementation dependent struct pollType struct poll_based_pollStruct * pol_unx.c Functions cast it to implementation dependent struct PRIMITIVE_WINDOW winType x11_winRecord * drw_x11.c Functions cast from struct winStruct * to x11_winRecord * winType win_winRecord * drw_win.c Functions cast from struct winStruct * to win_winRecord * winType emc_winRecord * drw_emc.c Functions cast from struct winStruct * to emc_winRecord * database databaseType dbType sql_cli.c Functions cast from databaseType to dbType databaseType dbType sql_fire.c Functions cast from databaseType to dbType databaseType dbType sql_lite.c Functions cast from databaseType to dbType databaseType dbType sql_my.c Functions cast from databaseType to dbType databaseType dbType sql_oci.c Functions cast from databaseType to dbType databaseType dbType sql_post.c Functions cast from databaseType to dbType databaseType dbType sql_tds.c Functions cast from databaseType to dbType sqlStatement sqlStmtType preparedStmtType sql_cli.c Functions cast from sqlStmtType to preparedStmtType sqlStmtType preparedStmtType sql_fire.c Functions cast from sqlStmtType to preparedStmtType sqlStmtType preparedStmtType sql_lite.c Functions cast from sqlStmtType to preparedStmtType sqlStmtType preparedStmtType sql_my.c Functions cast from sqlStmtType to preparedStmtType sqlStmtType preparedStmtType sql_oci.c Functions cast from sqlStmtType to preparedStmtType sqlStmtType preparedStmtType sql_post.c Functions cast from sqlStmtType to preparedStmtType sqlStmtType preparedStmtType sql_tds.c Functions cast from sqlStmtType to preparedStmtType There are also C types without corresponding Seed7 type. They are defined in "common.h":
C type C definition Comment int16Type short int It is assumed that sizeof(short int) == 2 uint16Type unsigned short int Unsigned integer type with the size of int16Type int32Type int If sizeof(int) == 4 long If sizeof(long) == 4 uint32Type unsigned int32Type Unsigned integer type with the size of int32Type int64Type long If sizeof(long) == 8 long long If sizeof(long long) == 8 __int64 If sizeof(__int64) == 8 uint64Type unsigned int64Type Unsigned integer type with the size of int64Type int128Type __int128 If sizeof(__int128) == 16 __int128_t If sizeof(__int128_t) == 16 uint128Type unsigned __int128 If sizeof(unsigned __int128) == 16 __uint128_t If sizeof(__uint128_t) == 16 uintType unsigned intType Unsigned integer type with the size of intType cstriType char * String type of the C compiler ustriType unsigned char * Helpful for unsigned comparisons utf16striType uint16Type * UTF-16 string utf32striType uint32Type * UTF-32 string strElemType charType UTF-32 character element of string. os_striType char * If the OS uses UTF-8 chars wchar_t * If the OS uses UTF-16 chars memSizeType uint32Type If C uses 32-bit pointers uint64Type If C uses 64-bit pointers errInfoType int Represents predefined Exceptions 15.2 String conversions
Seed7 strings are UTF-32 encoded and C strings are zero terminated byte sequences. C uses also byte sequences with a length. The byte sequences can be encoded with ISO-8859-1 or UTF-8. To convert between the different representations, "striutl.h" defines conversion functions between the types striType, cstriType, bstriType, utf16striType and utf32striType. The types utf16striType and utf32striType are independent of the size of wchar_t. Strings with utf16striType and utf32striType can be zero terminated or a buffer with a length, that is specified with a parameter.
Function Summary cstriType
stri_to_cstri (const const_striType stri, errInfoType *err_info) Create an ISO-8859-1 encoded C string from a Seed7 UTF-32 string. cstriType
stri_to_cstri8 (const const_striType stri, errInfoType *err_info) Create an UTF-8 encoded C string from a Seed7 UTF-32 string. cstriType
stri_to_cstri8_buf (const const_striType stri, memSizeType *length) Create an UTF-8 encoded C string buffer from a Seed7 UTF-32 string. bstriType
stri_to_bstri (const const_striType stri, errInfoType *err_info) Create an ISO-8859-1 encoded bstring from a Seed7 UTF-32 string. bstriType
stri_to_bstri8 (const_striType stri) Create an UTF-8 encoded bstring from a Seed7 UTF-32 string. utf16striType
stri_to_wstri16 (const const_striType stri, memSizeType *length, errInfoType *err_info) Create an UTF-16 encoded wide string buffer from a Seed7 UTF-32 string. utf32striType
stri_to_wstri32 (const const_striType stri, memSizeType *length, errInfoType *err_info) Create an UTF-32 encoded wide string buffer from a Seed7 UTF-32 string. striType
cstri_to_stri (const_cstriType cstri) Copy an ISO-8859-1 (Latin-1) encoded C string to a Seed7 string. striType
cstri_buf_to_stri (const_cstriType cstri, memSizeType length) Copy an ISO-8859-1 (Latin-1) encoded C string buffer to a Seed7 string. striType
cstri8_to_stri (const_cstriType cstri, errInfoType *err_info) Copy an UTF-8 encoded C string to a Seed7 string. striType
cstri8_buf_to_stri (const_cstriType cstri, memSizeType length, errInfoType *err_info) Copy an UTF-8 encoded C string buffer to a Seed7 string. striType
cstri8_or_cstri_to_stri (const_cstriType cstri) Copy an UTF-8 or ISO-8859-1 encoded C string to a Seed7 string. striType
wstri16_to_stri (const_utf16striType wstri, memSizeType length, errInfoType *err_info) Copy an UTF-16 encoded wide string buffer to a Seed7 string. striType
wstri32_to_stri (const_utf32striType wstri, memSizeType length, errInfoType *err_info) Copy an UTF-32 encoded wide string buffer to a Seed7 string.
Function Detail stri_to_cstri
cstriType stri_to_cstri (const const_striType stri, errInfoType *err_info)
Create an ISO-8859-1 encoded C string from a Seed7 UTF-32 string. The memory for the zero byte terminated C string is allocated. The C string result must be freed with the macro free_cstri().
- Parameters:
- stri - Seed7 UTF-32 string to be converted.
- err_info - Unchanged if the function succeeds, and MEMORY_ERROR if the memory allocation failed, and RANGE_ERROR if stri contains a null character or a character that is higher than the highest allowed ISO-8859-1 character (255).
- Returns:
- an ISO-8859-1 encoded null terminated C string, or NULL if the memory allocation failed or the conversion failed (the error is indicated by err_info).
stri_to_cstri8
cstriType stri_to_cstri8 (const const_striType stri, errInfoType *err_info)
Create an UTF-8 encoded C string from a Seed7 UTF-32 string. The memory for the zero byte terminated C string is allocated. The C string result must be freed with the macro free_cstri8(). This function is intended to create temporary strings, that are used as parameters. To get good performance the allocated memory for the C string is oversized.
- Parameters:
- stri - Seed7 UTF-32 string to be converted.
- err_info - Unchanged if the function succeeds, and MEMORY_ERROR if the memory allocation failed, and RANGE_ERROR if stri contains a null character or a character that is higher than the highest allowed Unicode character (U+10FFFF).
- Returns:
- an UTF-8 encoded null terminated C string, or NULL if the memory allocation failed or the conversion failed (the error is indicated by err_info).
stri_to_cstri8_buf
cstriType stri_to_cstri8_buf (const const_striType stri, memSizeType *length)
Create an UTF-8 encoded C string buffer from a Seed7 UTF-32 string. The memory for the zero byte terminated C string is allocated. Zero bytes inside the string are copied to the C string. The C string result must be freed with the macro free_cstri8(). This function is intended to create temporary strings, that are used as parameters. To get good performance the allocated memory for the C string is oversized.
- Parameters:
- stri - Seed7 UTF-32 string to be converted.
- length - Place to return the length of the result (without '\0').
- Returns:
- an UTF-8 encoded null terminated C string, or NULL if the memory allocation failed.
stri_to_bstri
bstriType stri_to_bstri (const const_striType stri, errInfoType *err_info)
Create an ISO-8859-1 encoded bstring from a Seed7 UTF-32 string. The memory for the bstring is allocated. No zero byte is added to the end of the bstring. No special action is done, if the UTF-32 string contains a null character.
- Parameters:
- stri - Seed7 UTF-32 string to be converted.
- err_info - Unchanged if the function succeeds, and MEMORY_ERROR if the memory allocation failed, and RANGE_ERROR if stri contains a character that is higher than the highest allowed ISO-8859-1 character (255).
- Returns:
- an ISO-8859-1 encoded bstring, or NULL if the memory allocation failed or the conversion failed (the error is indicated by err_info).
stri_to_bstri8
bstriType stri_to_bstri8 (const_striType stri)
Create an UTF-8 encoded bstring from a Seed7 UTF-32 string. The memory for the bstring is allocated. No zero byte is added to the end of the bstring. No special action is done, if the original string contains a null character.
- Parameters:
- stri - Seed7 UTF-32 string to be converted.
- Returns:
- an UTF-8 encoded bstring, or NULL if the memory allocation failed.
stri_to_wstri16
utf16striType stri_to_wstri16 (const const_striType stri, memSizeType *length, errInfoType *err_info)
Create an UTF-16 encoded wide string buffer from a Seed7 UTF-32 string. The memory for the zero byte terminated wide string is allocated. This function is intended to create temporary strings, that are used as parameters. To get good performance the allocated memory for the wide string is oversized.
- Parameters:
- stri - Seed7 UTF-32 string to be converted.
- length - Place to return the character length of the result (without '\0').
- err_info - Unchanged if the function succeeds, and MEMORY_ERROR if the memory allocation failed, and RANGE_ERROR if stri contains a character that is higher than the highest allowed Unicode character (U+10FFFF).
- Returns:
- an UTF-16 encoded null terminated wide string, or NULL if the memory allocation failed or the conversion failed (the error is indicated by err_info).
stri_to_wstri32
utf32striType stri_to_wstri32 (const const_striType stri, memSizeType *length, errInfoType *err_info)
Create an UTF-32 encoded wide string buffer from a Seed7 UTF-32 string. The memory for the zero byte terminated wide string is allocated. This function is intended to create temporary strings, that are used as parameters. To get good performance the allocated memory for the wide string is oversized.
- Parameters:
- stri - Seed7 UTF-32 string to be converted.
- length - Place to return the character length of the result (without '\0').
- err_info - Unchanged if the function succeeds, and MEMORY_ERROR if the memory allocation failed, and RANGE_ERROR if stri contains a character that is higher than the highest allowed Unicode character (U+10FFFF).
- Returns:
- an UTF-32 encoded null terminated wide string, or NULL if the memory allocation failed or the conversion failed (the error is indicated by err_info).
cstri_to_stri
striType cstri_to_stri (const_cstriType cstri)
Copy an ISO-8859-1 (Latin-1) encoded C string to a Seed7 string. The memory for the UTF-32 encoded Seed7 string is allocated.
- Parameters:
- cstri - Null terminated ISO-8859-1 encoded C string.
- Returns:
- an UTF-32 encoded Seed7 string, or NULL if the memory allocation failed.
cstri_buf_to_stri
striType cstri_buf_to_stri (const_cstriType cstri, memSizeType length)
Copy an ISO-8859-1 (Latin-1) encoded C string buffer to a Seed7 string. The memory for the UTF-32 encoded Seed7 string is allocated.
- Parameters:
- cstri - ISO-8859-1 encoded C string buffer (not null terminated).
- length - Byte length of the ISO-8859-1 encoded C string buffer.
- Returns:
- an UTF-32 encoded Seed7 string, or NULL if the memory allocation failed.
cstri8_to_stri
striType cstri8_to_stri (const_cstriType cstri, errInfoType *err_info)
Copy an UTF-8 encoded C string to a Seed7 string. The memory for the UTF-32 encoded Seed7 string is allocated.
- Parameters:
- cstri - Null terminated UTF-8 encoded C string.
- err_info - Unchanged if the function succeeds, and MEMORY_ERROR if the memory allocation failed, and RANGE_ERROR if the conversion failed.
- Returns:
- an UTF-32 encoded Seed7 string, or NULL if the memory allocation failed or invalid UTF-8 encodings are used.
cstri8_buf_to_stri
striType cstri8_buf_to_stri (const_cstriType cstri, memSizeType length, errInfoType *err_info)
Copy an UTF-8 encoded C string buffer to a Seed7 string. The memory for the UTF-32 encoded Seed7 string is allocated.
- Parameters:
- cstri - UTF-8 encoded C string buffer (not null terminated).
- length - Byte length of the UTF-8 encoded C string buffer.
- err_info - Unchanged if the function succeeds, and MEMORY_ERROR if the memory allocation failed, and RANGE_ERROR if the conversion failed.
- Returns:
- an UTF-32 encoded Seed7 string, or NULL if the memory allocation failed or invalid UTF-8 encodings are used.
cstri8_or_cstri_to_stri
striType cstri8_or_cstri_to_stri (const_cstriType cstri)
Copy an UTF-8 or ISO-8859-1 encoded C string to a Seed7 string. The memory for the UTF-32 encoded Seed7 string is allocated.
- Parameters:
- cstri - Null terminated UTF-8 or ISO-8859-1 encoded C string.
- Returns:
- an UTF-32 encoded Seed7 string, or NULL if the memory allocation failed.
wstri16_to_stri
striType wstri16_to_stri (const_utf16striType wstri, memSizeType length, errInfoType *err_info)
Copy an UTF-16 encoded wide string buffer to a Seed7 string. The memory for the UTF-32 encoded Seed7 string is allocated.
- Parameters:
- wstri - UTF-16 encoded wide string buffer (not null terminated).
- length - Character length of the UTF-16 encoded wide string buffer.
- err_info - Unchanged if the function succeeds, and MEMORY_ERROR if the memory allocation failed.
- Returns:
- an UTF-32 encoded Seed7 string, or NULL if the memory allocation failed.
wstri32_to_stri
striType wstri32_to_stri (const_utf32striType wstri, memSizeType length, errInfoType *err_info)
Copy an UTF-32 encoded wide string buffer to a Seed7 string. The memory for the UTF-32 encoded Seed7 string is allocated.
- Parameters:
- wstri - UTF-32 encoded wide string buffer (not null terminated).
- length - Character length of the UTF-32 encoded wide string buffer.
- err_info - Unchanged if the function succeeds, and MEMORY_ERROR if the memory allocation failed.
- Returns:
- an UTF-32 encoded Seed7 string, or NULL if the memory allocation failed.
15.3 Operating system string and path conversions
Operating systems disagree in their Unicode encoding (UTF-8 or UTF-16). To cope with this, "striutl.h" defines the type os_striType and functions to convert to and from os_striType. The different concepts to represent a file path (path delimiter and drive letter) are handled with cp_to_os_path and cp_from_os_path.
Function Summary striType
conv_from_os_stri (const const_os_striType os_stri, memSizeType length) Convert an os_striType string with length to a Seed7 UTF-32 string. os_striType
stri_to_os_stri (const_striType stri, errInfoType *err_info) Convert a Seed7 UTF-32 string to a null terminated os_striType string. striType
os_stri_to_stri (const_os_striType os_stri, errInfoType *err_info) Convert a null terminated os_striType string to a Seed7 UTF-32 string. os_striType
cp_to_os_path (const_striType std_path, int *path_info, errInfoType *err_info) Convert a Seed7 standard path to a path used by system calls. striType
cp_from_os_path (const_os_striType os_path, errInfoType *err_info) Convert a path returned by a system call to a Seed7 standard path.
Function Detail conv_from_os_stri
striType conv_from_os_stri (const const_os_striType os_stri, memSizeType length)
Convert an os_striType string with length to a Seed7 UTF-32 string. Many system calls return os_striType data with length. System calls are defined in "version.h" and "os_decls.h". They are prefixed with os_ and use strings of the type os_striType. Depending on the operating system os_striType can describe byte or wide char strings. The encoding can be Latin-1, UTF-8, UTF-16 or it can use a code page.
- Parameters:
- os_stri - Possibly binary string (may contain null characters).
- length - Length of os_stri in characters.
- Returns:
- a Seed7 UTF-32 string, or NULL if an error occurred.
stri_to_os_stri
os_striType stri_to_os_stri (const_striType stri, errInfoType *err_info)
Convert a Seed7 UTF-32 string to a null terminated os_striType string. The memory for the null terminated os_striType string is allocated. The os_striType result is allocated with the macro os_stri_alloc() and it must be freed with the macro os_stri_free(). Strings allocated with os_stri_alloc() must be freed in the reverse order of their creation. This allows that allocations work in a stack like manner. Many system calls have parameters with null terminated os_striType strings. System calls are defined in "version.h" and "os_decls.h". They are prefixed with os_ and use strings of the type os_striType. Depending on the operating system os_striType can describe byte or wide char strings. The encoding can be Latin-1, UTF-8, UTF-16 or it can use a code page.
- Parameters:
- stri - Seed7 UTF-32 string to be converted.
- err_info - Unchanged if the function succeeds, and MEMORY_ERROR if the memory allocation failed, and RANGE_ERROR if the conversion failed.
- Returns:
- a null terminated os_striType value used by system calls, or NULL if an error occurred.
os_stri_to_stri
striType os_stri_to_stri (const_os_striType os_stri, errInfoType *err_info)
Convert a null terminated os_striType string to a Seed7 UTF-32 string. Many system calls return null terminated os_striType strings. System calls are defined in "version.h" and "os_decls.h". They are prefixed with os_ and use strings of the type os_striType. Depending on the operating system os_striType can describe byte or wide char strings. The encoding can be Latin-1, UTF-8, UTF-16 or it can use a code page.
- Parameters:
- os_stri - Null terminated os_striType string to be converted.
- err_info - Unchanged if the function succeeds, and MEMORY_ERROR if the memory allocation failed.
- Returns:
- a Seed7 UTF-32 string, or NULL if an error occurred.
cp_to_os_path
os_striType cp_to_os_path (const_striType std_path, int *path_info, errInfoType *err_info)
Convert a Seed7 standard path to a path used by system calls. The memory for the null terminated os_striType path is allocated. The os_striType result is allocated with the macro os_stri_alloc() and it must be freed with the macro os_stri_free(). Strings allocated with os_stri_alloc() must be freed in the reverse order of their creation. This allows that allocations work in a stack like manner. System calls are defined in "version.h" and "os_decls.h". They are prefixed with os_ and use system paths of the type os_striType. Depending on the operating system os_striType can describe byte or wide char strings. The encoding can be Latin-1, UTF-8, UTF-16 or it can use a code page. Beyond the conversion to os_striType a mapping to drive letters might take place on some operating systems.
- Parameters:
- std_path - UTF-32 encoded Seed7 standard path to be converted.
- path_info - Unchanged if the function succeeds, and PATH_IS_EMULATED_ROOT if the path is "/", and PATH_NOT_MAPPED if the path cannot be mapped.
- err_info - Unchanged if the function succeeds, and MEMORY_ERROR if the memory allocation failed, and RANGE_ERROR if the path is not a standard path.
- Returns:
- a null terminated os_striType path used by system calls, or NULL if an error occurred.
cp_from_os_path
striType cp_from_os_path (const_os_striType os_path, errInfoType *err_info)
Convert a path returned by a system call to a Seed7 standard path. System calls are defined in "version.h" and "os_decls.h". They are prefixed with os_ and use system paths of the type os_striType. Depending on the operating system os_striType can describe byte or wide char strings. The encoding can be Latin-1, UTF-8, UTF-16 or it can use a code page. Beyond the conversion from os_striType a mapping from drive letters might take place on some operating systems.
- Parameters:
- os_path - Null terminated os_striType path to be converted.
- err_info - Unchanged if the function succeeds, and MEMORY_ERROR if the memory allocation failed.
- Returns:
- an UTF-32 encoded Seed7 standard path, or NULL if the memory allocation failed.
15.4 Macros to access the action parameters
A primitive action function has one parameter named 'arguments'. The 'arguments' parameter has the type listType and contains a list of objects. The header file "objutl.h" defines macros like arg_1, arg_2, arg_3, etc. to get a specific object from the 'arguments'.
Functions (macros) to get a Seed7 object from a list objectType
arg_1 (listType arguments) Take the first object from the list. objectType
arg_2 (listType arguments) Take the second object from the list. objectType
arg_3 (listType arguments) Take the third object from the list. . . .
. . . objectType
arg_12 (listType arguments) Take the twelfth object from the list. An object value contains a specific C implementation type. The header file "objutl.h" defines macros like isit_char and isit_set to check, if an object has the requested type. If the object has not the requested C implementation type and error message is written.
Functions (macros) to check the C type of Seed7 objects void
isit_array (objectType arg) Check if the object type is arrayType. void
isit_bigint (objectType arg) Check if the object type is bigIntType. void
isit_bool (objectType arg) Check if the object type is boolType. void
isit_bstri (objectType arg) Check if the object type is bstriType. void
isit_char (objectType arg) Check if the object type is charType. void
isit_database (objectType arg) Check if the object type is databaseType. void
isit_file (objectType arg) Check if the object type is fileType. void
isit_float (objectType arg) Check if the object type is floatType. void
isit_hash (objectType arg) Check if the object type is hashType. void
isit_int (objectType arg) Check if the object type is intType. void
isit_poll (objectType arg) Check if the object type is pollType. void
isit_set (objectType arg) Check if the object type is setType. void
isit_socket (objectType arg) Check if the object type is socketType. void
isit_sqlstmt (objectType arg) Check if the object type is sqlStmtType. void
isit_stri (objectType arg) Check if the object type is striType. void
isit_struct (objectType arg) Check if the object type is structType. void
isit_win (objectType arg) Check if the object type is winType. The header file "objutl.h" defines macros like take_bool and take_file. This macros return a value with the requested C implementation type.
Functions (macros) to get the C values of Seed7 objects arrayType
take_array (objectType arg) Take the array value from an object. bigIntType
take_bigint (objectType arg) Take the bigInteger value from an object. boolType
take_bool (objectType arg) Take the boolean value from an object. bstriType
take_bstri (objectType arg) Take the bstring value from an object. charType
take_char (objectType arg) Take the char value from an object. databaseType
take_database (objectType arg) Take the database value from an object. fileType
take_file (objectType arg) Take the file value from an object. floatType
take_float (objectType arg) Take the float value from an object. hashType
take_hash (objectType arg) Take the hash table value from an object. intType
take_int (objectType arg) Take the integer value from an object. pollType
take_poll (objectType arg) Take the poll data value from an object. setType
take_set (objectType arg) Take the set value from an object. socketType
take_socket (objectType arg) Take the socket value from an object. sqlStmtType
take_sqlstmt (objectType arg) Take the SQL prepared statement value from an object. striType
take_stri (objectType arg) Take the string value from an object. structType
take_struct (objectType arg) Take the struct value from an object. winType
take_win (objectType arg) Take the struct value from an object. 15.5 Functions to create action results
A primitive action function has a result of type objectType. The header file "objutl.h" defines macros like bld_bigint_temp and bld_stri_temp to create an object with the specified type.
Functions to create Seed7 objects with a C value objectType
bld_array_temp (arrayType temp_array) Create an object with an arrayType value. objectType
bld_bigint_temp (bigIntType temp_bigint) Create an object with a bigIntType value. objectType
bld_bstri_temp (bstriType temp_bstri) Create an object with a bstriType value. objectType
bld_char_temp (charType temp_char) Create an object with a charType value. objectType
bld_database_temp (databaseType temp_database) Create an object with a databaseType value. objectType
bld_file_temp (fileType temp_file) Create an object with a fileType value. objectType
bld_float_temp (floatType temp_float) Create an object with a floatType value. objectType
bld_hash_temp (hashType temp_hash) Create an object with a hashType value. objectType
bld_int_temp (intType temp_int) Create an object with an intType value. objectType
bld_poll_temp (pollType temp_poll) Create an object with a pollType value. objectType
bld_set_temp (setType temp_set) Create an object with a setType value. objectType
bld_socket_temp (socketType temp_socket) Create an object with a socketType value. objectType
bld_sqlstmt_temp (sqlStmtType temp_sqlstmt) Create an object with a sqlStmtType value. objectType
bld_stri_temp (striType temp_stri) Create an object with a striType value. objectType
bld_struct_temp (structType temp_struct) Create an object with a structType value. objectType
bld_win_temp (winType temp_win) Create an object with a winType value. 15.6 Memory management macros
The conversion functions mentioned above use macros to do the memory management. Some of this macros are not based on malloc() but manage the memory in a stack. Therefore it is important to use the correct macro to allocate and free memory. The macros below are defined in the header file "striutl.h".
Macro Summary void
free_cstri (cstriType cstri, striType stri) Macro to free memory that has been allocated by stri_to_cstri(). void
free_cstri8 (cstriType cstri, striType stri) Macro to free memory that has been allocated by stri_to_cstri8() or stri_to_cstri8_buf(). boolType
os_stri_alloc (os_striType &var, memSizeType len) Macro to allocate memory for an os_striType string. void
os_stri_free (os_striType var) Macro to free memory that has been allocated with os_stri_alloc.
Macro Detail free_cstri
void free_cstri (cstriType cstri, striType stri)
Macro to free memory that has been allocated by stri_to_cstri().
- Parameters:
- cstri - The string to be freed.
- stri - The parameter that was used when stri_to_cstri() was called.
free_cstri8
void free_cstri8 (cstriType cstri, striType stri)
Macro to free memory that has been allocated by stri_to_cstri8() or stri_to_cstri8_buf().
- Parameters:
- cstri - The string to be freed.
- stri - The parameter that was used when stri_to_cstri8() or stri_to_cstri8_buf() was called.
os_stri_alloc
boolType os_stri_alloc (os_striType &var, memSizeType len)
Macro to allocate memory for an os_striType string. Strings allocated with os_stri_alloc() must be freed with os_stri_free() in the reverse order of their creation. This allows that allocations work in a stack like manner.
- Parameters:
- var - Reference to a variable to which the allocated memory is assigned.
- len - Size of the allocated memory in characters.
- Returns:
- TRUE if the allocation succeeds, and FALSE if the memory allocation failed.
os_stri_free
void os_stri_free (os_striType var)
Macro to free memory that has been allocated with os_stri_alloc. Strings allocated with os_stri_alloc() must be freed with os_stri_free() in the reverse order of their creation. This allows that allocations work in a stack like manner. The strings returned by stri_to_os_stri and cp_to_os_path are also allocated with os_stri_alloc. Therefore they must also be freed with os_stri_free() in the reverse order of their creation.
- Parameters:
- var - The string to be freed.
15.7 Basic conversion functions
The conversion functions mentioned above are implemented with basic conversion functions. In some situations it might make sense to use the basic conversion functions directly. This functions are optimized for performance. Some functions use loop unrolling inspired by Duff's device. The basic conversion functions below are defined in the header file "striutl.h".
Function Summary void
memcpy_to_strelem (register strElemType *const dest, register const const_ustriType src, memSizeType len) Copy len bytes to Seed7 characters in a string. void
memset_to_strelem (register strElemType *const dest, register const strElemType ch, memSizeType len) Fill len Seed7 characters with the character ch. boolType
memcpy_from_strelem (register const const_ustriType dest, register const strElemType *const src, memSizeType len) Copy len Seed7 characters to a byte string. const strElemType *
memchr_strelem (register const strElemType *mem, const strElemType ch, memSizeType len) Scan the first len Seed7 characters for the character ch. memSizeType
utf8_to_stri (strElemType *const dest_stri, memSizeType *const dest_len, const_ustriType ustri, memSizeType len) Convert an UTF-8 encoded string to an UTF-32 encoded string. memSizeType
stri_to_utf8 (const ustriType out_stri, const strElemType *strelem, memSizeType len) Convert an UTF-32 encoded string to an UTF-8 encoded string. memSizeType
stri_to_utf16 (const utf16striType out_wstri, register const strElemType *strelem, memSizeType len, errInfoType *const err_info) Convert an UTF-32 encoded string to an UTF-16 encoded string.
Function Detail memcpy_to_strelem
void memcpy_to_strelem (register strElemType *const dest, register const const_ustriType src, memSizeType len)
Copy len bytes to Seed7 characters in a string. This function works also correct if 'src' and 'dest' point to the same address. In other words it works correct for:
memcpy_to_strelem(mem, (ustriType) mem, num);
- Parameters:
- dest - Destination array with UTF-32 encoded characters.
- src - Source array with ISO-8859-1 encoded bytes.
- len - Number of bytes in 'src' and UTF-32 characters in 'dest'.
memset_to_strelem
void memset_to_strelem (register strElemType *const dest, register const strElemType ch, memSizeType len)
Fill len Seed7 characters with the character ch.
- Parameters:
- dest - Destination array with UTF-32 encoded characters.
- ch - UTF-32 encoded character to be filled into 'dest'.
- len - Specifies how often 'ch' is filled into 'dest'.
memcpy_from_strelem
boolType memcpy_from_strelem (register const const_ustriType dest, register const strElemType *const src, memSizeType len)
Copy len Seed7 characters to a byte string. This function uses loop unrolling inspired by Duff's device and a trick with a binary or (|=) to check for allowed values.
- Parameters:
- dest - Destination array with ISO-8859-1 encoded bytes.
- src - Source array with UTF-32 encoded characters.
- len - Number of UTF-32 characters in 'src' and bytes in 'dest'.
- Returns:
- TRUE if one of the characters does not fit into a byte, FALSE otherwise.
memchr_strelem
const strElemType *memchr_strelem (register const strElemType *mem, const strElemType ch, memSizeType len)
Scan the first len Seed7 characters for the character ch.
- Parameters:
- mem - Array with UTF-32 characters.
- ch - UTF-32 character to be searched in 'mem'.
- len - Number of UTF-32 characters in 'mem'.
- Returns:
- a pointer to the matching character, or NULL if the character does not occur in the given string area.
utf8_to_stri
memSizeType utf8_to_stri (strElemType *const dest_stri, memSizeType *const dest_len, const_ustriType ustri, memSizeType len)
Convert an UTF-8 encoded string to an UTF-32 encoded string. The source and destination strings are not '\0' terminated. The memory for the destination dest_stri is not allocated.
- Parameters:
- dest_stri - Destination of the UTF-32 encoded string.
- dest_len - Place to return the length of dest_stri.
- ustri - UTF-8 encoded string to be converted.
- len - Number of bytes in ustri.
- Returns:
- the number of bytes in ustri that are left unconverted, or 0 if ustri has been successfully converted.
stri_to_utf8
memSizeType stri_to_utf8 (const ustriType out_stri, const strElemType *strelem, memSizeType len)
Convert an UTF-32 encoded string to an UTF-8 encoded string. The source and destination strings are not '\0' terminated. The memory for the destination out_stri is not allocated.
- Parameters:
- out_stri - Destination of the UTF-8 encoded string.
- strelem - UTF-32 encoded string to be converted.
- len - Number of UTF-32 characters in strelem.
- Returns:
- the length of the converted UTF-8 string.
stri_to_utf16
memSizeType stri_to_utf16 (const utf16striType out_wstri, register const strElemType *strelem, memSizeType len, errInfoType *const err_info)
Convert an UTF-32 encoded string to an UTF-16 encoded string. The source and destination strings are not '\0' terminated. The memory for the destination out_wstri is not allocated.
- Parameters:
- out_wstri - Destination of the UTF-16 encoded string.
- strelem - UTF-32 encoded string to be converted.
- len - Number of UTF-32 characters in strelem.
- err_info - Unchanged if the function succeeds, and MEMORY_ERROR if *strelem contains a character that is higher than the highest allowed Unicode character (U+10FFFF).
- Returns:
- the length of the converted UTF-16 string in characters.
15.8 Error handling
The C programming language does not provide exceptions. Seed7 uses several methods to provide error handling. Before an actual exception is raised an error state can be handled in different ways:
- The integer type errInfoType is used to describe an error state. Usually a variable or parameter named err_info is used to store the error state. The value OKAY_NO_ERROR is used to describe that no error occurred. Values like MEMORY_ERROR, NUMERIC_ERROR, OVERFLOW_ERROR, RANGE_ERROR, FILE_ERROR, DATABASE_ERROR, GRAPHIC_ERROR and ACTION_ERROR describe errors that occurred.
- In some situations a function has only one possible error situation (e.g. a MEMORY_ERROR). This is handled with functions that return NULL in case of a MEMORY_ERROR.
C code can check the value of the err_info variable, or check if a function returns NULL. In case of error it is possible to do some cleaning up. An error situation can be propagated this way over several function levels. It is important to assure that an existing error situation (err_info has a value not equal to OKAY_NO_ERROR) is not reset to a situation that no error occurred.
An actual exception can be triggered with the macro raise_error. This macro takes an errInfoType parameter to describe the actual exception. Note that all cleaning up must be done before raise_error is called. This macro calls the function raise_exception2 with the additional parameters __FILE__ and __LINE__. The function raise_exception2 has different implementations for interpreted and compiled programs:
- In the interpreter raise_exception2 sets a fail flag and the function is left normally.
- In compiled code raise_exception2 uses a longjmp to continue executing at the handler code of the exception.
That means that raise_error also returns normally in the interpreter. Therefore a function that calls raise_error must return after it has called this function. Surrounding functions must also return. This must be done up to the current action function. So either all these functions always return immediate or a special return value (e.g. NULL) signals them to return. Doing some clean up, when the special return value is received, will not work in compiled code. If cleaning up is necessary the call of raise_error should be done in the outer function.
Function Summary void
raise_error (errInfoType err_info) Macro to raise an exception.
Function Detail raise_error
void raise_error (errInfoType err_info)
Macro to raise an exception. This macro calls the function raise_exception2 with the additional parameters __FILE__ and __LINE__. The function raise_exception2 has different implementations for interpreted and compiled programs.
- Parameters:
- err_info - The exception to be raised.
17. ERRORS
17.1 Parsing errors
Parsing errors are triggered by interpreter and compiler. The checks for these errors are done before the program is executed respectively compiled. The errors do not terminate parsing except for error 1 (Out of heap space). If there are errors the program cannot be interpreted respectively compiled. The interpreter option -x can be used to execute even if the program contains errors. The following parsing errors exist:
17.2 Compilation errors
The compiler does checks when generating code. As a result of the checks some warnings might be written. The warning level can be specified with the option -wn
Level Warning 2 Comparison with %s always evaluates to %s. 2 Expression raises "%s". 1 Catch of "%s" although the checks are suppressed. 1 Catch of otherwise although the checks for %s are suppressed. 1 Duplicate when values %s. 1 Previous usage of %s. 1 When value must be constant. 1 Forward defined function called. 1 Forward definition of the called function. 17.3 Exceptions
An exception is an anomalous event that arises during program execution. Exceptions change the normal flow of program execution. An exception transfers the execution to a corresponding exception handler. If no corresponding exception handler exists the program is terminated. There are various exceptions, which can be raised: MEMORY_ERROR, NUMERIC_ERROR, OVERFLOW_ERROR, INDEX_ERROR, RANGE_ERROR, FILE_ERROR, DATABASE_ERROR, GRAPHIC_ERROR and ILLEGAL_ACTION. A program can raise an exception with the raise statement. For example:
raise RANGE_ERROR;
Additional exceptions can be declared with:
const EXCEPTION: MY_ERROR is enumlit;17.3.1 MEMORY_ERROR
The exception MEMORY_ERROR is raised if there is not enough memory to store some data. This error can be raised from the run-time library or from the interpreter kernel. Catching a MEMORY_ERROR is possible, but it must be done with care. Variables involved in a MEMORY_ERROR may have an illegal value. A MEMORY_ERROR may be raised by various operations of the following types:
- array, struct, hash, file, func, proc, reference, string.
- Additionally the interpreter kernel may raise this exception also.
17.3.2 NUMERIC_ERROR
The exception NUMERIC_ERROR is raised if a numeric operation cannot deliver a correct result. This includes several things that are mathematically undefined such as division by zero, integer exponentiation with a negative exponent, square root of a negative number and logarithm of a negative number. NUMERIC_ERROR can be raised by operations of several types:
- It may be raised from the following integer operations:
- !, **, div, rem, mdiv, mod, sqrt, log2, log10.
- It may be raised from the following bigInteger operations:
- !, **, div, rem, mdiv, mod, sqrt, log2, log10.
- It may be raised from the following rational operation:
- /.
- It may be raised from the following bigRational operation:
- /.
In detail the following conditions can cause a numeric error:
- Division (div, rem, mdiv, mod, /) by zero. E.g.: 1 div 0 raises NUMERIC_ERROR. Note that a float division by zero does not raise NUMERIC_ERROR but returns Infinity or -Infinity instead.
- Exponentiation (**) if the exponent is a negative integer. E.g.: 2 ** (-1) raises NUMERIC_ERROR.
- Functions (sqrt, log2, log10, !) that are only defined for positive arguments. E.g.: sqrt(-1) raises NUMERIC_ERROR.
17.3.3 OVERFLOW_ERROR
An integer overflow occurs if a calculation produces a result that cannot be stored in an integer variable. This happens if the result is less than integer.first or greater than integer.last.
- It may be raised from the following integer operations:
- - (sign), +, -, *, **, div, rem, mdiv, mod, <<, >>, +:=, -:=, *:=, <<:=, >>:=, !, abs, succ, pred, incr, decr.
In detail the following conditions can cause an overflow:
- Negating can overflow because in a two's complement representation there is no corresponding positive value for the most negative integer. E.g.: -integer.first raises OVERFLOW_ERROR.
- Addition, subtraction, multiplication and exponentiation (+, -, *, **, succ, pred) trigger an overflow if the result would be less than integer.first or greater than integer.last.
- Arithmetic operations that change a variable (+:=, -:=, *:=, incr, decr) trigger an overflow if the variable would get a value that is less than integer.first or greater than integer.last.
- Division with div and mdiv can overflow because a division by -1 is the same as negating the dividend. E.g.: integer.first div -1 raises OVERFLOW_ERROR.
- Remainder and modulo are defined to raise OVERFLOW_ERROR if the dividend is the most negative integer and the divisor is -1. E.g.: integer.first rem -1 raises OVERFLOW_ERROR. This has been defined as overflow because it can trigger so called undefined behavior of the underlying C code.
- All shift operations (<<, >>, <<:= and >>:=) trigger an overflow if the shift amount is negative or greater equal 64.
- Left shift operations (<< and <<:=) can also trigger an overflow if the shift result would be less than integer.first or greater than integer.last.
- Binomial coefficient (!) triggers an overflow if the result would be less than integer.first or greater than integer.last.
- Computing the absolute value with abs can overflow, if it is called with the most negative integer. E.g.: abs(integer.first) raises OVERFLOW_ERROR.
The interpreter checks always for an integer overflow. By default the compiler generates code to check for an integer overflow. The option -so can be used to suppress the generation of integer overflow checks. If an overflow situation occurs, although overflow checking has been switched off (with -so), the behavior is undefined (see chapter 17.6 Suppressing exception checks).
The separate overflow exception allows easy recognition of overflow situations. All overflow situations, where OVERFLOW_ERROR is raised correspond to C situations, which have undefined behavior. The overflow concept of Seed7 has been designed to allow, that simple C code is generated, if the overflow checks are switched off.
Compiler optimizations (e.g. with -oc2 or -oc3) can reduce the potential of overflow. In an optimized program an expression might be rephrased, such that an overflow is avoided and the correct result is computed instead. Consider the expression:
number + integer.last + integer.firstIf number is between succ(integer.first) and 0 the expression can be evaluated and no overflow will occur. For other values of number the exception OVERFLOW_ERROR is raised. When the expression above is optimized it is rephrased to:
pred(number)
This expression only triggers OVERFLOW_ERROR, if number has the value integer.first.
With overflow checks it is guaranteed that an integer overflow always raises OVERFLOW_ERROR. But you cannot rely on OVERFLOW_ERROR being raised if there is an alternate way to return the correct result.
17.3.4 INDEX_ERROR
An INDEX_ERROR occurs if an index is used to access an array, string, bstring or ref_list element beyond the elements that actually exist. E.g. An attempt to get an element of a string, bstring or ref_list with a negative or zero index raises INDEX_ERROR.
- It may be raised from the following array operations:
- [index], [index ..], [.. index], [start .. stop], [index len length], insert, remove.
- It may be raised from the following string operations:
- [index], [index ..], [.. index], [start .. stop], [index len length], [index fixLen length], @:= [index] char, @:= [index] string.
- It may be raised from the following bstring operation:
- [index].
- It may be raised from the following hash operations:
- [.
- It may be raised from the following ref_list operations:
- [index], @:= [index] element.
The interpreter checks always if an index refers to an existing element. By default the compiler generates code to check if indices refer to an existing element. The option -si can be used to suppress the generation of index checks. If a nonexistent element is referred, although index checking has been switched off (with -si), the behavior is undefined (see chapter 17.6 Suppressing exception checks).
17.3.5 RANGE_ERROR
Many functions define a range of valid arguments and raise RANGE_ERROR if this range is violated.
- It may be raised from the following boolean operations:
- conv, parse, boolean, succ, pred, boolean, rand.
- It may be raised from the following integer operations:
- parse, radix, RADIX, sci, rand, integer, bytes, bytes2Int.
- It may be raised from the following bigInteger operations:
- parse, radix, RADIX, sci, rand, integer, bytes, bytes2BigInt, ord, bigInteger, bitLength, modInverse, modPow.
- It may be raised from the following rational operations:
- parse, digits, sci, rational.
- It may be raised from the following bigRational operations:
- parse, digits, sci, bigRational.
- It may be raised from the following float operations:
- parse, digits, sci, float, round, trunc, rand.
- It may be raised from the following complex operations:
- parse, digits, sci, complex.
- It may be raised from the following char operations:
- conv, parse, chr, char, rand, char, trimValue.
- It may be raised from the following string operations:
- mult, pos, rpos.
- It may be raised from the following bitset operations:
- conv, parse, rand, min, max, next, integer, bitset.
- It may be raised from the following array operations:
- times, rand.
- It may be raised from the following bin32 operations:
- radix, RADIX, bytes, float2MbfBits.
- It may be raised from the following bin64 operations:
- radix, RADIX, bin64, bytes, float2MbfBits.
- It may be raised from the following category operations:
- parse, category.
- It may be raised from the following ref_list operations:
- pos.
- It may be raised from the following file operations:
- open, openUtf8, openUtf16le, openUtf16be, openUtf16, openInetSocket, write, writeln, gets, length, truncate, seek, tell, skip.
17.3.6 FILE_ERROR
A FILE_ERROR occurs if an illegal operation with a file is done.
- It may be raised by the following functions:
- fileType, fileTypeSL, fileSize, bigFileSize, getFileMode, setFileMode, getATime, setATime, getCTime, getMTime, setMTime, getOwner, setOwner, getGroup, setGroup, readDir, removeFile, removeTree, moveFile, cloneFile, copyFile, readlink, symlink, hasNext, seek, tell, bigTell, setbuf, write, inetSocketAddress, inetListenerAddress, openInetSocket, openInetListener.
17.3.7 DATABASE_ERROR
The exception DATABASE_ERROR may be raised by database functions. If a DATABASE_ERROR is caught it is possible to get some information about the cause of the error with:
const func string: errMessage (DATABASE_ERROR)There are messages coming from the database and from the Seed7 database driver. The database driver may have a message like:
Searching for dynamic libraries failed: libclntsh.soThis indicates that the connector library could not be found. In this case the environment variable LD_LIBRARY_PATH could be used to specify the place of the connector library.
17.3.8 GRAPHIC_ERROR
The exception GRAPHIC_ERROR may be raised by graphic drivers. If an underlying graphic library function reports an error a GRAPHIC_ERROR is raised.
17.3.9 ILLEGAL_ACTION
The exception ILLEGAL_ACTION may be raised by the interpreter kernel, if a primitive action does not point to any legal action. This check is only done if the s7 interpreter is compiled with '#define WITH_ACTION_CHECK'. The ILLEGAL_ACTION exception is also raised if the primitive action ACT_ILLEGAL is executed.
17.4 Handlers
To catch an EXCEPTION the following handler construct can be used:
block number := 1 div 0; exception catch NUMERIC_ERROR: number := 1; end block;It is also possible to catch several exceptions:
block doSomething(someValue); exception catch MEMORY_ERROR: writeln("MEMORY_ERROR"); catch NUMERIC_ERROR: writeln("NUMERIC_ERROR"); end block;An otherwise handler catches exceptions, that are not caught by the other handlers:
block doSomething(someValue); exception catch RANGE_ERROR: writeln("RANGE_ERROR"); otherwise: writeln("Any other exception"); end block;17.5 Trace exceptions
The interpreter option -te can be used to trace exceptions and handlers. If an exception occurs the following is written:
*** Exception NUMERIC_ERROR raised at integer.s7i(118) {160000 div fuel_max } at lander.sd7(836) *** Action "INT_DIV" *** The following commands are possible: RETURN Continue * Terminate # Terminate with stack trace / Trigger SIGFPE !n Raise exception with number (e.g.: !1 raises MEMORY_ERROR)In detail:
- After pressing RETURN the program continues without any change.
- Pressing * and RETURN terminates the program immediately.
- Pressing # and RETURN writes a stack trace and terminates the program. E.g.:
*** Program terminated after exception NUMERIC_ERROR raised with {integer:*NULL_ENTITY_OBJECT* div fuel_max } Stack: in (val integer: dividend) div (val integer: divisor) at integer.s7i(118) in init_display at lander.sd7(836) in setup at lander.sd7(906) in main at lander.sd7(1536) - Pressing / and RETURN triggers the signal SIGFPE. If the interpreter has been started from a debugger, this triggers the debugger.
17.6 Stack trace
If an exception is not caught the program is terminated and the s7 interpreter writes a stack trace:
*** Uncaught exception NUMERIC_ERROR raised with {integer: <SYMBOLOBJECT> *NULL_ENTITY_OBJECT* div fuel_max } Stack: in (val integer: dividend) div (val integer: divisor) at integer.s7i(118) in init_display at lander.sd7(836) in setup at lander.sd7(906) in main at lander.sd7(1536)The stack trace shows that a NUMERIC_ERROR was raised by the div operation. This operation is defined in line 118 of integer.s7i. More interesting is that div was called from the function 'init_display' in line 836 of lander.sd7. A NUMERIC_ERROR with div is probably caused by a zero division. A short examination in lander.sd7 shows that an assignment to 'fuel_max' was commented out to show how stack traces work.
A compiled program creates a much shorter crash message:
*** Uncaught exception NUMERIC_ERROR raised at sigutl.c(218)To get more information there are two possibilities:
- Start the program in the interpreter instead.
- Compile the program with the options -g -e and start it from a debugger.
If s7c is called with the option -g it instructs the C compiler to generate debugging information. This way a debugger like gdb can run the program and provide information. The option -e tells the compiler to generate code which sends a signal, if an uncaught exception occurs. This option allows debuggers to handle uncaught Seed7 exceptions. Note that -e sends the signal SIGFPE. This is done even if the exception is not related to floating point operations.
./s7 s7c -g -e lander gdb ./landerThen the debugger should be able to run the program and to write a backtrace if a crash occurs:
(gdb) run Starting program: /home/tm/seed7_5/prg/lander Program received signal SIGFPE, Arithmetic exception. 0x000000000041b942 in o_3912_init_display () at lander.sd7:839 839 fuel_gauge := 40 * rocket.fuel div fuel_max; (gdb) bt #0 0x000000000041b942 in o_3912_init_display () at lander.sd7:839 #1 0x000000000041c2e5 in o_3917_setup () at lander.sd7:908 #2 0x0000000000421fe1 in main (argc=1, argv=0x7fffffffdf28) at lander.sd7:1541Sometimes it is helpful to debug the generated C program instead of the Seed7 source. The option -g-debug_c creates debug information, which refers to the C program generated by the Seed7 compiler:
./s7 s7c -g-debug_c -e lander gdb ./landerNow the debugger refers to the temporary file tmp_lander.c:
(gdb) run Starting program: /home/tm/seed7_5/prg/lander Program received signal SIGFPE, Arithmetic exception. 0x08068518 in o_2541_init_display () at tmp_lander.c:19727 19727 o_2428_fuel_gauge=((40) * (((structType)(o_2338_rocket))->stru[10].value.intValue/*->o_2336_fuel*/)) / (o_2431_fuel_max); (gdb) bt #0 0x08068518 in o_2541_init_display () at tmp_lander.c:19727 #1 0x08068c21 in o_2546_setup () at tmp_lander.c:19864 #2 0x0806c304 in main (argc=1, argv=0xbffff324) at tmp_lander.c:21188Some Seed7 exceptions do not send signals. This hinders the debugger to recognize that an uncaught exception occurred. The compiler option -e can help in this situation. It instructs the compiler to generate code which sends a signal if an uncaught exception occurs. This allows the debugger to show a backtrace for uncaught Seed7 exceptions.
17.7 Suppressing exception checks
A Seed7 program can be compiled with the option -sx, to suppress the generation of checks for exceptions. The suppressed checks x are specified with letters from the following list:
- d Suppress the generation of checks for integer division by zero.
- i Suppress the generation of index checks (e.g. string, array).
- o Suppress the generation of integer overflow checks.
- r Suppress the generation of range checks.
If an exception situation occurs, although exception checking has been switched off (with -s), the behavior is undefined. In this case the following things can happen:
- The exception is still raised.
- A different exception is raised.
- The program hangs.
- The program crashes.
- The computation continues with some garbage value. This garbage value can then trigger dangerous things: The X-ray dose computed by your program might be totally wrong. Your program might compute the statics of a bridge wrong.
Undefined behavior is a term used in the language specification of C and in other programming languages. Undefined behavior usually means that the behavior of the program is unpredictable. Normally Seed7 has a well defined behavior in all situations. Even in situations where the language specification of C refers to undefined behavior.
A handler for an exception can only work reliable if the checks for the exception are done. The compiler warns if -s is used and there is a handler for an exception. e.g.:
*** example.sd7(123): Catch of OVERFLOW_ERROR although the checks are suppressed.
Only a program that never raises the specific exception and that does not have a handler for this exception can be considered to be compiled without checks for that exception. Careful program analysis and testing (the exception should never be raised) is necessary to decide about the omission of exception checking.
17.8 Signals
A signal is an asynchronous notification of an event. The event can come from outside such as a request to terminate the program. The event can also come from the program itself such as a memory access violation (segfault). Several signals are handled by the Seed7 run-time library. The interpreter respectively compiler option -ts can be used to influence the behavior, if a signal is sent to a Seed7 program (see below). The following signals are handled by Seed7:
Signal Special handler Behavior without -ts Behavior with -ts SIGABRT raise OVERFLOW_ERROR Raises exception Dialog to decide SIGILL raise OVERFLOW_ERROR Raises exception Dialog to decide SIGTRAP raise OVERFLOW_ERROR Raises exception Dialog to decide SIGINT - Terminate with message Dialog to decide SIGFPE raise NUMERIC_ERROR Raises exception Dialog to decide SIGTERM - Terminate with message Terminate with message SIGSEGV - Terminate program Terminate with message SIGPIPE - Ignored Ignored SIGWINCH Resize console - - SIGALRM Wait for some time - - Depending on the actual C compiler and operating system the signals SIGABRT, SIGILL or SIGTRAP might be used to raise OVERFLOW_ERROR and the signal SIGFPE might be used to raise NUMERIC_ERROR.
If the interpreter respectively compiler option -ts has been used some signals (see table above) trigger a dialog at the console. E.g.:
*** SIGNAL SIGINT RAISED *** The following commands are possible: RETURN Continue * Terminate / Trigger SIGFPE !n Raise exception with number (e.g.: !1 raises MEMORY_ERROR)The user can enter a command and activate it with RETURN. If the program was waiting for an input at the console the input can be entered again:
re-enter input>Triggering SIGFPE is useful if the program runs in a debugger. In this case SIGFPE will activate the debugger prompt. Raising an exception (e.g.: MEMORY_ERROR) can be used to get a stack trace (this works only in the interpreter). A compiled program must be executed with a debugger to get a stack trace.
17.9 Other errors and warnings
- No more memory. Parsing terminated.
- This error message is displayed after the parsing error 1 (Out of heap space). The file name and line number of the analyzer source code where this happens is displayed together with internal heap information.
- System declaration for main missing
- Each program must contain a system declaration that describes which procedure to start as first one.
- Exception %s raised with
- If your trace level specifies exception tracing exceptions and handlers are displayed with this messages and the user must type the ENTER-key to accept.
- Action $%s requires %s not %s
- This error can happen if an action tries to do something with the wrong primitive value. For example adding an integer to a string with INT_ADD. Since the analyze phase checks for the right types this error can only happen if the basic libraries are defined wrong.
- Action $%s with empty value
- This error can happen if an action tries to do something with NULL and NULL is not allowed as value. If parsing works correct this should never happen.
- Action $%s requires variable %s not constant
- This error can happen with actions which assign a value to a constant. Since the analyze phase checks for variable objects this error can only happen if the basic libraries are defined wrong. Principally this error is possible with the following operations: :=, incr, decr, wrd_rd, lin_rd