Conference: 9–10 September 2022 • Deadline for submission: 30 May 2022.
GNTCFL is a language with LISP-like syntax developed especially for GNTicker. Despite its resemblance to LISP, it is not a fully declarative programming language since it contains certain procedural elements.
A GNTCFL program is a set of function definitions that can be used as characteristic functions and predicates as well as user defined utility functions.
LISP-styled, the syntax of GNTCFL programs is very simple. It follows the BNF:
<program> ::= <function definition>... <function definition> ::= (defun <unique name> <frame definition> ([<formal arguments>]) ([<local variables>]) <expression>...) <frame definition> ::= "<number of references>;<reference>;..." <formal arguments> ::= <unique name>... <local variables> ::= <unique name>... <expression> ::= (<supercombinator> [<argument>...]) <supercombinator> ::= <primitive> | <special form> | <user-defined function> <special form> ::= if | for | and | or | let <argument> ::= <formal argument> | <local variable> | <constant> | <frame index> | <expression> <frame index> ::= #<number>
Frame definitions, special forms, primitives and user-defined functions are described in details in the following sections.
As mentioned above, a GNTCFL program consists entirely of function definitions. As in functional languages there is a general rule for expression evaluating, which applies to all combinations except special forms. The semantics of special forms are specific for each of them and are described separately.
be an expression, where the supercombinator is not a special form. Evaluating the expression involves subsequent evaluation of the arguments, prior to the application of the supercombinator over their values. In terms of the functional programming the expression evaluations follow the so called applicative model. The following example includes only primitives and constants and demonstrates the process
(* 2 3 (- 11 (+ 1 1) (/10 5))) -> (* 2 3 (- 11 2 (/10 5))) -> (* 2 3 (- 11 2 2)) -> (* 2 3 7) -> 42
The if special form
The if special form is an exception from the evaluation rule.
<if-expression> ::= (if <condition> <then> [<else>]) <condition> ::= <expression> <then> ::= <expression> <else> ::= <expression>
After the conditional expression has been evaluated, the process continues with evaluating only one of <then> and <else> expressions, according to the condition value. Thus the following expression is evaluated to 42 instead of raising a "division by zero" error:
(if (* 1 1) (* 7 6) (/ 8 0))
The for special form
<for-expression> ::= (for <local-variable> <start-value> <end-value> <step> <expression>)
The <local-variable> is assigned values starting from <start-value>, increased or decreased by <step> to reach <end-value>. On every assignment, <expression> is evaluated. The result is the last evaluation of <expression>. The <local-variable> must be declared in the defun construction (see GNTCFL syntax).
The while special form
<while-expression> ::= (while <condition> <expression>)
Evaluation of the while special form involves consequent evaluation of <condition> and <expression>. If <condition> evaluates to a zero value, the process of evaluation is completed and the result is the last value of <expression>.
The let special form
<let-expression> ::= (let <local-variable> <expression>)
The let special form is an assignment construction. First <expression> is evaluated and then its value is assigned to the <local-variable>. In all expressions in the same function, following the let construction, <local-variable> is evaluated to its assigned value. Consequent assignment of different values to the same local variable is possible. In that case the latest assignment is valid.
As shown in the previous sections, a function definition includes its frame definition, formal arguments and local variables.
Whenever a function needs to access some property of a GN component such as (and mainly) the characteristic of a named token, it needs to declare a reference in the so called function frame. The frame is a list of all needed GN properties. Frames describe an environment of network components for the functions. The BNF of the frame definitions is:
<frame definition> ::= "<number of references>;<reference>;..." <reference> ::= tokens.<unique name>. obj | tokens.<unique name>. char | places.<unique name>. obj | file.<file name>.<file extension>
where only reference definitions for the recently implemented reference types are given.
For example let us suppose that some function needs the characteristic of a token named "MyToken" and a reference to a place named "MyPlace". The frame definition will look like
With this frame the network components properties will be referable in the function body as #0 and #1, respectively.
Declaring an user-defined function
As shown above, a user-defined function definition follows the BNF:
<function definition> ::= (defun <unique name> <frame definition> ([<formal arguments>]) ([<local variables>]) <expression>...)
Having described of all the major components, let us go straight to the example:
(defun factorial "" (x) () (if (= x 0) 1 (* x (factorial (- x 1))))
Here x is a local variable and the semantics of the expression has already been discussed.
Let us now define a function that gets the square of the default characteristic of some token named "MyToken" and afterward adds 5 to it if there is at least one token in place "MyPlace".
(defun square "" (x) () (* x x)) (defun myfunction "2;tokens.MyToken.char;places.MyPlace.obj" () (sq) ;assign the square of the ;characteristic to the local variable ;sq (let sq (square #0)) ;return sq or sq + 5 (if (exists #1) (+ sq 5) sq))
In this example sq is a local variable and the special form let is used to assign some value to it so that it can be used afterward in all following expressions. The value of the last expression of the function body forms the functions value.
Characteristic functions and predicates
The characteristic function is applied to each token entering the place. Characteristic functions are user-defined functions, which use primitive like set, set-nth, setnamed, split to set the new value of the characteristic of the token to which the function is applied. The functions are referred by their names in the char and mergeRule attributes of the <place> tag.
Predicates are user-defined functions, which return a numeric value. Zero is considered false and any other value - true. Names of predicates are listed in the <predicates> tag, when describing the predicate matrix of a transition. A predicate is evaluated whenever a token tries to pass through the transition from an input place to an output place.
Some reserved words are defined only for the characteristic functions and predicates. The reserved word time is evaluated as an integer, showing the current step of the GN. The reserved word token can be used only in characteristic functions, and is evaluated as the value of the last value of the "Default" named characteristic of the token having entered the place.
The reserved word tokenobj is also defined only for characteristic functions and is valuated to a reference to the token the function is applied to.
Finally, here is an example of GNTCFL definitions for test.xml.
(defun inc "" () () (set (+ token 1))) (defun less_than_10 "1;tokens.T1.char" () () (< #0 10))
The primitives are built-in functions providing standard operations (arithmetical, input/output, etc). For a complete list of implemented primitives see the list below.
List of GNTCFL primitives
|set||one argument||Only for characteristic functions. When a token t enters the respective place, the set primitive sets the values of its default characteristic|
|set-nth||one argument||See set. set-nth sets the n-th coordinate of a vector characteristics|
|get-named||<token reference> <string name>||Retrieves the value of a named characteristic for a given token|
|set-named||<token reference> <string name> value||Sets the values of a named characteristic for a given token|
|del-named||<token reference> <string name>||Removes a named characteristic for the given token|
|+, *, -, /||numeric arguments||Performs arithmetic operations over its arguments.|
|and||Boolean (numeric arguments)||Logical AND over numeric arguments. 0 (zero) is considered false, everything else – true. and is a special form, not a primitive. Its arguments are being evaluated until some of them is found false – then the whole expression is false.|
|or||logical or||A special form like and.|
|not||Boolean arguments||Logical not.|
|remainder||two numeric arguments: a and b||Evaluates to remainder of the integer division of a to b|
|round, sqr, sqrt, atan||one numeric argument|
|=, !=, >, <, <=, >=||numeric or vector arguments|
|get-nth||<numeric> <vector>||Evaluates to the n-th vector component of the vector argument.|
|exists||<place reference frame index>||Evaluates to true if in the previous step there had been a token in the referred place or if a token is moved to this place during the current step (by some previous operation prior to the current function execution).|
|isthere||<place reference frame index>||Evaluates to true if in the previous step there had been at least one token in the referred place and it hasn't been moved during this step by an operation prior to this function execution.|
|wasthere||<place reference index>||Evaluates to true if there had been a token in this place in the previous step.|
|split||<token> <new name> <place> <name1> <value1> …||When this primitive is called by a characteristic function of a place, a new "blank" token appears in that place. Then to the token are set a number of named characteristics, corresponding to the arguments namei and valuei.|
|all kinds of arguments||Prints to the standard output.|
|Newline||no arguments||Prints a newline to the standard output.|
|timedelta||no arguments||Time in milliseconds since the last call of timedelta.|
|lifetime||no arguments||Time in milliseconds since the beginning of the first step.|
|fread||<file reference frame index>||Reads a word from the referred file. Evaluates to numeric or string according to the word type.|
|openwindow||<numeric id> <string title> <numeric dimensions> <numeric steps> [<min x> <max x>]||Creates and opens a window with the given title and associates an id with it. This id can be used to visualize function graphs by "sending" points to the window. If <min X> and <max X> are not specified, the window metrics is rescaled each time some point is visualized.|
|senddata||<numeric id> <vector>||Draws lines from the previously "sent" point to the points of this vector, i.e. visualizes the new points.|