LanguageLexer.avt

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

/*
    Компилятор языка программирования
    Объектно-ориентированный продвинутый векторный транслятор

    Copyright © 2021, 2024 Малик Разработчик

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

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

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

package ru.malik.elaborarer.avtoo.compiler;

import avt.lang.math.*;
import ru.malik.elaborarer.avtoo.lang.*;

public class LanguageLexer(Lexer, AVTOOConstants)
{
    private static final long UCMP   = 0x8000000000000000L;
    private static final long BLIMIT = 0x8000000000000000L;
    private static final long OLIMIT = 0x2000000000000000L;
    private static final long DLIMIT = 0x1999999999999999L;
    private static final long XLIMIT = 0x1000000000000000L;
    private static final long ILIMIT = 0x0000000100000000L;

    private static final char[] symbols;
    private static final String[] lexemes;
    private static final DocumentLexer defaultDocumentationLexer;

    private static {
        symbols = ".,:;`?=()[]{}<>!~&^|+-*/%#@".toCharArray();
        lexemes = new String[LEXEMES_LENGTH];
        lexemes[PRIVATE       ] = "private";
        lexemes[PACKAGE       ] = "package";
        lexemes[PROTECTED     ] = "protected";
        lexemes[PUBLIC        ] = "public";
        lexemes[PUBLISHED     ] = "published";
        lexemes[IMPORT        ] = "import";
        lexemes[UNION         ] = "union";
        lexemes[ABSTRACT      ] = "abstract";
        lexemes[FINAL         ] = "final";
        lexemes[CLASS         ] = "class";
        lexemes[STRUCT        ] = "struct";
        lexemes[SERVICE       ] = "service";
        lexemes[INTERFACE     ] = "interface";
        lexemes[HELPER        ] = "helper";
        lexemes[STATIC        ] = "static";
        lexemes[NATIVE        ] = "native";
        lexemes[INTERRUPT     ] = "interrupt";
        lexemes[SYNCHRONIZED  ] = "synchronized";
        lexemes[OPERATOR      ] = "operator";
        lexemes[THROWS        ] = "throws";
        lexemes[FALSE         ] = "false";
        lexemes[TRUE          ] = "true";
        lexemes[NULL          ] = "null";
        lexemes[NEW           ] = "new";
        lexemes[SUPER         ] = "super";
        lexemes[THIS          ] = "this";
        lexemes[INSTANCEOF    ] = "instanceof";
        lexemes[VOID          ] = "void";
        lexemes[BOOLEAN       ] = "boolean";
        lexemes[CHAR          ] = "char";
        lexemes[REAL          ] = "real";
        lexemes[DOUBLE        ] = "double";
        lexemes[DOUBLE2       ] = "double2";
        lexemes[DOUBLE4       ] = "double4";
        lexemes[DOUBLE8       ] = "double8";
        lexemes[FLOAT         ] = "float";
        lexemes[FLOAT2        ] = "float2";
        lexemes[FLOAT4        ] = "float4";
        lexemes[FLOAT8        ] = "float8";
        lexemes[BYTE          ] = "byte";
        lexemes[BYTE2         ] = "byte2";
        lexemes[BYTE4         ] = "byte4";
        lexemes[BYTE8         ] = "byte8";
        lexemes[SHORT         ] = "short";
        lexemes[SHORT2        ] = "short2";
        lexemes[SHORT4        ] = "short4";
        lexemes[SHORT8        ] = "short8";
        lexemes[INT           ] = "int";
        lexemes[INT2          ] = "int2";
        lexemes[INT4          ] = "int4";
        lexemes[INT8          ] = "int8";
        lexemes[LONG          ] = "long";
        lexemes[LONG2         ] = "long2";
        lexemes[LONG4         ] = "long4";
        lexemes[LONG8         ] = "long8";
        lexemes[WITH          ] = "with";
        lexemes[IF            ] = "if";
        lexemes[ELSE          ] = "else";
        lexemes[SWITCH        ] = "switch";
        lexemes[CASE          ] = "case";
        lexemes[DEFAULT       ] = "default";
        lexemes[DO            ] = "do";
        lexemes[FOR           ] = "for";
        lexemes[WHILE         ] = "while";
        lexemes[BREAK         ] = "break";
        lexemes[CONTINUE      ] = "continue";
        lexemes[RETURN        ] = "return";
        lexemes[THROW         ] = "throw";
        lexemes[TRY           ] = "try";
        lexemes[CATCH         ] = "catch";
        lexemes[FINALLY       ] = "finally";
        lexemes[INC_LOCAL     ] = "++";
        lexemes[DEC_LOCAL     ] = "--";
        lexemes[BOOL_NOT      ] = "!";
        lexemes[BOOL_AND      ] = "&&";
        lexemes[BOOL_OR       ] = "||";
        lexemes[O_BIT_NOT     ] = "~";
        lexemes[O_BIT_AND     ] = "&";
        lexemes[O_BIT_OR      ] = "|";
        lexemes[O_BIT_XOR     ] = "^";
        lexemes[O_SCAL_MUL    ] = "*";
        lexemes[O_SCAL_DIV    ] = "/";
        lexemes[O_SCAL_DIVU   ] = "//";
        lexemes[O_SCAL_REM    ] = "%";
        lexemes[O_SCAL_REMU   ] = "%%";
        lexemes[O_SCAL_ADD    ] = "+";
        lexemes[O_SCAL_SUB    ] = "-";
        lexemes[O_SCAL_SHR    ] = ">>";
        lexemes[O_SCAL_SHRU   ] = ">>>";
        lexemes[O_SCAL_SHL    ] = "<<";
        lexemes[O_SCAL_GT     ] = ">";
        lexemes[O_SCAL_GE     ] = ">=";
        lexemes[O_SCAL_LT     ] = "<";
        lexemes[O_SCAL_LE     ] = "<=";
        lexemes[O_SCAL_EQ     ] = "==";
        lexemes[O_SCAL_NE     ] = "!=";
        lexemes[O_VECT_LUP    ] = "####";
        lexemes[O_VECT_UUP    ] = "^^^^";
        lexemes[O_VECT_PCK    ] = "@@@@";
        lexemes[O_VECT_MUL    ] = "****";
        lexemes[O_VECT_DIV    ] = "////";
        lexemes[O_VECT_ADD    ] = "++++";
        lexemes[O_VECT_SUB    ] = "----";
        lexemes[O_VECT_SHR    ] = ">>>>";
        lexemes[O_VECT_SHRU   ] = ">>>>>";
        lexemes[O_VECT_SHL    ] = "<<<<";
        lexemes[O_VECT_GT     ] = "|>>|";
        lexemes[O_VECT_GE     ] = "|>=|";
        lexemes[O_VECT_LT     ] = "|<<|";
        lexemes[O_VECT_LE     ] = "|<=|";
        lexemes[O_VECT_EQ     ] = "|==|";
        lexemes[O_VECT_NE     ] = "|!=|";
        lexemes[O_VECT_HMUL   ] = "|**|";
        lexemes[O_VECT_HMULU  ] = "#**#";
        lexemes[O_VECT_SADD   ] = "|++|";
        lexemes[O_VECT_SADDU  ] = "#++#";
        lexemes[O_VECT_SSUB   ] = "|--|";
        lexemes[O_VECT_SSUBU  ] = "#--#";
        lexemes[A_BIT_AND     ] = "&=";
        lexemes[A_BIT_OR      ] = "|=";
        lexemes[A_BIT_XOR     ] = "^=";
        lexemes[A_SCAL_MUL    ] = "*=";
        lexemes[A_SCAL_DIV    ] = "/=";
        lexemes[A_SCAL_DIVU   ] = "//=";
        lexemes[A_SCAL_REM    ] = "%=";
        lexemes[A_SCAL_REMU   ] = "%%=";
        lexemes[A_SCAL_ADD    ] = "+=";
        lexemes[A_SCAL_SUB    ] = "-=";
        lexemes[A_SCAL_SHR    ] = ">>=";
        lexemes[A_SCAL_SHRU   ] = ">>>=";
        lexemes[A_SCAL_SHL    ] = "<<=";
        lexemes[A_VECT_MUL    ] = "****=";
        lexemes[A_VECT_DIV    ] = "////=";
        lexemes[A_VECT_ADD    ] = "++++=";
        lexemes[A_VECT_SUB    ] = "----=";
        lexemes[A_VECT_SHR    ] = ">>>>=";
        lexemes[A_VECT_SHRU   ] = ">>>>>=";
        lexemes[A_VECT_SHL    ] = "<<<<=";
        lexemes[A_VECT_GT     ] = "|>>|=";
        lexemes[A_VECT_GE     ] = "|>=|=";
        lexemes[A_VECT_LT     ] = "|<<|=";
        lexemes[A_VECT_LE     ] = "|<=|=";
        lexemes[A_VECT_EQ     ] = "|==|=";
        lexemes[A_VECT_NE     ] = "|!=|=";
        lexemes[A_VECT_HMUL   ] = "|**|=";
        lexemes[A_VECT_HMULU  ] = "#**#=";
        lexemes[A_VECT_SADD   ] = "|++|=";
        lexemes[A_VECT_SADDU  ] = "#++#=";
        lexemes[A_VECT_SSUB   ] = "|--|=";
        lexemes[A_VECT_SSUBU  ] = "#--#=";
        lexemes[PARENTH_OPENED] = "(";
        lexemes[PARENTH_CLOSED] = ")";
        lexemes[BRACKET_OPENED] = "[";
        lexemes[BRACKET_CLOSED] = "]";
        lexemes[CURLY_OPENED  ] = "{";
        lexemes[CURLY_CLOSED  ] = "}";
        lexemes[EQUALS        ] = "=";
        lexemes[QUESTION      ] = "?";
        lexemes[REVERSE       ] = "`";
        lexemes[PERIOD        ] = ".";
        lexemes[COMMA         ] = ",";
        lexemes[COLON         ] = ":";
        lexemes[SEMICOLON     ] = ";";
        defaultDocumentationLexer = new DocumentLexer() { lineEndingEnabled = true };
    }

    private static int parseName(int lineIndex, char[] line, int charIndex, char chr, LexemeSequence sequence) throws TextSourceException {
        if((chr < 'A' || chr > 'Z') && (chr < 'a' || chr > 'z') && (chr != '_')) return charIndex;
        int result = charIndex + 1;
        int length = 1;
        for(; (chr = line[result]) >= 'A' && chr <= 'Z' || chr >= 'a' && chr <= 'z' || chr >= '0' && chr <= '9' || chr == '_'; result++) if(++length > LIMIT_NAME_LENGTH)
        {
            throw new TextSourceException(package.getResourceString("lexer.name.too-long")) {
                source = !(sequence instanceof TextSource) ? null : (TextSource) sequence,
                lineIndex = lineIndex,
                charIndex = charIndex
            };
        }
        label0:
        {
            if(length <= 12) for(int index = KEYWORDS_LENGTH; (index = Array.lastIndexOfNon(null, lexemes, index - 1, 0)) >= 0; )
            {
                String lexeme = lexemes[index];
                if(lexeme.length == length && lexeme.contentEquals(line, charIndex)) switch(index)
                {
                case TRUE:
                case FALSE:
                    sequence.appendLexeme(lineIndex, charIndex, L_BOOLEAN, index != FALSE);
                    break label0;
                default:
                    sequence.appendLexeme(lineIndex, charIndex, index, lexeme);
                    break label0;
                }
            }
            sequence.appendLexeme(lineIndex, charIndex, L_NAME, new String(line, charIndex, length));
        }
        return result;
    }

    private static int parseChar(int lineIndex, char[] line, int charIndex, char chr, LexemeSequence sequence) throws TextSourceException {
        if(chr != '\u0027') return charIndex;
        int result = charIndex + 1;
        int2 ic = parseStringChar(line, result, line[result]);
        int code = ic[1];
        result = ic[0];
        if(code < 0 || line[result++] != '\u0027')
        {
            throw new TextSourceException(String.format(package.getResourceString("lexer.literal.type"), new Object[] { "char" })) {
                source = !(sequence instanceof TextSource) ? null : (TextSource) sequence,
                lineIndex = lineIndex,
                charIndex = charIndex
            };
        }
        sequence.appendLexeme(lineIndex, charIndex, L_CHAR, (char) code);
        return result;
    }

    private static int parseString(int lineIndex, char[] line, int charIndex, char chr, LexemeSequence sequence) throws TextSourceException {
        if(chr != '\u0022') return charIndex;
        int result = charIndex + 1;
        int length = 0;
        int capacity = 0x7f;
        char[] buffer = new char[capacity];
        while((chr = line[result]) != '\u0022')
        {
            int2 ic = parseStringChar(line, result, chr);
            int code = ic[1];
            result = ic[0];
            if(code < 0)
            {
                throw new TextSourceException(String.format(package.getResourceString("lexer.literal.type"), new Object[] { PACKNAME_LANG + "." + TYPENAME_STRING })) {
                    source = !(sequence instanceof TextSource) ? null : (TextSource) sequence,
                    lineIndex = lineIndex,
                    charIndex = charIndex
                };
            }
            if(length == capacity)
            {
                if(length == (Short.MAX_VALUE << 1 | 1))
                {
                    throw new TextSourceException(String.format(package.getResourceString("lexer.literal.too-long"), new Object[] { PACKNAME_LANG + "." + TYPENAME_STRING })) {
                        source = !(sequence instanceof TextSource) ? null : (TextSource) sequence,
                        lineIndex = lineIndex,
                        charIndex = charIndex
                    };
                }
                Array.copy(buffer, 0, buffer = new char[capacity = capacity << 1 | 1], 0, length);
            }
            buffer[length++] = (char) code;
        }
        result++;
        sequence.appendLexeme(lineIndex, charIndex, L_STRING, new String(buffer, 0, length));
        return result;
    }

    private static int parseNumeric(int lineIndex, char[] line, int charIndex, char chr, LexemeSequence sequence) throws TextSourceException {
        if((chr < '0' || chr > '9') && (chr != '.')) return charIndex;
        boolean hasOverflow = false;
        int result = charIndex + 1;
        long rawNumber = 0L; /* беззнаковое значение */
        /* префикс системы счисления */
        label0: if(chr == '0')
        {
            label1:
            {
                label2: switch(line[result])
                {
                case 'B':
                case 'b':
                    if((chr = line[result + 1]) < '0' || chr > '1')
                    {
                        sequence.appendLexeme(lineIndex, charIndex, L_BYTE, 0);
                        return result;
                    }
                    if(chr == '1' && line[result + 2] == '.') for(int shift = 63, chr = line[result += 3]; ; chr = line[++result])
                    {
                        int digit;
                        if(chr >= '0' && chr <= '1')
                        {
                            digit = chr - '0';
                        }
                        else if(chr == 'p' || chr == 'P')
                        {
                            break label1;
                        }
                        else
                        {
                            throw new TextSourceException(package.getResourceString("lexer.literal.numeric")) {
                                source = !(sequence instanceof TextSource) ? null : (TextSource) sequence,
                                lineIndex = lineIndex,
                                charIndex = charIndex
                            };
                        }
                        if(shift >= 0)
                        {
                            rawNumber |= (long) digit << shift;
                            shift--;
                        }
                    }
                    for(result++; ; chr = line[++result])
                    {
                        int digit;
                        if(chr >= '0' && chr <= '1')
                        {
                            digit = chr - '0';
                        }
                        else
                        {
                            break label2;
                        }
                        if(rawNumber + UCMP >= BLIMIT + UCMP)
                        {
                            hasOverflow = true;
                        } else
                        {
                            rawNumber = rawNumber << 1 | digit;
                        }
                    }
                case 'O':
                case 'o':
                    if((chr = line[result + 1]) < '0' || chr > '7')
                    {
                        sequence.appendLexeme(lineIndex, charIndex, L_BYTE, 0);
                        return result;
                    }
                    if(chr == '1' && line[result + 2] == '.') for(int shift = 61, chr = line[result += 3]; ; chr = line[++result])
                    {
                        int digit;
                        if(chr >= '0' && chr <= '7')
                        {
                            digit = chr - '0';
                        }
                        else if(chr == 'p' || chr == 'P')
                        {
                            break label1;
                        }
                        else
                        {
                            throw new TextSourceException(package.getResourceString("lexer.literal.numeric")) {
                                source = !(sequence instanceof TextSource) ? null : (TextSource) sequence,
                                lineIndex = lineIndex,
                                charIndex = charIndex
                            };
                        }
                        if(shift >= 0)
                        {
                            rawNumber |= (long) digit << shift;
                            shift -= 3;
                        }
                    }
                    for(result++; ; chr = line[++result])
                    {
                        int digit;
                        if(chr >= '0' && chr <= '7')
                        {
                            digit = chr - '0';
                        }
                        else
                        {
                            break label2;
                        }
                        if(rawNumber + UCMP >= OLIMIT + UCMP)
                        {
                            hasOverflow = true;
                        } else
                        {
                            rawNumber = rawNumber << 3 | digit;
                        }
                    }
                case 'X':
                case 'x':
                    if(((chr = line[result + 1]) < '0' || chr > '9') && (chr < 'a' || chr > 'f') && (chr < 'A' || chr > 'F'))
                    {
                        sequence.appendLexeme(lineIndex, charIndex, L_BYTE, 0);
                        return result;
                    }
                    if(chr == '1' && line[result + 2] == '.') for(int shift = 60, chr = line[result += 3]; ; chr = line[++result])
                    {
                        int digit;
                        if(chr >= '0' && chr <= '9')
                        {
                            digit = chr - '0';
                        }
                        else if(chr >= 'a' && chr <= 'f')
                        {
                            digit = chr - ('a' - 0x0a);
                        }
                        else if(chr >= 'A' && chr <= 'F')
                        {
                            digit = chr - ('A' - 0x0a);
                        }
                        else if(chr == 'p' || chr == 'P')
                        {
                            break label1;
                        }
                        else
                        {
                            throw new TextSourceException(package.getResourceString("lexer.literal.numeric")) {
                                source = !(sequence instanceof TextSource) ? null : (TextSource) sequence,
                                lineIndex = lineIndex,
                                charIndex = charIndex
                            };
                        }
                        if(shift >= 0)
                        {
                            rawNumber |= (long) digit << shift;
                            shift -= 4;
                        }
                    }
                    for(result++; ; chr = line[++result])
                    {
                        int digit;
                        if(chr >= '0' && chr <= '9')
                        {
                            digit = chr - '0';
                        }
                        else if(chr >= 'a' && chr <= 'f')
                        {
                            digit = chr - ('a' - 0x0a);
                        }
                        else if(chr >= 'A' && chr <= 'F')
                        {
                            digit = chr - ('A' - 0x0a);
                        }
                        else
                        {
                            break label2;
                        }
                        if(rawNumber + UCMP >= XLIMIT + UCMP)
                        {
                            hasOverflow = true;
                        } else
                        {
                            rawNumber = rawNumber << 4 | digit;
                        }
                    }
                default:
                    break label0;
                }
                /* тип целого числа */
                switch(chr)
                {
                case 'S':
                case 's':
                    if(rawNumber + UCMP >= ILIMIT + UCMP || (rawNumber = (int) rawNumber) < Short.MIN_VALUE || rawNumber > Short.MAX_VALUE)
                    {
                        throw new TextSourceException(String.format(package.getResourceString("lexer.literal.type"), new Object[] { "short" })) {
                            source = !(sequence instanceof TextSource) ? null : (TextSource) sequence,
                            lineIndex = lineIndex,
                            charIndex = charIndex
                        };
                    }
                    result++;
                    sequence.appendLexeme(lineIndex, charIndex, L_SHORT, (short) rawNumber);
                    break;
                case 'I':
                case 'i':
                    if(rawNumber + UCMP >= ILIMIT + UCMP)
                    {
                        throw new TextSourceException(String.format(package.getResourceString("lexer.literal.type"), new Object[] { "int" })) {
                            source = !(sequence instanceof TextSource) ? null : (TextSource) sequence,
                            lineIndex = lineIndex,
                            charIndex = charIndex
                        };
                    }
                    result++;
                    sequence.appendLexeme(lineIndex, charIndex, L_INT, (int) rawNumber);
                    break;
                case 'L':
                case 'l':
                    if(hasOverflow)
                    {
                        throw new TextSourceException(String.format(package.getResourceString("lexer.literal.type"), new Object[] { "long" })) {
                            source = !(sequence instanceof TextSource) ? null : (TextSource) sequence,
                            lineIndex = lineIndex,
                            charIndex = charIndex
                        };
                    }
                    result++;
                    sequence.appendLexeme(lineIndex, charIndex, L_LONG, rawNumber);
                    break;
                default:
                    if(rawNumber + UCMP >= ILIMIT + UCMP)
                    {
                        throw new TextSourceException(String.format(package.getResourceString("lexer.literal.type"), new Object[] { "int" })) {
                            source = !(sequence instanceof TextSource) ? null : (TextSource) sequence,
                            lineIndex = lineIndex,
                            charIndex = charIndex
                        };
                    }
                    if((rawNumber = (int) rawNumber) >= Byte.MIN_VALUE && rawNumber <= Byte.MAX_VALUE)
                    {
                        sequence.appendLexeme(lineIndex, charIndex, L_BYTE, (byte) rawNumber);
                        break;
                    }
                    if(rawNumber >= Short.MIN_VALUE && rawNumber <= Short.MAX_VALUE)
                    {
                        sequence.appendLexeme(lineIndex, charIndex, L_SHORT, (short) rawNumber);
                        break;
                    }
                    sequence.appendLexeme(lineIndex, charIndex, L_INT, (int) rawNumber);
                }
                return result;
            }
            /* порядок действительного числа */
            int order = 0;
            {
                boolean isNegative = (chr = line[++result]) == '-';
                boolean isSigned = isNegative || chr == '+';
                if(isSigned || chr >= '0' && chr <= '9')
                {
                    int index = !isSigned ? result : result + 1;
                    char dgt = line[index];
                    if(dgt >= '0' && dgt <= '9')
                    {
                        do if((order = (order * 10) + (dgt - '0')) > 99999)
                        {
                            throw new TextSourceException(package.getResourceString("lexer.literal.numeric")) {
                                source = !(sequence instanceof TextSource) ? null : (TextSource) sequence,
                                lineIndex = lineIndex,
                                charIndex = charIndex
                            };
                        } while((dgt = line[++index]) >= '0' && dgt <= '9');
                        if(isNegative) order = -order;
                        result = index;
                        chr = dgt;
                    }
                }
            }
            /* само действительное число */
            real realNumber = Long2.toRealBits(new long2 { 1L << 63 | rawNumber >> 1, 0x3fffL }) * pow2(order);
            /* тип действительного числа */
            switch(chr)
            {
            case 'F':
            case 'f':
                float floatNumber = (float) realNumber;
                if(Float.isInfinite(floatNumber))
                {
                    throw new TextSourceException(String.format(package.getResourceString("lexer.literal.type"), new Object[] { "float" })) {
                        source = !(sequence instanceof TextSource) ? null : (TextSource) sequence,
                        lineIndex = lineIndex,
                        charIndex = charIndex
                    };
                }
                result++;
                sequence.appendLexeme(lineIndex, charIndex, L_FLOAT, floatNumber);
                break;
            case 'D':
            case 'd':
                double doubleNumber = (double) realNumber;
                if(Double.isInfinite(doubleNumber))
                {
                    throw new TextSourceException(String.format(package.getResourceString("lexer.literal.type"), new Object[] { "double" })) {
                        source = !(sequence instanceof TextSource) ? null : (TextSource) sequence,
                        lineIndex = lineIndex,
                        charIndex = charIndex
                    };
                }
                result++;
                sequence.appendLexeme(lineIndex, charIndex, L_DOUBLE, doubleNumber);
                break;
            case 'R':
            case 'r':
                result++;
                /* падение через */
            default:
                if(Real.isInfinite(realNumber))
                {
                    throw new TextSourceException(String.format(package.getResourceString("lexer.literal.type"), new Object[] { "real" })) {
                        source = !(sequence instanceof TextSource) ? null : (TextSource) sequence,
                        lineIndex = lineIndex,
                        charIndex = charIndex
                    };
                }
                sequence.appendLexeme(lineIndex, charIndex, L_REAL, realNumber);
            }
            return result;
        }
        /* точка */
        boolean hasFractionPart = false;
        int lengthOfFractionPart = 0;
        if(chr == '.')
        {
            if((chr = line[result]) < '0' || chr > '9')
            {
                sequence.appendLexeme(lineIndex, charIndex, PERIOD, lexemes[PERIOD]);
                return result;
            }
            lengthOfFractionPart = 1;
            hasFractionPart = true;
            result++;
        }
        /* мантисса числа */
        for(boolean isRounded = false, rawNumber = chr - '0'; ; result++)
        {
            if((chr = line[result]) == '.')
            {
                if(hasFractionPart) break;
                hasFractionPart = true;
                continue;
            }
            if(chr < '0' || chr > '9') break;
            int digit = chr - '0';
            if(rawNumber + UCMP < DLIMIT + UCMP || rawNumber == DLIMIT && digit < 6)
            {
                rawNumber = rawNumber * 10L + digit;
                if(hasFractionPart) lengthOfFractionPart++;
                continue;
            }
            if(hasFractionPart)
            {
                if(!isRounded && digit >= 5 && rawNumber != 0xffffffffffffffffL) rawNumber++;
                isRounded = true;
                continue;
            }
            hasOverflow = true;
            lengthOfFractionPart--;
        }
        /* порядок числа */
        boolean hasOrder = false;
        int order = 0;
        if(chr == 'e' || chr == 'E')
        {
            boolean isNegative = false;
            int index = result + 1;
            char dgt = line[index];
            switch(dgt)
            {
            case '-':
                isNegative = true;
                /* падение через */
            case '+':
                dgt = line[++index];
            }
            if(dgt >= '0' && dgt <= '9')
            {
                do if((order = (order * 10) + (dgt - '0')) > 9999)
                {
                    throw new TextSourceException(package.getResourceString("lexer.literal.numeric")) {
                        source = !(sequence instanceof TextSource) ? null : (TextSource) sequence,
                        lineIndex = lineIndex,
                        charIndex = charIndex
                    };
                } while((dgt = line[++index]) >= '0' && dgt <= '9');
                if(isNegative) order = -order;
                hasOrder = true;
                result = index;
                chr = dgt;
            }
        }
        /* само число */
        if((hasFractionPart || hasOrder) && rawNumber != 0L) for(; rawNumber %% 10L == 0L; rawNumber //= 10L) lengthOfFractionPart--;
        real realNumber = RealRepresenter.pow10((real) (rawNumber + UCMP) - (real) UCMP, order - lengthOfFractionPart);
        /* тип числа */
        switch(chr)
        {
        case 'S':
        case 's':
            if(hasFractionPart || hasOrder || hasOverflow || rawNumber + UCMP > Short.MAX_VALUE + UCMP)
            {
                throw new TextSourceException(String.format(package.getResourceString("lexer.literal.type"), new Object[] { "short" })) {
                    source = !(sequence instanceof TextSource) ? null : (TextSource) sequence,
                    lineIndex = lineIndex,
                    charIndex = charIndex
                };
            }
            result++;
            sequence.appendLexeme(lineIndex, charIndex, L_SHORT, (short) rawNumber);
            break;
        case 'I':
        case 'i':
            if(hasFractionPart || hasOrder || hasOverflow || rawNumber + UCMP > Int.MAX_VALUE + UCMP)
            {
                throw new TextSourceException(String.format(package.getResourceString("lexer.literal.type"), new Object[] { "int" })) {
                    source = !(sequence instanceof TextSource) ? null : (TextSource) sequence,
                    lineIndex = lineIndex,
                    charIndex = charIndex
                };
            }
            result++;
            sequence.appendLexeme(lineIndex, charIndex, L_INT, (int) rawNumber);
            break;
        case 'L':
        case 'l':
            if(hasFractionPart || hasOrder || hasOverflow || rawNumber + UCMP > Long.MAX_VALUE + UCMP)
            {
                throw new TextSourceException(String.format(package.getResourceString("lexer.literal.type"), new Object[] { "long" })) {
                    source = !(sequence instanceof TextSource) ? null : (TextSource) sequence,
                    lineIndex = lineIndex,
                    charIndex = charIndex
                };
            }
            result++;
            sequence.appendLexeme(lineIndex, charIndex, L_LONG, rawNumber);
            break;
        case 'F':
        case 'f':
            float floatNumber = (float) realNumber;
            if(Float.isInfinite(floatNumber))
            {
                throw new TextSourceException(String.format(package.getResourceString("lexer.literal.type"), new Object[] { "float" })) {
                    source = !(sequence instanceof TextSource) ? null : (TextSource) sequence,
                    lineIndex = lineIndex,
                    charIndex = charIndex
                };
            }
            result++;
            sequence.appendLexeme(lineIndex, charIndex, L_FLOAT, floatNumber);
            break;
        case 'D':
        case 'd':
            double doubleNumber = (double) realNumber;
            if(Double.isInfinite(doubleNumber))
            {
                throw new TextSourceException(String.format(package.getResourceString("lexer.literal.type"), new Object[] { "double" })) {
                    source = !(sequence instanceof TextSource) ? null : (TextSource) sequence,
                    lineIndex = lineIndex,
                    charIndex = charIndex
                };
            }
            result++;
            sequence.appendLexeme(lineIndex, charIndex, L_DOUBLE, doubleNumber);
            break;
        case 'R':
        case 'r':
            if(Real.isInfinite(realNumber))
            {
                throw new TextSourceException(String.format(package.getResourceString("lexer.literal.type"), new Object[] { "real" })) {
                    source = !(sequence instanceof TextSource) ? null : (TextSource) sequence,
                    lineIndex = lineIndex,
                    charIndex = charIndex
                };
            }
            result++;
            sequence.appendLexeme(lineIndex, charIndex, L_REAL, realNumber);
            break;
        default:
            if(hasFractionPart || hasOrder)
            {
                if(Real.isInfinite(realNumber))
                {
                    throw new TextSourceException(String.format(package.getResourceString("lexer.literal.type"), new Object[] { "real" })) {
                        source = !(sequence instanceof TextSource) ? null : (TextSource) sequence,
                        lineIndex = lineIndex,
                        charIndex = charIndex
                    };
                }
                sequence.appendLexeme(lineIndex, charIndex, L_REAL, realNumber);
                break;
            }
            if(rawNumber + UCMP > Int.MAX_VALUE + UCMP)
            {
                throw new TextSourceException(String.format(package.getResourceString("lexer.literal.type"), new Object[] { "int" })) {
                    source = !(sequence instanceof TextSource) ? null : (TextSource) sequence,
                    lineIndex = lineIndex,
                    charIndex = charIndex
                };
            }
            if(rawNumber <= Byte.MAX_VALUE)
            {
                sequence.appendLexeme(lineIndex, charIndex, L_BYTE, (byte) rawNumber);
                break;
            }
            if(rawNumber <= Short.MAX_VALUE)
            {
                sequence.appendLexeme(lineIndex, charIndex, L_SHORT, (short) rawNumber);
                break;
            }
            sequence.appendLexeme(lineIndex, charIndex, L_INT, (int) rawNumber);
        }
        return result;
    }

    private static int parseOperator(int lineIndex, char[] line, int charIndex, char chr, LexemeSequence sequence) throws TextSourceException {
        if(Array.indexOf(chr, symbols, 0, 0) < 0) return charIndex;
        int result = charIndex + 1;
        int length = 1;
        for(chr = line[result]; length < 6 && Array.indexOf(chr, symbols, 0, 0) >= 0; length++) chr = line[++result];
        label0: for(; length > 0; length--)
        {
            for(int index = LEXEMES_LENGTH; (index = Array.lastIndexOfNon(null, lexemes, index - 1, 0)) >= KEYWORDS_LENGTH; )
            {
                String lexeme = lexemes[index];
                if(lexeme.length == length && lexeme.contentEquals(line, charIndex))
                {
                    sequence.appendLexeme(lineIndex, charIndex, index, lexeme);
                    break label0;
                }
            }
            if(--result == charIndex)
            {
                throw new TextSourceException(package.getResourceString("lexer.operator")) {
                    source = !(sequence instanceof TextSource) ? null : (TextSource) sequence,
                    lineIndex = lineIndex,
                    charIndex = charIndex
                };
            }
        }
        return result;
    }

    private static int2 parseStringChar(char[] line, int charIndex, char chr) {
        switch(chr)
        {
        default:
            return new int2 { charIndex + 1, chr };
        case '\0':
        case '\"':
        case '\'':
            return new int2 { charIndex, -1 };
        case '\\':
        }
        int result = charIndex + 1;
        switch(line[result++])
        {
        default:
            return new int2 { charIndex, -1 };
        case '0':
            return new int2 { result, 0x0000 };
        case 'b':
            return new int2 { result, 0x0008 };
        case 't':
            return new int2 { result, 0x0009 };
        case 'n':
            return new int2 { result, 0x000a };
        case 'f':
            return new int2 { result, 0x000c };
        case 'r':
            return new int2 { result, 0x000d };
        case '\"':
            return new int2 { result, 0x0022 };
        case '\'':
            return new int2 { result, 0x0027 };
        case '\\':
            return new int2 { result, 0x005c };
        case 'u':
        }
        int code = 0;
        for(int cci = 4; cci-- > 0; )
        {
            int digit;
            if((chr = line[result++]) >= '0' && chr <= '9')
            {
                digit = chr - '0';
            }
            else if(chr >= 'a' && chr <= 'f')
            {
                digit = chr - ('a' - 0x0a);
            }
            else if(chr >= 'A' && chr <= 'F')
            {
                digit = chr - ('A' - 0x0a);
            }
            else
            {
                return new int2 { charIndex, -1 };
            }
            code = code << 4 | digit;
        }
        return new int2 { result, code };
    }

    private static real pow2(int power) {
        return (power += 0x3fff) < -62 ? (
            0
        ) : power < 0x0001 ? (
            Long2.toRealBits(new long2 { 1L << (power + 62), 0L })
        ) : power < 0x7fff ? (
            Long2.toRealBits(new long2 { 1L << 63, (long) power })
        ) : (
            Real.POSITIVE_INFINITY
        );
    }

    protected boolean fldDocumentationEnabled;
    protected DocumentLexer fldDocumentationLexer;

    public () {  }

    public (DocumentLexer documentationLexer) { fldDocumentationLexer = documentationLexer; }

    public void split(char[][] text, int2 locationBegin, int2 locationEnd, LexemeSequence sequence) throws TextSourceException {
        if(text == null)
        {
            throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "text" }));
        }
        if(sequence == null)
        {
            throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "sequence" }));
        }
        int limit = text.length;
        if(limit-- <= 0)
        {
            sequence.appendLexeme(0, 0, L_END);
            return;
        }
        int lineIndexBegin = locationBegin[0];
        int charIndexBegin = locationBegin[1];
        int lineIndexEnd = locationEnd[0];
        int charIndexEnd = locationEnd[1];
        int count = text[limit].length - 1;
        if(lineIndexBegin < 0)
        {
            lineIndexBegin = 0;
            charIndexBegin = 0;
        }
        if(lineIndexBegin > limit)
        {
            lineIndexBegin = limit;
            charIndexBegin = count;
        }
        if(lineIndexEnd < 0)
        {
            lineIndexEnd = 0;
            charIndexEnd = 0;
        }
        if(lineIndexEnd > limit)
        {
            lineIndexEnd = limit;
            charIndexEnd = count;
        }
        if(charIndexBegin < 0)
        {
            charIndexBegin = 0;
        }
        if(charIndexBegin > (count = text[lineIndexBegin].length - 1))
        {
            charIndexBegin = count;
        }
        if(charIndexEnd < 0)
        {
            charIndexEnd = 0;
        }
        if(charIndexEnd > (count = text[lineIndexEnd].length - 1))
        {
            charIndexEnd = count;
        }
        char[] last = text[lineIndexEnd];
        if(charIndexEnd < last.length - 1)
        {
            Array.copy(last, 0, last = new char[charIndexEnd + 1], 0, charIndexEnd);
        }
        for(int lineIndex = lineIndexBegin; lineIndex <= lineIndexEnd; lineIndex++)
        {
            int charIndex = lineIndex <= lineIndexBegin ? charIndexBegin : 0;
            char[] line = lineIndex >= lineIndexEnd ? last : text[lineIndex];
            label0: for(char chr = line[charIndex]; chr > 0x00; )
            {
                while(chr <= 0x20) if((chr = line[++charIndex]) <= 0x00) break label0;
                int2 location = parseComment(text, lineIndex, lineIndexEnd, last, line, charIndex, chr, sequence);
                if((new int2 { lineIndex, charIndex } |<<| location) != 0)
                {
                    lineIndex = location[0];
                    charIndex = location[1];
                    chr = (line = lineIndex >= lineIndexEnd ? last : text[lineIndex])[charIndex];
                    continue;
                }
                if(
                    charIndex < (charIndex = parseName(lineIndex, line, charIndex, chr, sequence)) ||
                    charIndex < (charIndex = parseChar(lineIndex, line, charIndex, chr, sequence)) ||
                    charIndex < (charIndex = parseString(lineIndex, line, charIndex, chr, sequence)) ||
                    charIndex < (charIndex = parseNumeric(lineIndex, line, charIndex, chr, sequence)) ||
                    charIndex < (charIndex = parseOperator(lineIndex, line, charIndex, chr, sequence))
                )
                {
                    chr = line[charIndex];
                    continue;
                }
                throw new TextSourceException(package.getResourceString("lexer.character")) {
                    source = !(sequence instanceof TextSource) ? null : (TextSource) sequence,
                    lineIndex = lineIndex,
                    charIndex = charIndex
                };
            }
        }
        sequence.appendLexeme(lineIndexEnd, charIndexEnd, L_END);
    }

    public boolean documentationEnabled { read = fldDocumentationEnabled, write = fldDocumentationEnabled }

    public DocumentLexer documentationLexer { read = fldDocumentationLexer, write = fldDocumentationLexer }

    protected LexemeSequence newDocumentLexemeSequence() { return null; }

    private int2 parseComment(char[][] text, int lineIndex, int lineIndexEnd, char[] last, char[] line, int charIndex, char chr, LexemeSequence sequence) {
        if(chr != '/' || line[charIndex + 1] != '*') return new int2 { lineIndex, charIndex };
        int charIndexContent = charIndex + 2;
        int lineIndexResult = lineIndex;
        int charIndexResult = charIndexContent;
        boolean isDocumentation = line[charIndexResult] == '*' && line[charIndexResult + 1] != '/';
        label0: for(; lineIndexResult <= lineIndexEnd; charIndexResult = 0, line = ++lineIndexResult >= lineIndexEnd ? last : text[lineIndexResult]) do
        {
            int charIndexEnd = Array.indexOf('*', line, charIndexResult, 0);
            if(charIndexEnd < 0)
            {
                if(lineIndexResult < lineIndexEnd) break;
                charIndexResult = line.length - 1;
                break label0;
            }
            if(line[charIndexEnd + 1] == '/')
            {
                charIndexResult = charIndexEnd;
                break label0;
            }
            charIndexResult = charIndexEnd + 1;
        } while(true);
        if(isDocumentation && fldDocumentationEnabled)
        {
            DocumentLexer lexer = fldDocumentationLexer;
            if(lexer == null) lexer = defaultDocumentationLexer;
            LexemeSequence documentation = newDocumentLexemeSequence();
            if(documentation == null) documentation = new LexemeSequence();
            lexer.split(text, new int2 { lineIndex, charIndexContent }, new int2 { lineIndexResult, charIndexResult }, documentation);
            sequence.appendLexeme(lineIndex, charIndex, L_DOC, documentation);
        }
        if(line[charIndexResult] == '*') charIndexResult += 2;
        return new int2 { lineIndexResult, charIndexResult };
    }
}