Beispiel #1
0
        private void LexChar(char characterToMatch, Token context)
        {
            int characterInt = PeekChar();

            if (characterInt == -1)
            {
                return;
            }

            char character = (char)characterInt;

            if (character != characterToMatch)
            {
                throw UnexpectedCharException.Create(character, context, characterToMatch);
            }

            AdvanceChar();
        }
Beispiel #2
0
        public Lexeme <Token> LexOne()
        {
            int  characterInt;
            char character;

Start:

            do
            {
                characterInt = AdvanceChar();

                if (characterInt == -1)
                {
                    return(MakeLexeme(Token.EoF));
                }

                character = (char)characterInt;
            }while (char.IsWhiteSpace(character));

            if (character == '/' && PeekChar() == '/')
            {
                characterInt = AdvanceChar();

                while (characterInt != -1 && characterInt != '\n')
                {
                    characterInt = AdvanceChar();
                }

                if (characterInt == -1)
                {
                    return(MakeLexeme(Token.EoF));
                }

                goto Start;
            }

            TokenBuffer.Append(character);

            switch (character)
            {
            case '+':
                return(MakeLexeme(SwitchOnNextCharacter(
                                      Token.Add,
                                      ('+', Token.Increment),
                                      ('=', Token.AddCompoundAssign))));

            case '-':
                return(MakeLexeme(SwitchOnNextCharacter(
                                      Token.Subtract,
                                      ('-', Token.Decrement),
                                      ('=', Token.SubtractCompoundAssign))));

            case '*':
                return(MakeLexeme(SwitchOnNextCharacter(
                                      Token.Multiply,
                                      ('=', Token.MultiplyCompoundAssign))));

            case '/':
                return(MakeLexeme(SwitchOnNextCharacter(
                                      Token.Divide,
                                      ('=', Token.DivideCompoundAssign))));

            case '%':
                return(MakeLexeme(SwitchOnNextCharacter(
                                      Token.Remainder,
                                      ('=', Token.RemainderCompoundAssign))));

            case '!':
                return(MakeLexeme(
                           SwitchOnNextCharacter(Token.LogicalNot,
                                                 ('=', Token.ComparisonNotEqual))));

            case '~':
                return(MakeLexeme(
                           Token.BitwiseNot));

            case '^':
                return(MakeLexeme(SwitchOnNextCharacter(
                                      Token.BitwiseXor,
                                      ('=', Token.BitwiseXorCompoundAssign))));

            case '=':
                return(MakeLexeme(SwitchOnNextCharacter(
                                      Token.Assign,
                                      ('=', Token.ComparisonEqual),
                                      ('>', Token.Arrow))));

            case ':':
                return(MakeLexeme(SwitchOnNextCharacter(
                                      Token.Colon,
                                      (':', Token.StaticAccessor))));

            case '&':
                var andType = SwitchOnNextCharacter(
                    Token.BitwiseAnd,
                    ('=', Token.BitwiseAndCompoundAssign),
                    ('&', Token.LogicalAnd));
                if (andType == Token.LogicalAnd)
                {
                    andType = SwitchOnNextCharacter(
                        Token.LogicalAnd,
                        ('=', Token.LogicalAndCompoundAssign));
                }
                return(MakeLexeme(andType));

            case '|':
                var orType = SwitchOnNextCharacter(
                    Token.BitwiseOr,
                    ('=', Token.BitwiseOrCompoundAssign),
                    ('|', Token.LogicalOr));
                if (orType == Token.LogicalOr)
                {
                    orType = SwitchOnNextCharacter(
                        Token.LogicalOr,
                        ('=', Token.LogicalOrCompoundAssign));
                }
                return(MakeLexeme(orType));

            case '<':
                var lessType = SwitchOnNextCharacter(
                    Token.ComparisonLessThan,
                    ('=', Token.ComparisonLessThanOrEqual),
                    ('-', Token.ReferenceAssign),
                    ('<', Token.BitshiftLeft));
                if (lessType == Token.BitshiftLeft)
                {
                    lessType = SwitchOnNextCharacter(
                        Token.BitshiftLeft,
                        ('=', Token.BitshiftLeftCompoundAssign));
                }
                return(MakeLexeme(lessType));

            case '>':
                var greaterType = SwitchOnNextCharacter(
                    Token.ComparisonGreaterThan,
                    ('=', Token.ComparisonGreaterThanOrEqual),
                    ('>', Token.BitshiftRight));
                if (greaterType == Token.BitshiftRight)
                {
                    greaterType = SwitchOnNextCharacter(
                        Token.BitshiftRight,
                        ('=', Token.BitshiftRightCompoundAssign));
                }
                return(MakeLexeme(greaterType));

            case '\'':
                LexEscapableChar(Token.CharacterLiteral);
                LexChar('\'', Token.CharacterLiteral);
                return(MakeLexeme(Token.CharacterLiteral));

            case '\"':
                while (true)
                {
                    int nextCharacterInt = PeekChar();

                    if (nextCharacterInt == -1)
                    {
                        throw UnexpectedCharException.Create(null, Token.StringLiteral, "a char or a string delimiter");
                    }

                    char nextCharacter = (char)nextCharacterInt;

                    if (nextCharacter == '\"')
                    {
                        AdvanceChar();
                        TokenBuffer.Append(nextCharacter);
                        break;
                    }

                    LexEscapableChar(Token.StringLiteral);
                }
                return(MakeLexeme(Token.StringLiteral));

            case '{':
                return(MakeLexeme(Token.LBraces));

            case '}':
                return(MakeLexeme(Token.RBraces));

            case '[':
                return(MakeLexeme(Token.LBrackets));

            case ']':
                return(MakeLexeme(Token.RBrackets));

            case '(':
                return(MakeLexeme(Token.LParens));

            case ')':
                return(MakeLexeme(Token.RParens));

            case ';':
                return(MakeLexeme(Token.Semicolon));

            case '?':
                return(MakeLexeme(Token.QuestionMark));

            case ',':
                return(MakeLexeme(Token.Comma));
            }

            // Identifier or keyword
            if (char.IsLetter(character) || character == '_')
            {
                while (true)
                {
                    int nextCharacterInt = PeekChar();

                    if (nextCharacterInt == -1)
                    {
                        break;
                    }

                    char nextCharacter = (char)nextCharacterInt;

                    if (!char.IsLetterOrDigit(nextCharacter) && nextCharacter != '_')
                    {
                        break;
                    }

                    AdvanceChar();

                    TokenBuffer.Append(nextCharacter);
                }

                return(MakeLexeme(_keywords.TryGetValue(TokenBuffer.ToString(), out Token keyword) ? keyword : Token.Identifier));
            }

            // Numerical literal
            {
                bool reachedDot = false;

                if (character == '.')
                {
                    reachedDot = true;

                    int nextCharacterInt = PeekChar();

                    if (nextCharacterInt == -1)
                    {
                        throw UnexpectedCharException.Create(null, Token.FloatLiteral, "Digit");
                    }

                    character = (char)nextCharacterInt;

                    if (!char.IsDigit(character))
                    {
                        return(MakeLexeme(Token.Accessor));
                        //throw UnexpectedCharException.Create(character, Token.FloatLiteral, "Digit");
                    }
                }

                if (char.IsDigit(character))
                {
                    LexNumber(ref reachedDot);

                    return(reachedDot
                        ? MakeLexeme(Token.FloatLiteral)
                        : MakeLexeme(Token.IntegerLiteral));
                }
            }

            throw UnexpectedCharException.Create(character, Token.EoF, "EoF");
        }