Browse Source

moved csharp frontend to A2 trunk

git-svn-id: https://svn.inf.ethz.ch/svn/lecturers/a2/trunk@6331 8c9fc860-2736-0410-a75d-ab315db34111
felixf 10 years ago
parent
commit
968a9db4c1
4 changed files with 5295 additions and 0 deletions
  1. BIN
      source/Fox.Tool
  2. 39 0
      source/FoxCSharpFrontend.Mod
  3. 3789 0
      source/FoxCSharpParser.Mod
  4. 1467 0
      source/FoxCSharpScanner.Mod

BIN
source/Fox.Tool


+ 39 - 0
source/FoxCSharpFrontend.Mod

@@ -0,0 +1,39 @@
+MODULE FoxCSharpFrontend; (**  AUTHOR "fof"; PURPOSE "Oberon Compiler: CSharp frontend module";  **)
+
+IMPORT
+	Streams, Diagnostics,  SyntaxTree := FoxSyntaxTree, Parser := FoxCSharpParser, Scanner := FoxCSharpScanner, FoxFrontend;
+
+TYPE
+
+	Frontend* = OBJECT (FoxFrontend.Frontend)
+	VAR
+		scanner: Scanner.Scanner;
+		parser: Parser.Parser;
+		
+		PROCEDURE Initialize*(diagnostics: Diagnostics.Diagnostics; reader: Streams.Reader; CONST fileName: ARRAY OF CHAR; pos: LONGINT; activeCells: BOOLEAN);
+		BEGIN
+			Initialize^(diagnostics, reader, fileName, pos, activeCells);
+			scanner := Scanner.NewScanner(fileName, reader, pos, diagnostics);
+			parser := Parser.NewParser( scanner, diagnostics );
+		END Initialize;
+		
+		PROCEDURE Parse*(): SyntaxTree.Module;
+		BEGIN 
+			RETURN parser.Module();
+		END Parse;
+		
+		PROCEDURE Error(): BOOLEAN;
+		BEGIN
+			RETURN parser.error;
+		END Error;
+		
+	END Frontend;
+
+	PROCEDURE Get*():FoxFrontend.Frontend;
+	VAR frontend: Frontend;
+	BEGIN
+		NEW(frontend);
+		RETURN frontend;
+	END Get;
+
+END FoxCSharpFrontend.

+ 3789 - 0
source/FoxCSharpParser.Mod

@@ -0,0 +1,3789 @@
+MODULE FoxCSharpParser;
+(* module originating from Alexey Gokhberg's ActiveCells# Parser *)
+
+IMPORT Strings, StringPool, Diagnostics, D := Debugging, Basic := FoxBasic, FoxScanner,
+    Scanner := FoxCSharpScanner, SyntaxTree := FoxSyntaxTree, Global := FoxGlobal,
+    KernelLog (* DEBUG *);
+
+CONST
+    Trace = FALSE;
+
+    (* modifiers *)
+    Public = 0;
+    Internal = 1;
+
+    LynxCase = FoxScanner.Lowercase;
+
+    invalidPosition = -1;
+
+TYPE
+    LocalIdentEntry = OBJECT
+    VAR
+        next: LocalIdentEntry;
+        level: LONGINT;
+        name: SyntaxTree.Identifier;
+        local: SyntaxTree.Identifier;
+    END LocalIdentEntry;
+
+    LocalIdentTable = OBJECT
+    VAR
+        head: LocalIdentEntry;
+        level: LONGINT;
+        suffix: LONGINT;
+
+        PROCEDURE & Init;
+        BEGIN
+            Reset;
+        END Init;
+
+        PROCEDURE Reset;
+        BEGIN
+            head := NIL;
+            level := 0;
+            suffix := 0;
+        END Reset;
+
+        PROCEDURE OpenScope;
+        BEGIN
+            INC(level);
+        END OpenScope;
+        
+        PROCEDURE CloseScope;
+            VAR p: LocalIdentEntry;
+        BEGIN
+            p := head;
+            WHILE (p # NIL) & (p.level = level) DO
+                p := p.next;
+            END;
+            head := p;
+            DEC(level);
+        END CloseScope;
+
+        PROCEDURE Enter(name: SyntaxTree.Identifier): SyntaxTree.Identifier;
+            VAR p, q: LocalIdentEntry;
+                local: SyntaxTree.Identifier;
+                str: Scanner.IdentifierString;
+        BEGIN
+            IF level = 0 THEN
+                RETURN name;
+            END;
+            p := head;
+            q := NIL;
+            WHILE (q = NIL) & (p # NIL) & (p.level = level) DO
+                IF p.name = name THEN
+                    q := p;
+                END;
+                p := p.next;
+            END;
+            IF q # NIL THEN
+                RETURN q.local;
+            END;
+            Basic.GetString(name, str);
+            Strings.AppendChar(str, "@");
+            INC(suffix);
+            Basic.AppendNumber(str, suffix);
+            local := Basic.MakeString(str);
+            NEW(q);
+            q.level := level;
+            q.name := name;
+            q.local := local;
+            q.next := head;
+            head := q;
+            RETURN local; 
+        END Enter;
+
+        PROCEDURE Find(name: SyntaxTree.Identifier): SyntaxTree.Identifier;
+            VAR p: LocalIdentEntry;
+        BEGIN
+            p := head;
+            WHILE (p # NIL) & (p.name # name) DO
+                p := p.next;
+            END;
+            IF p # NIL THEN
+                RETURN p.local;
+            END;
+            RETURN name;
+        END Find;
+    END LocalIdentTable;
+
+    Parser* = OBJECT
+    VAR
+        scanner: Scanner.Scanner;
+        symbol-: Scanner.Symbol;
+        diagnostics: Diagnostics.Diagnostics;
+        currentScope: SyntaxTree.Scope;
+        recentCommentItem: ANY; 
+        recentLine: LONGINT;
+        recentComment: SyntaxTree.Comment;
+        moduleScope: SyntaxTree.ModuleScope;
+        error-: BOOLEAN;
+        activeCellsSupport: BOOLEAN;
+
+        initStatements: SyntaxTree.StatementSequence;
+        initOuter: SyntaxTree.Statement;
+
+        delegateModifiers: SyntaxTree.Modifier;
+
+        lynxChar: SyntaxTree.Identifier;
+        lynxSbyte: SyntaxTree.Identifier;
+        lynxShort: SyntaxTree.Identifier;
+        lynxInt: SyntaxTree.Identifier;
+        lynxLong: SyntaxTree.Identifier;
+        lynxFloat: SyntaxTree.Identifier;
+        lynxDouble: SyntaxTree.Identifier;
+        lynxBool: SyntaxTree.Identifier;
+        lynxObject: SyntaxTree.Identifier;
+        lynxString: SyntaxTree.Identifier;
+        lynxNewobj: SyntaxTree.Identifier;
+        lynxNewarr: SyntaxTree.Identifier;
+        lynxAsop: SyntaxTree.Identifier;
+        lynxUnop: SyntaxTree.Identifier;
+        lynxBinop: SyntaxTree.Identifier;
+
+        lynxSend: SyntaxTree.Identifier;
+        lynxReceive: SyntaxTree.Identifier;
+        lynxRecvnb: SyntaxTree.Identifier;
+        lynxConnect: SyntaxTree.Identifier;
+        lynxDelegate: SyntaxTree.Identifier;
+
+        lynxNewsel: SyntaxTree.Identifier;
+        lynxAddsel: SyntaxTree.Identifier;
+        lynxSelect: SyntaxTree.Identifier;
+        lynxSelidx: SyntaxTree.Identifier;
+
+        lynxType: SyntaxTree.Identifier;
+
+        identMain: SyntaxTree.Identifier;
+        localIdentTable: LocalIdentTable;
+
+        indent: LONGINT;    (* for debugging purposes only *)
+
+        (** constructor, init parser with scanner providing input and with diagnostics for error output *)
+        PROCEDURE & Init*(scanner: Scanner.Scanner; diagnostics: Diagnostics.Diagnostics);
+        BEGIN
+            SELF.scanner := scanner;
+            SELF.diagnostics := diagnostics;
+            error := ~scanner.GetNextSymbol(symbol);
+            recentCommentItem := NIL; 
+            recentComment := NIL;
+            initStatements := NIL;
+            initOuter := NIL;
+            InitDelegateModifiers;
+            InitSystemNames;
+            StringPool.GetIndex("lynx@type", lynxType);
+            StringPool.GetIndex("main", identMain);
+            NEW(localIdentTable);
+            (* debugging *)
+            indent := 0;
+            activeCellsSupport := FALSE;
+
+        END Init;
+
+        PROCEDURE InitDelegateModifiers;
+            VAR name: SyntaxTree.Identifier;
+        BEGIN
+            StringPool.GetIndex("DELEGATE", name);
+            delegateModifiers := SyntaxTree.NewModifier(invalidPosition, name, NIL);
+        END InitDelegateModifiers;
+
+        (*
+            NOTE: Fox semantical analysis has been extended in order to recognize
+                and properly support the following names of system procedures.
+                Lynx version of FoxGlobal provides the respective bindings.
+        *)
+        PROCEDURE InitSystemNames;
+        BEGIN
+            StringPool.GetIndex(Global.LynxChar, lynxChar);
+            StringPool.GetIndex(Global.LynxSbyte, lynxSbyte);
+            StringPool.GetIndex(Global.LynxShort, lynxShort);
+            StringPool.GetIndex(Global.LynxInt, lynxInt);
+            StringPool.GetIndex(Global.LynxLong, lynxLong);
+            StringPool.GetIndex(Global.LynxFloat, lynxFloat);
+            StringPool.GetIndex(Global.LynxDouble, lynxDouble);
+            StringPool.GetIndex(Global.LynxBool, lynxBool);
+            StringPool.GetIndex(Global.LynxObject, lynxObject);
+            StringPool.GetIndex(Global.LynxString, lynxString);
+            StringPool.GetIndex(Global.LynxNewobj, lynxNewobj);
+            StringPool.GetIndex(Global.LynxNewarr, lynxNewarr);
+            StringPool.GetIndex(Global.LynxAsop, lynxAsop);
+            StringPool.GetIndex(Global.LynxUnop, lynxUnop);
+            StringPool.GetIndex(Global.LynxBinop, lynxBinop);
+            StringPool.GetIndex(Global.LynxSend, lynxSend);
+            StringPool.GetIndex(Global.LynxReceive, lynxReceive);
+            StringPool.GetIndex(Global.LynxRecvnb, lynxRecvnb);
+            StringPool.GetIndex(Global.LynxConnect, lynxConnect);
+            StringPool.GetIndex(Global.LynxDelegate, lynxDelegate);
+            StringPool.GetIndex(Global.LynxNewsel, lynxNewsel);
+            StringPool.GetIndex(Global.LynxAddsel, lynxAddsel);
+            StringPool.GetIndex(Global.LynxSelect, lynxSelect);
+            StringPool.GetIndex(Global.LynxSelidx, lynxSelidx);
+        END InitSystemNames;
+
+        PROCEDURE ActiveCellsSupport*;
+        BEGIN 
+            activeCellsSupport := TRUE
+        END ActiveCellsSupport;
+
+        PROCEDURE S(CONST s: ARRAY OF CHAR);    (* for debugging purposes only *)
+            VAR i: LONGINT;
+        BEGIN
+            D.Ln;
+            INC(indent);
+            D.Int(indent, 1);
+            FOR i := 1 TO indent DO 
+                D.Str("  ");
+            END;
+            D.Str("start: ");
+            D.Str(s);
+            D.Str(" at pos ");
+            D.Int(symbol.start, 1);
+        END S;
+
+        PROCEDURE E(CONST s: ARRAY OF CHAR);    (* for debugging purposes only *)
+            VAR i: LONGINT;
+        BEGIN
+            D.Ln;
+            D.Int(indent, 1);
+            FOR i := 1 TO indent DO 
+                D.Str("  ");
+            END;
+            D.Str("end : ");
+            D.Str(s);
+            D.Str(" at pos ");
+            D.Int(symbol.start, 1);
+        END E;
+
+        PROCEDURE EE(CONST s, t: ARRAY OF CHAR);    (* for debugging purposes only *)
+            VAR i: LONGINT;
+        BEGIN
+            D.Ln;
+            D.Int(indent, 1);
+            FOR i := 1 TO indent DO 
+                D.Str("  ");
+            END;
+            D.Str("end : ");
+            D.Str(s);
+            D.Str(" (");
+            D.Str(t);
+            D.Str(") at pos ");
+        END EE;
+
+        (** output error message and / or given code *)
+        PROCEDURE Error(position: LONGINT; code: LONGINT; CONST message: ARRAY OF CHAR);
+            VAR errorMessage: ARRAY 256 OF CHAR;
+        BEGIN
+            IF diagnostics # NIL THEN
+                Basic.GetErrorMessage(code,message,errorMessage);
+                diagnostics.Error(scanner.source^, position, code, errorMessage);
+            END;
+            error := TRUE;
+(* @@@ *)
+HALT(100);
+        END Error;
+
+        (** helper procedures interfacing to the scanner **)
+
+        (** Get next symbol from scanner and store it in object-local variable 'symbol' *)
+        PROCEDURE NextSymbol;
+            VAR comment: SyntaxTree.Comment;
+        BEGIN
+            error := ~scanner.GetNextSymbol(symbol) OR error;
+            WHILE ~error & (symbol.token = Scanner.Comment) DO
+                comment := SyntaxTree.NewComment(symbol.start, currentScope, symbol.string^, symbol.stringLength);
+                moduleScope.AddComment(comment);
+                IF recentComment = NIL THEN
+                    recentComment := comment;
+                    IF symbol.line = recentLine THEN
+                        IF recentCommentItem # NIL THEN
+                            IF (recentCommentItem IS SyntaxTree.Symbol) THEN
+                                IF recentCommentItem(SyntaxTree.Symbol).comment = NIL THEN
+                                    recentCommentItem(SyntaxTree.Symbol).SetComment(comment)
+                                END;
+                            ELSIF (recentCommentItem IS SyntaxTree.Statement) THEN
+                                IF recentCommentItem(SyntaxTree.Statement).comment = NIL THEN
+                                    recentCommentItem(SyntaxTree.Statement).SetComment(comment)
+                                END;
+                            ELSIF (recentCommentItem IS SyntaxTree.IfPart) THEN
+                                IF recentCommentItem(SyntaxTree.IfPart).comment = NIL THEN
+                                    recentCommentItem(SyntaxTree.IfPart).SetComment(comment)
+                                END;
+                            ELSIF (recentCommentItem IS SyntaxTree.CasePart) THEN
+                                IF recentCommentItem(SyntaxTree.CasePart).comment = NIL THEN
+                                    recentCommentItem(SyntaxTree.CasePart).SetComment(comment)
+                                END;
+(* LYNX+
+                            ELSIF (recentCommentItem IS SyntaxTree.WithPart) THEN
+                                IF recentCommentItem(SyntaxTree.WithPart).comment = NIL THEN
+                                    recentCommentItem(SyntaxTree.WithPart).SetComment(comment)
+                                END;
+-LYNX *)
+                            END;
+                            comment.SetItem(recentCommentItem, TRUE);
+                            recentComment := NIL;
+                            recentCommentItem := NIL
+                        END;
+                    END;
+                END;
+                error := ~scanner.GetNextSymbol(symbol);
+            END;
+        END NextSymbol;
+
+        (** Check if current symbol equals sym. If yes then return true, return false otherwise *)
+        PROCEDURE Peek(token: Scanner.Token): BOOLEAN;
+            VAR comment: SyntaxTree.Comment;
+        BEGIN
+            WHILE ~error & (symbol.token = Scanner.Comment) DO
+                comment := SyntaxTree.NewComment(symbol.start, currentScope, symbol.string^, symbol.stringLength);
+                moduleScope.AddComment(comment);
+                IF recentComment = NIL THEN
+                    recentComment := comment;
+                END;
+                error := ~scanner.GetNextSymbol(symbol);
+            END;
+            RETURN symbol.token = token
+        END Peek;
+
+        (** Check if the current symbol equals sym. If yes then read next symbol, report error otherwise. Returns success value *)
+        PROCEDURE Mandatory(token: Scanner.Token): BOOLEAN;
+        BEGIN
+(* @@@ *)
+(*
+KernelLog.String("Mandatory: want ");
+KernelLog.Int(token, 1);
+KernelLog.String(" have ");
+KernelLog.Int(symbol.token, 1);
+KernelLog.Ln();
+*)
+            (* because of NextSymbol! *)
+            ASSERT(token # Scanner.Identifier);
+            ASSERT(token # Scanner.IntegerLiteral);
+            ASSERT(token # Scanner.RealLiteral);
+            ASSERT(token # Scanner.CharacterLiteral);
+            ASSERT(token # Scanner.StringLiteral);
+            IF ~Peek(token) THEN
+                Error(symbol.start, token, "");
+                RETURN FALSE
+            ELSE
+                NextSymbol;
+                RETURN TRUE
+            END
+        END Mandatory;
+
+        (** Check if the current symbol equals sym. If yes then read next symbol, report error otherwise *)
+        PROCEDURE Check(token: Scanner.Token);
+            VAR b: BOOLEAN;
+        BEGIN
+            b := Mandatory(token);
+        END Check;
+
+        (** Check if current symbol is an identifier. If yes then copy identifier to name and get next symbol,
+            report error otherwise and set name to empty name. Returns success value *)
+        PROCEDURE MandatoryIdentifier(VAR name: SyntaxTree.Identifier): BOOLEAN;
+        BEGIN
+            IF Peek(Scanner.Identifier) THEN
+                name := symbol.identifier;
+                NextSymbol;
+                RETURN TRUE
+            ELSE
+                Error(symbol.start, Scanner.Identifier, "");
+                name := SyntaxTree.invalidIdentifier;
+                RETURN FALSE
+            END
+        END MandatoryIdentifier;
+
+        (** Expect an identifier (using MandatoryIdentifier) and return identifier object **)
+        PROCEDURE Identifier(VAR position: LONGINT): SyntaxTree.Identifier;
+            VAR name: SyntaxTree.Identifier; 
+                identifier: SyntaxTree.Identifier;
+        BEGIN
+            position := symbol.start;
+            IF MandatoryIdentifier(name) THEN
+                identifier := name;
+            ELSE
+                identifier := SyntaxTree.invalidIdentifier;
+            END;
+            RETURN identifier
+        END Identifier;
+
+        (** Check if current symbol equals sym. If yes then get next symbol, return false otherwise *)
+        PROCEDURE Optional(token: Scanner.Token): BOOLEAN;
+        BEGIN
+            (* do not use for Identifier or literal if the result is needed ! *)
+            IF Peek(token) THEN
+                NextSymbol;
+                RETURN TRUE
+            ELSE
+                RETURN FALSE
+            END
+        END Optional;
+
+        (* ignore one ore more symbols of type token *)
+        PROCEDURE Ignore(token: Scanner.Token);
+        BEGIN 
+            WHILE Optional(token) DO 
+                (* void *)
+            END;
+        END Ignore;
+
+        (** Handling comments **)
+
+        PROCEDURE SetNextInComment(c: SyntaxTree.Comment; this: ANY);
+        BEGIN
+            WHILE c # NIL DO
+                c.SetItem(this, FALSE);
+                c := c.nextComment
+            END;
+        END SetNextInComment;
+
+        PROCEDURE CommentSymbol(symbol: SyntaxTree.Symbol);
+        BEGIN
+            IF (recentComment # NIL) (* & (recentComment.nextSymbol = NIL) *) THEN
+                symbol.SetComment(recentComment);
+                SetNextInComment(recentComment, symbol);
+                recentComment := NIL
+            END;
+            recentLine := scanner.line;
+            recentCommentItem := symbol;
+        END CommentSymbol;
+
+        (** Mapping tokens to AST operators **)
+
+(*
+    Mapping table for all punctuation tokens
+
+    Lynx                                     Fox
+    ------------------------------------------------------------
+
+    Exclamation* = 1;         (* ! *)        Not
+    ExclamationEqual* = 2;    (* != *)       Unequal
+    Percent* = 3;             (* % *)        lynx@binop    (rem)
+    PercentEqual* = 4;        (* %= *)       lynx@asop     (rem)
+    And* = 5;                 (* & *)        lynx@binop    (and)
+    AndEqual* = 6;            (* &= *)       lynx@asop     (and)
+    AndAnd* = 7;              (* && *)       And
+    LeftParenthesis* = 8;     (* ( *)        N/A
+    RightParenthesis* = 9;    (* ) *)        N/A
+    Times* = 10;              (* * *)        Times  
+    TimesEqual* = 11;         (* *= *)       lynx@asop     (mul)
+    Plus* = 12;               (* + *)        Plus
+    PlusEqual* = 13;          (* += *)       lynx@asop     (add)
+    PlusPlus* = 14;           (* ++ *)       lynx@asop     (add)
+    Comma* = 15;              (* , *)        N/A
+    Minus* = 16;              (* - *)        Minus  
+    MinusEqual* = 17;         (* -= *)       lynx@asop     (sub)
+    MinusMinus* = 18;         (* -- *)       lynx@asop     (sub)
+    Period* = 19;             (* . *)        N/A
+    Slash* = 20;              (* / *)        lynx@binop    (div)
+    SlashEqual* = 21;         (* /= *)       lynx@asop     (div)
+    Colon* = 22;              (* : *)        N/A
+    Semicolon* = 23;          (* ; *)        N/A
+    Less* = 24;               (* < *)        Less
+    LessEqual* = 25;          (* <= *)       LessEqual
+    LeftShift* = 26;          (* << *)       lynx@binop    (shl)
+    LeftShiftEqual* = 27;     (* <<= *)      lynx@asop     (shl)
+    Equal* = 28;              (* = *)        N/A
+    EqualEqual* = 29;         (* == *)       Equal
+    Greater* = 30;            (* > *)        Greater
+    GreaterEqual* = 31;       (* >= *)       GreaterEqual
+    RightShift* = 32;         (* >> *)       lynx@binop    (shr)
+    RightShiftEqual* = 33;    (* >>= *)      lynx@asop     (shr)
+    LeftBracket* = 34;        (* [ *)        N/A
+    RightBracket* = 35;       (* ] *)        N/A
+    Arrow* = 36;              (* ^ *)        lynx@binop    (xor)
+    ArrowEqual* = 37;         (* ^= *)       lynx@asop     (xor)
+    LeftBrace* = 38;          (* { *)        N/A
+    Bar* = 39;                (* | *)        lynx@binop    (or)
+    BarEqual* = 40;           (* |= *)       lynx@asop     (or)
+    BarBar* = 41;             (* || *)       Or
+    RightBrace* = 42;         (* } *)        N/A
+    Tilde* = 43;              (* ~ *)        lynx@unop     (not)
+*)
+
+        PROCEDURE MapOperator(token: Scanner.Token): LONGINT;
+            VAR operator: LONGINT;
+        BEGIN
+            CASE token OF
+              Scanner.Exclamation:    
+                operator := FoxScanner.Not;
+            | Scanner.ExclamationEqual:
+                operator := FoxScanner.Unequal;
+            | Scanner.Percent, Scanner.PercentEqual:
+                operator := 256 + Global.LynxOpRem;
+            | Scanner.And, Scanner.AndEqual:
+                operator := 256 + Global.LynxOpAnd;
+            | Scanner.AndAnd:
+                operator := FoxScanner.And;
+            | Scanner.Times:
+                operator := FoxScanner.Times;
+            | Scanner.TimesEqual:
+                operator := 256 + Global.LynxOpMul;
+            | Scanner.Plus:
+                operator := FoxScanner.Plus;
+            | Scanner.PlusEqual, Scanner.PlusPlus:
+                operator := 256 + Global.LynxOpAdd;
+            | Scanner.Minus:   
+                operator := FoxScanner.Minus;
+            | Scanner.MinusEqual, Scanner.MinusMinus:
+                operator := 256 + Global.LynxOpSub;
+            | Scanner.Slash, Scanner.SlashEqual:
+                operator := 256 + Global.LynxOpDiv;
+            | Scanner.Less:
+                operator := FoxScanner.Less;
+            | Scanner.LessEqual:
+                operator := FoxScanner.LessEqual;
+            | Scanner.LeftShift, Scanner.LeftShiftEqual:
+                operator := 256 + Global.LynxOpShl;
+            | Scanner.EqualEqual:
+                operator := FoxScanner.Equal;
+            | Scanner.Greater:
+                operator := FoxScanner.Greater;
+            | Scanner.GreaterEqual:
+                operator := FoxScanner.GreaterEqual;
+            | Scanner.RightShift, Scanner.RightShiftEqual:
+                operator := 256 + Global.LynxOpShr;
+            | Scanner.Arrow, Scanner.ArrowEqual:
+                operator := 256 + Global.LynxOpXor;
+            | Scanner.Bar, Scanner.BarEqual:
+                operator := 256 + Global.LynxOpOr;
+            | Scanner.BarBar:
+                operator := FoxScanner.Or;
+            | Scanner.Tilde:
+                operator := 256 + Global.LynxOpNot;
+            END;
+            RETURN operator;
+        END MapOperator;
+
+        PROCEDURE NewUnaryExpression(
+                position: LONGINT; 
+                operand: SyntaxTree.Expression; 
+                operator: LONGINT): SyntaxTree.Expression;
+            VAR expressionList: SyntaxTree.ExpressionList;
+                expression: SyntaxTree.Expression;
+                designator: SyntaxTree.Designator;
+        BEGIN
+            operator := MapOperator(operator);
+            IF operator < 256 THEN
+                expression := SyntaxTree.NewUnaryExpression(position, operand, operator);
+            ELSE
+                expressionList := SyntaxTree.NewExpressionList();
+                expression := SyntaxTree.NewIntegerValue(position, operator-256);
+                expressionList.AddExpression(expression);
+                expressionList.AddExpression(operand);
+                designator := SyntaxTree.NewIdentifierDesignator(position, lynxUnop);
+                expression := SyntaxTree.NewParameterDesignator(position, designator, expressionList);
+            END;
+            RETURN expression;
+        END NewUnaryExpression;
+
+        PROCEDURE NewBinaryExpression(
+                position: LONGINT; 
+                left, right: SyntaxTree.Expression; 
+                operator: LONGINT): SyntaxTree.Expression;
+            VAR expressionList: SyntaxTree.ExpressionList;
+                expression: SyntaxTree.Expression;
+                designator: SyntaxTree.Designator;
+        BEGIN
+            operator := MapOperator(operator);
+            IF operator < 256 THEN
+                expression := SyntaxTree.NewBinaryExpression(position, left, right, operator);
+            ELSE
+                expressionList := SyntaxTree.NewExpressionList();
+                expression := SyntaxTree.NewIntegerValue(position, operator-256);
+                expressionList.AddExpression(expression);
+                expressionList.AddExpression(left);
+                expressionList.AddExpression(right);
+                designator := SyntaxTree.NewIdentifierDesignator(position, lynxBinop);
+                expression := SyntaxTree.NewParameterDesignator(position, designator, expressionList);
+            END;
+            RETURN expression;
+        END NewBinaryExpression;
+
+        PROCEDURE NewTypeExpression(position: LONGINT): SyntaxTree.Expression;
+        BEGIN
+            RETURN SyntaxTree.NewIdentifierDesignator(position, lynxType);
+        END NewTypeExpression;
+
+        PROCEDURE NewReceiveExpression(
+                position: LONGINT; left, right: SyntaxTree.Expression): SyntaxTree.Expression;
+            VAR expressionList: SyntaxTree.ExpressionList;
+                expression: SyntaxTree.Expression;
+                designator: SyntaxTree.Designator;
+        BEGIN
+            expressionList := SyntaxTree.NewExpressionList();
+            expressionList.AddExpression(left);
+            expressionList.AddExpression(right);
+            designator := SyntaxTree.NewIdentifierDesignator(position, lynxRecvnb);
+            expression := SyntaxTree.NewParameterDesignator(position, designator, expressionList);
+            RETURN expression;
+        END NewReceiveExpression;
+
+        PROCEDURE MapNumberType(numberType: LONGINT): LONGINT;
+        BEGIN
+            CASE numberType OF
+              Scanner.IntNumber:
+                numberType := FoxScanner.Longint;
+            | Scanner.LongNumber:
+                numberType := FoxScanner.Hugeint;
+            | Scanner.FloatNumber:
+                numberType := FoxScanner.Real;
+            | Scanner.DoubleNumber:
+                numberType := FoxScanner.Longreal;
+            END;
+            RETURN numberType;
+        END MapNumberType;
+
+        (*
+            ACHTUNG: Initializers of members of modules, classes, structs,
+                cells, and cellnets are collected in a special statement
+                block. This block is inserted as the first statement in
+                the corresponding constructors.
+
+            TODO: This feature is not yet implemented. Initializers are 
+                collected but not inserted in constructors. Implement what is missing.
+        *)
+
+        (* create a statement block to collect initializers *)
+        PROCEDURE EnterInit;
+            VAR block: SyntaxTree.StatementBlock;
+        BEGIN
+            block := SyntaxTree.NewStatementBlock(invalidPosition, NIL);
+            initOuter := block;
+            initStatements := SyntaxTree.NewStatementSequence();
+            block.SetStatementSequence(initStatements);
+        END EnterInit;
+
+        (** Parsing according to the EBNF **)
+
+        (**
+            type-name:
+                identifier
+                module-name '.' identifier
+        **)
+        PROCEDURE QualifiedIdentifier(): SyntaxTree.QualifiedIdentifier;
+            VAR prefix, suffix: SyntaxTree.Identifier; 
+                qualifiedIdentifier: SyntaxTree.QualifiedIdentifier;
+                position0, position1: LONGINT;
+        BEGIN
+            IF Trace THEN 
+                S("QualifiedIdentifier") 
+            END;
+            prefix := Identifier(position0);
+            IF prefix # SyntaxTree.invalidIdentifier THEN
+                IF ~Optional(Scanner.Period) THEN
+                    suffix := prefix;
+                    prefix := SyntaxTree.invalidIdentifier;    (* empty *)
+                ELSE
+                    suffix := Identifier(position1);
+                END;
+                qualifiedIdentifier := SyntaxTree.NewQualifiedIdentifier(position0, prefix, suffix);
+            ELSE
+                qualifiedIdentifier := SyntaxTree.invalidQualifiedIdentifier;
+            END;
+            IF Trace THEN 
+                E("QualifiedIdentifier") 
+            END;
+            RETURN qualifiedIdentifier
+        END QualifiedIdentifier;
+
+        (**
+            expression-list:
+                expression
+                expression-list ',' expression
+        **)
+        PROCEDURE ExpressionList(expressionList: SyntaxTree.ExpressionList);
+            VAR expression: SyntaxTree.Expression;
+        BEGIN
+            IF Trace THEN 
+                S("ExpressionList")
+            END;
+            REPEAT
+                expression := Expression();
+                expressionList.AddExpression(expression);
+            UNTIL ~Optional(Scanner.Comma);
+            IF Trace THEN 
+                E("ExpressionList")
+            END;
+        END ExpressionList;
+
+        (**
+            argument-list:
+                argument
+                argument-list ',' argument
+
+            argument:
+                expression
+               'ref' variable-reference
+
+            variable-reference:
+                expression
+        **)
+        PROCEDURE ArgumentList(expressionList: SyntaxTree.ExpressionList);
+            VAR expression: SyntaxTree.Expression;
+                modifier: LONGINT;
+        BEGIN
+            IF Trace THEN 
+                S("ArgumentList")
+            END;
+            REPEAT
+                IF Optional(Scanner.Ref) THEN
+                    modifier := Scanner.Ref;
+                ELSE
+                    modifier := -1;
+                END;
+                (* 
+                    ACHTUNG: Modifiers cannot be validated without AST modifications,
+                        therefore 'modifier' value is not used in this release.
+                *)
+                expression := Expression();
+                expressionList.AddExpression(expression);
+            UNTIL ~Optional(Scanner.Comma);
+            IF Trace THEN 
+                E("ArgumentList")
+            END;
+        END ArgumentList;
+
+        (**
+            primary-expression:
+                array-creation-expression
+                primary-no-array-creation-expression
+
+            primary-no-array-creation-expression:
+                literal
+                simple-name
+                parenthesized-expression
+                member-access
+                invocation-expression
+                element-access
+                this-access
+                base-access
+                object-creation-expression
+                delegate-creation-expression
+                receive-expression
+
+            literal:
+                boolean-literal
+                integer-literal
+                real-literal
+                character-literal
+                string-literal
+                null-literal
+
+            boolean-literal:
+                'true'
+                'false'
+
+            null-literal:
+                'null'
+
+            simple-name:
+                identifier
+
+            parenthesized-expression:
+                '(' expression ')'
+
+            member-access:
+                primary-expression '.' identifier
+
+            invocation-expression:
+                primary-expression '(' [argument-list] ')'
+
+            element-access:
+                primary-no-array-creation-expression '[' expression-list ']'
+
+            this-access:
+                'this'
+
+            base-access:
+                'base' '.' identifier
+
+            object-creation-expression:
+                'new' non-array-type '(' [argument-list] ')'
+
+            array-creation-expression:
+                'new' non-array-type '[' expression-list ']' [rank-specifiers]
+
+            delegate-creation-expression:
+                'new' delegate-type '(' expression ')'
+
+            receive-expression:
+                primary-expression '??' primary-expression
+        **)
+        PROCEDURE Accessors(expression: SyntaxTree.Expression; arrayCreation: BOOLEAN): SyntaxTree.Expression;
+            VAR identifier: SyntaxTree.Identifier;
+                expressionList: SyntaxTree.ExpressionList;
+                position: LONGINT;
+        BEGIN
+            LOOP
+                position := symbol.start;
+                IF Optional(Scanner.Period) THEN
+                    identifier := Identifier(position);
+                    expression := SyntaxTree.NewSelectorDesignator(position, expression(SyntaxTree.Designator), identifier);
+                ELSIF Optional(Scanner.LeftParenthesis) THEN
+                    expressionList := SyntaxTree.NewExpressionList();
+                    IF ~Optional(Scanner.RightParenthesis) THEN
+                        ArgumentList(expressionList);
+                        Check(Scanner.RightParenthesis);
+                    END;
+                    expression := SyntaxTree.NewParameterDesignator(position, expression(SyntaxTree.Designator), expressionList);
+                ELSIF (~arrayCreation) & Optional(Scanner.LeftBracket) THEN
+                    expressionList := SyntaxTree.NewExpressionList();
+                    ExpressionList(expressionList);
+                    Check(Scanner.RightBracket);
+(* ACHTUNG: 27-09-2012
+                    expression := SyntaxTree.NewArrowDesignator(position, expression);
+*)
+                    expression := SyntaxTree.NewBracketDesignator(position, expression(SyntaxTree.Designator), expressionList);
+                ELSE
+                    EXIT;
+                END;
+            END;
+            RETURN expression;
+        END Accessors;
+
+        PROCEDURE PrimaryExpression(): SyntaxTree.Expression;
+            VAR expression: SyntaxTree.Expression;
+                designator: SyntaxTree.Designator;
+                realValue: SyntaxTree.RealValue;
+                identifier: SyntaxTree.Identifier;
+                type: SyntaxTree.Type;
+                typeExpression: SyntaxTree.Expression;
+                expressionList: SyntaxTree.ExpressionList;
+                position: LONGINT;
+                arrayCreation: BOOLEAN;
+                arrayType: SyntaxTree.ArrayType;
+                pointerType: SyntaxTree.PointerType;
+                rightExpression: SyntaxTree.Expression;
+                i, n: LONGINT;
+        BEGIN
+            IF Trace THEN 
+                S("PrimaryExpression")
+            END;
+
+            position := symbol.start;
+            arrayCreation := FALSE;
+
+            IF Peek(Scanner.True) THEN
+                expression := SyntaxTree.NewBooleanValue(position, TRUE);
+                expression.End(symbol.end);
+                NextSymbol;
+            ELSIF Peek(Scanner.False) THEN
+                expression := SyntaxTree.NewBooleanValue(position, FALSE);
+                expression.End(symbol.end);
+                NextSymbol;
+            ELSIF Peek(Scanner.IntegerLiteral) THEN
+                IF symbol.numberType = Scanner.IntNumber THEN
+                    expression := SyntaxTree.NewIntegerValue(position, symbol.integer);
+                    expression.End(symbol.end);
+                ELSIF symbol.numberType = Scanner.LongNumber THEN
+                    expression := SyntaxTree.NewIntegerValue(position, symbol.hugeint);
+                    expression.End(symbol.end);
+                ELSE
+                    HALT(100);
+                END;
+                NextSymbol;
+            ELSIF Peek(Scanner.RealLiteral) THEN
+                realValue := SyntaxTree.NewRealValue(position, symbol.real);
+                realValue.SetSubtype(MapNumberType(symbol.numberType));
+                expression := realValue;
+                expression.End(symbol.end);
+                NextSymbol;
+            ELSIF Peek(Scanner.CharacterLiteral) THEN
+                expression := SyntaxTree.NewCharacterValue(position, symbol.character);
+                expression.End(symbol.end);
+                NextSymbol;
+            ELSIF Peek(Scanner.StringLiteral) THEN
+                (* 
+                    TODO: Revise this: may need a string constructor wrapper ...
+                          ... and symbol.stringLength may be important too 
+                *)
+                expression := SyntaxTree.NewStringValue(position, symbol.string);
+                expression.End(symbol.end);
+                NextSymbol;
+            ELSIF Peek(Scanner.Identifier) THEN
+                identifier := Identifier(position);
+                identifier := localIdentTable.Find(identifier);
+                expression := SyntaxTree.NewIdentifierDesignator(position, identifier);
+            ELSIF Peek(Scanner.Null) THEN
+                expression := SyntaxTree.NewNilValue(position);
+                expression.End(symbol.end);
+                NextSymbol;
+            ELSIF Optional(Scanner.LeftParenthesis) THEN
+                expression := Expression();
+                Check(Scanner.RightParenthesis);
+            ELSIF Optional(Scanner.This) THEN
+                expression := SyntaxTree.NewSelfDesignator(position);
+            ELSIF Optional(Scanner.Base) THEN
+                Check(Scanner.Period);
+                position := symbol.start;
+                identifier := Identifier(position);
+                expression := SyntaxTree.NewIdentifierDesignator(position, identifier);
+                expression := SyntaxTree.NewArrowDesignator(position, expression(SyntaxTree.Designator));
+            ELSIF Optional(Scanner.New) THEN
+                type := NonArrayType();
+                expressionList := SyntaxTree.NewExpressionList();
+                typeExpression := NewTypeExpression(position);
+                expressionList.AddExpression(typeExpression);
+                IF Optional(Scanner.LeftBracket) THEN
+                    arrayCreation := TRUE;
+                    ExpressionList(expressionList);
+                    Check(Scanner.RightBracket);
+                    WHILE Optional(Scanner.LeftBracket) DO
+                        type := RankSpecifier(type);
+                        Check(Scanner.RightBracket);
+                    END;
+                    n := expressionList.Length() - 1;
+                    FOR i := 1 TO n DO
+                        arrayType := SyntaxTree.NewArrayType(position, currentScope, SyntaxTree.Open);
+                        arrayType.SetArrayBase(type);
+                        type := arrayType;
+                    END;
+                    pointerType := SyntaxTree.NewPointerType(position, currentScope);
+                    pointerType.SetPointerBase(type);
+                    type := pointerType;
+                END;
+                typeExpression.SetType(type);
+                IF ~arrayCreation THEN
+                    Check(Scanner.LeftParenthesis);
+                    IF ~Optional(Scanner.RightParenthesis) THEN
+                        ArgumentList(expressionList);
+                        Check(Scanner.RightParenthesis);
+                    END;
+                    designator := SyntaxTree.NewIdentifierDesignator(position, lynxNewobj);
+                    expression := SyntaxTree.NewParameterDesignator(position, designator, expressionList);
+                ELSE
+                    designator := SyntaxTree.NewIdentifierDesignator(position, lynxNewarr);
+                    expression := SyntaxTree.NewParameterDesignator(position, designator, expressionList);
+                END;
+             ELSE
+                Error(symbol.start, Diagnostics.Invalid, "Invalid primary expression");
+                NextSymbol;
+                expression := SyntaxTree.invalidExpression;
+            END;
+
+            expression := Accessors(expression, arrayCreation);
+
+            position := symbol.start;
+            IF Optional(Scanner.QuestionQuestion) THEN
+                rightExpression := PrimaryExpression();
+                expression := NewReceiveExpression(position, expression, rightExpression);
+            END;
+
+            IF Trace THEN 
+                E("PrimaryExpression")
+            END;
+            RETURN expression;
+        END PrimaryExpression;
+
+        (**
+            unary-expression:
+                primary-expression
+                '+' unary-expression
+                '-' unary-expression
+                '!' unary-expression
+                '~' unary-expression
+                cast-expression
+        **)
+        PROCEDURE UnaryExpression(): SyntaxTree.Expression;
+            VAR expression: SyntaxTree.Expression;
+                operator: LONGINT;
+                position: LONGINT;
+        BEGIN
+            IF Trace THEN 
+                S("UnaryExpression")
+            END;
+            position := symbol.start;
+            IF Peek(Scanner.Plus) OR Peek(Scanner.Minus) OR 
+                    Peek(Scanner.Exclamation) OR Peek(Scanner.Tilde) THEN
+                operator := symbol.token;
+                NextSymbol;
+                expression := UnaryExpression();
+                expression := NewUnaryExpression(position, expression, operator);
+            ELSE
+                (* TODO: Implement cast-expression *)
+                expression := PrimaryExpression();
+            END;
+            IF Trace THEN 
+                E("UnaryExpression")
+            END;
+            RETURN expression;
+        END UnaryExpression;
+
+        (**
+            multiplicative-expression:
+                unary-expression
+                multiplicative-expression '*' unary-expression
+                multiplicative-expression '/' unary-expression
+                multiplicative-expression '%' unary-expression
+        **)
+        PROCEDURE MultiplicativeExpression(): SyntaxTree.Expression;
+            VAR expression, rightExpression: SyntaxTree.Expression;
+                operator: LONGINT;
+                position: LONGINT;
+        BEGIN
+            IF Trace THEN 
+                S("MultiplicativeExpression")
+            END;
+            position := symbol.start;
+            expression := UnaryExpression();
+            WHILE Peek(Scanner.Times) OR Peek(Scanner.Slash) OR Peek(Scanner.Percent) DO
+                operator := symbol.token;
+                NextSymbol;
+                rightExpression := UnaryExpression();
+                expression := NewBinaryExpression(position, expression, rightExpression, operator);
+            END;
+            IF Trace THEN 
+                E("MultiplicativeExpression")
+            END;
+            RETURN expression;
+        END MultiplicativeExpression;
+
+        (**
+            additive-expression:
+                multiplicative-expression
+                additive-expression '+' multiplicative-expression
+                additive-expression '–' multiplicative-expression
+        **)
+        PROCEDURE AdditiveExpression(): SyntaxTree.Expression;
+            VAR expression, rightExpression: SyntaxTree.Expression;
+                operator: LONGINT;
+                position: LONGINT;
+        BEGIN
+            IF Trace THEN 
+                S("AdditiveExpression")
+            END;
+            position := symbol.start;
+            expression := MultiplicativeExpression();
+            WHILE Peek(Scanner.Plus) OR Peek(Scanner.Minus) DO
+                operator := symbol.token;
+                NextSymbol;
+                rightExpression := MultiplicativeExpression();
+                expression := NewBinaryExpression(position, expression, rightExpression, operator);
+            END;
+            IF Trace THEN 
+                E("AdditiveExpression")
+            END;
+            RETURN expression;
+        END AdditiveExpression;
+
+        (**
+            shift-expression:
+                additive-expression
+                shift-expression '<<' additive-expression
+                shift-expression '>>' additive-expression
+        **)
+        PROCEDURE ShiftExpression(): SyntaxTree.Expression;
+            VAR expression, rightExpression: SyntaxTree.Expression;
+                operator: LONGINT;
+                position: LONGINT;
+        BEGIN
+            IF Trace THEN 
+                S("ShiftExpression")
+            END;
+            position := symbol.start;
+            expression := AdditiveExpression();
+            WHILE Peek(Scanner.LeftShift) OR Peek(Scanner.RightShift) DO
+                operator := symbol.token;
+                NextSymbol;
+                rightExpression := AdditiveExpression();
+                expression := NewBinaryExpression(position, expression, rightExpression, operator);
+            END;
+            IF Trace THEN 
+                E("ShiftExpression")
+            END;
+            RETURN expression;
+        END ShiftExpression;
+
+        (**
+            relational-expression:
+                shift-expression
+                relational-expression '<' shift-expression
+                relational-expression '>' shift-expression
+                relational-expression '<=' shift-expression
+                relational-expression '>=' shift-expression
+                relational-expression 'is' type-name
+                relational-expression 'as' type-name
+        **)
+        PROCEDURE RelationalExpression(): SyntaxTree.Expression;
+            VAR expression, rightExpression: SyntaxTree.Expression;
+                operator: LONGINT;
+                position: LONGINT;
+        BEGIN
+            IF Trace THEN 
+                S("RelationalExpression")
+            END;
+            position := symbol.start;
+            expression := ShiftExpression();
+            WHILE Peek(Scanner.Less) OR Peek(Scanner.Greater) OR
+                    Peek(Scanner.LessEqual) OR Peek(Scanner.GreaterEqual) OR
+                    Peek(Scanner.Is) OR Peek(Scanner.As) DO
+                operator := symbol.token;
+                NextSymbol;
+                rightExpression := ShiftExpression();
+                expression := NewBinaryExpression(position, expression, rightExpression, operator);
+            END;
+            IF Trace THEN 
+                E("RelationalExpression")
+            END;
+            RETURN expression;
+        END RelationalExpression;
+
+        (**
+            equality-expression:
+                relational-expression
+                equality-expression '==' relational-expression
+                equality-expression '!=' relational-expression
+        **)
+        PROCEDURE EqualityExpression(): SyntaxTree.Expression;
+            VAR expression, rightExpression: SyntaxTree.Expression;
+                operator: LONGINT;
+                position: LONGINT;
+        BEGIN
+            IF Trace THEN 
+                S("EqualityExpression")
+            END;
+            position := symbol.start;
+            expression := RelationalExpression();
+            WHILE Peek(Scanner.EqualEqual) OR Peek(Scanner.ExclamationEqual) DO
+                operator := symbol.token;
+                NextSymbol;
+                rightExpression := RelationalExpression();
+                expression := NewBinaryExpression(position, expression, rightExpression, operator);
+            END;
+            IF Trace THEN 
+                E("EqualityExpression")
+            END;
+            RETURN expression;
+        END EqualityExpression;
+
+        (**
+            and-expression:
+                equality-expression
+                and-expression '&' equality-expression
+        **)
+        PROCEDURE AndExpression(): SyntaxTree.Expression;
+            VAR expression, rightExpression: SyntaxTree.Expression;
+                operator: LONGINT;
+                position: LONGINT;
+        BEGIN
+            IF Trace THEN 
+                S("AndExpression")
+            END;
+            position := symbol.start;
+            expression := EqualityExpression();
+            WHILE Peek(Scanner.And) DO
+                operator := symbol.token;
+                NextSymbol;
+                rightExpression := EqualityExpression();
+                expression := NewBinaryExpression(position, expression, rightExpression, operator);
+            END;
+            IF Trace THEN 
+                E("AndExpression")
+            END;
+            RETURN expression;
+        END AndExpression;
+
+        (**
+            exclusive-or-expression:
+                and-expression
+                exclusive-or-expression '^' and-expression
+        **)
+        PROCEDURE ExclusiveOrExpression(): SyntaxTree.Expression;
+            VAR expression, rightExpression: SyntaxTree.Expression;
+                operator: LONGINT;
+                position: LONGINT;
+        BEGIN
+            IF Trace THEN 
+                S("ExclusiveOrExpression")
+            END;
+            position := symbol.start;
+            expression := AndExpression();
+            WHILE Peek(Scanner.Arrow) DO
+                operator := symbol.token;
+                NextSymbol;
+                rightExpression := AndExpression();
+                expression := NewBinaryExpression(position, expression, rightExpression, operator);
+            END;
+            IF Trace THEN 
+                E("ExclusiveOrExpression")
+            END;
+            RETURN expression;
+        END ExclusiveOrExpression;
+
+        (**
+            inclusive-or-expression:
+                exclusive-or-expression
+                inclusive-or-expression '|' exclusive-or-expression
+        **)
+        PROCEDURE InclusiveOrExpression(): SyntaxTree.Expression;
+            VAR expression, rightExpression: SyntaxTree.Expression;
+                operator: LONGINT;
+                position: LONGINT;
+        BEGIN
+            IF Trace THEN 
+                S("InclusiveOrExpression")
+            END;
+            position := symbol.start;
+            expression := ExclusiveOrExpression();
+            WHILE Peek(Scanner.Bar) DO
+                operator := symbol.token;
+                NextSymbol;
+                rightExpression := ExclusiveOrExpression();
+                expression := NewBinaryExpression(position, expression, rightExpression, operator);
+            END;
+            IF Trace THEN 
+                E("InclusiveOrExpression")
+            END;
+            RETURN expression;
+        END InclusiveOrExpression;
+
+        (**
+            conditional-and-expression:
+                inclusive-or-expression
+                conditional-and-expression '&&' inclusive-or-expression
+        **)
+        PROCEDURE ConditionalAndExpression(): SyntaxTree.Expression;
+            VAR expression, rightExpression: SyntaxTree.Expression;
+                operator: LONGINT;
+                position: LONGINT;
+        BEGIN
+            IF Trace THEN 
+                S("ConditionalAndExpression")
+            END;
+            position := symbol.start;
+            expression := InclusiveOrExpression();
+            WHILE Peek(Scanner.AndAnd) DO
+                operator := symbol.token;
+                NextSymbol;
+                rightExpression := InclusiveOrExpression();
+                expression := NewBinaryExpression(position, expression, rightExpression, operator);
+            END;
+            IF Trace THEN 
+                E("ConditionalAndExpression")
+            END;
+            RETURN expression;
+        END ConditionalAndExpression;
+
+        (**
+            conditional-or-expression:
+                conditional-and-expression
+                conditional-or-expression '||' conditional-and-expression
+        **)
+        PROCEDURE ConditionalOrExpression(): SyntaxTree.Expression;
+            VAR expression, rightExpression: SyntaxTree.Expression;
+                operator: LONGINT;
+                position: LONGINT;
+        BEGIN
+            IF Trace THEN 
+                S("ConditionalOrExpression")
+            END;
+            position := symbol.start;
+            expression := ConditionalAndExpression();
+            WHILE Peek(Scanner.BarBar) DO
+                operator := symbol.token;
+                NextSymbol;
+                rightExpression := ConditionalAndExpression();
+                expression := NewBinaryExpression(position, expression, rightExpression, operator);
+            END;
+            IF Trace THEN 
+                E("ConditionalOrExpression")
+            END;
+            RETURN expression;
+        END ConditionalOrExpression;
+
+        (**
+            expression:
+                conditional-expression
+
+            conditional-expression:
+                conditional-or-expression
+        **)
+        PROCEDURE Expression(): SyntaxTree.Expression;
+            VAR expression: SyntaxTree.Expression;
+        BEGIN
+            IF Trace THEN 
+                S("Expression")
+            END;
+            expression := ConditionalOrExpression();
+            IF Trace THEN 
+                E("Expression")
+            END;
+            RETURN expression;
+        END Expression;
+
+        (**
+            local-variable-declaration:
+                type local-variable-declarators
+        **)
+        PROCEDURE LocalVariableDeclaration(
+                statements: SyntaxTree.StatementSequence; outer: SyntaxTree.Statement; type: SyntaxTree.Type);
+            VAR previousStatements: SyntaxTree.StatementSequence;
+                previousOuter: SyntaxTree.Statement;
+        BEGIN
+            IF Trace THEN 
+                S("LocalVariableDeclaration")
+            END;
+            previousStatements := initStatements;
+            previousOuter := initOuter;
+            initStatements := statements;
+            initOuter := outer;
+            IF type = NIL THEN
+                type := Type();
+            END;
+            REPEAT
+                VariableDeclarator(currentScope, {}, type, SyntaxTree.invalidIdentifier, invalidPosition);
+            UNTIL ~Optional(Scanner.Comma);
+            initStatements := previousStatements;
+            initOuter := previousOuter;
+            IF Trace THEN 
+                E("LocalVariableDeclaration")
+            END;
+        END LocalVariableDeclaration;
+
+        (**
+            local-constant-declaration:
+                'const' type constant-declarators
+        **)
+        PROCEDURE LocalConstantDeclaration(statements: SyntaxTree.StatementSequence; outer: SyntaxTree.Statement);
+            VAR type: SyntaxTree.Type;
+        BEGIN
+            (* ACHTUNG: Parameters 'statements' and 'outer' are not used *)
+            IF Trace THEN 
+                S("LocalConstantDeclaration")
+            END;
+            type := Type();
+            REPEAT
+                ConstantDeclarator(currentScope, {}, type);
+            UNTIL ~Optional(Scanner.Comma);
+            IF Trace THEN 
+                E("LocalConstantDeclaration")
+            END;
+        END LocalConstantDeclaration;
+
+        (**
+            block:
+                '{' [statement-list] '}'
+
+        **)
+        PROCEDURE Block(statements: SyntaxTree.StatementSequence; outer: SyntaxTree.Statement);
+            VAR block: SyntaxTree.StatementBlock;
+        BEGIN
+            IF Trace THEN 
+                S("Block")
+            END;
+            Check(Scanner.LeftBrace);
+            block := SyntaxTree.NewStatementBlock(symbol.end, outer);
+            (* CommentStatement(block); *)
+            IF ~Optional(Scanner.RightBrace) THEN
+                localIdentTable.OpenScope;
+                block.SetStatementSequence(StatementList(block));
+                localIdentTable.CloseScope;
+                Check(Scanner.RightBrace);
+            END;
+            statements.AddStatement(block);
+            IF Trace THEN 
+                E("Block")
+            END;
+        END Block;
+
+        (**
+            expression-statement:
+                statement-expression ';'
+
+            statement-expression:
+                invocation-expression
+                assignment
+                post-increment-expression
+                post-decrement-expression
+                send-expression
+                receive-expression
+                connect-expression
+                delegate-expression
+
+            assignment:
+                primary-expression assignment-operator expression
+
+            assignment-operator: one of
+                '=' '+=' '-=' '*=' '/=' '%=' '&=' '|=' '^=' '<<=' '>>='
+
+            post-increment-expression:
+                primary-expression '++'
+
+            post-decrement-expression:
+                primary-expression '--'
+
+            send-expression:
+                primary-expression '!' expression-list
+
+            receive-expression:
+                primary-expression '?' expression-list
+
+            connect-expression:
+                primary-expression '>>' primary-expression
+
+            delegate-expression:
+                primary-expression '<=' primary-expression
+        **)
+        PROCEDURE NewAsopStatement(
+                position: LONGINT;
+                operator: LONGINT;
+                left: SyntaxTree.Designator;
+                right: SyntaxTree.Expression;
+                outer: SyntaxTree.Statement): SyntaxTree.Statement;
+            VAR expressionList: SyntaxTree.ExpressionList;
+                expression: SyntaxTree.Expression;
+                designator: SyntaxTree.Designator;
+        BEGIN
+            operator := MapOperator(operator);
+            ASSERT(operator >= 256);
+            expressionList := SyntaxTree.NewExpressionList();
+            expression := SyntaxTree.NewIntegerValue(position, operator-256);
+            expressionList.AddExpression(expression);
+            expressionList.AddExpression(left);
+            expressionList.AddExpression(right);
+            designator := SyntaxTree.NewIdentifierDesignator(position, lynxAsop);
+            designator := SyntaxTree.NewParameterDesignator(position, designator, expressionList);
+            RETURN SyntaxTree.NewProcedureCallStatement(designator.position, designator, outer);
+        END NewAsopStatement;
+
+(* ACHTUNG: LYNX 15-MAY-2013 *)
+        PROCEDURE PatchPortReference(expression: SyntaxTree.Expression): SyntaxTree.Expression;
+            VAR result: SyntaxTree.Expression;
+                parameterDesignator: SyntaxTree.ParameterDesignator;
+                parameters: SyntaxTree.ExpressionList;
+                p0: SyntaxTree.Expression;
+                identifierDesignator: SyntaxTree.IdentifierDesignator;
+                bracketDesignator: SyntaxTree.BracketDesignator;
+                left, left2: SyntaxTree.Expression;
+        BEGIN
+            IF ~(expression IS SyntaxTree.ParameterDesignator) THEN
+                result := expression;
+            ELSE
+                parameterDesignator := expression(SyntaxTree.ParameterDesignator);
+                parameters := parameterDesignator.parameters;
+                IF parameters.Length() # 1 THEN
+                    result := expression;
+                ELSE
+                    p0 := parameters.GetExpression(0);
+                    IF p0 IS SyntaxTree.IdentifierDesignator THEN
+                        (* C(P) -> C.P *)
+                        left := parameterDesignator.left;
+                        identifierDesignator := p0(SyntaxTree.IdentifierDesignator);
+                        result := 
+                            SyntaxTree.NewSelectorDesignator(
+                                expression.position, left(SyntaxTree.Designator), identifierDesignator.identifier);
+                    ELSIF p0 IS SyntaxTree.BracketDesignator THEN
+                        bracketDesignator := p0(SyntaxTree.BracketDesignator);
+                        left2 := bracketDesignator.left; 
+                        IF left2 IS SyntaxTree.IdentifierDesignator THEN
+                            (* C(P[I]) -> C.P[I] *)
+                            left := parameterDesignator.left;
+                            identifierDesignator := left2(SyntaxTree.IdentifierDesignator);
+                            result :=
+                                SyntaxTree.NewBracketDesignator(
+                                    expression.position,
+                                    SyntaxTree.NewSelectorDesignator(
+                                        expression.position, 
+                                        left(SyntaxTree.Designator), 
+                                        identifierDesignator.identifier),
+                                    bracketDesignator.parameters);
+                        ELSE                    
+                            result := expression;
+                        END;
+                    ELSE
+                        result := expression;
+                    END;
+                END;
+            END;
+            RETURN result;
+        END PatchPortReference;
+
+        PROCEDURE NewPortStatement(
+                position: LONGINT;
+                name: SyntaxTree.Identifier;
+                left: SyntaxTree.Designator;
+                right: SyntaxTree.Expression;
+                outer: SyntaxTree.Statement): SyntaxTree.Statement;
+            VAR expressionList: SyntaxTree.ExpressionList;
+                designator: SyntaxTree.Designator;
+        BEGIN
+            expressionList := SyntaxTree.NewExpressionList();
+            expressionList.AddExpression(left);
+            expressionList.AddExpression(right);
+            designator := SyntaxTree.NewIdentifierDesignator(position, name);
+            designator := SyntaxTree.NewParameterDesignator(position, designator, expressionList);
+            RETURN SyntaxTree.NewProcedureCallStatement(designator.position, designator, outer);
+        END NewPortStatement; 
+
+        PROCEDURE StatementExpression(
+                statements: SyntaxTree.StatementSequence; 
+                outer: SyntaxTree.Statement;
+                expression: SyntaxTree.Expression): BOOLEAN;
+            VAR designator: SyntaxTree.Designator;
+                expressionList: SyntaxTree.ExpressionList;
+                statement: SyntaxTree.Statement;
+                operator: LONGINT;
+                position: LONGINT;
+                length, i: LONGINT;
+                temp: SyntaxTree.Expression;
+        BEGIN
+            IF Trace THEN 
+                S("StatementExpression")
+            END;
+            (* ACHTUNG: Only expressions of type SyntaxTree.Designator are supported
+                   in place of primary-expression in the above productions. This is
+                   required for compatibility with Fox back-end *)
+            statement := NIL;
+            position := symbol.start;
+            IF expression = NIL THEN
+                expression := PrimaryExpression();
+            END;
+            IF ~(expression IS SyntaxTree.Designator) THEN
+                Error(position, Diagnostics.Invalid, "Invalid expression statement");
+            ELSE
+                designator := expression(SyntaxTree.Designator);
+                position := symbol.start;
+                IF Optional(Scanner.Equal) THEN
+                    expression := Expression();
+                    statement := SyntaxTree.NewAssignment(position, designator, expression, outer);
+                ELSIF Peek(Scanner.PlusEqual) OR Peek(Scanner.MinusEqual) OR
+                        Peek(Scanner.TimesEqual) OR Peek(Scanner.SlashEqual) OR
+                        Peek(Scanner.PercentEqual) OR Peek(Scanner.AndEqual) OR
+                        Peek(Scanner.BarEqual) OR Peek(Scanner.ArrowEqual) OR
+                        Peek(Scanner.LeftShiftEqual) OR Peek(Scanner.RightShiftEqual) THEN
+                    operator := symbol.token;
+                    NextSymbol;
+                    (* lynx@asop(operator, designator, expression) *)
+                    expression := Expression();
+                    statement := NewAsopStatement(position, operator, designator, expression, outer);
+                ELSIF Optional(Scanner.PlusPlus) THEN
+                    (* lynx@asop(PlusEqual, designator, 1) *)
+                    operator := Scanner.PlusPlus;
+                    expression := SyntaxTree.NewIntegerValue(position, 1);
+                    statement := NewAsopStatement(position, operator, designator, expression, outer);
+                ELSIF Optional(Scanner.MinusMinus) THEN
+                    (* lynx@asop(MinusEqual, designator, 1) *)
+                    operator := Scanner.MinusMinus;
+                    expression := SyntaxTree.NewIntegerValue(position, 1);
+                    statement := NewAsopStatement(position, operator, designator, expression, outer);
+(* ACHTUNG: LYNX 15-MAY-2013
+               ELSIF Optional(Scanner.Exclamation) THEN
+                    (* lynx@send(designator, expression) *)
+                    expression := Expression();
+                    statement := NewPortStatement(position, lynxSend, designator, expression, outer);
+                ELSIF Optional(Scanner.Question) THEN
+                    (* lynx@receive(designator, expression) *)
+                    expression := Expression();
+                    statement := NewPortStatement(position, lynxReceive, designator, expression, outer);
+*)
+               ELSIF Optional(Scanner.Exclamation) THEN
+                    (* lynx@send(designator, expression) *)
+                    expressionList := SyntaxTree.NewExpressionList();
+                    ExpressionList(expressionList);
+                    length := expressionList.Length();
+                    FOR i := 0 TO length - 1 DO
+                        expression := expressionList.GetExpression(i);
+                        statement := NewPortStatement(position, lynxSend, designator, expression, outer);
+                        IF i < length - 1 THEN
+                            statements.AddStatement(statement);
+                        END;
+                    END;
+                ELSIF Optional(Scanner.Question) THEN
+                    (* lynx@receive(designator, expression) *)
+                    expressionList := SyntaxTree.NewExpressionList();
+                    ExpressionList(expressionList);
+                    length := expressionList.Length();
+                    FOR i := 0 TO length - 1 DO
+                        expression := expressionList.GetExpression(i);
+                        statement := NewPortStatement(position, lynxReceive, designator, expression, outer);
+                        IF i < length - 1 THEN
+                            statements.AddStatement(statement);
+                        END;
+                    END;
+(* ACHTUNG: LYNX 15-MAY-2013
+                ELSIF Optional(Scanner.RightShift) THEN
+                    (* lynx@connect(designator, expression) *)
+                    expression := PrimaryExpression();
+                    statement := NewPortStatement(position, lynxConnect, designator, expression, outer);
+                ELSIF Optional(Scanner.LessEqual) THEN
+                    (* lynx@delegate(designator, expression) *)
+                    expression := PrimaryExpression();
+                    statement := NewPortStatement(position, lynxDelegate, designator, expression, outer);
+*)
+                ELSIF Optional(Scanner.RightShift) THEN
+                    (* lynx@connect(designator, expression) *)
+                    expression := PrimaryExpression();
+                    temp := PatchPortReference(designator);
+                    designator := temp(SyntaxTree.Designator);
+                    expression := PatchPortReference(expression);
+                    statement := NewPortStatement(position, lynxConnect, designator, expression, outer);
+                ELSIF Optional(Scanner.LessEqual) THEN
+                    (* lynx@delegate(designator, expression) *)
+                    expression := PrimaryExpression();
+                    temp := PatchPortReference(designator);
+                    designator := temp(SyntaxTree.Designator);
+                    expression := PatchPortReference(expression);
+                    statement := NewPortStatement(position, lynxDelegate, designator, expression, outer);
+                ELSIF designator IS SyntaxTree.ParameterDesignator THEN
+                    statement := SyntaxTree.NewProcedureCallStatement(designator.position, designator, outer);
+                ELSE
+                    Error(position, Diagnostics.Invalid, "Invalid expression statement");
+                END;
+            END;
+            IF statement # NIL THEN
+                (* CommentStatement(statement); *)
+                statements.AddStatement(statement);
+            END;
+            IF Trace THEN 
+                E("StatementExpression")
+            END;
+            RETURN statement # NIL;
+        END StatementExpression;
+
+        PROCEDURE ExpressionStatement(
+                statements: SyntaxTree.StatementSequence; outer: SyntaxTree.Statement): BOOLEAN;
+            VAR b: BOOLEAN;
+        BEGIN
+            IF Trace THEN 
+                S("ExpressionStatement")
+            END;
+            b := StatementExpression(statements, outer, NIL);
+            Check(Scanner.Semicolon);
+            IF Trace THEN 
+                E("ExpressionStatement")
+            END;
+            RETURN b;
+        END ExpressionStatement;
+
+        (**
+            if-statement:
+                'if' '(' boolean-expression ')' embedded-statement
+                'if' '(' boolean-expression ')' embedded-statement 'else' embedded-statement
+        **)
+        PROCEDURE IfStatement(statements: SyntaxTree.StatementSequence; outer: SyntaxTree.Statement);
+            VAR expression: SyntaxTree.Expression;
+                ifStatement: SyntaxTree.IfStatement;
+                elsePart: SyntaxTree.IfPart;
+                statementSequence: SyntaxTree.StatementSequence;
+                b: BOOLEAN;
+        BEGIN
+            IF Trace THEN 
+                S("IfStatement")
+            END;
+            Check(Scanner.If);
+            ifStatement := SyntaxTree.NewIfStatement(symbol.start, outer);
+            (* CommentStatement(ifStatement); *)
+            Check(Scanner.LeftParenthesis);
+            expression := Expression();
+            Check(Scanner.RightParenthesis);
+            ifStatement.ifPart.SetCondition(expression);
+            statementSequence := SyntaxTree.NewStatementSequence();
+            b := EmbeddedStatement(statementSequence, ifStatement);
+            ifStatement.ifPart.SetStatements(statementSequence);
+            IF Optional(Scanner.Else) THEN
+                statementSequence := SyntaxTree.NewStatementSequence();
+                b := EmbeddedStatement(statementSequence, ifStatement);
+                ifStatement.SetElsePart(statementSequence);
+            END;
+            statements.AddStatement(ifStatement);
+            IF Trace THEN 
+                E("IfStatement")
+            END;
+        END IfStatement;
+
+        (**
+            switch-statement:
+                'switch' '(' expression ')' switch-block
+
+            switch-block:
+                '{' [switch-sections] '}'
+
+
+            switch-sections:
+                switch-section
+                switch-sections switch-section
+
+            switch-section:
+                switch-labels statement-list
+
+            switch-labels:
+                switch-label
+                switch-labels switch-label
+
+            switch-label:
+                'case' constant-expression ':'
+                'default' ':'
+        **)
+        PROCEDURE SwitchSection(caseStatement: SyntaxTree.CaseStatement; VAR haveDefault: BOOLEAN);
+            VAR casePart: SyntaxTree.CasePart;
+                statements: SyntaxTree.StatementSequence;
+                last: SyntaxTree.Statement;
+                element: SyntaxTree.Expression;
+                defaultSection: BOOLEAN;
+                length, position: LONGINT;
+        BEGIN
+            IF Trace THEN 
+                S("SwitchSection")
+            END;
+            casePart := SyntaxTree.NewCasePart();
+            defaultSection := FALSE;
+            WHILE Peek(Scanner.Case) OR Peek(Scanner.Default) DO
+                (* CommentCasePart(casePart); *)
+                IF Optional(Scanner.Case) THEN
+                    element := Expression();
+                    Check(Scanner.Colon);
+                    casePart.elements.AddExpression(element);
+                ELSE
+                    position := symbol.start;
+                    Check(Scanner.Default);
+                    Check(Scanner.Colon);
+                    IF haveDefault THEN
+                        Error(position, Diagnostics.Invalid, "Duplicate default label");
+                    ELSE
+                        defaultSection := TRUE;
+                        haveDefault := TRUE;
+                    END;
+                END;
+            END;
+            statements := StatementList(caseStatement);
+            length := statements.Length();
+            IF length = 0 THEN
+                Error(symbol.start, Diagnostics.Invalid, "Fall through in switch section");
+            ELSE
+                last := statements.GetStatement(length-1);
+                IF last IS SyntaxTree.ExitStatement THEN
+                    statements.RemoveStatement(last);
+                ELSIF ~(last IS SyntaxTree.ReturnStatement) THEN
+                    Error(symbol.start, Diagnostics.Invalid, "Fall through in switch section");
+                END;
+            END;
+            IF ~defaultSection THEN
+                casePart.SetStatements(statements);
+                caseStatement.AddCasePart(casePart);
+            ELSE
+                (* ignore case labels, if any *)
+                (* ACHTUNG: these labels will not be checked for duplicates *)
+                caseStatement.SetElsePart(statements);
+            END;
+            IF Trace THEN 
+                E("SwitchSection")
+            END;
+        END SwitchSection;
+
+        PROCEDURE SwitchStatement(statements: SyntaxTree.StatementSequence; outer: SyntaxTree.Statement);
+            VAR expression: SyntaxTree.Expression;
+                caseStatement: SyntaxTree.CaseStatement;
+                haveDefault: BOOLEAN;
+        BEGIN
+            IF Trace THEN 
+                S("SwitchStatement")
+            END;
+            Check(Scanner.Switch);
+            caseStatement := SyntaxTree.NewCaseStatement(symbol.start, outer);
+            (* CommentStatement(caseStatement); *)
+            Check(Scanner.LeftParenthesis);
+            expression := Expression();
+            Check(Scanner.RightParenthesis);
+            caseStatement.SetVariable(expression);
+            Check(Scanner.LeftBrace);
+            haveDefault := FALSE;
+            WHILE Peek(Scanner.Case) OR Peek(Scanner.Default) DO
+                SwitchSection(caseStatement, haveDefault);
+            END;
+            Check(Scanner.RightBrace);
+            statements.AddStatement(caseStatement);
+            IF Trace THEN 
+                E("SwitchStatement")
+            END;
+        END SwitchStatement;
+
+        (**
+            select-statement:
+                'select' select-block
+
+            select-block:
+                '{' select-sections '}'
+
+            select-sections:
+                select-section
+                select-sections select-section
+
+            select-section:
+                select-label statement-list
+
+            select-label:
+                'case' [select-replicator] primary-expression '?' primary-expression ':'
+
+            select-replicator:
+                '(' integral-type simple-name 'in' expression ':' expression ')'
+        **)
+
+        (**
+            Fox mapping schema:
+
+            // LYNX
+
+            select {
+            case c ? x:
+                S1;
+            case (int i in m : n) d[i] ? y:
+                S2;
+            }
+
+            // Fox
+
+            lynx@newsel;
+            lynx@addsel(0, 0, c);
+            FOR i := m TO n DO
+                lynx@addsel(1, i, d[i])
+            END;
+            CASE lynx@select() OF
+              0:
+                c ? x;
+                S1;
+            | 1:
+                i := lynx@selidx();
+                d[i] ? y;
+                S2;
+            END;
+        **)
+
+        PROCEDURE NewLynxNewsel(
+                position: LONGINT; outer: SyntaxTree.Statement): SyntaxTree.Statement;
+            VAR parameters: SyntaxTree.ExpressionList;
+                designator: SyntaxTree.Designator;
+        BEGIN
+            parameters := SyntaxTree.NewExpressionList();
+            designator := SyntaxTree.NewIdentifierDesignator(position, lynxNewsel);
+            designator := SyntaxTree.NewParameterDesignator(position, designator, parameters);
+            RETURN SyntaxTree.NewProcedureCallStatement(position, designator, outer);
+        END NewLynxNewsel;
+
+        PROCEDURE NewLynxAddsel(
+                position: LONGINT;
+                index: LONGINT;
+                variable: SyntaxTree.Identifier;
+                channel: SyntaxTree.Expression;
+                outer: SyntaxTree.Statement): SyntaxTree.Statement;
+            VAR parameters: SyntaxTree.ExpressionList;
+                designator: SyntaxTree.Designator;
+        BEGIN
+            parameters := SyntaxTree.NewExpressionList();
+            parameters.AddExpression(SyntaxTree.NewIntegerValue(position, index));
+            IF variable # SyntaxTree.invalidIdentifier THEN
+                parameters.AddExpression(
+                    SyntaxTree.NewIdentifierDesignator(position, variable));
+            ELSE
+                parameters.AddExpression(SyntaxTree.NewIntegerValue(position, 0));
+            END;
+            parameters.AddExpression(channel);
+            designator := SyntaxTree.NewIdentifierDesignator(position, lynxAddsel);
+            designator := SyntaxTree.NewParameterDesignator(position, designator, parameters);
+            RETURN SyntaxTree.NewProcedureCallStatement(position, designator, outer);
+        END NewLynxAddsel;
+
+        PROCEDURE NewLynxSelect(position: LONGINT): SyntaxTree.Expression;
+            VAR left: SyntaxTree.Designator;
+                parameters: SyntaxTree.ExpressionList;
+        BEGIN
+            left := SyntaxTree.NewIdentifierDesignator(position, lynxSelect);
+            parameters := SyntaxTree.NewExpressionList();
+            RETURN SyntaxTree.NewParameterDesignator(position, left, parameters);
+        END NewLynxSelect;
+
+        PROCEDURE NewLynxSelidx(
+                position: LONGINT; 
+                variable: SyntaxTree.Identifier;
+                outer: SyntaxTree.Statement): SyntaxTree.Statement;
+            VAR left: SyntaxTree.Designator;
+                parameters: SyntaxTree.ExpressionList;
+                right: SyntaxTree.Expression;
+        BEGIN
+            left := SyntaxTree.NewIdentifierDesignator(position, lynxSelidx);
+            parameters := SyntaxTree.NewExpressionList();
+            right := SyntaxTree.NewParameterDesignator(position, left, parameters);
+            left := SyntaxTree.NewIdentifierDesignator(position, variable);
+            RETURN SyntaxTree.NewAssignment(position, left, right, outer);
+        END NewLynxSelidx;
+
+        PROCEDURE SelectSection(
+                statements: SyntaxTree.StatementSequence; 
+                caseStatement: SyntaxTree.CaseStatement;
+                index: LONGINT;
+                outer: SyntaxTree.Statement);
+            VAR typename, varname: SyntaxTree.Identifier;
+                type: SyntaxTree.Type;
+                variable: SyntaxTree.Variable;
+                position: LONGINT;
+                from, to: SyntaxTree.Expression;
+                channel, target: SyntaxTree.Expression;
+                statement: SyntaxTree.Statement;
+                forStatement: SyntaxTree.ForStatement;
+                forBody: SyntaxTree.StatementSequence;
+                designator: SyntaxTree.Designator;
+                casePart: SyntaxTree.CasePart;
+                caseBody: SyntaxTree.StatementSequence;
+                length: LONGINT;
+                last: SyntaxTree.Statement;
+        BEGIN
+            IF Trace THEN 
+                S("SelectSection")
+            END;
+            position := symbol.start;
+            Check(Scanner.Case);
+            localIdentTable.OpenScope;
+            IF Optional(Scanner.LeftParenthesis) THEN
+                IF Optional(Scanner.Sbyte) THEN
+                    typename := lynxSbyte;
+                ELSIF Optional(Scanner.Short) THEN
+                    typename := lynxShort;
+                ELSIF Optional(Scanner.Int) THEN
+                    typename := lynxInt;
+                ELSIF Optional(Scanner.Long) THEN
+                    typename := lynxLong;
+                ELSE
+                    Error(position, Diagnostics.Invalid, "Missing integral type specifier");
+                    typename := lynxInt;
+                END;
+                type := 
+                    SyntaxTree.NewQualifiedType(
+                        position, 
+                        currentScope,
+                        SyntaxTree.NewQualifiedIdentifier(
+                            position, SyntaxTree.invalidIdentifier, typename));
+                varname := Identifier(position);
+                varname := localIdentTable.Enter(varname);
+                variable := SyntaxTree.NewVariable(position, varname);
+                CommentSymbol(variable);
+                variable.SetType(type);
+                currentScope.AddVariable(variable);
+                Check(Scanner.In);
+                from := Expression();
+                Check(Scanner.Colon);
+                to := Expression();
+                Check(Scanner.RightParenthesis);
+            ELSE
+                varname := SyntaxTree.invalidIdentifier;
+            END;
+            channel := PrimaryExpression();
+            Check(Scanner.Question);
+            target := PrimaryExpression();
+            Check(Scanner.Colon);
+
+            (* prolog *)
+            IF varname = SyntaxTree.invalidIdentifier THEN
+                statement := NewLynxAddsel(position, index, varname, channel, outer);
+                statements.AddStatement(statement);
+            ELSE
+                forStatement := SyntaxTree.NewForStatement(symbol.start, outer);
+                designator := SyntaxTree.NewIdentifierDesignator(position, varname);
+                forStatement.SetVariable(designator);
+                forStatement.SetFrom(from);
+                forStatement.SetTo(to);
+                forBody := SyntaxTree.NewStatementSequence();
+                statement := 
+                    NewLynxAddsel(position, index, varname, channel, forStatement);
+                forBody.AddStatement(statement);
+                forStatement.SetStatements(forBody);
+                statements.AddStatement(forStatement);
+            END;
+
+            (* case part *)
+            casePart := SyntaxTree.NewCasePart();
+            casePart.elements.AddExpression(SyntaxTree.NewIntegerValue(position, index));
+
+            (* same logic as for switch: *)
+            caseBody := StatementList(caseStatement);
+            length := caseBody.Length();
+            IF length = 0 THEN
+                Error(symbol.start, Diagnostics.Invalid, "Fall through in switch section");
+            ELSE
+                last := caseBody.GetStatement(length-1);
+                IF last IS SyntaxTree.ExitStatement THEN
+                    caseBody.RemoveStatement(last);
+                ELSIF ~(last IS SyntaxTree.ReturnStatement) THEN
+                    Error(symbol.start, Diagnostics.Invalid, "Fall through in switch section");
+                END;
+            END;
+
+            statement := NewPortStatement(position, lynxReceive, channel(SyntaxTree.Designator), target, caseStatement);
+            caseBody.PrependStatement(statement);
+            IF varname # SyntaxTree.invalidIdentifier THEN
+                statement := NewLynxSelidx(position, varname, caseStatement);
+                caseBody.PrependStatement(statement);
+            END;
+
+            casePart.SetStatements(caseBody);
+            caseStatement.AddCasePart(casePart);
+
+            localIdentTable.CloseScope;
+
+            IF Trace THEN 
+                E("SelectSection")
+            END;
+        END SelectSection;
+
+        PROCEDURE SelectStatement(statements: SyntaxTree.StatementSequence; outer: SyntaxTree.Statement);
+            VAR statement: SyntaxTree.Statement;
+                caseStatement: SyntaxTree.CaseStatement;
+                expression: SyntaxTree.Expression;
+                index: LONGINT;
+                position: LONGINT;
+        BEGIN
+            IF Trace THEN 
+                S("SelectStatement")
+            END;
+            position := symbol.start;
+            Check(Scanner.Select);
+            statement := NewLynxNewsel(position, outer);
+            statements.AddStatement(statement);
+            caseStatement := SyntaxTree.NewCaseStatement(position, outer);
+            expression := NewLynxSelect(position);
+            caseStatement.SetVariable(expression);
+            Check(Scanner.LeftBrace);
+            index := 0;
+            WHILE Peek(Scanner.Case) DO
+                SelectSection(statements, caseStatement, index, outer);
+                INC(index);
+            END;
+            position := symbol.start;
+            Check(Scanner.RightBrace);
+            IF index = 0 THEN
+                Error(position, Diagnostics.Invalid, "Empty select statement");
+            END;
+            statements.AddStatement(caseStatement);
+            IF Trace THEN 
+                E("SelectStatement")
+            END;
+        END SelectStatement;
+
+        (**
+            while-statement:
+                'while' '(' boolean-expression ')' embedded-statement
+        **)
+        PROCEDURE WhileStatement(statements: SyntaxTree.StatementSequence; outer: SyntaxTree.Statement);
+            VAR expression: SyntaxTree.Expression;
+                whileStatement: SyntaxTree.WhileStatement;
+                statementSequence: SyntaxTree.StatementSequence;
+                b: BOOLEAN;
+        BEGIN
+            IF Trace THEN 
+                S("WhileStatement")
+            END;
+            Check(Scanner.While);
+            whileStatement := SyntaxTree.NewWhileStatement(symbol.start, outer);
+            (* CommentStatement(whileStatement); *)
+            Check(Scanner.LeftParenthesis);
+            expression := Expression();
+            Check(Scanner.RightParenthesis);
+            whileStatement.SetCondition(expression);
+            statementSequence := SyntaxTree.NewStatementSequence();
+            b := EmbeddedStatement(statementSequence, whileStatement);
+            whileStatement.SetStatements(statementSequence);
+            statements.AddStatement(whileStatement);
+            IF Trace THEN 
+                E("WhileStatement")
+            END;
+        END WhileStatement;
+
+        (**
+            do-statement:
+                'do' embedded-statement 'while' '(' boolean-expression ')' ';'
+        **)
+        PROCEDURE DoStatement(statements: SyntaxTree.StatementSequence; outer: SyntaxTree.Statement);
+            VAR expression: SyntaxTree.Expression;
+                repeatStatement: SyntaxTree.RepeatStatement;
+                statementSequence: SyntaxTree.StatementSequence;
+                position: LONGINT;
+                b: BOOLEAN;
+        BEGIN
+            IF Trace THEN 
+                S("DoStatement")
+            END;
+            Check(Scanner.Do);
+            repeatStatement := SyntaxTree.NewRepeatStatement(symbol.start, outer);
+            (* CommentStatement(repeatStatement); *)
+            statementSequence := SyntaxTree.NewStatementSequence();
+            b := EmbeddedStatement(statementSequence, repeatStatement);
+            repeatStatement.SetStatements(statementSequence);
+            Check(Scanner.While);
+            Check(Scanner.LeftParenthesis);
+            position := symbol.start;
+            expression := Expression();
+            Check(Scanner.RightParenthesis);
+            expression := NewUnaryExpression(position, expression, Scanner.Exclamation); 
+            repeatStatement.SetCondition(expression);
+            statements.AddStatement(repeatStatement);
+            IF Trace THEN 
+                E("DoStatement")
+            END;
+        END DoStatement;
+
+        (**
+            statement-expression-list:
+                statement-expression
+                statement-expression-list ',' statement-expression
+        **)
+        PROCEDURE StatementExpressionList(statements: SyntaxTree.StatementSequence; outer: SyntaxTree.Statement);
+            VAR b: BOOLEAN;
+        BEGIN
+            IF Trace THEN 
+                S("StatementExpressionList")
+            END;
+            REPEAT
+                b := StatementExpression(statements, outer, NIL);
+            UNTIL ~Optional(Scanner.Comma);
+            IF Trace THEN 
+                E("StatementExpressionList")
+            END;
+        END StatementExpressionList;
+
+        (**
+            for-initializer:
+                local-variable-declaration
+                statement-expression-list
+        **)
+        PROCEDURE ForInitializer(statements: SyntaxTree.StatementSequence; outer: SyntaxTree.Statement);
+            VAR isDeclaration: BOOLEAN;
+                b: BOOLEAN;
+        BEGIN
+            IF Trace THEN 
+                S("ForInitializer")
+            END;
+
+            IF Peek(Scanner.Bool) OR Peek(Scanner.Sbyte) OR
+                    Peek(Scanner.Short) OR Peek(Scanner.Int) OR
+                    Peek(Scanner.Long) OR Peek(Scanner.Char) OR
+                    Peek(Scanner.Float) OR Peek(Scanner.Double) OR
+                    Peek(Scanner.Object) OR Peek(Scanner.String) THEN
+                LocalVariableDeclaration(statements, outer, NIL);
+            ELSIF Peek(Scanner.Identifier) THEN
+                (* either local-variable-declaration or statement expression *)
+                b := ExpressionOrDeclaration(statements, outer, isDeclaration);
+                IF ~isDeclaration & Optional(Scanner.Comma) THEN
+                    StatementExpressionList(statements, outer);
+                END;
+            ELSE
+                StatementExpressionList(statements, outer);
+            END;
+
+            IF Trace THEN 
+                E("ForInitializer")
+            END;
+        END ForInitializer;
+
+        (**
+            for-iterator:
+                statement-expression-list
+        **)
+        PROCEDURE ForIterator(statements: SyntaxTree.StatementSequence; outer: SyntaxTree.Statement);
+        BEGIN
+            IF Trace THEN 
+                S("ForIterator")
+            END;
+            StatementExpressionList(statements, outer);
+            IF Trace THEN 
+                E("ForIterator")
+            END;
+        END ForIterator;
+
+        (**
+            for-statement:
+                'for' '(' [for-initializer] ';' [for-condition] ';' [for-iterator] ')' embedded-statement
+
+            for-condition:
+                boolean-expression
+        **)
+        PROCEDURE ForStatement(statements: SyntaxTree.StatementSequence; outer: SyntaxTree.Statement);
+            VAR expression: SyntaxTree.Expression;
+                whileStatement: SyntaxTree.WhileStatement;
+                statementSequence: SyntaxTree.StatementSequence;
+                iterator: SyntaxTree.StatementSequence;
+                position0, position1: LONGINT;
+                i: LONGINT;
+                b: BOOLEAN;
+        BEGIN
+            IF Trace THEN 
+                S("ForStatement")
+            END;
+            Check(Scanner.For);
+            localIdentTable.OpenScope;
+            whileStatement := SyntaxTree.NewWhileStatement(symbol.start, outer);
+            (* CommentStatement(whileStatement); *)
+            Check(Scanner.LeftParenthesis);
+            IF ~Optional(Scanner.Semicolon) THEN
+                ForInitializer(statements, outer);
+                Check(Scanner.Semicolon);
+            END;
+            position0 := symbol.start;
+            position1 := symbol.end;
+            IF ~Optional(Scanner.Semicolon) THEN
+                expression := Expression();
+                Check(Scanner.Semicolon);
+            ELSE
+                expression := SyntaxTree.NewBooleanValue(position0, TRUE);
+                expression.End(position1);
+            END;
+            IF ~Optional(Scanner.RightParenthesis) THEN
+                iterator := SyntaxTree.NewStatementSequence();
+                ForIterator(iterator, whileStatement);
+                Check(Scanner.RightParenthesis);
+            ELSE
+                iterator := NIL;
+            END;
+            whileStatement.SetCondition(expression);
+            statementSequence := SyntaxTree.NewStatementSequence();
+            b := EmbeddedStatement(statementSequence, whileStatement);
+            IF iterator # NIL THEN
+                FOR i := 0 TO iterator.Length() - 1 DO
+                    statementSequence.AddStatement(iterator.GetStatement(i));
+                END;
+            END;
+            whileStatement.SetStatements(statementSequence);
+            statements.AddStatement(whileStatement);
+            localIdentTable.CloseScope;
+            IF Trace THEN 
+                E("ForStatement")
+            END;
+        END ForStatement;
+
+        (**
+            return-statement:
+                'return' [expression] ';'
+        **)
+        PROCEDURE ReturnStatement(statements: SyntaxTree.StatementSequence; outer: SyntaxTree.Statement);
+            VAR returnStatement: SyntaxTree.ReturnStatement;
+                expression: SyntaxTree.Expression;
+        BEGIN
+            IF Trace THEN 
+                S("ReturnStatement")
+            END;
+            Check(Scanner.Return);
+            returnStatement := SyntaxTree.NewReturnStatement(symbol.start, outer);
+            (* CommentStatement(returnStatement); *)
+            IF ~Optional(Scanner.Semicolon) THEN
+                expression := Expression();
+                returnStatement.SetReturnValue(expression);
+                Check(Scanner.Semicolon);
+            END;
+            statements.AddStatement(returnStatement);
+            IF Trace THEN 
+                E("ReturnStatement")
+            END;
+        END ReturnStatement;
+
+        (**
+            break-statement:
+                'break' ';'
+        **)
+        PROCEDURE BreakStatement(statements: SyntaxTree.StatementSequence; outer: SyntaxTree.Statement);
+            VAR statement: SyntaxTree.Statement;
+        BEGIN
+            IF Trace THEN 
+                S("BreakStatement")
+            END;
+            Check(Scanner.Break);
+            statement := SyntaxTree.NewExitStatement(symbol.start, outer);
+            (* CommentStatement(statement); *)
+            statements.AddStatement(statement);
+            Check(Scanner.Semicolon);
+            IF Trace THEN 
+                E("BreakStatement")
+            END;
+        END BreakStatement;
+
+        (**
+            embedded-statement:
+                block
+                empty-statement
+                expression-statement
+                selection-statement
+                iteration-statement
+                jump-statement
+
+            empty-statement:
+                ';'
+
+            selection-statement:
+                if-statement
+                switch-statement
+                select-statement
+
+            iteration-statement:
+                while-statement
+                do-statement
+                for-statement
+
+            jump-statement:
+                break-statement
+                return-statement
+        **)
+        PROCEDURE EmbeddedStatement(statements: SyntaxTree.StatementSequence; outer: SyntaxTree.Statement): BOOLEAN;
+            VAR result: BOOLEAN;
+        BEGIN
+            IF Trace THEN 
+                S("EmbeddedStatement")
+            END;
+            IF Optional(Scanner.Semicolon) THEN
+                result := FALSE;
+            ELSIF Peek(Scanner.LeftBrace) THEN
+                Block(statements, outer);
+                result := TRUE;
+            ELSIF Peek(Scanner.If) THEN
+                IfStatement(statements, outer);
+                result := TRUE;
+            ELSIF Peek(Scanner.Switch) THEN
+                SwitchStatement(statements, outer);
+                result := TRUE;
+            ELSIF Peek(Scanner.Select) THEN
+                SelectStatement(statements, outer);
+                result := TRUE;
+            ELSIF Peek(Scanner.While) THEN
+                WhileStatement(statements, outer);
+                result := TRUE;
+            ELSIF Peek(Scanner.Do) THEN
+                DoStatement(statements, outer);
+                result := TRUE;
+            ELSIF Peek(Scanner.For) THEN
+                ForStatement(statements, outer);
+                result := TRUE;
+            ELSIF Peek(Scanner.Break) THEN
+                BreakStatement(statements, outer);
+                result := TRUE;
+            ELSIF Peek(Scanner.Return) THEN
+                ReturnStatement(statements, outer);
+                result := TRUE;
+            ELSE
+                result := ExpressionStatement(statements, outer);
+            END;
+            IF Trace THEN 
+                E("EmbeddedStatement")
+            END;
+            RETURN result;
+        END EmbeddedStatement;
+
+        (**
+            statement:
+                declaration-statement
+                embedded-statement
+
+            declaration-statement:
+                local-variable-declaration ';'
+                local-constant-declaration ';'
+        **)
+        PROCEDURE ExpressionOrDeclaration(
+                statements: SyntaxTree.StatementSequence; 
+                outer: SyntaxTree.Statement;
+                VAR isDeclaration: BOOLEAN): BOOLEAN;
+            VAR result: BOOLEAN;
+                name0, name1: SyntaxTree.Identifier;
+                position0, position1, position2: LONGINT;
+                leftBracket: BOOLEAN;
+                qualifiedIdentifier: SyntaxTree.QualifiedIdentifier;
+                type: SyntaxTree.Type;
+                expression: SyntaxTree.Expression;
+                expressionList: SyntaxTree.ExpressionList;
+        BEGIN
+            name0 := Identifier(position0);
+            IF Optional(Scanner.Period) THEN
+                name1 := Identifier(position1);
+            ELSE
+                name1 := SyntaxTree.invalidIdentifier;
+            END;
+            isDeclaration := FALSE;
+            leftBracket := FALSE;
+            position2 := symbol.start;
+            IF Peek(Scanner.Identifier) THEN
+                isDeclaration := TRUE;
+            ELSIF Optional(Scanner.LeftBracket) THEN
+                leftBracket := TRUE;
+                IF Peek(Scanner.RightBracket) OR Peek(Scanner.Comma) THEN
+                    isDeclaration := TRUE;
+                END;
+            END;
+            IF isDeclaration THEN
+                (* local-variable-declaration *)
+                IF name1 = SyntaxTree.invalidIdentifier THEN
+                    name1 := name0;
+                    name0 := SyntaxTree.invalidIdentifier;
+                END;
+                qualifiedIdentifier := SyntaxTree.NewQualifiedIdentifier(position0, name0, name1);                       
+                type := SyntaxTree.NewQualifiedType(
+                    qualifiedIdentifier.position, currentScope, qualifiedIdentifier);
+                IF leftBracket THEN
+                    type := RankSpecifier(type);
+                    Check(Scanner.RightBracket);
+                END;
+                WHILE Optional(Scanner.LeftBracket) DO
+                    type := RankSpecifier(type);
+                    Check(Scanner.RightBracket);
+                END;
+                LocalVariableDeclaration(statements, outer, type);
+            ELSE
+                (* expression-statement *)
+                name0 := localIdentTable.Find(name0);
+                expression := SyntaxTree.NewIdentifierDesignator(position0, name0);
+                IF name1 # SyntaxTree.invalidIdentifier THEN
+                    expression := SyntaxTree.NewSelectorDesignator(position1, expression(SyntaxTree.Designator), name1);
+                END;
+                IF leftBracket THEN
+                    expressionList := SyntaxTree.NewExpressionList();
+                    ExpressionList(expressionList);
+                    Check(Scanner.RightBracket);
+                    expression := SyntaxTree.NewBracketDesignator(position2, expression(SyntaxTree.Designator), expressionList);
+                END;
+                expression := Accessors(expression, FALSE);
+                result := StatementExpression(statements, outer, expression);
+            END;
+            RETURN result;
+        END ExpressionOrDeclaration;
+
+        PROCEDURE Statement(statements: SyntaxTree.StatementSequence; outer: SyntaxTree.Statement): BOOLEAN;
+            VAR result: BOOLEAN;
+                isDeclaration: BOOLEAN;
+        BEGIN
+            IF Trace THEN 
+                S("Statement")
+            END;
+            IF Peek(Scanner.Const) THEN
+                LocalConstantDeclaration(statements, outer);
+                Check(Scanner.Semicolon);
+                result := TRUE;
+            ELSIF Peek(Scanner.Bool) OR Peek(Scanner.Sbyte) OR
+                    Peek(Scanner.Short) OR Peek(Scanner.Int) OR
+                    Peek(Scanner.Long) OR Peek(Scanner.Char) OR
+                    Peek(Scanner.Float) OR Peek(Scanner.Double) OR
+                    Peek(Scanner.Object) OR Peek(Scanner.String) THEN
+                LocalVariableDeclaration(statements, outer, NIL);
+                Check(Scanner.Semicolon);
+                result := TRUE;
+            ELSIF Peek(Scanner.Identifier) THEN
+                (* either local-variable-declaration or statement expression *)
+                result := ExpressionOrDeclaration(statements, outer, isDeclaration);
+                Check(Scanner.Semicolon);
+            ELSE
+                result := EmbeddedStatement(statements, outer);
+            END;
+            IF Trace THEN 
+                E("Statement")
+            END;
+            RETURN result;
+        END Statement;
+
+        (**
+            statement-list:
+                statement
+                statement-list statement
+        **)
+        PROCEDURE StatementList(outer: SyntaxTree.Statement): SyntaxTree.StatementSequence;
+            VAR statements: SyntaxTree.StatementSequence; 
+                b: BOOLEAN;
+        BEGIN
+            IF Trace THEN 
+                S("StatementList")
+            END;
+            statements := SyntaxTree.NewStatementSequence();
+            REPEAT
+                b := Statement(statements, outer);
+            UNTIL Peek(Scanner.RightBrace) OR Peek(Scanner.Case) OR Peek(Scanner.Default) ;
+            IF Trace THEN 
+                E("StatementList")
+            END;
+            RETURN statements;
+        END StatementList;
+
+        (**
+            block:
+                '{' [statement-list] '}'
+        **)
+        PROCEDURE Body(scope: SyntaxTree.ProcedureScope): SyntaxTree.Body;
+            VAR body: SyntaxTree.Body;
+                previousScope: SyntaxTree.Scope;
+        BEGIN
+            IF Trace THEN 
+                S("Body")
+            END;
+            previousScope := currentScope;
+            currentScope := scope;
+            Check(Scanner.LeftBrace);
+            body := SyntaxTree.NewBody(symbol.start, scope);
+            IF ~Optional(Scanner.RightBrace) THEN
+                body.SetStatementSequence(StatementList(body));
+                Check(Scanner.RightBrace);
+            END;
+            currentScope := previousScope;
+            IF Trace THEN 
+                E("Body")
+            END;
+            RETURN body;
+        END Body;
+
+        (**
+            type:
+                value-type
+                reference-type
+                port-type
+
+            value-type:
+                struct-type
+
+            struct-type:
+                type-name
+                simple-type
+
+            simple-type:
+                numeric-type
+               'bool'
+
+            numeric-type:
+                integral-type
+                floating-point-type
+
+            integral-type:
+                'sbyte'
+                'short'
+                'int'
+                'long'
+                'char'
+
+            floating-point-type:
+                'float'
+                'double'
+
+            reference-type:
+                class-type
+                array-type
+                delegate-type
+
+            class-type:
+                type-name
+                'object'
+                'string'
+
+            array-type:
+                non-array-type rank-specifiers
+
+            non-array-type:
+                value-type
+                class-type
+                delegate-type
+
+            rank-specifiers:
+                rank-specifier
+                rank-specifiers rank-specifier
+
+            rank-specifier:
+                '[' [dim-separators] ']'
+
+            dim-separators:
+                ','
+                dim-separators ','
+
+            delegate-type:
+                type-name
+        **)
+        PROCEDURE RankSpecifier(type: SyntaxTree.Type): SyntaxTree.Type;
+            VAR position: LONGINT;
+                arrayType: SyntaxTree.ArrayType;
+                pointerType: SyntaxTree.PointerType;
+        BEGIN
+            IF Trace THEN 
+                S("RankSpecifier")
+            END;
+            position := symbol.start;
+            REPEAT
+                arrayType := SyntaxTree.NewArrayType(position, currentScope, SyntaxTree.Open);
+                arrayType.SetArrayBase(type);
+                type := arrayType;
+            UNTIL ~Optional(Scanner.Comma);
+            pointerType := SyntaxTree.NewPointerType(position, currentScope);
+            pointerType.SetPointerBase(type);
+            type := pointerType;
+            IF Trace THEN 
+                E("RankSpecifier")
+            END;
+            RETURN type;
+        END RankSpecifier; 
+
+        PROCEDURE NonArrayType(): SyntaxTree.Type;
+            VAR type: SyntaxTree.Type;
+                position: LONGINT;
+                name: SyntaxTree.Identifier;
+                direction: LONGINT;
+                qualifiedIdentifier: SyntaxTree.QualifiedIdentifier;
+        BEGIN
+            IF Trace THEN 
+                S("NonArrayType")
+            END;
+            position := symbol.start;
+            name := SyntaxTree.invalidIdentifier;
+            direction := -1;
+            IF Optional(Scanner.Bool) THEN
+                name := lynxBool;
+            ELSIF Optional(Scanner.Sbyte) THEN
+                name := lynxSbyte;
+            ELSIF Optional(Scanner.Short) THEN
+                name := lynxShort;
+            ELSIF Optional(Scanner.Int) THEN
+                name := lynxInt;
+            ELSIF Optional(Scanner.Long) THEN
+                name := lynxLong;
+            ELSIF Optional(Scanner.Char) THEN
+                name := lynxChar;
+            ELSIF Optional(Scanner.Float) THEN
+                name := lynxFloat;
+            ELSIF Optional(Scanner.Double) THEN
+                name := lynxDouble;
+            ELSIF Optional(Scanner.Object) THEN
+                name := lynxObject;
+            ELSIF Optional(Scanner.String) THEN
+                name := lynxString;
+            ELSIF Optional(Scanner.In) THEN
+                direction := SyntaxTree.InPort;
+            ELSIF Optional(Scanner.Out) THEN
+                direction := SyntaxTree.OutPort;
+            END;
+            IF direction >= 0 THEN
+                type := SyntaxTree.NewPortType(position, direction, NIL, currentScope);
+            ELSE
+                IF name # SyntaxTree.invalidIdentifier THEN
+                    qualifiedIdentifier := 
+                        SyntaxTree.NewQualifiedIdentifier(
+                            position, SyntaxTree.invalidIdentifier, name);
+                ELSE
+                    qualifiedIdentifier := QualifiedIdentifier();
+                END;
+                type := SyntaxTree.NewQualifiedType(
+                    qualifiedIdentifier.position, currentScope, qualifiedIdentifier);
+            END;
+            IF Trace THEN 
+                E("NonArrayType")
+            END;
+            RETURN type;
+        END NonArrayType;
+
+        PROCEDURE Type(): SyntaxTree.Type;
+            VAR type: SyntaxTree.Type;
+        BEGIN
+            IF Trace THEN 
+                S("Type")
+            END;
+            type := NonArrayType();
+            WHILE Optional(Scanner.LeftBracket) DO
+                type := RankSpecifier(type);
+                Check(Scanner.RightBracket);
+            END;
+            IF Trace THEN 
+                E("Type")
+            END;
+            RETURN type;
+        END Type;
+
+        (**
+            attributes:
+                '[' attribute-list ']'
+
+            attribute-list:
+                attribute
+                attribute-list ',' attribute
+
+            attribute:
+                attribute-name [attribute-argument]
+
+            attribute-name:
+                identifier
+
+            attribute-argument:
+                '(' attribute-argument-expression ')'
+
+            attribute-argument-expression:
+                expression
+        **)
+        PROCEDURE AppendModifier(VAR list: SyntaxTree.Modifier; modifier: SyntaxTree.Modifier);
+        VAR this, next: SyntaxTree.Modifier;
+        BEGIN
+            IF list = NIL THEN 
+                list := modifier
+            ELSE
+                this := list;
+                next := list.nextModifier;
+                WHILE next # NIL DO
+                    this := next;
+                    next := this.nextModifier;
+                END;
+                this.SetNext(modifier);
+            END;
+        END AppendModifier;
+
+        PROCEDURE Attributes(): SyntaxTree.Modifier;
+            VAR identifier: SyntaxTree.Identifier;
+                modifier, list: SyntaxTree.Modifier;
+                position: LONGINT;
+                expression: SyntaxTree.Expression;
+        BEGIN
+            IF Trace THEN
+                S("Attributes")
+            END;
+            (* left bracket already consumed *)
+            list := NIL;
+            REPEAT            
+                position := symbol.start;
+                identifier := Identifier(position);
+                IF Optional(Scanner.LeftParenthesis) THEN
+                    expression := Expression();
+                    Check(Scanner.RightParenthesis);
+                ELSE
+                    expression := NIL;
+                END;
+                modifier := SyntaxTree.NewModifier(position, identifier, expression);
+                AppendModifier(list, modifier);
+            UNTIL ~Optional(Scanner.Comma);
+            Check(Scanner.RightBracket);
+            IF Trace THEN
+                E("Attributes")
+            END;
+            RETURN list;
+        END Attributes;
+
+        (**
+            constant-modifiers:
+                constant-modifier
+                constant-modifiers constant-modifier
+
+            constant-modifier:
+                'public'
+
+            field-modifiers:
+                field-modifier
+                field-modifiers field-modifier
+
+            field-modifier:
+                'public'
+                'internal'
+
+            method-modifiers:
+                method-modifier
+                method-modifiers method-modifier
+
+            method-modifier:
+                'public'
+
+            constructor-modifiers:
+                constructor-modifier
+                constructor-modifiers constructor-modifier
+
+            constructor-modifier:
+                public
+
+            class-modifiers:
+                class-modifier
+                class-modifiers class-modifier
+
+            class-modifier:
+                'public'
+
+            struct-modifiers:
+                struct-modifier
+                struct-modifiers struct-modifier
+
+            struct-modifier:
+                'public'
+
+            delegate-modifiers:
+                delegate-modifier
+                delegate-modifiers delegate-modifier
+
+            delegate-modifier:
+               'public'
+        **)
+        PROCEDURE Modifiers(VAR modifiers: SET);
+        BEGIN
+            modifiers := {};
+            LOOP
+                IF Optional(Scanner.Public) THEN
+                    INCL(modifiers, Public);
+                ELSIF Optional(Scanner.Internal) THEN
+                    INCL(modifiers, Internal);
+                ELSE
+                    EXIT;
+                END;
+            END;
+        END Modifiers;
+
+        PROCEDURE IdentifierAccess(modifiers: SET; allowedReadOnly: BOOLEAN): SET;
+            VAR access: SET;
+        BEGIN
+            IF modifiers * {Public, Internal} = {Public, Internal} THEN
+                Error(symbol.start, Diagnostics.Invalid, "conflicting modifiers");
+            END;
+            IF Public IN modifiers THEN
+                access := SyntaxTree.Public + SyntaxTree.Protected + SyntaxTree.Internal;
+            ELSIF Internal IN modifiers THEN
+                IF ~allowedReadOnly THEN
+                    Error(symbol.start, Diagnostics.Invalid, "may not be defined internal")
+                ELSE
+                    access :=  SyntaxTree.ReadOnly + {SyntaxTree.InternalWrite};
+                END;
+            ELSE
+                access := SyntaxTree.Internal;
+            END;
+            RETURN access;
+        END IdentifierAccess;
+
+        (**
+            constant-declaration:
+                [constant-modifiers] 'const' type constant-declarators ';'
+
+            constant-declarators:
+                constant-declarator
+                constant-declarators ',' constant-declarator
+
+            constant-declarator:
+                identifier '=' constant-expression
+        **)
+        PROCEDURE ConstantDeclarator(
+                parentScope: SyntaxTree.Scope; 
+                modifiers: SET; 
+                type: SyntaxTree.Type);
+            VAR name: SyntaxTree.Identifier;
+                position: LONGINT;
+                constant: SyntaxTree.Constant;
+                expression: SyntaxTree.Expression;
+                access: SET;
+        BEGIN
+            IF Trace THEN 
+                S("ConstantDeclarator") 
+            END;
+            name := Identifier(position);
+            name := localIdentTable.Enter(name);
+            access := IdentifierAccess(modifiers, FALSE);
+            constant := SyntaxTree.NewConstant(position, name);
+            CommentSymbol(constant);
+            constant.SetAccess(access);
+            (* ACHTUNG: Make sure that Fox semantic checker will respect a type set at this stage: *)
+            constant.SetType(type);
+            Check(Scanner.Equal);
+            expression := Expression();
+            constant.SetValue(expression);
+            parentScope.AddConstant(constant);
+            IF Trace THEN 
+                E("ConstantDeclarator") 
+            END;
+        END ConstantDeclarator;
+
+        PROCEDURE ConstantDeclaration(parentScope: SyntaxTree.Scope; modifiers: SET);
+            VAR type: SyntaxTree.Type;
+        BEGIN
+            IF Trace THEN 
+                S("ConstantDeclaration") 
+            END;
+            type := Type();
+            REPEAT
+                ConstantDeclarator(parentScope, modifiers, type);
+            UNTIL ~Optional(Scanner.Comma);
+            Check(Scanner.Semicolon);
+            IF Trace THEN 
+                E("ConstantDeclaration") 
+            END;
+        END ConstantDeclaration;
+
+        (**
+            field-declaration:
+                [field-modifiers] type variable-declarators ';'
+
+            field-modifiers:
+                field-modifier
+                field-modifiers field-modifier
+
+            variable-declarators:
+                variable-declarator
+                variable-declarators ',' variable-declarator
+
+            variable-declarator:
+                identifier
+                identifier '=' variable-initializer
+
+            variable-initializer:
+                expression
+//                array-initializer
+        **)
+        PROCEDURE VariableDeclarator(
+                parentScope: SyntaxTree.Scope; 
+                modifiers: SET; 
+                type: SyntaxTree.Type;
+                name: SyntaxTree.Identifier;
+                position: LONGINT);
+            VAR variable: SyntaxTree.Variable;
+                expression: SyntaxTree.Expression;
+                designator: SyntaxTree.Designator;
+                statement: SyntaxTree.Statement;
+                start: LONGINT;
+                access: SET;
+        BEGIN
+            IF Trace THEN 
+                S("VariableDeclarator") 
+            END;
+            IF name = SyntaxTree.invalidIdentifier THEN
+                name := Identifier(position);
+            END;
+            name := localIdentTable.Enter(name);
+            access := IdentifierAccess(modifiers, TRUE);
+            variable := SyntaxTree.NewVariable(position, name);
+            CommentSymbol(variable);
+            variable.SetAccess(access);
+            variable.SetType(type);
+            parentScope.AddVariable(variable);
+            start := symbol.start;
+            (* 'initOuter' is set to NIL in contexts where initialization is not yet implemented *)
+            IF (initOuter # NIL) & Optional(Scanner.Equal) THEN
+                (* ACHTUNG: array-initializer form is not supported *)
+                designator := SyntaxTree.NewIdentifierDesignator(position, name);
+                expression := Expression();
+                statement := SyntaxTree.NewAssignment(start, designator, expression, initOuter);
+                initStatements.AddStatement(statement);
+            END;
+            IF Trace THEN 
+                E("VariableDeclarator") 
+            END;
+        END VariableDeclarator;
+
+        PROCEDURE FieldDeclaration(
+                parentScope: SyntaxTree.Scope; 
+                modifiers: SET;
+                type: SyntaxTree.Type;
+                name: SyntaxTree.Identifier;
+                position: LONGINT);
+        BEGIN
+            IF Trace THEN 
+                S("FieldDeclaration") 
+            END;
+            REPEAT
+                VariableDeclarator(parentScope, modifiers, type, name, position);
+                name := SyntaxTree.invalidIdentifier;
+                position := invalidPosition;
+            UNTIL ~Optional(Scanner.Comma);
+            Check(Scanner.Semicolon);
+            IF Trace THEN 
+                E("FieldDeclaration") 
+            END;
+        END FieldDeclaration;
+
+        (**
+            formal-parameter-list:
+                fixed-parameters
+
+            fixed-parameters:
+                fixed-parameter
+                fixed-parameters ',' fixed-parameter
+
+            fixed-parameter:
+                [parameter-modifier] type identifier
+
+            parameter-modifier:
+               'ref'
+        **)
+        PROCEDURE FixedParameter(procedureType: SyntaxTree.ProcedureType; parentScope: SyntaxTree.Scope);
+            VAR type: SyntaxTree.Type;
+                name: SyntaxTree.Identifier;
+                parameter: SyntaxTree.Parameter;
+                kind, position: LONGINT;
+        BEGIN
+            IF Trace THEN 
+                S("FixedParameter")
+            END;
+            IF Optional(Scanner.Ref) THEN
+                kind := SyntaxTree.VarParameter;
+            ELSE
+                kind := SyntaxTree.ValueParameter;
+            END;
+            type := Type();
+            name := Identifier(position);
+            parameter := SyntaxTree.NewParameter(position, procedureType, name, kind);
+            procedureType.AddParameter(parameter);
+            parameter.SetType(type);
+            IF Trace THEN 
+                E("FixedParameter")
+            END;
+        END FixedParameter;
+
+        PROCEDURE FormalParameterList(
+                procedureType: SyntaxTree.ProcedureType; 
+                parentScope: SyntaxTree.Scope;
+                returnType: SyntaxTree.Type);
+        BEGIN
+            IF Trace THEN 
+                S("FormalParameterList")
+            END;
+            Check(Scanner.LeftParenthesis);
+            IF ~Optional(Scanner.RightParenthesis) THEN
+                REPEAT
+                    FixedParameter(procedureType, parentScope);
+                UNTIL ~Optional(Scanner.Comma);
+                Check(Scanner.RightParenthesis);
+            END;
+            IF returnType # NIL THEN
+                procedureType.SetReturnType(returnType);
+            END;
+            IF Trace THEN 
+                E("FormalParameterList")
+            END;
+        END FormalParameterList;
+
+        (**
+            constructor-initializer:
+                ':' 'base' '(' [argument-list] ')'
+        **)
+        PROCEDURE ConstructorInitializer(scope: SyntaxTree.ProcedureScope);
+        BEGIN
+            IF Trace THEN 
+                S("ConstructorInitializer")
+            END;
+            (* TODO *)
+            IF Trace THEN 
+                E("ConstructorInitializer")
+            END;
+        END ConstructorInitializer;
+
+        (**
+            method-declaration:
+                method-header method-body
+
+            method-header:
+                [method-modifiers] return-type member-name '(' [formal-parameter-list] ')'
+
+            return-type:
+                type
+               'void'
+
+            member-name:
+                identifier
+
+            method-body:
+                block
+
+            constructor-declaration:
+                [constructor-modifiers] constructor-declarator constructor-body
+
+            constructor-declarator:
+                identifier ( [formal-parameter-list] ) [constructor-initializer]
+
+            constructor-body:
+                block
+        **)
+        PROCEDURE ProcedureDeclaration(
+                parentScope: SyntaxTree.Scope; 
+                modifiers: SET;
+                type: SyntaxTree.Type;
+                name: SyntaxTree.Identifier;
+                position: LONGINT;
+                isConstructor: BOOLEAN);
+            VAR procedure: SyntaxTree.Procedure;
+                procedureType: SyntaxTree.ProcedureType;
+                procedureScope: SyntaxTree.ProcedureScope;
+                previousScope: SyntaxTree.Scope;
+                access: SET;
+                body: SyntaxTree.Body;
+        BEGIN
+            procedureType := SyntaxTree.NewProcedureType(position, parentScope);
+            access := IdentifierAccess(modifiers, FALSE);
+            procedureScope := SyntaxTree.NewProcedureScope(parentScope);
+            procedure := SyntaxTree.NewProcedure(position, name, procedureScope);
+            procedure.SetConstructor(isConstructor);
+            CommentSymbol(procedure);
+            procedure.SetAccess(access);
+            procedure.SetType(procedureType);
+            FormalParameterList(procedureType, procedureScope, type);
+            IF isConstructor & Optional(Scanner.Colon) THEN
+                (* TODO: Connect initializer to the body *)
+                ConstructorInitializer(procedureScope);
+            END;
+            previousScope := currentScope;
+            currentScope := procedureScope;
+            body := Body(procedureScope);
+            currentScope := previousScope;
+            procedureScope.SetBody(body);
+            parentScope.AddProcedure(procedure);
+        END ProcedureDeclaration;
+
+        PROCEDURE MethodDeclaration(
+                parentScope: SyntaxTree.Scope; 
+                modifiers: SET;
+                type: SyntaxTree.Type;
+                name: SyntaxTree.Identifier;
+                position: LONGINT);
+        BEGIN
+            IF Trace THEN 
+                S("MethodDeclaration") 
+            END;
+            localIdentTable.Reset;
+            IF (name = identMain) &
+                    (parentScope IS SyntaxTree.CellScope) &
+                    ~parentScope(SyntaxTree.CellScope).ownerCell.isCellNet THEN
+                (* bodies of cells are represented as main() functions *)
+                BodyDeclaration(parentScope, modifiers, type, name, position);
+            ELSE
+                ProcedureDeclaration(parentScope, modifiers, type, name, position, FALSE);
+            END;
+            IF Trace THEN 
+                E("MethodDeclaration") 
+            END;
+        END MethodDeclaration;
+
+        PROCEDURE ConstructorDeclaration(
+                parentScope: SyntaxTree.Scope; 
+                modifiers: SET;
+                name: SyntaxTree.Identifier;
+                position: LONGINT);
+        BEGIN
+            IF Trace THEN 
+                S("ConstructorDeclaration") 
+            END;
+            localIdentTable.Reset;
+            IF (parentScope IS SyntaxTree.ModuleScope) OR
+                    ((parentScope IS SyntaxTree.CellScope) &
+                        parentScope(SyntaxTree.CellScope).ownerCell.isCellNet) THEN
+                (* bodies of modules and cellnets are represented as constructors *)
+                BodyDeclaration(parentScope, modifiers, NIL, name, position);
+            ELSE
+                ProcedureDeclaration(parentScope, modifiers, NIL, name, position, TRUE);
+            END;
+            IF Trace THEN 
+                E("ConstructorDeclaration") 
+            END;
+        END ConstructorDeclaration;
+
+        PROCEDURE BodyDeclaration(
+                parentScope: SyntaxTree.Scope; 
+                modifiers: SET;
+                type: SyntaxTree.Type;
+                name: SyntaxTree.Identifier;
+                position: LONGINT);
+            VAR procedureScope: SyntaxTree.ProcedureScope;
+                procedureType: SyntaxTree.ProcedureType;
+                procedure: SyntaxTree.Procedure;
+        BEGIN
+            procedureScope := SyntaxTree.NewProcedureScope(parentScope);
+            IF parentScope IS SyntaxTree.ModuleScope THEN
+                procedure := SyntaxTree.NewProcedure(position, Global.ModuleBodyName, procedureScope);
+                procedure.SetAccess(SyntaxTree.Hidden);
+            ELSE
+                procedure := SyntaxTree.NewProcedure(position, Global.RecordBodyName, procedureScope);
+                procedure.SetAccess(SyntaxTree.Public+SyntaxTree.Protected+SyntaxTree.Internal);
+            END;
+            parentScope.AddProcedure(procedure);
+            procedureType := SyntaxTree.NewProcedureType(position, parentScope);
+            FormalParameterList(procedureType, procedureScope, type);
+            IF procedureType.numberParameters # 0 THEN
+                Error(position, Diagnostics.Invalid, "constructor/main has parameters");
+            ELSIF procedureType.returnType # NIL THEN
+                Error(position, Diagnostics.Invalid, "constructor/main returns value");
+            END;
+            procedure.SetType(procedureType);
+            procedure.SetBodyProcedure(TRUE);
+            procedureScope.SetBody(Body(procedureScope));
+            IF parentScope IS SyntaxTree.ModuleScope THEN
+                parentScope(SyntaxTree.ModuleScope).SetBodyProcedure(procedure);
+            ELSE
+                parentScope(SyntaxTree.CellScope).SetBodyProcedure(procedure);
+            END;
+        END BodyDeclaration;
+
+        (**
+            class-declaration:
+                [class-modifiers] 'class' identifier [class-base] class-body [';']
+
+            class-base:
+                ':' class-type
+
+            class-body:
+                '{' [class-member-declarations] '}'
+
+            class-member-declarations:
+                class-member-declaration
+                class-member-declarations class-member-declaration
+
+            class-member-declaration:
+                constant-declaration
+                field-declaration
+                method-declaration
+                constructor-declaration
+                type-declaration
+
+            type-declaration:
+                class-declaration
+                struct-declaration
+                delegate-declaration
+                cell-declaration
+                cellnet-declaration
+        **)
+        PROCEDURE MemberDeclaration(parentScope: SyntaxTree.Scope; parentName: SyntaxTree.Identifier);
+            VAR attributes: SyntaxTree.Modifier;
+                modifiers: SET;
+                type: SyntaxTree.Type;
+                name: SyntaxTree.Identifier;
+                position: LONGINT;
+        BEGIN
+            IF Optional(Scanner.LeftBracket) THEN
+                attributes := Attributes();
+            ELSE
+                attributes := NIL;
+            END;
+            Modifiers(modifiers);
+            IF Optional(Scanner.Const) THEN
+                ConstantDeclaration(parentScope, modifiers);
+            ELSIF Optional(Scanner.Class) THEN
+                ClassDeclaration(parentScope, modifiers);
+            ELSIF Optional(Scanner.Struct) THEN
+                StructDeclaration(parentScope, modifiers);
+            ELSIF Optional(Scanner.Delegate) THEN
+                DelegateDeclaration(parentScope, modifiers);
+            ELSIF Optional(Scanner.Cell) THEN
+                CellDeclaration(parentScope, modifiers, attributes, FALSE);
+            ELSIF Optional(Scanner.Cellnet) THEN
+                CellDeclaration(parentScope, modifiers, attributes, TRUE);
+            ELSIF Peek(Scanner.Identifier) & (symbol.identifier = parentName) THEN
+                name := Identifier(position);
+                ConstructorDeclaration(parentScope, modifiers, name, position);
+            ELSIF Optional(Scanner.Void) THEN
+                name := Identifier(position);
+                MethodDeclaration(parentScope, modifiers, NIL, name, position);
+            ELSE
+                type := Type();
+                name := Identifier(position);
+                IF Peek(Scanner.LeftParenthesis) THEN
+                    MethodDeclaration(parentScope, modifiers, type, name, position);
+                ELSE
+                    FieldDeclaration(parentScope, modifiers, type, name, position);
+                END;
+            END;
+        END MemberDeclaration;
+
+        PROCEDURE ClassMemberDeclaration(parentScope: SyntaxTree.Scope; parentName: SyntaxTree.Identifier);
+        BEGIN
+            IF Trace THEN 
+                S("ClassMemberDeclaration") 
+            END;
+            MemberDeclaration(parentScope, parentName);
+            IF Trace THEN 
+                E("ClassMemberDeclaration") 
+            END;
+        END ClassMemberDeclaration;
+
+        PROCEDURE ClassMemberDeclarations(parentScope: SyntaxTree.Scope; parentName: SyntaxTree.Identifier);
+            VAR previousScope: SyntaxTree.Scope;
+        BEGIN
+            IF Trace THEN 
+                S("ClassMemberDeclarations") 
+            END;
+            previousScope := currentScope;
+            currentScope := parentScope;
+            WHILE ~Peek(Scanner.RightBrace) DO
+                ClassMemberDeclaration(parentScope, parentName);
+            END;
+            currentScope := previousScope;
+            IF Trace THEN 
+                E("ClassMemberDeclarations") 
+            END;
+        END ClassMemberDeclarations;
+
+        PROCEDURE ClassDeclaration(parentScope: SyntaxTree.Scope; modifiers: SET);
+            VAR name: SyntaxTree.Identifier;
+                position: LONGINT;
+                typeDeclaration: SyntaxTree.TypeDeclaration;
+                access: SET;
+                objectType: SyntaxTree.RecordType;
+                pointerType: SyntaxTree.PointerType;
+                recordScope: SyntaxTree.RecordScope;
+                qualifiedIdentifier: SyntaxTree.QualifiedIdentifier;
+                baseType: SyntaxTree.Type;
+                previousStatements: SyntaxTree.StatementSequence;
+                previousOuter: SyntaxTree.Statement;
+                b: BOOLEAN;
+        BEGIN
+            IF Trace THEN 
+                S("ClassDeclaration") 
+            END;
+
+            previousStatements := initStatements;
+            previousOuter := initOuter;
+            (* TODO: Implement initialization of fields *)
+            initStatements := NIL;
+            initOuter := NIL;
+
+            EnterInit;
+
+            (* symbol 'class' already consumed *)
+            name := Identifier(position);
+            access := IdentifierAccess(modifiers, FALSE);
+            typeDeclaration := SyntaxTree.NewTypeDeclaration(position, name);
+            CommentSymbol(typeDeclaration);
+
+            recordScope := SyntaxTree.NewRecordScope(parentScope);
+            pointerType := SyntaxTree.NewPointerType(position, parentScope);
+            objectType := SyntaxTree.NewRecordType(position, parentScope, recordScope);
+            objectType.IsObject(TRUE);
+            objectType.SetPointerType(pointerType);
+            pointerType.SetPointerBase(objectType);
+            IF Optional(Scanner.Colon) THEN
+                qualifiedIdentifier := QualifiedIdentifier();
+                baseType := SyntaxTree.NewQualifiedType(
+                    qualifiedIdentifier.position, parentScope, qualifiedIdentifier);
+                objectType.SetBaseType(baseType);
+            END;
+            Check(Scanner.LeftBrace);
+            ClassMemberDeclarations(recordScope, name);
+            Check(Scanner.RightBrace);
+            b := Optional(Scanner.Semicolon);
+
+            pointerType.SetTypeDeclaration(typeDeclaration);
+            typeDeclaration.SetDeclaredType(pointerType);
+            typeDeclaration.SetAccess(access);
+            parentScope.AddTypeDeclaration(typeDeclaration);
+
+            initStatements := previousStatements;
+            initOuter := previousOuter;
+
+            IF Trace THEN 
+                E("ClassDeclaration") 
+            END;
+        END ClassDeclaration;
+
+        (**
+            struct-declaration:
+                [struct-modifiers] 'struct' identifier struct-body [';']
+
+            struct-body:
+                '{' [struct-member-declarations] '}'
+
+            struct-member-declarations:
+                struct-member-declaration
+                struct-member-declarations struct-member-declaration
+
+            struct-member-declaration:
+                constant-declaration
+                field-declaration
+                method-declaration
+                constructor-declaration
+                type-declaration
+        **)
+        PROCEDURE StructMemberDeclaration(parentScope: SyntaxTree.Scope; parentName: SyntaxTree.Identifier);
+        BEGIN
+            IF Trace THEN 
+                S("StructMemberDeclaration") 
+            END;
+            MemberDeclaration(parentScope, parentName);
+            IF Trace THEN 
+                E("StructMemberDeclaration") 
+            END;
+        END StructMemberDeclaration;
+
+        PROCEDURE StructMemberDeclarations(parentScope: SyntaxTree.Scope; parentName: SyntaxTree.Identifier);
+            VAR previousScope: SyntaxTree.Scope;
+        BEGIN
+            IF Trace THEN 
+                S("StructMemberDeclarations") 
+            END;
+            previousScope := currentScope;
+            currentScope := parentScope;
+            WHILE ~Peek(Scanner.RightBrace) DO
+                StructMemberDeclaration(parentScope, parentName);
+            END;
+            currentScope := previousScope;
+            IF Trace THEN 
+                E("StructMemberDeclarations") 
+            END;
+        END StructMemberDeclarations;
+
+        PROCEDURE StructDeclaration(parentScope: SyntaxTree.Scope; modifiers: SET);
+            VAR name: SyntaxTree.Identifier;
+                position: LONGINT;
+                typeDeclaration: SyntaxTree.TypeDeclaration;
+                access: SET;
+                recordType: SyntaxTree.RecordType;
+                recordScope: SyntaxTree.RecordScope;
+                previousStatements: SyntaxTree.StatementSequence;
+                previousOuter: SyntaxTree.Statement;
+                b: BOOLEAN;
+        BEGIN
+            IF Trace THEN 
+                S("StructDeclaration") 
+            END;
+
+            previousStatements := initStatements;
+            previousOuter := initOuter;
+            (* TODO: Implement initialization of fields *)
+            initStatements := NIL;
+            initOuter := NIL;
+
+            (* symbol 'struct' already consumed *)
+            name := Identifier(position);
+            access := IdentifierAccess(modifiers, FALSE);
+            typeDeclaration := SyntaxTree.NewTypeDeclaration(position, name);
+            CommentSymbol(typeDeclaration);
+
+            recordScope := SyntaxTree.NewRecordScope(parentScope);
+            recordType := SyntaxTree.NewRecordType(position, parentScope, recordScope);
+            Check(Scanner.LeftBrace);
+            StructMemberDeclarations(recordScope, name);
+            Check(Scanner.RightBrace);
+            b := Optional(Scanner.Semicolon);
+
+            recordType.SetTypeDeclaration(typeDeclaration);
+            typeDeclaration.SetDeclaredType(recordType);
+            typeDeclaration.SetAccess(access);
+            parentScope.AddTypeDeclaration(typeDeclaration);
+
+            initStatements := previousStatements;
+            initOuter := previousOuter;
+
+            IF Trace THEN 
+                E("StructDeclaration") 
+            END;
+        END StructDeclaration;
+
+        (**
+            delegate-declaration:
+                [delegate-modifiers] 'delegate' return-type identifier '(' [formal-parameter-list] ')' ';'
+
+        **)
+        PROCEDURE DelegateDeclaration(parentScope: SyntaxTree.Scope; modifiers: SET);
+            VAR returnType: SyntaxTree.Type;
+                name: SyntaxTree.Identifier;
+                position: LONGINT;
+                typeDeclaration: SyntaxTree.TypeDeclaration;
+                access: SET;
+                procedureType: SyntaxTree.ProcedureType;
+        BEGIN
+            IF Trace THEN 
+                S("DelegateDeclaration") 
+            END;
+
+            (* symbol 'delegate' already consumed *)
+            IF Optional(Scanner.Void) THEN
+                returnType := NIL;
+            ELSE
+                returnType := Type();
+            END;
+            name := Identifier(position);
+            access := IdentifierAccess(modifiers, FALSE);
+            typeDeclaration := SyntaxTree.NewTypeDeclaration(position, name);
+            CommentSymbol(typeDeclaration);
+
+            procedureType := SyntaxTree.NewProcedureType(position, parentScope);
+            procedureType.SetModifiers(delegateModifiers);
+            (* ACHTUNG: Should we create a fictionary parentScope for parameters? *)
+            FormalParameterList(procedureType, parentScope, returnType);
+
+            procedureType.SetTypeDeclaration(typeDeclaration);
+            typeDeclaration.SetDeclaredType(procedureType);
+            typeDeclaration.SetAccess(access);
+            parentScope.AddTypeDeclaration(typeDeclaration);
+
+            IF Trace THEN 
+                E("DelegateDeclaration") 
+            END;
+        END DelegateDeclaration;
+
+        (**
+            port-list:
+                port-declaration
+                port-list ',' port-declaration
+
+            port-declaration:
+                port-type  ['[' constant-expression ']'] identifier
+
+            port-type:
+                'in'
+                'out'
+        **)
+        PROCEDURE PortDeclaration(cell: SyntaxTree.CellType; parentScope: SyntaxTree.Scope);
+            VAR position: LONGINT;
+                direction: LONGINT;
+                type: SyntaxTree.Type;
+                arrayType: SyntaxTree.ArrayType;
+                expression: SyntaxTree.Expression;
+                name: SyntaxTree.Identifier;
+                parameter: SyntaxTree.Parameter;
+        BEGIN
+            IF Trace THEN
+                S("PortDeclaration")
+            END;
+            position := symbol.start;
+            IF Optional(Scanner.In) THEN
+                direction := SyntaxTree.InPort;
+            ELSIF Optional(Scanner.Out) THEN
+                direction := SyntaxTree.OutPort;
+            ELSE
+                Error(position, Diagnostics.Invalid, "invalid direction, expected in or out");
+            END;
+            type := SyntaxTree.NewPortType(position, direction, NIL, parentScope);
+            IF Optional(Scanner.LeftBracket) THEN
+                expression := Expression();
+                arrayType := SyntaxTree.NewArrayType(position, parentScope, SyntaxTree.Static);
+                arrayType.SetArrayBase(type);
+                arrayType.SetLength(expression);
+                type := arrayType;
+                Check(Scanner.RightBracket);
+            END;
+            name := Identifier(position);
+            parameter := SyntaxTree.NewParameter(position, cell, name, SyntaxTree.ValueParameter);
+            cell.AddParameter(parameter);
+            parameter.SetType(type);
+            IF Trace THEN
+                E("PortDeclaration")
+            END;
+        END PortDeclaration;
+
+        PROCEDURE PortList(cell: SyntaxTree.CellType; parentScope: SyntaxTree.Scope);
+        BEGIN
+            IF Trace THEN
+                S("PortList")
+            END;
+            Check(Scanner.LeftParenthesis);
+            IF ~Optional(Scanner.RightParenthesis) THEN
+                REPEAT
+                    PortDeclaration(cell, parentScope);
+                UNTIL ~Optional(Scanner.Comma);
+                Check(Scanner.RightParenthesis);
+            END;
+            IF Trace THEN
+                E("PortList")
+            END;
+        END PortList;
+
+        (**
+            cell-declaration:
+               [cell-modifiers] 'cell' identifier ['(' [cell-parameter-list] ')'] cell-body [';']
+
+            cell-body:
+                '{' [cell-member-declarations] '}'
+
+            cell-member-declarations:
+                cell-member-declaration
+                cell-member-declarations cell-member-declaration
+
+            cell-member-declaration:
+                constant-declaration
+                field-declaration
+                method-declaration
+                constructor-declaration
+                type-declaration
+
+            cellnet-declaration:
+               [cell-modifiers] 'cellnet' identifier ['(' [cell-parameter-list] ')'] cell-body [';']
+        **)
+        PROCEDURE CellMemberDeclaration(parentScope: SyntaxTree.Scope; parentName: SyntaxTree.Identifier);
+        BEGIN
+            IF Trace THEN 
+                S("CellMemberDeclaration") 
+            END;
+            MemberDeclaration(parentScope, parentName);
+            IF Trace THEN 
+                E("CellMemberDeclaration") 
+            END;
+        END CellMemberDeclaration;
+
+        PROCEDURE CellMemberDeclarations(parentScope: SyntaxTree.Scope; parentName: SyntaxTree.Identifier);
+            VAR previousScope: SyntaxTree.Scope;
+        BEGIN
+            IF Trace THEN 
+                S("CellMemberDeclarations") 
+            END;
+            previousScope := currentScope;
+            currentScope := parentScope;
+            WHILE ~Peek(Scanner.RightBrace) DO
+                CellMemberDeclaration(parentScope, parentName);
+            END;
+            currentScope := previousScope;
+            IF Trace THEN 
+                E("CellMemberDeclarations") 
+            END;
+        END CellMemberDeclarations;
+
+        PROCEDURE CellDeclaration(
+                parentScope: SyntaxTree.Scope; 
+                modifiers: SET; 
+                attributes: SyntaxTree.Modifier; 
+                isCellNet: BOOLEAN);
+            VAR name: SyntaxTree.Identifier;
+                position: LONGINT;
+                access: SET;
+                typeDeclaration: SyntaxTree.TypeDeclaration;
+                cellScope: SyntaxTree.CellScope;
+                cellType: SyntaxTree.CellType;
+                previousStatements: SyntaxTree.StatementSequence;
+                previousOuter: SyntaxTree.Statement;
+                b: BOOLEAN;
+        BEGIN
+            IF Trace THEN 
+                S("CellDeclaration") 
+            END;
+
+            previousStatements := initStatements;
+            previousOuter := initOuter;
+            (* TODO: Implement initialization of fields *)
+            initStatements := NIL;
+            initOuter := NIL;
+
+            (* symbol 'cell' already consumed *)
+            name := Identifier(position);
+            access := IdentifierAccess(modifiers, FALSE);
+            typeDeclaration := SyntaxTree.NewTypeDeclaration(position, name);
+            CommentSymbol(typeDeclaration);
+
+            cellScope := SyntaxTree.NewCellScope(parentScope);
+            cellType := SyntaxTree.NewCellType(position, parentScope, cellScope);
+            cellType.IsCellNet(isCellNet);
+            cellScope.SetOwnerCell(cellType);
+
+            IF attributes # NIL THEN
+                cellType.SetModifiers(attributes);
+            END;
+
+            IF Peek(Scanner.LeftParenthesis) THEN
+                PortList(cellType, cellScope);
+            END;
+
+            EnterInit;
+
+            Check(Scanner.LeftBrace);
+            CellMemberDeclarations(cellScope, name);
+            Check(Scanner.RightBrace);
+            b := Optional(Scanner.Semicolon);
+
+            cellType.SetTypeDeclaration(typeDeclaration);
+            typeDeclaration.SetDeclaredType(cellType);
+            typeDeclaration.SetAccess(access);
+            parentScope.AddTypeDeclaration(typeDeclaration);
+
+            initStatements := previousStatements;
+            initOuter := previousOuter;
+
+            IF Trace THEN 
+                E("CellDeclaration") 
+            END;
+        END CellDeclaration;
+
+        (**
+            import-directives:
+                import-directive
+                import-directives import-directive
+
+            import-directive:
+                import-alias-directive
+                import-module-directive
+
+            import-alias-directive:
+                'import' identifier '=' module-name ';'
+
+            import-module-directive:
+                'import' module-name ';'
+
+            module-name:
+                identifier
+        **)
+        PROCEDURE ImportDirective(moduleScope: SyntaxTree.ModuleScope);
+            VAR alias, name, context: SyntaxTree.Identifier;
+                import: SyntaxTree.Import; 
+                position, idPosition: LONGINT;
+        BEGIN
+            IF Trace THEN 
+                S("ImportDirective") 
+            END;
+            (* import symbol already consumed *)
+            position := symbol.start;
+            alias := Identifier(idPosition);
+            IF alias # SyntaxTree.invalidIdentifier THEN
+                IF Optional(Scanner.Equal) THEN
+                    name := Identifier(idPosition);
+                ELSE 
+                    name := alias;  
+                END;
+                import := SyntaxTree.NewImport(position, alias, name, TRUE);
+                CommentSymbol(import);
+                moduleScope.AddImport(import);
+            END;
+            Check(Scanner.Semicolon);
+            IF Trace THEN 
+                E("ImportDirective");
+            END;
+        END ImportDirective;
+
+        PROCEDURE ImportDirectives(moduleScope: SyntaxTree.ModuleScope);
+        BEGIN
+            IF Trace THEN 
+                S("ImportDirectives") 
+            END;
+            WHILE Optional(Scanner.Import) DO
+                ImportDirective(moduleScope);
+            END;
+            IF Trace THEN 
+                E("ImportDirectives");
+            END;
+        END ImportDirectives;
+
+        (**
+            compilation-unit:
+                'module' identifier '{' [import-directives] [class-member-declarations] '}' [';']
+                'cellnet' identifier '{' [import-directives] [class-member-declarations] '}' [';']
+        **)
+        PROCEDURE Module*(): SyntaxTree.Module;
+            VAR moduleName, context: SyntaxTree.Identifier;
+                module: SyntaxTree.Module;
+                position: LONGINT;
+                isCellNet: BOOLEAN;
+                scannerDiagnostics: Diagnostics.Diagnostics;
+                b: BOOLEAN;
+        BEGIN
+            IF Trace THEN 
+                S("Module") 
+            END;
+            position := symbol.start;
+            (* needed to feed in comment already before module starts: *)
+            moduleScope := SyntaxTree.NewModuleScope(); 
+            currentScope := moduleScope;
+            isCellNet := Optional(Scanner.Cellnet);
+            IF isCellNet OR Mandatory(Scanner.Module) THEN
+                moduleName := Identifier(position);
+                module := SyntaxTree.NewModule(scanner.source^, position, moduleName, moduleScope, LynxCase);
+                IF isCellNet THEN
+                    module.SetCellNet(TRUE);
+                END;
+                module.SetType(SyntaxTree.moduleType);
+                CommentSymbol(module);
+                Check(Scanner.LeftBrace);
+                IF Peek(Scanner.Import) THEN
+                    ImportDirectives(moduleScope) 
+                END;
+                EnterInit;
+                ClassMemberDeclarations(moduleScope, moduleName);
+                Check(Scanner.RightBrace);
+                b := Optional(Scanner.Semicolon);
+                IF ~error & ~scanner.error THEN 
+                    (* read ahead to read comments *)
+                    scannerDiagnostics := NIL;
+                    scanner.ResetErrorDiagnostics(scannerDiagnostics);
+                    NextSymbol;
+                    scanner.ResetErrorDiagnostics(scannerDiagnostics);
+                    (* do not use Check for not reading after end of module *)
+                    SetNextInComment(recentComment, module);
+                    module.SetClosingComment(recentComment);
+                    recentComment := NIL;
+                END;
+            END;
+            IF Trace THEN 
+                E("Module") 
+            END;
+            RETURN module
+        END Module;
+
+    END Parser;    (* Parser *)
+
+    (** parser retrieval **)
+    PROCEDURE NewParser*(scanner: Scanner.Scanner; diagnostics: Diagnostics.Diagnostics): Parser;
+        VAR parser: Parser;
+    BEGIN
+        NEW(parser, scanner, diagnostics);
+        RETURN parser;
+    END NewParser;
+
+END FoxCSharpParser.

+ 1467 - 0
source/FoxCSharpScanner.Mod

@@ -0,0 +1,1467 @@
+MODULE FoxCSharpScanner;
+
+IMPORT Streams, Strings, Diagnostics, Commands, StringPool, 
+    D := Debugging, Basic := FoxBasic, FoxScanner,
+    KernelLog (* DEBUG *);
+
+CONST
+    Trace = FALSE;
+
+    (* overal scanner limitation *)
+    MaxIdentifierLength* = FoxScanner.MaxIdentifierLength;
+
+    (* parametrization of numeric scanner: *)
+    MaxHexDigits* = FoxScanner.MaxHexDigits;
+    MaxHugeHexDigits* = FoxScanner.MaxHugeHexDigits;
+    MaxRealExponent* = FoxScanner.MaxRealExponent;
+    MaxLongrealExponent* = FoxScanner.MaxLongrealExponent;
+
+    (* scanner constants *)
+    EOT* = 0X; 
+    LF* = 0AX; 
+    CR* = 0DX; 
+    TAB* = 09X;
+
+TYPE
+    StringType* = FoxScanner.StringType;
+    IdentifierType* = FoxScanner.IdentifierType;
+    IdentifierString* = FoxScanner.IdentifierString; 
+
+CONST
+    (* tokens *)
+
+    None*= 0;
+
+    (* operators and punctuators *)    
+    Exclamation* = 1;         (* ! *)    
+    ExclamationEqual* = 2;    (* != *)
+    Percent* = 3;             (* % *)   
+    PercentEqual* = 4;        (* %= *)
+    And* = 5;                 (* & *)   
+    AndEqual* = 6;            (* &= *)   
+    AndAnd* = 7;              (* && *)
+    LeftParenthesis* = 8;     (* ( *)
+    RightParenthesis* = 9;    (* ) *)
+    Times* = 10;              (* * *)    
+    TimesEqual* = 11;         (* *= *)
+    Plus* = 12;               (* + *)    
+    PlusEqual* = 13;          (* += *)    
+    PlusPlus* = 14;           (* ++ *)
+    Comma* = 15;              (* , *)
+    Minus* = 16;              (* - *)   
+    MinusEqual* = 17;         (* -= *)   
+    MinusMinus* = 18;         (* -- *)
+    Period* = 19;             (* . *)
+    Slash* = 20;              (* / *)
+    SlashEqual* = 21;         (* /= *)
+    Colon* = 22;              (* : *)
+    Semicolon* = 23;          (* ; *)
+    Less* = 24;               (* < *)
+    LessEqual* = 25;          (* <= *)
+    LeftShift* = 26;          (* << *)
+    LeftShiftEqual* = 27;     (* <<= *)
+    Equal* = 28;              (* = *)
+    EqualEqual* = 29;         (* == *)
+    Greater* = 30;            (* > *)
+    GreaterEqual* = 31;       (* >= *)
+    RightShift* = 32;         (* >> *)
+    RightShiftEqual* = 33;    (* >>= *)
+    LeftBracket* = 34;        (* [ *)
+    RightBracket* = 35;       (* ] *)
+    Arrow* = 36;              (* ^ *)
+    ArrowEqual* = 37;         (* ^= *)
+    LeftBrace* = 38;          (* { *)
+    Bar* = 39;                (* | *)
+    BarEqual* = 40;           (* |= *)
+    BarBar* = 41;             (* || *)
+    RightBrace* = 42;         (* } *)
+    Tilde* = 43;              (* ~ *)
+
+    (* keywords *)
+    As* = 44;
+    Base* = 45;
+    Bool* = 46;
+    Break* = 47;
+    Case* = 48;
+    Char* = 49;
+    Class* = 50;
+    Const* = 51;
+    Default* = 52;
+    Delegate* = 53;
+    Do* = 54;
+    Double* = 55;
+    Else* = 56;
+    False* = 57;
+    Float* = 58;
+    For* = 59;
+    If* = 60;
+    Import* = 61;
+    Int* = 62;
+    Internal* = 63;
+    Is* = 64;
+    Long* = 65;
+    Module* = 66;
+    New* = 67;
+    Null* = 68;
+    Object* = 69;
+    Public* = 70;
+    Readonly* = 71;
+    Ref* = 72;
+    Return* = 73;
+    Sbyte* = 74;
+    Short* = 75;
+    String* = 76;
+    Struct* = 77;
+    Switch* = 78;
+    This* = 79;
+    True* = 80;
+    Void* = 81;
+    While* = 82;
+
+    Identifier* = 83;
+    IntegerLiteral* = 84;
+    RealLiteral* = 85;
+    CharacterLiteral* = 86;
+    StringLiteral* = 87;
+
+    Comment*= 88; 
+
+    (* Active Cells *)
+    Cell* = 89;
+    Cellnet* = 90;
+    In* = 91;
+    Out* = 92;
+    Select* = 93;
+
+    Question* = 94;           (* ? *)
+    QuestionQuestion* = 95;   (* ?? *)
+
+    EndOfText*= 96;
+
+    (* number types *)
+    IntNumber*= 1; 
+    LongNumber*= 2; 
+    FloatNumber*= 3; 
+    DoubleNumber*= 4; 
+
+    SingleQuote = 27X;  
+    DoubleQuote* = 22X;
+    Backslash = 5CX;
+
+TYPE
+    (* keywords book keeping *)
+    Keyword* = FoxScanner.Keyword;
+    KeywordTable* = FoxScanner.KeywordTable;
+
+TYPE
+    Token* = LONGINT;
+
+    (**
+        symbol: data structure for the data transfer of 
+        the last read input from the scanner to the parser
+    **)
+    Symbol* = RECORD
+        start*, end*, line-: LONGINT;
+        token*: Token;
+        identifier*: IdentifierType;
+        identifierString*: IdentifierString;
+        string*: StringType;
+        stringLength*: LONGINT;
+        numberType*: LONGINT;
+        integer*: LONGINT;
+        hugeint*: HUGEINT;
+        character*: CHAR;
+        real*: LONGREAL;
+    END;
+
+    StringMaker* = FoxScanner.StringMaker;
+
+    Scanner* = OBJECT
+    VAR
+        source-: StringType;
+        reader: Streams.Reader;
+        diagnostics: Diagnostics.Diagnostics;
+        ch: CHAR;
+        position: LONGINT;
+        line-: LONGINT;
+        error-: BOOLEAN;
+        stringWriter: Streams.Writer;
+        stringMaker: StringMaker;
+
+        (*
+            source: name of the source code for reference in error outputs
+            reader: input stream
+            position: reference position (offset) of the input stream, for error output
+            diagnostics: error output object
+        *)
+        PROCEDURE & InitializeScanner*(
+                CONST source: ARRAY OF CHAR; 
+                reader: Streams.Reader; 
+                position: LONGINT; 
+                diagnostics: Diagnostics.Diagnostics);
+        BEGIN
+            NEW(stringMaker,1024);
+            stringWriter := stringMaker.GetWriter();
+            error := FALSE;
+            NEW(SELF.source, Strings.Length(source)+1);
+            COPY(source, SELF.source^);
+            SELF.reader := reader;
+            SELF.diagnostics := diagnostics;
+            ch := " ";
+            IF reader = NIL THEN 
+                ch := EOT
+            ELSE
+                GetNextCharacter 
+            END;
+            IF Trace THEN 
+                D.Str("New scanner  ");
+                D.Ln;  
+            END;
+            SELF.position := position;
+            line := 0;
+        END InitializeScanner;
+
+        (** report an error occured during scanning **)
+        PROCEDURE ErrorS(CONST msg: ARRAY OF CHAR);
+        BEGIN
+            IF diagnostics # NIL THEN
+                diagnostics.Error(source^, position, Diagnostics.Invalid, msg)
+            END;
+            error := TRUE;
+        END ErrorS;
+
+        (** report an error occured during scanning **)
+        PROCEDURE Error(code: INTEGER);
+            VAR errorMessage: ARRAY 256 OF CHAR;
+        BEGIN
+            IF diagnostics # NIL THEN
+                Basic.GetErrorMessage(code, "", errorMessage);
+                diagnostics.Error(source^, position, code, errorMessage)
+            END;
+            error := TRUE;
+        END Error;
+
+        (** get next character, end of text results in ch = EOT **)
+        PROCEDURE GetNextCharacter;
+        BEGIN
+            reader.Char(ch); 
+            INC(position);
+            IF ch = LF THEN 
+                INC(line) 
+            END;
+        END GetNextCharacter;
+
+        PROCEDURE IsNewlineCharacter(ch: CHAR): BOOLEAN;
+        BEGIN
+            RETURN (ch = 0AX) OR (ch = 0DX);
+        END IsNewlineCharacter;
+
+        (**
+            CharacterLiteral =
+                "'" Character "'".
+            Character =
+                SingleCharacter |
+                SimpleEscapeSequence |
+                HexadecimalEscapeSequence.
+            SingleCharacter =
+                any character except ' (27X), \ (5CX), and NewLineCharacter.
+            SimpleEscapeSequence =
+                "\'" | '\"' | '\\' | '\0' | 
+                '\a' | '\b' | '\f' | '\n' | '\r' | '\t' | '\v'.
+            HexadecimalEscapeSequence =
+                '\x' HexDigit {HexDigit}.
+        **)
+        PROCEDURE GetEscapeSequence(VAR esc: CHAR);
+            VAR i, k, n: LONGINT;
+
+            PROCEDURE HexDigit(ch: CHAR; VAR dig: LONGINT): BOOLEAN;
+            BEGIN
+                IF (ch >= '0') & (ch <= '9') THEN
+                    dig := ORD(ch) - ORD('0');
+                    RETURN TRUE;
+                END;
+                IF (ch >= 'A') & (ch <= 'F') THEN
+                    dig := ORD(ch) - ORD('A') + 10;
+                    RETURN TRUE;
+                END;
+                IF (ch >= 'a') & (ch <= 'f') THEN
+                    dig := ORD(ch) - ORD('a') + 10;
+                    RETURN TRUE;
+                END;
+                RETURN FALSE;
+            END HexDigit;
+
+        BEGIN
+            CASE ch OF
+              SingleQuote, DoubleQuote, Backslash:
+                esc := ch;
+                GetNextCharacter
+            | '0':
+                esc := 0X;
+                GetNextCharacter
+            | 'a':
+                esc := 07X;
+                GetNextCharacter
+            | 'b':
+                esc := 08X;
+                GetNextCharacter
+            | 'f':
+                esc := 0CX;
+                GetNextCharacter
+            | 'n':
+                esc := 0AX;
+                GetNextCharacter
+            | 'r':
+                esc := 0DX;
+                GetNextCharacter
+            | 't':
+                esc := 09X;
+                GetNextCharacter
+            | 'v':
+                esc := 0BX;
+                GetNextCharacter
+            | 'x':
+                GetNextCharacter;
+                n := 0;
+                i := 0;
+                WHILE (i < 2) & HexDigit(ch, k) DO
+                    n := n * 16 + k;
+                    GetNextCharacter;
+                    INC(i);
+                END;
+                IF i = 0 THEN
+                    ErrorS("Illegal hexadecimal escape sequence");
+                END;
+                esc := CHR(n);
+            ELSE
+                ErrorS("Illegal escape sequence");
+                esc := 0X;    (* arbitrary *)
+            END;
+        END GetEscapeSequence;
+
+        PROCEDURE GetCharacter(VAR symbol: Symbol);
+            VAR vch: CHAR;
+        BEGIN
+            GetNextCharacter;
+            IF ch = EOT THEN
+                ErrorS("Unexpected end of character literal");
+                symbol.character := 0X;
+                RETURN;
+            END;
+            IF ch = Backslash THEN
+                GetNextCharacter;
+                GetEscapeSequence(vch);
+            ELSIF (ch = SingleQuote) OR IsNewlineCharacter(ch) THEN
+                ErrorS("Illegal character literal");
+                vch := 0X;
+            ELSE
+                vch := ch;
+                GetNextCharacter;
+            END;
+            IF ch = SingleQuote THEN
+                GetNextCharacter
+            ELSE
+                ErrorS("Illegal character literal")
+            END;
+            symbol.character := vch;
+            symbol.integer := ORD(vch);
+        END GetCharacter;
+
+        (**
+            StringLiteral =
+                '"' {StringCharacter} '"'.
+            StringCharacter =
+                SingleStringCharacter |
+                SimpleEscapeSequence |
+                HexadecimalEscapeSequence.
+            SingleStringCharacter =
+                any character except " (22X), \ (5CX), and NewLineCharacter.
+
+        **)
+        PROCEDURE GetString(VAR symbol: Symbol);
+            VAR vch: CHAR;
+        BEGIN
+            stringMaker.Clear;
+            GetNextCharacter;
+            LOOP
+                IF (ch = EOT) THEN
+                    ErrorS("Unexpected end of string literal");
+                    EXIT;
+                END;
+                IF IsNewlineCharacter(ch) THEN
+                    ErrorS("Illegal string literal");
+                    EXIT;
+                END;
+                IF ch = DoubleQuote THEN
+                    GetNextCharacter;
+                    EXIT;
+                END;
+                IF ch = Backslash THEN
+                    GetNextCharacter;
+                    GetEscapeSequence(vch);
+                ELSE
+                    vch := ch;
+                    GetNextCharacter;
+                END;
+                stringWriter.Char(vch);
+            END;
+            stringWriter.Char(0X);
+            stringWriter.Update;
+            (*
+                ACHTUNG: Due to the implementation of GetStringCopy
+                    the length of the copied string may be inconsistent
+                    with its contents if the string contains 0X.
+                    This must be fixed in the future.
+            *)
+            symbol.string := stringMaker.GetStringCopy(symbol.stringLength);
+        END GetString;
+
+        (**
+            Identifier = 
+                (Letter | '_') {Letter | Digit | '_'}.
+            Letter = 
+                'A' | 'B' | .. |  'Z' | 'a' | 'b' |  .. | 'z' .
+        **)
+        PROCEDURE GetIdentifier(VAR symbol: Symbol);
+            VAR i: LONGINT;
+        BEGIN
+            i := 0;
+            REPEAT 
+                symbol.identifierString[i] := ch; 
+                INC(i);  
+                GetNextCharacter 
+            UNTIL reservedCharacter[ORD(ch)] OR (i = MaxIdentifierLength);
+            IF i = MaxIdentifierLength THEN 
+                Error(Basic.IdentifierTooLong);
+                DEC(i)
+            END;
+            symbol.identifierString[i] := 0X;
+            StringPool.GetIndex(symbol.identifierString, symbol.identifier);
+        END GetIdentifier;
+
+        (**
+            Number =
+                IntegerLiteral | 
+                RealLiteral.
+            IntegerLiteral =
+                DecimalIntegerLiteral |
+                HexadecimalIntegerLiteral.
+            DecimalIntegerLiteral =
+                Digit {Digit} [IntegerTypeSuffix].
+            HexadecimalIntegerLiteral =
+                ('0X' | '0x') HexDigit {HexDigit} [IntegerTypeSuffix].
+            IntegerTypeSuffix =
+                'L' | 'l'.
+            RealLiteral =
+                Digit {Digit} '.' Digit {Digit} [ExponentPart] [RealTypeSuffix] |
+                '.' Digit {Digit} [ExponentPart] [RealTypeSuffix] |
+                Digit {Digit} [ExponentPart] [RealTypeSuffix] |
+                Digit {Digit} [RealTypeSuffix].
+            ExponentPart =
+                ('E' | 'e') ['+' | '-'] Digit {Digit}.
+            RealTypeSuffix =
+                'F' | 'f' | 'D' | 'd'.
+            Digit = 
+                '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'.
+            HexDigit = 
+                '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' |
+                'A' | 'B' | 'C' | 'D' | 'E' | 'F' |
+                'a' | 'b' | 'c' | 'd' | 'e' | 'f'.
+        **)
+        PROCEDURE GetNumber(VAR symbol: Symbol; frac: BOOLEAN): Token;
+            VAR i, nextInt, m, n, d, e, si: LONGINT;
+                dig: ARRAY 24 OF CHAR;
+                f: LONGREAL;
+                hex, neg, long: BOOLEAN;
+                hugeint, tenh: HUGEINT;
+                result: LONGINT;
+
+            PROCEDURE Append(ch: CHAR);
+            BEGIN
+                symbol.identifierString[si] := ch;
+                INC(si);
+            END Append;
+
+            PROCEDURE Digit(ch: CHAR): LONGINT;
+            BEGIN
+                RETURN ORD(ch) - ORD('0')
+            END Digit;
+
+            PROCEDURE HexDigit(ch: CHAR): LONGINT;
+            BEGIN
+                IF (ch >= '0') & (ch <= '9') THEN
+                    RETURN ORD(ch) - ORD('0')
+                END;
+                IF (ch >= 'A') & (ch <= 'F') THEN
+                    RETURN ORD(ch) - ORD('A') + 10
+                END;
+                IF (ch >= 'a') & (ch <= 'f') THEN
+                    RETURN ORD(ch) - ORD('a') + 10
+                END;
+                (* cannot happen *)
+                Error(Basic.NumberIllegalCharacter);
+                RETURN 0
+            END HexDigit;
+
+            PROCEDURE Ten(e: LONGINT): LONGREAL;
+                VAR x, p: LONGREAL;
+            BEGIN
+                x := 1;
+                p := 10;
+                WHILE e > 0 DO
+                    IF ODD(e) THEN
+                        x := x * p
+                    END;
+                    e := e DIV 2;
+                    IF e > 0 THEN
+                        p := p * p
+                    END
+                END;
+                RETURN x
+            END Ten;
+
+        BEGIN
+            (* ch is '.' or Digit *)
+            si := 0;
+            hex := FALSE;
+            IF ~frac & (ch = '0') THEN
+                Append(ch);
+                GetNextCharacter;
+                IF (ch = 'X') OR (ch = 'x') THEN
+                    Append(ch);
+                    GetNextCharacter;
+                    hex := TRUE
+                END;
+            END;
+            i := 0;
+            m := 0;
+            n := 0;
+            d := 0;
+            long := FALSE;
+            IF frac THEN
+                Append('.');
+                (* fictionary zero mantissa: *)
+                i := 1;
+                d := 1;
+            END;
+            LOOP    (* read mantissa *)
+                IF ((ch >= '0') & (ch <= '9')) OR
+                        (hex & 
+                            (((ch >= 'A') & (ch <= 'F')) OR
+                                ((ch >= 'a') & (ch <= 'f')))) THEN
+                    IF (m > 0) OR (ch # '0') THEN    (* ignore leading zeros *)
+                        IF n < LEN(dig) THEN
+                            dig[n] := ch;
+                            INC(n);
+                        END;
+                        INC(m);
+                    END;
+                    Append(ch);
+                    GetNextCharacter;
+                    INC(i)
+                ELSIF ~hex & (ch = '.') THEN
+                    IF d # 0 THEN
+                        EXIT
+                    END;
+                    Append(ch);
+                    GetNextCharacter;
+                    d := i
+                ELSE
+                    EXIT
+                END
+            END;
+            IF d = 0 THEN
+                IF ((ch = 'F') OR (ch = 'f') OR 
+                        (ch = 'D') OR (ch = 'd') OR 
+                        (ch = 'E') OR (ch = 'e')) THEN
+                    d := i
+                END;
+            ELSIF d = i THEN
+                (* '.' must be followed by a digit *)
+                Error(Basic.NumberIllegalCharacter)
+            END;
+            (* 0 <= n <= m <= i, 0 <= d <= i *)
+            IF d = 0 THEN    (* integer *)
+                IF (ch = 'L') OR (ch = 'l') THEN
+                    Append(ch);
+                    GetNextCharacter;
+                    long := TRUE
+                END;
+                IF n = m THEN
+                    symbol.integer := 0;
+                    symbol.hugeint := 0;
+                    i := 0;
+                    IF hex THEN
+                        IF ~long & 
+                                ((n < MaxHexDigits) OR 
+                                    ((n = MaxHexDigits) & (dig[0] <= '7'))) THEN
+                            WHILE i < n DO
+                                symbol.integer := symbol.integer * 10H + HexDigit(dig[i]);
+                                INC(i)
+                            END;
+                            symbol.numberType := IntNumber;
+                            symbol.hugeint := symbol.integer;
+                        ELSIF n <= MaxHugeHexDigits THEN
+                            hugeint := 0;
+                            IF (n = MaxHugeHexDigits) & (dig[0] > '7') THEN
+                                (* prevent overflow *)
+                                hugeint := -1
+                            END;
+                            WHILE i < n DO
+                                hugeint := hugeint * 10H + HexDigit(dig[i]);
+                                INC(i)
+                            END;
+                            symbol.numberType := LongNumber;
+                            symbol.hugeint := hugeint;
+                            symbol.integer := SHORT(symbol.hugeint);
+
+                        ELSE
+                            symbol.numberType := LongNumber;
+                            Error(Basic.NumberTooLarge)
+                        END
+                    ELSE    (* decimal *)
+                        WHILE (i < n) & ~long DO
+                            d := Digit(dig[i]);
+                            INC(i);
+                            nextInt := symbol.integer * 10 + d;
+                            IF nextInt >= 0 THEN
+                                symbol.integer := nextInt
+                            ELSE    (* overflow *)
+                                long := TRUE
+                            END;
+                        END;
+                        IF long THEN
+                            (* restart computation *)
+                            (*
+                                ACHTUNG: Reportedly, Fox has or had certain limitations
+                                    working with HUGEINT that affected the original code. 
+                                    Furthermore, at present Ronin supports HUGEINT as
+                                    a mere alias to LONGINT, therefore the following code
+                                    is just reserved for the future and long integer
+                                    constants are not yet supported.
+                            *)
+                            i := 0;
+                            hugeint := 0;
+                            tenh := 10;
+                            WHILE i < n DO
+                                d := Digit(dig[i]);
+                                INC(i);
+                                hugeint := hugeint * tenh + d;
+                                IF hugeint < 0 THEN
+                                    Error(Basic.NumberTooLarge)
+                                END
+                            END;
+                            symbol.numberType := LongNumber;
+                            symbol.hugeint := hugeint;
+                            symbol.integer := SHORT(symbol.hugeint);
+                        ELSE
+                            symbol.numberType := IntNumber;
+                            symbol.hugeint := symbol.integer;
+                        END
+                    END
+                ELSE
+                    symbol.numberType := LongNumber;
+                    Error(Basic.NumberTooLarge)
+                END;
+                result := IntegerLiteral;
+            ELSE    (* fraction *)
+                IF (ch = 'F') OR (ch = 'f') THEN
+                    Append(ch);
+                    GetNextCharacter;
+                    long := FALSE
+                ELSIF (ch = 'D') OR (ch = 'd') THEN
+                    Append(ch);
+                    GetNextCharacter;
+                    long := TRUE
+                ELSE
+                    long := TRUE
+                END;
+                f := 0;
+                e := 0;
+                WHILE n > 0 DO
+                    (* 0 <= f < 1 *)
+                    DEC(n);
+                    f := (Digit(dig[n]) + f) / 10
+                END;
+                IF (ch = 'E') OR (ch = 'e') THEN
+                    Append(ch);
+                    GetNextCharacter;
+                    neg := FALSE;
+                    IF ch = '-' THEN
+                        neg := TRUE;
+                        Append(ch);
+                        GetNextCharacter
+                    ELSIF ch = '+' THEN
+                        Append(ch);
+                        GetNextCharacter
+                    END;
+                    IF (ch >= '0') & (ch <= '9') THEN
+                        REPEAT
+                            n := Digit(ch);
+                            Append(ch);
+                            GetNextCharacter;
+                            IF e <= (MAX(INTEGER) - n) DIV 10 THEN
+                                e := e * 10 + n
+                            ELSE
+                                Error(Basic.NumberTooLarge)
+                            END
+                        UNTIL (ch < '0') OR (ch > '9');
+                        IF neg THEN
+                            e := -e
+                        END
+                    ELSE
+                        Error(Basic.NumberIllegalCharacter)
+                    END
+                END;
+                (* decimal point shift *)
+                DEC(e, i-d-m);
+                IF long THEN
+                    symbol.numberType := DoubleNumber;
+                    IF (1 - MaxLongrealExponent < e) & (e <= MaxLongrealExponent) THEN
+                        IF e < 0 THEN
+                            symbol.real := f / Ten(-e)
+                        ELSE
+                            symbol.real := f * Ten(e)
+                        END
+                    ELSE
+                        Error(Basic.NumberTooLarge)
+                    END
+                ELSE
+                    symbol.numberType := FloatNumber;
+                    IF (1- MaxRealExponent < e) & (e <= MaxRealExponent) THEN
+                        IF e < 0 THEN
+                            symbol.real := f / Ten(-e)
+                        ELSE
+                            symbol.real := f * Ten(e)
+                        END
+                    ELSE
+                        Error(Basic.NumberTooLarge)
+                    END
+                END;
+                result := RealLiteral;
+            END;
+            symbol.identifierString[si] := 0X;
+            RETURN result;
+        END GetNumber;
+
+        (** read / skip a comment **)
+        (**
+            Comment =
+                SingleLineComment |
+                DelimitedComment.
+            SingleLineComment =
+                '//' {InputCharacter}.
+            InputCharacter =
+                any character except a NewLineCharacter.
+            NewlineCharacter =
+                Carriage return character (0DX) |
+                Line feed character (0AX).
+            DelimitedComment =
+                '/*' [DelimitedCommentText] Asterisks '/'.
+            DelimitedCommentText =
+                DelimitedCommentSection {DelimitedCommentSection}.
+            DelimitedCommentSection =
+                NotAsterisk |
+                Asterisks NotSlash.
+            Asterisks =
+                '*' {'*'}.
+            NotAsterisk =
+                any character except *.
+            NotSlash =
+                any character except /.            
+        **)
+        PROCEDURE ReadSingleLineComment(VAR symbol: Symbol);
+        BEGIN
+            stringMaker.Clear;
+            WHILE (ch # 0DX) & (ch # 0AX) DO
+                stringWriter.Char(ch);
+                GetNextCharacter;
+            END;
+            stringWriter.Char(0X);
+            stringWriter.Update;
+            symbol.token := Comment;
+            symbol.string := stringMaker.GetString(symbol.stringLength);
+        END ReadSingleLineComment;
+
+        PROCEDURE ReadDelimitedComment(VAR symbol: Symbol);
+            VAR done: BOOLEAN;
+        BEGIN
+            stringMaker.Clear;
+            done := FALSE;
+            WHILE ~done & (ch # EOT) DO
+                IF ch = '*' THEN
+                    GetNextCharacter;
+                    IF ch = '/' THEN
+                        GetNextCharacter;
+                        done := TRUE;
+                    ELSE
+                        stringWriter.Char('*');
+                    END;
+                ELSE
+                    stringWriter.Char(ch);
+                    GetNextCharacter;
+                END;
+            END;
+            IF ~done THEN
+                Error(Basic.CommentNotClosed);
+            END;
+            stringWriter.Char(0X);
+            stringWriter.Update;
+            symbol.token := Comment;
+            symbol.string := stringMaker.GetString(symbol.stringLength);
+        END ReadDelimitedComment;
+
+        PROCEDURE SkipBlanks;
+        BEGIN
+            WHILE (ch = 20X) OR (ch = 09X) OR (ch = 0BX) OR (ch = 0CX) OR
+                    (ch = 0DX) OR (ch = 0AX) DO
+                (* ignore  C# whitespace characters '\t' (09X), '\v' (0BX), '\f' (0CX) 
+                       and newlines '\r' (0DX), '\n' (0AX) *)
+                IF ch = EOT THEN
+                    IF Trace THEN 
+                        D.String("EOT"); 
+                        D.Ln; 
+                    END;
+                    RETURN
+                ELSE 
+                    GetNextCharacter
+                END
+            END;
+        END SkipBlanks;
+
+        (** get next symbol **)
+        PROCEDURE GetNextSymbol*(VAR symbol: Symbol): BOOLEAN;
+            VAR s, token: LONGINT;
+        BEGIN
+            SkipBlanks;
+            symbol.start := position;
+            symbol.line := line;
+            stringMaker.Clear;
+(* @@@ *)
+(*
+KernelLog.String("GetNextSymbol ");
+KernelLog.Char(ch);
+KernelLog.Ln();
+*)
+            CASE ch OF
+              EOT:
+                s := EndOfText
+            | DoubleQuote:
+                s := StringLiteral;
+                GetString(symbol)
+            | SingleQuote:
+                s := CharacterLiteral;
+                GetCharacter(symbol)
+            | '!':
+                GetNextCharacter;
+                IF ch = '=' THEN
+                    GetNextCharacter;
+                    s := ExclamationEqual
+                ELSE
+                    s := Exclamation
+                END
+            | '%':
+                GetNextCharacter;
+                IF ch = '=' THEN
+                    GetNextCharacter;
+                    s := PercentEqual
+                ELSE
+                    s := Percent
+                END
+            | '&':
+                GetNextCharacter;
+                IF ch = '=' THEN
+                    GetNextCharacter;
+                    s := AndEqual
+                ELSIF ch = '&' THEN
+                    GetNextCharacter;
+                    s := AndAnd
+                ELSE
+                    s := And
+                END
+            | '(':
+                s := LeftParenthesis;
+                GetNextCharacter
+            | ')':
+                s := RightParenthesis;
+                GetNextCharacter
+            | '*':
+                GetNextCharacter;
+                IF ch = '=' THEN
+                    GetNextCharacter;
+                    s := TimesEqual
+                ELSE
+                    s := Times
+                END
+            | '+':
+                GetNextCharacter;
+                IF ch = '=' THEN
+                    GetNextCharacter;
+                    s := PlusEqual
+                ELSIF ch = '+' THEN
+                    GetNextCharacter;
+                    s := PlusPlus
+                ELSE
+                    s := Plus
+                END
+            | ',':
+                s := Comma;
+                GetNextCharacter
+            | '-':
+                GetNextCharacter;
+                IF ch = '=' THEN
+                    GetNextCharacter;
+                    s := MinusEqual
+                ELSIF ch = '-' THEN
+                    GetNextCharacter;
+                    s := MinusMinus
+                ELSE
+                    s := Minus
+                END
+            | '.':
+                GetNextCharacter;
+                IF (ch >= '0') & (ch <= '9') THEN
+                    s := GetNumber(symbol, TRUE)
+                ELSE
+                    s := Period
+                END
+            | '/':
+                GetNextCharacter;
+                IF ch = '=' THEN
+                    GetNextCharacter;
+                    s := SlashEqual
+                ELSIF ch = '/' THEN
+                    GetNextCharacter;
+                    ReadSingleLineComment(symbol);
+                    s := Comment
+                ELSIF ch = '*' THEN
+                    GetNextCharacter;
+                    ReadDelimitedComment(symbol);
+                    s := Comment
+                ELSE
+                    s := Slash
+                END
+            | '0' .. '9':
+                s := GetNumber(symbol, FALSE)
+            | ':':
+                s := Colon;
+                GetNextCharacter
+            | ';':
+                s := Semicolon;
+                GetNextCharacter
+            | '<':
+                GetNextCharacter;
+                IF ch = '=' THEN
+                    GetNextCharacter;
+                    s := LessEqual
+                ELSIF ch = '<' THEN
+                    GetNextCharacter;
+                    IF ch = '=' THEN
+                        GetNextCharacter;
+                        s := LeftShiftEqual
+                    ELSE
+                        s := LeftShift
+                    END
+                ELSE
+                    s := Less
+                END
+            | '=':
+                GetNextCharacter;
+                IF ch = '=' THEN
+                    GetNextCharacter;
+                    s := EqualEqual
+                ELSE
+                    s := Equal
+                END
+            | '>':
+                GetNextCharacter;
+                IF ch = '=' THEN
+                    GetNextCharacter;
+                    s := GreaterEqual
+                ELSIF ch = '>' THEN
+                    GetNextCharacter;
+                    IF ch = '=' THEN
+                        GetNextCharacter;
+                        s := RightShiftEqual
+                    ELSE
+                        s := RightShift
+                    END
+                ELSE
+                    s := Greater
+                END
+            | '?':
+                GetNextCharacter;
+                IF ch = '?' THEN
+                    GetNextCharacter;
+                    s := QuestionQuestion
+                ELSE
+                    s := Question;
+                END
+            | '[':
+                s := LeftBracket;
+                GetNextCharacter
+            | ']':
+                s := RightBracket;
+                GetNextCharacter
+            | '^':
+                GetNextCharacter;
+                IF ch = '=' THEN
+                    GetNextCharacter;
+                    s := ArrowEqual
+                ELSE
+                    s := Arrow
+                END
+            | '{':
+                s := LeftBrace;
+                GetNextCharacter
+            | '|':
+                GetNextCharacter;
+                IF ch = '=' THEN
+                    GetNextCharacter;
+                    s := BarEqual
+                ELSIF ch = '|' THEN
+                    GetNextCharacter;
+                    s := BarBar
+                ELSE
+                    s := Bar
+                END
+            | '}':
+                s := RightBrace;
+                GetNextCharacter
+            | '~':
+                s := Tilde;
+                GetNextCharacter
+            | 'A' .. 'Z':
+                s := Identifier;
+                GetIdentifier(symbol)
+            | 'a' .. 'z':
+                s := Identifier;
+                GetIdentifier(symbol);
+                token := keywords.IndexByIdentifier(symbol.identifier);
+                IF  (token >= 0) THEN 
+                    s := token 
+                END;
+            ELSE
+                s := Identifier;
+                GetIdentifier(symbol)
+            END;
+
+            symbol.token := s;
+            symbol.end := position;
+
+            IF Trace THEN 
+                OutSymbol(D.Log, symbol); 
+                D.Ln; 
+            END;
+
+            RETURN ~error
+        END GetNextSymbol;
+
+        PROCEDURE ResetError*();
+        BEGIN 
+            error := FALSE
+        END ResetError;
+
+        (** set the diagnostics mode of the scanner 
+            (diagnostics = NIL ==> no report) and reset the error state
+            intended for silent symbol peeeking after the end of a module *)
+        PROCEDURE ResetErrorDiagnostics*(VAR diagnostics: Diagnostics.Diagnostics);
+            VAR b: BOOLEAN; 
+                d: Diagnostics.Diagnostics;
+        BEGIN
+            error := FALSE;
+            d := SELF.diagnostics; 
+            SELF.diagnostics := diagnostics; 
+            diagnostics := d;
+        END ResetErrorDiagnostics;
+
+    END Scanner;
+
+    (** return a new scanner on a stream, error output via diagnostics  **)
+    PROCEDURE NewScanner*(
+            CONST source: ARRAY OF CHAR; 
+            reader: Streams.Reader; 
+            position: LONGINT; 
+            diagnostics: Diagnostics.Diagnostics): Scanner;
+        VAR s: Scanner;
+    BEGIN
+        NEW( s, source, reader, position, diagnostics );  
+        RETURN s;
+    END NewScanner;
+
+    VAR
+        reservedCharacter: ARRAY 256 OF BOOLEAN;
+        tokens-: ARRAY EndOfText+1 OF Keyword;
+        keywords: KeywordTable;
+
+    PROCEDURE SymbolToString*(CONST symbol: Symbol; VAR str: ARRAY OF CHAR);
+        VAR id: StringPool.Index;
+    BEGIN
+        CASE symbol.token OF
+          Identifier, IntegerLiteral, RealLiteral: 
+            COPY(symbol.identifierString, str)
+        | StringLiteral, Comment: 
+            ASSERT(LEN(str) >= LEN(symbol.string^)); 
+            COPY(symbol.string^, str);
+        ELSE
+            GetKeyword(symbol.token, id);
+            IF id < 0 THEN 
+                str[0] := 0X 
+            ELSE 
+                StringPool.GetString(id, str) END;
+        END;
+    END SymbolToString;
+
+    (** debugging output **)
+    PROCEDURE OutSymbol*(w: Streams.Writer; CONST symbol: Symbol);
+        VAR str: ARRAY 256 OF CHAR;
+            i: LONGINT;
+
+        PROCEDURE OutChar(ch: CHAR);
+        BEGIN
+            IF ((ch >= 20X) & (ch < 7FX)) OR ((ch > 0A0X) & (ch # 0ADX)) THEN
+                w.Char(ch);
+            ELSE
+                w.Char(Backslash);
+                w.Char('x');
+                w.Hex(ORD(ch), 1);
+            END;
+        END OutChar;
+
+    BEGIN
+        w.Int(symbol.start, 1); 
+        w.String("-");
+        w.Int(symbol.end, 1); 
+        w.String(":");
+        w.String(tokens[symbol.token]);
+        IF (symbol.token = IntegerLiteral) OR (symbol.token = RealLiteral) THEN
+            CASE symbol.numberType OF
+              IntNumber: 
+                w.String("(int)")
+            | LongNumber: 
+                w.String("(long)")
+            | FloatNumber: 
+                w.String("(float)")
+            | DoubleNumber: 
+                w.String("(double)")
+            END;
+        ELSIF symbol.token = CharacterLiteral THEN
+            w.String(":"); 
+            w.Char("'"); 
+            OutChar(symbol.character);
+            w.Char("'");
+        ELSIF symbol.token = StringLiteral THEN
+            w.String(":"); 
+            w.Char('"'); 
+            i := 0;
+            WHILE symbol.string^[i] # 0X DO
+                OutChar(symbol.string^[i]);
+                INC(i);
+            END;
+            w.Char('"');
+        ELSIF symbol.token = Comment THEN
+            w.String("/*"); 
+            w.String(symbol.string^); 
+            w.String("*/");
+        ELSE
+            SymbolToString(symbol, str); 
+            w.String(": "); 
+            w.String(str);
+        END
+    END OutSymbol;
+
+    (** reserved characters are the characters that may not occur within an identifier **)
+    PROCEDURE InitReservedCharacters;
+        VAR i: LONGINT;
+    BEGIN
+        FOR i := 0 TO LEN(reservedCharacter) - 1 DO
+            CASE CHR(i) OF
+            | 'a' .. 'z', 'A' .. 'Z': 
+                reservedCharacter[i] := FALSE;
+            | '0'..'9': 
+                reservedCharacter[i] := FALSE;
+            | '_': 
+                reservedCharacter[i] := FALSE
+            ELSE
+                reservedCharacter[i] := TRUE
+            END;
+        END;
+    END InitReservedCharacters;
+
+    (* get keyword by token *)
+    PROCEDURE GetKeyword*(token: LONGINT; VAR identifier: IdentifierType);
+    BEGIN
+        keywords.IdentifierByIndex(token, identifier);
+    END GetKeyword;
+
+    PROCEDURE InitTokens;
+    VAR i: LONGINT;
+    BEGIN
+        tokens[None] := "None";
+
+        (* operators and punctuators *)    
+        tokens[Exclamation] := "Exclamation";
+        tokens[ExclamationEqual] := "ExclamationEqual";
+        tokens[Percent] := "Percent";   
+        tokens[PercentEqual] := "PercentEqual";
+        tokens[And] := "And";
+        tokens[AndEqual] := "AndEqual";
+        tokens[AndAnd] := "AndAnd";
+        tokens[LeftParenthesis] := "LeftParenthesis";
+        tokens[RightParenthesis] := "RightParenthesis";
+        tokens[Times] := "Times";
+        tokens[TimesEqual] := "TimesEqual";
+        tokens[Plus] := "Plus";
+        tokens[PlusEqual] := "PlusEqual";
+        tokens[PlusPlus] := "PlusPlus";
+        tokens[Comma] := "Comma";
+        tokens[Minus] := "Minus";
+        tokens[MinusEqual] := "MinusEqual";
+        tokens[MinusMinus] := "MinusMinus";
+        tokens[Period] := "Period";
+        tokens[Slash] := "Slash";
+        tokens[SlashEqual] := "SlashEqual";
+        tokens[Colon] := "Colon";
+        tokens[Semicolon] := "Semicolon";
+        tokens[Less] := "Less";
+        tokens[LessEqual] := "LessEqual";
+        tokens[LeftShift] := "LeftShift";
+        tokens[LeftShiftEqual] := "LeftShiftEqual";
+        tokens[Equal] := "Equal";
+        tokens[EqualEqual] := "EqualEqual";
+        tokens[Greater] := "Greater";
+        tokens[GreaterEqual] := "GreaterEqual";
+        tokens[RightShift] := "RightShift";
+        tokens[RightShiftEqual] := "RightShiftEqual";
+        tokens[LeftBracket] := "LeftBracket";
+        tokens[RightBracket] := "RightBracket";
+        tokens[Arrow] := "Arrow";
+        tokens[ArrowEqual] := "ArrowEqual";
+        tokens[LeftBrace] := "LeftBrace";
+        tokens[Bar] := "Bar";
+        tokens[BarEqual] := "BarEqual";
+        tokens[BarBar] := "BarBar";
+        tokens[RightBrace] := "RightBrace";
+        tokens[Tilde] := "Tilde";
+
+        (* keywords *)
+        tokens[As] := "As";
+        tokens[Base] := "Base";
+        tokens[Bool] := "Bool";
+        tokens[Break] := "Break";
+        tokens[Case] := "Case";
+        tokens[Char] := "Char";
+        tokens[Class] := "Class";
+        tokens[Const] := "Const";
+        tokens[Default] := "Default";
+        tokens[Delegate] := "Delegate";
+        tokens[Do] := "Do";
+        tokens[Double] := "Double";
+        tokens[Else] := "Else";
+        tokens[False] := "False";
+        tokens[Float] := "Float";
+        tokens[For] := "For";
+        tokens[If] := "If";
+        tokens[Import] := "Import";
+        tokens[Int] := "Int";
+        tokens[Internal] := "Internal";
+        tokens[Is] := "Is";
+        tokens[Long] := "Long";
+        tokens[Module] := "Module";
+        tokens[New] := "New";
+        tokens[Null] := "Null";
+        tokens[Object] := "Object";
+        tokens[Public] := "Public";
+        tokens[Readonly] := "Readonly";
+        tokens[Ref] := "Ref";
+        tokens[Return] := "Return";
+        tokens[Sbyte] := "Sbyte";
+        tokens[Short] := "Short";
+        tokens[String] := "String";
+        tokens[Struct] := "Struct";
+        tokens[Switch] := "Switch";
+        tokens[This] := "This";
+        tokens[True] := "True";
+        tokens[Void] := "Void";
+        tokens[While] := "While";
+
+        tokens[Identifier] := "Identifier";
+        tokens[IntegerLiteral] := "IntegerLiteral";
+        tokens[RealLiteral] := "RealLiteral";
+        tokens[CharacterLiteral] := "CharacterLiteral";
+        tokens[StringLiteral] := "StringLiteral";
+
+        tokens[Comment] := "Comment";
+        tokens[EndOfText] := "EndOfText";
+
+        (* Active Cells *)
+        tokens[Cell] := "Cell";
+        tokens[Cellnet] := "Cellnet";
+        tokens[In] := "In";
+        tokens[Out] := "Out";
+        tokens[Select] := "Select";
+
+        tokens[Question] := "Question";
+        tokens[QuestionQuestion] := "QuestionQuestion";
+
+        FOR i := 0 TO EndOfText DO 
+            ASSERT(tokens[i] # "") 
+        END;
+    END InitTokens;
+
+    (** enter keywords in the list of keywords **)
+    PROCEDURE InitKeywords;
+
+        PROCEDURE Enter(CONST name: ARRAY OF CHAR; token: LONGINT);
+        BEGIN
+            keywords.PutString(name, token);
+            Basic.SetErrorExpected(token, name);
+        END Enter;
+
+    BEGIN
+        NEW(keywords,EndOfText+1);
+
+        (* keywords *)
+        Enter("as", As);
+        Enter("base", Base);
+        Enter("bool", Bool);
+        Enter("break", Break);
+        Enter("case", Case);
+        Enter("char", Char);
+        Enter("class", Class);
+        Enter("const", Const);
+        Enter("default", Default);
+        Enter("delegate", Delegate);
+        Enter("do", Do);
+        Enter("double", Double);
+        Enter("else", Else);
+        Enter("false", False);
+        Enter("float", Float);
+        Enter("for", For);
+        Enter("if", If);
+        Enter("import", Import);
+        Enter("int", Int);
+        Enter("internal", Internal);
+        Enter("is", Is);
+        Enter("long", Long);
+        Enter("module", Module);
+        Enter("new", New);
+        Enter("null", Null);
+        Enter("object", Object);
+        Enter("public", Public);
+        Enter("readonly", Readonly);
+        Enter("ref", Ref);
+        Enter("return", Return);
+        Enter("sbyte", Sbyte);
+        Enter("short", Short);
+        Enter("string", String);
+        Enter("struct", Struct);
+        Enter("switch", Switch);
+        Enter("this", This);
+        Enter("true", True);
+        Enter("void", Void);
+        Enter("while", While);
+
+        (* operators and punctuators *)
+        Enter("!", Exclamation);   
+        Enter("!=", ExclamationEqual);
+        Enter("%", Percent);
+        Enter("%=", PercentEqual);
+        Enter("&", And);
+        Enter("&=", AndEqual);
+        Enter("&&", AndAnd);
+        Enter("(", LeftParenthesis);
+        Enter(")", RightParenthesis);
+        Enter("*", Times);
+        Enter("*=", TimesEqual);
+        Enter("+", Plus);
+        Enter("+=", PlusEqual);
+        Enter("++", PlusPlus);
+        Enter(",", Comma);
+        Enter("-", Minus);
+        Enter("-=", MinusEqual);
+        Enter("--", MinusMinus);
+        Enter(".", Period);
+        Enter("/", Slash);
+        Enter("/=", SlashEqual);
+        Enter(":", Colon);
+        Enter(";", Semicolon);
+        Enter("<", Less);
+        Enter("<=", LessEqual);
+        Enter("<<", LeftShift);
+        Enter("<<=", LeftShiftEqual);
+        Enter("=", Equal);
+        Enter("==", EqualEqual);
+        Enter(">", Greater);
+        Enter(">=", GreaterEqual);
+        Enter(">>", RightShift);
+        Enter(">>=", RightShiftEqual);
+        Enter("[", LeftBracket);
+        Enter("]", RightBracket);
+        Enter("^", Arrow);
+        Enter("^=", ArrowEqual);
+        Enter("{", LeftBrace);
+        Enter("|", Bar);
+        Enter("}", BarEqual);
+        Enter("||", BarBar);
+        Enter("}", RightBrace);
+        Enter("~", Tilde);
+
+        (* Active Cells *)
+        Enter("cell", Cell);
+        Enter("cellnet", Cellnet);
+        Enter("in", In);
+        Enter("out", Out);
+        Enter("select", Select);
+
+        Enter("?", Question);
+        Enter("??", QuestionQuestion);
+
+        Basic.SetErrorMessage(Identifier, "missing identifier");
+        Basic.SetErrorMessage(IntegerLiteral, "missing integer literal");
+        Basic.SetErrorMessage(RealLiteral, "missing real literal");
+        Basic.SetErrorMessage(CharacterLiteral, "missing character literal");
+        Basic.SetErrorMessage(StringLiteral, "missing string literal");
+      END InitKeywords;
+
+    (** debugging / reporting **)
+    PROCEDURE ReportKeywords*(context: Commands.Context);
+        VAR i: LONGINT; 
+            name: Keyword;
+    BEGIN
+        FOR i := 0 TO EndOfText DO
+            context.out.Int(i, 1); 
+            context.out.String(": ");
+            context.out.Char('"');
+            keywords.StringByIndex(i, name);
+            context.out.String(name);
+            context.out.Char('"');
+            context.out.Ln;
+        END;
+    END ReportKeywords;
+
+(*
+    PROCEDURE TestScanner*(context: Commands.Context);
+        VAR filename: ARRAY 256 OF CHAR; 
+            reader: Streams.Reader; 
+            scanner: Scanner;
+            sym: Symbol;
+    BEGIN
+        context.arg.SkipWhitespace; 
+        context.arg.String(filename);
+        reader := TextUtilities.GetTextReader(filename);
+        scanner := NewScanner(filename, reader, 0, NIL);
+        REPEAT
+            IF scanner.GetNextSymbol(sym) THEN
+                OutSymbol(context.out, sym);
+                context.out.Ln;
+            END;
+        UNTIL scanner.error OR (sym.token = EndOfText)
+    END TestScanner;
+*)
+
+BEGIN
+    InitReservedCharacters;
+    InitTokens;
+    InitKeywords
+END FoxCSharpScanner.