MATRIX
SCRIPT LANGUAGE
OVERVIEW
A MATRIX-script includes any logical aspects for the execution
of a control task by the MATRIX. The MATRIX is a STATE-MACHINE.
I.e., depending on the status of the system (the MATRIX) the reactions
of the system can change on appointed occurrences - as per particulars
given below. For the time being we attend to the elementary structures
of a MATRIX script.
SCRIPT STRUCTURE
A MATRIX script operates like many program languages: It consists
out of a initiation part, a declaration part, functions and a
main function.
There are iterations, variables and levels, so called STATES.
Anybody who ever programmed or scripted in any language will easily
find his way. Many things retrieve and some things even in a C-like
syntax.
KERNEL, DEVICES AND PLUGINS
A DEVICE announces the arriving of data to the kernel. The kernel
searches the SCRIPT for an EVENT which can accept that data and
processes it concerning the actions defined in the SCRIPT for
this EVENT.
So, an EVENT within the script is similar to an event handler
and the appearance of an event is not dissimilar to the appearance
of an exception of an interrupt.
The range of functions of a MATRIX script depends on the integrated
DEVICES and PLUG-INs. A DEVICE or PLUG-IN represents, as software,
the functionality of a specific hard- or software ( for example
a DVD-Player, the belonging DEVICE provides functions like; "Play",
"Go to Track" etc.)
The same can be valid for software, e.g. a speech recognition:
The speech recognition tries to identify incoming sounds from
the soundcard as spoken words. Finally the result is a word recognized,
or not. This functionality now can be replicated by a DEVICE.
The DEVICE takes on the task to send the recognized word to the
MATRIX ,or, in the case of not recognizing, to send a failure
code.
The difference in principal between a DEVICE and a PLUG-IN is
the way of communication with the kernel.
A DEVICE communicates via sockets with the kernel - but a PLUG-IN
is linked to the runtime as DSO. There is no loss of time caused
by the socket communication, but therefore a PLUG-IN always has
to run on the same computer the kernel is executed on. Only DEVICES
are able to work with the kernel distributed in the net.
The PLUG-IN named "matrix" is already ingrained in the kernel,
hence it must not be loaded. matrix provides some functions of
the kernel that are reserved just for it. The most important event
is: matix:main() . As the first of all EVENTS, it will be called
only a single time immediately after the start. The perfect place
for initializations and suchlike.
Before using a DEVICE (and its functions) or a PLUG-In, it is
necessary to tell the kernel which DEVICEs or PLUG_INs shall be
applied.
use a device
For making
it possible to work with a device within the script, the device
has to be declared at the beginning of the script. In the following
example the DEVICE "console" shall be declared. This DEVICE is
a very simple one and is able to handle the tasks of keyboard
inputs and screen outputs; in a way the "standard out" of the
MATRIX.
That is the
way it happens:
use con
= console@localhost("inout");
use |
is
a directive for the MATRIX, a keyword for the declaration
of devices! |
con |
is
an ALIAS for the DEVICE "console" ("con" is used in the script
every time the console is triggered). |
= |
is
the assignment. Therewith "con" will be understood as ALIAS
for the following DEVICE. |
console@localhost |
is
the designation of the DEVICE which enables the KERNEL to
find the DEVICE.
Here, @ describes the separation between the designator of
the DEVICE and the designation of the computer, the DEVICE
runs on (see network).
"localhost" stands for the fact that the DEVICE and
the kernel of the MATRIX are located on the same computer.
At the same place could stand a host name ("examle.aec.at")
or an IP-address (for example 192.168.1.10). The only requirement
by the KERNELs is, that the mentioned DEVICE runs from the
beginning on the specified computer and that the computer
is accessible via TCP/IP. |
"localhost" |
stands
for the fact that the DEVICE and the kernel of the MATRIX
are located on the same computer. At the same place could
stand a host name ("examle.aec.at")
or an IP-address (for example 192.168.1.10). The only requirement
by the KERNELs is, that the mentioned DEVICE runs from the
beginning on the specified computer and that the computer
is accessible via TCP/IP.
|
The bracketed
STRING (= "inout")
can be used by the DEVICE as an initialization parameter.
Important:
The semicolon at the end of the line! ; In general the symbol
for the end of a line in the script language!
use
tts = tts@localhost("");
use gram = gramma@voice.aec.at("");
use cave = cave@192.168.23.57("inout");
Include
a Plug-In
Right
after the use-assignment, still in the initialization part
of the script, the includes get defined. Until now, "calc"
is the most important PLUG-IN. So, we take it as example for
the integration of a PLUG-IN in the script:
include
c = calc("");
include |
The
keyword for the MATRIX. This way the kernel recons that
a PLUG-IN has to be integrated at this position. |
C |
The
ALIAS that is assigned to the PLUG-IN within this script. |
= |
The
assignment of the PLUG-IN for the ALIAS. |
calc("");
calc
is the PLUG-IN, the string within the brackets serves the
purpose of compatibility with other PLUG-INs. That string
(in this case an empty character string) can be used for initializing
the PLUG-IN.But
calc does not know any initialization.
For the
scope of service of "calc" see Utility (calc) Plugin
variables
types:
int |
Integer |
float |
floating-point |
string |
a
sequence of CHARs (character string) |
void |
for
the declaration of a function that returns nothing |
|
int
i;
float fl_var:
string myString = "My Name in my string!";
int y = 0;
functions
The keyword for the declaration of functions used in the script is:
functions
A function gets declared as following:
type name( [type variablenname [, type variablenname [, ...]]] )
[type local_variable_name;
[type local_variable_name;
[...]]]
{
(ACTIONS, code, function calls, etc)
[return value;]
}
Whereat value has
to be specified in the declaration head as a type.
EXAMPLE 2
void do_some_inits( int init_number )
int i;
{
for (i = 0; i <= max; i = c:iadd(i,1) ) {
test_array[i] = init_number;
}
}
int do_some_inits( int init_number )
int i;
{
i = init_number;
return i;
}
Example 3 is
basically senseless, but should explain the possibility of returning
a value out of a function. Events An event starts with the assignment
"->"
in the first character string of a line. Followed by the ALIAS of
the device, than a colon (":") and
the chosen function of the DEVICE. |
[state1 [| state2 [ ...]]]-> Device_ALIAS:function_name( parameter_1 [, parameter_N])
{
(ACTIONS, code, function calls, etc)
}
the device-alias
has already been declared by "use".
The actual function of the DEVICE depends on the actual DEVICE.
Following:
An example for an EVENT for the DEVICE "console"
ALIAS "con":
|
EXAMPLE 4
->con:read('A')
{
con:writeln("the KEY 'A' has been pressed");
}
include c = calc("");
string st;
string key;
->con:read(^key)
{
st = "the KEY '";
st = c:sadd(st, key);
st = c:sadd(st, "'has been pressed");
con:writeln(st);
}
EXAMPLE 6
1 #!../matrix
2 use con = console@localhost("");
3 include c = calc("");
4
5 # every line starting with an hash (#) at the first
6 # column will be ignored by the kernel. It is ment to
7 # be a REMARK or Comment-Line.
8
9 # here we declare global variables
10 int max = 5;
11 int test_array[5];
12
13 functions
14 # the word "functions" opens the functiondeclaration
15 # space in the script!
16
17 void do_some_inits( int init_number )
18 # "do_some_inits" is a function declaration.
19 # Note, this function does not return any value!
20 # it just changes the content of the globalstructrure
21 # "test_array"
22 int i;
23 # functions do support local variables!
24 {
25 for (i = 0; i <= max; i = c:iadd(i,1) ) {
26 test_array[i] = init_number;
27 }
28 }
29
30 ->con:read('i')
31 # everything starting with an "->" at the first column is
32 # ment to be an EVENT! An EVENT can be triggered by any
33 # DEVICE
34 {
35 do_some_inits( 1 );
36 con:writeln("manual init done");
37 }
38
39 -> matrix:main()
40 # this is the only EVENT which is understood by the
41 # kernel itself the keyword "matrix" does not have to be
42 # declared (in a use command at the beginning of the
43 # script) since matrix refers to the kernel itself.
44 # matrix:main is the main-program if you like. One can
45 # use it but it is not obligatory.
46 {
47 do_some_inits( 0 );
48 con:writeln(" first init done");
49 }
The DEMO-script
explains:
In front of every line stands a line number. They are not part
of the script, but should make it easier to refer the following
comments to the right line!
Line 1
can be dropped. This line makes the isolated script executable,
so it does not have to be activated in the command line after
the syntax: ./matrix scriptname It is sufficient to execute only
the script ./scriptname
Line 2
use-commando The DEVICE console gets included and assigned to
the ALIAS con.
Line 3
include The PLUG-IN calc gets linked to the running time and assigned
to the ALIAS c
Line 5
to 7
Nothing but comments. Every line that starts with the character
hash (#), will be ignored as comment line.
Line 10
to 11
Declaration of the scripts global variables!
Line 13:
Keyword for beginning declarations of functions!
Line 17
to 28:
Function do_some_inits gets declared. Do_some_inits occupies every
cell of the global structure "test_array" with the value transferred
to the function (init_number vom typ int).
Line 30
to 37:
The EVENT con:read(´i´) gets declared and an ACTION gets fixed.
I.e., that every time "i" gets pressed at the console computer
(here: localhost), the fixed ACTION will be executed. That is
in general the call for the function do_some_inits and the transfer
of the value 1 to this function. After that follows the output
to the device CONSOLE (con:writeln) "Manual init done".
Line 39
to 49:
At this point the EVENT matrix:main gets declared and an AKTION
gets fixed. If the EVENT happens (that happens only a single time
immediately after the start!), the function do_some_inits will
be activated and the value 0 will be transferred. After that the
text: " first init done" will be transferred to con:writeln.
STATES
As already
mentioned below, the MATRIX can also be used as a STATE-MACHINE.
For the explanation of a STATE-MACHINEs concept we choose a rather
abstract example; "The Four Seasons". The Four Seasons Supposed
the task is to develop an installation about the topic; the four
seasons. In this case we ignore the artistic quality of the argumentation
and determine the following facts in order to understand the functions
of STATES:
1. We have
an installation the user interacts with by speech.
2. The user has influence on the weather. The MATRIX understands
"warmer", "colder" and "precipitation".
3. For the output we have something like a spotlight - light /
or a speaker - sound.
4. The seasons ought to be selectable via keyboard, so 1 = winter,
2 = spring etc. …
ENTER
Warmth, cold & precipitation (VOICE) Seasons (Keyboard)
ERGO
Spring, summer, fall and winter And there is the possibility of
precipitation - like rain, thunder-storm, snow…
Ideal would
be a system, that puts itself automatically into several STATES
in order to be able to reflect the status of the seasons, if the
task was to produce the considering precipitation.
The thing declared as season, can be understood as STATE and be
implemented! The MATRIX "knows" which season is on and changes
"rain" into "snow". The appended SCRIPT could look like the following:
|
EXAMPLE 7
WINTER->voice:read(^cmd) {
if ( cmd == 1) precipitation ( snow );
if ( cmd == 2) temperature_up( frost_max );
if ( cmd == 3) temperature_down( frost_min );
}
SPRING->voice:read(^cmd) {
if ( cmd == 1) precipitation ( rain );
if ( cmd == 2) temperature_up( cool_max );
if ( cmd == 3) temperature_down( cool_min );
}
SUMMER->voice:read(^cmd) {
if ( cmd == 1) precipitation ( thunder );
if ( cmd == 2) temperature_up( warm_max );
if ( cmd == 3) temperature_down( warm_min );
}
AUTUMN->voice:read(^cmd) {
if ( cmd == 1) precipitation ( rainstorm );
if ( cmd == 2) temperature_up( cool_max );
if ( cmd == 3) temperature_down( cool_min );
}
->con:read('1') {
state(WINTER);
}
->con:read('2') {
state(SPRING);
}
->con:read('3') {
state(SUMMER);
}
->con:read('4') {
state(AUTUM);
}
This SCRIPT
contains four times the same EVENT voice:read. This EVENT always
takes every command from the DEVICE voice (in this case the ALIAS
for a speech recognition DEVICE).
Cmd = 1 signifies,
that the word "precipitation" has been recognized.
Cmd
= 2 signifies, that "warmer" has been recognized.
Cmd
= 3 signifies, that "colder" has been recognized.
All the four
EVENTS deal with any case of appearance of a CALL. Only the STATE
noted in front of the "->"
makes sure, that only one EVENT (the one with the valid STATE)
will be executed at the same time.
The EVENTS con:read()
get executed only if the correlating figure gets pressed. The
assignment of these EVENTS consist of the task to change the valid
STATE to the STATE referring to the figure. Because of there is
nothing standing in front of the "->"
of these EVENTS, i.e. they are not referring to a STATE, they
keep on being valid no matter what STATE is actual at this time.
In a way the con:read-EVENTS stay valid all over the year.
Going one step further, we could say that, for instance, in spring
or fall should happen something that does not happen in winter
or summer (for example an existing spotlight should shine only
half as light as in the other seasons) and add the following supplement:
|
SPRING | AUTUM -> voice:read(^cmd) {
if (cmd == 1) light:out(5);
}
WINTER | SUMMER -> voice:read(^cmd) {
if (cmd == 1) light:out(10);
}
When
ever the STATE "AUTUM" or SPRING" is valid, and somebody asks
for precipitation, the light will be set on level 5. In summer
and winter on level 10.
I.e., an EVENT can stay active all the time (without STATE), or
only at a specified point of time (with a STATE) or even during
several STATES - by connecting all the STATES with a PIPE-symbol
(logical-or).
These
STATES do not only make the SCRIPT more legible. Above all, the
very complex structures of a inside networked system can be recreated
without establishing a vast number of variables and requests (speed).
But above all, the applications actions in the particular STATES
stay completely independent and lead to a safe total behavior
of the installation. No matter from what STATE I want to switch
to another, the other STATES will not be derogated.
NOTE:
This is not valid for variables, used and changed in more than
one STATE!
The
Grammar of E
The description
of the grammar of "E" is following in Backus-Naur Form
(BNF), notation of Unix-Tools "Bison". Words in lowercase
letters are nonterminal symbols and words in uppercase letters
are terminal symbols. The terminal symbols are returned from the
lexer presented below. Note, the syntax may change in further
releases of the matrix.
|
script :
| load_part def_part event_blocks
;
load_part : load_lines lib_lines
;
load_lines :
| load_lines load_line
;
load_line : LOAD BEZEICHNER EQUAL BEZEICHNER AT_HOST
LEFT_ROUND STRING_C RIGHT_ROUND SEMICOLON
;
lib_lines :
| lib_lines lib_line
;
lib_line : INCLUDE BEZEICHNER EQUAL BEZEICHNER
LEFT_ROUND STRING_C
RIGHT_ROUND SEMICOLON
;
def_part : var_def_lines {g_symtbl = $1} func_def
;
var_def_lines :
| var_def_lines var_def_line
;
var_def_line : variable_init SEMICOLON
| symbol_def SEMICOLON
;
variable_init : symbol_def EQUAL constante
;
func_def :
| FUNCTION func_definition
;
func_definition :
| function_def func_definition
;
function_def : function_head action_block
;
function_head : symbol_def function_para var_def_lines
;
function_para : LEFT_ROUND parameters_def
RIGHT_ROUND
;
parameters_def : symbol_def
| symbol_def COLON parameters_def
;
symbol_def : INT_T variable_def
| FLOAT_T variable_def
| STRING_T variable_def
;
variable_def : BEZEICHNER
| BEZEICHNER index
;
constante : INT_C
| FLOAT_C
| STRING_C
| CHAR_C
;
event_blocks : event_block
| event_block event_blocks
;
event_block : event action_line
;
event : state EVENT BEZEICHNER evnt_para_block
| state EVENT BEZEICHNER
DOUBLEPOINT BEZEICHNER evnt_para_block
;
state :
| BEZEICHNER
| state OR BEZEICHNER
;
evnt_para_block : LEFT_ROUND evnt_paras
RIGHT_ROUND
;
evnt_paras :
| evnt_para
| evnt_para COLON evnt_paras
;
evnt_para : expression
| GET variable
;
action_block : LEFT_GESCH action_lines
RIGHT_GESCH
;
action_lines : action_line
| action_line action_lines
;
action_line : statement_line
| expression_line
| action_block
;
statement_line : statement
;
expression_line : expression SEMICOLON
;
statement : if_statement
| for_statement
| while_statement
| ret_statement
| break_statement
| event_block
| state_statement
;
expression : action
| queue_statement
| function
| compair
| zuweisung
| constante
| variable
| exit
;
compair : expression EQUIV expression
;
action : BEZEICHNER DOUBLEPOINT
BEZEICHNER para_block
;
para_block : LEFT_ROUND paras RIGHT_ROUND
;
paras :
| expression
| expression COLON paras
;
if_statement : IF LEFT_ROUND expression
RIGHT_ROUND action_line %prec ELSE
| IF LEFT_ROUND expression
RIGHT_ROUND action_line ELSE action_line
;
for_statement : FOR for_para action_line
;
ret_statement : RETURN SEMICOLON
| RETURN expression SEMICOLON
;
break_statement : BREAK SEMICOLON
;
queue_statement : QUEUE_REL LEFT_ROUND expression
RIGHT_ROUND action_line
| QUEUE_ABS LEFT_ROUND expression
RIGHT_ROUND action_line
| QUEUE_REL_P LEFT_ROUND expression
RIGHT_ROUND action_line
| DEQUEUE LEFT_ROUND expression
RIGHT_ROUND
;
for_para : LEFT_ROUND expression SEMICOLON expression
SEMICOLON expression RIGHT_ROUND
;
while_statement : WHILE LEFT_ROUND expression
RIGHT_ROUND action_line
;
state_statement : STATESWITCH LEFT_ROUND BEZEICHNER
RIGHT_ROUND SEMICOLON
| STATEPOP SEMICOLON
| STATEPUSH LEFT_ROUND BEZEICHNER
RIGHT_ROUND SEMICOLON
;
zuweisung : variable EQUAL expression
;
function : BEZEICHNER para_block
;
exit : EXIT LEFT_ROUND expression RIGHT_ROUND
{
new_stmt = new_symb();
new_stmt->whatami = IAM_EXIT;
new_stmt->para = $3;
$$ = new_stmt;
}
;
variable : BEZEICHNER
| BEZEICHNER index
;
index : LEFT_ECKIG expression RIGHT_ECKIG
The Lexical analysator
of E
if return (IF);
else return (ELSE);
while return (WHILE);
for return (FOR);
int return (INT_T);
float return (FLOAT_T);
string return (STRING_T);
return return (RETURN);
break return (BREAK);
functions return (FUNCTION);
"->" return (EVENT);
use return (LOAD);
ALIAS return (ALIAS);
WITH return (WITH);
LIB return (LIB);
include return (INCLUDE);
state return (STATESWITCH);
statepop return (STATEPOP);
statepush return (STATEPUSH);
exit return (EXIT);
queue_rel return (QUEUE_REL);
queue_rel_p return(QUEUE_REL_P);
dequeue return (DEQUEUE);
queue_abs return (QUEUE_ABS);
@[a-zA-Z0-9_\-]*(\.[a-zA-Z0-9_\-]*)* return (AT_HOST);
[a-zA-Z_][a-zA-Z0-9_]* return (BEZEICHNER);
[+-]?[0-9]* return (INT_C);
[+-]?[0-9]*(\.[0-9]*)?([EeDd][+-]?[0-9]+)? return (FLOAT_C);
\"[^"]*\" return (STRING_C);
\'[^']*\' return (CHAR_C);
";" return (SEMICOLON);
":" return (DOUBLEPOINT);
"," return (COLON);
"=" return (EQUAL);
"==" return (EQUIV);
"!=" return (EQUIV);
"<" return (EQUIV);
">" return (EQUIV);
">=" return (EQUIV);
"<=" return (EQUIV);
"(" return (LEFT_ROUND);
")" return (RIGHT_ROUND)
"{" return (LEFT_GESCH);
"}" return (RIGHT_GESCH);
"[" return (LEFT_ECKIG);
"]" return (RIGHT_ECKIG);
"^" return (GET);
"|" return (OR);
\n myline++;
\t ;
" " ;
. return (ANY);
^#.*$ ;
|