Smans Language, Reference

ver. 2.0, Dec 2009

0. Introduction
1. Declaring database
2. Creating table relations
3. Printing database contents
4. Selecting class elements
5. Navigation through the relations
6. Updating data
7. Set variable
8. Table manipulation, exporting and importing
9. Limitation in class names and values
10. Meaning and quoting
11. Program objects
12. Multilevel classification
A. Language Reference

0. Introduction

Smans language initially was designed as XPath compatible language working with data tables. Nevertheless, Smans is not only query language like XPath or XQuery. Smans is also language of data description and manipulation. If query looks like A[.=1][B=2], the correspondent data description in Smans has a view A 1[B 2]=.

Most important you need to know is the principle of data representation or data semantic the Smans works with. Smans data are based on the class-relational data model. Unlike SQL, Smans database is rather a natural join of tables, not set of tables. Better to consider a Smans database as a lot of interrelated columns (or more exactly classes). For example, by statement A 1[B 2]= we lightly join two columns (classes), A and B, and two their fields (elements), A 1 and B 2. To get A table (relation) in Smans means to get A column and all other columns directly related with A.

Specific representation gives some advance in contrast to tabular (relational) data representation. For example, Smans database is featured by dynamic structure (schema independent data). There is automatic integrity control for the fields belonging to many tables and the trigger procedure is not required for this. Like object-oriented database system, Smans lightly represents hierarchic and multiple values data.

1. Declaring database

Constructions 1

$base S = ; Opens modifiable database with S name. S may be enclosed in "..." or in '...'.

$base S != ; Opens S database as new modifiable. Old database is deleted.

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

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

Database type is specified by base key word immediately after $. The name of the current database may be missing. It is useful if there is necessity to change status of the current database. For example, =$base declares a current database as readable only.

Examples 1

See the following test example. The --..., (: ... :) constructions are Smans comments. The A='a' Smans description creates new A 'a' element in notedb/temp.sdb database. The =A is a Smans request, which prints values of A elements.
-- 1.1. Testing database declaration
-- Declares 'temp' database as modifiable
$base "notedb/temp" =;
A = 'a';
-- Current 'temp' database will be only for reading
= $base;
= A;
-- Declares 'other' database, modifiable by default
$base "notedb/other";
= A; -- A is non-existent in 'other' database
-- Back to 'temp' database non-modifiable due to previous declaration
$base "notedb/temp";
= A;
-- Clears database
$base != ;
= A;
(: -- Test non-modifiable database
= $base;
A =;
:)

2. Creating table relations

Constructions 2

readTable()  (:
R; A; ...
'r'; 'a'; ...
...
:) ; Reads table from the following comment block, where first row R;A;... declares names of columns (classes). Other rows are column (class) value sequences. By default, the first column is a primary key in the correspondent table. It is possible to change quantity and order of input columns if to call readTable with parameters. For example, in case of readTable(2,1) the Smans system reads only two columns and second input column is supposed as key. The contraction rt is able in place of readTable. For example, we can import R[A, B] table very simply through the following fragment:
rt() (:
R;  A;    B
#1; 'a1'; 1
#a; '()'; 2.9
:)
Smans does not assume the type declaration. Example above demonstrates all the possible value types, R column contains # identifiers, A contains '...' single quoted strings, and B column contains numbers. The "..." string is not value in Smans. Double quoted string is useful to express a complex column name with special symbols and blanks. More about data types and their limitations see 9.Limitation... section. While, there is no schema control in Smans. It is similar to XML for which DDT or XML schema is eligible but optional.

Only ";" semicolon may be delimiter of the table fields. Values of the field are separated by the ','. If input table has several rows with equal key value, they are combined into one row with multi-valued fields. Two input tables below are equal.
rt() (:
R;  A;    B
#1; 'a1'; 1
#1; 'a1'; 2
:)
rt() (:
R;  A;    B
#1; 'a1'; 1, 2
:)
Following constructions explains addition the new rows and fields to R table. If table does not exist yet, it will be created.

D = ; It is general definition of Smans statement, which is used to add new data in a database. The D expression in this case is a description. Below are some detailed elaborations of D description used to add a new row or fields in the R table.

R #[A 'a', ...] = ; Adds new row with fields R #, A 'a',..., where R # is primary key field. Because # identifier is indefinite, system automatically generates new. We can suggest that the R[A,...] is a relation header (or schema without type definition) in terms of relational model. In this case the R #1[A 'a', ...] will be tuple <#1, 'a', ...>. Inside of description it is possible to separate name and value of the field (data element) by means of colon ':', like R:#1[A:'a', ...].

R 'r'[A 'a', ...] = ; Adds R 'r', A 'a',... fields to the R table. Here R 'r' is a primary key field. In case if R 'r' row exists the A 'a',... will be added to that row. Remind that value type may be other. 

R[A 'a', ...] [B 'b', ...] = ; Here A 'a',... fields in first brackets are considered as key (beside R). If R table already has rows with A 'a',... key, this statement adds new B 'b',... fields to that existent rows. Otherwise, new row R #,A 'a',...,B 'b',.... will be added. 

Examples 2

Now input the table information.
readTable() (:
note; fellow; telephone; address
#2; 'Forman Daniel'; '650 756-9546'; '27 Crestline Ave'
#; 'Smith Anne'; '400 297-0752'; '10 Seventh Av'
:);
Result is this table:
note  fellow           telephone     address
#2 'Forman Daniel' '650 756-9546' '27 Crestline Ave'
#3 'Smith Anne' '400 297-0752' '10 Seventh Av'
Following statement adds new #4 row with the multiple valued field telephone.
note #[fellow 'Ringer Michael',
telephone {'415 506-0111', '503 743-5226'},
address '4 Broadway Av'] =;

The statement below will not add a new row, because the note[telephone '400 297-0752'] exists already in #3 row.

note [telephone '400 297-0752'][
fellow 'Smith Robert',
address '10 Seventh Av'] =;
Look at the resulted table with the multiple valued fields.
note fellow           telephone     address
#2 'Forman Daniel' '650 756-9546' '27 Crestline Ave'
#3 'Smith Anne' '400 297-0752' '10 Seventh Av'
'Smith Robert'
#4 'Ringer Michael' '415 506-0111' '4 Broadway Av'
'503 743-5226'

3. Printing database contents

Constructions 3

printSchema() ; Prints schema of the current database. Schema is generated as a set of expressions, like R[A,B].
printTableHead(Q, ...) ; Prints only first row of tables expressed by Q queries. That row consists of the column names.
printTable($file "F", Q, A, ...) ; Prints in F file the tables expressed by Q queries. If F name is without extension, procedure prints tables in F directory in separate files, for example R.tab, .... The A parameters are used rarely and necessary only to project a part of table consisting of some A columns.
printTableRows($file "F", Q, ...) ; Prints in F file the Q tables without head (row of column names).
printRelation($file "F", Q, ...) ; Prints in F file the Q relations. Output result is a set of Smans expressions, like R {#1[A 'a',...],#2[...],...}. This output is less visual than tables, but reflects more real Smans representation.
printClass($file "F", Q, ...) ; Prints in F file the Q classes. Each class looks like A {'a', ...}. Any A class is a named set of values and represents union of all A columns. To print A class as column of R table, the Q should be A[R] expression.
print($file "F", E, ...) ; Prints values of E expressions in F file. Here on place of each E may be query expression or simple string in double/single quotes. If E parameters are several, the concatenation of E results will be printed. For example, output result of print(A, "[", B, "]=;") looks like A ...[B ...]=;

The $file "F" parameter may be missing in all these procedures. In this case, system prints output in the Report area (window or API buffer). If Q queries are missing, procedures print all the possible tables, relations, classes and so on. The print() without E parameters prints empty line. Smans enables abbreviations pt, ptr, pr, pc, ps, pth, p for correspondent procedures printTable, printTableRows, printRelation, printClass, printSchema, printTableHead, print.

"..." ;
Q ;
"...{Q}..." ;
All these three statements have the same destination as print("..."), print(Q), print("...",Q,"...") or p("..."), p(Q), p("...",Q,"..."). To print all the simple classes, it is enough to use * on place of Q.

count(Q,...) ;
first(Q,...) ;
last(Q,...) ;
Functions count(), first(), and last(), or c(), f() and l() respectively, are most often used before printing if database is a big. The result of count() is a sum of data elements. The first() gives only one first element, the last() gives last element, from all pointed in parameters.

Examples 3

Try to print all the "schema relations" from 2. Creating....

print("--- DB SCHEMA ---");
printSchema();


Result will be such:

--- DB SCHEMA ---
note[
address,
fellow,
telephone
];
Before printing the note table there is sense in counting number of its rows. Sometimes, printing of table head may be useful also. Below and further all the Smans fragments are separated from printed result by "-----" line.
print("Total notes: ", count(note));
printTableHead(note);

-----
Total notes: 3
note; fellow; telephone; address
Now, it's time to print table at last.
printTable(note);

-----
note; fellow; telephone; address
#2; 'Forman Daniel'; '650 756-9546'; '27 Crestline Ave'
#3; 'Smith Anne', 'Smith Robert'; '400 297-0752'; '10 Seventh Av'
#4; 'Ringer Michael'; '415 506-0111', '503 743-5226'; '4 Broadway Av'
The above is a usual view of printed table. Values inside field are separated by ',' comma, fields are divided by ';' and each row is located in a single line. To print table in external file printTable should have $file parameter.
printTable($file "notedb/notes0.tab", note);
Let's see example of projection note table to fellow and telephone columns.
printTable(note, fellow, telephone);

-----
fellow; telephone
'Forman Daniel'; '650 756-9546'
'Smith Anne', 'Smith Robert'; '400 297-0752'
'Ringer Michael'; '415 506-0111', '503 743-5226'
Below is example of other Smans procedures. Notice, to print only values of fellow class, the '=' is used with =fellow query.
printRelation(first(note));
printClass(fellow);
print("All fellows: ", =fellow);

-----
note #2[address '27 Crestline Ave',
fellow 'Forman Daniel',
telephone '650 756-9546'];
fellow {
'Forman Daniel',
'Ringer Michael',
'Smith Anne',
'Smith Robert'
};
All fellows: {'Forman Daniel', 'Ringer Michael', 'Smith Anne', 'Smith Robert'}
Actually, to print concatenation of the some words with query result, the string like below seems more advanced. Here we print only fellows related with notes.
"Note`s fellows: {=fellow[note]}";

-----
Note's fellows: {'Forman Daniel', 'Ringer Michael', 'Smith Anne', 'Smith Robert'}

4. Selecting class elements

Constructions 4

Q ; The Q denotes query expressed in Smans language. Goal of any query is to defined value of class existent in database. For example, statement consisting of class name or their composition with each other is a query, if those names are present without correspondent values. The A 'a' expression says about 'a' value of A class and it is not query. In this case, query should be enclosed as ?{A 'a'} or looks like {A='a'} or A{.='a'}. Expression is a query if includes some indefinite symbols, for example such as '%' - any term (name or value), '*' - any name, '.' - any value. The '%' is used independently or with symbol sequence in name or value. For example, '%man%' reflects value as indefinite string with man sequence. It is useful to remember that '%' denotes any string value, #% - any identifier, and 0% - any number. Below there are more detail query constructions.

=Q ; This expression reflects only value, no class names.

{Q & Q1} ; or Q intersect Q1 ;
{Q | Q1} ; or Q union Q1 ;
{Q ! Q1} ; or Q except Q1 ; These important expressions define known algebraic operations on the sets of elements. If ',' is located inside of {}, like {Q,Q1}, result is union as for '|' expression.

Q[Q1 |/&/, ...] ; Selects elements of Q classes having relation with Q1 classes or/and/, so on. The '|', '&', and ',' inside of [] executes predicative logic with possible comparison. The ',' has the same meaning as '&' inside of []. To make the set operation, we need to use braces inside of brackets, like Q[{Q1&Q2}]. The definition includes following, more detail.

Q[Q1 =/>/</>=/<=/!= E |/&/, ...] ; Selects elements of Q classes having relation with Q1 classes, which values are defined by E expression (equal/more/...) and so on. Simple example in XPath style may be such: A[A1 >= 'a1']. It is adequate to the RESTRICTION of the relational algebra: A WHERE A1>= 'a1'. In Smans, on place of any Q or Q1 query a complex expression is supposed, not only simple class (or column) name, like A. On place of E expression a query or values of some type are implied. 

Examples:
A[B={#1,'a', 23.9}] ; Considers B equal to one of the three possible values.
{A,B}[{C,D}>1] ; Selects A and B related with C or D.

A[D[E='%er']] ; Here E equals to any string value ended with 'er'.
A[B>C,D] ; The all B values are more then maximal value of C.

Q[. =/>/</>=/<=/!= E |/&/, ...] ;
{Q =/>/</>=/<=/!= E |/&/, ...} ;
Q{. =/>/</>=/<=/!= E |/&/, ...} ;
Q{ =/>/</>=/<=/!= E |/&/, ...} ; All these constructions are equal and select elements of Q classes, which values are defined by E expressions and so on. On place of E expression a query or values of any type are implied. First construction is inherited from XPath. Nevertheless, semantically more preferable to enclose the values inside of {}, and relation inside of [].

Examples:
*{.!=C}[B] ; Selects elements having values different to C (values of C) and related with B class.
A{=#%} ; Selects A elements with any identifier (#%).
A{>0 & <6} ; Selects A elements more than 0 and less than 6.
A%{1 - 5} ; Selects A... elements with values between 1 and 5.
Q{E1 - E2} ; or Q{E1 to E2} ; Queries express a range of values.
Example:
A%{1 - 5} ; Selects A... elements with values between 1 and 5.
All the complete expressions (statements) are separated by the ';'. If statement ends with '=', like D =, the operand D is a description, not query (or request). See A.Reference... about all the Smans operators, ordered from highest to lowest precedence. Consecution of operators is executed from left to the right.

Examples 4

Return back at the previous 3 example. We consider some notes in the note table. Remember that many examples in each next division further are the continuation of examples from the previous divisions, in this document.
note
fellow telephone address
#2
'Forman Daniel' '650 756-9546' '27 Crestline Ave'
#3
'Smith Anne', 'Smith Robert' '400 297-0752' '10 Seventh Av'
#4
'Ringer Michael' '415 506-0111', '503 743-5226' '4 Broadway Av'

Following request reports some elements that belong to the telephone class and related with note class of elements.
telephone[note];
Result in the Report area:
telephone {
'400 297-0752',
'415 506-0111',
'503 743-5226',
'650 756-9546'
};
Let's image telephones related with notes #3 or #4. Beside the following fragment, telephone[note{.={#3,#4}}] has the same meaning.
telephone[note = #3 | note = #4];
-----
telephone {
'400 297-0752',
'415 506-0111',
'503 743-5226'
};
To print all the notes having definite relation it is possible to use note[*], but it will run slower than simple note query getting all the elements of note class.
note[*];
-----
note {
#2,
#3,
#4
};
Following fragment prints two statements about note classes having relation with fellow 'Ringer Michael' and having relation with other.
note[fellow = 'Ringer Michael'];
note[fellow != 'Ringer Michael'];
-----
note #4;
note {
#2,
#3
};
If we want to print correspondent notes and telephones with code less than 416, following statements may be helpful.
telephone{. < '416'};
note[telephone < '416'];
-----
telephone {
'400 297-0752',
'415 506-0111'
};
note {
#3,
#4
};
To telephone feature of example above let's add fellow. Statement may have view note[telephone<'416'&fellow='Ringer Michael'] or as below.
note[telephone < '416'][fellow = 'Ringer Michael'];
-----
note #4;
Following are expressions printing telephones with area code in range between 100 and 415. The 416 will not be printed in any case if numbers are longer than 3 digits ('416' < '416 000-0000').
telephone{. = ('100' to '416')};
note[telephone{. = ('100' to '416')}];
-----
telephone {
'400 297-0752',
'415 506-0111'
};
note {
#3,
#4
};
Now examples of the set theory are suggested.
note[*] except note[fellow = 'Ringer Michael'];
"--";
note[*] intersect note[fellow = 'Ringer Michael'];
"--";
note[*] union note[fellow = 'Ringer Michael'];
-----
note {
#2,
#3
};
--
note #4;
--
note {
#2,
#3,
#4
};
Finally let's output all the notes that have relation with 'Ringer...'.
note[* = 'Ringer%'];

-----
note #4;

5. Navigation through the relations

Constructions 5

Q / Q1 ; Is path to elements of Q1 class directly related with elements of Q class.

Q // Q1 ; Is path to elements of Q1 class indirectly related with elements of Q class.

Smans enables a direct access to any class, so /Q or //Q are not necessary, unlike XPath working with hierarchic XML. Remind that according to XPath A[B/C] is a predicate expression and denotes selection of A related with B that related with C. It is not suitable sometimes, but alack, compatibility with XPath more important :( and Smans has the same consecutive interpretation of A[B/C]. So, navigation due to path expression inside of brackets is executed in reverse order. Smans database system will pass from C to B, then search A elements related with the found B elements. If path is outside of brackets, Smans navigates rightly from left queries to the right.

Examples 5

We have table existent already in database:
note
fellow telephone address
#2
'Forman Daniel' '650 756-9546' '27 Crestline Ave'
#3
'Smith Anne'
'Smith Robert'
'400 297-0752' '10 Seventh Av'
#4
'Ringer Michael' '415 506-0111'
'503 743-5226'
'4 Broadway Av'

Let's add new another table related with previous through the fellow column:
fellow birthday profession
'Forman Daniel'
'Mann Arthur' '1979/04/04' 'developer'
'Ringer Michael' '1973/05/20' 'database admin'
'Smith Anne' '1981/02/13' 'Web designer'
'Smith Robert' '1982/12/01' 'group manager'

To print all classes having relation with note, we can use not only *[note] or [note], but also note/* or note/. Let's try last statement.
note/;

-----
address {
'10 Seventh Av',
'27 Crestline Ave',
'4 Broadway Av'
},
fellow {
'Forman Daniel',
'Ringer Michael',
'Smith Anne',
'Smith Robert'
},
telephone {
'400 297-0752',
'415 506-0111',
'503 743-5226',
'650 756-9546'
};
Following statements print fellow elements related and non-related with note class.
note/fellow;
fellow ! note/fellow;

-----
fellow {
'Forman Daniel',
'Ringer Michael',
'Smith Anne',
'Smith Robert'
};
fellow 'Mann Arthur';
Database has two fellow 'Smith%' elements. To get all telephones related with their, there are few possible statements, for example fellow{.='Smith%'}/note/telephone or telephone[note/fellow{.='Smith%'}]. Below is other '//' statement.
fellow{. = 'Smith%'}//telephone;

-----
telephone '400 297-0752';
To find fellows of profession including words 'Web' or 'developer' we can use statement fellow[profession{.={'%Web%','%developer%'}}]. Below, slightly simpler expression is presented and it is used as a step of '/' path expression.
birthday{. > '1975'}/fellow[profession{'%Web%', '%developer%'}];

-----
fellow {
'Mann Arthur',
'Smith Anne'
};

6. Updating data

Constructions 6

D = Q ; Statement adds values expressed by Q query to D classes. Here, D means class names. Really, D expression before '=' is description, that is D names are created if they are not existent in database.
Q != Q1 ; Deletes Q1 values from existent Q classes.

Smans (basic language) does not define type of class. Nevertheless, sometimes, definition of possible class values helps to control a creation of class relations.
Examples:
month = {1,2,3,4,5,6,7,8,9,10,11,12};
vacation #[month = 13] =; This description will not be executed, because {month = 13} is not existent.
A1 == A0 ; Changes name of a class from existent A0 to a new, A1. Remind that Smans database is a class-relational. Changing of A0 class means changing of A0 relation that A0 class represents.
A1 'a1' == A0 'a0' ; Statement changes name of an element from A0 'a0' to A1 'a1'. Here, for A0 'a0' element, we change not only class name but also a class value. All the correspondent A0 'a0' relations will be also changed, for example A0 a0[B 'b'] -> A1 a1[B 'b']. Usually developer change only value of class (column), in this case, statement will have view A0 'a1' == A0 'a0'.

Q1 -= Q ; Forms Q1 relation based on the Q relation. The Q1 and Q classes should be existent already and have equal values. To create new A1 duplicate of A relation, we need to use two statements: A1 = A; A1 -= A.
A1 'a1' -= A 'a' ; Forms new A1 'a1' relation based on the A 'a' relation. For example, if A 'a'[B 'b'] relation exists in database (DB), that statement forms another additional A1 'a1'[B 'b'] relation.

Q0  != ; This is a general view of statement that clears class elements. The Q0 is considered as complete query. Simple example, A!= clears all elements of A class. By default E operand (and its parts) inside of E!= statement is a query. To delete a last class element, we can use A # !=  in place of last(A) !=  .
Q1[Q2]  != ; Clears relation of Q1 elements with other Q2 elements. For example, A 'a'[B]!= clears relation of A 'a' element with all elements of B class. Be careful, in case of {Q1[Q2]}!= the statement clears all the elements found by Q1[Q2] query.

Q[D] =
; Creates relation for existent Q elements with other new or existent D elements. Such type of statement is the same as D[D1]= described already in 2. Creating table relations. Remind that Q sign denotes query, D is a description. To get existent elements we need to use ?{Q} or other query form described in 4. Selecting class elements and 5.Navigation through the relations.
Examples:
A #1[B] !=; Before to set a new A[B] relation for A #1, this statement deletes old existent.
{A=#1}[B>'b'] =; Sets A[B] relation for existent A #1 with B elements that have value more than 'b'.
?{A#}[B#] =; Sets
A[B] relation between existent last A# element and new B# element. 

Examples 6

Go back to the previous Example 5. We need to set new phone class name in place of old telephone. Beside this, 415 506-0111 telephone number should be changed.
phone == telephone;
phone '415 506-0999' == phone '415 506-0111';
Suppose that Smith couple is separated and we place Smith Anne in other note record.
note[fellow 'Smith Anne'] !=;
note #[fellow 'Smith Anne'] =;
Now we set a phone element to the last note.
?{note #}[phone '511 666-3344'] =;
Anne has still the same address as Robert, only phone is other 511 666-03344.

?{note[phone '511 666-3344']}[?{fellow 'Smith Robert'//address}] =;

Smith Robert is not interesting us and following fragment deletes correspondent note and fellow record. By the way, second statement deletes all the fellows missing in note class (table).

{note[fellow 'Smith Robert']} !=;
{fellow ! [note]} !=;


Let's print all the current tables in our database.

"-- ISSUE DATABASE --";
printTable();

-----
-- ISSUE DATABASE --
fellow; birthday; profession
'Forman Daniel'; ;
'Ringer Michael'; '1973/05/20'; 'database admin'
'Smith Anne'; '1981/02/13'; 'Web designer'

note; fellow; phone; address
#2; 'Forman Daniel'; '650 756-9546'; '27 Crestline Ave'
#4; 'Ringer Michael'; '415 506-0999', '503 743-5226'; '4 Broadway Av'
#5; 'Smith Anne'; '511 666-3344'; '10 Seventh Av'
Just in case save notes from #4 to #10 in a new note2008 table. First statement below creates note2008 class which values coincident with existent notes in range from #4 to #10.

note2008 = note{#4 - #10};
note2008 -= note;
"-- NEW TABLE --";
printTable(note2008);
-----
-- NEW TABLE --
note2008; fellow; phone; address
#4; 'Ringer Michael'; '415 506-0999', '503 743-5226'; '4 Broadway Av'
#5; 'Smith Anne'; '511 666-3344'; '10 Seventh Av'

7. Set variable

Constructions 7

$x := E ; Assigns E elements to $x variable. The E may be not query, for example in form A{1,2} or 'abc'. In other case, if E represents the class name or set of class names without values, this E expression is not query also for := assignement. We can use a variable later inside of query, for example ?{$x}. If query is needed during assignment, we can make a query through the $x:=?{E}. In place of $x:=A 'a', a query is expressed also in $x:=A{='a'} statement.

$x = E ; Assigns E values to $x variable. The E is not query if values are defined directly in the E. To clear a variable (and clear a correspondent memory), this $x={} statement works.

$x = ;
$x != ; The variable may be helpful for database updating, not only for the following queries. For example, if system meets $x= expression, it means D= description and elements of $x will be assigned to database. To delete all the $x elements from database, this simple $x!= is enough quite.

REMARK: if variable name coincides with database name, we need to use $var category, for example $var x.

Examples 7

Let's print the current note table and then $note variable containing notes related with Ringer.
printTable(note);
$note := note[* = 'Ringer%'];
$note;

-----
note; fellow; phone; address
#2; 'Forman Daniel'; '650 756-9546'; '27 Crestline Ave'
#4; 'Ringer Michael'; '415 506-0999', '503 743-5226'; '4 Broadway Av'
#5; 'Smith Anne'; '511 666-3344'; '10 Seventh Av'

note #4;
Now in place of note #4 (or something more complex) we can use $note variable in a query.
fellow[$note];

-----
fellow 'Ringer Michael';
Variable may be used not only to keep elements, but also class names and values. Below the $phone variable keeps phone that is a class name used in the following queries. The $x variable gets some values of phone class existent in database.
$phone := %ph%;
$x = {$phone != '415%'};

Following fragment prints $phone and $x variables in a string context.
"$phone := {$phone};";
"$x = {$x};";

-----
phone := {phone {'415 506-0999', '503 743-5226', '511 666-3344', '650 756-9546'}, work_phone '503 743-5226'};
$x = {'503 743-5226', '511 666-3344', '650 756-9546'};

8. Table manipulation, exporting and importing

Constructions 8

readTable($file "F", N0, N1, ...) ; Reads 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. See 2. Creating table relations. If there are not N0, N1, ..., all the columns will be input.

printTable($file "F", Q, A, B, ...) ; Prints table in F file. Table is expressed by Q query and has column names A, B, .... This procedure is considered in 3. Printing database contents. There is procedure name contraction, pt(...). Any parameter may be missed. If the A, B, ... are absent, column names will be output all in the 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(A{#1-#1000}, A, B, B.C). Really it is supposed, that there are two tables A[B], B[C]. Simultaneously, the B column is primary key for B table and foreign key for A table.

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

addColumn(table, column0, column1) ; Adds column1 after column0 in the table. The ac() is abbreviation. This procedure helps not only to add new column, but also change column order if column1 exists already. Only first key column in the table remains invariable.

The basic language constructions are enough for other manipulation with usual columns of table. For example to rename column (or table itself) the column1 == column0 statement is quite suitable. To delete column, we need to use column0 != . Nevertheless, there is specific cases, for example with column name beginning with '@' symbol. The @name column may be considered only regarding with some table, not independently. This Smans' exception breaks the class-relational conception of class as unification of several columns with one name. Several @name columns consist of unique elements even if these elements have equal values. So, to rename and delete @column, we need to use special procedures. The same is regarding also to name in double quotes, like "column", see 9.Limitation section.

renameColumn(table, @column0, @column1) ; Changes column name for table from @column0 to @column1. The rc() is abbreviation of this procedure.

deleteColumn(table, @column) ; Deletes @column in the table. The dc() is possible abbreviation.

Examples 8

First of all let's print the current database we formed in the previous examples. Database keeps schema of 3 tables fellow[birthday, profession], note[fellow, phone, address], note2008[fellow, phone, address].
pt();
-----
fellow; birthday; profession
'Forman Daniel'; ;
'Ringer Michael'; '1973/05/20'; 'database admin'
'Smith Anne'; '1981/02/13'; 'Web designer'

note; fellow; phone; address
#2; 'Forman Daniel'; '650 756-9546'; '27 Crestline Ave'
#4; 'Ringer Michael'; '415 506-0999', '503 743-5226'; '4 Broadway Av'
#5; 'Smith Anne'; '511 666-3344'; '10 Seventh Av'

note2008; fellow; phone; address
#2; 'Forman Daniel'; '650 756-9546'; '27 Crestline Ave'
#4; 'Ringer Michael'; '415 506-0999', '503 743-5226'; '4 Broadway Av'
#5; 'Smith Anne'; '511 666-3344'; '10 Seventh Av'
We are interested in a join of the first two tables, note and fellow. See below fellow projection of that joined table.
pt(note, fellow, address, phone, fellow.birthday, fellow.profession);
-----
fellow; address; phone; birthday; profession
'Forman Daniel'; '27 Crestline Ave'; '650 756-9546'; ;
'Ringer Michael'; '4 Broadway Av'; '415 506-0999', '503 743-5226'; '1973/05/20'; 'database admin'
'Smith Anne'; '10 Seventh Av'; '511 666-3344'; '1981/02/13'; 'Web designer'
To connect directly fellow with address and phone, in other words to form table fellow[address, phone, birthday, profession], we can print aforesaid table in external file through the pt($file"fellow.tab",<the same parameters>) and then read it rt($file "fellow.tab").

Another way is illustrated below. First statement prints in note.tab file the note table with current existent header note; fellow; phone; address. Then, next statement reads only fellow; phone; address . It's all. Joined table is formed in database. Because note and note2008 tables are not necessary they are deleted. Last statement prints resulted database, which contains only one join table, fellow, with added phone and address columns.
pt($file "notedb/store1/note.tab", note);
rt($file "notedb/store1/note.tab", 2, 3, 4);
note% !=;
pt();

-----
fellow; birthday; profession; phone; address
'Forman Daniel'; ; ; '650 756-9546'; '27 Crestline Ave'
'Ringer Michael'; '1973/05/20'; 'database admin'; '415 506-0999', '503 743-5226'; '4 Broadway Av'
'Smith Anne'; '1981/02/13'; 'Web designer'; '511 666-3344'; '10 Seventh Av'
Let's rename profession column to profile and change heading order to fellow;phone;address;birthday;profile.
profile == profession;
ac(fellow, fellow, phone);
ac(fellow, phone, address);
pt();

-----
fellow; phone; address; birthday; profile
'Forman Daniel'; '650 756-9546'; '27 Crestline Ave'; ;
'Ringer Michael'; '415 506-0999', '503 743-5226'; '4 Broadway Av'; '1973/05/20'; 'database admin'
'Smith Anne'; '511 666-3344'; '10 Seventh Av'; '1981/02/13'; 'Web designer'

9. Limitation in class names and values

Constructions 9

There are following types of class value possible in Smans language:
N - integer number. The maximal value is 2147483647 (for non-commercial version);
N.N - fractional number. The maximal value is 2147483647.999999. Digits (at least 0) must be before point. Maximal number of digits after point is 6;
'...' - single quoted string. Inside of ' quotes may be any symbol except the same ' single quote;
#S - identifier. Any symbol may be in S sequence except special $'#\"*%({[)}] :`/=<>!&|?,;  The '.' and '-' may be used as joining symbols.

Possible simple class names are represented in the following view:
A - usual simple name. Such name begins with letter and contains any symbol except special (as #S). The '.' and '-' are used as joining symbols;
"..." - double quoted name. Any symbol, except ", may be inside of "..." quotes. The "..." is useful if name includes special symbols including blank.
@S - At-name. The same rule as for #S is acceptable for possible S symbols.

Maximal length of name or value is 252 symbols (for non-commercial version). If number does not conform to specified criteria, it is taken to be non-numerical value. Numerical values may be useful for correct order of output data. It regards to identifier also, that is #9 < #10, whereas a10 < a9, '10' < '9'.

There is limitation for relations including attributes with "..." or @S names. For example A 1[B 2]= statements, beside A[B] relation, forms in database classes A and B. Elements of such classes are accessible independently. For example, B query gives B 2 element. In case of A 1[@B 2]= or A 1["B" 2]= , @B or "B" elements are not independent and are accessible only through the A key class, for example by queries A/@B or @B[A].


Examples 9

These examples show some exceptional situations the user should foresee working with specific names and values. The pr() procedure below, that is printRelation(), prints all the relations formed in notedb/temp database by only one statement office 'billing' [employer 0100, @comment 'unknown',  "basic support" 'billing'] = . As result two classes, employer and office, are accessible directly, no more.
$base "notedb/temp" !=;
"-- office RELATION --";
office 'billing' [employer 0100,
@comment 'unknown',
"basic support" 'billing'] =;
pr();

-----
-- office RELATION --
employer[] 100[office 'billing'],
office[] 'billing'[@comment 'unknown',
"basic support" 'billing',
employer 100];

Following statements check query with @... attributes. Remind that "..." attributes have the same features as @....
"-- office CHECKING --";
"AVAILABLE CLASSES";
*;
"CLASSES RELATED WITH @comment";
*[@comment];
[employer]; -- works
[@comment]; -- does not work
*[@%]; -- does not work

-----
-- office CHECKING --
AVAILABLE CLASSES
employer 100,
office 'billing';
CLASSES RELATED WITH @comment
office 'billing';
office 'billing';
;
;
Let's create "basic support" as key independent class. It is possible. Before it was attribute class dependent on employer key class. The office class is not needed more and we delete in the first statement.
'-- "support" RELATION --';
office !=;
"basic support" 'billing'[employer 0100,
@comment 'unknown'] =;
pr();

-----
-- "support" RELATION --
"basic support"[] 'billing'[@comment 'unknown',
employer 100],
employer[] 100["basic support" 'billing'];
The "..." simple statement is used to print string's content. Following are example of queries where "..." is a class name.
'-- "support" CHECKING --';
"basic support" .;
{"basic support", "any"};

-----
-- "support" CHECKING --
"basic support" 'billing';
"basic support" 'billing';
Last example demonstrates ordering of values, which is automatic in Smans. First statement makes non-suitable very long numbers. System takes their but orders as sign sequences, not numbers. So, they are placed last in the printed sequence.
"-- ORDERING --";
employer {121474836470, 1111111111111111111111111111} =;
employer 2147483647.999999 =;
employer {#100, '100', 100} =;
employer;

-----
-- ORDERING --
employer {
100,
2147483647.999999,
'100',
#100,
1111111111111111111111111111,
121474836470
};

10. Meaning and qouting

Constructions 10

meaning(...) ; The meaning() or m() function assumes parameters as Smans expressions and result will be execution of that expressions. Usually parameters are enclosed in ' quotations. By default parameters are queries. System recognizes description by existence of  '; ' or for D= construction. For example, the m("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.

quote(E, S) ; Quotes E as S-quoted string. The optional S may be double that denotes "..." strings as result. To produce '...' strings, S may be missing or be single. Contraction of quote() is q().

unquote(E, S) ; Unquotes E from S-quoted string. The optional S may be double or single, but usually is not used. In last case, unquoting is automatic. Contraction of unquote() is $uq().


Examples 10

After R[A #, B #][]= statement the database will contain relation like R #1[A #1,B #1]. Then we create query 'A[R]'[subject 'A']= relation to show how Smans query may be saved and got. 

R[A #, B #][] =;
query 'A[R]'[subject 'A'] =;
p("Meaning of query=", =query);
meaning(=query);
$xq = query[subject = 'A'];
p("Meaning of $xq=", $xq);
meaning($xq);

-----
Meaning of query='A[R]'
A #1
Meaning of $xq='A[R]'
A #1

Following is example of the $xd description and $xq query meaning. The m() is  abbreviation of meaning() .

description 'R[A #, B #][]'[subject 'R'] =;
$xd = description[subject = 'R'];
m($xd) =; -- first
p("Meaning of $xq=", $xq, " after first $xd=", $xd);
m($xq);
m($xd) =; -- second
p("Meaning of $xq=", $xq, " after second $xd=", $xd);
m($xq);

-----
Meaning of $xq='A[R]' after first $xd='R[A #, B #][]'
A {#1, #2}
Meaning of $xq='A[R]' after second $xd='R[A #, B #][]'
A {#1, #2, #3}

It is permissible to use the set as parameter of m(...) function.

query 'B[R]'[subject 'B'] =;
$xqs = query '%[%R%]%';
p("Meaning of the set $xqs=", $xqs);
m($xqs);

-----
Meaning of the set $xqs={'A[R]', 'B[R]'}
{A {#1, #2, #3}, B {#1, #2, #3}}

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

$xqs1 := unquote($xqs);
$xqs2 := quote(first($xqs1));
p("Meaning of first query ", $xqs2, " from ", $xqs);
m($xqs2);

-----
Meaning of first query 'A[R]' from {'A[R]', 'B[R]'}
A {#1, #2, #3}

11. Program objects

Constructions 11

#po.S.new (...) ; Creates new program object. The S subject of this point-expression is name of program class.
#po.S.s(...) ; Point expression invokes s method for S program class. Really it invokes the s static method of the S Java class.
#po.S.n.s(...) ; Point expression invokes s method for program object of S class and stored with #n identifier.

It is possibly to get fields of program class or object:
#po.S.s  ; It is access to s field of #po.S program class. Really the s is a static variable of the S Java class.
#po.S.n.s ; Is access to  s field of #po.S.n program object.

Smans 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 Smans we can also create such program object, but expression will be another, $x := #po.java.io.File.new("Note"). Name of program class in Smans begins with "#po". The variable $x does not have type, we can assign to it anything. Really, in last 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 Smans statement gives to $y variable the absolute path of "Note" file (like  C:\project\demo\Note for Windows): $y := $x.getAbsolutePath();

It is very important to mark some features of work with int, double, boolean and  String Java objects in Smans language. Such object and their types are expressed directly via real name. 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, look at {#po.java.lang.System.out}.println("file1.txt"). These object names cannot be subject of Smans point-expression. For example, to define length of "file1.txt" string, we need to use #po.java.lang.String.new("file1.txt").length(), the "file1.txt".length() is not correct.

Smans 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 single or double. A mapState(..., single) maps program objects with the attribute values quoted like '...'. For a mapState(..., double) attribute values are enclosed in "...".


Examples 11

Example below demonstrates the using of a Date Java program object, more exactly its toString method, through the meaning() function.

$date := DATE '#po.java.util.Date.new().toString()';
"START {meaning($date)}";

-----
START DATE:Fri Oct 02 12:08:09 MSD 2009

The Vector is well known and useful Java class. Let us create Vector object and print it's Smans name, which looks like #po.java.util.Vector.<number>. In the Java, internal name of such object has slightly other view like java.util.Vector@02a.

$v := #po.java.util.Vector.new();
$v;

-----
#po.java.util.Vector.1;

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);
$v0;

-----
red;

Following example demonstrates a using of the mapState() procedure. Before mapState() we create the point class with two values, which represent identifiers of Point Java objects.

point {
  #po.java.awt.Point.new(1,2),
  #po.java.awt.Point.new(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 that there is necessity to change the Point object from coordinates x=3, y=4 into a state with coordinates x=4, y=5 by means of move() Java method. We call move() method for $x variable, which keeps point elements found by means of point[x=3,y=4] query. To check all the current attributes of object, the state() Smans function may be helpful. Statement before last produces the same as mapState().

$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 String object may be saved, for example by po #po.java.lang.String.... =, and then get by $z=po... and changed in other Smans session. Program classes usually exist separately from database in the program library. Only placing its names in #po... identifier makes sense for Smans. 

po #po.java.lang.String.new({'a','b','c'}) =;
$z = po;
$z;

-----
#po.java.lang.String.16,
#po.java.lang.String.20,
#po.java.lang.String.21;

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

$z.toString();
$z.concat({"1","2","3"});

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

Below is example of executing the outside programs via current Java Runtime, for example calculator of the Microsoft Windows.

$xrun = #po.java.lang.Runtime.getRuntime();
"SEE CALCULATOR";
$xrun.exec("calc.exe");

-----
SEE CALCULATOR

12. Multilevel classification

Constructions 12

Descriptions

A: B: ... = ; Creates multilevel class, for example, A:B 'b'=.
A[D1, ...]: B[D2, ...]: ... = ; Creates relation for multilevel class or multilevel relation, for example, A1:A2 'a'[B1:B2 'b']=.

Class hierarchy is a tree of class names. Such names are separated by ':' colon. The ':' colon sign is universal and may be used to separate names with values also, for example A1:{'a1', A2:'a2'}=. Each branch of a tree ends up with a set of leaves or in our case a set of values. Values in such tree are not necessary in Smans language. That is we can create class with indefinite values, for example animal:dog= . It is equal to empty dog class, which belongs to animal class. In context with tabular representation, empty dog table belongs to animal set of tables. It is possible to set a relation directly for class names, not only for values, for example, animal:dog[sound 'bark', size, color]=.

Queries

A{} ; This expression helps to select class name only, ignoring its values.
A:B:... ; This is a query for classes with complex names, for example A:B.
A::B::... ; Query like this denotes that A and B names may not be connected directly with each other. For example A1::A3 may give A1:A2:A3 'a' element.
C: ; This query is equal to C{}:%. Any name ':' composition is supposed on place of C. For example A1:A2: may give A1:A2{}:{A3, 'a'} elements or only A1:A2 if A1:A2 class is empty.
C:: ; This query is equal to C{}::%. Statement requests the all elements belonging to C class. For example A1:A2:: may give A1:A2:A3:A4 'a' element.
C:[Q] ;
C::[Q] ; In difference to C: and C:: these queries find complex elements of C class having relation with Q class.
:C ;
::C ; Statements are the simple variants of *:C and *::C queries. For example, ::A3 may give A1:A2:A3 'a' element. In last case, the :A3 does not work, but works the :A2.

For previous animal:dog[sound 'bark', size, color]= example, query animal:: gives us whole animal class, which is animal:dog. To find class names featured by sound 'bark', query should have a view animal::[sound 'bark'] or even simpler [sound 'bark']. In last case result includes animal class but may be wider. To use size name as attribute in a query we should use animal::[size{}].

Usual simple names are not repeatable in a usual complex name. For example, A:A is not possible. To avoid such problem a complex name has to begin with @ at-name or "..." double quoted name, for example @A:A:A. One notice, queries with @ and "..." names works slower sometimes. Moreover, :C and
::C queries do not work for such names.

Examples 12

Let us classify by Smans language the elements of the contact category with necessary properties: phone and address. Other affiliation, hobby, profession properties depends on the terminal subcategory.
$base "notedb/mydata" !=;
@category
[@property]:contact[@property:phone]:{
known_person[@property:address]:{
relative[@property:affiliation],
fellow[@property:hobby,
@property:profession]
}
} =;
Following are few variants of query with correspondent results.
pr(@category:%);
pr(@category:);
pr(@category::);
-----
@category:contact[@property:phone];
@category[@property]:contact[@property:phone];
@category[@property]:contact[@property:phone]:
known_person[@property:address]:{
fellow[@property:{hobby,profession}],
relative[@property:affiliation]
};
To get the fellow elements of @category class we can use following statements:
@category::fellow{};
@category::[@property::phone{}, @property::profession{}];
-----
@category:contact:known_person:fellow;
@category:contact:known_person:fellow;
Now let's create contact complex class with usual names and relation defined by this class. The pr() prints this relation.
contact:known_person:{
relative #[phone #, address #, affiliation #],
fellow #[phone #, address #, hobby #, profession #]
} =;
pr(contact::);
-----
contact[]:known_person[]:{
fellow[] #1[address #2,
hobby #1,
phone #2,
profession #1],
relative[] #1[address #1,
affiliation #1,
phone #1]
};
Because fellow is a subclass, to print it we can use the ::fellow statement. The simple fellow query does not work.
::fellow;
-----
contact:known_person:fellow #1;
Below are some query variants for testing. First statement with % reflects all elements even if they do not have values. Second reflects only names. Third statement reflects all elements with values. Fourth gives last value element.
contact::%;
contact::*{};
contact::.;
contact::#;
-----
contact:known_person{}:{
fellow{} #1,
relative{} #1
};
contact:known_person{}:{
fellow,
relative
};
contact:known_person:{
fellow #1,
relative #1
};
contact:known_person:relative #1;
Now let's get all the contacts featured by phone and profession .
contact::[phone, profession];
-----
contact:known_person:fellow #1;
If we need to find all known_person except the contact namely fellow, we can use following statement.
{::known_person:: ! contact::fellow}.;
-----
contact:known_person{}:relative #1;

A. Language Reference

Symantec designations ('|' separator and '...' trailing ellipsis are special symbols):
E                Expression
Q                Request in statement: Q; | =Q; | Q!=; | Q!=Q; | D=Q; | ?{Q,...};
D                Description in statement: D=; | D=Q;
R|R 'r'          Relation name in relation: R[E] | R 'r'[E]
A|B     Simple class name (or term) in class: {A{'a',...},B{'b',...}} | A:{B:...,...}
'a'|'b' Class value (or term) in class: {A{'a',...},B{'b',...}} | A:{'a', B 'b',...}
A:B:...          Complex class name in class: A:{B:...,...}.
A 'a'|B|'b'      Element name in class: A{'a',...}|{B,...}|{'b',...}
Syntax notation in EBNF:
K    Key symbol         "$" | "'" | "#" | "." | "@" | "\"" | "*" | "%" | "(" | "{" | "[" | ")" | "}" | "]" 
| " " | ":" | "`" | "/" | "-" | "=" | "<" | ">" | "!" | "&" | "|" | "?" | "," | ";"
C    Non-key character
L    Letter
D    Digit
I    Integer            D+
N    Number             I | I.I | "0%"
W    Word               C(C|"."|"-")*
S   Sequence "%"?(W"%"?)+ | "%"

Id   Identifier "#" | "#"S
On Object name #po.L+("."L+)*(.I)?
Sv   String value "'"(K|C)*"'"
(or single quoted string)
Vl   Class value   "." | N | Id | On | Sv

Sn   String name "\""(K|C)*"\""
(or double quoted string)
An At-name "@"S
Nm   Class name    "*" | S | Sn | An | W(" "W)*

Tr Class term Vl | Nm
El   Element name       Tr | Nm Vl | Nm:El | Nm::El
Spn Specification name C+ | "'"(C|K-"'")+"'" | "\""(C|K-"\"")+"\""
Spc   Specification     "$"L+" "Spn | "$"Spn
Exp  Expression         El | Spc | Exp K | K Exp | Exp Exp |
Stm  Statement          Exp ("," Exp)*
Scr  Script             Stm (";" Stm)*
Expressions ordered by priority (with special symbols '|' and '...'): 
1  -- ... | (: ... :)        1, 2
1  [Exp, ...]            2, 4, 6
1  {Exp, ...} | ?{Exp}    3, 4, 6
1  (Exp, ...)             4
2  Spc 1, 3, 7, 8
3 Nm | Vl 2, 4, 6, 9
4  W(Exp, ...)           2, 3, 4, 8
4  On(Exp, ...)           11
5 Nm Vl 0, 2, 3, 4
5 Nm:El | Nm::El 12
6  Exp{Exp, ...}        4, 12
6  Exp[Exp, ...]         2, 4, 6, 10
7  Exp/Exp | Exp//Exp    5
7  /Exp | Exp/          5
8  - Exp | Exp - Exp | Exp - 4
Exp to Exp
9  Exp != Exp | Exp = Exp   4
9 Exp > Exp | Exp >= Exp 4
9 Exp < Exp | Exp <= Exp 4
10  = Exp           1, 4
11  Exp = Exp;              1, 6, 7
11 Exp == Exp; 6
11 Exp -= Exp; 6
11 Exp := Exp 7
12 Exp ! Exp 4
Exp except Exp
13 Exp & Exp 4
Exp intersect Exp
14 Exp | Exp 4
Exp union Exp
15  Exp != | Exp =        2, 6, 7
16  Exp, Exp               3, 4
17  Stm; Stm               4, 6
Procedures
rt  |    readTable        2, 8
p   | print            3
pc | printClass 3
pr | printRelation 3
ps | printSchema 3
pt | printTable 3
pth | printTableHead 3
ptr | printTableRows 3
rc | renameColumn 8
ac | addColumn 8
dc | deleteColumn 8
ms | mapState 11
Functions
c   |    count            3
f | first 3
l | last 3
m | meaning 10
q | quote 10
uq | unquote 10
s | state 11