private void ReadNumber()
{
// Just read everything that looks like it could be a number -- we will
// verify it afterwards by proper number parsing.
var sb = new StringBuilder();
var hasOctalPrefix = false;
var hasExponentialModifier = false;
var hasDotModifier = false;
var hasFloatSuffix = false;
var hasIntegerSuffix = false;
var hasHexModifier = false;
var isPreprocessingNumber = false;
while (true)
{
switch (_charReader.Current)
{
// dot
case '.':
if (hasHexModifier || hasOctalPrefix)
goto ExitLoop;
sb.Append(_charReader.Current);
NextChar();
hasDotModifier = true;
break;
// special handling for e, it could be the exponent indicator
// followed by an optional sign
case 'E':
case 'e':
if (hasHexModifier)
goto case '0';
sb.Append(_charReader.Current);
NextChar();
hasExponentialModifier = true;
if (_charReader.Current == '-' || _charReader.Current == '+')
{
sb.Append(_charReader.Current);
NextChar();
}
break;
case 'F':
case 'f':
case 'H':
case 'h':
if (hasHexModifier)
goto case '0';
hasFloatSuffix = true;
NextChar();
goto ExitLoop;
case 'L':
case 'l':
case 'U':
case 'u':
hasIntegerSuffix = true;
var currentSuffix = _charReader.Current;
NextChar();
if ((currentSuffix == 'U' || currentSuffix == 'u')
&& (_charReader.Current == 'L' || _charReader.Current == 'l'))
{
NextChar();
}
else if ((currentSuffix == 'L' || currentSuffix == 'l')
&& (_charReader.Current == 'U' || _charReader.Current == 'u'))
{
NextChar();
}
goto ExitLoop;
case '#':
if (sb.ToString() != "1.")
goto ExitLoop;
if (_charReader.Peek(1) == 'I' && _charReader.Peek(2) == 'N'
&& (_charReader.Peek(3) == 'D' || _charReader.Peek(3) == 'F'))
{
var isInfinity = _charReader.Peek(3) == 'F';
NextChar();
NextChar();
NextChar();
NextChar();
_kind = SyntaxKind.FloatLiteralToken;
_value = isInfinity ? float.PositiveInfinity : float.NaN;
return;
}
goto ExitLoop;
case 'X':
case 'x':
hasHexModifier = true;
sb.Append(_charReader.Current);
NextChar();
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (_charReader.Current == '0' && sb.Length == 0)
{
switch (_charReader.Peek())
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
hasOctalPrefix = true;
break;
}
sb.Append(_charReader.Current);
NextChar();
break;
}
if (hasOctalPrefix)
{
switch (_charReader.Current)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
sb.Append(_charReader.Current);
NextChar();
break;
default:
goto ExitLoop;
}
}
else
{
sb.Append(_charReader.Current);
NextChar();
}
break;
case 'A':
case 'B':
case 'C':
case 'D':
case 'a':
case 'b':
case 'c':
case 'd':
if (hasHexModifier)
goto case '0';
goto default;
default:
if (_mode == LexerMode.Directive && char.IsLetter(_charReader.Current))
{
isPreprocessingNumber = true;
goto case '0';
}
goto ExitLoop;
}
}
ExitLoop:
var text = sb.ToString();
if (isPreprocessingNumber)
_value = ReadPreprocessingNumber(text);
else if ((hasDotModifier || hasExponentialModifier || hasFloatSuffix) && !hasHexModifier)
_value = ReadDouble(text);
else
_value = ReadInt32OrInt64(text, hasHexModifier, hasOctalPrefix);
}