lexer.cs
来自「全功能c#编译器」· CS 代码 · 共 767 行 · 第 1/2 页
CS
767 行
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Andrea Paatz" email="andrea@icsharpcode.net"/>
// <version value="$version"/>
// </file>
using System;
using System.IO;
using System.Collections;
using System.Drawing;
using System.Diagnostics;
using System.Globalization;
using System.Text;
using ICSharpCode.CsVbRefactory.Parser;
namespace ICSharpCode.CsVbRefactory.Parser.CSharp
{
public class Lexer : AbstractLexer
{
public Lexer(TextReader reader) : base(reader)
{
}
protected override Token Next()
{
int nextChar;
while ((nextChar = reader.Read()) != -1) {
char ch = (char)nextChar;
++col;
if (Char.IsWhiteSpace(ch)) {
++col;
HandleLineEnd(ch);
continue;
}
if (Char.IsLetter(ch) || ch == '_') {
int x = col;
int y = line;
string s = ReadIdent(ch);
int keyWordToken = Keywords.GetToken(s);
if (keyWordToken >= 0) {
return new Token(keyWordToken, x, y);
}
return new Token(Tokens.Identifier, x, y, s);
}
if (Char.IsDigit(ch)) {
return ReadDigit(ch, col);
}
switch (ch) {
case '/':
int peek = reader.Peek();
if (peek == '/' || peek == '*') {
ReadComment();
continue;
}
break;
case '#':
Point start = new Point(col, line);
string directive = ReadIdent('#');
string argument = ReadToEOL();
// this.specialTracker.AddPreProcessingDirective(directive, argument, start, new Point(start.X + directive.Length + argument.Length, start.Y));
continue;
case '"':
return ReadString();
case '\'':
return ReadChar();
case '@':
int next = reader.Read();
++col;
if (next == -1) {
errors.Error(line, col, String.Format("EOF after @"));
} else {
int x = col;
int y = line;
ch = (char)next;
if (ch == '"') {
return ReadVerbatimString();
}
if (Char.IsLetterOrDigit(ch)) {
return new Token(Tokens.Identifier, x, y, ReadIdent(ch));
}
errors.Error(y, x, String.Format("Unexpected char in Lexer.Next() : {0}", ch));
}
break;
}
Token token = ReadOperator(ch);
// try error recovery :)
if (token == null) {
return Next();
}
return token;
}
return new Token(Tokens.EOF, col, line, String.Empty);
}
// The C# compiler has a fixed size length therefore we'll use a fixed size char array for identifiers
// it's also faster than using a string builder.
const int MAX_IDENTIFIER_LENGTH = 512;
char[] identBuffer = new char[MAX_IDENTIFIER_LENGTH];
string ReadIdent(char ch)
{
int curPos = 1;
identBuffer[0] = ch;
int peek;
while ((peek = reader.Peek()) != -1 && (Char.IsLetterOrDigit(ch = (char)peek) || ch == '_')) {
reader.Read();
++col;
if (curPos < MAX_IDENTIFIER_LENGTH) {
identBuffer[curPos++] = ch;
} else {
errors.Error(line, col, String.Format("Identifier too long"));
while ((peek = reader.Peek()) != -1 && (Char.IsLetterOrDigit(ch = (char)peek) || ch == '_')) {
reader.Read();
++col;
}
break;
}
}
return new String(identBuffer, 0, curPos);
}
Token ReadDigit(char ch, int x)
{
int y = line;
++col;
sb.Length = 0;
sb.Append(ch);
string prefix = null;
string suffix = null;
bool ishex = false;
bool isunsigned = false;
bool islong = false;
bool isfloat = false;
bool isdouble = false;
bool isdecimal = false;
char peek = (char)reader.Peek();
if (ch == '.') {
isdouble = true;
++col;
while (Char.IsDigit((char)reader.Peek())) { // read decimal digits beyond the dot
sb.Append((char)reader.Read());
++col;
}
peek = (char)reader.Peek();
} else if (ch == '0' && (peek == 'x' || peek == 'X')) {
reader.Read(); // skip 'x'
++col;
while (IsHex((char)reader.Peek())) {
sb.Append(Char.ToUpper((char)reader.Read()));
++col;
}
ishex = true;
prefix = "0x";
peek = (char)reader.Peek();
} else {
while (Char.IsDigit((char)reader.Peek())) {
sb.Append((char)reader.Read());
++col;
}
peek = (char)reader.Peek();
}
if (peek == '.') { // read floating point number
reader.Read();
peek = (char)reader.Peek();
if (!Char.IsDigit(peek)) {
isdouble = true; // double is default
// TODO: what happens with the '.' ?
} else {
isdouble = true; // double is default
if (ishex) {
errors.Error(y, x, String.Format("No hexadecimal floating point values allowed"));
}
sb.Append('.');
++col;
while (Char.IsDigit((char)reader.Peek())) { // read decimal digits beyond the dot
sb.Append((char)reader.Read());
++col;
}
peek = (char)reader.Peek();
}
}
if (peek == 'e' || peek == 'E') { // read exponent
isdouble = true;
sb.Append((char)reader.Read());
++col;
peek = (char)reader.Peek();
if (peek == '-' || peek == '+') {
sb.Append((char)reader.Read());
++col;
}
while (Char.IsDigit((char)reader.Peek())) { // read exponent value
sb.Append((char)reader.Read());
++col;
}
isunsigned = true;
peek = (char)reader.Peek();
}
if (peek == 'f' || peek == 'F') { // float value
reader.Read();
suffix = "f";
++col;
isfloat = true;
} else if (peek == 'm' || peek == 'M') { // double type suffix (obsolete, double is default)
reader.Read();
suffix = "m";
++col;
isdouble = true;
} else if (peek == 'd' || peek == 'D') { // decimal value
reader.Read();
suffix = "d";
++col;
isdecimal = true;
} else if (!isdouble) {
if (peek == 'u' || peek == 'U') {
reader.Read();
suffix = "u";
++col;
isunsigned = true;
peek = (char)reader.Peek();
}
if (peek == 'l' || peek == 'L') {
reader.Read();
peek = (char)reader.Peek();
++col;
islong = true;
if (!isunsigned && (peek == 'u' || peek == 'U')) {
reader.Read();
suffix = "lu";
++col;
isunsigned = true;
} else {
suffix = isunsigned ? "ul" : "l";
}
}
}
string digit = sb.ToString();
string stringValue = prefix + digit + suffix;
if (isfloat) {
try {
return new Token(Tokens.Literal, x, y, stringValue, Single.Parse(digit, CultureInfo.InvariantCulture));
} catch (Exception) {
errors.Error(y, x, String.Format("Can't parse float {0}", digit));
return new Token(Tokens.Literal, x, y, stringValue, 0f);
}
}
if (isdecimal) {
try {
return new Token(Tokens.Literal, x, y, stringValue, Decimal.Parse(digit, CultureInfo.InvariantCulture));
} catch (Exception) {
errors.Error(y, x, String.Format("Can't parse decimal {0}", digit));
return new Token(Tokens.Literal, x, y, stringValue, 0m);
}
}
if (isdouble) {
try {
return new Token(Tokens.Literal, x, y, stringValue, Double.Parse(digit, CultureInfo.InvariantCulture));
} catch (Exception) {
errors.Error(y, x, String.Format("Can't parse double {0}", digit));
return new Token(Tokens.Literal, x, y, stringValue, 0d);
}
}
if (islong) {
if (isunsigned) {
try {
return new Token(Tokens.Literal, x, y, stringValue, UInt64.Parse(digit, ishex ? NumberStyles.HexNumber : NumberStyles.Number));
} catch (Exception) {
errors.Error(y, x, String.Format("Can't parse unsigned long {0}", digit));
return new Token(Tokens.Literal, x, y, stringValue, 0UL);
}
} else {
try {
return new Token(Tokens.Literal, x, y, stringValue, Int64.Parse(digit, ishex ? NumberStyles.HexNumber : NumberStyles.Number));
} catch (Exception) {
errors.Error(y, x, String.Format("Can't parse long {0}", digit));
return new Token(Tokens.Literal, x, y, stringValue, 0L);
}
}
} else {
if (isunsigned) {
try {
return new Token(Tokens.Literal, x, y, stringValue, UInt32.Parse(digit, ishex ? NumberStyles.HexNumber : NumberStyles.Number));
} catch (Exception) {
errors.Error(y, x, String.Format("Can't parse unsigned int {0}", digit));
return new Token(Tokens.Literal, x, y, stringValue, 0U);
}
} else {
try {
return new Token(Tokens.Literal, x, y, stringValue, Int32.Parse(digit, ishex ? NumberStyles.HexNumber : NumberStyles.Number));
} catch (Exception) {
errors.Error(y, x, String.Format("Can't parse int {0}", digit));
return new Token(Tokens.Literal, x, y, stringValue, 0);
}
}
}
}
Token ReadString()
{
int x = col;
int y = line;
sb.Length = 0;
originalValue.Length = 0;
originalValue.Append('"');
bool doneNormally = false;
int nextChar;
while ((nextChar = reader.Read()) != -1) {
char ch = (char)nextChar;
++col;
if (ch == '"') {
doneNormally = true;
originalValue.Append('"');
break;
}
if (ch == '\\') {
originalValue.Append('\\');
originalValue.Append(ReadEscapeSequence(out ch));
sb.Append(ch);
} else if (ch == '\n') {
errors.Error(y, x, String.Format("No new line is allowed inside a string literal"));
break;
} else {
originalValue.Append(ch);
sb.Append(ch);
}
}
if (!doneNormally) {
errors.Error(y, x, String.Format("End of file reached inside string literal"));
}
return new Token(Tokens.Literal, x, y, originalValue.ToString(), sb.ToString());
}
Token ReadVerbatimString()
{
int x = col;
int y = line;
int nextChar;
sb.Length = 0;
originalValue.Length = 0;
originalValue.Append("@\"");
while ((nextChar = reader.Read()) != -1) {
char ch = (char)nextChar;
++col;
if (ch == '"') {
if (reader.Peek() != '"') {
originalValue.Append('"');
break;
}
originalValue.Append("\"\"");
sb.Append('"');
reader.Read();
}
if (HandleLineEnd(ch)) {
sb.Append('\n');
originalValue.Append('\n');
} else {
sb.Append(ch);
originalValue.Append(ch);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?