Zigzag Language

1. Relational Database Application

1.1. Dissimilarity from SQL
1.2. Declaring database
$base S =; $base S ~; = $base S; ~ $base S; $base S; $S; $S*
1.3. Creating table relations
R (A1, ...); R:r (A1:a1, ...); [E1, ...]; S*...; *S...; #n
1.4. Selecting table relations
= E; = A:a; = R:r (A1:a1, ...); = [E1 =/~/, ...]; = A: a^b; S*...; *S...
1.5. Printing database contents
$printX($file "F", Q1, ...); $count(...); $one(...); = ; =S; ={S}; = *
1.6. Updating relation
=E = (A1:a1, ...); E ~ (A1:a1, ...); R: #
1.7. Coping and deleting relation
R0 = R1; R0 =/~ R1:; R:[r0 =/~ r1]; R:r ~ ( ); R:r ~
1.8. Exporting and importing table data
$readTable($file "F", N0, N1, ...); $printTable($file "F", Q, A0, A1, ...)
1.9. Quoting and numbering
A:S; R(S:...); *S*...
2. Object-oriented Database Application
2.1. Dissimilarity from relational database
2.2. Multilevel classification
C1: C2: ...; C1(E11, ...): C2(E21, ...): ...
2.3. Class passing
E / ; E / E1; / E; / E / ; E / / E1
2.4. Class analysis
C():c; E:c | ; E:c \ ; | [C, C:c]; \ C:c
2.5. Class manipulation
C : {C1/}; C: = C1:; C: ~ C1:
2.6. Multitude variable
$var S; $S = E; = {$S}; {$S} ~; {$S} =; $S*
2.7. Program objects
@po S . (...); @po S . s(...); @po S #n . s(...); $mapState(..., S); $state(...)
2.8. Meaning and other
$(...); $quote(..., S); $unquote(..., S)
2.9. XML data
$readXmlDocument($file "F", C:...), $printXmlDocument($file "F", Q, Q1),
$readXmlKnowledge($file "F", C:...), $printXmlKnowledge($file "F", Q, Q1)

3. Language Reference

Zigzag Language

1. Relational Database Application

1.1. Dissimilarity from SQL

The main merit of Zigzag (or Z, pronounced "zi") language is its conciseness. Zigzag language makes possible working with relational database that features multiple values of field and dynamic structure (schema independent data). There is integrity control for the fields belonging to many tables and the trigger procedure is not required for this. Moreover, attribute names, together with values, may be expressed via request in a description or another request. These (and other) unique possibilities are not provided by SQL.

1.2. Declaring database

Considered structure:
$base S = ; Opens modifiable database with S name, which may be "..." or sequence of words.

$base S ~ ; Opens S database as new modifiable.

= $base S ; Opens S database as non-modifiable (only readable).

~ $base S ; Closes S database.

$base S ; Sets S database as current. If database is not opened yet, opens it as modifiable.

Considered auxiliary structure:
$S ;
$S* ; Contractions of specification. If S1 specific name was declared by $base "S1" before, the $"S"* suggests S1 database.

Database type is specified by base key word immediately after $. The name of the current database may be missing and used only $base. It needs to be careful with $S . If a specification is without type, system tries to remember type or, otherwise, supposes multitude variable ($var S).


Example 1.2
See the following test example. The < ... > construction is a Zigzag comment. The {A}= Zigzag description creates new A object in Notes/Test.ass database. The ={A} is a Zigzag request, which prints result but only in the second case for Notes/T* database.
< Tests multibase working >
< Opens "Notes/Test" for modification >
$base "Notes/Test" =; 
{A}=;
< Opens "Notes/RelDB" with current status or
for modification ("modify" status by default) >
$base "Notes/RelDB";
={A}; < Non-existent in RelDB >
< Opens "Notes/Test" for reading >
= $"Notes/T"*; < Apparently name is "Notes/Test" >
={A};
< Clears current database >
$base ~; 

1.3. Creating table relations

Considered description structure:
Note: Here and further left sentences are Zigzag statements, right sentences - literal translation and commentary. For example A(B) is translated as A relation of B, the A:B is translated as A namely B or B of class A.

R (A1, ...) - an R relation of an A1, ... attributes. Really for Zigzag, if R(A1, A2) relation exists, it supposes existence of relations A1(R) and A2(R).

R:r (A1:a1, ...) - an R namely r relation of an A1 namely a1, ... attributes.

R:(A:a, ...) (A1:a1, ...) - an R namely relation of an A: a, ... , which is relation of A1: a1, .... The attributes of first relation, A:a,..., are key.

Zigzag does not assume the type declaration in a separate apparent form, it is not obligated. Zigzag defines type of value automatically. For example, 1.2 is a value of number, 'abc' is a value of quote, A:B is a value of class or an instance of class "A", the R(A) is a value of relation or an instance of relation "R". While, there are not schema control in Zigzag. It is similar to XML for which DDT or XML schema is eligible but optional. We can suggest that the R(A1,...) is a relation in terms of relational model. In this case the R:r(A1:a1,...) will be tuple <r, <a1,...>>. Nevertheless, the R:r(A1:a1,...) may denote also relation. The R, A and even R:r may denote a class in terms of the set theory. So we can name the R either "class" or "relation" depending on the context.

Considered auxiliary structure:
[E1, ...] - a set of E1, ... objects. For example [A:a1, A:a2], or equal A: [a1, a2].

S*... .
*S... .
S denotes sequence of non-key symbols and blanks (word sequence). The *S... or S*... are simple names (element names) in a database consisting of S, for example a* in place of [a1, a2, ... an]. Any combination of the S words and * demands the test for existence of the correspondent names in the database. For example, R:S*S1(A:a) denotes that system will save R:S S1 in database only if no R:S*S1 object is existent.

#n . The # symbol is used for control of numerical values. The R: #1 is the same as R: 1, but R: #1 1 or R: #a causes error message.


Example 1.3
Look at the table with the multiple valued fields.
note  workfellow      telephone     address
1     Ringer Michael  415 506-0111  4 Broadway Av
                      503 743-5226
2     Smith Anne      400 297-0752  10 Seventh Av
      Smith Robert
Let us create new empty Notes/RelDB database.
$base "Notes/RelDB" ~;
Now input the table information. Description of schema, first statement, is optional. Zigzag's DBMS deduces schema automatically.
note (workfellow, telephone, address);
note:#1 ( workfellow:Ringer Michael,
          telephone:[415 506-0111,503 743-5226],
          address:4 Broadway Av
        );
note:#2 ( workfellow:Smith Anne,
          telephone:400 297-0752,
          address:10 Seventh Av
        );
We can use some attributes as key without preliminary declaration. Following fragment suggests that telephone is a key attribute, even if it has multiple value.
note:( telephone:[415 506-0111,503 743-5226]
     ) ( workfellow:Ringer Michael,
         address:4 Broadway Av
       );
note:( telephone:400 297-0752
     ) ( workfellow:Smith Anne,
          address:10 Seventh Av
        );

The statement below will not add a new note, because the note: (telephone:415 506-0111) exists, it is note: 1.

note:( telephone:415 506-0111
     ) ( workfellow:Ringer Michael
       );
The following statement also will not add a new note. However it adds new workfellow: Smith Robert attribute to note: 2. It also will try to connect note: 2 with the address:10 Seventh Av, which exists already.

note:( telephone:400 297-0752
     )  ( *fellow*:Smith Robert,
          address:10 *
        );

1.4. Selecting table relations

Considered request structure:
= E - the E (or anything equal to the E expression).

= A:a - the A namely a (or the a object of the A class).

Possible variants:
= A: - objects of the A class;
= :a - the a object of an arbitrary class;
Important note: if database includes only one object, A, then =A: equals indefinitude, the =:A equals A, and the =A(): equals A.

= R:r (A1:a1, ...) - the R namely r relation of the A1: a1, .... More general form of this request is = E (E1, ...) . The most often used form is R:(A1:a1,...). It is adequate to the RESTRICTION of the relational algebra: R WHERE A1 = a1 AND ...

Examples:
= R: (A:a) - the R namely relation of the A: a;
= (A:a, B:b) - the relation of the A: a and B: b ;
= ([A:a,B:b]) - the relation of the A: a or B: b ;
= [A,B]: (R:#1) - the A or B namely relation of the R: #1.
= [E1=/~/, ...] - the set of the E1 and/no/or the ... . Such important expressions define algebraic operations on the sets. The =[E1=E2] is a INTERSECTION, the =[E1~E2] is a DIFFERENCE, the =[E1,E2] is a UNION.
Examples:
= [R: ~ (B:)] - the R class no the relation of the B class;
= [:a=A:, B:] - the union of the =[:a = A:] intersection and =[B:]. Evidently = [:a = A:] equals = A: a.
= A:a^b - the A class namely range from a to b.

Considered auxiliary structure:
S*... .
*S... . Both expressions denote the element names of database containing S.

All the complete expressions separated by the ';' are statements. Expression may be a description or a request. If Zigzag expression begins with '=' or with '~' symbol, its operand (and itself expression) is a request: = Q;, ~ Q;. If expression ends with '=', like D =, the operand, D, is a description. If expression ends with '~', system considers operand as a request: Q ~. Let us define formally operands in '~' and '=' binary operations: D = Q, Q ~ Q. Look also at these combinations: =Q = Q; D = D1=; = [Q, D=]; D = =Q;.

See 4.Reference... about all the Zigzag operators, ordered from highest to lowest precedence. Consecution of operators is executed from left to the right. For example, A : B : C is equal to [ A : B ] : C, the A = B = C is equal to [A = B] = C.


Example 1.4
Return back at the previous example. Note that many examples in the next divisions are also the continuation of the previous divisions in this article.
note  workfellow      telephone     address
1     Ringer Michael  415 506-0111  4 Broadway Av
                      503 743-5226
2     Smith Anne      400 297-0752  10 Seventh Av
      Smith Robert
Following request reports some objects that belong to the telephone class with values in the range from 415* .
= telephone:415*^;
Result in the Report area (in Report window for Sav ZBase Interpreter, or in Report buffer for Sav Zigzag DBMS):
telephone:[
            415 506-0111,
            503 743-5226
          ];
We can image relations with address containing 'way' and with one of the 0111 or 0752 phones.
= (address:*way*,*phone:[*0111,*0752]);
Result:
note:1;
Finally let's output all the notes that have relation with 4... phone or address, but do not have relation with Anne.
= [note:([*phone,addr*]:4*)~(:*Anne)];

-----
note:1;

1.5. Printing database contents

Considered procedure structure:
$printX($file "F", Q1, ...) – print X of the Q1, ... in F file.
$printX(Q1, ...) – print X of the Q1, ... . Missing of the $file parameter denotes output in the Report area (window or buffer).

We can use: print, printLine, printClass, printRelation, or a abbreviation thereof p, pl, pc, pr. The F is an output file. The Q1, ... are requests.

Considered function structure:
$count(...) - number of ... .
$one(...) - one of ... .

Functions $count(...) and $one(...), or $c(...) and $o(...) respectively, are most often used before printing if database is a big. The result of $count(...) is a sum of data objects. The $one(...) gives only one first object from all pointed in ... parameters.

Useful request statements:
To print object names, we can use =Q statements in place of $pc(Q).
= . Prints all the database names.
Following are some useful statements printing simple database names like age word, 30 number, age 30 space combination, "age:30" string, or 'age:30' quote.
= S . The S simple name will be printed in any case even if S is not kept in database.
= {S}. Prints S simple name only if it exists in database as class name.
= * . Prints all the simple class names.

To understand expressions above, review examples for database that consists of the {A,A:a}.

Statement            Result
=;         A():a;
=B;        B;
={A,B,a}   A;
=*;        A;

Example 1.5
Try to print all the "schema relations" from 1.3. Creating....

$pl("SCHEMA OF ", *);
$pl("------------------------------------------------------");
$pr(*);

SCHEMA OF address, note, telephone, workfellow
------------------------------------------------------
address ( note
        ),
note ( address,
       telephone,
       workfellow
     ),
telephone ( note
          ),
workfellow ( note
           );
Before printing the note: relations there is sense in counting number of its. Then, if number is more than wanted, only one first relation may be printed.
= $count(note:);
$pr($one(note:));

-----
2;
note:1( address:4 Broadway Av,
        telephone:[
                    415 506-0111,
                    503 743-5226
                  ],
        workfellow:Ringer Michael
      );
If you want to print into the Notes/wf415.txt file the workfellows of the notes having the telephone started with 415*, enter:
$p($file "Notes/wf415.txt",
   workfellow:(note:(telephone:415*)) 
  );
Result in the Notes/wf415.txt will be:
workfellow:Ringer Michael
If you need to print all the complex names in the Notes/c.txt file, enter:
$pc($file "Notes/c.txt");

1.6. Updating relation

Considered structure:
=E = (A1:a1, ...) - the E is relation of the A1: a1 and ... . It is the same as [=E] (=A1:a1, ...). Expression supposes objects expressed by A1:a1, ... exist in database. New A1:a1 object for existent E objects may be related via [=E] (A1:a1).

E ~ (A1:a1, ...) - E is not relation of the A1: a1 and .... The a(~b2) is not correct!  The a~(b) is the same as =a~(=b).

R: # - R namely some number. The indefinite number is last number if the R: # request, and is new number if the R: # description.


Example 1.6
Suppose that Smith couple split. Anne lives in another place. (See 1.3. Creating...).
=note:(:Smith*) ~ (:Smith Anne);
note:# (:Smith Anne);
=note:# = (t*:503 743-5226);
Take a look at the result using
$pr( (:Smith*) );
-----
note:[
       2 ( address:10 Seventh Av,
           telephone:400 297-0752,
           workfellow:Smith Robert
          ),
       3 ( telephone:503 743-5226,
           workfellow:Smith Anne
         )
     ];

1.7. Coping and deleting relation

Considered structure:
R0 = R1R0 equals to R1. The R0 relation is renamed to R1. It is better to use R0 = {R1} expressions for difficult R1 expressions in place of R0 = R1. For example, the R0 =: R1, R0 = (R1), R0 = R1: have other sense, different from R0 = {:R1}, R0 = {(R1)}, R0 = {R1:} correspondently. 

R0 =/~ R1:R0 is equal/unequal to R1 class. The R1 relation is copied to/deleted from R0. Difficult R1 expressions better to conclude in {} braces, like R0 ~ {R1}:.

R: [r0 =/~ r1]R namely r0 is equal/unequal to R namely r1. Expression might be transformed to R:r0 =/~ R:r1. It copies relations from R:r1 to R:r0 or deletes relations of R:r1 from R:r0.

R:r ~ ( ) - R namely r is not relation. Deletes relations.

R:r ~ - R namely r is not. Deletes objects.


Example 1.7
We have new sample information. Anne Smith is daughter of Michael Ringer. Michael died and Anne has father's address. Remember contents of database.
$pr(note:);

-----
note:[ 
       1 ( address:4 Broadway Av,
           telephone:[ 415 506-0111,
                       503 743-5226
                     ],
           workfellow:Ringer Michael
         ),
       2 ( address:10 Seventh Av,
           telephone:400 297-0752,
           workfellow:Smith Robert
         ),
       3 ( telephone:503 743-5226,
           workfellow:Smith Anne
         )
     ];
Set data of Michael Ringer (1 record) to 3 record.
note: [=#3 = =(:Ringer Michael)];
$pr(note:#3);

-----
note:3 ( address:4 Broadway Av,
         telephone:[
                     415 506-0111,
                     503 743-5226
                   ],
         workfellow:[
                      Ringer Michael,
                      Smith Anne
                    ]

        );
Following fragment demonstrates integrity control. To delete Ringer Michael, we need not point records (1, 3) with this field and we may not use triggers or like SQL CONSTRAINT statements.
:Ringer Michael ~;
$pr(note:[#1,#3]);
-----
note:[
       1( address:4 Broadway Av,
          telephone:[
                      415 506-0111,
                      503 743-5226
                    ]
        ),
       3( address:4 Broadway Av,
          telephone:[
                      415 506-0111,
                      503 743-5226
                    ],
          workfellow:Smith Anne
        )
     ];
The 1 record does not have workfellow value, so we can clear and it.
note:#1 ~ ();
$pr(note:);
-----
note:[
       1,
       2 ( address:10 Seventh Av,
           telephone:400 297-0752,
           workfellow:Smith Robert
         ),
       3 ( address:4 Broadway Av,
           telephone:[
                       415 506-0111,
                       503 743-5226
                     ],
           workfellow:Smith Anne
         )
     ];

1.8. Exporting and importing table data

Considered structure:
$readTable($file "F", N0, N1, ...) - read table from F file with column numbers N0 key, N1, ....  The contraction, $rt(...), is able. If F file parameter is missing, imported tabular data are located immediately after procedure expression, in <> brackets. If there are not N0, N1, ..., all the columns will be input.
For example, we can import R(A, B) table directly from script:
$rt() <
R ; A ; B
#1; a1; b1
#2; a2; b2
>
$printTable($file "F", Q, A0, A1, ...) - print table in F file from Q with column names A0 key, and A1, .... This procedure is an analogue of the PROJECTION from the relational algebra. There is procedure name contraction, $pt(...). Any parameter may be missed. The Q is a request. The A0, A1, ... are attribute names and may be expressed even by requests. The A0 is primary key. If F file parameter is missing, Report area is supposed. The $printTableRows($file "F", Q, A0, A1, ...) procedure, $ptr(...) contraction, prints only table rows, without first line determining column names. If the A0, A1, ... are absent, attributes entered by $readTable(...) will be output in alphabet order.

This $printTable() procedure may also execute the JOIN operation of relational algebra if some attribute is expressed via string with point, like A1.A2. For example, look at the $printTable(A0:, A0, A1, A1.A2). Really it is supposed, that there are two tables A0(A1), A1(A2). The point expression A1.A2 may be translated as A2 attribute of A1 of A0: table. Here, the attribute A1 is foreign key in A0 table.

Notice large profit of $printTable() procedures for database archiving. The F file may be directory, without extension ( .tab). For example: If database consists of R1, R2 tables, $pt($file "tables") exports all the tables in tables/R1.tab and tables/R2.tab accordingly; Then we can import all the files from tables by $rt($file "tables").

A first input line of tabular data must define the names of columns. Only ";" semicolon may be delimiter of the table fields. Values of the field are separated by the ','. The words with the $ * # " ' [ { ( ] } ) . ^ : / | \ ~ = , ; < > key symbols need be enclosed in the quotes. The price may be without quotes, $10.2. See distinction of the "..." and '...' in the 1.9 section.


Example 1.8
Consider creating workfellow(address, telephone) and note(workfellow) relations in Notes/ObjDB.ass database. It needs firstly to output relations note(address, telephone, workfellow) in a Note.tab file. Following $pt() procedure prints table with ordered columns note, address, telephone, workfellow in the Notes/Note.tab file.
$pt($file "Notes/Note.tab", note:, note, address, telephone, workfellow);
Now we need to declare ObjDB database as new empty, and then to input two workfellow and note tables from the one Note.tab file.
$base "Notes/ObjDB" ~;
$rt($file "Notes/Note.tab", 4, 2, 3);
$rt($file "Notes/Note.tab", 1, 4);
The statement $rt($file "Notes/Note.tab", 4, 2, 3) creates workfellow, address, telephone table. The statement $rt($file "Notes/Note.tab", 1, 4) creates note, workfellow table. Now lets print note and workfellow tables existent in the current database. Beside this we will print LEFT OUTER JOIN of these tables on the workfellow attribute. 
$base "Notes/ObjDB" ~;
$pt(workfellow:);
$pl("----------");
$pt(note:);
$pl("----------");
$pt(note:, note, workfellow, workfellow.telephone);
-----
note; workfellow
1; 
2; Smith Robert
3; Smith Anne
----------
workfellow; address; telephone
Smith Anne; 4 Broadway Av; 415 506-0111, 503 743-5226
Smith Robert; 10 Seventh Av; 400 297-0752
----------
note; workfellow; telephone
1; ; 
2; Smith Robert; 400 297-0752
3; Smith Anne; 415 506-0111, 503 743-5226
At last we can export workfellow table.
$pt($file "Notes/Workfellow.tab", workfellow: );

1.9. Quoting and numbering

Considered structure:
A: S
R (S:...). Considered features of this expression are applicable and for R(S).

In this section the S designates '...' or "..." name, or n number, or any sequence beginning with a symbol %, +, or - .

The n is positive number with possible decimal fraction. The 2147483647.999999 is maximum by default (for non-commercial version). If number has decimal fraction, the digits (at least 0) must be before point. Maximum of digits after point is 6. If element (element's name) does not conform to specified criteria, it is taken to be non-numerical element. Numerical elements may be useful for correct order of output data. To select row of numbers, we need use ^ symbol, for example 1^5 denotes [1,2,3,4,5], the 1^ denotes all number >= 1. Note that 1* construction denotes non-numerical elements beginning with 1.

Using of A:S, R(S:...), for example A:'...', R('...':...), reduces the required database size and accelerates running, but a price must be paid in loss of the system wits for request. The expression =A:S supposes that S may be only on the nearest hierachy level for A (i.e. result will not include A:...:S). The =:S, =(S:), for example =:'...', =('...':), are not attainable. If R:1('A':a) exists in database, we cannot confirm that inverse relation, 'A':a (R:1), also exists. Quoting and numbering may be fit for a big database. It may be useful to express repeating class levels: 'A': 'A' or 1: 1.

Considered auxiliary structure:
*'...'*.... Either * or *... may be missing.
#*

All expressions with * are requests to elements existent in database. The '2'*'3' denotes '2...3' quote element in database starting with 2 and ending with 3. The #* combination is used to select only all the numbers from current class level.

The '...', "..." simple names and #n number may end up word sequence. For example, a #1, a "b", a b 'c' are allowable, whereas #1 a, 'a' 'b' and a "b" c are not correct. So, the * 'a' construction is possible and can suggest a 'a' or 'aa', not 'a' 'a'.

Additional note. System tests existing of correspondent elements in a database only if it needs to test element connection or presence. For example, 'a' will be tested in database not only for 'a'*, but also for {'a'}, ('a'), or 'a': expression, and not for ['a', 'b'], or $print('a') statements.


Example 1.9
Let us create "Note/Test" base and test numbers. As you can see system recognizes only positive number from 0 to 2147483647.999999.

$base "Notes/Test" ~;
employer:2147483647.999999;
employer:[2147483648, -1];
= employer:;
= employer:#*;
employer: ~;
-----
employer:[
           -1,
           2147483648,
           2147483647.999999
         ];
employer:2147483647.999999;

Following fragments research connections of numbers and '...' quotes.

office:'accounting'(employer:0100);
office:A('comment':'unknown');

$pr();
-----
employer( office
        ):100( office:'accounting'
             ),
office( 'comment',
        employer

      ):[ 
                    'accounting'( employer:100
                      ),
                  A( 'comment':'unknown' 
                      )
        ];


= '***ELLIPSIS***';
= office:''*;
= office:*'acc'*;

= ["ATTAINABLE EXPRESSIONS"];
= :A; 
= [(employer:), office:('comment':)]; 
= employer:; 
-----

'***ELLIPSIS***'; 
office:'accounting'; 
office:'accounting'; 
"ATTAINABLE EXPRESSIONS"; 
office:A; office:[ 
                   'accounting', 
                   A 
                 ]; 
employer:100;
 

Following fragment produces Failure messages.

= {"UNATTAINABLE EXPRESSIONS"};
= :'accounting'; 
= ('comment':); 

2. Object-oriented Database Application

2.1. Dissimilarity from relational database

Zigzag language maps related objects on database and vice versa, whereas SQL maps object relations. These general definitions (equal at the first sight) disclose essentially different data models of both languages. Connections of the Zigzag objects make up new type of data - association, which may be either relation or class. So Zigzag language manipulates with relations and classes. The relation features relational database, while class, for example its inheritance, adds to database object-oriented nature. Zigzag implements data inheritance, not just type inheritance as SQL3 or all the known object DBMSs.

2.2. Multilevel classification

Considered structure:
C1: C2: ...
C1(E11, ...): C2(E21, ...): ...

Note that R1(A1): R2(A2) expression equals to [R1(A1): R2] (A2) and equals to R1(A1):  [R2(A2)]. The R1: [:R2] is allowable, but it is the same as R1: R2. It may be useful to know: the R1: expression assumes all the levels of R1 class, R1: R2: ..., but R1:* only one level - R1: R2.


Example 2.2
Let us classify by Zigzag language the objects of the telephone notebook with necessary properties: telephone, and address.
category: acquainted (property: telephone,
                      property: address
                     ): [ relative (property: propinquity
                                   ),
                          workfellow (property: position,
                                      property: function
                                     )
                        ];
Execute the queries.
= category:relative;
$p("-----");
= :acquainted:(property:telephone, property:propinquity);
$p("-----"); 
= category:~:workfellow;
Report window will have three equal Zigzag statements separated by the "-----"; string.
category:acquainted:relative;
Additional test:
$p("category:*");
$pr(category:*);
Result:
category:*
category:acquainted( property:[ 
                                address,
                                telephone
                              ]
                    );

2.3. Class passing

Considered structure:
E /  - value of E: class.

E / E1 - E1 value of E: class.

/ E - name of class with E value.

/ E / - value of class with E value.

E / / E1 - intermediate levels of class, between E name and E1 value.


Example 2.3
We are going to complicate category of 2.2 section namely add unacquainted relative.
category:[unacquainted:relative = =:relative];
$pr(category:);
category:[
           acquainted( property:[
                                  address,
                                  telephone
                                ]
                     ):[
                         relative( property:propinquity
                                 ),
                         workfellow( property:[
                                                function,
                                                position
                                              ]
                                   )
                       ],
           unacquainted():relative( property:propinquity
                                  )
         ];
It is left to enter many of '/' request combinations and look at result.
$p("= category:unacquainted/");
= category:unacquainted/;
$p("= category:*/");
= category:*/;
$p("= category/relative");
= category/relative;
$p("= category/(property:propinquity, property:address)");
= category/(property:propinquity, property:address);
$p("= /relative");
= /relative;
$p("= category:acquainted:[/relative]");
= category:acquainted:[/relative];
$p("= [/relative = /workfellow]");
= [/relative = /workfellow];
$p("= /relative/");
= /relative/;
$p("= category//relative");
= category//relative;
Result:
"= category:unacquainted/";
relative;
"= category:*/";
relative,
workfellow;
"= category/relative";
acquainted:relative,
unacquainted:relative;
"= category/(property:propinquity, property:address)";
acquainted:relative;
"= /relative";
category:[
           acquainted,
           unacquainted
         ];
"= category:acquainted:[/relative]";
category:acquainted;
"= [/relative = /workfellow]";
category:acquainted;
"= /relative/";
relative,
workfellow;
"= category//relative";
acquainted,
unacquainted;

2.4. Class analysis

Considered structure:
C():c . It is equal to [C, C:c] expression.

E:c | . Result is lower level, c. It is allowed to use ...|..., result of E:[c1,c2] | c1 will be c1.

E:c \ . Result is E. It is allowed to use ...\..., result of [C1,C2]:E \ C1 will be C1.

| C():c . Normalization. Result is C:c.

\ C:c . Result is a [C, C:c] or equal C():c.


Example 2.4
Let us return to the category class. Firstly we delete category:unacquainted: class and category:unacquainted itself object.
category:unacquainted(): ~;
= category:;
category:acquainted():[
                        relative,
                        workfellow
                      ];
Now test '|' and '\' combinations.
$p("", "CURRENT (CONSIDERED) OBJECTS", category:);
$p("", "CURRENT IDENTIFIERS", category:|);
$p("", "CURRENT CATEGORIES", category:\);
$p("", "NORMAL OBJECTS", |category:);
$p("", "ALL OBJECTS", \category:);
$p("", "NORMAL IDENTIFIERS", |category:|);
$p("", "NORMAL CATEGORIES", |category:\);
$p("", "NORMAL GENERAL CATEGORIES", |category:\*);
$p("", "ALL IDENTIFIERS", \category:|);
$p("", "ALL CATEGORIES", \category:\);
Result:
CURRENT (CONSIDERED) OBJECTS
category:acquainted
category:acquainted:relative
category:acquainted:workfellow

CURRENT IDENTIFIERS
acquainted
relative
workfellow

CURRENT CATEGORIES
category
category:acquainted

NORMAL OBJECTS
category:acquainted:relative
category:acquainted:workfellow

ALL OBJECTS
category
category:acquainted
category:acquainted:relative
category:acquainted:workfellow

NORMAL IDENTIFIERS
relative
workfellow

NORMAL CATEGORIES
category:acquainted

NORMAL GENERAL CATEGORIES
category

ALL IDENTIFIERS
acquainted
category
relative
workfellow

ALL CATEGORIES
category
category:acquainted

2.5. Class manipulation

Considered structure:
C: {C1/} - C class namely value of C1. If C1/ equals c1, the C:{C1/} equals C:c1. Note that C:[C1/] expression has other meaning and is equal to [C:C1/].

C: = C1: - C class is equal to C1 class. Relations of C1: objects are copied to identical C: objects.

Assume that C: [c, c1], C1(A): [c1(A:a1), c2(A:a2)] are available. Consequently, the C: = C1: entails C(A): [ c, c1(A:a1)].

C: ~ C1: - C class is unequal to C1 class. Relations of C1: are removed from C: objects identical by value.


Example 2.5
Remember about workfellow class.
$pt(workfellow:);
workfellow  ; address      ; telephone
Smith Anne  ; 4 Broadway Av; 415 506-0111, 503 743-5226
Smith Robert; 10 Seventh Av; 400 297-0752
Assume we face the need of transmitting workfellow relation to object:workfellow relation. Look at the workfellow class values.
= workfellow/;
Smith Anne,
Smith Robert;
Make value of the object:workfellow class initially.
object:workfellow: {=workfellow/};
$pr(object:);
object:workfellow():[
                      Smith Anne(
                                ),
                      Smith Robert(
                                  )
                    ];
Now we can copy relations from workfellow:
object:workfellow: = workfellow:;
$pr(object:);
object:workfellow():[
                      Smith Anne ( address:4 Broadway Av,
                                   telephone:[
                                               415 506-0111,
                                               503 743-5226
                                             ]
                                 ),
                      Smith Robert ( address:10 Seventh Av,
                                     telephone:400 297-0752
                                   )
                    ];
Let's print all the objects with Smith* simple class values.
$p(:Smith*);
object:workfellow:Smith Anne
object:workfellow:Smith Robert
workfellow:Smith Anne
workfellow:Smith Robert
Let us print now name of class with Smith* values.
$p(/Smith*);
object:workfellow
workfellow
The old workfellow (not object:workfellow) relation should be deleted.
workfellow(): ~;
Lastly we can print information about objects through property/ attributes.
$pt(object:, :workfellow, property/);
object:workfellow; address      ; telephone
Smith Anne       ; 4 Broadway Av; 415 506-0111, 503 743-5226
Smith Robert     ; 10 Seventh Av; 400 297-0752

2.6. Multitude variable

Considered structure:
$var S - S variable. Declares S specification name, "..." or word sequence, as multitude variable. The $var x is the same as $var "x".

$S = E - $S is equal to E. The S variable assumes E objects. If $S = [] equation, value of $S is null.

= {$S} . Expression extracts the objects equal to the S multitude from a database.

{$S} = . It creates objects of S in a current database.

{$S} ~ . It deletes objects of S from database.

$S* . Using ellipsis for name of multitude variable.

The var key word is optional and needed only if a multitude variable of other type with the same name was declared earlier. For example, if $base "s1" and $var s1 were declared, the $s1 implies "Ambiguous" error. Type or name of variable must follow immediately after $.

System supposes that objects of multitude variable are in a current database and therefore tests objects for the existence only if variable is in {} brackets, or defines connection. For example, content of $x will be tested in ($x), {$x}, $x: , but not in  =[$x], $print($x). Constructions $x (...) and $x: ... may be used for creation of new connections in a database. Pay attention that to create or delete database connection via = or ~ symbol, a variable has to be bracketed like this [$x] = (...) or [$x] ~ (...).


Example 2.6
Previously declared variable name may be with '*' ellipsis, see $tel*.
$var xTelephone = tel*:;
= $xTel*;
Result:
telephone:[
            400 297-0752,
            415 506-0111,
            503 743-5226
          ];
=====
$x = $xTel*(:Smith Anne);
= $x;
Result:
telephone:[
            415 506-0111,
            503 743-5226
          ];
=====
$x = [$x ~ telephone:415*];
= $x;
Result:
telephone:503 743-5226;
The following fragment illustrates using the variable data in another database.
$p("** Test New Database **");
$base "Notes/Test" ~;

= ["Content of $x"];
= [$x];
= ["Current DB"];
= {$x};
{$x} =;
= "DB after $x=";
= {$x};
{$x} ~;
= "DB after $x~";
= {$x};
Result:
** Test New Database **
"Content of $x";
telephone:503 743-5226;
"Current DB";
;
"DB after {$x}=";
telephone:503 743-5226;
"DB after {$x}~";
;

2.7. Program objects

Considered structure:
@po S . (...). Creates new program object. The @po S subject of this point-expression is name of program class.
@po S . s(...). Point expression is invoking s method for @po S program class. Really it invokes the s static method of the S Java class.
@po S #n . s(...). Point expression is invoking s method for @po S #n program object.

Possible structure:
@po S . s  - s field of @po S program class. Really the s is a static variable of the S Java class.
@po S #n . ss field of @po S #n program object.
We will not consider but it is possibly to get fields of program class or object.

Zigzag primarily was dedicated to work under/with Java, so Java objects and classes are most accessible. Look at Java expression, which creates File object.

java.io.File x = new java.io.File("Note");
The x is variable pointing Java program object of java.io.File program class. By means of Zigzag we can also create such program object, but expression will be another.
$x = @po java io File.("Note");
Name of program class in Zigzag begins with "@po". The varible $x does not have type, we can assign to it anything. Really, in this case, value of $x will be program object's name, like @po java io File #1. Now we can execute method applicable for correspondent Java program object. For example, following Zigzag statement gives to $y variable the absolute path of "Note" file (like  C:\SavZBase\demo\Note for Windows).
$y = $x.getAbsolutePath();
It is very important to mark some features of working in Zigzag with int, double, boolean and  String Java objects. Such objects are expressed directly via real name when play role of Java method's input/output or Java constructor's input parameters. The int is expressed by simple number like 3, the double - by number with point like 34.123, the boolean - by either true or false word, the String - by "..." or word combination like "file1.txt" or first textual file. For example [@po java lang System.out].println("file1.txt"). These real names cannot be subject of Zigzag point-expression. For example, to define length of "file1.txt" string, we need use @po java lang String.("file1.txt").length(), the "file1.txt".length() is not correct.

Considered functions and procedures:
$mapState(..., S). Procedure maps all the attributes of the ... program objects in database. Possible contraction is $ms(...,S).
$state(...). Result of function is a mapping of all the attributes of the ... program objects.  Possible contraction is $s(...).

Let's stop on the $mapState and $state. To realize attributes of the program objects, they get public fields and invoke the public getX() methods that are without parameters. System takes the getX() method as virtual attribute with X name. The last optional parameter, S, of $mapState may be quote or string. A $mapState(..., quote) maps program objects with the attribute values quoted like '...'. For a $mapState(..., string) attribute values are "...".


Example 2.7
The Vector is well known and useful Java class. Let us create Vector object and print it's Zigzag name.

$v = @po java util Vector.();
$p($v);

-----
@po java util Vector #1

In the Java, internal name of this object may have view like java.util.Vector@02a. Now we will add to Vector the three String objects with real names red, green, blue and print first Vector's element.

$v.addElement(red);
$v.addElement(green);
$v.addElement(blue);
$v0 = $v.elementAt(0);
$p($v0);

-----
red

Following example we use to demonstrate a using of the $mapState procedure. The objects of the Java class Point instance a Zigzag class point.

point:[
  @po java awt Point.(1,2),
  @po java awt Point.(3,4)
];
$mapState(point:, quote);
$pr(point:);
-----
point:[
        @po java awt Point #1( location:'java.awt.Point[x=1,y=2]',
                                x:1,
                                y:2
                              ),
        @po java awt Point #2( location:'java.awt.Point[x=3,y=4]',
                                x:3,
                                y:4
                              )
      ];
Assume there is necessity to change the Point object into a state with coordinates x=3, y=4. In this case the $state function may be helpful.
$x = point:(x:3,y:4);
$x.move(4,5);
= $state($x);
{$x} ~ ();
{$x} = ($quote($state($x)));
$pr(point:);
-----
location:java.awt.Point[x=4,y=5],
x:4,
y:5;
point:[
        @po java awt Point #1( location:'java.awt.Point[x=1,y=2]',
                                x:1,
                                y:2
                              ),
        @po java awt Point #2( location:'java.awt.Point[x=4,y=5]',
                                x:4,
                                y:5
                              )
      ];
Persistent program objects are main determinative feature of object databases. Current Vector object may be saved, for example by Vector:$v=, and then get and changed in other Zigzag session. Program classes usually exist separately from database in the program library. Only placing its names in database makes sense. See example of using Array Java class creating object consisting of three String objects.

@po java lang reflect Array =;
$x = @po*Array.newInstance(@po java lang String, 3);
$p($x);

-----
@po [Ljava lang String; #1

Knowing methods and constructors of correspondent Java objects and classes we can invoke its in Zigzag lightly.

@po*Array.set($x, 0, $v0);
$x0 = @po*Array.get($x, 0);
$p($x0);
$y = @po java lang String.($x0);
$p($y.length());

-----
red
3

Parameter of method or constructor in Zigzag may be multitude. In this case method or constructor is invoked for each element of multitude separately.

string program object: @po java lang String.([a,b,c]);
$z = s*p*o*/;
$p($z);

-----
@po java lang String #6
@po java lang String #7
@po java lang String #8

As you saw example before, $z result is multitude of three String objects. We can invoke for this result other methods.

$pl($z.toString());
$pl($z.concat(["1","2","3"]));

-----
a, b, c
a1, a2, a3, b1, b2, b3, c1, c2, c3

Following is example of working with double Java objects. Two methods are used simultaneously.

$pl(@po java lang Math.[floor, ceil](2.33));

-----
2.0, 3.0

Below is example of executing other outside programs via current Java Runtime.

$xrun = @po java lang Runtime.getRuntime();
$p(NOW SEE CALCULATOR);
$xrun.exec("C:\WINNT\System32\calc.exe");

-----
NOW SEE CALCULATOR

2.8. Meaning and other

Considered structure:
$(...) - meaning of ... . This unnamed "meaning" function assumes arguments as Zigzag expressions and result will be execution of that expressions. Usually arguments are enclosed in " quotations.

By default arguments are requests as here $("A:"). System recognizes description by existence of  ";" or for D= construction. For example, the $("A:a;B:b;") creates A:a and B:b database objects. Function helps also to invoke program object's (see section before) methods and fields.

Considered structure:
$quote(..., S) - quote of a ... as S. The S may be string that denotes "..." values. To produce '...' values, S may be missing or be quote. Contraction of $quote is $q.
$unquote(..., S) - unquote of a ... that S. The S may be string or quote (by default) denoting "..." or '...' source.  Contraction of $unquote is $uq.


Example 2.8
Example below demonstrates the using of a Date Java program object, more exactly its toString method, to define current date.

session:# (date: "@po java util Date.().toString()");
$date = date/(session:#);
$pl("EXPRESSION: ", $date);
$pl("DATE: ", $($date));

-----
EXPRESSION: "@po java util Date.().toString()"
DATE: Sun Mar 30 17:17:44 GMT+04:00 2003

See following example. After R:(A:#, B:#) database will contain relation like R:1(A:1,B:1). Then we create other expression(subject) relation to show how Zigzag request may be saved and get.

R:(A:#, B:#);
expression:request:"A:(R:)" (subject:A);
$xr = :request / (subject:A);
$pl("Meaning of ", $xr);
= $($xr);

-----
Meaning of "A:(R:)"
A:1;

Following is example of the description meaning.

expression:description:"R:(A:#, B:#);" (subject:R);
$xd = :description / (subject:R);
$($xd);
$pl("Meaning of ", $xr, " after second ", $xd);
= $($xr);

-----
Meaning of "A:(R:)" after second "R:(A:#, B:#);"
A:[
    1,
    2
  ];

It is permissible to use several parameters in $(...).

$pl("Meaning of ", $xr, " after third ", $xd);
= $($xd, $xr);

-----
Meaning of "A:(R:)" after third "R:(A:#, B:#);"
A:[
    1,
    2,
    3
  ];

Parameter of $(...) meaning may be a multitude of the expressions.

expression:request:"B:(R:)" (subject:B);
$xrs = :request/*"("*"R"*")"*;
$p($xrs);
$pl("Meaning of ", $xrs);
= $($xrs);

-----
"A:(R:)"
"B:(R:)"
Meaning of "A:(R:)", "B:(R:)"
A:[
    1,
    2,
    3
  ],
B:[
    1,
    2,
    3
  ];

The last fragment demonstrates a using of quote and unquote functions.

$xrs1 = $unquote($xrs, string);
$xrs1 = $quote($xrs1);
expression:new:$xrs1;
= :new:;
= $(:new:''*);

-----
expression:new:[
                 'A:(R:)',
                 'B:(R:)'
               ];
expression:new:[
                 A:[
                     1,
                     2,
                     3
                   ],
                 B:[
                     1,
                     2,
                     3
                   ]
               ];

2.9. XML data

Considered structure:
$readXmlDocument($file "F", C:...). Contraction: $rd(...) or $rxd(...).
$printXmlDocument($file "F", Q, C:...). Contraction: $pd(...) or $pxd(...).
$readXmlKnowledge($file "F", C:...). Contraction: $rk(...) or $rxk(...).
$printXmlKnowledge($file "F", Q, C:...). Contraction: $pk(...) or $pxk(...).

F is name of either XML file or directory of XML files. Directory is supposed if the F name is without point. The Q request, as C:... roots (paths in database), may be missed in all the procedures. The $file parameter may be missed in printXmlKnowledge and printXmlDocument. If $file is absent, output is a Report area (string buffer for Sav Zigzag).

The XML knowledge differs from XML document in that the knowledge does not suppose repeatable data (tags or texts) in one class (in one tag). Internal Zigzag representation of XML data is different for $rd(...) and $rk(...). For example, test this f.xml file.
<R1>
  r1
  <r2 A="a"/>
  <r2/>
  <_1/>
</R1>

Zigzag data for $rd($file 'f.xml', C1):
C1:R1:[
       1(@T:'r1'),
       2(@N:r2,A:'a'),
       3(@N:r2),
       4(@N:1)
      ]
For $rk($file 'f.xml', C2) Zigzag data will be more general like knowledge:
C2:R1:[
       'r1',
       r2(A:'a'),
       1
      ]

To print the C1 document or the C2 knowledge, we can use $pd(C1:, C1) or $pk(C2:, C2).


Example 2.9
Let us see p1.xml XML file representing paragraph with two sentences.

<!--
XML is a subset of SGML.
XML enables SGML to be processed on the Web.
-->
<paragraph>
  <sentence>
    <phrase>
      <noun>XML</noun>
      <phrase>
        <verb>is</verb>
        <phrase>
          <noun>subset</noun>
          <preposition>of</preposition>
          <noun>SGML</noun>
        </phrase>
      </phrase>
    </phrase>
  </sentence>
  <sentence>
    <phrase>
      <noun>XML</noun>
      <phrase>
        <verb>enables</verb>
        <phrase>
          <noun>SGML</noun>
          <phrase>
            <particle>to</particle>
            <verb group="auxiliary">be</verb>
           <verb>processed</verb>
            <preposition>on</preposition>
            <phrase>
              <article>the</article>
              <noun>Web</noun>
            </phrase>
          </phrase>
        </phrase>
      </phrase>
    </phrase>
  </sentence>
</paragraph>

We can read XML file by rd(...) procedure in document root.

$base 'Notes/xml'~;
< XML Data >
$rd($file 'Notes/p1.xml', document);

Now we will assign path for is and be text to $x variable. Before declare current database as non-modifiable. Lastly, print $x as XML document.

=$base;
$x = document:(@T:['is','be'],@N:verb);
$pd($x, document);
-----
<paragraph>
  <sentence>
    <phrase>
      <phrase>
        <verb>
          is
        </verb>
      </phrase>
    </phrase>
  </sentence>
  <sentence>
    <phrase>
      <phrase>
        <phrase>
          <phrase>
            <verb>
              be
            </verb>
          </phrase>
        </phrase>
      </phrase>
    </phrase>
  </sentence>
</paragraph>

Reflect $x value. It is tree of position numbers of texts and tags in XML. To define $x1 variable as grandparents of $x, we need to ascend two levels up. It will be positions of phrase tags.

$pr($x);
$x1 = $x\\;
$pr($x1);
-----
document:1:[
              1:1:2:1:1( @T:'is'
                       ),
              2:1:2:2:2:2:1( @T:'be'
                           )
        ];
document:1:[
              1:1:2( @N:phrase
                   ),
              2:1:2:2:2( @N:phrase
                       )
            ];

To print in XML format phrases directly belonged to $x1, we can use this.

$pd(=[$x1:*=(@N:phrase)]:, $x1);
-----
<phrase>
  <noun>
    subset
  </noun>
  <preposition>
    of
  </preposition>
  <noun>
    SGML
  </noun>
</phrase>
<phrase>
  <article>
    the
  </article>
  <noun>
    Web
  </noun>
</phrase>

Fragment below selects paths of $x non-having group attribute with value "auxiliary". Then it defines near phrase ancestors and prints its last child.

$x2 = [$x~$x(group:'auxiliary')];
$x3 = |[\$x2=(@N:phrase)];
$pr($x3);
$pd(=$x3:#:, $x3);
-----
document:1:1:1:2( @N:phrase
                );
<phrase>
  <noun>
    subset
  </noun>
  <preposition>
    of
  </preposition>
  <noun>
    SGML
  </noun>
</phrase>

By next statement we print all document's descendants from 1 to 3 grandchildren of document in directory "Notes/paragraph". Result will be XML files.

$pd($file 'Notes/paragraph', document:, document:*:1^3);
-----

Finally let us to make sense of XML knowledge.

$pk(=$x3:#:, $x3);
$base=;
$rk($file 'Notes/p1.xml', combinations);
$pk(combinations:);
-----
<_2>
  <_1 _N="noun">
    <_1 _T="subset"/>
  </_1>
  <_2 _N="preposition">
    <_1 _T="of"/>
  </_2>
  <_3 _N="noun">
    <_1 _T="SGML"/>
  </_3>
</_2>
<combinations>
  <paragraph>
    <sentence>
      <phrase>
        <article>
          the
        </article>
        <noun>
          SGML
          Web
          XML
          subset
        </noun>
        <particle>
          to
        </particle>
        <preposition>
          of
          on
        </preposition>
        <verb group="auxiliary">
          be
          enables
          is
          processed
        </verb>
      </phrase>
    </sentence>
  </paragraph>
</combinations>

3. Language Reference

Symantec designations ('|' separator and '...' trailing ellipsis are special symbols):
E                   Expression
Q                   Request in =Q | ~Q | Q~ | Q~Q | D=Q | $print(Q,...)
D                   Description in D; | D= | D=Q
R|R:r               Relation name in R(E) | R:r(E) relation
A|A:a               Relation attribute in E(A,...) | E(A:a,...) relation
C:c                 Data object in C:[c:[...],...] class
C                   Class name in C:E
c                   Class value (or Instance name) in E:c
A|B|C|...|R|...     Element (or Simple object)
a|b|c|...|r|...     Element (or Simple object)
S|s                 Sequence of characters, which has contextual limitation 
N|n                 Number
Syntax designations:
Z     Key symbol         $ | * | # | " | ' |   | [ | { | ( | ] | } | ) | . | ^ | : | / | | | \ | ~ | = | , | ; | < | >
C     Non-key character
L     Letter
D     Digit
I     Integer            D...
N     Number             I | I.I
W     Word               C...
ND    Number Designation N | #N | # | #*
SC    String Combination "..." | "..."* | "..."*SC
QC    Quote Combination  '...' | '...'* | '...'*QC
WW    Word sequence      W | W WW
WC    Word Combination   WW | WW* | WW*WC
NC    Name Combination   ND | SC | QC | WC | WC NC
Nm    Element name       * | * NC | NC
      (Simple name)
SNm   Specific name      WW | "..." | WW* | "..."*
Sp    Specification      $W SNm | $SNm
Exp   Expression         Nm | Sp | Exp Z | Z Exp
Stm   Statement          Exp, ...
Scr   Script             Stm; ...
Expressions ordered by priority:
 1  Sp | Sp(Exp, ...)
    $base SNm             1.2
    $file SNm             1.5, 1.8
    $var SNm              2.6
    $Sp(Exp,...)          1.5, 1.8, 2.7, 2.8, 2.9, 3.1
 1  Nm
    SC | QC               1.9
    ND                    1.6, 1.9
    ...*...               1.3, 1.4, 1.9
    *                     1.5, 2.2
 1  <...>                 1.2, 1.8
 1  {Exp, ...}            2.5, 2.6
 1  [Exp, ...]            1.3, 1.4
 1  (Exp, ...)            1.4
 2  Exp(Exp, ...)         1.3, 1.4
 3  Exp.Exp               2.7
 4  ^Exp | Exp^Exp | Exp^ 1.4
 5  Exp:Exp               1.3, 1.9, 2.2
 5  :Exp | Exp:           1.4
 6  /Exp | Exp/           2.3
 6  Exp/Exp | Exp//Exp    2.3
 7  |Exp | \Exp           2.4
 7  Exp|Exp | Exp\Exp     2.4
 7  Exp| | Exp\           2.4
 8  ~Exp                  1.2
 8  =Exp                  1.4, 1.6
 9  Exp~Exp               1.4, 1.6, 1.7, 2.5, 2.6
10  Exp=Exp               1.4, 1.6, 1.7, 2.5, 2.6
11  Exp~ | Exp=           1.2, 1.7
12  Exp,Exp               1.3, 1.4
13  Stm;Stm               1.3
Procedures
$p   | $print             1.5
$pl  | $printLine         1.5
$pc  | $printClass        1.5
$pr  | $printRelation     1.5
$pt  | $printTable        1.8
$ptr | $printTableRows    1.8
$rt  | $readTable         1.8
$ms  | $mapState          2.7
$rd  | $readXmlDocument   2.9
$pd  | $printXmlDocument  2.9
$rk  | $readXmlKnowledge  2.9
$pk  | $printXmlKnowledge 2.9
Functions
$c  | $count              1.5
$o  | $one                1.5
$s  | $state              2.7
$   | $meaning            2.8
$q  | $quote              2.8
$uq | $unquote            2.8