示例#1
0
        private LexResult LexNumber()
        {
            Debug.Assert(SyntaxUtils.IsNumeric(Buffer.Peek()) || Buffer.Peek() == '.');
            CppTokenKind kind;
            char         first   = Buffer.Peek(0);
            char         second  = Buffer.Peek(1);
            bool         dotSeen = false;

            if (first == '0')
            {
                if (second == 'x' || second == 'X')
                {
                    // Hex
                    kind = CppTokenKind.HexLiteral;
                    Buffer.AdvanceColumns(2); // Skip 0[xX]
                }
                else if (second == 'b' || second == 'B')
                {
                    // Binary
                    kind = CppTokenKind.BinaryLiteral;
                    Buffer.AdvanceColumns(2); // Skip 0[bB]
                }
                else
                {
                    // Octal
                    kind = CppTokenKind.OctalLiteral;
                }
            }
            else if (first == '.')
            {
                Debug.Assert(SyntaxUtils.IsNumeric(second));
                kind = CppTokenKind.IntegerFloatLiteral;
                Buffer.AdvanceColumn();
                dotSeen = true;
            }
            else
            {
                Debug.Assert(SyntaxUtils.IsNumeric(first));
                kind = CppTokenKind.IntegerLiteral;
            }

            // @NOTE(final): We never set the DecimalHexLiteral kind initially,
            // as every hex decimal always starts as a normal hex literal!
            Debug.Assert(kind != CppTokenKind.HexadecimalFloatLiteral);

            // First number part
            int  firstLiteralPos = Buffer.TextPosition.Index;
            bool readNextLiteral = false;

            do
            {
                readNextLiteral = false;
                int s = Buffer.TextPosition.Index;
                switch (kind)
                {
                case CppTokenKind.IntegerLiteral:
                case CppTokenKind.IntegerFloatLiteral:
                    if (SyntaxUtils.IsNumeric(Buffer.Peek()))
                    {
                        Buffer.AdvanceColumnsWhile(SyntaxUtils.IsNumeric);
                    }
                    else
                    {
                        AddError(Buffer.TextPosition, $"Expect integer literal, but got '{Buffer.Peek()}'", kind.ToString());
                    }
                    break;

                case CppTokenKind.OctalLiteral:
                    if (SyntaxUtils.IsOctal(Buffer.Peek()))
                    {
                        Buffer.AdvanceColumnsWhile(SyntaxUtils.IsOctal);
                    }
                    else
                    {
                        AddError(Buffer.TextPosition, $"Expect octal literal, but got '{Buffer.Peek()}'", kind.ToString());
                    }
                    break;

                case CppTokenKind.HexLiteral:
                    if (SyntaxUtils.IsHex(Buffer.Peek()))
                    {
                        Buffer.AdvanceColumnsWhile(SyntaxUtils.IsHex);
                    }
                    else
                    {
                        AddError(Buffer.TextPosition, $"Expect hex literal, but got '{Buffer.Peek()}'", kind.ToString());
                    }
                    break;

                case CppTokenKind.BinaryLiteral:
                    if (SyntaxUtils.IsBinary(Buffer.Peek()))
                    {
                        Buffer.AdvanceColumnsWhile(SyntaxUtils.IsBinary);
                    }
                    else
                    {
                        AddError(Buffer.TextPosition, $"Expect binary literal, but got '{Buffer.Peek()}'", kind.ToString());
                    }
                    break;

                default:
                    AddError(Buffer.TextPosition, $"Unsupported token kind '{kind}' for integer literal on {Buffer}", kind.ToString());
                    break;
                }
                bool hadIntegerLiteral = Buffer.TextPosition.Index > s;
                if (kind != CppTokenKind.IntegerFloatLiteral && kind != CppTokenKind.HexadecimalFloatLiteral)
                {
                    // @NOTE(final): Single quotes (') are allowed as separators for any non-decimal literal
                    char check0 = Buffer.Peek();
                    if (check0 == '\'')
                    {
                        if (!hadIntegerLiteral)
                        {
                            AddError(Buffer.TextPosition, $"Too many single quote escape in integer literal, expect any integer literal but got '{Buffer.Peek()}'", kind.ToString());
                            return(new LexResult(kind, false));
                        }
                        Buffer.AdvanceColumn();
                        readNextLiteral = true;
                    }
                }
            } while (!Buffer.IsEOF && readNextLiteral);

            // Validate any literal after starting dot
            if (dotSeen)
            {
                if (firstLiteralPos == Buffer.TextPosition.Index)
                {
                    AddError(Buffer.TextPosition, $"Expect any integer literal after starting dot, but got '{Buffer.Peek()}'", kind.ToString());
                    return(new LexResult(kind, false));
                }
            }

            // Dot separator
            if ((!dotSeen) &&
                ((kind == CppTokenKind.IntegerLiteral) ||
                 (kind == CppTokenKind.HexLiteral) ||
                 (kind == CppTokenKind.OctalLiteral)
                ))
            {
                char check0 = Buffer.Peek();
                if (check0 == '.')
                {
                    dotSeen = true;
                    Buffer.AdvanceColumn();
                    if (kind == CppTokenKind.IntegerLiteral || kind == CppTokenKind.OctalLiteral)
                    {
                        kind = CppTokenKind.IntegerFloatLiteral;
                    }
                    else
                    {
                        Debug.Assert(kind == CppTokenKind.HexLiteral);
                        kind = CppTokenKind.HexadecimalFloatLiteral;
                    }
                }
                else if (SyntaxUtils.IsExponentPrefix(check0))
                {
                    if (kind == CppTokenKind.IntegerLiteral || kind == CppTokenKind.OctalLiteral)
                    {
                        kind = CppTokenKind.IntegerFloatLiteral;
                    }
                    else
                    {
                        Debug.Assert(kind == CppTokenKind.HexLiteral);
                        kind = CppTokenKind.HexadecimalFloatLiteral;
                    }
                }
            }

            // Decimal after dot separator
            if ((kind != CppTokenKind.IntegerFloatLiteral) &&
                (kind != CppTokenKind.HexadecimalFloatLiteral))
            {
                // Integer suffix
                if (SyntaxUtils.IsIntegerSuffix(Buffer.Peek()))
                {
                    Buffer.AdvanceColumnsWhile(SyntaxUtils.IsIntegerSuffix, 3);
                }
            }
            else
            {
                if (kind == CppTokenKind.IntegerFloatLiteral)
                {
                    // Float decimal
                    if (SyntaxUtils.IsNumeric(Buffer.Peek()))
                    {
                        Buffer.AdvanceColumnsWhile(SyntaxUtils.IsNumeric);
                    }
                    if (Buffer.Peek() == 'e' || Buffer.Peek() == 'E')
                    {
                        AdvanceExponent('e');
                    }
                }
                else
                {
                    // Hex decimal
                    Debug.Assert(kind == CppTokenKind.HexadecimalFloatLiteral);
                    if (SyntaxUtils.IsHex(Buffer.Peek()))
                    {
                        Buffer.AdvanceColumnsWhile(SyntaxUtils.IsHex);
                    }
                    if (Buffer.Peek() == 'p' || Buffer.Peek() == 'P')
                    {
                        AdvanceExponent('e');
                    }
                }

                // Float suffix
                if (SyntaxUtils.IsFloatSuffix(Buffer.Peek()))
                {
                    Buffer.AdvanceColumn();
                }
            }
            return(new LexResult(kind, true));
        }