buildftr.pas

Переключить прокрутку окна
Загрузить этот исходный код

{
    Этот исходный текст является частью Продвинутого векторного транслятора.

    Copyright © 2017 Малик Разработчик

    Это свободная программа: вы можете перераспространять её и/или
    изменять её на условиях Стандартной общественной лицензии GNU в том виде,
    в каком она была опубликована Фондом свободного программного обеспечения;
    либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.

    Эта программа распространяется в надежде, что она может быть полезна,
    но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
    или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЁННЫХ ЦЕЛЕЙ. Подробнее см. в Стандартной
    общественной лицензии GNU.

    Вы должны были получить копию Стандартной общественной лицензии GNU
    вместе с этой программой. Если это не так, см.
    <http://www.gnu.org/licenses/>.
}

unit BuildFTr;

{$MODE DELPHI,EXTENDEDSYNTAX ON}

interface

uses
    Lang, Utils, IOStream, TranIntf, TranType, TranTree, BuildLex, BuildNms;

{$ASMMODE INTEL,CALLING REGISTER,INLINE ON,GOTO ON}
{$H+,I-,J-,M-,Q-,R-,T-}

type
    BuilderNode = interface;
    TranslatorBuilderNode = class;
    TranslatorTreeBuilder = class;

    BuilderNode = interface(SyntaxNode) ['{2187DBA7-8D82-42DE-95E7-6B43015BBA94}']
        procedure setOptimized(optimized: boolean);
        procedure setAssignedLabelNumber(assignedLabelNumber: int);
        procedure setLabelName(const labelName: UnicodeString);
        function isOptimized(): boolean;
        function getAssignedLabelNumber(): int;
        function getLabelName(): UnicodeString;
        property optimized: boolean read isOptimized write setOptimized;
        property assignedLabelNumber: int read getAssignedLabelNumber write setAssignedLabelNumber;
        property labelName: UnicodeString read getLabelName write setLabelName;
    end;

    TranslatorBuilderNode = class(TranslatorSyntaxNode, BuilderNode)
    public
        constructor create(); override;
        function toString(): AnsiString; override;
        procedure clearData(); override;
        procedure setOptimized(optimized: boolean); virtual;
        procedure setAssignedLabelNumber(assignedLabelNumber: int); virtual;
        procedure setLabelName(const labelName: UnicodeString); virtual;
        function isOptimized(): boolean; virtual;
        function getAssignedLabelNumber(): int; virtual;
        function getLabelName(): UnicodeString; virtual;
    strict private
        optimized: boolean;
        assignedLabelNumber: int;
        labelName: UnicodeString;
    end;

    TranslatorTreeBuilder = class(TranslatorNamespacesBuilder, BuilderOfTrees)
    public
        const NULL = 0;
        { function bounds }// Компилируем ли этот вид узла? o – всегда, x – никогда, # – не всегда.
        const FUNCTION_START  = 1; // {                                                           o
        const FUNCTION_RETURN = 2; // }                                                           o
        { operators }
        const OPERATOR_EMPTY       = 100; // ;                                                    x
        const OPERATOR_LABEL       = 101; // label: <оператор>                                    x
        const OPERATOR_BLOCK       = 102; // {<операторы>}                                        x
        const OPERATOR_VARIABLE    = 103; // <тип> имя = <выражение>;                             #
        const OPERATOR_DISPOSE     = 104; // dispose <выражение>;                                 o
        const OPERATOR_WITH        = 105; // with(<выражение>) <оператор>                         x
        const OPERATOR_TRY_CATCH   = 106; // try {<операторы>} catch(<исключение>) {<операторы>}  x
        const OPERATOR_TRY_FINALLY = 107; // try {<операторы>} finally {<операторы>}              x
        const OPERATOR_BREAK       = 108; // break <метка>;                                       o
        const OPERATOR_CONTINUE    = 109; // continue <метка>;                                    o
        const OPERATOR_IF          = 110; // if(<выражение>) <оператор> else <оператор>           x
        const OPERATOR_SWITCH      = 111; // switch(<выражение>) {case <выражение>: <операторы>}  o
        const OPERATOR_DO          = 112; // for(<выражение>; <выражение>; <выражение>) <оператор>x
        const OPERATOR_FOR         = 113; // while(<выражение>) <оператор>                        x
        const OPERATOR_WHILE       = 114; // do <оператор> while(<выражение>);                    x
        const OPERATOR_THROW       = 115; // throw <исключение>;                                  o
        const OPERATOR_RETURN      = 116; // return <выражение>;                                  o
        const TF_OPERATOR_RETURN   = 117; // try { return <выражение>; } finally                  o
        { operator's blocks }
        const BLOCK_WITH           = 200; // with variable                                        o
        const BLOCK_CATCH          = 201; // catch                                                x
        const BLOCK_FINALLY_START  = 202; // finally begin                                        x
        const BLOCK_FINALLY_RETURN = 203; // finally return                                       o
        const BLOCK_CASE           = 204; // case                                                 x
        const BLOCK_DEFAULT        = 205; // default                                              x
        { expression's pieces }
        const EXPR_VALUE_NULL      = 300; // null                                                 o
        const EXPR_VALUE_BOOLEAN   = 301; // false..true                                          #
        const EXPR_VALUE_INT       = 302; // 0x80000000..0x7fffffff                               o
        const EXPR_VALUE_LONG      = 303; // 0x8000000000000000L..0x7fffffffffffffffL             o
        const EXPR_VALUE_ULTRA     = 304; // new ultra { int, int, int, int }                     o
        const EXPR_VALUE_REAL      = 307; // ±целая.дробнаяE±порядок(F, D, R)                     o
        const EXPR_VALUE_XVECTOR   = 308; // new xvector { float, float, float, float }           o
        const EXPR_VALUE_STRING    = 311; // "строка"                                             o
        const EXPR_LOCAL_VARIABLE  = 320; // <локальная переменная>                               #
        const EXPR_GLOBAL_VARIABLE = 322; // <глобальная переменная>                              #
        const EXPR_GLOBAL_FUNCTION = 323; // <глобальная функция>                                 #
        { expression's new operations }
        const EXPR_NEW_STRUCT            = 350; // new <структура> {…}                            o
        const EXPR_NEW_ARRAY_BY_ELEMENTS = 351; // new <тип> {…}                                  o
        const EXPR_NEW_ARRAY_BY_LENGTH   = 352; // new <тип>[<выражение>]                         o
        const EXPR_NEW_ULTRA             = 353; // new ultra {…}                                  o
        const EXPR_NEW_XVECTOR           = 356; // new xvector {…}                                o
        const EXPR_FIELD_ASSIGN          = 359; // поле=…                                         o
        const EXPR_ARRAY_ASSIGN          = 360; // [индекс]=…                                     o
        { expression's operations }
        const EXPR_CALL      = 400; // x(y)                                                       o
        const EXPR_ARRAY     = 401; // x[y]                                                       #
        const EXPR_COMPOUND  = 402; // x[y]                                                       o
        const EXPR_FIELD     = 403; // x.поле                                                     #
        const EXPR_INCR_POST = 404; // x++                                                        o
        const EXPR_DECR_POST = 405; // x--                                                        o
        const EXPR_TYPE_CAST = 406; // (<тип>) x                                                  #
        const EXPR_SNOTB     = 407; // ~x                                                         o
        const EXPR_SNOTL     = 408; // !x                                                         x
        const EXPR_SNEG      = 409; // -x                                                         o
        const EXPR_INCR_PRED = 410; // ++x                                                        o
        const EXPR_DECR_PRED = 411; // --x                                                        o
        const EXPR_QPACKUS   = 412; // @@@@x                                                      o
        const EXPR_QUNPCKL   = 413; // ####x                                                      o
        const EXPR_QUNPCKH   = 414; // ^^^^x                                                      o
        const EXPR_QNEG      = 415; // ----x                                                      o
        const EXPR_OPACKUS   = 416; // @@..@@x                                                    o
        const EXPR_OUNPCKL   = 417; // ##..##x                                                    o
        const EXPR_OUNPCKH   = 418; // ^^..^^x                                                    o
        const EXPR_ONEG      = 419; // --..--x                                                    o
        const EXPR_SMULL     = 420; // x * y                                                      o
        const EXPR_SDIVS     = 421; // x / y                                                      o
        const EXPR_SREMS     = 422; // x % y                                                      o
        const EXPR_SDIVU     = 423; // x // y                                                     o
        const EXPR_SREMU     = 424; // x %% y                                                     o
        const EXPR_QMULL     = 425; // x **** y                                                   o
        const EXPR_QMULH     = 426; // x ***^ y                                                   o
        const EXPR_QMULHS    = 427; // x ***| y                                                   o
        const EXPR_QDIV      = 428; // x //// y                                                   o
        const EXPR_OMULL     = 429; // x **..** y                                                 o
        const EXPR_OMULH     = 430; // x **..*^ y                                                 o
        const EXPR_OMULHS    = 431; // x **..*| y                                                 o
        const EXPR_SADD      = 432; // x + y                                                      o
        const EXPR_SSUB      = 433; // x - y                                                      o
        const EXPR_QADD      = 434; // x ++++ y                                                   o
        const EXPR_QADDS     = 435; // x +++| y                                                   o
        const EXPR_QADDUS    = 436; // x +++# y                                                   o
        const EXPR_QSUB      = 437; // x ---- y                                                   o
        const EXPR_QSUBS     = 438; // x ---| y                                                   o
        const EXPR_QSUBUS    = 439; // x ---# y                                                   o
        const EXPR_OADD      = 440; // x ++..++ y                                                 o
        const EXPR_OADDS     = 441; // x ++..+| y                                                 o
        const EXPR_OADDUS    = 442; // x ++..+# y                                                 o
        const EXPR_OSUB      = 443; // x --..-- y                                                 o
        const EXPR_OSUBS     = 444; // x --..-| y                                                 o
        const EXPR_OSUBUS    = 445; // x --..-# y                                                 o
        const EXPR_SSLL      = 446; // x << y                                                     o
        const EXPR_SSRA      = 447; // x >> y                                                     o
        const EXPR_SSRL      = 448; // x >>> y                                                    o
        const EXPR_QSLL      = 449; // x <<<< y                                                   o
        const EXPR_QSRA      = 450; // x >>>> y                                                   o
        const EXPR_QSRL      = 451; // x >>>>> y                                                  o
        const EXPR_OSLL      = 452; // x <<..<< y                                                 o
        const EXPR_OSRA      = 453; // x >>..>> y                                                 o
        const EXPR_OSRL      = 454; // x >>..>>> y                                                o
        const EXPR_SGT       = 455; // x > y                                                      o
        const EXPR_SGE       = 456; // x >= y                                                     o
        const EXPR_SLT       = 457; // x < y                                                      o
        const EXPR_SLE       = 458; // x <= y                                                     o
        const EXPR_QGT       = 459; // x >>|| y                                                   o
        const EXPR_QGE       = 460; // x >=|| y                                                   o
        const EXPR_QLT       = 461; // x <<|| y                                                   o
        const EXPR_QLE       = 462; // x <=|| y                                                   o
        const EXPR_OGT       = 463; // x >>|..| y                                                 o
        const EXPR_OGE       = 464; // x >=|..| y                                                 o
        const EXPR_OLT       = 465; // x <<|..| y                                                 o
        const EXPR_OLE       = 466; // x <=|..| y                                                 o
        const EXPR_SEQ       = 467; // x == y                                                     o
        const EXPR_SNE       = 468; // x != y                                                     o
        const EXPR_QEQ       = 469; // x ==|| y                                                   o
        const EXPR_QNE       = 470; // x !=|| y                                                   o
        const EXPR_OEQ       = 471; // x ==|..| y                                                 o
        const EXPR_ONE       = 472; // x !=|..| y                                                 o
        const EXPR_SANDB     = 473; // x & y                                                      o
        const EXPR_SXORB     = 474; // x ^ y                                                      o
        const EXPR_SORB      = 475; // x | y                                                      o
        const EXPR_SANDL     = 476; // x && y                                                     x
        const EXPR_SORL      = 477; // x || y                                                     x
        const EXPR_QUESTION  = 550; // x ? y : z                                                  x
        const EXPR_SEQ_NULL  = 551; // x == null                                                  o
        const EXPR_SNE_NULL  = 552; // x != null                                                  o
        const EXPR_SZR_TEST  = 553; // (x & y) == 0                                               o
        const EXPR_SNZ_TEST  = 554; // (x & y) != 0                                               o
        { expression's assignments (must be between 600 and 699) }
        const ASSIGN        = 605; // x = y                                                       o
        const ASSIGN_SMULL  = 619; // x *= y                                                      o
        const ASSIGN_SDIVS  = 620; // x /= y                                                      o
        const ASSIGN_SREMS  = 621; // x %= y                                                      o
        const ASSIGN_SDIVU  = 622; // x //= y                                                     o
        const ASSIGN_SREMU  = 623; // x %%= y                                                     o
        const ASSIGN_QMULL  = 624; // x ****= y                                                   o
        const ASSIGN_QMULH  = 625; // x ***^= y                                                   o
        const ASSIGN_QMULHS = 626; // x ***|= y                                                   o
        const ASSIGN_QDIV   = 627; // x ////= y                                                   o
        const ASSIGN_OMULL  = 628; // x **..**= y                                                 o
        const ASSIGN_OMULH  = 629; // x **..*^= y                                                 o
        const ASSIGN_OMULHS = 630; // x **..*|= y                                                 o
        const ASSIGN_SADD   = 631; // x += y                                                      o
        const ASSIGN_SSUB   = 632; // x -= y                                                      o
        const ASSIGN_QADD   = 633; // x ++++= y                                                   o
        const ASSIGN_QADDS  = 634; // x +++|= y                                                   o
        const ASSIGN_QADDUS = 635; // x +++#= y                                                   o
        const ASSIGN_QSUB   = 636; // x ----= y                                                   o
        const ASSIGN_QSUBS  = 637; // x ---|= y                                                   o
        const ASSIGN_QSUBUS = 638; // x ---#= y                                                   o
        const ASSIGN_OADD   = 639; // x ++..++= y                                                 o
        const ASSIGN_OADDS  = 640; // x ++..+|= y                                                 o
        const ASSIGN_OADDUS = 641; // x ++..+#= y                                                 o
        const ASSIGN_OSUB   = 642; // x --..--= y                                                 o
        const ASSIGN_OSUBS  = 643; // x --..-|= y                                                 o
        const ASSIGN_OSUBUS = 644; // x --..-#= y                                                 o
        const ASSIGN_SSLL   = 645; // x <<= y                                                     o
        const ASSIGN_SSRA   = 646; // x >>= y                                                     o
        const ASSIGN_SSRL   = 647; // x >>>= y                                                    o
        const ASSIGN_QSLL   = 648; // x <<<<= y                                                   o
        const ASSIGN_QSRA   = 649; // x >>>>= y                                                   o
        const ASSIGN_QSRL   = 650; // x >>>>>= y                                                  o
        const ASSIGN_OSLL   = 651; // x <<..<<= y                                                 o
        const ASSIGN_OSRA   = 652; // x >>..>>= y                                                 o
        const ASSIGN_OSRL   = 653; // x >>..>>>= y                                                o
        const ASSIGN_QGT    = 658; // x >>||= y                                                   o
        const ASSIGN_QGE    = 659; // x >=||= y                                                   o
        const ASSIGN_QLT    = 660; // x <<||= y                                                   o
        const ASSIGN_QLE    = 661; // x <=||= y                                                   o
        const ASSIGN_OGT    = 662; // x >>|..|= y                                                 o
        const ASSIGN_OGE    = 663; // x >=|..|= y                                                 o
        const ASSIGN_OLT    = 664; // x <<|..|= y                                                 o
        const ASSIGN_OLE    = 665; // x <=|..|= y                                                 o
        const ASSIGN_QEQ    = 668; // x ==||= y                                                   o
        const ASSIGN_QNE    = 669; // x !=||= y                                                   o
        const ASSIGN_OEQ    = 670; // x ==|..|= y                                                 o
        const ASSIGN_ONE    = 671; // x !=|..|= y                                                 o
        const ASSIGN_SANDB  = 672; // x &= y                                                      o
        const ASSIGN_SXORB  = 673; // x ^= y                                                      o
        const ASSIGN_SORB   = 674; // x |= y                                                      o
        { jumps }
        const JUMP    = 900; // jump                                                              o
        const TF_JUMP = 916; // try { jump } finally                                              o

        { вспомогательные методы }
        class function isNodeValueAssign(value: int): boolean;
        class function getTypeKind(theType: TypeDescriptor): int;
        class function ultraToXVector(const value: ultra): xvector;
        class function xvectorToUltra(const value: xvector): ultra;
        class function getArrayOfParents(node: Node): Node_Array1d;
        class function getCommonParent(node1, node2: Node): Node;
    strict private
        class function insertTypeCast(node: SyntaxNode; cast: TypeDescriptor): SyntaxNode;
        class function getNodeWithMinLabelNumber(node, next: SyntaxNode): SyntaxNode;
        class function findLocalVariable(const name: UnicodeString;
                parent: SyntaxNode): LocalVariable;

    public
        constructor create(operandSize, extension: int);
        function buildSyntaxTree(forFunction: GlobalFunction): Tree; virtual;
    protected
        function possibleAssign(dstType, srcType: TypeDescriptor;
                srcAsoc: _Interface): boolean; overload; virtual;
    strict private { секция построения дерева }
        currWithVarNum: int;
        arrayLengthField: StructureField;
        function parseExprPost(lexemes: Lexer; position: int; parent, child: SyntaxNode): int;
        function parseExprNew(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseExprElem(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseExprPref(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseExprMult(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseExprAdd(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseExprShift(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseExprRel(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseExprEqual(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseExprBAnd(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseExprBXor(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseExprBOr(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseExprLAnd(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseExprLOr(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseExprCond(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseExprAssign(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseLocalVar(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseDispose(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseWith(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseTry(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseBreak(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseContinue(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseIf(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseSwitch(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseDo(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseFor(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseWhile(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseThrow(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseReturn(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseOpBlock(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseOperator(lexemes: Lexer; position: int; parent: SyntaxNode): int;
        function parseStatement(lexemes: Lexer; position: int; parent: SyntaxNode;
                raisesExceptionIfEmpty: boolean): int;
        function parseForExpr(lexemes: Lexer; position: int; parent: SyntaxNode;
                expressionOnly: boolean): int;
        function parseIdentifier(lexemes: Lexer; position: int; parent: SyntaxNode): NamedObject;
    strict private { секция связывания узлов }
        procedure optimizeJumps(tree: SyntaxTree; touchReturn: boolean);
        procedure numerateNodes(node: SyntaxNode);
        procedure placeJumpsInExpression(node: SyntaxNode);
        procedure placeJumpsInBoolean(node, goIfTrue, goIfFalse: SyntaxNode);
        function placeJumpsInOperator(node, next: SyntaxNode): SyntaxNode;
        function insertInitializations(root: SyntaxNode): SyntaxNode;
    strict private { секция анализа дерева }
        function isReachable(node: SyntaxNode): boolean;
        function isReturnTo(last: SyntaxNode): boolean;
        function hasLinksTo(node: SyntaxNode): boolean;
    end;

resourcestring
    msgExpectedStatement = 'Ожидается оператор.';
    msgExpectedKeywordWhile = 'Ожидается ключевое слово "while".';
    msgExpectedKeywordCatchFinally = 'Ожидается ключевое слово "catch" или "finally".';
    msgExpectedAssignOrCall = 'Ожидается оператор "присвоить" или вызов функции.';
    msgSwitchCaseValueAlreadyPresent = 'Это значение метки "case" уже встречалось.';
    msgSwitchDefaultAlreadyPresent = 'Метка "default" уже встречалась.';
    msgBreakLabelNotFound = 'Меточный оператор "break": метка не найдена.';
    msgBreakUnlabeledNotAllowed = 'Безметочный оператор "break" может быть ' +
            'только внутри блоков "do", "for", "while" и "switch".';
    msgContinueLabelNotFound = 'Меточный оператор "continue": метка не найдена.';
    msgContinueLabeledNotAllowed = 'Меточный оператор "continue" допустим, только если этой ' +
            'меткой помечен блок "do", "for" или "while".';
    msgContinueUnlabeledNotAllowed = 'Безметочный оператор "continue" может быть ' +
            'только внутри блоков "do", "for" и "while".';
    msgFinallyBreakNotAllowed = 'Операторы "break", "continue" и "return" ' +
            'недопустимы, если они означают выход из блока "finally".';
    msgFinallyTryNotAllowed = 'Оператор "try" недопустим внутри блока "finally".';
    msgTypeMustBeArray = 'Тип выражения должен быть массивом.';
    msgTypeMustBeStruct = 'Тип выражения должен быть структурой.';
    msgTypeMustBeFunction = 'Тип выражения должен быть функциональным.';
    msgTypeMustBeAvailableForNew = 'Тип выражения должен быть подходящим для создания ' +
            'операцией "new".';
    msgOperationApplicableOnlyToVar = 'Эта операция применима только к переменным, ' +
            'полям структур и ячейкам массива.';
    msgLengthMustInFirstSquareBrackets = 'Длина массива должна быть указана только в первых ' +
            'квадратных скобках.';
    msgCannotAssignToNull = 'Нельзя присвоить значению "null" что-либо.';
    msgDetectedUnreachableCode = 'Обнаружен недостижимый код.';
    msgFunctionShouldReturnValue = 'Функция должна возвращать значение или ' +
            'генерировать исключение.';

implementation

type
    FoundObject = interface;
    TranslatorFoundObject = class;

    FoundObject = interface(StructureField) ['{2187DBA7-8D82-42DE-95E7-6B43015BBA95}']
        function getFoundIn(): LocalVariable;
        function getBaseObject(): StructureField;
        property foundIn: LocalVariable read getFoundIn;
        property baseObject: StructureField read getBaseObject;
    end;

    TranslatorFoundObject = class(RefCountInterfacedObject, NamedObject, NameAndType,
            StructureField, FoundObject)
    public
        constructor create(foundIn: LocalVariable; baseObject: StructureField);
        function toString(): AnsiString; override;
        procedure setDeclarePosition(declarePosition: int); virtual;
        procedure setStartPosition(startPosition: int); virtual;
        function getDeclarePosition(): int; virtual;
        function getStartPosition(): int; virtual;
        function getName(): UnicodeString; virtual;
        function getDataType(): TypeDescriptor; virtual;
        function isPublic(): boolean; virtual;
        function getOffset(): int; virtual;
        function getOwner(): TypeStructure; virtual;
        function getFoundIn(): LocalVariable; virtual;
        function getBaseObject(): StructureField; virtual;
    strict private
        foundIn: LocalVariable;
        baseObject: StructureField;
    end;

{ TranslatorBuilderNode }

constructor TranslatorBuilderNode.create();
begin
    inherited create();
    self.assignedLabelNumber := -1;
    self.labelName := '';
end;

function TranslatorBuilderNode.toString(): AnsiString;
var
    compiledLabelNumber: int;
    assignedLabelNumber: int;
    position: int;
    lineNumber: int;
    charNumber: int;
    value: int;
    kind: int;
    dataType: TypeDescriptor;
    associate: _Interface;
    goAlwaysToNode: SyntaxNode;
    goIfTrueToNode: SyntaxNode;
    goIfFalseToNode: SyntaxNode;
    labelName: UnicodeString;
    s: AnsiString;
    stream: Output;
    node: BuilderNode;
    ival: int;
    lval: long;
    uval: ultra;
    rval: real;
    xval: xvector;
begin
    compiledLabelNumber := getLabelNumber();
    assignedLabelNumber := getAssignedLabelNumber();
    position := getPosition();
    if position >= 0 then with (getOwner() as SyntaxTree).lexemes do begin
        lineNumber := getLine(position);
        charNumber := getChar(position);
    end else begin
        lineNumber := 0;
        charNumber := 0;
    end;
    value := getValue();
    dataType := getDataType();
    associate := getAssociate();
    goAlwaysToNode := getGoAlwaysToNode();
    goIfTrueToNode := getGoIfTrueToNode();
    goIfFalseToNode := getGoIfFalseToNode();
    labelName := getLabelName();
    stream := ByteArrayStream.create();
    if compiledLabelNumber >= 0 then begin
        s := 'C' + intToString(compiledLabelNumber) + #$20;
    end else begin
        s := '';
    end;
    if assignedLabelNumber >= 0 then begin
        s := s + '.L.' + intToString(assignedLabelNumber);
    end else begin
        s := s + '$' + intToHexString(getHashCode());
    end;
    stream.write(stringToByteArray(s));
    if (lineNumber >= 1) and (charNumber >= 1) then begin
        stream.write(stringToByteArray(' (' +
                intToString(lineNumber) + ':' +
                intToString(charNumber) + ')'));
    end;
    case value of
    TranslatorTreeBuilder.NULL:
        s := '<null>';
    TranslatorTreeBuilder.FUNCTION_START:
        s := '{';
    TranslatorTreeBuilder.FUNCTION_RETURN:
        s := '}';
    TranslatorTreeBuilder.OPERATOR_EMPTY:
        s := ';';
    TranslatorTreeBuilder.OPERATOR_LABEL:
        s := '';
    TranslatorTreeBuilder.OPERATOR_BLOCK:
        s := '{…}';
    TranslatorTreeBuilder.OPERATOR_VARIABLE:
        s := 'declare var';
    TranslatorTreeBuilder.OPERATOR_DISPOSE:
        s := 'dispose';
    TranslatorTreeBuilder.OPERATOR_WITH:
        s := 'with';
    TranslatorTreeBuilder.OPERATOR_TRY_CATCH:
        s := 'try…catch';
    TranslatorTreeBuilder.OPERATOR_TRY_FINALLY:
        s := 'try…finally';
    TranslatorTreeBuilder.OPERATOR_BREAK:
        s := 'break';
    TranslatorTreeBuilder.OPERATOR_CONTINUE:
        s := 'continue';
    TranslatorTreeBuilder.OPERATOR_IF:
        s := 'if';
    TranslatorTreeBuilder.OPERATOR_SWITCH:
        s := 'switch';
    TranslatorTreeBuilder.OPERATOR_FOR:
        s := 'for';
    TranslatorTreeBuilder.OPERATOR_WHILE:
        s := 'while';
    TranslatorTreeBuilder.OPERATOR_DO:
        s := 'do';
    TranslatorTreeBuilder.OPERATOR_THROW:
        s := 'throw';
    TranslatorTreeBuilder.OPERATOR_RETURN:
        s := 'return';
    TranslatorTreeBuilder.TF_OPERATOR_RETURN:
        s := 'return finally';
    TranslatorTreeBuilder.BLOCK_WITH:
        s := 'with var';
    TranslatorTreeBuilder.BLOCK_CATCH:
        s := 'catch';
    TranslatorTreeBuilder.BLOCK_FINALLY_START:
        s := 'finally';
    TranslatorTreeBuilder.BLOCK_FINALLY_RETURN:
        s := 'finally return';
    TranslatorTreeBuilder.BLOCK_CASE:
        s := 'case';
    TranslatorTreeBuilder.BLOCK_DEFAULT:
        s := 'default';
    TranslatorTreeBuilder.EXPR_VALUE_NULL:
        s := 'null';
    TranslatorTreeBuilder.EXPR_VALUE_BOOLEAN:
        s := 'boolean value';
    TranslatorTreeBuilder.EXPR_VALUE_INT:
        s := 'int value';
    TranslatorTreeBuilder.EXPR_VALUE_LONG:
        s := 'long value';
    TranslatorTreeBuilder.EXPR_VALUE_ULTRA:
        s := 'ultra value';
    TranslatorTreeBuilder.EXPR_VALUE_REAL:
        s := 'real value';
    TranslatorTreeBuilder.EXPR_VALUE_XVECTOR:
        s := 'xvector value';
    TranslatorTreeBuilder.EXPR_VALUE_STRING:
        s := 'char[] value';
    TranslatorTreeBuilder.EXPR_LOCAL_VARIABLE:
        s := 'local var';
    TranslatorTreeBuilder.EXPR_GLOBAL_VARIABLE:
        s := 'global var';
    TranslatorTreeBuilder.EXPR_GLOBAL_FUNCTION:
        s := 'global function';
    TranslatorTreeBuilder.EXPR_NEW_STRUCT:
        s := 'new struct';
    TranslatorTreeBuilder.EXPR_NEW_ARRAY_BY_ELEMENTS:
        s := 'new array[] {…}';
    TranslatorTreeBuilder.EXPR_NEW_ARRAY_BY_LENGTH:
        s := 'new array[…]';
    TranslatorTreeBuilder.EXPR_NEW_ULTRA:
        s := 'new ultra';
    TranslatorTreeBuilder.EXPR_NEW_XVECTOR:
        s := 'new xvector';
    TranslatorTreeBuilder.EXPR_FIELD_ASSIGN:
        s := 'field=';
    TranslatorTreeBuilder.EXPR_ARRAY_ASSIGN:
        s := '[' + intToString(getIndex()) + ']=';
    TranslatorTreeBuilder.EXPR_CALL:
        s := 'f(x)';
    TranslatorTreeBuilder.EXPR_ARRAY:
        s := 'a[i]';
    TranslatorTreeBuilder.EXPR_COMPOUND:
        s := 'с[i]';
    TranslatorTreeBuilder.EXPR_FIELD:
        s := '.field';
    TranslatorTreeBuilder.EXPR_INCR_POST:
        s := 'x++';
    TranslatorTreeBuilder.EXPR_DECR_POST:
        s := 'x--';
    TranslatorTreeBuilder.EXPR_TYPE_CAST:
        s := 'type cast';
    TranslatorTreeBuilder.EXPR_SNOTB:
        s := '~';
    TranslatorTreeBuilder.EXPR_SNOTL:
        s := '!';
    TranslatorTreeBuilder.EXPR_SNEG:
        s := '-x';
    TranslatorTreeBuilder.EXPR_INCR_PRED:
        s := '++x';
    TranslatorTreeBuilder.EXPR_DECR_PRED:
        s := '--x';
    TranslatorTreeBuilder.EXPR_QPACKUS:
        s := '@@@@';
    TranslatorTreeBuilder.EXPR_QUNPCKL:
        s := '####';
    TranslatorTreeBuilder.EXPR_QUNPCKH:
        s := '^^^^';
    TranslatorTreeBuilder.EXPR_QNEG:
        s := '----x';
    TranslatorTreeBuilder.EXPR_OPACKUS:
        s := '@@..@@';
    TranslatorTreeBuilder.EXPR_OUNPCKL:
        s := '##..##';
    TranslatorTreeBuilder.EXPR_OUNPCKH:
        s := '^^..^^';
    TranslatorTreeBuilder.EXPR_ONEG:
        s := '--..--x';
    TranslatorTreeBuilder.EXPR_SMULL:
        s := '*';
    TranslatorTreeBuilder.EXPR_SDIVS:
        s := '/';
    TranslatorTreeBuilder.EXPR_SREMS:
        s := '%';
    TranslatorTreeBuilder.EXPR_SDIVU:
        s := '//';
    TranslatorTreeBuilder.EXPR_SREMU:
        s := '%%';
    TranslatorTreeBuilder.EXPR_QMULL:
        s := '****';
    TranslatorTreeBuilder.EXPR_QMULH:
        s := '***^';
    TranslatorTreeBuilder.EXPR_QMULHS:
        s := '***|';
    TranslatorTreeBuilder.EXPR_QDIV:
        s := '////';
    TranslatorTreeBuilder.EXPR_OMULL:
        s := '**..**';
    TranslatorTreeBuilder.EXPR_OMULH:
        s := '**..*^';
    TranslatorTreeBuilder.EXPR_OMULHS:
        s := '**..*|';
    TranslatorTreeBuilder.EXPR_SADD:
        s := '+';
    TranslatorTreeBuilder.EXPR_SSUB:
        s := '-';
    TranslatorTreeBuilder.EXPR_QADD:
        s := '++++';
    TranslatorTreeBuilder.EXPR_QADDS:
        s := '+++|';
    TranslatorTreeBuilder.EXPR_QADDUS:
        s := '+++#';
    TranslatorTreeBuilder.EXPR_QSUB:
        s := '----';
    TranslatorTreeBuilder.EXPR_QSUBS:
        s := '---|';
    TranslatorTreeBuilder.EXPR_QSUBUS:
        s := '---#';
    TranslatorTreeBuilder.EXPR_OADD:
        s := '++..++';
    TranslatorTreeBuilder.EXPR_OADDS:
        s := '++..+|';
    TranslatorTreeBuilder.EXPR_OADDUS:
        s := '++..+#';
    TranslatorTreeBuilder.EXPR_OSUB:
        s := '--..--';
    TranslatorTreeBuilder.EXPR_OSUBS:
        s := '--..-|';
    TranslatorTreeBuilder.EXPR_OSUBUS:
        s := '--..-#';
    TranslatorTreeBuilder.EXPR_SSLL:
        s := '<<';
    TranslatorTreeBuilder.EXPR_SSRA:
        s := '>>';
    TranslatorTreeBuilder.EXPR_SSRL:
        s := '>>>';
    TranslatorTreeBuilder.EXPR_QSLL:
        s := '<<<<';
    TranslatorTreeBuilder.EXPR_QSRA:
        s := '>>>>';
    TranslatorTreeBuilder.EXPR_QSRL:
        s := '>>>>>';
    TranslatorTreeBuilder.EXPR_OSLL:
        s := '<<..<<';
    TranslatorTreeBuilder.EXPR_OSRA:
        s := '>>..>>';
    TranslatorTreeBuilder.EXPR_OSRL:
        s := '>>..>>>';
    TranslatorTreeBuilder.EXPR_SGT:
        s := '>';
    TranslatorTreeBuilder.EXPR_SGE:
        s := '>=';
    TranslatorTreeBuilder.EXPR_SLT:
        s := '<';
    TranslatorTreeBuilder.EXPR_SLE:
        s := '<=';
    TranslatorTreeBuilder.EXPR_QGT:
        s := '>>||';
    TranslatorTreeBuilder.EXPR_QGE:
        s := '>=||';
    TranslatorTreeBuilder.EXPR_QLT:
        s := '<<||';
    TranslatorTreeBuilder.EXPR_QLE:
        s := '<=||';
    TranslatorTreeBuilder.EXPR_OGT:
        s := '>>|..|';
    TranslatorTreeBuilder.EXPR_OGE:
        s := '>=|..|';
    TranslatorTreeBuilder.EXPR_OLT:
        s := '<<|..|';
    TranslatorTreeBuilder.EXPR_OLE:
        s := '<=|..|';
    TranslatorTreeBuilder.EXPR_SEQ:
        s := '==';
    TranslatorTreeBuilder.EXPR_SNE:
        s := '!=';
    TranslatorTreeBuilder.EXPR_QEQ:
        s := '==||';
    TranslatorTreeBuilder.EXPR_QNE:
        s := '!=||';
    TranslatorTreeBuilder.EXPR_OEQ:
        s := '==|..|';
    TranslatorTreeBuilder.EXPR_ONE:
        s := '!=|..|';
    TranslatorTreeBuilder.EXPR_SANDB:
        s := '&';
    TranslatorTreeBuilder.EXPR_SXORB:
        s := '^';
    TranslatorTreeBuilder.EXPR_SORB:
        s := '|';
    TranslatorTreeBuilder.EXPR_SANDL:
        s := '&&';
    TranslatorTreeBuilder.EXPR_SORL:
        s := '||';
    TranslatorTreeBuilder.EXPR_QUESTION:
        s := '?:';
    TranslatorTreeBuilder.EXPR_SEQ_NULL:
        s := 'x == null';
    TranslatorTreeBuilder.EXPR_SNE_NULL:
        s := 'x != null';
    TranslatorTreeBuilder.EXPR_SZR_TEST:
        s := '& == 0';
    TranslatorTreeBuilder.EXPR_SNZ_TEST:
        s := '& != 0';
    TranslatorTreeBuilder.ASSIGN:
        s := '=';
    TranslatorTreeBuilder.ASSIGN_SMULL:
        s := '*=';
    TranslatorTreeBuilder.ASSIGN_SDIVS:
        s := '/=';
    TranslatorTreeBuilder.ASSIGN_SREMS:
        s := '%=';
    TranslatorTreeBuilder.ASSIGN_SDIVU:
        s := '//=';
    TranslatorTreeBuilder.ASSIGN_SREMU:
        s := '%%=';
    TranslatorTreeBuilder.ASSIGN_QMULL:
        s := '****=';
    TranslatorTreeBuilder.ASSIGN_QMULH:
        s := '***^=';
    TranslatorTreeBuilder.ASSIGN_QMULHS:
        s := '***|=';
    TranslatorTreeBuilder.ASSIGN_QDIV:
        s := '////=';
    TranslatorTreeBuilder.ASSIGN_OMULL:
        s := '**..**=';
    TranslatorTreeBuilder.ASSIGN_OMULH:
        s := '**..*^=';
    TranslatorTreeBuilder.ASSIGN_OMULHS:
        s := '**..*|=';
    TranslatorTreeBuilder.ASSIGN_SADD:
        s := '+=';
    TranslatorTreeBuilder.ASSIGN_SSUB:
        s := '-=';
    TranslatorTreeBuilder.ASSIGN_QADD:
        s := '++++=';
    TranslatorTreeBuilder.ASSIGN_QADDS:
        s := '+++|=';
    TranslatorTreeBuilder.ASSIGN_QADDUS:
        s := '+++#=';
    TranslatorTreeBuilder.ASSIGN_QSUB:
        s := '----=';
    TranslatorTreeBuilder.ASSIGN_QSUBS:
        s := '---|=';
    TranslatorTreeBuilder.ASSIGN_QSUBUS:
        s := '---#=';
    TranslatorTreeBuilder.ASSIGN_OADD:
        s := '++..++=';
    TranslatorTreeBuilder.ASSIGN_OADDS:
        s := '++..+|=';
    TranslatorTreeBuilder.ASSIGN_OADDUS:
        s := '++..+#=';
    TranslatorTreeBuilder.ASSIGN_OSUB:
        s := '--..--=';
    TranslatorTreeBuilder.ASSIGN_OSUBS:
        s := '--..-|=';
    TranslatorTreeBuilder.ASSIGN_OSUBUS:
        s := '--..-#=';
    TranslatorTreeBuilder.ASSIGN_SSLL:
        s := '<<=';
    TranslatorTreeBuilder.ASSIGN_SSRA:
        s := '>>=';
    TranslatorTreeBuilder.ASSIGN_SSRL:
        s := '>>>=';
    TranslatorTreeBuilder.ASSIGN_QSLL:
        s := '<<<<=';
    TranslatorTreeBuilder.ASSIGN_QSRA:
        s := '>>>>=';
    TranslatorTreeBuilder.ASSIGN_QSRL:
        s := '>>>>>=';
    TranslatorTreeBuilder.ASSIGN_OSLL:
        s := '<<..<<=';
    TranslatorTreeBuilder.ASSIGN_OSRA:
        s := '>>..>>=';
    TranslatorTreeBuilder.ASSIGN_OSRL:
        s := '>>..>>>=';
    TranslatorTreeBuilder.ASSIGN_QGT:
        s := '>>||=';
    TranslatorTreeBuilder.ASSIGN_QGE:
        s := '>=||=';
    TranslatorTreeBuilder.ASSIGN_QLT:
        s := '<<||=';
    TranslatorTreeBuilder.ASSIGN_QLE:
        s := '<=||=';
    TranslatorTreeBuilder.ASSIGN_OGT:
        s := '>>|..|=';
    TranslatorTreeBuilder.ASSIGN_OGE:
        s := '>=|..|=';
    TranslatorTreeBuilder.ASSIGN_OLT:
        s := '<<|..|=';
    TranslatorTreeBuilder.ASSIGN_OLE:
        s := '<=|..|=';
    TranslatorTreeBuilder.ASSIGN_QEQ:
        s := '==||=';
    TranslatorTreeBuilder.ASSIGN_QNE:
        s := '!=||=';
    TranslatorTreeBuilder.ASSIGN_OEQ:
        s := '==|..|=';
    TranslatorTreeBuilder.ASSIGN_ONE:
        s := '!=|..|=';
    TranslatorTreeBuilder.ASSIGN_SANDB:
        s := '&=';
    TranslatorTreeBuilder.ASSIGN_SXORB:
        s := '^=';
    TranslatorTreeBuilder.ASSIGN_SORB:
        s := '|=';
    TranslatorTreeBuilder.JUMP:
        s := 'jump';
    TranslatorTreeBuilder.TF_JUMP:
        s := 'jump finally';
    else
        s := '<unknown>';
    end;
    if length(labelName) > 0 then begin
        stream.write(stringToByteArray(#$20 + stringToUTF8(labelName) + ': ' + s));
    end else begin
        stream.write(stringToByteArray(#$20 + s));
    end;
    if (dataType <> nil) or (associate <> nil) then begin
        stream.write(stringToByteArray(' (type='));
        if dataType <> nil then begin
            kind := dataType.kind;
            s := dataType.toString();
        end else begin
            kind := -1;
            s := 'null';
        end;
        stream.write(stringToByteArray(s + ', asoc='));
        if associate <> nil then begin
            s := '(' + (associate as TObject).getClass().getSimpleName() + ') ';
            if associate is BuilderNode then begin
                node := associate as BuilderNode;
                compiledLabelNumber := node.labelNumber;
                assignedLabelNumber := node.assignedLabelNumber;
                if compiledLabelNumber >= 0 then begin
                    s := s + 'C' + intToString(compiledLabelNumber) + #$20;
                end;
                if assignedLabelNumber >= 0 then begin
                    s := s + '.L.' + intToString(assignedLabelNumber);
                end else begin
                    s := s + '$' + intToHexString(node.getHashCode());
                end;
            end else
            if (kind = TranslatorType.KIND_BOOLEAN) and (associate is BooleanAsObject) then begin
                if (associate as BooleanAsObject).booleanValue() = true then begin
                    s := s + 'true';
                end else begin
                    s := s + 'false';
                end;
            end else
            if ((kind = TranslatorType.KIND_CHAR) or (kind = TranslatorType.KIND_BYTE) or
                    (kind = TranslatorType.KIND_SHORT) or (kind = TranslatorType.KIND_INT)) and
                    (associate is IntegerAsObject) then begin
                ival := (associate as IntegerAsObject).intValue();
                s := s + intToString(ival) + ' [' + intToHexString(ival) + ']';
            end else
            if (kind = TranslatorType.KIND_LONG) and (associate is LongAsObject) then begin
                lval := (associate as LongAsObject).longValue();
                s := s + longToString(lval) + 'L [' + longToHexString(lval) + ']';
            end else
            if (kind = TranslatorType.KIND_ULTRA) and (associate is UltraAsObject) then begin
                uval := (associate as UltraAsObject).ultraValue();
                s := s + 'new ultra { ' +
                        intToString(uval.ints[0]) + ', ' + intToString(uval.ints[1]) + ', ' +
                        intToString(uval.ints[2]) + ', ' + intToString(uval.ints[3]) + ' } [' +
                        intToHexString(uval.ints[3]) + #$20 + intToHexString(uval.ints[2]) + #$20 +
                        intToHexString(uval.ints[1]) + #$20 + intToHexString(uval.ints[0]) + ']';
            end else
            if (kind = TranslatorType.KIND_FLOAT) and (associate is FloatAsObject) then begin
                rval := (associate as FloatAsObject).floatValue();
                with RealValueRepresenter.create(RealValueRepresenter.FLOAT_SIGNIFICAND_DIGITS,
                        RealValueRepresenter.FLOAT_ORDER_DIGITS) do begin
                    try
                        s := s + toString(rval) + 'F [' +
                                intToHexString(floatToIntBits(rval)) + ']';
                    finally
                        free();
                    end;
                end;
            end else
            if (kind = TranslatorType.KIND_DOUBLE) and (associate is DoubleAsObject) then begin
                rval := (associate as DoubleAsObject).doubleValue();
                with RealValueRepresenter.create(RealValueRepresenter.DOUBLE_SIGNIFICAND_DIGITS,
                        RealValueRepresenter.DOUBLE_ORDER_DIGITS) do begin
                    try
                        s := s + toString(rval) + 'D [' +
                                longToHexString(doubleToLongBits(rval)) + ']';
                    finally
                        free();
                    end;
                end;
            end else
            if (kind = TranslatorType.KIND_REAL) and (associate is RealAsObject) then begin
                rval := (associate as RealAsObject).realValue();
                s := s + realToString(rval) + 'R [' +
                        shortToHexString(realExtractExponent(rval)) + #$20 +
                        longToHexString(realExtractSignificand(rval)) + ']';
            end else
            if (kind = TranslatorType.KIND_XVECTOR) and (associate is XVectorAsObject) then begin
                xval := (associate as XVectorAsObject).xvectorValue();
                with RealValueRepresenter.create(RealValueRepresenter.FLOAT_SIGNIFICAND_DIGITS,
                        RealValueRepresenter.FLOAT_ORDER_DIGITS) do begin
                    try
                        s := s + 'new xvector { ' +
                                toString(xval.floats[0]) + 'F, ' +
                                toString(xval.floats[1]) + 'F, ' +
                                toString(xval.floats[2]) + 'F, ' +
                                toString(xval.floats[3]) + 'F } [' +
                                intToHexString(floatToIntBits(xval.floats[3])) + #$20 +
                                intToHexString(floatToIntBits(xval.floats[2])) + #$20 +
                                intToHexString(floatToIntBits(xval.floats[1])) + #$20 +
                                intToHexString(floatToIntBits(xval.floats[0])) + ']';
                    finally
                        free();
                    end;
                end;
            end else
            if (kind = TranslatorType.KIND_ARRAY) and
                    (associate is UnicodeStringAsObject) then begin
                s := s + '"' + stringToUTF8(
                        (associate as UnicodeStringAsObject).unicodeStringValue()) + '"';
            end else begin
                s := s + associate.toString();
            end;
        end else begin
            s := 'null';
        end;
        stream.write(stringToByteArray(s + ')'));
    end;
    if (goIfTrueToNode <> nil) or (goIfFalseToNode <> nil) then begin
        stream.write(stringToByteArray(' (ifTrue→'));
        if goIfTrueToNode <> nil then begin
            node := goIfTrueToNode as BuilderNode;
            compiledLabelNumber := node.labelNumber;
            assignedLabelNumber := node.assignedLabelNumber;
            if compiledLabelNumber >= 0 then begin
                s := 'C' + intToString(compiledLabelNumber) + #$20;
            end else begin
                s := '';
            end;
            if assignedLabelNumber >= 0 then begin
                s := s + '.L.' + intToString(assignedLabelNumber);
            end else begin
                s := s + '$' + intToHexString(node.getHashCode());
            end;
        end else begin
            s := 'null';
        end;
        stream.write(stringToByteArray(s + ', ifFalse→'));
        if goIfFalseToNode <> nil then begin
            node := goIfFalseToNode as BuilderNode;
            compiledLabelNumber := node.labelNumber;
            assignedLabelNumber := node.assignedLabelNumber;
            if compiledLabelNumber >= 0 then begin
                s := 'C' + intToString(compiledLabelNumber) + #$20;
            end else begin
                s := '';
            end;
            if assignedLabelNumber >= 0 then begin
                s := s + '.L.' + intToString(assignedLabelNumber);
            end else begin
                s := s + '$' + intToHexString(node.getHashCode());
            end;
        end else begin
            s := 'null';
        end;
        stream.write(stringToByteArray(s + ')'));
    end else
    if goAlwaysToNode <> nil then begin
        stream.write(stringToByteArray(' (always→'));
        node := goAlwaysToNode as BuilderNode;
        compiledLabelNumber := node.labelNumber;
        assignedLabelNumber := node.assignedLabelNumber;
        if compiledLabelNumber >= 0 then begin
            s := 'C' + intToString(compiledLabelNumber) + #$20;
        end else begin
            s := '';
        end;
        if assignedLabelNumber >= 0 then begin
            s := s + '.L.' + intToString(assignedLabelNumber);
        end else begin
            s := s + '$' + intToHexString(node.getHashCode());
        end;
        stream.write(stringToByteArray(s + ')'));
    end;
    result := stream.toString();
end;

procedure TranslatorBuilderNode.clearData();
begin
    inherited clearData();
    optimized := false;
    assignedLabelNumber := -1;
    labelName := '';
end;

procedure TranslatorBuilderNode.setOptimized(optimized: boolean);
begin
    self.optimized := optimized;
end;

procedure TranslatorBuilderNode.setAssignedLabelNumber(assignedLabelNumber: int);
begin
    self.assignedLabelNumber := assignedLabelNumber;
end;

procedure TranslatorBuilderNode.setLabelName(const labelName: UnicodeString);
begin
    self.labelName := labelName;
end;

function TranslatorBuilderNode.isOptimized(): boolean;
begin
    result := optimized;
end;

function TranslatorBuilderNode.getAssignedLabelNumber(): int;
begin
    result := assignedLabelNumber;
end;

function TranslatorBuilderNode.getLabelName(): UnicodeString;
begin
    result := labelName;
end;

{ TranslatorTreeBuilder }

class function TranslatorTreeBuilder.isNodeValueAssign(value: int): boolean;
begin
    case value of
    EXPR_INCR_POST, EXPR_DECR_POST, EXPR_INCR_PRED, EXPR_DECR_PRED, 600..699:
        result := true;
    else
        result := false;
    end;
end;

class function TranslatorTreeBuilder.getTypeKind(theType: TypeDescriptor): int;
begin
    if theType = nil then begin
        result := -1;
    end else begin
        result := theType.kind;
    end;
end;

class function TranslatorTreeBuilder.ultraToXVector(const value: ultra): xvector;
begin
    result := ((TranslatorLocalConstantUltra.create(nil, value)) as
            GlobalConstant).getXVectorValue();
end;

class function TranslatorTreeBuilder.xvectorToUltra(const value: xvector): ultra;
begin
    result := ((TranslatorLocalConstantXVector.create(nil, value)) as
            GlobalConstant).getUltraValue();
end;

class function TranslatorTreeBuilder.getArrayOfParents(node: Node): Node_Array1d;
var
    c: int;
    pstack: Stack;
begin
    pstack := Stack.create();
    try
        repeat
            node := node.parent as Node;
            if node = nil then begin
                break;
            end;
            pstack.push(node);
        until false;
        c := pstack.size();
        result := Node_Array1d(Interface_Array1d_create(c));
        pstack.copyInto(Interface_Array1d(result));
    finally
        pstack.free();
    end;
end;

class function TranslatorTreeBuilder.getCommonParent(node1, node2: Node): Node;
var
    i1: int;
    i2: int;
    parents1: Node_Array1d;
    parents2: Node_Array1d;
begin
    parents1 := getArrayOfParents(node1);
    parents2 := getArrayOfParents(node2);
    i1 := length(parents1) - 1;
    i2 := length(parents2) - 1;
    if (i1 < 0) or (i2 < 0) or (parents1[i1] <> parents2[i2]) then begin
        result := nil;
        exit;
    end;
    repeat
        dec(i1);
        dec(i2);
        if i1 < 0 then begin
            result := parents1[0];
            break;
        end;
        if i2 < 0 then begin
            result := parents2[0];
            break;
        end;
        if parents1[i1] <> parents2[i2] then begin
            result := parents1[i1 + 1];
            break;
        end;
    until false;
end;

class function TranslatorTreeBuilder.insertTypeCast(node: SyntaxNode;
        cast: TypeDescriptor): SyntaxNode;
begin
    result := node;
    case node.value of
    EXPR_VALUE_NULL:
        node.dataType := cast;
    EXPR_VALUE_BOOLEAN: ;
    EXPR_VALUE_INT:
        case cast.kind of
        TranslatorType.KIND_CHAR:
            node.setDataAssociate(node.position, EXPR_VALUE_INT, cast,
                    (node.associate as IntegerAsObject).intValue() and $ffff);
        TranslatorType.KIND_BYTE:
            node.setDataAssociate(node.position, EXPR_VALUE_INT, cast,
                    (node.associate as IntegerAsObject).byteValue());
        TranslatorType.KIND_SHORT:
            node.setDataAssociate(node.position, EXPR_VALUE_INT, cast,
                    (node.associate as IntegerAsObject).shortValue());
        TranslatorType.KIND_INT:
            node.setDataAssociate(node.position, EXPR_VALUE_INT, cast,
                    (node.associate as IntegerAsObject).intValue());
        TranslatorType.KIND_LONG:
            node.setDataAssociate(node.position, EXPR_VALUE_LONG, cast, int64(
                    (node.associate as IntegerAsObject).intValue()));
        TranslatorType.KIND_ULTRA:
            node.setDataAssociate(node.position, EXPR_VALUE_ULTRA, cast, ultraBuild(0,
                    (node.associate as IntegerAsObject).intValue()));
        TranslatorType.KIND_FLOAT:
            node.setDataAssociate(node.position, EXPR_VALUE_REAL, cast, realToFloat(intToReal(
                    (node.associate as IntegerAsObject).intValue())));
        TranslatorType.KIND_DOUBLE:
            node.setDataAssociate(node.position, EXPR_VALUE_REAL, cast, realToDouble(intToReal(
                    (node.associate as IntegerAsObject).intValue())));
        TranslatorType.KIND_REAL:
            node.setDataAssociate(node.position, EXPR_VALUE_REAL, cast, intToReal(
                    (node.associate as IntegerAsObject).intValue()));
        TranslatorType.KIND_XVECTOR:
            node.setDataAssociate(node.position, EXPR_VALUE_XVECTOR, cast, xvectorBuild(0, 0, 0,
                    (node.associate as IntegerAsObject).intValue()));
        end;
    EXPR_VALUE_LONG:
        case cast.kind of
        TranslatorType.KIND_CHAR:
            node.setDataAssociate(node.position, EXPR_VALUE_INT, cast,
                    (node.associate as LongAsObject).intValue() and $ffff);
        TranslatorType.KIND_BYTE:
            node.setDataAssociate(node.position, EXPR_VALUE_INT, cast,
                    (node.associate as LongAsObject).byteValue());
        TranslatorType.KIND_SHORT:
            node.setDataAssociate(node.position, EXPR_VALUE_INT, cast,
                    (node.associate as LongAsObject).shortValue());
        TranslatorType.KIND_INT:
            node.setDataAssociate(node.position, EXPR_VALUE_INT, cast,
                    (node.associate as LongAsObject).intValue());
        TranslatorType.KIND_LONG:
            node.setDataAssociate(node.position, EXPR_VALUE_LONG, cast,
                    (node.associate as LongAsObject).longValue());
        TranslatorType.KIND_ULTRA:
            node.setDataAssociate(node.position, EXPR_VALUE_ULTRA, cast, ultraBuild(0,
                    (node.associate as LongAsObject).longValue()));
        TranslatorType.KIND_FLOAT:
            node.setDataAssociate(node.position, EXPR_VALUE_REAL, cast, realToFloat(longToReal(
                    (node.associate as LongAsObject).longValue())));
        TranslatorType.KIND_DOUBLE:
            node.setDataAssociate(node.position, EXPR_VALUE_REAL, cast, realToDouble(longToReal(
                    (node.associate as LongAsObject).longValue())));
        TranslatorType.KIND_REAL:
            node.setDataAssociate(node.position, EXPR_VALUE_REAL, cast, longToReal(
                    (node.associate as LongAsObject).longValue()));
        TranslatorType.KIND_XVECTOR:
            node.setDataAssociate(node.position, EXPR_VALUE_XVECTOR, cast, xvectorBuild(0, 0, 0,
                    (node.associate as LongAsObject).longValue()));
        end;
    EXPR_VALUE_ULTRA:
        case cast.kind of
        TranslatorType.KIND_CHAR:
            node.setDataAssociate(node.position, EXPR_VALUE_INT, cast,
                    (node.associate as UltraAsObject).intValue() and $ffff);
        TranslatorType.KIND_BYTE:
            node.setDataAssociate(node.position, EXPR_VALUE_INT, cast,
                    (node.associate as UltraAsObject).byteValue());
        TranslatorType.KIND_SHORT:
            node.setDataAssociate(node.position, EXPR_VALUE_INT, cast,
                    (node.associate as UltraAsObject).shortValue());
        TranslatorType.KIND_INT:
            node.setDataAssociate(node.position, EXPR_VALUE_INT, cast,
                    (node.associate as UltraAsObject).intValue());
        TranslatorType.KIND_LONG:
            node.setDataAssociate(node.position, EXPR_VALUE_LONG, cast,
                    (node.associate as UltraAsObject).longValue());
        TranslatorType.KIND_ULTRA:
            node.setDataAssociate(node.position, EXPR_VALUE_ULTRA, cast,
                    (node.associate as UltraAsObject).ultraValue());
        TranslatorType.KIND_FLOAT:
            node.setDataAssociate(node.position, EXPR_VALUE_REAL, cast, realToFloat(longToReal(
                    (node.associate as UltraAsObject).longValue())));
        TranslatorType.KIND_DOUBLE:
            node.setDataAssociate(node.position, EXPR_VALUE_REAL, cast, realToDouble(longToReal(
                    (node.associate as UltraAsObject).longValue())));
        TranslatorType.KIND_REAL:
            node.setDataAssociate(node.position, EXPR_VALUE_REAL, cast, longToReal(
                    (node.associate as UltraAsObject).longValue()));
        TranslatorType.KIND_XVECTOR:
            node.setDataAssociate(node.position, EXPR_VALUE_XVECTOR, cast, ultraToXVector(
                    (node.associate as UltraAsObject).ultraValue()));
        end;
    EXPR_VALUE_REAL:
        case cast.kind of
        TranslatorType.KIND_CHAR:
            node.setDataAssociate(node.position, EXPR_VALUE_INT, cast,
                    (node.associate as RealAsObject).intValue() and $ffff);
        TranslatorType.KIND_BYTE:
            node.setDataAssociate(node.position, EXPR_VALUE_INT, cast,
                    (node.associate as RealAsObject).byteValue());
        TranslatorType.KIND_SHORT:
            node.setDataAssociate(node.position, EXPR_VALUE_INT, cast,
                    (node.associate as RealAsObject).shortValue());
        TranslatorType.KIND_INT:
            node.setDataAssociate(node.position, EXPR_VALUE_INT, cast,
                    (node.associate as RealAsObject).intValue());
        TranslatorType.KIND_LONG:
            node.setDataAssociate(node.position, EXPR_VALUE_LONG, cast,
                    (node.associate as RealAsObject).longValue());
        TranslatorType.KIND_ULTRA:
            node.setDataAssociate(node.position, EXPR_VALUE_ULTRA, cast, ultraBuild(0,
                    (node.associate as RealAsObject).longValue()));
        TranslatorType.KIND_FLOAT:
            node.setDataAssociate(node.position, EXPR_VALUE_REAL, cast,
                    (node.associate as RealAsObject).floatValue());
        TranslatorType.KIND_DOUBLE:
            node.setDataAssociate(node.position, EXPR_VALUE_REAL, cast,
                    (node.associate as RealAsObject).doubleValue());
        TranslatorType.KIND_REAL:
            node.setDataAssociate(node.position, EXPR_VALUE_REAL, cast,
                    (node.associate as RealAsObject).realValue());
        TranslatorType.KIND_XVECTOR:
            node.setDataAssociate(node.position, EXPR_VALUE_XVECTOR, cast, xvectorBuild(0, 0, 0,
                    (node.associate as RealAsObject).floatValue()));
        end;
    EXPR_VALUE_XVECTOR:
        case cast.kind of
        TranslatorType.KIND_CHAR:
            node.setDataAssociate(node.position, EXPR_VALUE_INT, cast,
                    (node.associate as XVectorAsObject).intValue() and $ffff);
        TranslatorType.KIND_BYTE:
            node.setDataAssociate(node.position, EXPR_VALUE_INT, cast,
                    (node.associate as XVectorAsObject).byteValue());
        TranslatorType.KIND_SHORT:
            node.setDataAssociate(node.position, EXPR_VALUE_INT, cast,
                    (node.associate as XVectorAsObject).shortValue());
        TranslatorType.KIND_INT:
            node.setDataAssociate(node.position, EXPR_VALUE_INT, cast,
                    (node.associate as XVectorAsObject).intValue());
        TranslatorType.KIND_LONG:
            node.setDataAssociate(node.position, EXPR_VALUE_LONG, cast,
                    (node.associate as XVectorAsObject).longValue());
        TranslatorType.KIND_ULTRA:
            node.setDataAssociate(node.position, EXPR_VALUE_ULTRA, cast, xvectorToUltra(
                    (node.associate as XVectorAsObject).xvectorValue()));
        TranslatorType.KIND_FLOAT:
            node.setDataAssociate(node.position, EXPR_VALUE_REAL, cast,
                    (node.associate as XVectorAsObject).floatValue());
        TranslatorType.KIND_DOUBLE:
            node.setDataAssociate(node.position, EXPR_VALUE_REAL, cast,
                    (node.associate as XVectorAsObject).doubleValue());
        TranslatorType.KIND_REAL:
            node.setDataAssociate(node.position, EXPR_VALUE_REAL, cast,
                    (node.associate as XVectorAsObject).realValue());
        TranslatorType.KIND_XVECTOR:
            node.setDataAssociate(node.position, EXPR_VALUE_XVECTOR, cast,
                    (node.associate as XVectorAsObject).xvectorValue());
        end;
    else
        if (node.dataType as TObject) <> (cast as TObject) then begin
            result := node.owner.addNodeBefore(node) as SyntaxNode;
            result.setDataAssociate(-1, EXPR_TYPE_CAST, cast, cast);
            node.setParent(result, 0);
        end;
    end;
end;

class function TranslatorTreeBuilder.getNodeWithMinLabelNumber(node, next: SyntaxNode): SyntaxNode;
begin
    result := node.getChildWithMinLabelNumber();
    if result = nil then begin
        result := next;
    end;
end;

class function TranslatorTreeBuilder.findLocalVariable(const name: UnicodeString;
        parent: SyntaxNode): LocalVariable;
var
    i: int;
    child: SyntaxNode;
    local: LocalVariable;
begin
    repeat
        for i := parent.getChildrensCount() - 1 downto 0 do begin
            child := parent.getChild(i) as SyntaxNode;
            case child.value of
            OPERATOR_VARIABLE, BLOCK_WITH: begin
                local := child.associate as LocalVariable;
                if local.name = name then begin
                    result := local;
                    exit;
                end;
            end;
            end;
        end;
        if parent.value = FUNCTION_START then begin
            result := (parent.associate as GlobalFunction).functionType.findArgument(name);
            if result <> nil then begin
                exit;
            end;
        end;
        parent := parent.parent as SyntaxNode;
    until parent = nil;
    result := nil;
end;

constructor TranslatorTreeBuilder.create(operandSize, extension: int);
var
    lengthType: TypePrimitive;
begin
    inherited create(operandSize, extension);
    if operandSize >= TranslatorType.SIZE_32_BIT then begin
        lengthType := typeInt;
    end else begin
        lengthType := typeShort;
    end;
    self.arrayLengthField := TranslatorStructureField.create(nil, 0, true, lengthType, 'length');
end;

function TranslatorTreeBuilder.buildSyntaxTree(forFunction: GlobalFunction): Tree;
var
    optimized: boolean;
    i: int;
    c: int;
    aln: int;
    position: int;
    lexemes: Lexer;
    nmsp: Namespace;
    tree: SyntaxTree;
    root: SyntaxNode;
    next: SyntaxNode;
    last: BuilderNode;
    node: BuilderNode;
    rtyp: TypeDescriptor;
begin
    { проверка возможности построения }
    if forFunction = nil then begin
        raise NullPointerException.create(msgNullPointer);
    end;
    if forFunction.isAssembler() then begin
        result := nil;
        exit;
    end;
    { инициализация переменных }
    currWithVarNum := 0;
    nmsp := forFunction.owner;
    lexemes := nmsp.lexemes;
    position := forFunction.startPosition;
    { создание дерева разбора }
    tree := TranslatorSyntaxTree.create(lexemes, TranslatorBuilderNode);
    root := tree.root as SyntaxNode;
    try
        { построение дерева разбора }
        root.setDataAssociate(position, FUNCTION_START, nil, forFunction);
        if length(nmsp.name) <= 0 then begin
            next := insertInitializations(root);
        end else begin
            next := root;
        end;
        position := parseOpBlock(lexemes, position + 1, next);
        if lexemes.getType(position) <> TranslatorLexer.CLOSED_CURLY_BRACKET then begin
            raise CompileError.create(msgExpectedClosedCurlyBracket, lexemes, position);
        end;
        last := tree.addChildLast(root) as BuilderNode;
        last.setDataAssociate(position, FUNCTION_RETURN, nil, nil);
        last.optimized := true;
        { нумерация узлов }
        tree.assignLabelNumberTo(root);
        c := root.getChildrensCount() - 2;
        for i := 0 to c do begin
            numerateNodes(root.getChild(i) as SyntaxNode);
        end;
        tree.assignLabelNumberTo(last);
        { расстановка переходов }
        next := last;
        for i := c downto 0 do begin
            next := placeJumpsInOperator(root.getChild(i) as SyntaxNode, next);
        end;
        { оптимизация переходов }
        optimizeJumps(tree, false);
        { проверка достижимости }
        repeat
            optimized := false;
            for i := tree.getNodesWithLabelNumberCount() - 1 downto 1 do begin
                node := tree.getNodeWithLabelNumber(i) as BuilderNode;
                if not isReachable(node) then begin
                    if node.optimized = false then begin
                        position := node.position;
                        if position >= 0 then begin
                            raise CompileError.create(msgDetectedUnreachableCode, lexemes,
                                    position);
                        end;
                    end;
                    node.goAlwaysToNode := nil;
                    tree.deleteLabelNumber(i);
                    optimized := true;
                end;
            end;
        until not optimized;
        { проверка обязательного возврата значения функциями }
        rtyp := forFunction.functionType.getReturnType();
        if (rtyp <> nil) and (rtyp.kind <> TranslatorType.KIND_VOID) and
                not isReturnTo(last) then begin
            position := last.position;
            raise CompileError.create(msgFunctionShouldReturnValue, lexemes, position);
        end;
        { оптимизация переходов через return }
        optimizeJumps(tree, true);
        { присвоение номеров меток }
        c := tree.getNodesWithLabelNumberCount() - 1;
        aln := 0;
        for i := 1 to c do begin
            node := tree.getNodeWithLabelNumber(i) as BuilderNode;
            if hasLinksTo(node) then begin
                node.assignedLabelNumber := aln;
                inc(aln);
            end;
        end;
    except
        tree.deleteChildrens(root);
        root.clearData();
        tree := nil;
        raise;
    end;
    result := tree;
end;

function TranslatorTreeBuilder.possibleAssign(dstType, srcType: TypeDescriptor;
        srcAsoc: _Interface): boolean;
var
    asocIsLong: boolean;
    dstTypeKind: int;
    srcTypeKind: int;
    srcAsocLong: long;
begin
    dstTypeKind := getTypeKind(dstType);
    srcTypeKind := getTypeKind(srcType);
    asocIsLong := ((
            (srcTypeKind = TranslatorType.KIND_CHAR) or
            (srcTypeKind = TranslatorType.KIND_BYTE) or
            (srcTypeKind = TranslatorType.KIND_SHORT) or
            (srcTypeKind = TranslatorType.KIND_INT)) and
            (srcAsoc is IntegerAsObject)) or ((
            (srcTypeKind = TranslatorType.KIND_LONG)) and
            (srcAsoc is LongAsObject));
    if asocIsLong then begin
        if srcTypeKind = TranslatorType.KIND_LONG then begin
            srcAsocLong := (srcAsoc as LongAsObject).longValue();
        end else begin
            srcAsocLong := (srcAsoc as IntegerAsObject).intValue();
        end;
        result := (dstType is TypePrimitive) and
                (dstType as TypePrimitive).possibleAssignLong(srcAsocLong);
    end else begin
        result := false;
    end;
    result := result or (
            (srcType <> nil) and srcType.possibleAssignTo(dstType)) or (
            (srcType = nil) and (
            (dstTypeKind = TranslatorType.KIND_STRUCT) or
            (dstTypeKind = TranslatorType.KIND_ARRAY) or
            (dstTypeKind = TranslatorType.KIND_FUNC)));
end;

function TranslatorTreeBuilder.parseExprPost(lexemes: Lexer; position: int;
        parent, child: SyntaxNode): int;
var
    i: int;
    count: int;
    index: int;
    typeKind: int;
    typeResu: TypeDescriptor;
    typeArgu: TypeDescriptor;
    typeArra: TypeArray;
    typeFunc: TypeFunction;
    typeStru: TypeStructure;
    fildAsoc: StructureField;
    nodeOper: SyntaxNode;
    nodeArgu: SyntaxNode;
    nodeAsoc: _Interface;
    readNode: SyntaxNode;
    readAsoc: _Interface;
    where: Namespace;
    owner: Tree;
    ident: UnicodeString;
begin
    nodeArgu := child;
    typeResu := nodeArgu.dataType;
    owner := parent.owner;
    where := ((owner.root as SyntaxNode).associate as GlobalFunction).owner;
    repeat
        typeKind := getTypeKind(typeResu);
        case lexemes.getType(position) of
        TranslatorLexer.OPENED_SQUARE_BRACKET: begin
            case typeKind of
            TranslatorType.KIND_ARRAY: begin
                typeArra := typeResu as TypeArray;
                typeResu := typeArra.elementType;
                nodeOper := owner.addNodeBefore(nodeArgu) as SyntaxNode;
                nodeOper.setDataAssociate(position, EXPR_ARRAY, typeResu, nil);
                nodeArgu.setParent(nodeOper, 0);
                position := parseExprAssign(lexemes, position + 1, nodeOper);
                readNode := nodeOper.getChild(1) as SyntaxNode;
                if not possibleAssign(typeInt, readNode.dataType, readNode.associate) then begin
                    if operandSize < TranslatorType.SIZE_32_BIT then begin
                        raise CompileError.create(msgTypeMustBeShort, lexemes, position);
                    end else begin
                        raise CompileError.create(msgTypeMustBeInt, lexemes, position);
                    end;
                end;
                if operandSize < TranslatorType.SIZE_32_BIT then begin
                    insertTypeCast(readNode, typeShort);
                end else begin
                    insertTypeCast(readNode, typeInt);
                end;
            end;
            TranslatorType.KIND_ULTRA: begin
                typeResu := typeInt;
                nodeOper := owner.addNodeBefore(nodeArgu) as SyntaxNode;
                nodeOper.setDataAssociate(position, EXPR_COMPOUND, typeResu, nil);
                nodeArgu.setParent(nodeOper, 0);
                position := parseExprAssign(lexemes, position + 1, nodeOper);
                readNode := nodeOper.getChild(1) as SyntaxNode;
                if not possibleAssign(typeInt, readNode.dataType, readNode.associate) then begin
                    raise CompileError.create(msgTypeMustBeInt, lexemes, position);
                end;
                readNode := insertTypeCast(readNode, typeInt);
                readAsoc := readNode.associate;
                if (readNode.value = EXPR_VALUE_INT) and (readAsoc is IntegerAsObject) then begin
                    index := (readAsoc as IntegerAsObject).intValue();
                    if (index < 0) or (index > 3) then begin
                        raise CompileError.create(msgCompoundIndexOutOfBounds, lexemes, position);
                    end;
                    nodeAsoc := nodeArgu.associate;
                    if (nodeArgu.value = EXPR_VALUE_ULTRA) and
                            (nodeAsoc is UltraAsObject) then begin
                        nodeOper.setDataAssociate(nodeOper.position, EXPR_VALUE_INT, typeResu,
                                (nodeAsoc as UltraAsObject).getInt(index));
                        owner.deleteChildrens(nodeOper);
                    end;
                end;
            end;
            TranslatorType.KIND_XVECTOR: begin
                typeResu := typeFloat;
                nodeOper := owner.addNodeBefore(nodeArgu) as SyntaxNode;
                nodeOper.setDataAssociate(position, EXPR_COMPOUND, typeResu, nil);
                nodeArgu.setParent(nodeOper, 0);
                position := parseExprAssign(lexemes, position + 1, nodeOper);
                readNode := nodeOper.getChild(1) as SyntaxNode;
                if not possibleAssign(typeInt, readNode.dataType, readNode.associate) then begin
                    raise CompileError.create(msgTypeMustBeInt, lexemes, position);
                end;
                readNode := insertTypeCast(readNode, typeInt);
                readAsoc := readNode.associate;
                if (readNode.value = EXPR_VALUE_INT) and (readAsoc is IntegerAsObject) then begin
                    index := (readAsoc as IntegerAsObject).intValue();
                    if (index < 0) or (index > 3) then begin
                        raise CompileError.create(msgCompoundIndexOutOfBounds, lexemes, position);
                    end;
                    nodeAsoc := nodeArgu.associate;
                    if (nodeArgu.value = EXPR_VALUE_XVECTOR) and
                            (nodeAsoc is XVectorAsObject) then begin
                        nodeOper.setDataAssociate(nodeOper.position, EXPR_VALUE_REAL, typeResu,
                                (nodeAsoc as XVectorAsObject).getFloat(index));
                        owner.deleteChildrens(nodeOper);
                    end;
                end;
            end;
            else
                raise CompileError.create(msgTypeMustBeArray, lexemes, position);
            end;
            if lexemes.getType(position) <> TranslatorLexer.CLOSED_SQUARE_BRACKET then begin
                raise CompileError.create(msgExpectedClosedSquareBracket, lexemes, position);
            end;
        end;
        TranslatorLexer.OPENED_PARENTHESIS: begin
            if typeKind <> TranslatorType.KIND_FUNC then begin
                raise CompileError.create(msgTypeMustBeFunction, lexemes, position);
            end;
            typeFunc := typeResu as TypeFunction;
            typeResu := typeFunc.getReturnType();
            nodeOper := owner.addNodeBefore(nodeArgu) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_CALL, typeResu, nil);
            count := typeFunc.getArgumentsCount() - 1;
            inc(position);
            for i := 0 to count do begin
                typeArgu := typeFunc.getArgument(i).dataType;
                position := parseExprAssign(lexemes, position, nodeOper);
                readNode := nodeOper.getChild(i) as SyntaxNode;
                if not possibleAssign(typeArgu, readNode.dataType, readNode.associate) then begin
                    raise CompileError.create(msgCannotAssignDataType, lexemes, position);
                end;
                insertTypeCast(readNode, typeArgu);
                if i < count then begin
                    if lexemes.getType(position) <> TranslatorLexer.COMMA then begin
                        raise CompileError.create(msgExpectedComma, lexemes, position);
                    end;
                    inc(position);
                end;
            end;
            nodeArgu.setParent(nodeOper, count + 1);
            if lexemes.getType(position) <> TranslatorLexer.CLOSED_PARENTHESIS then begin
                raise CompileError.create(msgExpectedClosedParenthesis, lexemes, position);
            end;
        end;
        TranslatorLexer.PERIOD: begin
            case typeKind of
            TranslatorType.KIND_STRUCT: begin
                inc(position);
                if lexemes.getType(position) <> TranslatorLexer.IDENTIFIER then begin
                    raise CompileError.create(msgExpectedIdentifierOfField, lexemes, position);
                end;
                ident := lexemes.getValueUString(position);
                typeStru := typeResu as TypeStructure;
                fildAsoc := typeStru.findField(ident, true);
                if (fildAsoc = nil) or not where.isVisible(fildAsoc) then begin
                    raise CompileError.create(msgExpectedIdentifierOfField, lexemes, position);
                end;
                typeResu := fildAsoc.dataType;
                nodeOper := owner.addNodeBefore(nodeArgu) as SyntaxNode;
                nodeOper.setDataAssociate(position, EXPR_FIELD, typeResu, fildAsoc);
                nodeArgu.setParent(nodeOper, 0);
            end;
            TranslatorType.KIND_ARRAY: begin
                inc(position);
                if lexemes.getType(position) <> TranslatorLexer.IDENTIFIER then begin
                    raise CompileError.create(msgExpectedIdentifierOfField, lexemes, position);
                end;
                ident := lexemes.getValueUString(position);
                fildAsoc := arrayLengthField;
                if fildAsoc.name <> ident then begin
                    raise CompileError.create(msgExpectedIdentifierOfField, lexemes, position);
                end;
                typeResu := fildAsoc.dataType;
                nodeOper := owner.addNodeBefore(nodeArgu) as SyntaxNode;
                nodeOper.setDataAssociate(position, EXPR_FIELD, typeResu, fildAsoc);
                nodeArgu.setParent(nodeOper, 0);
            end;
            else
                raise CompileError.create(msgTypeMustBeStruct, lexemes, position);
            end;
        end;
        TranslatorLexer.INCR: begin
            case typeKind of
            TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE, TranslatorType.KIND_SHORT,
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_FLOAT,
            TranslatorType.KIND_DOUBLE, TranslatorType.KIND_REAL: ;
            else
                raise CompileError.create(msgTypeMustBeNumeric, lexemes, position);
            end;
            case nodeArgu.value of
            EXPR_LOCAL_VARIABLE, EXPR_GLOBAL_VARIABLE, EXPR_ARRAY, EXPR_FIELD: ;
            else
                raise CompileError.create(msgOperationApplicableOnlyToVar, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArgu) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_INCR_POST, typeResu, nil);
            nodeArgu.setParent(nodeOper, 0);
        end;
        TranslatorLexer.DECR: begin
            case typeKind of
            TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE, TranslatorType.KIND_SHORT,
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_FLOAT,
            TranslatorType.KIND_DOUBLE, TranslatorType.KIND_REAL: ;
            else
                raise CompileError.create(msgTypeMustBeNumeric, lexemes, position);
            end;
            case nodeArgu.value of
            EXPR_LOCAL_VARIABLE, EXPR_GLOBAL_VARIABLE, EXPR_ARRAY, EXPR_FIELD: ;
            else
                raise CompileError.create(msgOperationApplicableOnlyToVar, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArgu) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_DECR_POST, typeResu, nil);
            nodeArgu.setParent(nodeOper, 0);
        end;
        else
            break;
        end;
        inc(position);
        nodeArgu := nodeOper;
    until false;
    result := position;
end;

function TranslatorTreeBuilder.parseExprNew(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
var
    i: int;
    flag: boolean;
    newPosition: int;
    asgPosition: int;
    exprTypeKind: int;
    exprNode: SyntaxNode;
    exprType: TypeDescriptor;
    exprStru: TypeStructure;
    fildNode: SyntaxNode;
    fildType: TypeDescriptor;
    fildAsoc: StructureField;
    readNode: SyntaxNode;
    where: Namespace;
    owner: Tree;
    ident: UnicodeString;
begin
    owner := parent.owner;
    newPosition := position;
    inc(position);
    where := ((owner.root as SyntaxNode).associate as GlobalFunction).owner;
    exprType := tryParseType(where, position);
    if exprType = nil then begin
        raise CompileError.create(msgExpectedDataType, lexemes, position);
    end;
    position := stayPosition;
    exprTypeKind := exprType.kind;
    if lexemes.getType(position) = TranslatorLexer.OPENED_SQUARE_BRACKET then begin
        if exprTypeKind = TranslatorType.KIND_ARRAY then begin
            raise CompileError.create(msgLengthMustInFirstSquareBrackets, lexemes, position);
        end;
        if not exprType.isMatchForVariable() then begin
            raise CompileError.create(msgTypeNotApplicableToVar, lexemes, position);
        end;
        exprNode := owner.addChildLast(parent) as SyntaxNode;
        exprNode.setDataAssociate(newPosition, EXPR_NEW_ARRAY_BY_LENGTH, nil, nil);
        position := parseExprAssign(lexemes, position + 1, exprNode);
        readNode := exprNode.getChild(0) as SyntaxNode;
        if not possibleAssign(typeInt, readNode.dataType, readNode.associate) then begin
            if operandSize < TranslatorType.SIZE_32_BIT then begin
                raise CompileError.create(msgTypeMustBeShort, lexemes, position);
            end else begin
                raise CompileError.create(msgTypeMustBeInt, lexemes, position);
            end;
        end;
        if operandSize < TranslatorType.SIZE_32_BIT then begin
            insertTypeCast(readNode, typeShort);
        end else begin
            insertTypeCast(readNode, typeInt);
        end;
        repeat
            if lexemes.getType(position) <> TranslatorLexer.CLOSED_SQUARE_BRACKET then begin
                raise CompileError.create(msgExpectedClosedSquareBracket, lexemes, position);
            end;
            inc(position);
            exprType := getCanonicalType(TranslatorTypeArray.create(operandSize, exprType));
            if lexemes.getType(position) <> TranslatorLexer.OPENED_SQUARE_BRACKET then begin
                break;
            end;
            inc(position);
        until false;
        exprNode.dataType := exprType;
        result := position;
        exit;
    end;
    case exprTypeKind of
    TranslatorType.KIND_ARRAY: begin
        if lexemes.getType(position) <> TranslatorLexer.OPENED_CURLY_BRACKET then begin
            raise CompileError.create(msgExpectedOpenedCurlyBracket, lexemes, position);
        end;
        inc(position);
        exprNode := owner.addChildLast(parent) as SyntaxNode;
        exprNode.setDataAssociate(newPosition, EXPR_NEW_ARRAY_BY_ELEMENTS, exprType, nil);
        if lexemes.getType(position) <> TranslatorLexer.CLOSED_CURLY_BRACKET then begin
            fildType := (exprType as TypeArray).elementType;
            i := 0;
            repeat
                fildNode := owner.addChildLast(exprNode) as SyntaxNode;
                fildNode.setDataAssociate(-1, EXPR_ARRAY_ASSIGN, fildType, nil);
                position := parseExprAssign(lexemes, position, fildNode);
                readNode := fildNode.getChild(0) as SyntaxNode;
                if not possibleAssign(fildType, readNode.dataType, readNode.associate) then begin
                    raise CompileError.create(msgCannotAssignDataType, lexemes, position);
                end;
                insertTypeCast(readNode, fildType);
                if lexemes.getType(position) <> TranslatorLexer.COMMA then begin
                    break;
                end;
                inc(position);
                inc(i);
            until false;
            if lexemes.getType(position) <> TranslatorLexer.CLOSED_CURLY_BRACKET then begin
                raise CompileError.create(msgExpectedClosedCurlyBracket, lexemes, position);
            end;
        end;
        inc(position);
    end;
    TranslatorType.KIND_STRUCT: begin
        exprNode := owner.addChildLast(parent) as SyntaxNode;
        exprNode.setDataAssociate(newPosition, EXPR_NEW_STRUCT, exprType, nil);
        if lexemes.getType(position) = TranslatorLexer.OPENED_CURLY_BRACKET then begin
            inc(position);
            exprStru := exprType as TypeStructure;
            if lexemes.getType(position) = TranslatorLexer.IDENTIFIER then repeat
                ident := lexemes.getValueUString(position);
                fildAsoc := exprStru.findField(ident, true);
                if (fildAsoc = nil) or not where.isVisible(fildAsoc) then begin
                    raise CompileError.create(msgExpectedIdentifierOfField, lexemes, position);
                end;
                fildType := fildAsoc.dataType;
                fildNode := owner.addChildLast(exprNode) as SyntaxNode;
                fildNode.setDataAssociate(position, EXPR_FIELD_ASSIGN, fildType, fildAsoc);
                inc(position);
                if lexemes.getType(position) <> TranslatorLexer.ASSIGN then begin
                    raise CompileError.create(msgExpectedAssign, lexemes, position);
                end;
                asgPosition := position;
                position := parseExprAssign(lexemes, position + 1, fildNode);
                readNode := fildNode.getChild(0) as SyntaxNode;
                if not possibleAssign(fildType, readNode.dataType, readNode.associate) then begin
                    raise CompileError.create(msgCannotAssignDataType, lexemes, asgPosition);
                end;
                insertTypeCast(readNode, fildType);
                if lexemes.getType(position) <> TranslatorLexer.COMMA then begin
                    break;
                end;
                inc(position);
                if lexemes.getType(position) <> TranslatorLexer.IDENTIFIER then begin
                    raise CompileError.create(msgExpectedIdentifierOfField, lexemes, position);
                end;
            until false;
            if lexemes.getType(position) <> TranslatorLexer.CLOSED_CURLY_BRACKET then begin
                raise CompileError.create(msgExpectedClosedCurlyBracket, lexemes, position);
            end;
            inc(position);
        end;
    end;
    TranslatorType.KIND_ULTRA: begin
        if operandSize < TranslatorType.SIZE_64_BIT then begin
            raise CompileError.create(msgTypeNotSupported, lexemes, position);
        end;
        if lexemes.getType(position) <> TranslatorLexer.OPENED_CURLY_BRACKET then begin
            raise CompileError.create(msgExpectedOpenedCurlyBracket, lexemes, position);
        end;
        inc(position);
        exprNode := owner.addChildLast(parent) as SyntaxNode;
        exprNode.setDataAssociate(newPosition, EXPR_NEW_ULTRA, exprType, nil);
        flag := true;
        for i := 0 to 3 do begin
            position := parseExprAssign(lexemes, position, exprNode);
            readNode := exprNode.getChild(i) as SyntaxNode;
            if not possibleAssign(typeInt, readNode.dataType, readNode.associate) then begin
                raise CompileError.create(msgTypeMustBeInt, lexemes, position);
            end;
            readNode := insertTypeCast(readNode, typeInt);
            if (readNode.value <> EXPR_VALUE_INT) or
                    not (readNode.associate is IntegerAsObject) then begin
                flag := false;
            end;
            if i < 3 then begin
                if lexemes.getType(position) <> TranslatorLexer.COMMA then begin
                    raise CompileError.create(msgExpectedComma, lexemes, position);
                end;
                inc(position);
            end;
        end;
        if lexemes.getType(position) <> TranslatorLexer.CLOSED_CURLY_BRACKET then begin
            raise CompileError.create(msgExpectedClosedCurlyBracket, lexemes, position);
        end;
        inc(position);
        if flag = true then begin
            exprNode.setDataAssociate(newPosition, EXPR_VALUE_ULTRA, exprType, ultraBuild(
                    ((exprNode.getChild(3) as SyntaxNode).associate as IntegerAsObject).intValue(),
                    ((exprNode.getChild(2) as SyntaxNode).associate as IntegerAsObject).intValue(),
                    ((exprNode.getChild(1) as SyntaxNode).associate as IntegerAsObject).intValue(),
                    ((exprNode.getChild(0) as SyntaxNode).associate as IntegerAsObject).intValue()
            ));
            owner.deleteChildrens(exprNode);
        end;
    end;
    TranslatorType.KIND_XVECTOR: begin
        if operandSize < TranslatorType.SIZE_64_BIT then begin
            raise CompileError.create(msgTypeNotSupported, lexemes, position);
        end;
        if lexemes.getType(position) <> TranslatorLexer.OPENED_CURLY_BRACKET then begin
            raise CompileError.create(msgExpectedOpenedCurlyBracket, lexemes, position);
        end;
        inc(position);
        exprNode := owner.addChildLast(parent) as SyntaxNode;
        exprNode.setDataAssociate(newPosition, EXPR_NEW_XVECTOR, exprType, nil);
        flag := true;
        for i := 0 to 3 do begin
            position := parseExprAssign(lexemes, position, exprNode);
            readNode := exprNode.getChild(i) as SyntaxNode;
            if not possibleAssign(typeFloat, readNode.dataType, readNode.associate) then begin
                raise CompileError.create(msgTypeMustBeFloat, lexemes, position);
            end;
            readNode := insertTypeCast(readNode, typeFloat);
            if (readNode.value <> EXPR_VALUE_REAL) or
                    not (readNode.associate is FloatAsObject) then begin
                flag := false;
            end;
            if i < 3 then begin
                if lexemes.getType(position) <> TranslatorLexer.COMMA then begin
                    raise CompileError.create(msgExpectedComma, lexemes, position);
                end;
                inc(position);
            end;
        end;
        if lexemes.getType(position) <> TranslatorLexer.CLOSED_CURLY_BRACKET then begin
            raise CompileError.create(msgExpectedClosedCurlyBracket, lexemes, position);
        end;
        inc(position);
        if flag = true then begin
            exprNode.setDataAssociate(newPosition, EXPR_VALUE_XVECTOR, exprType, xvectorBuild(
                    ((exprNode.getChild(3) as SyntaxNode).associate as FloatAsObject).floatValue(),
                    ((exprNode.getChild(2) as SyntaxNode).associate as FloatAsObject).floatValue(),
                    ((exprNode.getChild(1) as SyntaxNode).associate as FloatAsObject).floatValue(),
                    ((exprNode.getChild(0) as SyntaxNode).associate as FloatAsObject).floatValue()
            ));
            owner.deleteChildrens(exprNode);
        end;
    end;
    else
        raise CompileError.create(msgTypeMustBeArray, lexemes, position);
    end;
    result := position;
end;

function TranslatorTreeBuilder.parseExprElem(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
var
    value: int;
    child: SyntaxNode;
    withv: SyntaxNode;
    assoc: _Interface;
    local: LocalVariable;
    dtype: TypeDescriptor;
    owner: Tree;
begin
    owner := parent.owner;
    case lexemes.getType(position) of
    TranslatorLexer.OPENED_PARENTHESIS: begin
        position := parseExprAssign(lexemes, position + 1, parent);
        if lexemes.getType(position) <> TranslatorLexer.CLOSED_PARENTHESIS then begin
            raise CompileError.create(msgExpectedClosedParenthesis, lexemes, position);
        end;
        child := parent.getChild(parent.getChildrensCount() - 1) as SyntaxNode;
    end;
    TranslatorLexer.KW_NULL: begin
        child := owner.addChildLast(parent) as SyntaxNode;
        child.setDataAssociate(position, EXPR_VALUE_NULL, nil, nil);
    end;
    TranslatorLexer.KW_FALSE: begin
        child := owner.addChildLast(parent) as SyntaxNode;
        child.setDataAssociate(position, EXPR_VALUE_BOOLEAN, typeBoolean, false);
    end;
    TranslatorLexer.KW_TRUE: begin
        child := owner.addChildLast(parent) as SyntaxNode;
        child.setDataAssociate(position, EXPR_VALUE_BOOLEAN, typeBoolean, true);
    end;
    TranslatorLexer.KW_NEW: begin
        position := parseExprNew(lexemes, position, parent) - 1;
        child := parent.getChild(parent.getChildrensCount() - 1) as SyntaxNode;
    end;
    TranslatorLexer.IDENTIFIER: begin
        assoc := parseIdentifier(lexemes, position, parent);
        if assoc is GlobalConstant then begin
            child := owner.addChildLast(parent) as SyntaxNode;
            with assoc as GlobalConstant do begin
                dtype := dataType;
                case dtype.kind of
                TranslatorType.KIND_BOOLEAN:
                    child.setDataAssociate(position, EXPR_VALUE_BOOLEAN, dtype, booleanValue);
                TranslatorType.KIND_CHAR:
                    child.setDataAssociate(position, EXPR_VALUE_INT, dtype, charValue);
                TranslatorType.KIND_BYTE, TranslatorType.KIND_SHORT, TranslatorType.KIND_INT:
                    child.setDataAssociate(position, EXPR_VALUE_INT, dtype, intValue);
                TranslatorType.KIND_LONG:
                    child.setDataAssociate(position, EXPR_VALUE_LONG, dtype, longValue);
                TranslatorType.KIND_ULTRA:
                    child.setDataAssociate(position, EXPR_VALUE_ULTRA, dtype, getUltraValue());
                TranslatorType.KIND_FLOAT, TranslatorType.KIND_DOUBLE, TranslatorType.KIND_REAL:
                    child.setDataAssociate(position, EXPR_VALUE_REAL, dtype, realValue);
                TranslatorType.KIND_XVECTOR:
                    child.setDataAssociate(position, EXPR_VALUE_XVECTOR, dtype, getXVectorValue());
                end;
            end;
        end else
        if assoc is GlobalVariable then begin
            child := owner.addChildLast(parent) as SyntaxNode;
            child.setDataAssociate(position, EXPR_GLOBAL_VARIABLE,
                    (assoc as GlobalVariable).dataType, assoc);
        end else
        if assoc is GlobalFunction then begin
            child := owner.addChildLast(parent) as SyntaxNode;
            if not (assoc as GlobalFunction).isInterrupt() then begin
                child.setDataAssociate(position, EXPR_GLOBAL_FUNCTION, getCanonicalType(
                        (assoc as GlobalFunction).functionType), assoc);
            end else begin
                case operandSize of
                TranslatorType.SIZE_16_BIT:
                    child.setDataAssociate(position, EXPR_GLOBAL_FUNCTION, typeShort, assoc);
                TranslatorType.SIZE_32_BIT:
                    child.setDataAssociate(position, EXPR_GLOBAL_FUNCTION, typeInt, assoc);
                TranslatorType.SIZE_64_BIT:
                    child.setDataAssociate(position, EXPR_GLOBAL_FUNCTION, typeLong, assoc);
                end;
            end;
        end else
        if assoc is LocalVariable then begin
            child := owner.addChildLast(parent) as SyntaxNode;
            child.setDataAssociate(position, EXPR_LOCAL_VARIABLE,
                    (assoc as LocalVariable).dataType, assoc);
        end else
        if assoc is FoundObject then begin
            with assoc as FoundObject do begin
                local := foundIn;
                dtype := baseObject.dataType;
            end;
            child := owner.addChildLast(parent) as SyntaxNode;
            child.setDataAssociate(position, EXPR_FIELD, dtype, assoc);
            withv := owner.addChildLast(child) as SyntaxNode;
            withv.setDataAssociate(-1, EXPR_LOCAL_VARIABLE, local.dataType, local);
        end else begin
            raise CompileError.create(msgExpectedIdentifierOfVariable, lexemes, position);
        end;
        position := stayPosition - 1;
    end;
    TranslatorLexer.NUM_INT: begin
        value := lexemes.getValueInt(position);
        if operandSize < TranslatorType.SIZE_32_BIT then begin
            if (value < -$8000) or (value > $ffff) then begin
                raise CompileError.create(msgTypeNotSupported, lexemes, position);
            end;
            child := owner.addChildLast(parent) as SyntaxNode;
            if value < $8000 then begin
                child.setDataAssociate(position, EXPR_VALUE_INT, typeShort, value);
            end else begin
                child.setDataAssociate(position, EXPR_VALUE_INT, typeChar, value);
            end;
        end else begin
            child := owner.addChildLast(parent) as SyntaxNode;
            child.setDataAssociate(position, EXPR_VALUE_INT, typeInt, value);
        end;
    end;
    TranslatorLexer.NUM_LONG: begin
        if operandSize < TranslatorType.SIZE_64_BIT then begin
            raise CompileError.create(msgTypeNotSupported, lexemes, position);
        end;
        child := owner.addChildLast(parent) as SyntaxNode;
        child.setDataAssociate(position, EXPR_VALUE_LONG, typeLong,
                lexemes.getValueLong(position));
    end;
    TranslatorLexer.NUM_FLOAT: begin
        child := owner.addChildLast(parent) as SyntaxNode;
        child.setDataAssociate(position, EXPR_VALUE_REAL, typeFloat,
                lexemes.getValueReal(position));
    end;
    TranslatorLexer.NUM_DOUBLE: begin
        child := owner.addChildLast(parent) as SyntaxNode;
        child.setDataAssociate(position, EXPR_VALUE_REAL, typeDouble,
                lexemes.getValueReal(position));
    end;
    TranslatorLexer.NUM_REAL: begin
        child := owner.addChildLast(parent) as SyntaxNode;
        child.setDataAssociate(position, EXPR_VALUE_REAL, typeReal,
                lexemes.getValueReal(position));
    end;
    TranslatorLexer.STRING_LITERAL: begin
        child := owner.addChildLast(parent) as SyntaxNode;
        child.setDataAssociate(position, EXPR_VALUE_STRING, getCanonicalType(
                TranslatorTypeArray.create(operandSize, typeChar)),
                lexemes.getValueUString(position));
    end;
    else
        raise CompileError.create(msgExpressionError, lexemes, position);
    end;
    result := parseExprPost(lexemes, position + 1, parent, child);
end;

function TranslatorTreeBuilder.parseExprPref(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
var
    typeKind: int;
    tempPosition: int;
    currentAction: int;
    operations: Stack;
    typeResu: TypeDescriptor;
    typeCast: TypeDescriptor;
    nodeOper: SyntaxNode;
    nodeArgu: SyntaxNode;
    stackobj: _Interface;
    owner: Tree;
begin
    owner := parent.owner;
    operations := nil;
    try
        repeat
            currentAction := lexemes.getType(position);
            case currentAction of
            TranslatorLexer.SNOTB, TranslatorLexer.SNOTL,
            TranslatorLexer.SPLUS, TranslatorLexer.SMINUS,
            TranslatorLexer.INCR, TranslatorLexer.DECR,
            TranslatorLexer.QPACKUS, TranslatorLexer.QUNPCKL, TranslatorLexer.QUNPCKH,
            TranslatorLexer.QADD, TranslatorLexer.QSUB,
            TranslatorLexer.OPACKUS, TranslatorLexer.OUNPCKL, TranslatorLexer.OUNPCKH,
            TranslatorLexer.OADD, TranslatorLexer.OSUB: begin
                if operations = nil then begin
                    operations := Stack.create(2);
                end;
                operations.push(position);
                operations.push(currentAction);
            end;
            TranslatorLexer.OPENED_PARENTHESIS: begin
                typeCast := tryParseType(((owner.root as SyntaxNode).associate as
                        GlobalFunction).owner, position + 1);
                tempPosition := stayPosition;
                if (typeCast = nil) or (lexemes.getType(tempPosition) <>
                        TranslatorLexer.CLOSED_PARENTHESIS) then begin
                    break;
                end;
                if operations = nil then begin
                    operations := Stack.create(2);
                end;
                operations.push(position);
                operations.push(typeCast);
                position := tempPosition;
            end;
            else
                break;
            end;
            inc(position);
        until false;
        result := parseExprElem(lexemes, position, parent);
        if operations = nil then begin
            exit;
        end;
        nodeArgu := parent.getChild(parent.getChildrensCount() - 1) as SyntaxNode;
        typeResu := nodeArgu.dataType;
        repeat
            stackobj := operations.pop();
            position := (operations.pop() as IntegerAsObject).intValue();
            if stackobj is TypeDescriptor then begin
                typeCast := stackobj as TypeDescriptor;
                typeKind := typeCast.kind;
                if ((typeResu = nil) or not typeResu.possibleCastTo(typeCast)) and (
                        (typeResu <> nil) or (
                        (typeKind <> TranslatorType.KIND_STRUCT) and
                        (typeKind <> TranslatorType.KIND_ARRAY) and
                        (typeKind <> TranslatorType.KIND_FUNC))) then begin
                    raise CompileError.create(msgCannotCastToType, lexemes, position);
                end;
                typeResu := typeCast;
                nodeOper := insertTypeCast(nodeArgu, typeCast);
                nodeOper.position := position;
                nodeArgu := nodeOper;
                continue;
            end;
            typeKind := getTypeKind(typeResu);
            case (stackobj as IntegerAsObject).intValue() of
            TranslatorLexer.SNOTB: begin
                currentAction := EXPR_SNOTB;
                case typeKind of
                TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE,
                TranslatorType.KIND_SHORT, TranslatorType.KIND_INT: begin
                    if operandSize < TranslatorType.SIZE_32_BIT then begin
                        typeResu := typeShort;
                        nodeArgu := insertTypeCast(nodeArgu, typeShort);
                        if nodeArgu.value = EXPR_VALUE_INT then begin
                            nodeArgu.setDataAssociate(position, EXPR_VALUE_INT, typeResu, short(
                                    (nodeArgu.associate as IntegerAsObject).shortValue() xor -1));
                            continue;
                        end;
                    end else begin
                        typeResu := typeInt;
                        nodeArgu := insertTypeCast(nodeArgu, typeInt);
                        if nodeArgu.value = EXPR_VALUE_INT then begin
                            nodeArgu.setDataAssociate(position, EXPR_VALUE_INT, typeResu,
                                    (nodeArgu.associate as IntegerAsObject).intValue() xor (-1));
                            continue;
                        end;
                    end;
                end;
                TranslatorType.KIND_LONG: begin
                    typeResu := typeLong;
                    nodeArgu := insertTypeCast(nodeArgu, typeLong);
                    if nodeArgu.value = EXPR_VALUE_LONG then begin
                        nodeArgu.setDataAssociate(position, EXPR_VALUE_LONG, typeResu,
                                (nodeArgu.associate as LongAsObject).longValue() xor (-1));
                        continue;
                    end;
                end;
                TranslatorType.KIND_ULTRA: begin
                    typeResu := typeUltra;
                    nodeArgu := insertTypeCast(nodeArgu, typeUltra);
                    if nodeArgu.value = EXPR_VALUE_ULTRA then begin
                        nodeArgu.setDataAssociate(position, EXPR_VALUE_ULTRA, typeResu,
                                (nodeArgu.associate as UltraAsObject).ultraValue() xor
                                ultraBuild(-1, -1));
                        continue;
                    end;
                end;
                else
                    raise CompileError.create(msgCannotApplyOperation, lexemes, position);
                end;
            end;
            TranslatorLexer.SNOTL: begin
                currentAction := EXPR_SNOTL;
                case typeKind of
                TranslatorType.KIND_BOOLEAN: begin
                    typeResu := typeBoolean;
                    nodeArgu := insertTypeCast(nodeArgu, typeBoolean);
                    if nodeArgu.value = EXPR_VALUE_BOOLEAN then begin
                        nodeArgu.setDataAssociate(position, EXPR_VALUE_BOOLEAN, typeResu,
                                not (nodeArgu.associate as BooleanAsObject).booleanValue());
                        continue;
                    end;
                end;
                else
                    raise CompileError.create(msgCannotApplyOperation, lexemes, position);
                end;
            end;
            TranslatorLexer.SPLUS: begin
                case typeKind of
                TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE,
                TranslatorType.KIND_SHORT, TranslatorType.KIND_INT: begin
                    if operandSize < TranslatorType.SIZE_32_BIT then begin
                        typeResu := typeShort;
                    end else begin
                        typeResu := typeInt;
                    end;
                end;
                TranslatorType.KIND_LONG: begin
                    typeResu := typeLong;
                end;
                TranslatorType.KIND_FLOAT, TranslatorType.KIND_DOUBLE,
                TranslatorType.KIND_REAL: begin
                    { typeResu := typeResu; }
                end;
                else
                    raise CompileError.create(msgCannotApplyOperation, lexemes, position);
                end;
                nodeArgu := insertTypeCast(nodeArgu, typeResu);
                continue;
            end;
            TranslatorLexer.SMINUS: begin
                currentAction := EXPR_SNEG;
                case typeKind of
                TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE,
                TranslatorType.KIND_SHORT, TranslatorType.KIND_INT: begin
                    if operandSize < TranslatorType.SIZE_32_BIT then begin
                        typeResu := typeShort;
                        nodeArgu := insertTypeCast(nodeArgu, typeShort);
                        if nodeArgu.value = EXPR_VALUE_INT then begin
                            nodeArgu.setDataAssociate(position, EXPR_VALUE_INT, typeResu, short(
                                    -(nodeArgu.associate as IntegerAsObject).shortValue()));
                            continue;
                        end;
                    end else begin
                        typeResu := typeInt;
                        nodeArgu := insertTypeCast(nodeArgu, typeInt);
                        if nodeArgu.value = EXPR_VALUE_INT then begin
                            nodeArgu.setDataAssociate(position, EXPR_VALUE_INT, typeResu,
                                    -(nodeArgu.associate as IntegerAsObject).intValue());
                            continue;
                        end;
                    end;
                end;
                TranslatorType.KIND_LONG: begin
                    typeResu := typeLong;
                    nodeArgu := insertTypeCast(nodeArgu, typeLong);
                    if nodeArgu.value = EXPR_VALUE_LONG then begin
                        nodeArgu.setDataAssociate(position, EXPR_VALUE_LONG, typeResu,
                                -(nodeArgu.associate as LongAsObject).longValue());
                        continue;
                    end;
                end;
                TranslatorType.KIND_FLOAT, TranslatorType.KIND_DOUBLE,
                TranslatorType.KIND_REAL: begin
                    { typeResu := typeResu; }
                    nodeArgu := insertTypeCast(nodeArgu, typeResu);
                    if nodeArgu.value = EXPR_VALUE_REAL then begin
                        nodeArgu.setDataAssociate(position, EXPR_VALUE_REAL, typeResu,
                                -(nodeArgu.associate as RealAsObject).realValue());
                        continue;
                    end;
                end;
                else
                    raise CompileError.create(msgCannotApplyOperation, lexemes, position);
                end;
            end;
            TranslatorLexer.INCR: begin
                case typeKind of
                TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE, TranslatorType.KIND_SHORT,
                TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_FLOAT,
                TranslatorType.KIND_DOUBLE, TranslatorType.KIND_REAL: ;
                else
                    raise CompileError.create(msgTypeMustBeNumeric, lexemes, position);
                end;
                case nodeArgu.value of
                EXPR_LOCAL_VARIABLE, EXPR_GLOBAL_VARIABLE, EXPR_ARRAY, EXPR_FIELD: ;
                else
                    raise CompileError.create(msgOperationApplicableOnlyToVar, lexemes, position);
                end;
                currentAction := EXPR_INCR_PRED;
            end;
            TranslatorLexer.DECR: begin
                case typeKind of
                TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE, TranslatorType.KIND_SHORT,
                TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_FLOAT,
                TranslatorType.KIND_DOUBLE, TranslatorType.KIND_REAL: ;
                else
                    raise CompileError.create(msgTypeMustBeNumeric, lexemes, position);
                end;
                case nodeArgu.value of
                EXPR_LOCAL_VARIABLE, EXPR_GLOBAL_VARIABLE, EXPR_ARRAY, EXPR_FIELD: ;
                else
                    raise CompileError.create(msgOperationApplicableOnlyToVar, lexemes, position);
                end;
                currentAction := EXPR_DECR_PRED;
            end;
            TranslatorLexer.QPACKUS: begin
                if operandSize < TranslatorType.SIZE_64_BIT then begin
                    raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
                end;
                currentAction := EXPR_QPACKUS;
                case typeKind of
                TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE, TranslatorType.KIND_SHORT,
                TranslatorType.KIND_INT, TranslatorType.KIND_LONG: begin
                    typeResu := typeInt;
                    nodeArgu := insertTypeCast(nodeArgu, typeLong);
                    if nodeArgu.value = EXPR_VALUE_LONG then begin
                        nodeArgu.setDataAssociate(position, EXPR_VALUE_INT, typeResu,
                                mmxPack((nodeArgu.associate as LongAsObject).longValue()));
                        continue;
                    end;
                end;
                TranslatorType.KIND_ULTRA: begin
                    if extension < EXTENSION_SSE4_1 then begin
                        raise CompileError.create(msgOperationNotSupportedEX, lexemes, position);
                    end;
                    typeResu := typeLong;
                    nodeArgu := insertTypeCast(nodeArgu, typeUltra);
                    if nodeArgu.value = EXPR_VALUE_ULTRA then begin
                        nodeArgu.setDataAssociate(position, EXPR_VALUE_LONG, typeResu,
                                pack4IntUS((nodeArgu.associate as UltraAsObject).ultraValue()));
                        continue;
                    end;
                end;
                else
                    raise CompileError.create(msgCannotApplyOperation, lexemes, position);
                end;
            end;
            TranslatorLexer.QUNPCKL: begin
                if operandSize < TranslatorType.SIZE_64_BIT then begin
                    raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
                end;
                currentAction := EXPR_QUNPCKL;
                case typeKind of
                TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE,
                TranslatorType.KIND_SHORT, TranslatorType.KIND_INT: begin
                    typeResu := typeLong;
                    nodeArgu := insertTypeCast(nodeArgu, typeInt);
                    if nodeArgu.value = EXPR_VALUE_INT then begin
                        nodeArgu.setDataAssociate(position, EXPR_VALUE_LONG, typeResu,
                                mmxUnpackLo((nodeArgu.associate as IntegerAsObject).intValue()));
                        continue;
                    end;
                end;
                TranslatorType.KIND_LONG: begin
                    typeResu := typeUltra;
                    nodeArgu := insertTypeCast(nodeArgu, typeLong);
                    if nodeArgu.value = EXPR_VALUE_LONG then begin
                        nodeArgu.setDataAssociate(position, EXPR_VALUE_ULTRA, typeResu,
                                sseiUnpackLo((nodeArgu.associate as LongAsObject).longValue()));
                        continue;
                    end;
                end;
                else
                    raise CompileError.create(msgCannotApplyOperation, lexemes, position);
                end;
            end;
            TranslatorLexer.QUNPCKH: begin
                if operandSize < TranslatorType.SIZE_64_BIT then begin
                    raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
                end;
                currentAction := EXPR_QUNPCKH;
                case typeKind of
                TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE,
                TranslatorType.KIND_SHORT, TranslatorType.KIND_INT: begin
                    typeResu := typeLong;
                    nodeArgu := insertTypeCast(nodeArgu, typeInt);
                    if nodeArgu.value = EXPR_VALUE_INT then begin
                        nodeArgu.setDataAssociate(position, EXPR_VALUE_LONG, typeResu,
                                mmxUnpackHi((nodeArgu.associate as IntegerAsObject).intValue()));
                        continue;
                    end;
                end;
                TranslatorType.KIND_LONG: begin
                    typeResu := typeUltra;
                    nodeArgu := insertTypeCast(nodeArgu, typeLong);
                    if nodeArgu.value = EXPR_VALUE_LONG then begin
                        nodeArgu.setDataAssociate(position, EXPR_VALUE_ULTRA, typeResu,
                                sseiUnpackHi((nodeArgu.associate as LongAsObject).longValue()));
                        continue;
                    end;
                end;
                else
                    raise CompileError.create(msgCannotApplyOperation, lexemes, position);
                end;
            end;
            TranslatorLexer.QADD: begin
                if operandSize < TranslatorType.SIZE_64_BIT then begin
                    raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
                end;
                case typeKind of
                TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE, TranslatorType.KIND_SHORT,
                TranslatorType.KIND_INT, TranslatorType.KIND_LONG: begin
                    typeResu := typeLong;
                end;
                TranslatorType.KIND_ULTRA: begin
                    typeResu := typeUltra;
                end;
                TranslatorType.KIND_FLOAT, TranslatorType.KIND_XVECTOR: begin
                    typeResu := typeXVector;
                end;
                else
                    raise CompileError.create(msgCannotApplyOperation, lexemes, position);
                end;
                nodeArgu := insertTypeCast(nodeArgu, typeResu);
                continue;
            end;
            TranslatorLexer.QSUB: begin
                if operandSize < TranslatorType.SIZE_64_BIT then begin
                    raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
                end;
                currentAction := EXPR_QNEG;
                case typeKind of
                TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE, TranslatorType.KIND_SHORT,
                TranslatorType.KIND_INT, TranslatorType.KIND_LONG: begin
                    typeResu := typeLong;
                    nodeArgu := insertTypeCast(nodeArgu, typeLong);
                    if nodeArgu.value = EXPR_VALUE_LONG then begin
                        nodeArgu.setDataAssociate(position, EXPR_VALUE_LONG, typeResu, mmxSub(0,
                                (nodeArgu.associate as LongAsObject).longValue()));
                        continue;
                    end;
                end;
                TranslatorType.KIND_ULTRA: begin
                    typeResu := typeUltra;
                    nodeArgu := insertTypeCast(nodeArgu, typeUltra);
                    if nodeArgu.value = EXPR_VALUE_ULTRA then begin
                        nodeArgu.setDataAssociate(position, EXPR_VALUE_ULTRA, typeResu,
                                sseiSub(ultraBuild(0, 0, 0, 0),
                                (nodeArgu.associate as UltraAsObject).ultraValue()));
                        continue;
                    end;
                end;
                TranslatorType.KIND_FLOAT, TranslatorType.KIND_XVECTOR: begin
                    typeResu := typeXVector;
                    nodeArgu := insertTypeCast(nodeArgu, typeXVector);
                    if nodeArgu.value = EXPR_VALUE_XVECTOR then begin
                        nodeArgu.setDataAssociate(position, EXPR_VALUE_XVECTOR, typeResu,
                                ssefSub(xvectorBuild(0, 0, 0, 0),
                                (nodeArgu.associate as XVectorAsObject).xvectorValue()));
                        continue;
                    end;
                end;
                else
                    raise CompileError.create(msgCannotApplyOperation, lexemes, position);
                end;
            end;
            TranslatorLexer.OPACKUS: begin
                if operandSize < TranslatorType.SIZE_64_BIT then begin
                    raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
                end;
                currentAction := EXPR_OPACKUS;
                case typeKind of
                TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE, TranslatorType.KIND_SHORT,
                TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_ULTRA: begin
                    typeResu := typeLong;
                    nodeArgu := insertTypeCast(nodeArgu, typeUltra);
                    if nodeArgu.value = EXPR_VALUE_ULTRA then begin
                        nodeArgu.setDataAssociate(position, EXPR_VALUE_LONG, typeResu,
                                ssesPack((nodeArgu.associate as UltraAsObject).ultraValue()));
                        continue;
                    end;
                end;
                else
                    raise CompileError.create(msgCannotApplyOperation, lexemes, position);
                end;
            end;
            TranslatorLexer.OUNPCKL: begin
                if operandSize < TranslatorType.SIZE_64_BIT then begin
                    raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
                end;
                currentAction := EXPR_OUNPCKL;
                case typeKind of
                TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE, TranslatorType.KIND_SHORT,
                TranslatorType.KIND_INT, TranslatorType.KIND_LONG: begin
                    typeResu := typeUltra;
                    nodeArgu := insertTypeCast(nodeArgu, typeLong);
                    if nodeArgu.value = EXPR_VALUE_LONG then begin
                        nodeArgu.setDataAssociate(position, EXPR_VALUE_ULTRA, typeResu,
                                ssesUnpackLo((nodeArgu.associate as LongAsObject).longValue()));
                        continue;
                    end;
                end;
                else
                    raise CompileError.create(msgCannotApplyOperation, lexemes, position);
                end;
            end;
            TranslatorLexer.OUNPCKH: begin
                if operandSize < TranslatorType.SIZE_64_BIT then begin
                    raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
                end;
                currentAction := EXPR_OUNPCKH;
                case typeKind of
                TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE, TranslatorType.KIND_SHORT,
                TranslatorType.KIND_INT, TranslatorType.KIND_LONG: begin
                    typeResu := typeUltra;
                    nodeArgu := insertTypeCast(nodeArgu, typeLong);
                    if nodeArgu.value = EXPR_VALUE_LONG then begin
                        nodeArgu.setDataAssociate(position, EXPR_VALUE_ULTRA, typeResu,
                                ssesUnpackHi((nodeArgu.associate as LongAsObject).longValue()));
                        continue;
                    end;
                end;
                else
                    raise CompileError.create(msgCannotApplyOperation, lexemes, position);
                end;
            end;
            TranslatorLexer.OADD: begin
                if operandSize < TranslatorType.SIZE_64_BIT then begin
                    raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
                end;
                case typeKind of
                TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE, TranslatorType.KIND_SHORT,
                TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_ULTRA: begin
                    typeResu := typeUltra;
                end;
                else
                    raise CompileError.create(msgCannotApplyOperation, lexemes, position);
                end;
                nodeArgu := insertTypeCast(nodeArgu, typeResu);
                continue;
            end;
            TranslatorLexer.OSUB: begin
                if operandSize < TranslatorType.SIZE_64_BIT then begin
                    raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
                end;
                currentAction := EXPR_ONEG;
                case typeKind of
                TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE, TranslatorType.KIND_SHORT,
                TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_ULTRA: begin
                    typeResu := typeUltra;
                    nodeArgu := insertTypeCast(nodeArgu, typeUltra);
                    if nodeArgu.value = EXPR_VALUE_ULTRA then begin
                        nodeArgu.setDataAssociate(position, EXPR_VALUE_ULTRA, typeResu,
                                ssesSub(ultraBuild(0, 0, 0, 0, 0, 0, 0, 0),
                                (nodeArgu.associate as UltraAsObject).ultraValue()));
                        continue;
                    end;
                end;
                else
                    raise CompileError.create(msgCannotApplyOperation, lexemes, position);
                end;
            end;
            end;
            nodeOper := owner.addNodeBefore(nodeArgu) as SyntaxNode;
            nodeOper.setDataAssociate(position, currentAction, typeResu, nil);
            nodeArgu.setParent(nodeOper, 0);
            nodeArgu := nodeOper;
        until operations.isEmpty();
    finally
        operations.free();
    end;
end;

function TranslatorTreeBuilder.parseExprMult(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
var
    operPosition: int;
    ival: int;
    lval: long;
    nodeOper: SyntaxNode;
    nodeArg1: SyntaxNode;
    nodeArg2: SyntaxNode;
    typeResu: TypeDescriptor;
    typeArg1: TypeDescriptor;
    typeArg2: TypeDescriptor;
    owner: Tree;
begin
    position := parseExprPref(lexemes, position, parent);
    nodeArg1 := parent.getChild(parent.getChildrensCount() - 1) as SyntaxNode;
    typeArg1 := nodeArg1.dataType;
    owner := parent.owner;
    repeat
        operPosition := position;
        case lexemes.getType(position) of
        TranslatorLexer.SMULL: begin
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_SMULL, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprPref(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_SHORT: begin
                typeResu := typeShort;
                nodeArg1 := insertTypeCast(nodeArg1, typeShort);
                nodeArg2 := insertTypeCast(nodeArg2, typeShort);
                if (nodeArg1.value = EXPR_VALUE_INT) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResu, short(
                            (nodeArg1.associate as IntegerAsObject).shortValue() *
                            (nodeArg2.associate as IntegerAsObject).shortValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_INT: begin
                typeResu := typeInt;
                nodeArg1 := insertTypeCast(nodeArg1, typeInt);
                nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                if (nodeArg1.value = EXPR_VALUE_INT) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResu,
                            (nodeArg1.associate as IntegerAsObject).intValue() *
                            (nodeArg2.associate as IntegerAsObject).intValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_LONG) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu,
                            (nodeArg1.associate as LongAsObject).longValue() *
                            (nodeArg2.associate as LongAsObject).longValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_FLOAT: begin
                typeResu := typeFloat;
                nodeArg1 := insertTypeCast(nodeArg1, typeFloat);
                nodeArg2 := insertTypeCast(nodeArg2, typeFloat);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_REAL, typeResu,
                            realToFloat(
                            (nodeArg1.associate as FloatAsObject).floatValue() *
                            (nodeArg2.associate as FloatAsObject).floatValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_DOUBLE: begin
                typeResu := typeDouble;
                nodeArg1 := insertTypeCast(nodeArg1, typeDouble);
                nodeArg2 := insertTypeCast(nodeArg2, typeDouble);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_REAL, typeResu,
                            realToDouble(
                            (nodeArg1.associate as DoubleAsObject).doubleValue() *
                            (nodeArg2.associate as DoubleAsObject).doubleValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_REAL: begin
                typeResu := typeReal;
                nodeArg1 := insertTypeCast(nodeArg1, typeReal);
                nodeArg2 := insertTypeCast(nodeArg2, typeReal);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_REAL, typeResu,
                            (nodeArg1.associate as RealAsObject).realValue() *
                            (nodeArg2.associate as RealAsObject).realValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.SDIVS: begin
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_SDIVS, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprPref(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_SHORT: begin
                typeResu := typeShort;
                nodeArg1 := insertTypeCast(nodeArg1, typeShort);
                nodeArg2 := insertTypeCast(nodeArg2, typeShort);
                if nodeArg2.value = EXPR_VALUE_INT then begin
                    ival := (nodeArg2.associate as IntegerAsObject).shortValue();
                    if ival = 0 then begin
                        raise CompileError.create(msgIntegerDivisionByZero, lexemes, operPosition);
                    end;
                end else begin
                    ival := 0;
                end;
                if (nodeArg1.value = EXPR_VALUE_INT) and (ival <> 0) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResu, short(
                            (nodeArg1.associate as IntegerAsObject).shortValue() div ival));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_INT: begin
                typeResu := typeInt;
                nodeArg1 := insertTypeCast(nodeArg1, typeInt);
                nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                if nodeArg2.value = EXPR_VALUE_INT then begin
                    ival := (nodeArg2.associate as IntegerAsObject).intValue();
                    if ival = 0 then begin
                        raise CompileError.create(msgIntegerDivisionByZero, lexemes, operPosition);
                    end;
                end else begin
                    ival := 0;
                end;
                if (nodeArg1.value = EXPR_VALUE_INT) and (ival <> 0) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResu,
                            (nodeArg1.associate as IntegerAsObject).intValue() div ival);
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                if nodeArg2.value = EXPR_VALUE_LONG then begin
                    lval := (nodeArg2.associate as LongAsObject).longValue();
                    if lval = 0 then begin
                        raise CompileError.create(msgIntegerDivisionByZero, lexemes, operPosition);
                    end;
                end else begin
                    lval := 0;
                end;
                if (nodeArg1.value = EXPR_VALUE_LONG) and (lval <> 0) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu,
                            (nodeArg1.associate as LongAsObject).longValue() div lval);
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_FLOAT: begin
                typeResu := typeFloat;
                nodeArg1 := insertTypeCast(nodeArg1, typeFloat);
                nodeArg2 := insertTypeCast(nodeArg2, typeFloat);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_REAL, typeResu,
                            realToFloat(
                            (nodeArg1.associate as FloatAsObject).floatValue() /
                            (nodeArg2.associate as FloatAsObject).floatValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_DOUBLE: begin
                typeResu := typeDouble;
                nodeArg1 := insertTypeCast(nodeArg1, typeDouble);
                nodeArg2 := insertTypeCast(nodeArg2, typeDouble);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_REAL, typeResu,
                            realToDouble(
                            (nodeArg1.associate as DoubleAsObject).doubleValue() /
                            (nodeArg2.associate as DoubleAsObject).doubleValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_REAL: begin
                typeResu := typeReal;
                nodeArg1 := insertTypeCast(nodeArg1, typeReal);
                nodeArg2 := insertTypeCast(nodeArg2, typeReal);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_REAL, typeResu,
                            (nodeArg1.associate as RealAsObject).realValue() /
                            (nodeArg2.associate as RealAsObject).realValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.SREMS: begin
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_SREMS, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprPref(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_SHORT: begin
                typeResu := typeShort;
                nodeArg1 := insertTypeCast(nodeArg1, typeShort);
                nodeArg2 := insertTypeCast(nodeArg2, typeShort);
                if nodeArg2.value = EXPR_VALUE_INT then begin
                    ival := (nodeArg2.associate as IntegerAsObject).shortValue();
                    if ival = 0 then begin
                        raise CompileError.create(msgIntegerDivisionByZero, lexemes, operPosition);
                    end;
                end else begin
                    ival := 0;
                end;
                if (nodeArg1.value = EXPR_VALUE_INT) and (ival <> 0) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResu, short(
                            (nodeArg1.associate as IntegerAsObject).shortValue() mod ival));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_INT: begin
                typeResu := typeInt;
                nodeArg1 := insertTypeCast(nodeArg1, typeInt);
                nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                if nodeArg2.value = EXPR_VALUE_INT then begin
                    ival := (nodeArg2.associate as IntegerAsObject).intValue();
                    if ival = 0 then begin
                        raise CompileError.create(msgIntegerDivisionByZero, lexemes, operPosition);
                    end;
                end else begin
                    ival := 0;
                end;
                if (nodeArg1.value = EXPR_VALUE_INT) and (ival <> 0) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResu,
                            (nodeArg1.associate as IntegerAsObject).intValue() mod ival);
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                if nodeArg2.value = EXPR_VALUE_LONG then begin
                    lval := (nodeArg2.associate as LongAsObject).longValue();
                    if lval = 0 then begin
                        raise CompileError.create(msgIntegerDivisionByZero, lexemes, operPosition);
                    end;
                end else begin
                    lval := 0;
                end;
                if (nodeArg1.value = EXPR_VALUE_LONG) and (lval <> 0) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu,
                            (nodeArg1.associate as LongAsObject).longValue() mod lval);
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_FLOAT: begin
                typeResu := typeFloat;
                nodeArg1 := insertTypeCast(nodeArg1, typeReal);
                nodeArg2 := insertTypeCast(nodeArg2, typeReal);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_REAL, typeResu,
                            realToFloat(realMod(
                            (nodeArg1.associate as RealAsObject).realValue(),
                            (nodeArg2.associate as RealAsObject).realValue())));
                    owner.deleteChildrens(nodeOper);
                end else begin
                    nodeOper.dataType := typeReal;
                    nodeOper := insertTypeCast(nodeOper, typeResu);
                end;
            end;
            TranslatorType.KIND_DOUBLE: begin
                typeResu := typeDouble;
                nodeArg1 := insertTypeCast(nodeArg1, typeReal);
                nodeArg2 := insertTypeCast(nodeArg2, typeReal);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_REAL, typeResu,
                            realToDouble(realMod(
                            (nodeArg1.associate as RealAsObject).realValue(),
                            (nodeArg2.associate as RealAsObject).realValue())));
                    owner.deleteChildrens(nodeOper);
                end else begin
                    nodeOper.dataType := typeReal;
                    nodeOper := insertTypeCast(nodeOper, typeResu);
                end;
            end;
            TranslatorType.KIND_REAL: begin
                typeResu := typeReal;
                nodeArg1 := insertTypeCast(nodeArg1, typeReal);
                nodeArg2 := insertTypeCast(nodeArg2, typeReal);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_REAL, typeResu,
                            realMod(
                            (nodeArg1.associate as RealAsObject).realValue(),
                            (nodeArg2.associate as RealAsObject).realValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.SDIVU: begin
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_SDIVU, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprPref(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_SHORT: begin
                typeResu := typeShort;
                nodeArg1 := insertTypeCast(nodeArg1, typeShort);
                nodeArg2 := insertTypeCast(nodeArg2, typeShort);
                if nodeArg2.value = EXPR_VALUE_INT then begin
                    ival := (nodeArg2.associate as IntegerAsObject).shortValue() and $ffff;
                    if ival = 0 then begin
                        raise CompileError.create(msgIntegerDivisionByZero, lexemes, operPosition);
                    end;
                end else begin
                    ival := 0;
                end;
                if (nodeArg1.value = EXPR_VALUE_INT) and (ival <> 0) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResu, short(
                            ((nodeArg1.associate as IntegerAsObject).shortValue() and $ffff) div
                            ival));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_INT: begin
                typeResu := typeInt;
                nodeArg1 := insertTypeCast(nodeArg1, typeInt);
                nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                if nodeArg2.value = EXPR_VALUE_INT then begin
                    ival := (nodeArg2.associate as IntegerAsObject).intValue();
                    if ival = 0 then begin
                        raise CompileError.create(msgIntegerDivisionByZero, lexemes, operPosition);
                    end;
                end else begin
                    ival := 0;
                end;
                if (nodeArg1.value = EXPR_VALUE_INT) and (ival <> 0) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResu,
                            intUDiv((nodeArg1.associate as IntegerAsObject).intValue(), ival));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                if nodeArg2.value = EXPR_VALUE_LONG then begin
                    lval := (nodeArg2.associate as LongAsObject).longValue();
                    if lval = 0 then begin
                        raise CompileError.create(msgIntegerDivisionByZero, lexemes, operPosition);
                    end;
                end else begin
                    lval := 0;
                end;
                if (nodeArg1.value = EXPR_VALUE_LONG) and (lval <> 0) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu,
                            longUDiv((nodeArg1.associate as LongAsObject).longValue(), lval));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_FLOAT: begin
                typeResu := typeFloat;
                nodeArg1 := insertTypeCast(nodeArg1, typeFloat);
                nodeArg2 := insertTypeCast(nodeArg2, typeFloat);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_REAL, typeResu,
                            realToFloat(
                            (nodeArg1.associate as FloatAsObject).floatValue() /
                            (nodeArg2.associate as FloatAsObject).floatValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_DOUBLE: begin
                typeResu := typeDouble;
                nodeArg1 := insertTypeCast(nodeArg1, typeDouble);
                nodeArg2 := insertTypeCast(nodeArg2, typeDouble);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_REAL, typeResu,
                            realToDouble(
                            (nodeArg1.associate as DoubleAsObject).doubleValue() /
                            (nodeArg2.associate as DoubleAsObject).doubleValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_REAL: begin
                typeResu := typeReal;
                nodeArg1 := insertTypeCast(nodeArg1, typeReal);
                nodeArg2 := insertTypeCast(nodeArg2, typeReal);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_REAL, typeResu,
                            (nodeArg1.associate as RealAsObject).realValue() /
                            (nodeArg2.associate as RealAsObject).realValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.SREMU: begin
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_SREMU, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprPref(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_SHORT: begin
                typeResu := typeShort;
                nodeArg1 := insertTypeCast(nodeArg1, typeShort);
                nodeArg2 := insertTypeCast(nodeArg2, typeShort);
                if nodeArg2.value = EXPR_VALUE_INT then begin
                    ival := (nodeArg2.associate as IntegerAsObject).shortValue() and $ffff;
                    if ival = 0 then begin
                        raise CompileError.create(msgIntegerDivisionByZero, lexemes, operPosition);
                    end;
                end else begin
                    ival := 0;
                end;
                if (nodeArg1.value = EXPR_VALUE_INT) and (ival <> 0) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResu, short(
                            ((nodeArg1.associate as IntegerAsObject).shortValue() and $ffff) mod
                            ival));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_INT: begin
                typeResu := typeInt;
                nodeArg1 := insertTypeCast(nodeArg1, typeInt);
                nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                if nodeArg2.value = EXPR_VALUE_INT then begin
                    ival := (nodeArg2.associate as IntegerAsObject).intValue();
                    if ival = 0 then begin
                        raise CompileError.create(msgIntegerDivisionByZero, lexemes, operPosition);
                    end;
                end else begin
                    ival := 0;
                end;
                if (nodeArg1.value = EXPR_VALUE_INT) and (ival <> 0) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResu,
                            intUMod((nodeArg1.associate as IntegerAsObject).intValue(), ival));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                if nodeArg2.value = EXPR_VALUE_LONG then begin
                    lval := (nodeArg2.associate as LongAsObject).longValue();
                    if lval = 0 then begin
                        raise CompileError.create(msgIntegerDivisionByZero, lexemes, operPosition);
                    end;
                end else begin
                    lval := 0;
                end;
                if (nodeArg1.value = EXPR_VALUE_LONG) and (lval <> 0) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu,
                            longUMod((nodeArg1.associate as LongAsObject).longValue(), lval));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_FLOAT: begin
                typeResu := typeFloat;
                nodeArg1 := insertTypeCast(nodeArg1, typeReal);
                nodeArg2 := insertTypeCast(nodeArg2, typeReal);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_REAL, typeResu,
                            realToFloat(realMod(
                            (nodeArg1.associate as RealAsObject).realValue(),
                            (nodeArg2.associate as RealAsObject).realValue())));
                    owner.deleteChildrens(nodeOper);
                end else begin
                    nodeOper.dataType := typeReal;
                    nodeOper := insertTypeCast(nodeOper, typeResu);
                end;
            end;
            TranslatorType.KIND_DOUBLE: begin
                typeResu := typeDouble;
                nodeArg1 := insertTypeCast(nodeArg1, typeReal);
                nodeArg2 := insertTypeCast(nodeArg2, typeReal);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_REAL, typeResu,
                            realToDouble(realMod(
                            (nodeArg1.associate as RealAsObject).realValue(),
                            (nodeArg2.associate as RealAsObject).realValue())));
                    owner.deleteChildrens(nodeOper);
                end else begin
                    nodeOper.dataType := typeReal;
                    nodeOper := insertTypeCast(nodeOper, typeResu);
                end;
            end;
            TranslatorType.KIND_REAL: begin
                typeResu := typeReal;
                nodeArg1 := insertTypeCast(nodeArg1, typeReal);
                nodeArg2 := insertTypeCast(nodeArg2, typeReal);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_REAL, typeResu,
                            realMod(
                            (nodeArg1.associate as RealAsObject).realValue(),
                            (nodeArg2.associate as RealAsObject).realValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.QMULL: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_QMULL, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprPref(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_LONG) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu, mmxMulLo(
                            (nodeArg1.associate as LongAsObject).longValue(),
                            (nodeArg2.associate as LongAsObject).longValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, sseiMulLo(
                            (nodeArg1.associate as UltraAsObject).ultraValue(),
                            (nodeArg2.associate as UltraAsObject).ultraValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_XVECTOR: begin
                typeResu := typeXVector;
                nodeArg1 := insertTypeCast(nodeArg1, typeXVector);
                nodeArg2 := insertTypeCast(nodeArg2, typeXVector);
                if (nodeArg1.value = EXPR_VALUE_XVECTOR) and
                        (nodeArg2.value = EXPR_VALUE_XVECTOR) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_XVECTOR, typeResu, ssefMul(
                            (nodeArg1.associate as XVectorAsObject).xvectorValue(),
                            (nodeArg2.associate as XVectorAsObject).xvectorValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.QMULH: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_QMULH, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprPref(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_LONG) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu, mmxMulHi(
                            (nodeArg1.associate as LongAsObject).longValue(),
                            (nodeArg2.associate as LongAsObject).longValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, sseiMulHi(
                            (nodeArg1.associate as UltraAsObject).ultraValue(),
                            (nodeArg2.associate as UltraAsObject).ultraValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.QMULHS: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_QMULHS, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprPref(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_LONG) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu, mmxMulHiS(
                            (nodeArg1.associate as LongAsObject).longValue(),
                            (nodeArg2.associate as LongAsObject).longValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.QDIV: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_QDIV, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprPref(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_XVECTOR: begin
                typeResu := typeXVector;
                nodeArg1 := insertTypeCast(nodeArg1, typeXVector);
                nodeArg2 := insertTypeCast(nodeArg2, typeXVector);
                if (nodeArg1.value = EXPR_VALUE_XVECTOR) and
                        (nodeArg2.value = EXPR_VALUE_XVECTOR) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_XVECTOR, typeResu, ssefDiv(
                            (nodeArg1.associate as XVectorAsObject).xvectorValue(),
                            (nodeArg2.associate as XVectorAsObject).xvectorValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.OMULL: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_OMULL, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprPref(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, ssesMulLo(
                            (nodeArg1.associate as UltraAsObject).ultraValue(),
                            (nodeArg2.associate as UltraAsObject).ultraValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.OMULH: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_OMULH, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprPref(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, ssesMulHi(
                            (nodeArg1.associate as UltraAsObject).ultraValue(),
                            (nodeArg2.associate as UltraAsObject).ultraValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.OMULHS: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_OMULHS, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprPref(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, ssesMulHiS(
                            (nodeArg1.associate as UltraAsObject).ultraValue(),
                            (nodeArg2.associate as UltraAsObject).ultraValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        else
            break;
        end;
        nodeOper.dataType := typeResu;
        nodeArg1 := nodeOper;
        typeArg1 := typeResu;
    until false;
    result := position;
end;

function TranslatorTreeBuilder.parseExprAdd(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
var
    operPosition: int;
    nodeOper: SyntaxNode;
    nodeArg1: SyntaxNode;
    nodeArg2: SyntaxNode;
    typeResu: TypeDescriptor;
    typeArg1: TypeDescriptor;
    typeArg2: TypeDescriptor;
    owner: Tree;
begin
    position := parseExprMult(lexemes, position, parent);
    nodeArg1 := parent.getChild(parent.getChildrensCount() - 1) as SyntaxNode;
    typeArg1 := nodeArg1.dataType;
    owner := parent.owner;
    repeat
        operPosition := position;
        case lexemes.getType(position) of
        TranslatorLexer.SPLUS: begin
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_SADD, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprMult(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_SHORT: begin
                typeResu := typeShort;
                nodeArg1 := insertTypeCast(nodeArg1, typeShort);
                nodeArg2 := insertTypeCast(nodeArg2, typeShort);
                if (nodeArg1.value = EXPR_VALUE_INT) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResu, short(
                            (nodeArg1.associate as IntegerAsObject).shortValue() +
                            (nodeArg2.associate as IntegerAsObject).shortValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_INT: begin
                typeResu := typeInt;
                nodeArg1 := insertTypeCast(nodeArg1, typeInt);
                nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                if (nodeArg1.value = EXPR_VALUE_INT) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResu,
                            (nodeArg1.associate as IntegerAsObject).intValue() +
                            (nodeArg2.associate as IntegerAsObject).intValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_LONG) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu,
                            (nodeArg1.associate as LongAsObject).longValue() +
                            (nodeArg2.associate as LongAsObject).longValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_FLOAT: begin
                typeResu := typeFloat;
                nodeArg1 := insertTypeCast(nodeArg1, typeFloat);
                nodeArg2 := insertTypeCast(nodeArg2, typeFloat);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_REAL, typeResu,
                            realToFloat(
                            (nodeArg1.associate as FloatAsObject).floatValue() +
                            (nodeArg2.associate as FloatAsObject).floatValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_DOUBLE: begin
                typeResu := typeDouble;
                nodeArg1 := insertTypeCast(nodeArg1, typeDouble);
                nodeArg2 := insertTypeCast(nodeArg2, typeDouble);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_REAL, typeResu,
                            realToDouble(
                            (nodeArg1.associate as DoubleAsObject).doubleValue() +
                            (nodeArg2.associate as DoubleAsObject).doubleValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_REAL: begin
                typeResu := typeReal;
                nodeArg1 := insertTypeCast(nodeArg1, typeReal);
                nodeArg2 := insertTypeCast(nodeArg2, typeReal);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_REAL, typeResu,
                            (nodeArg1.associate as RealAsObject).realValue() +
                            (nodeArg2.associate as RealAsObject).realValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.SMINUS: begin
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_SSUB, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprMult(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_SHORT: begin
                typeResu := typeShort;
                nodeArg1 := insertTypeCast(nodeArg1, typeShort);
                nodeArg2 := insertTypeCast(nodeArg2, typeShort);
                if (nodeArg1.value = EXPR_VALUE_INT) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResu, short(
                            (nodeArg1.associate as IntegerAsObject).shortValue() -
                            (nodeArg2.associate as IntegerAsObject).shortValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_INT: begin
                typeResu := typeInt;
                nodeArg1 := insertTypeCast(nodeArg1, typeInt);
                nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                if (nodeArg1.value = EXPR_VALUE_INT) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResu,
                            (nodeArg1.associate as IntegerAsObject).intValue() -
                            (nodeArg2.associate as IntegerAsObject).intValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_LONG) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu,
                            (nodeArg1.associate as LongAsObject).longValue() -
                            (nodeArg2.associate as LongAsObject).longValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_FLOAT: begin
                typeResu := typeFloat;
                nodeArg1 := insertTypeCast(nodeArg1, typeFloat);
                nodeArg2 := insertTypeCast(nodeArg2, typeFloat);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_REAL, typeResu,
                            realToFloat(
                            (nodeArg1.associate as FloatAsObject).floatValue() -
                            (nodeArg2.associate as FloatAsObject).floatValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_DOUBLE: begin
                typeResu := typeDouble;
                nodeArg1 := insertTypeCast(nodeArg1, typeDouble);
                nodeArg2 := insertTypeCast(nodeArg2, typeDouble);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_REAL, typeResu,
                            realToDouble(
                            (nodeArg1.associate as DoubleAsObject).doubleValue() -
                            (nodeArg2.associate as DoubleAsObject).doubleValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_REAL: begin
                typeResu := typeReal;
                nodeArg1 := insertTypeCast(nodeArg1, typeReal);
                nodeArg2 := insertTypeCast(nodeArg2, typeReal);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_REAL, typeResu,
                            (nodeArg1.associate as RealAsObject).realValue() -
                            (nodeArg2.associate as RealAsObject).realValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.QADD: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_QADD, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprMult(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_LONG) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu, mmxAdd(
                            (nodeArg1.associate as LongAsObject).longValue(),
                            (nodeArg2.associate as LongAsObject).longValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, sseiAdd(
                            (nodeArg1.associate as UltraAsObject).ultraValue(),
                            (nodeArg2.associate as UltraAsObject).ultraValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_XVECTOR: begin
                typeResu := typeXVector;
                nodeArg1 := insertTypeCast(nodeArg1, typeXVector);
                nodeArg2 := insertTypeCast(nodeArg2, typeXVector);
                if (nodeArg1.value = EXPR_VALUE_XVECTOR) and
                        (nodeArg2.value = EXPR_VALUE_XVECTOR) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_XVECTOR, typeResu, ssefAdd(
                            (nodeArg1.associate as XVectorAsObject).xvectorValue(),
                            (nodeArg2.associate as XVectorAsObject).xvectorValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.QADDS: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_QADDS, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprMult(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_LONG) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu, mmxAddS(
                            (nodeArg1.associate as LongAsObject).longValue(),
                            (nodeArg2.associate as LongAsObject).longValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.QADDUS: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_QADDUS, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprMult(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_LONG) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu, mmxAddUS(
                            (nodeArg1.associate as LongAsObject).longValue(),
                            (nodeArg2.associate as LongAsObject).longValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.QSUB: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_QSUB, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprMult(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_LONG) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu, mmxSub(
                            (nodeArg1.associate as LongAsObject).longValue(),
                            (nodeArg2.associate as LongAsObject).longValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, sseiSub(
                            (nodeArg1.associate as UltraAsObject).ultraValue(),
                            (nodeArg2.associate as UltraAsObject).ultraValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_XVECTOR: begin
                typeResu := typeXVector;
                nodeArg1 := insertTypeCast(nodeArg1, typeXVector);
                nodeArg2 := insertTypeCast(nodeArg2, typeXVector);
                if (nodeArg1.value = EXPR_VALUE_XVECTOR) and
                        (nodeArg2.value = EXPR_VALUE_XVECTOR) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_XVECTOR, typeResu, ssefSub(
                            (nodeArg1.associate as XVectorAsObject).xvectorValue(),
                            (nodeArg2.associate as XVectorAsObject).xvectorValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.QSUBS: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_QSUBS, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprMult(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_LONG) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu, mmxSubS(
                            (nodeArg1.associate as LongAsObject).longValue(),
                            (nodeArg2.associate as LongAsObject).longValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.QSUBUS: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_QSUBUS, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprMult(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_LONG) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu, mmxSubUS(
                            (nodeArg1.associate as LongAsObject).longValue(),
                            (nodeArg2.associate as LongAsObject).longValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.OADD: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_OADD, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprMult(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, ssesAdd(
                            (nodeArg1.associate as UltraAsObject).ultraValue(),
                            (nodeArg2.associate as UltraAsObject).ultraValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.OADDS: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_OADDS, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprMult(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, ssesAddS(
                            (nodeArg1.associate as UltraAsObject).ultraValue(),
                            (nodeArg2.associate as UltraAsObject).ultraValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.OADDUS: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_OADDUS, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprMult(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, ssesAddUS(
                            (nodeArg1.associate as UltraAsObject).ultraValue(),
                            (nodeArg2.associate as UltraAsObject).ultraValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.OSUB: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_OSUB, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprMult(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, ssesSub(
                            (nodeArg1.associate as UltraAsObject).ultraValue(),
                            (nodeArg2.associate as UltraAsObject).ultraValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.OSUBS: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_OSUBS, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprMult(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, ssesSubS(
                            (nodeArg1.associate as UltraAsObject).ultraValue(),
                            (nodeArg2.associate as UltraAsObject).ultraValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.OSUBUS: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_OSUBUS, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprMult(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, ssesSubUS(
                            (nodeArg1.associate as UltraAsObject).ultraValue(),
                            (nodeArg2.associate as UltraAsObject).ultraValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        else
            break;
        end;
        nodeOper.dataType := typeResu;
        nodeArg1 := nodeOper;
        typeArg1 := typeResu;
    until false;
    result := position;
end;

function TranslatorTreeBuilder.parseExprShift(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
var
    operPosition: int;
    nodeOper: SyntaxNode;
    nodeArg1: SyntaxNode;
    nodeArg2: SyntaxNode;
    typeResu: TypeDescriptor;
    typeArg1: TypeDescriptor;
    typeArg2: TypeDescriptor;
    owner: Tree;
begin
    position := parseExprAdd(lexemes, position, parent);
    nodeArg1 := parent.getChild(parent.getChildrensCount() - 1) as SyntaxNode;
    typeArg1 := nodeArg1.dataType;
    owner := parent.owner;
    repeat
        operPosition := position;
        case lexemes.getType(position) of
        TranslatorLexer.SSLL: begin
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_SSLL, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprAdd(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            if not possibleAssign(typeInt, typeArg2, nodeArg2.associate) then begin
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
            case getTypeKind(typeArg1) of
            TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE,
            TranslatorType.KIND_SHORT, TranslatorType.KIND_INT: begin
                if operandSize < TranslatorType.SIZE_32_BIT then begin
                    typeResu := typeShort;
                    nodeArg1 := insertTypeCast(nodeArg1, typeShort);
                    nodeArg2 := insertTypeCast(nodeArg2, typeShort);
                    if (nodeArg1.value = EXPR_VALUE_INT) and
                            (nodeArg2.value = EXPR_VALUE_INT) then begin
                        nodeOper.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResu, short(
                                (nodeArg1.associate as IntegerAsObject).shortValue() shl
                                (nodeArg2.associate as IntegerAsObject).intValue()));
                        owner.deleteChildrens(nodeOper);
                    end;
                end else begin
                    typeResu := typeInt;
                    nodeArg1 := insertTypeCast(nodeArg1, typeInt);
                    nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                    if (nodeArg1.value = EXPR_VALUE_INT) and
                            (nodeArg2.value = EXPR_VALUE_INT) then begin
                        nodeOper.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResu,
                                (nodeArg1.associate as IntegerAsObject).intValue() shl
                                (nodeArg2.associate as IntegerAsObject).intValue());
                        owner.deleteChildrens(nodeOper);
                    end;
                end;
            end;
            TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu,
                            (nodeArg1.associate as LongAsObject).longValue() shl
                            (nodeArg2.associate as IntegerAsObject).intValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.SSRA: begin
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_SSRA, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprAdd(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            if not possibleAssign(typeInt, typeArg2, nodeArg2.associate) then begin
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
            case getTypeKind(typeArg1) of
            TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE,
            TranslatorType.KIND_SHORT, TranslatorType.KIND_INT: begin
                if operandSize < TranslatorType.SIZE_32_BIT then begin
                    typeResu := typeShort;
                    nodeArg1 := insertTypeCast(nodeArg1, typeShort);
                    nodeArg2 := insertTypeCast(nodeArg2, typeShort);
                    if (nodeArg1.value = EXPR_VALUE_INT) and
                            (nodeArg2.value = EXPR_VALUE_INT) then begin
                        nodeOper.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResu, intSar(
                                (nodeArg1.associate as IntegerAsObject).shortValue(),
                                (nodeArg2.associate as IntegerAsObject).intValue()));
                        owner.deleteChildrens(nodeOper);
                    end;
                end else begin
                    typeResu := typeInt;
                    nodeArg1 := insertTypeCast(nodeArg1, typeInt);
                    nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                    if (nodeArg1.value = EXPR_VALUE_INT) and
                            (nodeArg2.value = EXPR_VALUE_INT) then begin
                        nodeOper.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResu, intSar(
                                (nodeArg1.associate as IntegerAsObject).intValue(),
                                (nodeArg2.associate as IntegerAsObject).intValue()));
                        owner.deleteChildrens(nodeOper);
                    end;
                end;
            end;
            TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu, longSar(
                            (nodeArg1.associate as LongAsObject).longValue(),
                            (nodeArg2.associate as IntegerAsObject).intValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.SSRL: begin
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_SSRL, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprAdd(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            if not possibleAssign(typeInt, typeArg2, nodeArg2.associate) then begin
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
            case getTypeKind(typeArg1) of
            TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE,
            TranslatorType.KIND_SHORT, TranslatorType.KIND_INT: begin
                if operandSize < TranslatorType.SIZE_32_BIT then begin
                    typeResu := typeShort;
                    nodeArg1 := insertTypeCast(nodeArg1, typeShort);
                    nodeArg2 := insertTypeCast(nodeArg2, typeShort);
                    if (nodeArg1.value = EXPR_VALUE_INT) and
                            (nodeArg2.value = EXPR_VALUE_INT) then begin
                        nodeOper.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResu, short((
                                (nodeArg1.associate as IntegerAsObject).shortValue() and $ffff) shr
                                (nodeArg2.associate as IntegerAsObject).intValue()));
                        owner.deleteChildrens(nodeOper);
                    end;
                end else begin
                    typeResu := typeInt;
                    nodeArg1 := insertTypeCast(nodeArg1, typeInt);
                    nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                    if (nodeArg1.value = EXPR_VALUE_INT) and
                            (nodeArg2.value = EXPR_VALUE_INT) then begin
                        nodeOper.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResu,
                                (nodeArg1.associate as IntegerAsObject).intValue() shr
                                (nodeArg2.associate as IntegerAsObject).intValue());
                        owner.deleteChildrens(nodeOper);
                    end;
                end;
            end;
            TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu,
                            (nodeArg1.associate as LongAsObject).longValue() shr
                            (nodeArg2.associate as IntegerAsObject).intValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.QSLL: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_QSLL, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprAdd(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            if not possibleAssign(typeInt, typeArg2, nodeArg2.associate) then begin
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
            case getTypeKind(typeArg1) of
            TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE, TranslatorType.KIND_SHORT,
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu, mmxShl(
                            (nodeArg1.associate as LongAsObject).longValue(),
                            (nodeArg2.associate as IntegerAsObject).intValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, sseiShl(
                            (nodeArg1.associate as UltraAsObject).ultraValue(),
                            (nodeArg2.associate as IntegerAsObject).intValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.QSRA: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_QSRA, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprAdd(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            if not possibleAssign(typeInt, typeArg2, nodeArg2.associate) then begin
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
            case getTypeKind(typeArg1) of
            TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE, TranslatorType.KIND_SHORT,
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu, mmxSar(
                            (nodeArg1.associate as LongAsObject).longValue(),
                            (nodeArg2.associate as IntegerAsObject).intValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, sseiSar(
                            (nodeArg1.associate as UltraAsObject).ultraValue(),
                            (nodeArg2.associate as IntegerAsObject).intValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.QSRL: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_QSRL, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprAdd(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            if not possibleAssign(typeInt, typeArg2, nodeArg2.associate) then begin
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
            case getTypeKind(typeArg1) of
            TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE, TranslatorType.KIND_SHORT,
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu, mmxShr(
                            (nodeArg1.associate as LongAsObject).longValue(),
                            (nodeArg2.associate as IntegerAsObject).intValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, sseiShr(
                            (nodeArg1.associate as UltraAsObject).ultraValue(),
                            (nodeArg2.associate as IntegerAsObject).intValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.OSLL: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_OSLL, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprAdd(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            if not possibleAssign(typeInt, typeArg2, nodeArg2.associate) then begin
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
            case getTypeKind(typeArg1) of
            TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE, TranslatorType.KIND_SHORT,
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, ssesShl(
                            (nodeArg1.associate as UltraAsObject).ultraValue(),
                            (nodeArg2.associate as IntegerAsObject).intValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.OSRA: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_OSRA, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprAdd(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            if not possibleAssign(typeInt, typeArg2, nodeArg2.associate) then begin
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
            case getTypeKind(typeArg1) of
            TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE, TranslatorType.KIND_SHORT,
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, ssesSar(
                            (nodeArg1.associate as UltraAsObject).ultraValue(),
                            (nodeArg2.associate as IntegerAsObject).intValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.OSRL: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_OSRL, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprAdd(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            if not possibleAssign(typeInt, typeArg2, nodeArg2.associate) then begin
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
            case getTypeKind(typeArg1) of
            TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE, TranslatorType.KIND_SHORT,
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, ssesShr(
                            (nodeArg1.associate as UltraAsObject).ultraValue(),
                            (nodeArg2.associate as IntegerAsObject).intValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        else
            break;
        end;
        nodeOper.dataType := typeResu;
        nodeArg1 := nodeOper;
        typeArg1 := typeResu;
    until false;
    result := position;
end;

function TranslatorTreeBuilder.parseExprRel(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
var
    operPosition: int;
    nodeOper: SyntaxNode;
    nodeArg1: SyntaxNode;
    nodeArg2: SyntaxNode;
    typeResu: TypeDescriptor;
    typeArg1: TypeDescriptor;
    typeArg2: TypeDescriptor;
    owner: Tree;
begin
    position := parseExprShift(lexemes, position, parent);
    nodeArg1 := parent.getChild(parent.getChildrensCount() - 1) as SyntaxNode;
    typeArg1 := nodeArg1.dataType;
    owner := parent.owner;
    repeat
        operPosition := position;
        case lexemes.getType(position) of
        TranslatorLexer.SGT: begin
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_SGT, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprShift(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_SHORT: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeShort);
                nodeArg2 := insertTypeCast(nodeArg2, typeShort);
                if (nodeArg1.value = EXPR_VALUE_INT) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu,
                            (nodeArg1.associate as IntegerAsObject).shortValue() >
                            (nodeArg2.associate as IntegerAsObject).shortValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_INT: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeInt);
                nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                if (nodeArg1.value = EXPR_VALUE_INT) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu,
                            (nodeArg1.associate as IntegerAsObject).intValue() >
                            (nodeArg2.associate as IntegerAsObject).intValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_LONG: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_LONG) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu,
                            (nodeArg1.associate as LongAsObject).longValue() >
                            (nodeArg2.associate as LongAsObject).longValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_FLOAT: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeFloat);
                nodeArg2 := insertTypeCast(nodeArg2, typeFloat);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu, realCmpl(
                            (nodeArg1.associate as FloatAsObject).floatValue(),
                            (nodeArg2.associate as FloatAsObject).floatValue()) > 0);
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_DOUBLE: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeDouble);
                nodeArg2 := insertTypeCast(nodeArg2, typeDouble);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu, realCmpl(
                            (nodeArg1.associate as DoubleAsObject).doubleValue(),
                            (nodeArg2.associate as DoubleAsObject).doubleValue()) > 0);
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_REAL: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeReal);
                nodeArg2 := insertTypeCast(nodeArg2, typeReal);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu, realCmpl(
                            (nodeArg1.associate as RealAsObject).realValue(),
                            (nodeArg2.associate as RealAsObject).realValue()) > 0);
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.SGE: begin
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_SGE, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprShift(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_SHORT: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeShort);
                nodeArg2 := insertTypeCast(nodeArg2, typeShort);
                if (nodeArg1.value = EXPR_VALUE_INT) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu,
                            (nodeArg1.associate as IntegerAsObject).shortValue() >=
                            (nodeArg2.associate as IntegerAsObject).shortValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_INT: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeInt);
                nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                if (nodeArg1.value = EXPR_VALUE_INT) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu,
                            (nodeArg1.associate as IntegerAsObject).intValue() >=
                            (nodeArg2.associate as IntegerAsObject).intValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_LONG: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_LONG) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu,
                            (nodeArg1.associate as LongAsObject).longValue() >=
                            (nodeArg2.associate as LongAsObject).longValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_FLOAT: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeFloat);
                nodeArg2 := insertTypeCast(nodeArg2, typeFloat);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu, realCmpl(
                            (nodeArg1.associate as FloatAsObject).floatValue(),
                            (nodeArg2.associate as FloatAsObject).floatValue()) >= 0);
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_DOUBLE: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeDouble);
                nodeArg2 := insertTypeCast(nodeArg2, typeDouble);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu, realCmpl(
                            (nodeArg1.associate as DoubleAsObject).doubleValue(),
                            (nodeArg2.associate as DoubleAsObject).doubleValue()) >= 0);
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_REAL: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeReal);
                nodeArg2 := insertTypeCast(nodeArg2, typeReal);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu, realCmpl(
                            (nodeArg1.associate as RealAsObject).realValue(),
                            (nodeArg2.associate as RealAsObject).realValue()) >= 0);
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.SLT: begin
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_SLT, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprShift(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_SHORT: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeShort);
                nodeArg2 := insertTypeCast(nodeArg2, typeShort);
                if (nodeArg1.value = EXPR_VALUE_INT) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu,
                            (nodeArg1.associate as IntegerAsObject).shortValue() <
                            (nodeArg2.associate as IntegerAsObject).shortValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_INT: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeInt);
                nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                if (nodeArg1.value = EXPR_VALUE_INT) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu,
                            (nodeArg1.associate as IntegerAsObject).intValue() <
                            (nodeArg2.associate as IntegerAsObject).intValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_LONG: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_LONG) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu,
                            (nodeArg1.associate as LongAsObject).longValue() <
                            (nodeArg2.associate as LongAsObject).longValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_FLOAT: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeFloat);
                nodeArg2 := insertTypeCast(nodeArg2, typeFloat);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu, realCmpg(
                            (nodeArg1.associate as FloatAsObject).floatValue(),
                            (nodeArg2.associate as FloatAsObject).floatValue()) < 0);
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_DOUBLE: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeDouble);
                nodeArg2 := insertTypeCast(nodeArg2, typeDouble);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu, realCmpg(
                            (nodeArg1.associate as DoubleAsObject).doubleValue(),
                            (nodeArg2.associate as DoubleAsObject).doubleValue()) < 0);
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_REAL: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeReal);
                nodeArg2 := insertTypeCast(nodeArg2, typeReal);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu, realCmpg(
                            (nodeArg1.associate as RealAsObject).realValue(),
                            (nodeArg2.associate as RealAsObject).realValue()) < 0);
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.SLE: begin
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_SLE, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprShift(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_SHORT: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeShort);
                nodeArg2 := insertTypeCast(nodeArg2, typeShort);
                if (nodeArg1.value = EXPR_VALUE_INT) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu,
                            (nodeArg1.associate as IntegerAsObject).shortValue() <=
                            (nodeArg2.associate as IntegerAsObject).shortValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_INT: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeInt);
                nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                if (nodeArg1.value = EXPR_VALUE_INT) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu,
                            (nodeArg1.associate as IntegerAsObject).intValue() <=
                            (nodeArg2.associate as IntegerAsObject).intValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_LONG: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_LONG) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu,
                            (nodeArg1.associate as LongAsObject).longValue() <=
                            (nodeArg2.associate as LongAsObject).longValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_FLOAT: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeFloat);
                nodeArg2 := insertTypeCast(nodeArg2, typeFloat);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu, realCmpg(
                            (nodeArg1.associate as FloatAsObject).floatValue(),
                            (nodeArg2.associate as FloatAsObject).floatValue()) <= 0);
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_DOUBLE: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeDouble);
                nodeArg2 := insertTypeCast(nodeArg2, typeDouble);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu, realCmpg(
                            (nodeArg1.associate as DoubleAsObject).doubleValue(),
                            (nodeArg2.associate as DoubleAsObject).doubleValue()) <= 0);
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_REAL: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeReal);
                nodeArg2 := insertTypeCast(nodeArg2, typeReal);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu, realCmpg(
                            (nodeArg1.associate as RealAsObject).realValue(),
                            (nodeArg2.associate as RealAsObject).realValue()) <= 0);
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.QGT: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_QGT, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprShift(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_LONG) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu, mmxGreate(
                            (nodeArg1.associate as LongAsObject).longValue(),
                            (nodeArg2.associate as LongAsObject).longValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, sseiGreate(
                            (nodeArg1.associate as UltraAsObject).ultraValue(),
                            (nodeArg2.associate as UltraAsObject).ultraValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_FLOAT, TranslatorType.KIND_XVECTOR: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeXVector);
                nodeArg2 := insertTypeCast(nodeArg2, typeXVector);
                if (nodeArg1.value = EXPR_VALUE_XVECTOR) and
                        (nodeArg2.value = EXPR_VALUE_XVECTOR) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, ssefCmpg(
                            (nodeArg1.associate as XVectorAsObject).xvectorValue(),
                            (nodeArg2.associate as XVectorAsObject).xvectorValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.QGE: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_QGE, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprShift(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_LONG) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu, mmxGreate(
                            (nodeArg2.associate as LongAsObject).longValue(),
                            (nodeArg1.associate as LongAsObject).longValue()) xor (-1));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, sseiGreate(
                            (nodeArg2.associate as UltraAsObject).ultraValue(),
                            (nodeArg1.associate as UltraAsObject).ultraValue()) xor
                            ultraBuild(-1, -1));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_FLOAT, TranslatorType.KIND_XVECTOR: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeXVector);
                nodeArg2 := insertTypeCast(nodeArg2, typeXVector);
                if (nodeArg1.value = EXPR_VALUE_XVECTOR) and
                        (nodeArg2.value = EXPR_VALUE_XVECTOR) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, ssefCmpge(
                            (nodeArg1.associate as XVectorAsObject).xvectorValue(),
                            (nodeArg2.associate as XVectorAsObject).xvectorValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.QLT: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_QLT, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprShift(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_LONG) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu, mmxGreate(
                            (nodeArg2.associate as LongAsObject).longValue(),
                            (nodeArg1.associate as LongAsObject).longValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, sseiGreate(
                            (nodeArg2.associate as UltraAsObject).ultraValue(),
                            (nodeArg1.associate as UltraAsObject).ultraValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_FLOAT, TranslatorType.KIND_XVECTOR: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeXVector);
                nodeArg2 := insertTypeCast(nodeArg2, typeXVector);
                if (nodeArg1.value = EXPR_VALUE_XVECTOR) and
                        (nodeArg2.value = EXPR_VALUE_XVECTOR) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, ssefCmpl(
                            (nodeArg1.associate as XVectorAsObject).xvectorValue(),
                            (nodeArg2.associate as XVectorAsObject).xvectorValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.QLE: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_QLE, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprShift(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_LONG) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu, mmxGreate(
                            (nodeArg1.associate as LongAsObject).longValue(),
                            (nodeArg2.associate as LongAsObject).longValue()) xor (-1));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, sseiGreate(
                            (nodeArg1.associate as UltraAsObject).ultraValue(),
                            (nodeArg2.associate as UltraAsObject).ultraValue()) xor
                            ultraBuild(-1, -1));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_FLOAT, TranslatorType.KIND_XVECTOR: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeXVector);
                nodeArg2 := insertTypeCast(nodeArg2, typeXVector);
                if (nodeArg1.value = EXPR_VALUE_XVECTOR) and
                        (nodeArg2.value = EXPR_VALUE_XVECTOR) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, ssefCmple(
                            (nodeArg1.associate as XVectorAsObject).xvectorValue(),
                            (nodeArg2.associate as XVectorAsObject).xvectorValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.OGT: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_OGT, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprShift(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, ssesGreate(
                            (nodeArg1.associate as UltraAsObject).ultraValue(),
                            (nodeArg2.associate as UltraAsObject).ultraValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.OGE: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_OGE, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprShift(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, ssesGreate(
                            (nodeArg2.associate as UltraAsObject).ultraValue(),
                            (nodeArg1.associate as UltraAsObject).ultraValue()) xor
                            ultraBuild(-1, -1));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.OLT: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_OLT, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprShift(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, ssesGreate(
                            (nodeArg2.associate as UltraAsObject).ultraValue(),
                            (nodeArg1.associate as UltraAsObject).ultraValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.OLE: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_OLE, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprShift(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, ssesGreate(
                            (nodeArg1.associate as UltraAsObject).ultraValue(),
                            (nodeArg2.associate as UltraAsObject).ultraValue()) xor
                            ultraBuild(-1, -1));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        else
            break;
        end;
        nodeOper.dataType := typeResu;
        nodeArg1 := nodeOper;
        typeArg1 := typeResu;
    until false;
    result := position;
end;

function TranslatorTreeBuilder.parseExprEqual(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
var
    operPosition: int;
    typeKind1: int;
    typeKind2: int;
    nodeVal1: int;
    nodeVal2: int;
    nodeOper: SyntaxNode;
    nodeArg1: SyntaxNode;
    nodeArg2: SyntaxNode;
    typeResu: TypeDescriptor;
    typeArg1: TypeDescriptor;
    typeArg2: TypeDescriptor;
    owner: Tree;
begin
    position := parseExprRel(lexemes, position, parent);
    nodeArg1 := parent.getChild(parent.getChildrensCount() - 1) as SyntaxNode;
    typeArg1 := nodeArg1.dataType;
    owner := parent.owner;
    repeat
        operPosition := position;
        case lexemes.getType(position) of
        TranslatorLexer.SEQ: begin
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_SEQ, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprRel(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            typeKind1 := getTypeKind(typeArg1);
            typeKind2 := getTypeKind(typeArg2);
            if ((typeKind1 = TranslatorType.KIND_STRUCT) or
                    (typeKind1 = TranslatorType.KIND_ARRAY) or
                    (typeKind1 = TranslatorType.KIND_FUNC)) and (
                    (typeKind2 = TranslatorType.KIND_STRUCT) or
                    (typeKind2 = TranslatorType.KIND_ARRAY) or
                    (typeKind2 = TranslatorType.KIND_FUNC)) and (
                    typeArg1.possibleAssignTo(typeArg2) or
                    typeArg2.possibleAssignTo(typeArg1)) then begin
                typeResu := typeBoolean;
            end else
            if (typeKind2 = -1) and (
                    (typeKind1 = TranslatorType.KIND_STRUCT) or
                    (typeKind1 = TranslatorType.KIND_ARRAY) or
                    (typeKind1 = TranslatorType.KIND_FUNC)) then begin
                typeResu := typeBoolean;
                owner.deleteNode(nodeArg2);
                nodeOper.setDataAssociate(operPosition, EXPR_SEQ_NULL, typeResu, nil);
            end else
            if (typeKind1 = -1) and (
                    (typeKind2 = TranslatorType.KIND_STRUCT) or
                    (typeKind2 = TranslatorType.KIND_ARRAY) or
                    (typeKind2 = TranslatorType.KIND_FUNC)) then begin
                typeResu := typeBoolean;
                owner.deleteNode(nodeArg1);
                nodeOper.setDataAssociate(operPosition, EXPR_SEQ_NULL, typeResu, nil);
            end else
            if (typeKind1 = -1) and (typeKind2 = -1) then begin
                typeResu := typeBoolean;
                owner.deleteChildrens(nodeOper);
                nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu, true);
            end else
            case getCommonTypeKind(typeKind1, typeKind2) of
            TranslatorType.KIND_BOOLEAN: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeBoolean);
                nodeArg2 := insertTypeCast(nodeArg2, typeBoolean);
                if (nodeArg1.value = EXPR_VALUE_BOOLEAN) and
                        (nodeArg2.value = EXPR_VALUE_BOOLEAN) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu,
                            (nodeArg1.associate as BooleanAsObject).booleanValue() =
                            (nodeArg2.associate as BooleanAsObject).booleanValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_SHORT: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeShort);
                nodeArg2 := insertTypeCast(nodeArg2, typeShort);
                nodeVal1 := nodeArg1.value;
                nodeVal2 := nodeArg2.value;
                if (nodeVal1 = EXPR_SANDB) and (nodeVal2 = EXPR_VALUE_INT) and
                        ((nodeArg2.associate as IntegerAsObject).shortValue() = 0) then begin
                    nodeArg1.getChild(0).setParent(nodeOper, 0);
                    nodeArg1.getChild(0).setParent(nodeOper, 1);
                    owner.deleteNode(nodeArg1);
                    owner.deleteNode(nodeArg2);
                    nodeOper.setDataAssociate(operPosition, EXPR_SZR_TEST, typeResu, nil);
                end else
                if (nodeVal2 = EXPR_SANDB) and (nodeVal1 = EXPR_VALUE_INT) and
                        ((nodeArg1.associate as IntegerAsObject).shortValue() = 0) then begin
                    nodeArg2.getChild(0).setParent(nodeOper, 0);
                    nodeArg2.getChild(0).setParent(nodeOper, 1);
                    owner.deleteNode(nodeArg1);
                    owner.deleteNode(nodeArg2);
                    nodeOper.setDataAssociate(operPosition, EXPR_SZR_TEST, typeResu, nil);
                end else
                if (nodeVal1 = EXPR_VALUE_INT) and (nodeVal2 = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu,
                            (nodeArg1.associate as IntegerAsObject).shortValue() =
                            (nodeArg2.associate as IntegerAsObject).shortValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_INT: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeInt);
                nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                nodeVal1 := nodeArg1.value;
                nodeVal2 := nodeArg2.value;
                if (nodeVal1 = EXPR_SANDB) and (nodeVal2 = EXPR_VALUE_INT) and
                        ((nodeArg2.associate as IntegerAsObject).intValue() = 0) then begin
                    nodeArg1.getChild(0).setParent(nodeOper, 0);
                    nodeArg1.getChild(0).setParent(nodeOper, 1);
                    owner.deleteNode(nodeArg1);
                    owner.deleteNode(nodeArg2);
                    nodeOper.setDataAssociate(operPosition, EXPR_SZR_TEST, typeResu, nil);
                end else
                if (nodeVal2 = EXPR_SANDB) and (nodeVal1 = EXPR_VALUE_INT) and
                        ((nodeArg1.associate as IntegerAsObject).intValue() = 0) then begin
                    nodeArg2.getChild(0).setParent(nodeOper, 0);
                    nodeArg2.getChild(0).setParent(nodeOper, 1);
                    owner.deleteNode(nodeArg1);
                    owner.deleteNode(nodeArg2);
                    nodeOper.setDataAssociate(operPosition, EXPR_SZR_TEST, typeResu, nil);
                end else
                if (nodeVal1 = EXPR_VALUE_INT) and (nodeVal2 = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu,
                            (nodeArg1.associate as IntegerAsObject).intValue() =
                            (nodeArg2.associate as IntegerAsObject).intValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_LONG: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                nodeVal1 := nodeArg1.value;
                nodeVal2 := nodeArg2.value;
                if (nodeVal1 = EXPR_SANDB) and (nodeVal2 = EXPR_VALUE_LONG) and
                        ((nodeArg2.associate as LongAsObject).longValue() = 0) then begin
                    nodeArg1.getChild(0).setParent(nodeOper, 0);
                    nodeArg1.getChild(0).setParent(nodeOper, 1);
                    owner.deleteNode(nodeArg1);
                    owner.deleteNode(nodeArg2);
                    nodeOper.setDataAssociate(operPosition, EXPR_SZR_TEST, typeResu, nil);
                end else
                if (nodeVal2 = EXPR_SANDB) and (nodeVal1 = EXPR_VALUE_LONG) and
                        ((nodeArg1.associate as LongAsObject).longValue() = 0) then begin
                    nodeArg2.getChild(0).setParent(nodeOper, 0);
                    nodeArg2.getChild(0).setParent(nodeOper, 1);
                    owner.deleteNode(nodeArg1);
                    owner.deleteNode(nodeArg2);
                    nodeOper.setDataAssociate(operPosition, EXPR_SZR_TEST, typeResu, nil);
                end else
                if (nodeVal1 = EXPR_VALUE_LONG) and (nodeVal2 = EXPR_VALUE_LONG) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu,
                            (nodeArg1.associate as LongAsObject).longValue() =
                            (nodeArg2.associate as LongAsObject).longValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_ULTRA: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu,
                            ssesPack(ssesShr(sseiEquals(
                            (nodeArg1.associate as UltraAsObject).ultraValue(),
                            (nodeArg2.associate as UltraAsObject).ultraValue()), $08)) = (-1));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_FLOAT: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeFloat);
                nodeArg2 := insertTypeCast(nodeArg2, typeFloat);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu, realCmpl(
                            (nodeArg1.associate as FloatAsObject).floatValue(),
                            (nodeArg2.associate as FloatAsObject).floatValue()) = 0);
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_DOUBLE: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeDouble);
                nodeArg2 := insertTypeCast(nodeArg2, typeDouble);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu, realCmpl(
                            (nodeArg1.associate as DoubleAsObject).doubleValue(),
                            (nodeArg2.associate as DoubleAsObject).doubleValue()) = 0);
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_REAL: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeReal);
                nodeArg2 := insertTypeCast(nodeArg2, typeReal);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu, realCmpl(
                            (nodeArg1.associate as RealAsObject).realValue(),
                            (nodeArg2.associate as RealAsObject).realValue()) = 0);
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_XVECTOR: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeXVector);
                nodeArg2 := insertTypeCast(nodeArg2, typeXVector);
                if (nodeArg1.value = EXPR_VALUE_XVECTOR) and
                        (nodeArg2.value = EXPR_VALUE_XVECTOR) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu,
                            ssesPack(ssesShr(ssefCmpe(
                            (nodeArg1.associate as XVectorAsObject).xvectorValue(),
                            (nodeArg2.associate as XVectorAsObject).xvectorValue()), $08)) = -1);
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.SNE: begin
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_SNE, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprRel(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            typeKind1 := getTypeKind(typeArg1);
            typeKind2 := getTypeKind(typeArg2);
            if ((typeKind1 = TranslatorType.KIND_STRUCT) or
                    (typeKind1 = TranslatorType.KIND_ARRAY) or
                    (typeKind1 = TranslatorType.KIND_FUNC)) and (
                    (typeKind2 = TranslatorType.KIND_STRUCT) or
                    (typeKind2 = TranslatorType.KIND_ARRAY) or
                    (typeKind2 = TranslatorType.KIND_FUNC)) and (
                    typeArg1.possibleAssignTo(typeArg2) or
                    typeArg2.possibleAssignTo(typeArg1)) then begin
                typeResu := typeBoolean;
            end else
            if (typeKind2 = -1) and (
                    (typeKind1 = TranslatorType.KIND_STRUCT) or
                    (typeKind1 = TranslatorType.KIND_ARRAY) or
                    (typeKind1 = TranslatorType.KIND_FUNC)) then begin
                typeResu := typeBoolean;
                owner.deleteNode(nodeArg2);
                nodeOper.setDataAssociate(operPosition, EXPR_SNE_NULL, typeResu, nil);
            end else
            if (typeKind1 = -1) and (
                    (typeKind2 = TranslatorType.KIND_STRUCT) or
                    (typeKind2 = TranslatorType.KIND_ARRAY) or
                    (typeKind2 = TranslatorType.KIND_FUNC)) then begin
                typeResu := typeBoolean;
                owner.deleteNode(nodeArg1);
                nodeOper.setDataAssociate(operPosition, EXPR_SNE_NULL, typeResu, nil);
            end else
            if (typeKind1 = -1) and (typeKind2 = -1) then begin
                typeResu := typeBoolean;
                owner.deleteChildrens(nodeOper);
                nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu, false);
            end else
            case getCommonTypeKind(typeKind1, typeKind2) of
            TranslatorType.KIND_BOOLEAN: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeBoolean);
                nodeArg2 := insertTypeCast(nodeArg2, typeBoolean);
                if (nodeArg1.value = EXPR_VALUE_BOOLEAN) and
                        (nodeArg2.value = EXPR_VALUE_BOOLEAN) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu,
                            (nodeArg1.associate as BooleanAsObject).booleanValue() <>
                            (nodeArg2.associate as BooleanAsObject).booleanValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_SHORT: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeShort);
                nodeArg2 := insertTypeCast(nodeArg2, typeShort);
                nodeVal1 := nodeArg1.value;
                nodeVal2 := nodeArg2.value;
                if (nodeVal1 = EXPR_SANDB) and (nodeVal2 = EXPR_VALUE_INT) and
                        ((nodeArg2.associate as IntegerAsObject).shortValue() = 0) then begin
                    nodeArg1.getChild(0).setParent(nodeOper, 0);
                    nodeArg1.getChild(0).setParent(nodeOper, 1);
                    owner.deleteNode(nodeArg1);
                    owner.deleteNode(nodeArg2);
                    nodeOper.setDataAssociate(operPosition, EXPR_SNZ_TEST, typeResu, nil);
                end else
                if (nodeVal2 = EXPR_SANDB) and (nodeVal1 = EXPR_VALUE_INT) and
                        ((nodeArg1.associate as IntegerAsObject).shortValue() = 0) then begin
                    nodeArg2.getChild(0).setParent(nodeOper, 0);
                    nodeArg2.getChild(0).setParent(nodeOper, 1);
                    owner.deleteNode(nodeArg1);
                    owner.deleteNode(nodeArg2);
                    nodeOper.setDataAssociate(operPosition, EXPR_SNZ_TEST, typeResu, nil);
                end else
                if (nodeVal1 = EXPR_VALUE_INT) and (nodeVal2 = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu,
                            (nodeArg1.associate as IntegerAsObject).shortValue() <>
                            (nodeArg2.associate as IntegerAsObject).shortValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_INT: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeInt);
                nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                nodeVal1 := nodeArg1.value;
                nodeVal2 := nodeArg2.value;
                if (nodeVal1 = EXPR_SANDB) and (nodeVal2 = EXPR_VALUE_INT) and
                        ((nodeArg2.associate as IntegerAsObject).intValue() = 0) then begin
                    nodeArg1.getChild(0).setParent(nodeOper, 0);
                    nodeArg1.getChild(0).setParent(nodeOper, 1);
                    owner.deleteNode(nodeArg1);
                    owner.deleteNode(nodeArg2);
                    nodeOper.setDataAssociate(operPosition, EXPR_SNZ_TEST, typeResu, nil);
                end else
                if (nodeVal2 = EXPR_SANDB) and (nodeVal1 = EXPR_VALUE_INT) and
                        ((nodeArg1.associate as IntegerAsObject).intValue() = 0) then begin
                    nodeArg2.getChild(0).setParent(nodeOper, 0);
                    nodeArg2.getChild(0).setParent(nodeOper, 1);
                    owner.deleteNode(nodeArg1);
                    owner.deleteNode(nodeArg2);
                    nodeOper.setDataAssociate(operPosition, EXPR_SNZ_TEST, typeResu, nil);
                end else
                if (nodeVal1 = EXPR_VALUE_INT) and (nodeVal2 = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu,
                            (nodeArg1.associate as IntegerAsObject).intValue() <>
                            (nodeArg2.associate as IntegerAsObject).intValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_LONG: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                nodeVal1 := nodeArg1.value;
                nodeVal2 := nodeArg2.value;
                if (nodeVal1 = EXPR_SANDB) and (nodeVal2 = EXPR_VALUE_LONG) and
                        ((nodeArg2.associate as LongAsObject).longValue() = 0) then begin
                    nodeArg1.getChild(0).setParent(nodeOper, 0);
                    nodeArg1.getChild(0).setParent(nodeOper, 1);
                    owner.deleteNode(nodeArg1);
                    owner.deleteNode(nodeArg2);
                    nodeOper.setDataAssociate(operPosition, EXPR_SNZ_TEST, typeResu, nil);
                end else
                if (nodeVal2 = EXPR_SANDB) and (nodeVal1 = EXPR_VALUE_LONG) and
                        ((nodeArg1.associate as LongAsObject).longValue() = 0) then begin
                    nodeArg2.getChild(0).setParent(nodeOper, 0);
                    nodeArg2.getChild(0).setParent(nodeOper, 1);
                    owner.deleteNode(nodeArg1);
                    owner.deleteNode(nodeArg2);
                    nodeOper.setDataAssociate(operPosition, EXPR_SNZ_TEST, typeResu, nil);
                end else
                if (nodeVal1 = EXPR_VALUE_LONG) and (nodeVal2 = EXPR_VALUE_LONG) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu,
                            (nodeArg1.associate as LongAsObject).longValue() <>
                            (nodeArg2.associate as LongAsObject).longValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_ULTRA: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu,
                            ssesPack(ssesShr(sseiEquals(
                            (nodeArg1.associate as UltraAsObject).ultraValue(),
                            (nodeArg2.associate as UltraAsObject).ultraValue()), $08)) <> (-1));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_FLOAT: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeFloat);
                nodeArg2 := insertTypeCast(nodeArg2, typeFloat);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu, realCmpl(
                            (nodeArg1.associate as FloatAsObject).floatValue(),
                            (nodeArg2.associate as FloatAsObject).floatValue()) <> 0);
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_DOUBLE: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeDouble);
                nodeArg2 := insertTypeCast(nodeArg2, typeDouble);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu, realCmpl(
                            (nodeArg1.associate as DoubleAsObject).doubleValue(),
                            (nodeArg2.associate as DoubleAsObject).doubleValue()) <> 0);
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_REAL: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeReal);
                nodeArg2 := insertTypeCast(nodeArg2, typeReal);
                if (nodeArg1.value = EXPR_VALUE_REAL) and
                        (nodeArg2.value = EXPR_VALUE_REAL) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu, realCmpl(
                            (nodeArg1.associate as RealAsObject).realValue(),
                            (nodeArg2.associate as RealAsObject).realValue()) <> 0);
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_XVECTOR: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeXVector);
                nodeArg2 := insertTypeCast(nodeArg2, typeXVector);
                if (nodeArg1.value = EXPR_VALUE_XVECTOR) and
                        (nodeArg2.value = EXPR_VALUE_XVECTOR) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu,
                            ssesPack(ssesShr(ssefCmpe(
                            (nodeArg1.associate as XVectorAsObject).xvectorValue(),
                            (nodeArg2.associate as XVectorAsObject).xvectorValue()), $08)) <> -1);
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.QEQ: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_QEQ, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprRel(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_LONG) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu, mmxEquals(
                            (nodeArg1.associate as LongAsObject).longValue(),
                            (nodeArg2.associate as LongAsObject).longValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, sseiEquals(
                            (nodeArg1.associate as UltraAsObject).ultraValue(),
                            (nodeArg2.associate as UltraAsObject).ultraValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_FLOAT, TranslatorType.KIND_XVECTOR: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeXVector);
                nodeArg2 := insertTypeCast(nodeArg2, typeXVector);
                if (nodeArg1.value = EXPR_VALUE_XVECTOR) and
                        (nodeArg2.value = EXPR_VALUE_XVECTOR) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, ssefCmpe(
                            (nodeArg1.associate as XVectorAsObject).xvectorValue(),
                            (nodeArg2.associate as XVectorAsObject).xvectorValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.QNE: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_QNE, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprRel(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_LONG) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu, mmxEquals(
                            (nodeArg1.associate as LongAsObject).longValue(),
                            (nodeArg2.associate as LongAsObject).longValue()) xor (-1));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, sseiEquals(
                            (nodeArg1.associate as UltraAsObject).ultraValue(),
                            (nodeArg2.associate as UltraAsObject).ultraValue()) xor
                            ultraBuild(-1, -1));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_FLOAT, TranslatorType.KIND_XVECTOR: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeXVector);
                nodeArg2 := insertTypeCast(nodeArg2, typeXVector);
                if (nodeArg1.value = EXPR_VALUE_XVECTOR) and
                        (nodeArg2.value = EXPR_VALUE_XVECTOR) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, ssefCmpne(
                            (nodeArg1.associate as XVectorAsObject).xvectorValue(),
                            (nodeArg2.associate as XVectorAsObject).xvectorValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.OEQ: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_OEQ, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprRel(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, ssesEquals(
                            (nodeArg1.associate as UltraAsObject).ultraValue(),
                            (nodeArg2.associate as UltraAsObject).ultraValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        TranslatorLexer.ONE: begin
            if operandSize < TranslatorType.SIZE_64_BIT then begin
                raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
            end;
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_ONE, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprRel(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu, ssesEquals(
                            (nodeArg1.associate as UltraAsObject).ultraValue(),
                            (nodeArg2.associate as UltraAsObject).ultraValue()) xor
                            ultraBuild(-1, -1));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        else
            break;
        end;
        nodeOper.dataType := typeResu;
        nodeArg1 := nodeOper;
        typeArg1 := typeResu;
    until false;
    result := position;
end;

function TranslatorTreeBuilder.parseExprBAnd(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
var
    operPosition: int;
    nodeOper: SyntaxNode;
    nodeArg1: SyntaxNode;
    nodeArg2: SyntaxNode;
    typeResu: TypeDescriptor;
    typeArg1: TypeDescriptor;
    typeArg2: TypeDescriptor;
    owner: Tree;
begin
    position := parseExprEqual(lexemes, position, parent);
    nodeArg1 := parent.getChild(parent.getChildrensCount() - 1) as SyntaxNode;
    typeArg1 := nodeArg1.dataType;
    owner := parent.owner;
    repeat
        operPosition := position;
        case lexemes.getType(position) of
        TranslatorLexer.SANDB: begin
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_SANDB, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprEqual(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_BOOLEAN: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeBoolean);
                nodeArg2 := insertTypeCast(nodeArg2, typeBoolean);
                if (nodeArg1.value = EXPR_VALUE_BOOLEAN) and
                        (nodeArg2.value = EXPR_VALUE_BOOLEAN) then begin
                    {$BOOLEVAL ON}
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu,
                            (nodeArg1.associate as BooleanAsObject).booleanValue() and
                            (nodeArg2.associate as BooleanAsObject).booleanValue());
                    {$BOOLEVAL OFF}
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_SHORT: begin
                typeResu := typeShort;
                nodeArg1 := insertTypeCast(nodeArg1, typeShort);
                nodeArg2 := insertTypeCast(nodeArg2, typeShort);
                if (nodeArg1.value = EXPR_VALUE_INT) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResu, short(
                            (nodeArg1.associate as IntegerAsObject).shortValue() and
                            (nodeArg2.associate as IntegerAsObject).shortValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_INT: begin
                typeResu := typeInt;
                nodeArg1 := insertTypeCast(nodeArg1, typeInt);
                nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                if (nodeArg1.value = EXPR_VALUE_INT) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResu,
                            (nodeArg1.associate as IntegerAsObject).intValue() and
                            (nodeArg2.associate as IntegerAsObject).intValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_LONG) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu,
                            (nodeArg1.associate as LongAsObject).longValue() and
                            (nodeArg2.associate as LongAsObject).longValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu,
                            (nodeArg1.associate as UltraAsObject).ultraValue() and
                            (nodeArg2.associate as UltraAsObject).ultraValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        else
            break;
        end;
        nodeOper.dataType := typeResu;
        nodeArg1 := nodeOper;
        typeArg1 := typeResu;
    until false;
    result := position;
end;

function TranslatorTreeBuilder.parseExprBXor(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
var
    operPosition: int;
    nodeOper: SyntaxNode;
    nodeArg1: SyntaxNode;
    nodeArg2: SyntaxNode;
    typeResu: TypeDescriptor;
    typeArg1: TypeDescriptor;
    typeArg2: TypeDescriptor;
    owner: Tree;
begin
    position := parseExprBAnd(lexemes, position, parent);
    nodeArg1 := parent.getChild(parent.getChildrensCount() - 1) as SyntaxNode;
    typeArg1 := nodeArg1.dataType;
    owner := parent.owner;
    repeat
        operPosition := position;
        case lexemes.getType(position) of
        TranslatorLexer.SXORB: begin
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_SXORB, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprBAnd(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_BOOLEAN: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeBoolean);
                nodeArg2 := insertTypeCast(nodeArg2, typeBoolean);
                if (nodeArg1.value = EXPR_VALUE_BOOLEAN) and
                        (nodeArg2.value = EXPR_VALUE_BOOLEAN) then begin
                    {$BOOLEVAL ON}
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu,
                            (nodeArg1.associate as BooleanAsObject).booleanValue() xor
                            (nodeArg2.associate as BooleanAsObject).booleanValue());
                    {$BOOLEVAL OFF}
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_SHORT: begin
                typeResu := typeShort;
                nodeArg1 := insertTypeCast(nodeArg1, typeShort);
                nodeArg2 := insertTypeCast(nodeArg2, typeShort);
                if (nodeArg1.value = EXPR_VALUE_INT) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResu, short(
                            (nodeArg1.associate as IntegerAsObject).shortValue() xor
                            (nodeArg2.associate as IntegerAsObject).shortValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_INT: begin
                typeResu := typeInt;
                nodeArg1 := insertTypeCast(nodeArg1, typeInt);
                nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                if (nodeArg1.value = EXPR_VALUE_INT) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResu,
                            (nodeArg1.associate as IntegerAsObject).intValue() xor
                            (nodeArg2.associate as IntegerAsObject).intValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_LONG) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu,
                            (nodeArg1.associate as LongAsObject).longValue() xor
                            (nodeArg2.associate as LongAsObject).longValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu,
                            (nodeArg1.associate as UltraAsObject).ultraValue() xor
                            (nodeArg2.associate as UltraAsObject).ultraValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        else
            break;
        end;
        nodeOper.dataType := typeResu;
        nodeArg1 := nodeOper;
        typeArg1 := typeResu;
    until false;
    result := position;
end;

function TranslatorTreeBuilder.parseExprBOr(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
var
    operPosition: int;
    nodeOper: SyntaxNode;
    nodeArg1: SyntaxNode;
    nodeArg2: SyntaxNode;
    typeResu: TypeDescriptor;
    typeArg1: TypeDescriptor;
    typeArg2: TypeDescriptor;
    owner: Tree;
begin
    position := parseExprBXor(lexemes, position, parent);
    nodeArg1 := parent.getChild(parent.getChildrensCount() - 1) as SyntaxNode;
    typeArg1 := nodeArg1.dataType;
    owner := parent.owner;
    repeat
        operPosition := position;
        case lexemes.getType(position) of
        TranslatorLexer.SORB: begin
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_SORB, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprBXor(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_BOOLEAN: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeBoolean);
                nodeArg2 := insertTypeCast(nodeArg2, typeBoolean);
                if (nodeArg1.value = EXPR_VALUE_BOOLEAN) and
                        (nodeArg2.value = EXPR_VALUE_BOOLEAN) then begin
                    {$BOOLEVAL ON}
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu,
                            (nodeArg1.associate as BooleanAsObject).booleanValue() or
                            (nodeArg2.associate as BooleanAsObject).booleanValue());
                    {$BOOLEVAL OFF}
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_SHORT: begin
                typeResu := typeShort;
                nodeArg1 := insertTypeCast(nodeArg1, typeShort);
                nodeArg2 := insertTypeCast(nodeArg2, typeShort);
                if (nodeArg1.value = EXPR_VALUE_INT) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResu, short(
                            (nodeArg1.associate as IntegerAsObject).shortValue() or
                            (nodeArg2.associate as IntegerAsObject).shortValue()));
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_INT: begin
                typeResu := typeInt;
                nodeArg1 := insertTypeCast(nodeArg1, typeInt);
                nodeArg2 := insertTypeCast(nodeArg2, typeInt);
                if (nodeArg1.value = EXPR_VALUE_INT) and
                        (nodeArg2.value = EXPR_VALUE_INT) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResu,
                            (nodeArg1.associate as IntegerAsObject).intValue() or
                            (nodeArg2.associate as IntegerAsObject).intValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_LONG: begin
                typeResu := typeLong;
                nodeArg1 := insertTypeCast(nodeArg1, typeLong);
                nodeArg2 := insertTypeCast(nodeArg2, typeLong);
                if (nodeArg1.value = EXPR_VALUE_LONG) and
                        (nodeArg2.value = EXPR_VALUE_LONG) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResu,
                            (nodeArg1.associate as LongAsObject).longValue() or
                            (nodeArg2.associate as LongAsObject).longValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            TranslatorType.KIND_ULTRA: begin
                typeResu := typeUltra;
                nodeArg1 := insertTypeCast(nodeArg1, typeUltra);
                nodeArg2 := insertTypeCast(nodeArg2, typeUltra);
                if (nodeArg1.value = EXPR_VALUE_ULTRA) and
                        (nodeArg2.value = EXPR_VALUE_ULTRA) then begin
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResu,
                            (nodeArg1.associate as UltraAsObject).ultraValue() or
                            (nodeArg2.associate as UltraAsObject).ultraValue());
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        else
            break;
        end;
        nodeOper.dataType := typeResu;
        nodeArg1 := nodeOper;
        typeArg1 := typeResu;
    until false;
    result := position;
end;

function TranslatorTreeBuilder.parseExprLAnd(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
var
    operPosition: int;
    nodeOper: SyntaxNode;
    nodeArg1: SyntaxNode;
    nodeArg2: SyntaxNode;
    typeResu: TypeDescriptor;
    typeArg1: TypeDescriptor;
    typeArg2: TypeDescriptor;
    owner: Tree;
begin
    position := parseExprBOr(lexemes, position, parent);
    nodeArg1 := parent.getChild(parent.getChildrensCount() - 1) as SyntaxNode;
    typeArg1 := nodeArg1.dataType;
    owner := parent.owner;
    repeat
        operPosition := position;
        case lexemes.getType(position) of
        TranslatorLexer.SANDL: begin
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_SANDL, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprBOr(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_BOOLEAN: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeBoolean);
                nodeArg2 := insertTypeCast(nodeArg2, typeBoolean);
                if (nodeArg1.value = EXPR_VALUE_BOOLEAN) and
                        (nodeArg2.value = EXPR_VALUE_BOOLEAN) then begin
                    {$BOOLEVAL ON}
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu,
                            (nodeArg1.associate as BooleanAsObject).booleanValue() and
                            (nodeArg2.associate as BooleanAsObject).booleanValue());
                    {$BOOLEVAL OFF}
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        else
            break;
        end;
        nodeOper.dataType := typeResu;
        nodeArg1 := nodeOper;
        typeArg1 := typeResu;
    until false;
    result := position;
end;

function TranslatorTreeBuilder.parseExprLOr(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
var
    operPosition: int;
    nodeOper: SyntaxNode;
    nodeArg1: SyntaxNode;
    nodeArg2: SyntaxNode;
    typeResu: TypeDescriptor;
    typeArg1: TypeDescriptor;
    typeArg2: TypeDescriptor;
    owner: Tree;
begin
    position := parseExprLAnd(lexemes, position, parent);
    nodeArg1 := parent.getChild(parent.getChildrensCount() - 1) as SyntaxNode;
    typeArg1 := nodeArg1.dataType;
    owner := parent.owner;
    repeat
        operPosition := position;
        case lexemes.getType(position) of
        TranslatorLexer.SORL: begin
            nodeOper := owner.addNodeBefore(nodeArg1) as SyntaxNode;
            nodeOper.setDataAssociate(position, EXPR_SORL, nil, nil);
            nodeArg1.setParent(nodeOper, 0);
            position := parseExprLAnd(lexemes, position + 1, nodeOper);
            nodeArg2 := nodeOper.getChild(1) as SyntaxNode;
            typeArg2 := nodeArg2.dataType;
            case getCommonTypeKind(getTypeKind(typeArg1), getTypeKind(typeArg2)) of
            TranslatorType.KIND_BOOLEAN: begin
                typeResu := typeBoolean;
                nodeArg1 := insertTypeCast(nodeArg1, typeBoolean);
                nodeArg2 := insertTypeCast(nodeArg2, typeBoolean);
                if (nodeArg1.value = EXPR_VALUE_BOOLEAN) and
                        (nodeArg2.value = EXPR_VALUE_BOOLEAN) then begin
                    {$BOOLEVAL ON}
                    nodeOper.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResu,
                            (nodeArg1.associate as BooleanAsObject).booleanValue() or
                            (nodeArg2.associate as BooleanAsObject).booleanValue());
                    {$BOOLEVAL OFF}
                    owner.deleteChildrens(nodeOper);
                end;
            end;
            else
                raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
            end;
        end;
        else
            break;
        end;
        nodeOper.dataType := typeResu;
        nodeArg1 := nodeOper;
        typeArg1 := typeResu;
    until false;
    result := position;
end;

function TranslatorTreeBuilder.parseExprCond(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
{ Искали пасхальные яйца в этом исходном тексте? Вот они! }
var
    kindMania: int;
    kindDemen: int;
    operPosition: int;
    colonPosition: int;
    seWorld: SyntaxNode;
    nodeFring: SyntaxNode;
    nodeMania: SyntaxNode;
    nodeDemen: SyntaxNode;
    typeFring: TypeDescriptor;
    typeMania: TypeDescriptor;
    typeDemen: TypeDescriptor;
    typeResult: TypeDescriptor;
    owner: Tree;
begin
    position := parseExprLOr(lexemes, position, parent);
    if lexemes.getType(position) = TranslatorLexer.QUESTION_MARK then begin
        nodeFring := parent.getChild(parent.getChildrensCount() - 1) as SyntaxNode;
        typeFring := nodeFring.dataType;
        if (typeFring = nil) or (typeFring.kind <> TranslatorType.KIND_BOOLEAN) then begin
            raise CompileError.create(msgTypeMustBeBoolean, lexemes, position);
        end;
        owner := parent.owner;
        operPosition := position;
        seWorld := owner.addNodeBefore(nodeFring) as SyntaxNode;
        seWorld.setDataAssociate(position, EXPR_QUESTION, nil, nil);
        nodeFring.setParent(seWorld, 0);
        position := parseExprAssign(lexemes, position + 1, seWorld);
        if lexemes.getType(position) <> TranslatorLexer.COLON then begin
            raise CompileError.create(msgExpectedColon, lexemes, position);
        end;
        colonPosition := position;
        position := parseExprAssign(lexemes, position + 1, seWorld);
        nodeMania := seWorld.getChild(1) as SyntaxNode;
        nodeDemen := seWorld.getChild(2) as SyntaxNode;
        typeMania := nodeMania.dataType;
        typeDemen := nodeDemen.dataType;
        kindMania := getTypeKind(typeMania);
        kindDemen := getTypeKind(typeDemen);
        if ((kindMania = TranslatorType.KIND_STRUCT) or
                (kindMania = TranslatorType.KIND_ARRAY) or
                (kindMania = TranslatorType.KIND_FUNC)) and (
                (kindDemen = TranslatorType.KIND_STRUCT) or
                (kindDemen = TranslatorType.KIND_ARRAY) or
                (kindDemen = TranslatorType.KIND_FUNC)) then begin
            if typeDemen.possibleAssignTo(typeMania) then begin
                typeResult := typeMania;
            end else
            if typeMania.possibleAssignTo(typeDemen) then begin
                typeResult := typeDemen;
            end else begin
                raise CompileError.create(msgCannotApplyOperation, lexemes, colonPosition);
            end;
        end else
        if (kindDemen = -1) and (
                (kindMania = TranslatorType.KIND_STRUCT) or
                (kindMania = TranslatorType.KIND_ARRAY) or
                (kindMania = TranslatorType.KIND_FUNC)) then begin
            typeResult := typeMania;
        end else
        if (kindMania = -1) and (
                (kindDemen = TranslatorType.KIND_STRUCT) or
                (kindDemen = TranslatorType.KIND_ARRAY) or
                (kindDemen = TranslatorType.KIND_FUNC)) then begin
            typeResult := typeDemen;
        end else
        if (kindMania = -1) and (kindDemen = -1) then begin
            typeResult := nil;
            owner.deleteChildrens(seWorld);
            seWorld.setDataAssociate(operPosition, EXPR_VALUE_NULL, nil, nil);
        end else
        case getCommonTypeKind(kindMania, kindDemen) of
        TranslatorType.KIND_BOOLEAN: begin
            typeResult := typeBoolean;
            nodeMania := insertTypeCast(nodeMania, typeBoolean);
            nodeDemen := insertTypeCast(nodeDemen, typeBoolean);
            if (nodeFring.value = EXPR_VALUE_BOOLEAN) and
                    (nodeMania.value = EXPR_VALUE_BOOLEAN) and
                    (nodeDemen.value = EXPR_VALUE_BOOLEAN) then begin
                if (seWorld.associate as BooleanAsObject).booleanValue() = true then begin
                    seWorld.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResult,
                            nodeMania.associate);
                end else begin
                    seWorld.setDataAssociate(operPosition, EXPR_VALUE_BOOLEAN, typeResult,
                            nodeDemen.associate);
                end;
                owner.deleteChildrens(seWorld);
            end;
        end;
        TranslatorType.KIND_SHORT: begin
            typeResult := typeShort;
            nodeMania := insertTypeCast(nodeMania, typeShort);
            nodeDemen := insertTypeCast(nodeDemen, typeShort);
            if (nodeFring.value = EXPR_VALUE_BOOLEAN) and
                    (nodeMania.value = EXPR_VALUE_INT) and
                    (nodeDemen.value = EXPR_VALUE_INT) then begin
                if (seWorld.associate as BooleanAsObject).booleanValue() = true then begin
                    seWorld.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResult,
                            nodeMania.associate);
                end else begin
                    seWorld.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResult,
                            nodeDemen.associate);
                end;
                owner.deleteChildrens(seWorld);
            end;
        end;
        TranslatorType.KIND_INT: begin
            typeResult := typeInt;
            nodeMania := insertTypeCast(nodeMania, typeInt);
            nodeDemen := insertTypeCast(nodeDemen, typeInt);
            if (nodeFring.value = EXPR_VALUE_BOOLEAN) and
                    (nodeMania.value = EXPR_VALUE_INT) and
                    (nodeDemen.value = EXPR_VALUE_INT) then begin
                if (seWorld.associate as BooleanAsObject).booleanValue() = true then begin
                    seWorld.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResult,
                            nodeMania.associate);
                end else begin
                    seWorld.setDataAssociate(operPosition, EXPR_VALUE_INT, typeResult,
                            nodeDemen.associate);
                end;
                owner.deleteChildrens(seWorld);
            end;
        end;
        TranslatorType.KIND_LONG: begin
            typeResult := typeLong;
            nodeMania := insertTypeCast(nodeMania, typeLong);
            nodeDemen := insertTypeCast(nodeDemen, typeLong);
            if (nodeFring.value = EXPR_VALUE_BOOLEAN) and
                    (nodeMania.value = EXPR_VALUE_LONG) and
                    (nodeDemen.value = EXPR_VALUE_LONG) then begin
                if (seWorld.associate as BooleanAsObject).booleanValue() = true then begin
                    seWorld.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResult,
                            nodeMania.associate);
                end else begin
                    seWorld.setDataAssociate(operPosition, EXPR_VALUE_LONG, typeResult,
                            nodeDemen.associate);
                end;
                owner.deleteChildrens(seWorld);
            end;
        end;
        TranslatorType.KIND_ULTRA: begin
            typeResult := typeUltra;
            nodeMania := insertTypeCast(nodeMania, typeUltra);
            nodeDemen := insertTypeCast(nodeDemen, typeUltra);
            if (nodeFring.value = EXPR_VALUE_BOOLEAN) and
                    (nodeMania.value = EXPR_VALUE_ULTRA) and
                    (nodeDemen.value = EXPR_VALUE_ULTRA) then begin
                if (seWorld.associate as BooleanAsObject).booleanValue() = true then begin
                    seWorld.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResult,
                            nodeMania.associate);
                end else begin
                    seWorld.setDataAssociate(operPosition, EXPR_VALUE_ULTRA, typeResult,
                            nodeDemen.associate);
                end;
                owner.deleteChildrens(seWorld);
            end;
        end;
        TranslatorType.KIND_FLOAT: begin
            typeResult := typeFloat;
            nodeMania := insertTypeCast(nodeMania, typeFloat);
            nodeDemen := insertTypeCast(nodeDemen, typeFloat);
            if (nodeFring.value = EXPR_VALUE_BOOLEAN) and
                    (nodeMania.value = EXPR_VALUE_REAL) and
                    (nodeDemen.value = EXPR_VALUE_REAL) then begin
                if (seWorld.associate as BooleanAsObject).booleanValue() = true then begin
                    seWorld.setDataAssociate(operPosition, EXPR_VALUE_REAL, typeResult,
                            nodeMania.associate);
                end else begin
                    seWorld.setDataAssociate(operPosition, EXPR_VALUE_REAL, typeResult,
                            nodeDemen.associate);
                end;
                owner.deleteChildrens(seWorld);
            end;
        end;
        TranslatorType.KIND_DOUBLE: begin
            typeResult := typeDouble;
            nodeMania := insertTypeCast(nodeMania, typeDouble);
            nodeDemen := insertTypeCast(nodeDemen, typeDouble);
            if (nodeFring.value = EXPR_VALUE_BOOLEAN) and
                    (nodeMania.value = EXPR_VALUE_REAL) and
                    (nodeDemen.value = EXPR_VALUE_REAL) then begin
                if (seWorld.associate as BooleanAsObject).booleanValue() = true then begin
                    seWorld.setDataAssociate(operPosition, EXPR_VALUE_REAL, typeResult,
                            nodeMania.associate);
                end else begin
                    seWorld.setDataAssociate(operPosition, EXPR_VALUE_REAL, typeResult,
                            nodeDemen.associate);
                end;
                owner.deleteChildrens(seWorld);
            end;
        end;
        TranslatorType.KIND_REAL: begin
            typeResult := typeReal;
            nodeMania := insertTypeCast(nodeMania, typeReal);
            nodeDemen := insertTypeCast(nodeDemen, typeReal);
            if (nodeFring.value = EXPR_VALUE_BOOLEAN) and
                    (nodeMania.value = EXPR_VALUE_REAL) and
                    (nodeDemen.value = EXPR_VALUE_REAL) then begin
                if (seWorld.associate as BooleanAsObject).booleanValue() = true then begin
                    seWorld.setDataAssociate(operPosition, EXPR_VALUE_REAL, typeResult,
                            nodeMania.associate);
                end else begin
                    seWorld.setDataAssociate(operPosition, EXPR_VALUE_REAL, typeResult,
                            nodeDemen.associate);
                end;
                owner.deleteChildrens(seWorld);
            end;
        end;
        TranslatorType.KIND_XVECTOR: begin
            typeResult := typeXVector;
            nodeMania := insertTypeCast(nodeMania, typeXVector);
            nodeDemen := insertTypeCast(nodeDemen, typeXVector);
            if (nodeFring.value = EXPR_VALUE_BOOLEAN) and
                    (nodeMania.value = EXPR_VALUE_XVECTOR) and
                    (nodeDemen.value = EXPR_VALUE_XVECTOR) then begin
                if (seWorld.associate as BooleanAsObject).booleanValue() = true then begin
                    seWorld.setDataAssociate(operPosition, EXPR_VALUE_XVECTOR, typeResult,
                            nodeMania.associate);
                end else begin
                    seWorld.setDataAssociate(operPosition, EXPR_VALUE_XVECTOR, typeResult,
                            nodeDemen.associate);
                end;
                owner.deleteChildrens(seWorld);
            end;
        end;
        else
            raise CompileError.create(msgCannotApplyOperation, lexemes, operPosition);
        end;
        seWorld.dataType := typeResult;
    end;
    result := position;
end;

function TranslatorTreeBuilder.parseExprAssign(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
var
    nodeVal: int;
    nodeType: int;
    typeKind: int;
    operPosition: int;
    nodeOper: SyntaxNode;
    nodeLeft: SyntaxNode;
    nodeRight: SyntaxNode;
    typeLeft: TypeDescriptor;
    owner: Tree;
begin
    position := parseExprCond(lexemes, position, parent);
    case lexemes.getType(position) of
    TranslatorLexer.ASSIGN:
        nodeType := ASSIGN;
    TranslatorLexer.ASANDB:
        nodeType := ASSIGN_SANDB;
    TranslatorLexer.ASORB:
        nodeType := ASSIGN_SORB;
    TranslatorLexer.ASXORB:
        nodeType := ASSIGN_SXORB;
    TranslatorLexer.ASMULL:
        nodeType := ASSIGN_SMULL;
    TranslatorLexer.ASDIVS:
        nodeType := ASSIGN_SDIVS;
    TranslatorLexer.ASREMS:
        nodeType := ASSIGN_SREMS;
    TranslatorLexer.ASDIVU:
        nodeType := ASSIGN_SDIVU;
    TranslatorLexer.ASREMU:
        nodeType := ASSIGN_SREMU;
    TranslatorLexer.ASPLUS:
        nodeType := ASSIGN_SADD;
    TranslatorLexer.ASMINUS:
        nodeType := ASSIGN_SSUB;
    TranslatorLexer.ASSRA:
        nodeType := ASSIGN_SSRA;
    TranslatorLexer.ASSRL:
        nodeType := ASSIGN_SSRL;
    TranslatorLexer.ASSLL:
        nodeType := ASSIGN_SSLL;
    TranslatorLexer.AQMULL:
        nodeType := ASSIGN_QMULL;
    TranslatorLexer.AQMULH:
        nodeType := ASSIGN_QMULH;
    TranslatorLexer.AQMULHS:
        nodeType := ASSIGN_QMULHS;
    TranslatorLexer.AQDIV:
        nodeType := ASSIGN_QDIV;
    TranslatorLexer.AQADD:
        nodeType := ASSIGN_QADD;
    TranslatorLexer.AQADDS:
        nodeType := ASSIGN_QADDS;
    TranslatorLexer.AQADDUS:
        nodeType := ASSIGN_QADDUS;
    TranslatorLexer.AQSUB:
        nodeType := ASSIGN_QSUB;
    TranslatorLexer.AQSUBS:
        nodeType := ASSIGN_QSUBS;
    TranslatorLexer.AQSUBUS:
        nodeType := ASSIGN_QSUBUS;
    TranslatorLexer.AQSRA:
        nodeType := ASSIGN_QSRA;
    TranslatorLexer.AQSRL:
        nodeType := ASSIGN_QSRL;
    TranslatorLexer.AQSLL:
        nodeType := ASSIGN_QSLL;
    TranslatorLexer.AQGT:
        nodeType := ASSIGN_QGT;
    TranslatorLexer.AQGE:
        nodeType := ASSIGN_QGE;
    TranslatorLexer.AQLT:
        nodeType := ASSIGN_QLT;
    TranslatorLexer.AQLE:
        nodeType := ASSIGN_QLE;
    TranslatorLexer.AQEQ:
        nodeType := ASSIGN_QEQ;
    TranslatorLexer.AQNE:
        nodeType := ASSIGN_QNE;
    TranslatorLexer.AOMULL:
        nodeType := ASSIGN_OMULL;
    TranslatorLexer.AOMULH:
        nodeType := ASSIGN_OMULH;
    TranslatorLexer.AOMULHS:
        nodeType := ASSIGN_OMULHS;
    TranslatorLexer.AOADD:
        nodeType := ASSIGN_OADD;
    TranslatorLexer.AOADDS:
        nodeType := ASSIGN_OADDS;
    TranslatorLexer.AOADDUS:
        nodeType := ASSIGN_OADDUS;
    TranslatorLexer.AOSUB:
        nodeType := ASSIGN_OSUB;
    TranslatorLexer.AOSUBS:
        nodeType := ASSIGN_OSUBS;
    TranslatorLexer.AOSUBUS:
        nodeType := ASSIGN_OSUBUS;
    TranslatorLexer.AOSRA:
        nodeType := ASSIGN_OSRA;
    TranslatorLexer.AOSRL:
        nodeType := ASSIGN_OSRL;
    TranslatorLexer.AOSLL:
        nodeType := ASSIGN_OSLL;
    TranslatorLexer.AOGT:
        nodeType := ASSIGN_OGT;
    TranslatorLexer.AOGE:
        nodeType := ASSIGN_OGE;
    TranslatorLexer.AOLT:
        nodeType := ASSIGN_OLT;
    TranslatorLexer.AOLE:
        nodeType := ASSIGN_OLE;
    TranslatorLexer.AOEQ:
        nodeType := ASSIGN_OEQ;
    TranslatorLexer.AONE:
        nodeType := ASSIGN_ONE;
    else
        result := position;
        exit;
    end;
    nodeLeft := parent.getChild(parent.getChildrensCount() - 1) as SyntaxNode;
    nodeVal := nodeLeft.value;
    if (nodeVal <> EXPR_LOCAL_VARIABLE) and (nodeVal <> EXPR_GLOBAL_VARIABLE) and
            (nodeVal <> EXPR_FIELD) and (nodeVal <> EXPR_ARRAY) then begin
        raise CompileError.create(msgOperationApplicableOnlyToVar, lexemes, position);
    end;
    typeLeft := nodeLeft.dataType;
    if typeLeft = nil then begin
        raise CompileError.create(msgCannotAssignToNull, lexemes, position);
    end;
    typeKind := typeLeft.kind;
    case nodeType of
    ASSIGN_SMULL, ASSIGN_SDIVS, ASSIGN_SREMS, ASSIGN_SDIVU, ASSIGN_SREMU, ASSIGN_SADD, ASSIGN_SSUB:
        if (typeKind <> TranslatorType.KIND_CHAR) and
                (typeKind <> TranslatorType.KIND_BYTE) and
                (typeKind <> TranslatorType.KIND_SHORT) and
                (typeKind <> TranslatorType.KIND_INT) and
                (typeKind <> TranslatorType.KIND_LONG) and
                (typeKind <> TranslatorType.KIND_FLOAT) and
                (typeKind <> TranslatorType.KIND_DOUBLE) and
                (typeKind <> TranslatorType.KIND_REAL) then begin
            raise CompileError.create(msgCannotApplyOperation, lexemes, position);
        end;
    ASSIGN_SSLL, ASSIGN_SSRA, ASSIGN_SSRL:
        if (typeKind <> TranslatorType.KIND_CHAR) and
                (typeKind <> TranslatorType.KIND_BYTE) and
                (typeKind <> TranslatorType.KIND_SHORT) and
                (typeKind <> TranslatorType.KIND_INT) and
                (typeKind <> TranslatorType.KIND_LONG) then begin
            raise CompileError.create(msgCannotApplyOperation, lexemes, position);
        end;
    ASSIGN_SANDB, ASSIGN_SXORB, ASSIGN_SORB:
        if (typeKind <> TranslatorType.KIND_BOOLEAN) and
                (typeKind <> TranslatorType.KIND_CHAR) and
                (typeKind <> TranslatorType.KIND_BYTE) and
                (typeKind <> TranslatorType.KIND_SHORT) and
                (typeKind <> TranslatorType.KIND_INT) and
                (typeKind <> TranslatorType.KIND_LONG) and
                (typeKind <> TranslatorType.KIND_ULTRA) then begin
            raise CompileError.create(msgCannotApplyOperation, lexemes, position);
        end;
    ASSIGN_QMULL, ASSIGN_QADD, ASSIGN_QSUB: begin
        if operandSize < TranslatorType.SIZE_64_BIT then begin
            raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
        end;
        if (typeKind <> TranslatorType.KIND_LONG) and
                (typeKind <> TranslatorType.KIND_ULTRA) and
                (typeKind <> TranslatorType.KIND_XVECTOR) then begin
            raise CompileError.create(msgCannotApplyOperation, lexemes, position);
        end;
    end;
    ASSIGN_QMULH, ASSIGN_QSLL, ASSIGN_QSRA, ASSIGN_QSRL,
    ASSIGN_QGT, ASSIGN_QGE, ASSIGN_QLT, ASSIGN_QLE, ASSIGN_QEQ, ASSIGN_QNE: begin
        if operandSize < TranslatorType.SIZE_64_BIT then begin
            raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
        end;
        if (typeKind <> TranslatorType.KIND_LONG) and
                (typeKind <> TranslatorType.KIND_ULTRA) then begin
            raise CompileError.create(msgCannotApplyOperation, lexemes, position);
        end;
    end;
    ASSIGN_QMULHS, ASSIGN_QADDS, ASSIGN_QADDUS, ASSIGN_QSUBS, ASSIGN_QSUBUS: begin
        if operandSize < TranslatorType.SIZE_64_BIT then begin
            raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
        end;
        if typeKind <> TranslatorType.KIND_LONG then begin
            raise CompileError.create(msgCannotApplyOperation, lexemes, position);
        end;
    end;
    ASSIGN_QDIV: begin
        if operandSize < TranslatorType.SIZE_64_BIT then begin
            raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
        end;
        if typeKind <> TranslatorType.KIND_XVECTOR then begin
            raise CompileError.create(msgCannotApplyOperation, lexemes, position);
        end;
    end;
    ASSIGN_OMULL, ASSIGN_OMULH, ASSIGN_OMULHS, ASSIGN_OADD, ASSIGN_OADDS, ASSIGN_OADDUS,
    ASSIGN_OSUB, ASSIGN_OSUBS, ASSIGN_OSUBUS, ASSIGN_OSLL, ASSIGN_OSRA, ASSIGN_OSRL,
    ASSIGN_OGT, ASSIGN_OGE, ASSIGN_OLT, ASSIGN_OLE, ASSIGN_OEQ, ASSIGN_ONE: begin
        if operandSize < TranslatorType.SIZE_64_BIT then begin
            raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
        end;
        if typeKind <> TranslatorType.KIND_ULTRA then begin
            raise CompileError.create(msgCannotApplyOperation, lexemes, position);
        end;
    end;
    end;
    owner := parent.owner;
    operPosition := position;
    nodeOper := owner.addNodeBefore(nodeLeft) as SyntaxNode;
    nodeOper.setDataAssociate(position, nodeType, typeLeft, nil);
    nodeLeft.setParent(nodeOper, 0);
    position := parseExprAssign(lexemes, position + 1, nodeOper);
    nodeRight := nodeOper.getChild(1) as SyntaxNode;
    case nodeType of
    ASSIGN_SSLL, ASSIGN_SSRA, ASSIGN_SSRL,
    ASSIGN_QSLL, ASSIGN_QSRA, ASSIGN_QSRL,
    ASSIGN_OSLL, ASSIGN_OSRA, ASSIGN_OSRL:
        if operandSize < TranslatorType.SIZE_32_BIT then begin
            typeLeft := typeShort;
        end else begin
            typeLeft := typeInt;
        end;
    ASSIGN_SREMS, ASSIGN_SREMU:
        case typeKind of
        TranslatorType.KIND_FLOAT, TranslatorType.KIND_DOUBLE:
            typeLeft := typeReal;
        end;
    end;
    if not possibleAssign(typeLeft, nodeRight.dataType, nodeRight.associate) then begin
        raise CompileError.create(msgCannotAssignDataType, lexemes, operPosition);
    end;
    insertTypeCast(nodeRight, typeLeft);
    result := position;
end;

function TranslatorTreeBuilder.parseLocalVar(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
begin
    position := parseForExpr(lexemes, position, parent, false);
    if lexemes.getType(position) <> TranslatorLexer.SEMICOLON then begin
        raise CompileError.create(msgExpectedSemicolon, lexemes, position);
    end;
    result := position + 1;
end;

function TranslatorTreeBuilder.parseDispose(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
var
    operNode: SyntaxNode;
begin
    operNode := parent.owner.addChildLast(parent) as SyntaxNode;
    operNode.setDataAssociate(position - 1, OPERATOR_DISPOSE, nil, nil);
    position := parseExprAssign(lexemes, position, operNode);
    case getTypeKind((operNode.getChild(0) as SyntaxNode).dataType) of
    TranslatorType.KIND_ARRAY, TranslatorType.KIND_STRUCT: ;
    else
        raise CompileError.create(msgTypeMustBeStruct, lexemes, position);
    end;
    if lexemes.getType(position) <> TranslatorLexer.SEMICOLON then begin
        raise CompileError.create(msgExpectedSemicolon, lexemes, position);
    end;
    result := position + 1;
end;

function TranslatorTreeBuilder.parseWith(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
var
    currWithVarNum: int;
    vtyp: TypeDescriptor;
    local: LocalVariable;
    operNode: SyntaxNode;
    wvarNode: SyntaxNode;
    owner: Tree;
begin
    if lexemes.getType(position) <> TranslatorLexer.OPENED_PARENTHESIS then begin
        raise CompileError.create(msgExpectedOpenedParenthesis, lexemes, position);
    end;
    owner := parent.owner;
    currWithVarNum := self.currWithVarNum;
    operNode := owner.addChildLast(parent) as SyntaxNode;
    operNode.setDataAssociate(position - 1, OPERATOR_WITH, nil, nil);
    repeat
        inc(position);
        wvarNode := owner.addChildLast(operNode) as SyntaxNode;
        wvarNode.setDataAssociate(-1, NULL, nil, nil);
        position := parseExprAssign(lexemes, position, wvarNode);
        vtyp := (wvarNode.getChild(0) as SyntaxNode).dataType;
        if (vtyp = nil) or (vtyp.kind <> TranslatorType.KIND_STRUCT) then begin
            raise CompileError.create(msgTypeMustBeStruct, lexemes, position);
        end;
        local := TranslatorLocalVariable.create(vtyp, stringToUTF16(
                'with.' + intToString(currWithVarNum)));
        inc(currWithVarNum);
        wvarNode.setDataAssociate(-1, BLOCK_WITH, nil, local);
    until lexemes.getType(position) <> TranslatorLexer.COMMA;
    if lexemes.getType(position) <> TranslatorLexer.CLOSED_PARENTHESIS then begin
        raise CompileError.create(msgExpectedClosedParenthesis, lexemes, position);
    end;
    self.currWithVarNum := currWithVarNum;
    result := parseOperator(lexemes, position + 1, operNode);
end;

function TranslatorTreeBuilder.parseTry(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
var
    operPosition: int;
    element: NamedObject;
    operNode: SyntaxNode;
    bodyNode: SyntaxNode;
    fretNode: SyntaxNode;
    owner: Tree;
begin
    operNode := parent;
    repeat
        if operNode.value = BLOCK_FINALLY_START then begin
            raise CompileError.create(msgFinallyTryNotAllowed, lexemes, position - 1);
        end;
        operNode := operNode.parent as SyntaxNode;
    until operNode = nil;
    if lexemes.getType(position) <> TranslatorLexer.OPENED_CURLY_BRACKET then begin
        raise CompileError.create(msgExpectedOpenedCurlyBracket, lexemes, position);
    end;
    owner := parent.owner;
    operNode := owner.addChildLast(parent) as SyntaxNode;
    operNode.setDataAssociate(position - 1, OPERATOR_TRY_CATCH, nil, nil);
    bodyNode := owner.addChildLast(operNode) as SyntaxNode;
    bodyNode.setDataAssociate(position, OPERATOR_BLOCK, nil, nil);
    position := parseOpBlock(lexemes, position + 1, bodyNode);
    if lexemes.getType(position) <> TranslatorLexer.CLOSED_CURLY_BRACKET then begin
        raise CompileError.create(msgExpectedClosedCurlyBracket, lexemes, position);
    end;
    inc(position);
    case lexemes.getType(position) of
    TranslatorLexer.KW_CATCH: repeat
        operPosition := position;
        inc(position);
        if lexemes.getType(position) <> TranslatorLexer.OPENED_PARENTHESIS then begin
            raise CompileError.create(msgExpectedOpenedParenthesis, lexemes, position);
        end;
        inc(position);
        element := parseIdentifier(lexemes, position, parent);
        if not (element is GlobalException) then begin
            raise CompileError.create(msgExpectedIdentifierOfException, lexemes, position);
        end;
        position := stayPosition;
        if lexemes.getType(position) <> TranslatorLexer.CLOSED_PARENTHESIS then begin
            raise CompileError.create(msgExpectedClosedParenthesis, lexemes, position);
        end;
        inc(position);
        if lexemes.getType(position) <> TranslatorLexer.OPENED_CURLY_BRACKET then begin
            raise CompileError.create(msgExpectedOpenedCurlyBracket, lexemes, position);
        end;
        bodyNode := owner.addChildLast(operNode) as SyntaxNode;
        bodyNode.setDataAssociate(operPosition, BLOCK_CATCH, nil, element as GlobalException);
        position := parseOpBlock(lexemes, position + 1, bodyNode);
        if lexemes.getType(position) <> TranslatorLexer.CLOSED_CURLY_BRACKET then begin
            raise CompileError.create(msgExpectedClosedCurlyBracket, lexemes, position);
        end;
        inc(position);
    until lexemes.getType(position) <> TranslatorLexer.KW_CATCH;
    TranslatorLexer.KW_FINALLY: begin
        operNode.value := OPERATOR_TRY_FINALLY;
        operPosition := position;
        inc(position);
        if lexemes.getType(position) <> TranslatorLexer.OPENED_CURLY_BRACKET then begin
            raise CompileError.create(msgExpectedOpenedCurlyBracket, lexemes, position);
        end;
        bodyNode := owner.addChildLast(operNode) as SyntaxNode;
        bodyNode.setDataAssociate(operPosition, BLOCK_FINALLY_START, nil, nil);
        position := parseOpBlock(lexemes, position + 1, bodyNode);
        if lexemes.getType(position) <> TranslatorLexer.CLOSED_CURLY_BRACKET then begin
            raise CompileError.create(msgExpectedClosedCurlyBracket, lexemes, position);
        end;
        fretNode := owner.addChildLast(bodyNode) as SyntaxNode;
        fretNode.setDataAssociate(position, BLOCK_FINALLY_RETURN, nil, nil);
        inc(position);
    end;
    else
        raise CompileError.create(msgExpectedKeywordCatchFinally, lexemes, position);
    end;
    result := position;
end;

function TranslatorTreeBuilder.parseBreak(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
var
    operPosition: int;
    operNode: SyntaxNode;
    asocNode: BuilderNode;
    labelName: UnicodeString;
begin
    operPosition := position - 1;
    asocNode := parent as BuilderNode;
    if lexemes.getType(position) = TranslatorLexer.IDENTIFIER then begin
        labelName := lexemes.getValueUString(position);
        inc(position);
        repeat
            case asocNode.value of
            BLOCK_FINALLY_START: begin
                raise CompileError.create(msgFinallyBreakNotAllowed, lexemes, position);
            end;
            OPERATOR_LABEL: begin
                if asocNode.labelName = labelName then begin
                    break;
                end;
            end;
            end;
            asocNode := asocNode.parent as BuilderNode;
            if asocNode = nil then begin
                raise CompileError.create(msgBreakLabelNotFound, lexemes, position);
            end;
        until false;
    end else begin
        repeat
            case asocNode.value of
            BLOCK_FINALLY_START: begin
                raise CompileError.create(msgFinallyBreakNotAllowed, lexemes, position);
            end;
            OPERATOR_DO, OPERATOR_FOR, OPERATOR_WHILE, OPERATOR_SWITCH: begin
                break;
            end;
            end;
            asocNode := asocNode.parent as BuilderNode;
            if asocNode = nil then begin
                raise CompileError.create(msgBreakUnlabeledNotAllowed, lexemes, position);
            end;
        until false;
    end;
    if lexemes.getType(position) <> TranslatorLexer.SEMICOLON then begin
        raise CompileError.create(msgExpectedSemicolon, lexemes, position);
    end;
    operNode := parent.owner.addChildLast(parent) as SyntaxNode;
    operNode.setDataAssociate(operPosition, OPERATOR_BREAK, nil, asocNode);
    result := position + 1;
end;

function TranslatorTreeBuilder.parseContinue(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
var
    operPosition: int;
    operNode: SyntaxNode;
    asocNode: BuilderNode;
    targNode: BuilderNode;
    labelName: UnicodeString;
begin
    operPosition := position - 1;
    asocNode := parent as BuilderNode;
    if lexemes.getType(position) = TranslatorLexer.IDENTIFIER then begin
        labelName := lexemes.getValueUString(position);
        inc(position);
        repeat
            case asocNode.value of
            BLOCK_FINALLY_START: begin
                raise CompileError.create(msgFinallyBreakNotAllowed, lexemes, position);
            end;
            OPERATOR_LABEL: begin
                if asocNode.labelName = labelName then begin
                    if asocNode.getChildrensCount() <= 0 then begin
                        raise CompileError.create(msgContinueLabeledNotAllowed, lexemes, position);
                    end;
                    targNode := asocNode.getChild(0) as BuilderNode;
                    case targNode.value of
                    OPERATOR_DO, OPERATOR_FOR, OPERATOR_WHILE: begin
                        asocNode := targNode;
                        break;
                    end;
                    else
                        raise CompileError.create(msgContinueLabeledNotAllowed, lexemes, position);
                    end;
                end;
            end;
            end;
            asocNode := asocNode.parent as BuilderNode;
            if asocNode = nil then begin
                raise CompileError.create(msgContinueLabelNotFound, lexemes, position);
            end;
        until false;
    end else begin
        repeat
            case asocNode.value of
            BLOCK_FINALLY_START: begin
                raise CompileError.create(msgFinallyBreakNotAllowed, lexemes, position);
            end;
            OPERATOR_DO, OPERATOR_FOR, OPERATOR_WHILE: begin
                break;
            end;
            end;
            asocNode := asocNode.parent as BuilderNode;
            if asocNode = nil then begin
                raise CompileError.create(msgContinueUnlabeledNotAllowed, lexemes, position);
            end;
        until false;
    end;
    if lexemes.getType(position) <> TranslatorLexer.SEMICOLON then begin
        raise CompileError.create(msgExpectedSemicolon, lexemes, position);
    end;
    operNode := parent.owner.addChildLast(parent) as SyntaxNode;
    operNode.setDataAssociate(operPosition, OPERATOR_CONTINUE, nil, asocNode);
    result := position + 1;
end;

function TranslatorTreeBuilder.parseIf(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
var
    operNode: SyntaxNode;
    exprType: TypeDescriptor;
begin
    if lexemes.getType(position) <> TranslatorLexer.OPENED_PARENTHESIS then begin
        raise CompileError.create(msgExpectedOpenedParenthesis, lexemes, position);
    end;
    operNode := parent.owner.addChildLast(parent) as SyntaxNode;
    operNode.setDataAssociate(position - 1, OPERATOR_IF, nil, nil);
    position := parseExprAssign(lexemes, position + 1, operNode);
    exprType := (operNode.getChild(0) as SyntaxNode).dataType;
    if getTypeKind(exprType) <> TranslatorType.KIND_BOOLEAN then begin
        raise CompileError.create(msgTypeMustBeBoolean, lexemes, position);
    end;
    if lexemes.getType(position) <> TranslatorLexer.CLOSED_PARENTHESIS then begin
        raise CompileError.create(msgExpectedClosedParenthesis, lexemes, position);
    end;
    position := parseOperator(lexemes, position + 1, operNode);
    if lexemes.getType(position) = TranslatorLexer.KW_ELSE then begin
        position := parseOperator(lexemes, position + 1, operNode);
    end;
    result := position;
end;

function TranslatorTreeBuilder.parseSwitch(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
var
    presentDefault: boolean;
    caseIntValue: int;
    exprTypeKind: int;
    operPosition: int;
    operNode: SyntaxNode;
    exprNode: SyntaxNode;
    exprType: TypeDescriptor;
    caseValue: GlobalConstant;
    presentCases: Vector;
    where: Namespace;
    owner: Tree;
begin
    if lexemes.getType(position) <> TranslatorLexer.OPENED_PARENTHESIS then begin
        raise CompileError.create(msgExpectedOpenedParenthesis, lexemes, position);
    end;
    owner := parent.owner;
    operPosition := position - 1;
    operNode := owner.addChildLast(parent) as SyntaxNode;
    operNode.setDataAssociate(operPosition, OPERATOR_SWITCH, nil, nil);
    position := parseExprAssign(lexemes, position + 1, operNode);
    exprNode := operNode.getChild(0) as SyntaxNode;
    exprType := exprNode.dataType;
    exprTypeKind := getTypeKind(exprType);
    if operandSize < TranslatorType.SIZE_32_BIT then begin
        case exprTypeKind of
        TranslatorType.KIND_BYTE, TranslatorType.KIND_SHORT: begin
            exprType := typeShort;
            exprTypeKind := exprType.kind;
            insertTypeCast(exprNode, exprType);
        end;
        TranslatorType.KIND_CHAR: ;
        else
            raise CompileError.create(msgTypeMustBeShort, lexemes, position);
        end;
    end else begin
        if not possibleAssign(typeInt, exprType, exprNode.associate) then begin
            raise CompileError.create(msgTypeMustBeInt, lexemes, position);
        end;
        exprType := typeInt;
        exprTypeKind := exprType.kind;
        insertTypeCast(exprNode, exprType);
    end;
    if lexemes.getType(position) <> TranslatorLexer.CLOSED_PARENTHESIS then begin
        raise CompileError.create(msgExpectedClosedParenthesis, lexemes, position);
    end;
    inc(position);
    if lexemes.getType(position) <> TranslatorLexer.OPENED_CURLY_BRACKET then begin
        raise CompileError.create(msgExpectedOpenedCurlyBracket, lexemes, position);
    end;
    inc(position);
    where := ((owner.root as SyntaxNode).associate as GlobalFunction).owner;
    presentDefault := false;
    presentCases := Vector.create();
    try
        repeat
            operPosition := position;
            case lexemes.getType(position) of
            TranslatorLexer.KW_CASE: begin
                caseValue := parseConst(where, position + 1);
                position := stayPosition;
                if not possibleAssign(exprTypeKind, caseValue) then begin
                    raise CompileError.create(msgCannotAssignDataType, lexemes, position);
                end;
                caseIntValue := caseValue.intValue;
                if presentCases.contains(caseIntValue) then begin
                    raise CompileError.create(msgSwitchCaseValueAlreadyPresent, lexemes, position);
                end;
                if lexemes.getType(position) <> TranslatorLexer.COLON then begin
                    raise CompileError.create(msgExpectedColon, lexemes, position);
                end;
                presentCases.addElement(caseIntValue);
                exprNode := owner.addChildLast(operNode) as SyntaxNode;
                exprNode.setDataAssociate(operPosition, BLOCK_CASE, nil, caseIntValue);
                position := parseOpBlock(lexemes, position + 1, operNode);
            end;
            TranslatorLexer.KW_DEFAULT: begin
                inc(position);
                if presentDefault then begin
                    raise CompileError.create(msgSwitchDefaultAlreadyPresent, lexemes, position);
                end;
                if lexemes.getType(position) <> TranslatorLexer.COLON then begin
                    raise CompileError.create(msgExpectedColon, lexemes, position);
                end;
                presentDefault := true;
                exprNode := owner.addChildLast(operNode) as SyntaxNode;
                exprNode.setDataAssociate(operPosition, BLOCK_DEFAULT, nil, nil);
                position := parseOpBlock(lexemes, position + 1, operNode);
            end;
            else
                break;
            end;
        until false;
        if not presentDefault then begin
            exprNode := owner.addChildLast(operNode) as SyntaxNode;
            exprNode.setDataAssociate(-1, BLOCK_DEFAULT, nil, nil);
        end;
    finally
        presentCases.free();
    end;
    if lexemes.getType(position) <> TranslatorLexer.CLOSED_CURLY_BRACKET then begin
        raise CompileError.create(msgExpectedClosedCurlyBracket, lexemes, position);
    end;
    result := position + 1;
end;

function TranslatorTreeBuilder.parseDo(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
var
    operNode: SyntaxNode;
    exprType: TypeDescriptor;
begin
    operNode := parent.owner.addChildLast(parent) as SyntaxNode;
    operNode.setDataAssociate(position - 1, OPERATOR_DO, nil, nil);
    position := parseOperator(lexemes, position, operNode);
    if lexemes.getType(position) <> TranslatorLexer.KW_WHILE then begin
        raise CompileError.create(msgExpectedKeywordWhile, lexemes, position);
    end;
    inc(position);
    if lexemes.getType(position) <> TranslatorLexer.OPENED_PARENTHESIS then begin
        raise CompileError.create(msgExpectedOpenedParenthesis, lexemes, position);
    end;
    position := parseExprAssign(lexemes, position + 1, operNode);
    exprType := (operNode.getChild(1) as SyntaxNode).dataType;
    if getTypeKind(exprType) <> TranslatorType.KIND_BOOLEAN then begin
        raise CompileError.create(msgTypeMustBeBoolean, lexemes, position);
    end;
    if lexemes.getType(position) <> TranslatorLexer.CLOSED_PARENTHESIS then begin
        raise CompileError.create(msgExpectedClosedParenthesis, lexemes, position);
    end;
    inc(position);
    if lexemes.getType(position) <> TranslatorLexer.SEMICOLON then begin
        raise CompileError.create(msgExpectedSemicolon, lexemes, position);
    end;
    result := position + 1;
end;

function TranslatorTreeBuilder.parseFor(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
var
    count: int;
    operNode: SyntaxNode;
    exprNode: SyntaxNode;
    stepNode: SyntaxNode;
    bodyNode: SyntaxNode;
    owner: Tree;
begin
    if lexemes.getType(position) <> TranslatorLexer.OPENED_PARENTHESIS then begin
        raise CompileError.create(msgExpectedOpenedParenthesis, lexemes, position);
    end;
    owner := parent.owner;
    operNode := owner.addChildLast(parent) as SyntaxNode;
    operNode.setDataAssociate(position - 1, OPERATOR_FOR, nil, nil);
    inc(position);
    if lexemes.getType(position) <> TranslatorLexer.SEMICOLON then begin
        repeat
            position := parseForExpr(lexemes, position, operNode, false);
            if lexemes.getType(position) <> TranslatorLexer.COMMA then begin
                break;
            end;
            inc(position);
        until false;
        if lexemes.getType(position) <> TranslatorLexer.SEMICOLON then begin
            raise CompileError.create(msgExpectedSemicolon, lexemes, position);
        end;
    end;
    inc(position);
    count := operNode.getChildrensCount();
    if lexemes.getType(position) = TranslatorLexer.SEMICOLON then begin
        exprNode := owner.addChildLast(operNode) as SyntaxNode;
        exprNode.setDataAssociate(-1, EXPR_VALUE_BOOLEAN, typeBoolean, true);
    end else begin
        position := parseExprAssign(lexemes, position, operNode);
        exprNode := operNode.getChild(count) as SyntaxNode;
        if getTypeKind(exprNode.dataType) <> TranslatorType.KIND_BOOLEAN then begin
            raise CompileError.create(msgTypeMustBeBoolean, lexemes, position);
        end;
        if lexemes.getType(position) <> TranslatorLexer.SEMICOLON then begin
            raise CompileError.create(msgExpectedSemicolon, lexemes, position);
        end;
    end;
    inc(position);
    stepNode := owner.addChildLast(operNode) as SyntaxNode;
    stepNode.setDataAssociate(-1, OPERATOR_BLOCK, nil, nil);
    if lexemes.getType(position) <> TranslatorLexer.CLOSED_PARENTHESIS then begin
        repeat
            position := parseForExpr(lexemes, position, stepNode, true);
            if lexemes.getType(position) <> TranslatorLexer.COMMA then begin
                break;
            end;
            inc(position);
        until false;
        if lexemes.getType(position) <> TranslatorLexer.CLOSED_PARENTHESIS then begin
            raise CompileError.create(msgExpectedClosedParenthesis, lexemes, position);
        end;
    end;
    position := parseOperator(lexemes, position + 1, operNode);
    bodyNode := operNode.getChild(count + 2) as SyntaxNode;
    bodyNode.index := count;
    stepNode.index := count + 1;
    exprNode.index := count + 2;
    result := position;
end;

function TranslatorTreeBuilder.parseWhile(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
var
    operNode: SyntaxNode;
    exprType: TypeDescriptor;
begin
    if lexemes.getType(position) <> TranslatorLexer.OPENED_PARENTHESIS then begin
        raise CompileError.create(msgExpectedOpenedParenthesis, lexemes, position);
    end;
    operNode := parent.owner.addChildLast(parent) as SyntaxNode;
    operNode.setDataAssociate(position - 1, OPERATOR_WHILE, nil, nil);
    position := parseExprAssign(lexemes, position + 1, operNode);
    exprType := (operNode.getChild(0) as SyntaxNode).dataType;
    if getTypeKind(exprType) <> TranslatorType.KIND_BOOLEAN then begin
        raise CompileError.create(msgTypeMustBeBoolean, lexemes, position);
    end;
    if lexemes.getType(position) <> TranslatorLexer.CLOSED_PARENTHESIS then begin
        raise CompileError.create(msgExpectedClosedParenthesis, lexemes, position);
    end;
    position := parseOperator(lexemes, position + 1, operNode);
    operNode.getChild(1).index := 0;
    result := position;
end;

function TranslatorTreeBuilder.parseThrow(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
var
    operPosition: int;
    element: NamedObject;
    operNode: SyntaxNode;
begin
    operPosition := position - 1;
    element := parseIdentifier(lexemes, position, parent);
    if not (element is GlobalException) then begin
        raise CompileError.create(msgExpectedIdentifierOfException, lexemes, position);
    end;
    position := stayPosition;
    if lexemes.getType(position) <> TranslatorLexer.SEMICOLON then begin
        raise CompileError.create(msgExpectedSemicolon, lexemes, position);
    end;
    operNode := parent.owner.addChildLast(parent) as SyntaxNode;
    operNode.setDataAssociate(operPosition, OPERATOR_THROW, nil, element as GlobalException);
    result := position + 1;
end;

function TranslatorTreeBuilder.parseReturn(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
var
    operPosition: int;
    operNode: SyntaxNode;
    exprNode: SyntaxNode;
    returnType: TypeDescriptor;
    owner: Tree;
begin
    operPosition := position - 1;
    operNode := parent;
    repeat
        if operNode.value = BLOCK_FINALLY_START then begin
            raise CompileError.create(msgFinallyBreakNotAllowed, lexemes, operPosition);
        end;
        operNode := operNode.parent as SyntaxNode;
    until operNode = nil;
    owner := parent.owner;
    operNode := owner.addChildLast(parent) as SyntaxNode;
    operNode.setDataAssociate(operPosition, OPERATOR_RETURN, nil, nil);
    returnType := ((owner.root as SyntaxNode).associate as
            GlobalFunction).functionType.getReturnType();
    if returnType.kind <> TranslatorType.KIND_VOID then begin
        position := parseExprAssign(lexemes, position, operNode);
        exprNode := operNode.getChild(0) as SyntaxNode;
        if not possibleAssign(returnType, exprNode.dataType, exprNode.associate) then begin
            raise CompileError.create(msgCannotAssignDataType, lexemes, position);
        end;
        insertTypeCast(exprNode, returnType);
    end;
    if lexemes.getType(position) <> TranslatorLexer.SEMICOLON then begin
        raise CompileError.create(msgExpectedSemicolon, lexemes, position);
    end;
    result := position + 1;
end;

function TranslatorTreeBuilder.parseOpBlock(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
var
    newPosition: int;
begin
    repeat
        newPosition := parseStatement(lexemes, position, parent, false);
        if newPosition <= position then begin
            break;
        end;
        position := newPosition;
    until false;
    result := position;
end;

function TranslatorTreeBuilder.parseOperator(lexemes: Lexer; position: int;
        parent: SyntaxNode): int;
begin
    result := parseStatement(lexemes, position, parent, true);
end;

function TranslatorTreeBuilder.parseStatement(lexemes: Lexer; position: int;
        parent: SyntaxNode; raisesExceptionIfEmpty: boolean): int;
var
    owner: Tree;
    child: BuilderNode;
begin
    owner := parent.owner;
    while (lexemes.getType(position) = TranslatorLexer.IDENTIFIER) and
            (lexemes.getType(position + 1) = TranslatorLexer.COLON) do begin
        child := owner.addChildLast(parent) as BuilderNode;
        child.setDataAssociate(position, OPERATOR_LABEL, nil, nil);
        child.labelName := lexemes.getValueUString(position);
        inc(position, 2);
        parent := child;
    end;
    case lexemes.getType(position) of
    TranslatorLexer.OPENED_PARENTHESIS, TranslatorLexer.INCR, TranslatorLexer.DECR,
    TranslatorLexer.SNOTB, TranslatorLexer.SNOTL, TranslatorLexer.SPLUS, TranslatorLexer.SMINUS,
    TranslatorLexer.QPACKUS, TranslatorLexer.QUNPCKL, TranslatorLexer.QUNPCKH,
    TranslatorLexer.QADD, TranslatorLexer.QSUB,
    TranslatorLexer.OPACKUS, TranslatorLexer.OUNPCKL, TranslatorLexer.OUNPCKH,
    TranslatorLexer.OADD, TranslatorLexer.OSUB,
    TranslatorLexer.KW_NULL, TranslatorLexer.KW_FALSE, TranslatorLexer.KW_TRUE,
    TranslatorLexer.KW_NEW, TranslatorLexer.IDENTIFIER, TranslatorLexer.NUM_INT,
    TranslatorLexer.NUM_LONG, TranslatorLexer.NUM_FLOAT, TranslatorLexer.NUM_DOUBLE,
    TranslatorLexer.NUM_REAL, TranslatorLexer.STRING_LITERAL,
    TranslatorLexer.KW_VOID, TranslatorLexer.KW_BOOLEAN, TranslatorLexer.KW_CHAR,
    TranslatorLexer.KW_BYTE, TranslatorLexer.KW_SHORT, TranslatorLexer.KW_INT,
    TranslatorLexer.KW_LONG, TranslatorLexer.KW_ULTRA, TranslatorLexer.KW_ULTRA32,
    TranslatorLexer.KW_ULTRA64, TranslatorLexer.KW_FLOAT, TranslatorLexer.KW_DOUBLE,
    TranslatorLexer.KW_REAL, TranslatorLexer.KW_XVECTOR, TranslatorLexer.KW_YVECTOR,
    TranslatorLexer.KW_ZVECTOR, TranslatorLexer.KW_FVECTOR: begin
        result := parseLocalVar(lexemes, position, parent);
    end;
    TranslatorLexer.SEMICOLON: begin
        child := owner.addChildLast(parent) as BuilderNode;
        child.setDataAssociate(position, OPERATOR_EMPTY, nil, nil);
        result := position + 1;
    end;
    TranslatorLexer.OPENED_CURLY_BRACKET: begin
        child := owner.addChildLast(parent) as BuilderNode;
        child.setDataAssociate(position, OPERATOR_BLOCK, nil, nil);
        position := parseOpBlock(lexemes, position + 1, child);
        if lexemes.getType(position) <> TranslatorLexer.CLOSED_CURLY_BRACKET then begin
            raise CompileError.create(msgExpectedClosedCurlyBracket, lexemes, position);
        end;
        result := position + 1;
    end;
    TranslatorLexer.KW_DISPOSE: begin
        result := parseDispose(lexemes, position + 1, parent);
    end;
    TranslatorLexer.KW_WITH: begin
        result := parseWith(lexemes, position + 1, parent);
    end;
    TranslatorLexer.KW_TRY: begin
        if operandSize < TranslatorType.SIZE_64_BIT then begin
            raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
        end;
        result := parseTry(lexemes, position + 1, parent);
    end;
    TranslatorLexer.KW_BREAK: begin
        result := parseBreak(lexemes, position + 1, parent);
    end;
    TranslatorLexer.KW_CONTINUE: begin
        result := parseContinue(lexemes, position + 1, parent);
    end;
    TranslatorLexer.KW_IF: begin
        result := parseIf(lexemes, position + 1, parent);
    end;
    TranslatorLexer.KW_SWITCH: begin
        result := parseSwitch(lexemes, position + 1, parent);
    end;
    TranslatorLexer.KW_DO: begin
        result := parseDo(lexemes, position + 1, parent);
    end;
    TranslatorLexer.KW_FOR: begin
        result := parseFor(lexemes, position + 1, parent);
    end;
    TranslatorLexer.KW_WHILE: begin
        result := parseWhile(lexemes, position + 1, parent);
    end;
    TranslatorLexer.KW_THROW: begin
        if operandSize < TranslatorType.SIZE_64_BIT then begin
            raise CompileError.create(msgOperationNotSupportedOS, lexemes, position);
        end;
        result := parseThrow(lexemes, position + 1, parent);
    end;
    TranslatorLexer.KW_RETURN: begin
        result := parseReturn(lexemes, position + 1, parent);
    end;
    else
        if raisesExceptionIfEmpty then begin
            raise CompileError.create(msgExpectedStatement, lexemes, position);
        end;
        result := position;
    end;
end;

function TranslatorTreeBuilder.parseForExpr(lexemes: Lexer; position: int;
        parent: SyntaxNode; expressionOnly: boolean): int;
var
    owner: Tree;
    local: LocalVariable;
    operNode: SyntaxNode;
    exprNode: SyntaxNode;
    varType: TypeDescriptor;
    varName: UnicodeString;
begin
    owner := parent.owner;
    if expressionOnly = false then begin
        varType := tryParseType(((owner.root as SyntaxNode).associate as GlobalFunction).owner,
                position);
    end else begin
        varType := nil;
    end;
    if varType <> nil then begin
        position := stayPosition;
        if lexemes.getType(position) <> TranslatorLexer.IDENTIFIER then begin
            raise CompileError.create(msgExpectedIdentifierOfVariable, lexemes, position);
        end;
        varName := lexemes.getValueUString(position);
        if findLocalVariable(varName, parent) <> nil then begin
            raise CompileError.create(msgAlreadyExistsIdentifier, lexemes, position);
        end;
        local := TranslatorLocalVariable.create(varType, varName);
        local.declarePosition := position;
        operNode := owner.addChildLast(parent) as SyntaxNode;
        operNode.setDataAssociate(position, OPERATOR_VARIABLE, nil, local);
        inc(position);
        if lexemes.getType(position) = TranslatorLexer.ASSIGN then begin
            position := parseExprAssign(lexemes, position + 1, operNode);
            exprNode := operNode.getChild(0) as SyntaxNode;
            if not possibleAssign(varType, exprNode.dataType, exprNode.associate) then begin
                raise CompileError.create(msgCannotAssignDataType, lexemes, position);
            end;
            insertTypeCast(exprNode, varType);
        end;
    end else begin
        position := parseExprAssign(lexemes, position, parent);
        exprNode := parent.getChild(parent.getChildrensCount() - 1) as SyntaxNode;
        case exprNode.value of
        EXPR_CALL, EXPR_INCR_POST, EXPR_DECR_POST, EXPR_INCR_PRED, EXPR_DECR_PRED, 600..699: begin
            exprNode.dataType := nil;
        end;
        else
            raise CompileError.create(msgExpectedAssignOrCall, lexemes, position);
        end;
    end;
    result := position;
end;

function TranslatorTreeBuilder.parseIdentifier(lexemes: Lexer; position: int;
        parent: SyntaxNode): NamedObject;
var
    i: int;
    value: int;
    owner: Tree;
    where: Namespace;
    place: Namespace;
    child: SyntaxNode;
    local: LocalVariable;
    field: StructureField;
    entry: NamespaceEntry;
    ident: UnicodeString;
begin
    owner := parent.owner;
    ident := lexemes.getValueUString(position);
    where := ((owner.root as SyntaxNode).associate as GlobalFunction).owner;
    repeat
        value := parent.value;
        if value = OPERATOR_WITH then begin
            for i := parent.getChildrensCount() - 1 downto 0 do begin
                child := parent.getChild(i) as SyntaxNode;
                if child.value <> BLOCK_WITH then begin
                    continue;
                end;
                local := child.associate as LocalVariable;
                field := (local.dataType as TypeStructure).findField(ident, true);
                if (field <> nil) and where.isVisible(field) then begin
                    stayPosition := position + 1;
                    result := TranslatorFoundObject.create(local, field);
                    exit;
                end;
            end;
        end else begin
            for i := parent.getChildrensCount() - 1 downto 0 do begin
                child := parent.getChild(i) as SyntaxNode;
                if child.value <> OPERATOR_VARIABLE then begin
                    continue;
                end;
                local := child.associate as LocalVariable;
                if local.name = ident then begin
                    stayPosition := position + 1;
                    result := local;
                    exit;
                end;
            end;
            if value = FUNCTION_START then begin
                local := (parent.associate as GlobalFunction).functionType.findArgument(ident);
                if local <> nil then begin
                    stayPosition := position + 1;
                    result := local;
                    exit;
                end;
            end;
        end;
        parent := parent.parent as SyntaxNode;
    until parent = nil;
    where := ((owner.root as SyntaxNode).associate as GlobalFunction).owner;
    entry := where.findEntry(ident, true);
    if entry <> nil then begin
        stayPosition := position + 1;
        result := entry;
        exit;
    end;
    place := findNamespace(ident);
    if place = nil then begin
        raise CompileError.create(msgExpectedIdentifierOfVariable, lexemes, position);
    end;
    inc(position);
    if lexemes.getType(position) <> TranslatorLexer.PERIOD then begin
        raise CompileError.create(msgExpectedPeriod, lexemes, position);
    end;
    inc(position);
    if lexemes.getType(position) <> TranslatorLexer.IDENTIFIER then begin
        raise CompileError.create(msgExpectedIdentifierOfVariable, lexemes, position);
    end;
    ident := lexemes.getValueUString(position);
    entry := place.findEntry(ident, false);
    if (entry = nil) or not where.isVisible(entry) then begin
        raise CompileError.create(msgExpectedIdentifierOfVariable, lexemes, position);
    end;
    stayPosition := position + 1;
    result := entry;
end;

procedure TranslatorTreeBuilder.optimizeJumps(tree: SyntaxTree; touchReturn: boolean);
label
    label0;
var
    optimized: boolean;
    cval: int;
    clbn: int;
    curr: SyntaxNode;
    goan: SyntaxNode;
    asoc: BuilderNode;
    enum: NodeEnumerator;
begin
    { оптимизация переходов }
    repeat
        optimized := false;
        curr := tree.root as SyntaxNode;
        enum := curr.enumerateChildrens();
        repeat
            cval := curr.value;
            clbn := curr.labelNumber;
            if (clbn < 0) and (cval <> BLOCK_CASE) and (cval <> BLOCK_DEFAULT) then begin
                goto label0;
            end;
            asoc := curr.goAlwaysToNode as BuilderNode;
            if (asoc <> nil) and ((asoc as TObject) <> (curr as TObject)) then begin
                if touchReturn and (asoc.labelNumber = clbn + 1) and (cval = JUMP) then begin
                    tree.deleteLabelNumber(clbn);
                    curr.goAlwaysToNode := nil;
                    optimized := true;
                    goto label0;
                end;
                goan := asoc.goAlwaysToNode;
                if goan <> nil then begin
                    case asoc.value of
                    JUMP, EXPR_VALUE_BOOLEAN: begin
                        curr.goAlwaysToNode := goan;
                        asoc.optimized := true;
                        optimized := true;
                    end;
                    OPERATOR_RETURN: begin
                        if touchReturn then begin
                            curr.goAlwaysToNode := goan;
                            asoc.optimized := true;
                            optimized := true;
                        end;
                    end;
                    end;
                end;
                goto label0;
            end;
            asoc := curr.goIfTrueToNode as BuilderNode;
            if (asoc <> nil) and ((asoc as TObject) <> (curr as TObject)) then begin
                goan := asoc.goAlwaysToNode;
                if goan <> nil then begin
                    case asoc.value of
                    JUMP, EXPR_VALUE_BOOLEAN: begin
                        curr.goIfTrueToNode := goan;
                        asoc.optimized := true;
                        optimized := true;
                    end;
                    OPERATOR_RETURN: begin
                        if touchReturn then begin
                            curr.goIfTrueToNode := goan;
                            asoc.optimized := true;
                            optimized := true;
                        end;
                    end;
                    end;
                end;
            end;
            asoc := curr.goIfFalseToNode as BuilderNode;
            if (asoc <> nil) and ((asoc as TObject) <> (curr as TObject)) then begin
                goan := asoc.goAlwaysToNode;
                if goan <> nil then begin
                    case asoc.value of
                    JUMP, EXPR_VALUE_BOOLEAN: begin
                        curr.goIfFalseToNode := goan;
                        asoc.optimized := true;
                        optimized := true;
                    end;
                    OPERATOR_RETURN: begin
                        if touchReturn then begin
                            curr.goIfFalseToNode := goan;
                            asoc.optimized := true;
                            optimized := true;
                        end;
                    end;
                    end;
                end;
            end;
            label0:
            curr := enum.nextChild() as SyntaxNode;
        until curr = nil;
    until not optimized;
end;

procedure TranslatorTreeBuilder.numerateNodes(node: SyntaxNode);
var
    i: int;
    c: int;
    parent: SyntaxNode;
begin
    { нумерация узлов нужна для определения порядка их компиляции }
    { не все узлы будут иметь номера, поскольку некоторые из них не порождают исполняемый код }
    c := node.getChildrensCount() - 1;
    case node.value of
    { нумеруются только дочерние узлы, – родительский узел не нумеруется }
    OPERATOR_LABEL, OPERATOR_BLOCK, OPERATOR_WITH, OPERATOR_TRY_CATCH, OPERATOR_TRY_FINALLY,
    OPERATOR_IF, OPERATOR_FOR, OPERATOR_WHILE, OPERATOR_DO, BLOCK_CATCH, BLOCK_FINALLY_START,
    EXPR_SNOTL, EXPR_SANDL, EXPR_SORL, EXPR_QUESTION: begin
        for i := 0 to c do begin
            numerateNodes(node.getChild(i) as SyntaxNode);
        end;
    end;
    { родительский и дочерние узлы нумеруются в случае, если есть дочерние узлы }
    OPERATOR_VARIABLE, BLOCK_WITH: begin
        if c >= 0 then begin
            for i := 0 to c do begin
                numerateNodes(node.getChild(i) as SyntaxNode);
            end;
            (node.owner as SyntaxTree).assignLabelNumberTo(node);
        end;
    end;
    { только родительский узел нумеруется, поскольку дочерних узлов нет }
    OPERATOR_BREAK, OPERATOR_CONTINUE, OPERATOR_THROW, BLOCK_FINALLY_RETURN,
    EXPR_VALUE_NULL, EXPR_VALUE_BOOLEAN, EXPR_VALUE_LONG, EXPR_VALUE_ULTRA,
    EXPR_VALUE_REAL, EXPR_VALUE_XVECTOR, EXPR_VALUE_STRING: begin
        (node.owner as SyntaxTree).assignLabelNumberTo(node);
    end;
    { сначала нумеруются дочерние узлы, затем – родительский узел }
    OPERATOR_DISPOSE, OPERATOR_RETURN, EXPR_NEW_ARRAY_BY_LENGTH,
    EXPR_NEW_ULTRA, EXPR_NEW_XVECTOR, EXPR_FIELD_ASSIGN, EXPR_ARRAY_ASSIGN, EXPR_CALL,
    EXPR_COMPOUND, EXPR_INCR_POST, EXPR_DECR_POST, EXPR_SNOTB, EXPR_SNEG,
    EXPR_INCR_PRED, EXPR_DECR_PRED, EXPR_QPACKUS, EXPR_QUNPCKL, EXPR_QUNPCKH, EXPR_QNEG,
    EXPR_OPACKUS, EXPR_OUNPCKL, EXPR_OUNPCKH, EXPR_ONEG, EXPR_SMULL, EXPR_SDIVS, EXPR_SREMS,
    EXPR_SDIVU, EXPR_SREMU, EXPR_QMULL, EXPR_QMULH, EXPR_QMULHS, EXPR_QDIV, EXPR_OMULL, EXPR_OMULH,
    EXPR_OMULHS, EXPR_SADD, EXPR_SSUB, EXPR_QADD, EXPR_QADDS, EXPR_QADDUS, EXPR_QSUB, EXPR_QSUBS,
    EXPR_QSUBUS, EXPR_OADD, EXPR_OADDS, EXPR_OADDUS, EXPR_OSUB, EXPR_OSUBS, EXPR_OSUBUS, EXPR_SSLL,
    EXPR_SSRA, EXPR_SSRL, EXPR_QSLL, EXPR_QSRA, EXPR_QSRL, EXPR_OSLL, EXPR_OSRA, EXPR_OSRL,
    EXPR_SGT, EXPR_SGE, EXPR_SLT, EXPR_SLE, EXPR_QGT, EXPR_QGE, EXPR_QLT, EXPR_QLE, EXPR_OGT,
    EXPR_OGE, EXPR_OLT, EXPR_OLE, EXPR_SEQ, EXPR_SNE, EXPR_QEQ, EXPR_QNE, EXPR_OEQ, EXPR_ONE,
    EXPR_SANDB, EXPR_SXORB, EXPR_SORB, EXPR_SEQ_NULL, EXPR_SNE_NULL, EXPR_SZR_TEST, EXPR_SNZ_TEST,
    ASSIGN, ASSIGN_SMULL, ASSIGN_SDIVS, ASSIGN_SREMS, ASSIGN_SDIVU, ASSIGN_SREMU, ASSIGN_QMULL,
    ASSIGN_QMULH, ASSIGN_QMULHS, ASSIGN_QDIV, ASSIGN_OMULL, ASSIGN_OMULH, ASSIGN_OMULHS,
    ASSIGN_SADD, ASSIGN_SSUB, ASSIGN_QADD, ASSIGN_QADDS, ASSIGN_QADDUS, ASSIGN_QSUB, ASSIGN_QSUBS,
    ASSIGN_QSUBUS, ASSIGN_OADD, ASSIGN_OADDS, ASSIGN_OADDUS, ASSIGN_OSUB, ASSIGN_OSUBS,
    ASSIGN_OSUBUS, ASSIGN_SSLL, ASSIGN_SSRA, ASSIGN_SSRL, ASSIGN_QSLL, ASSIGN_QSRA, ASSIGN_QSRL,
    ASSIGN_OSLL, ASSIGN_OSRA, ASSIGN_OSRL, ASSIGN_QGT, ASSIGN_QGE, ASSIGN_QLT, ASSIGN_QLE,
    ASSIGN_OGT, ASSIGN_OGE, ASSIGN_OLT, ASSIGN_OLE, ASSIGN_QEQ, ASSIGN_QNE, ASSIGN_OEQ, ASSIGN_ONE,
    ASSIGN_SANDB, ASSIGN_SXORB, ASSIGN_SORB: begin
        for i := 0 to c do begin
            numerateNodes(node.getChild(i) as SyntaxNode);
        end;
        (node.owner as SyntaxTree).assignLabelNumberTo(node);
    end;
    { сначала нумеруется родительский узел, затем – дочерние узлы }
    EXPR_NEW_STRUCT, EXPR_NEW_ARRAY_BY_ELEMENTS: begin
        (node.owner as SyntaxTree).assignLabelNumberTo(node);
        for i := 0 to c do begin
            numerateNodes(node.getChild(i) as SyntaxNode);
        end;
    end;
    { особая нумерация узлов в операторе switch }
    OPERATOR_SWITCH: begin
        numerateNodes(node.getChild(0) as SyntaxNode);
        (node.owner as SyntaxTree).assignLabelNumberTo(node);
        for i := 1 to c do begin
            numerateNodes(node.getChild(i) as SyntaxNode);
        end;
    end;
    { особая нумерация целых чисел, если это количество бит для сдвига }
    EXPR_VALUE_INT: begin
        i := (node.parent as SyntaxNode).value;
        if (node.index <> 1) or (
                (i <> EXPR_SSLL) and (i <> EXPR_SSRA) and (i <> EXPR_SSRL) and
                (i <> EXPR_QSLL) and (i <> EXPR_QSRA) and (i <> EXPR_QSRL) and
                (i <> EXPR_OSLL) and (i <> EXPR_OSRA) and (i <> EXPR_OSRL) and
                (i <> ASSIGN_SSLL) and (i <> ASSIGN_SSRA) and (i <> ASSIGN_SSRL) and
                (i <> ASSIGN_QSLL) and (i <> ASSIGN_QSRA) and (i <> ASSIGN_QSRL) and
                (i <> ASSIGN_OSLL) and (i <> ASSIGN_OSRA) and (i <> ASSIGN_OSRL)) then begin
            (node.owner as SyntaxTree).assignLabelNumberTo(node);
        end;
    end;
    { особая нумерация узлов там, куда можно присвоить значение }
    EXPR_LOCAL_VARIABLE, EXPR_GLOBAL_VARIABLE, EXPR_ARRAY, EXPR_FIELD: begin
        for i := 0 to c do begin
            numerateNodes(node.getChild(i) as SyntaxNode);
        end;
        if (node.index > 0) or not isNodeValueAssign((node.parent as SyntaxNode).value) then begin
            (node.owner as SyntaxTree).assignLabelNumberTo(node);
        end;
    end;
    { особая нумерация узлов для глобальной функции }
    EXPR_GLOBAL_FUNCTION: begin
        parent := node.parent as SyntaxNode;
        if (parent.value <> EXPR_CALL) or (node.index <> parent.getChildrensCount() - 1) then begin
            (node.owner as SyntaxTree).assignLabelNumberTo(node);
        end;
    end;
    { особая нумерация узлов для операции приведения к типу }
    EXPR_TYPE_CAST: begin
        for i := 0 to c do begin
            numerateNodes(node.getChild(i) as SyntaxNode);
        end;
        case getTypeKind((node.getChild(0) as SyntaxNode).dataType) of
        TranslatorType.KIND_CHAR:
            case getTypeKind(node.dataType) of
            TranslatorType.KIND_BYTE, TranslatorType.KIND_LONG, TranslatorType.KIND_ULTRA,
            TranslatorType.KIND_FLOAT, TranslatorType.KIND_DOUBLE, TranslatorType.KIND_REAL,
            TranslatorType.KIND_XVECTOR:
                (node.owner as SyntaxTree).assignLabelNumberTo(node);
            TranslatorType.KIND_SHORT:
                if operandSize > TranslatorType.SIZE_16_BIT then begin
                    (node.owner as SyntaxTree).assignLabelNumberTo(node);
                end;
            end;
        TranslatorType.KIND_BYTE:
            case getTypeKind(node.dataType) of
            TranslatorType.KIND_CHAR:
                if operandSize > TranslatorType.SIZE_16_BIT then begin
                    (node.owner as SyntaxTree).assignLabelNumberTo(node);
                end;
            TranslatorType.KIND_LONG, TranslatorType.KIND_ULTRA, TranslatorType.KIND_FLOAT,
            TranslatorType.KIND_DOUBLE, TranslatorType.KIND_REAL, TranslatorType.KIND_XVECTOR:
                (node.owner as SyntaxTree).assignLabelNumberTo(node);
            end;
        TranslatorType.KIND_SHORT:
            case getTypeKind(node.dataType) of
            TranslatorType.KIND_CHAR:
                if operandSize > TranslatorType.SIZE_16_BIT then begin
                    (node.owner as SyntaxTree).assignLabelNumberTo(node);
                end;
            TranslatorType.KIND_BYTE, TranslatorType.KIND_LONG, TranslatorType.KIND_ULTRA,
            TranslatorType.KIND_FLOAT, TranslatorType.KIND_DOUBLE, TranslatorType.KIND_REAL,
            TranslatorType.KIND_XVECTOR:
                (node.owner as SyntaxTree).assignLabelNumberTo(node);
            end;
        TranslatorType.KIND_INT:
            case getTypeKind(node.dataType) of
            TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE, TranslatorType.KIND_SHORT,
            TranslatorType.KIND_LONG, TranslatorType.KIND_ULTRA, TranslatorType.KIND_FLOAT,
            TranslatorType.KIND_DOUBLE, TranslatorType.KIND_REAL, TranslatorType.KIND_XVECTOR:
                (node.owner as SyntaxTree).assignLabelNumberTo(node);
            end;
        TranslatorType.KIND_LONG:
            case getTypeKind(node.dataType) of
            TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE, TranslatorType.KIND_SHORT,
            TranslatorType.KIND_INT, TranslatorType.KIND_ULTRA, TranslatorType.KIND_FLOAT,
            TranslatorType.KIND_DOUBLE, TranslatorType.KIND_REAL, TranslatorType.KIND_XVECTOR:
                (node.owner as SyntaxTree).assignLabelNumberTo(node);
            end;
        TranslatorType.KIND_ULTRA:
            case getTypeKind(node.dataType) of
            TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE, TranslatorType.KIND_SHORT,
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_FLOAT,
            TranslatorType.KIND_DOUBLE, TranslatorType.KIND_REAL, TranslatorType.KIND_XVECTOR:
                (node.owner as SyntaxTree).assignLabelNumberTo(node);
            end;
        TranslatorType.KIND_FLOAT:
            case getTypeKind(node.dataType) of
            TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE, TranslatorType.KIND_SHORT,
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_ULTRA,
            TranslatorType.KIND_DOUBLE, TranslatorType.KIND_REAL, TranslatorType.KIND_XVECTOR:
                (node.owner as SyntaxTree).assignLabelNumberTo(node);
            end;
        TranslatorType.KIND_DOUBLE:
            case getTypeKind(node.dataType) of
            TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE, TranslatorType.KIND_SHORT,
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_ULTRA,
            TranslatorType.KIND_FLOAT, TranslatorType.KIND_REAL, TranslatorType.KIND_XVECTOR:
                (node.owner as SyntaxTree).assignLabelNumberTo(node);
            end;
        TranslatorType.KIND_REAL:
            case getTypeKind(node.dataType) of
            TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE, TranslatorType.KIND_SHORT,
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_ULTRA,
            TranslatorType.KIND_FLOAT, TranslatorType.KIND_DOUBLE, TranslatorType.KIND_XVECTOR:
                (node.owner as SyntaxTree).assignLabelNumberTo(node);
            end;
        TranslatorType.KIND_XVECTOR:
            case getTypeKind(node.dataType) of
            TranslatorType.KIND_CHAR, TranslatorType.KIND_BYTE, TranslatorType.KIND_SHORT,
            TranslatorType.KIND_INT, TranslatorType.KIND_LONG, TranslatorType.KIND_ULTRA,
            TranslatorType.KIND_FLOAT, TranslatorType.KIND_DOUBLE, TranslatorType.KIND_REAL:
                (node.owner as SyntaxTree).assignLabelNumberTo(node);
            end;
        end;
    end;
    end;
end;

procedure TranslatorTreeBuilder.placeJumpsInExpression(node: SyntaxNode);
var
    lbln: int;
    tree: SyntaxTree;
    asn1: SyntaxNode;
    asn2: SyntaxNode;
    asn3: SyntaxNode;
    minl: SyntaxNode;
    jmp1: SyntaxNode;
    curr: SyntaxNode;
    enum: NodeEnumerator;
begin
    { расстановка переходов в логических выражениях,
      не попавших под действие метода placeJumpsInBoolean }
    tree := node.owner as SyntaxTree;
    repeat
        curr := node;
        enum := node.enumerateChildrens();
        repeat
            case curr.value of
            { дополнительная расстановка переходов в операторах ||, && и ! }
            EXPR_SORL, EXPR_SANDL, EXPR_SNOTL: begin
                if (curr.goIfTrueToNode = nil) or (curr.goIfFalseToNode = nil) then begin
                    lbln := curr.getChildWithMaxLabelNumber().labelNumber + 1;
                    asn1 := tree.addNodeBefore(curr) as SyntaxNode;
                    asn1.setDataAssociate(-1, EXPR_QUESTION, nil, nil);
                    asn2 := tree.addChildLast(asn1) as SyntaxNode;
                    asn2.setDataAssociate(-1, EXPR_VALUE_BOOLEAN, typeBoolean, true);
                    jmp1 := tree.addChildLast(asn1) as SyntaxNode;
                    jmp1.setDataAssociate(-1, JUMP, nil, nil);
                    asn3 := tree.addChildLast(asn1) as SyntaxNode;
                    asn3.setDataAssociate(-1, EXPR_VALUE_BOOLEAN, typeBoolean, false);
                    curr.setParent(asn1, 0);
                    jmp1.setGoAlwaysToNode(tree.getNodeWithLabelNumber(lbln));
                    tree.setLabelNumber(asn2, lbln);
                    tree.setLabelNumber(jmp1, lbln + 1);
                    tree.setLabelNumber(asn3, lbln + 2);
                    placeJumpsInBoolean(curr, asn2, asn3);
                    break;
                end;
            end;
            { дополнительная расстановка переходов в операторе ?: }
            EXPR_QUESTION: begin
                asn1 := curr.getChild(0) as SyntaxNode;
                if (asn1.goIfTrueToNode = nil) or (asn1.goIfFalseToNode = nil) then begin
                    lbln := curr.getChildWithMaxLabelNumber().labelNumber + 1;
                    asn2 := curr.getChild(1) as SyntaxNode;
                    asn3 := curr.getChild(2) as SyntaxNode;
                    minl := asn3.getChildWithMinLabelNumber();
                    jmp1 := tree.addNodeBefore(asn3) as SyntaxNode;
                    jmp1.setDataAssociate(-1, JUMP, nil, nil);
                    jmp1.setGoAlwaysToNode(tree.getNodeWithLabelNumber(lbln));
                    tree.setLabelNumber(jmp1, minl.labelNumber);
                    placeJumpsInBoolean(asn1, asn2.getChildWithMinLabelNumber(), minl);
                    break;
                end;
            end;
            end;
            curr := enum.nextChild() as SyntaxNode;
            if curr = nil then begin
                exit;
            end;
        until false;
    until false;
end;

procedure TranslatorTreeBuilder.placeJumpsInBoolean(node, goIfTrue, goIfFalse: SyntaxNode);
var
    asn1: SyntaxNode;
    asn2: SyntaxNode;
    asn3: SyntaxNode;
begin
    { расстановка переходов в выражениях типа boolean }
    node.setDataGoToNode(goIfTrue, goIfFalse);
    case node.value of
    { оператор ?: }
    EXPR_QUESTION: begin
        asn1 := node.getChild(0) as SyntaxNode;
        asn2 := node.getChild(1) as SyntaxNode;
        asn3 := node.getChild(2) as SyntaxNode;
        placeJumpsInBoolean(asn1, asn2.getChildWithMinLabelNumber(),
                asn3.getChildWithMinLabelNumber());
        placeJumpsInBoolean(asn2, goIfTrue, goIfFalse);
        placeJumpsInBoolean(asn3, goIfTrue, goIfFalse);
    end;
    { оператор || }
    EXPR_SORL: begin
        asn1 := node.getChild(0) as SyntaxNode;
        asn2 := node.getChild(1) as SyntaxNode;
        placeJumpsInBoolean(asn1, goIfTrue, asn2.getChildWithMinLabelNumber());
        placeJumpsInBoolean(asn2, goIfTrue, goIfFalse);
    end;
    { оператор && }
    EXPR_SANDL: begin
        asn1 := node.getChild(0) as SyntaxNode;
        asn2 := node.getChild(1) as SyntaxNode;
        placeJumpsInBoolean(asn1, asn2.getChildWithMinLabelNumber(), goIfFalse);
        placeJumpsInBoolean(asn2, goIfTrue, goIfFalse);
    end;
    { оператор ! }
    EXPR_SNOTL: begin
        asn1 := node.getChild(0) as SyntaxNode;
        placeJumpsInBoolean(asn1, goIfFalse, goIfTrue);
    end;
    { константа типа boolean }
    EXPR_VALUE_BOOLEAN: begin
        if (node.associate as BooleanAsObject).booleanValue() = true then begin
            node.setGoAlwaysToNode(goIfTrue);
        end else begin
            node.setGoAlwaysToNode(goIfFalse);
        end;
    end;
    else
        placeJumpsInExpression(node);
    end;
end;

function TranslatorTreeBuilder.placeJumpsInOperator(node, next: SyntaxNode): SyntaxNode;
label
    label0;
var
    i: int;
    c: int;
    v: int;
    tree: SyntaxTree;
    asn1: SyntaxNode;
    asn2: SyntaxNode;
    asn3: SyntaxNode;
    asn4: SyntaxNode;
    asn5: SyntaxNode;
    jmp1: SyntaxNode;
    texc: GlobalException;
begin
    { расстановка переходов в операторах }
    c := node.getChildrensCount() - 1;
    tree := node.owner as SyntaxTree;
    case node.value of
    { пустой }
    OPERATOR_EMPTY: ;
    (* метка:, {…}, with *)
    OPERATOR_LABEL, OPERATOR_BLOCK, OPERATOR_WITH: begin
        for i := c downto 0 do begin
            next := placeJumpsInOperator(node.getChild(i) as SyntaxNode, next);
        end;
    end;
    { заявление локальной переменной, dispose, выражение в операторе with }
    OPERATOR_VARIABLE, OPERATOR_DISPOSE, BLOCK_WITH: begin
        if c >= 0 then begin
            placeJumpsInExpression(node.getChild(0) as SyntaxNode);
            next := node.getChildWithMinLabelNumber();
        end;
    end;
    { try…catch }
    OPERATOR_TRY_CATCH: begin
        asn1 := node.getChild(0) as SyntaxNode;
        asn2 := next;
        for i := c downto 1 do begin
            asn2 := placeJumpsInOperator(node.getChild(i) as SyntaxNode, next);
        end;
        jmp1 := tree.addNodeAfter(asn1) as SyntaxNode;
        jmp1.setDataAssociate(-1, JUMP, nil, nil);
        jmp1.setGoAlwaysToNode(next);
        tree.setLabelNumber(jmp1, asn2.labelNumber);
        next := placeJumpsInOperator(asn1, jmp1);
        node.setDataGoToNode(next, jmp1); { нужно для определения границ «опасного» кода }
    end;
    { try…finally }
    OPERATOR_TRY_FINALLY: begin
        asn1 := node.getChild(0) as SyntaxNode;
        asn2 := placeJumpsInOperator(node.getChild(1) as SyntaxNode, next);
        jmp1 := tree.addNodeAfter(asn1) as SyntaxNode;
        jmp1.setDataAssociate(-1, TF_JUMP, nil, node);
        jmp1.setGoAlwaysToNode(next);
        tree.setLabelNumber(jmp1, asn2.labelNumber);
        next := placeJumpsInOperator(asn1, jmp1);
        node.setDataGoToNode(next, jmp1); { нужно для определения границ «финализируемого» кода }
    end;
    { break }
    OPERATOR_BREAK: begin
        asn1 := node.associate as SyntaxNode;
        asn2 := node.parent as SyntaxNode;
        v := JUMP;
        repeat
            if asn2.value = OPERATOR_TRY_FINALLY then begin
                v := TF_JUMP;
                break;
            end;
            if (asn2 as TObject) = (asn1 as TObject) then begin
                break;
            end;
            asn2 := asn2.parent as SyntaxNode;
        until asn2 = nil;
        node.value := v;
        node.setGoAlwaysToNode(tree.getNodeWithLabelNumber(asn1.
                getChildWithMaxLabelNumber().labelNumber + 1));
        next := node;
    end;
    { continue }
    OPERATOR_CONTINUE: begin
        asn1 := node.associate as SyntaxNode;
        asn2 := node.parent as SyntaxNode;
        v := JUMP;
        repeat
            if asn2.value = OPERATOR_TRY_FINALLY then begin
                v := TF_JUMP;
                break;
            end;
            if (asn2 as TObject) = (asn1 as TObject) then begin
                break;
            end;
            asn2 := asn2.parent as SyntaxNode;
        until asn2 = nil;
        node.value := v;
        if asn1.value = OPERATOR_FOR then begin
            i := asn1.getChildrensCount() - 2;
            node.setGoAlwaysToNode(getNodeWithMinLabelNumber(asn1.getChild(i) as SyntaxNode,
                    (asn1.getChild(i + 1) as SyntaxNode).getChildWithMinLabelNumber()));
        end else begin
            node.setGoAlwaysToNode((asn1.getChild(asn1.getChildrensCount() - 1) as SyntaxNode).
                    getChildWithMinLabelNumber());
        end;
        next := node;
    end;
    { if }
    OPERATOR_IF: begin
        asn1 := node.getChild(0) as SyntaxNode;
        asn2 := node.getChild(1) as SyntaxNode;
        if c < 2 then begin
            asn2 := placeJumpsInOperator(asn2, next);
            placeJumpsInBoolean(asn1, asn2, next);
        end else begin
            asn3 := node.getChild(2) as SyntaxNode;
            jmp1 := tree.addNodeBefore(asn3) as SyntaxNode;
            jmp1.setDataAssociate(-1, JUMP, nil, nil);
            jmp1.setGoAlwaysToNode(next);
            asn3 := placeJumpsInOperator(asn3, next);
            asn2 := placeJumpsInOperator(asn2, jmp1);
            placeJumpsInBoolean(asn1, asn2, asn3);
            tree.setLabelNumber(jmp1, asn3.labelNumber);
        end;
        next := asn1.getChildWithMinLabelNumber();
    end;
    { switch }
    OPERATOR_SWITCH: begin
        for i := c downto 1 do begin
            next := placeJumpsInOperator(node.getChild(i) as SyntaxNode, next);
        end;
        asn1 := node.getChild(0) as SyntaxNode;
        placeJumpsInExpression(asn1);
        next := asn1.getChildWithMinLabelNumber();
    end;
    { do…while }
    OPERATOR_DO: begin
        asn1 := node.getChild(0) as SyntaxNode;
        asn2 := node.getChild(1) as SyntaxNode;
        asn3 := asn2.getChildWithMinLabelNumber();
        asn4 := placeJumpsInOperator(asn1, asn3);
        placeJumpsInBoolean(asn2, asn4, next);
        next := asn4;
    end;
    { for }
    OPERATOR_FOR: begin
        dec(c, 3);
        asn1 := node.getChild(c + 1) as SyntaxNode;
        asn2 := node.getChild(c + 2) as SyntaxNode;
        asn3 := node.getChild(c + 3) as SyntaxNode;
        asn4 := asn3.getChildWithMinLabelNumber();
        asn5 := placeJumpsInOperator(asn2, asn4);
        asn5 := placeJumpsInOperator(asn1, asn5);
        jmp1 := tree.addNodeBefore(asn1) as SyntaxNode;
        jmp1.setDataAssociate(-1, JUMP, nil, nil);
        jmp1.setGoAlwaysToNode(asn4);
        tree.setLabelNumber(jmp1, asn5.labelNumber);
        placeJumpsInBoolean(asn3, asn5, next);
        next := jmp1;
        for i := c downto 0 do begin
            next := placeJumpsInOperator(node.getChild(i) as SyntaxNode, next);
        end;
    end;
    { while }
    OPERATOR_WHILE: begin
        asn1 := node.getChild(0) as SyntaxNode;
        asn2 := node.getChild(1) as SyntaxNode;
        asn3 := asn2.getChildWithMinLabelNumber();
        asn4 := placeJumpsInOperator(asn1, asn3);
        placeJumpsInBoolean(asn2, asn4, next);
        jmp1 := tree.addChildFirst(node) as SyntaxNode;
        jmp1.setDataAssociate(-1, JUMP, nil, nil);
        jmp1.setGoAlwaysToNode(asn3);
        tree.setLabelNumber(jmp1, asn4.labelNumber);
        next := jmp1;
    end;
    { throw }
    OPERATOR_THROW: begin
        texc := node.associate as GlobalException;
        asn1 := node.parent as SyntaxNode;
        with tree.root do begin
            jmp1 := getChild(getChildrensCount() - 1) as SyntaxNode;
        end;
        repeat
            if asn1.value = OPERATOR_TRY_CATCH then begin
                c := asn1.getChildrensCount() - 1;
                for i := 0 to c do begin
                    asn2 := asn1.getChild(i) as SyntaxNode;
                    if (asn2.value = BLOCK_CATCH) and
                            texc.isInheritedFrom(asn2.associate as GlobalException) then begin
                        jmp1 := asn2;
                        goto label0;
                    end;
                end;
            end;
            asn1 := asn1.parent as SyntaxNode;
        until asn1 = nil;
        label0:
        node.setGoAlwaysToNode(jmp1);
        next := node;
    end;
    { return }
    OPERATOR_RETURN: begin
        asn1 := node.parent as SyntaxNode;
        repeat
            if asn1.value = OPERATOR_TRY_FINALLY then begin
                node.value := TF_OPERATOR_RETURN;
                break;
            end;
            asn1 := asn1.parent as SyntaxNode;
        until asn1 = nil;
        with tree.root do begin
            node.setGoAlwaysToNode(getChild(getChildrensCount() - 1) as SyntaxNode);
        end;
        if c >= 0 then begin
            asn1 := node.getChild(0) as SyntaxNode;
            placeJumpsInExpression(asn1);
            next := asn1.getChildWithMinLabelNumber();
        end else begin
            next := node;
        end;
    end;
    { catch }
    BLOCK_CATCH: begin
        i := node.index;
        asn1 := node.parent as SyntaxNode;
        if i < asn1.getChildrensCount() - 1 then begin
            jmp1 := tree.addChildLast(node) as SyntaxNode;
            jmp1.setDataAssociate(-1, JUMP, nil, nil);
            jmp1.setGoAlwaysToNode(next);
            tree.setLabelNumber(jmp1, getNodeWithMinLabelNumber(asn1.getChild(i + 1) as SyntaxNode,
                    next).labelNumber);
            next := jmp1;
        end;
        for i := c downto 0 do begin
            next := placeJumpsInOperator(node.getChild(i) as SyntaxNode, next);
        end;
        node.setGoAlwaysToNode(next); { нужно для определения начала блока catch }
    end;
    { finally }
    BLOCK_FINALLY_START: begin
        for i := c downto 0 do begin
            next := placeJumpsInOperator(node.getChild(i) as SyntaxNode, next);
        end;
        node.setGoAlwaysToNode(next); { нужно для определения начала блока finally }
    end;
    { finally return }
    BLOCK_FINALLY_RETURN: begin
        next := node;
    end;
    { case, default }
    BLOCK_CASE, BLOCK_DEFAULT: begin
        node.goAlwaysToNode := next; { нужно для определения переходов по оператору switch }
    end;
    { выражение }
    else
        placeJumpsInExpression(node);
        next := node.getChildWithMinLabelNumber();
    end;
    result := next;
end;

function TranslatorTreeBuilder.insertInitializations(root: SyntaxNode): SyntaxNode;
var
    i: int;
    limit: int;
    owner: Tree;
    callNode: SyntaxNode;
    funcNode: SyntaxNode;
    tryfNode: SyntaxNode;
    bodyNode: SyntaxNode;
    fnType: TypeFunction;
    func: GlobalFunction;
begin
    { вставка инициализаций и финализаций в главную функцию }
    owner := root.owner;
    limit := getNamespacesCount() - 1;
    for i := 0 to limit do begin
        func := getNamespace(i).findEntry(FUNCTION_INITIALIZATION, false) as GlobalFunction;
        if func = nil then begin
            continue;
        end;
        fnType := func.functionType;
        callNode := owner.addChildLast(root) as SyntaxNode;
        callNode.setDataAssociate(-1, EXPR_CALL, nil, nil);
        funcNode := owner.addChildLast(callNode) as SyntaxNode;
        funcNode.setDataAssociate(-1, EXPR_GLOBAL_FUNCTION, fnType, func);
    end;
    if operandSize < TranslatorType.SIZE_64_BIT then begin
        result := owner.addChildLast(root) as SyntaxNode;
        result.setDataAssociate(-1, OPERATOR_BLOCK, nil, nil);
        bodyNode := root;
    end else begin
        tryfNode := owner.addChildLast(root) as SyntaxNode;
        tryfNode.setDataAssociate(-1, OPERATOR_TRY_FINALLY, nil, nil);
        result := owner.addChildLast(tryfNode) as SyntaxNode;
        result.setDataAssociate(-1, OPERATOR_BLOCK, nil, nil);
        bodyNode := owner.addChildLast(tryfNode) as SyntaxNode;
        bodyNode.setDataAssociate(-1, BLOCK_FINALLY_START, nil, nil);
    end;
    for i := limit downto 0 do begin
        func := getNamespace(i).findEntry(FUNCTION_FINALIZATION, false) as GlobalFunction;
        if func = nil then begin
            continue;
        end;
        fnType := func.functionType;
        callNode := owner.addChildLast(bodyNode) as SyntaxNode;
        callNode.setDataAssociate(-1, EXPR_CALL, nil, nil);
        funcNode := owner.addChildLast(callNode) as SyntaxNode;
        funcNode.setDataAssociate(-1, EXPR_GLOBAL_FUNCTION, fnType, func);
    end;
    if operandSize >= TranslatorType.SIZE_64_BIT then begin
        funcNode := owner.addChildLast(bodyNode) as SyntaxNode;
        funcNode.setDataAssociate(-1, BLOCK_FINALLY_RETURN, nil, nil);
    end;
end;

function TranslatorTreeBuilder.isReachable(node: SyntaxNode): boolean;
var
    i: int;
    cval: int;
    currIndex: int;
    nodeIndex: int;
    prevIndex: int;
    tree: SyntaxTree;
    curr: SyntaxNode;
    galw: SyntaxNode;
    gift: SyntaxNode;
    giff: SyntaxNode;
    enum: NodeEnumerator;
    nobj: TObject;
begin
    nodeIndex := node.labelNumber;
    if nodeIndex = 0 then begin
        result := true;
        exit;
    end;
    prevIndex := nodeIndex - 1;
    tree := node.owner as SyntaxTree;
    nobj := node as TObject;
    for i := tree.getNodesWithLabelNumberCount() - 1 downto 0 do begin
        curr := tree.getNodeWithLabelNumber(i);
        cval := curr.value;
        if (cval = OPERATOR_THROW) or (cval = BLOCK_FINALLY_RETURN) then begin
            continue;
        end;
        currIndex := curr.labelNumber;
        if currIndex = nodeIndex then begin
            continue;
        end;
        galw := curr.goAlwaysToNode;
        gift := curr.goIfTrueToNode;
        giff := curr.goIfFalseToNode;
        if ((currIndex = prevIndex) and (galw = nil) and (gift = nil) and (giff = nil)) or
                ((galw as TObject) = nobj) or ((gift as TObject) = nobj) or
                ((giff as TObject) = nobj) then begin
            result := true;
            exit;
        end;
    end;
    curr := node.parent as SyntaxNode;
    repeat
        case curr.value of
        OPERATOR_TRY_CATCH, OPERATOR_TRY_FINALLY: begin
            if ((curr.goIfTrueToNode as TObject) = nobj) or
                    ((curr.goIfFalseToNode as TObject) = nobj) then begin
                result := true;
                exit;
            end;
        end;
        BLOCK_CATCH, BLOCK_FINALLY_START: begin
            if (curr.goAlwaysToNode as TObject) = nobj then begin
                result := true;
                exit;
            end;
        end;
        end;
        curr := curr.parent as SyntaxNode;
    until curr = nil;
    curr := tree.root as SyntaxNode;
    enum := curr.enumerateChildrens();
    repeat
        case curr.value of
        BLOCK_CASE, BLOCK_DEFAULT: begin
            if (curr.goAlwaysToNode as TObject) = nobj then begin
                result := true;
                exit;
            end;
        end;
        end;
        curr := enum.nextChild() as SyntaxNode;
    until curr = nil;
    result := false;
end;

function TranslatorTreeBuilder.isReturnTo(last: SyntaxNode): boolean;
var
    i: int;
    cval: int;
    currIndex: int;
    nodeIndex: int;
    prevIndex: int;
    tree: SyntaxTree;
    curr: SyntaxNode;
    galw: SyntaxNode;
    gift: SyntaxNode;
    giff: SyntaxNode;
    enum: NodeEnumerator;
    nobj: TObject;
begin
    nodeIndex := last.labelNumber;
    prevIndex := nodeIndex - 1;
    tree := last.owner as SyntaxTree;
    nobj := last as TObject;
    for i := tree.getNodesWithLabelNumberCount() - 1 downto 0 do begin
        curr := tree.getNodeWithLabelNumber(i);
        cval := curr.value;
        if cval = BLOCK_FINALLY_RETURN then begin
            continue;
        end;
        currIndex := curr.labelNumber;
        if currIndex = nodeIndex then begin
            continue;
        end;
        galw := curr.goAlwaysToNode;
        gift := curr.goIfTrueToNode;
        giff := curr.goIfFalseToNode;
        if (((currIndex = prevIndex) and (galw = nil) and (gift = nil) and (giff = nil)) or
                ((galw as TObject) = nobj) or ((gift as TObject) = nobj) or
                ((giff as TObject) = nobj)) and (cval <> OPERATOR_RETURN) and
                (cval <> TF_OPERATOR_RETURN) and (cval <> OPERATOR_THROW) then begin
            result := false;
            exit;
        end;
    end;
    curr := tree.root as SyntaxNode;
    enum := curr.enumerateChildrens();
    repeat
        case curr.value of
        BLOCK_CASE, BLOCK_DEFAULT, BLOCK_CATCH: begin
            if (curr.goAlwaysToNode as TObject) = nobj then begin
                result := false;
                exit;
            end;
        end;
        end;
        curr := enum.nextChild() as SyntaxNode;
    until curr = nil;
    result := true;
end;

function TranslatorTreeBuilder.hasLinksTo(node: SyntaxNode): boolean;
var
    value: int;
    notcheck: int;
    nobj: TObject;
    curr: SyntaxNode;
    enum: NodeEnumerator;
begin
    notcheck := node.labelNumber - 1;
    nobj := node as TObject;
    curr := node.owner.root as SyntaxNode;
    enum := curr.enumerateChildrens();
    repeat
        value := curr.value;
        if (curr.labelNumber <> notcheck) and
                (value <> EXPR_SORL) and (value <> EXPR_SANDL) and
                (value <> EXPR_SNOTL) and (value <> EXPR_QUESTION) and
                (value <> OPERATOR_THROW) and (
                ((curr.goAlwaysToNode as TObject) = nobj) or
                ((curr.goIfTrueToNode as TObject) = nobj) or
                ((curr.goIfFalseToNode as TObject) = nobj)) then begin
            result := true;
            exit;
        end;
        curr := enum.nextChild() as SyntaxNode;
    until curr = nil;
    result := false;
end;

{ TranslatorFoundObject }

constructor TranslatorFoundObject.create(foundIn: LocalVariable; baseObject: StructureField);
begin
    inherited create();
    if baseObject = nil then begin
        baseObject := TranslatorStructureField.create(nil, 0, false, nil, '');
    end;
    self.foundIn := foundIn;
    self.baseObject := baseObject;
end;

function TranslatorFoundObject.toString(): AnsiString;
begin
    result := baseObject.toString();
end;

procedure TranslatorFoundObject.setDeclarePosition(declarePosition: int);
begin
    baseObject.setDeclarePosition(declarePosition);
end;

procedure TranslatorFoundObject.setStartPosition(startPosition: int);
begin
    baseObject.setStartPosition(startPosition);
end;

function TranslatorFoundObject.getDeclarePosition(): int;
begin
    result := baseObject.getDeclarePosition();
end;

function TranslatorFoundObject.getStartPosition(): int;
begin
    result := baseObject.getStartPosition();
end;

function TranslatorFoundObject.getName(): UnicodeString;
begin
    result := baseObject.getName();
end;

function TranslatorFoundObject.getDataType(): TypeDescriptor;
begin
    result := baseObject.getDataType();
end;

function TranslatorFoundObject.isPublic(): boolean;
begin
    result := baseObject.isPublic();
end;

function TranslatorFoundObject.getOffset(): int;
begin
    result := baseObject.getOffset();
end;

function TranslatorFoundObject.getOwner(): TypeStructure;
begin
    result := baseObject.getOwner();
end;

function TranslatorFoundObject.getFoundIn(): LocalVariable;
begin
    result := foundIn;
end;

function TranslatorFoundObject.getBaseObject(): StructureField;
begin
    result := baseObject;
end;

end.