📄 expressionfinder.cs
字号:
curOffset += 2;
if (!ReadMultiLineComment(text, ref curOffset, ref offset)) {
return null;
}
} else {
goto default;
}
break;
case '#':
if (!ReadToEOL(text, ref curOffset, ref offset)) {
return null;
}
break;
default:
outText.Append(ch);
++curOffset;
break;
}
}
return outText.ToString();
}
bool ReadToEOL(string text, ref int curOffset, ref int offset)
{
while (curOffset <= initialOffset) {
char ch = text[curOffset++];
--offset;
if (ch == '\n') {
return true;
}
}
return false;
}
bool ReadChar(StringBuilder outText, string text, ref int curOffset)
{
if (curOffset > initialOffset)
return false;
char first = text[curOffset++];
outText.Append(first);
if (curOffset > initialOffset)
return false;
char second = text[curOffset++];
outText.Append(second);
if (first == '\\') {
// character is escape sequence, so read one char more
char next;
do {
if (curOffset > initialOffset)
return false;
next = text[curOffset++];
outText.Append(next);
// unicode or hexadecimal character literals can have more content characters
} while((second == 'u' || second == 'x') && char.IsLetterOrDigit(next));
}
return text[curOffset - 1] == '\'';
}
bool ReadString(StringBuilder outText, string text, ref int curOffset)
{
while (curOffset <= initialOffset) {
char ch = text[curOffset++];
outText.Append(ch);
if (ch == '"') {
return true;
} else if (ch == '\\') {
if (curOffset <= initialOffset)
outText.Append(text[curOffset++]);
}
}
return false;
}
bool ReadVerbatimString(StringBuilder outText, string text, ref int curOffset)
{
while (curOffset <= initialOffset) {
char ch = text[curOffset++];
outText.Append(ch);
if (ch == '"') {
if (curOffset < text.Length && text[curOffset] == '"') {
outText.Append(text[curOffset++]);
} else {
return true;
}
}
}
return false;
}
bool ReadMultiLineComment(string text, ref int curOffset, ref int offset)
{
while (curOffset <= initialOffset) {
char ch = text[curOffset++];
--offset;
if (ch == '*') {
if (curOffset < text.Length && text[curOffset] == '/') {
++curOffset;
--offset;
return true;
}
}
}
return false;
}
#endregion
#region mini backward lexer
string text;
int offset;
char GetNext()
{
if (offset >= 0) {
return text[offset--];
}
return '\0';
}
char GetNextNonWhiteSpace()
{
char ch;
do {
ch = GetNext();
} while (char.IsWhiteSpace(ch));
return ch;
}
char Peek(int n)
{
if (offset - n >= 0) {
return text[offset - n];
}
return '\0';
}
char Peek()
{
if (offset >= 0) {
return text[offset];
}
return '\0';
}
void UnGet()
{
++offset;
}
void UnGetToken()
{
do {
UnGet();
} while (char.IsLetterOrDigit(Peek()));
}
// tokens for our lexer
static int Err = 0;
static int Dot = 1;
static int StrLit = 2;
static int Ident = 3;
static int New = 4;
static int Bracket = 5;
static int Parent = 6;
static int Curly = 7;
static int Using = 8;
static int Digit = 9;
int curTokenType;
readonly static string[] tokenStateName = new string[] {
"Err", "Dot", "StrLit", "Ident", "New", "Bracket", "Paren", "Curly", "Using", "Digit"
};
string GetTokenName(int state)
{
return tokenStateName[state];
}
/// <summary>
/// used to control whether an expression is in a ObjectCreation context (new *expr*),
/// or is in the default context (e.g. "new MainForm().Show()", 'new ' is there part of the expression
/// </summary>
bool hadParenthesis;
string lastIdentifier;
void ReadNextToken()
{
curTokenType = Err;
char ch = GetNextNonWhiteSpace();
if (ch == '\0') {
return;
}
switch (ch) {
case '}':
if (ReadBracket('{', '}')) {
curTokenType = Curly;
}
break;
case ')':
if (ReadBracket('(', ')')) {
hadParenthesis = true;
curTokenType = Parent;
}
break;
case ']':
if (ReadBracket('[', ']')) {
curTokenType = Bracket;
}
break;
case '>':
if (ReadTypeParameters()) {
// hack: ignore type parameters and continue reading without changing state
ReadNextToken();
}
break;
case '.':
curTokenType = Dot;
break;
case ':':
if (GetNext() == ':') {
// treat :: like dot
curTokenType = Dot;
}
break;
case '\'':
case '"':
if (ReadStringLiteral(ch)) {
curTokenType = StrLit;
}
break;
default:
if (IsNumber(ch)) {
ReadDigit(ch);
curTokenType = Digit;
} else if (IsIdentifierPart(ch)) {
string ident = ReadIdentifier(ch);
if (ident != null) {
switch (ident) {
case "new":
curTokenType = New;
break;
case "using":
curTokenType = Using;
break;
case "return":
case "throw":
case "in":
case "else":
// treat as error / end of expression
break;
default:
curTokenType = Ident;
lastIdentifier = ident;
break;
}
}
}
break;
}
}
bool IsNumber(char ch)
{
if (!Char.IsDigit(ch))
return false;
int n = 0;
while (true) {
ch = Peek(n);
if (Char.IsDigit(ch)) {
n++;
continue;
}
return n > 0 && !Char.IsLetter(ch);
}
}
bool ReadStringLiteral(char litStart)
{
while (true) {
char ch = GetNext();
if (ch == '\0') {
return false;
}
if (ch == litStart) {
if (Peek() == '@' && litStart == '"') {
GetNext();
}
return true;
}
}
}
bool ReadTypeParameters()
{
int level = 1;
while (level > 0) {
char ch = GetNext();
switch (ch) {
case '?':
case '[':
case ',':
case ']':
break;
case '<':
--level;
break;
case '>':
++level;
break;
default:
if (!char.IsWhiteSpace(ch) && !char.IsLetterOrDigit(ch))
return false;
break;
}
}
return true;
}
bool ReadBracket(char openBracket, char closingBracket)
{
int curlyBraceLevel = 0;
int squareBracketLevel = 0;
int parenthesisLevel = 0;
switch (openBracket) {
case '(':
parenthesisLevel++;
break;
case '[':
squareBracketLevel++;
break;
case '{':
curlyBraceLevel++;
break;
}
while (parenthesisLevel != 0 || squareBracketLevel != 0 || curlyBraceLevel != 0) {
char ch = GetNext();
switch (ch) {
case '\0':
return false;
case '(':
parenthesisLevel--;
break;
case '[':
squareBracketLevel--;
break;
case '{':
curlyBraceLevel--;
break;
case ')':
parenthesisLevel++;
break;
case ']':
squareBracketLevel++;
break;
case '}':
curlyBraceLevel++;
break;
}
}
return true;
}
string ReadIdentifier(char ch)
{
string identifier = ch.ToString();
while (IsIdentifierPart(Peek())) {
identifier = GetNext() + identifier;
}
return identifier;
}
void ReadDigit(char ch)
{
//string digit = ch.ToString();
while (Char.IsDigit(Peek()) || Peek() == '.') {
GetNext();
//digit = GetNext() + digit;
}
//return digit;
}
bool IsIdentifierPart(char ch)
{
return Char.IsLetterOrDigit(ch) || ch == '_' || ch == '@';
}
#endregion
#region finite state machine
readonly static int ERROR = 0;
readonly static int START = 1;
readonly static int DOT = 2;
readonly static int MORE = 3;
readonly static int CURLY = 4;
readonly static int CURLY2 = 5;
readonly static int CURLY3 = 6;
readonly static int ACCEPT = 7;
readonly static int ACCEPTNOMORE = 8;
readonly static int ACCEPT2 = 9;
readonly static string[] stateName = new string[] {
"ERROR",
"START",
"DOT",
"MORE",
"CURLY",
"CURLY2",
"CURLY3",
"ACCEPT",
"ACCEPTNOMORE",
"ACCEPT2"
};
string GetStateName(int state)
{
return stateName[state];
}
int state = 0;
int lastAccept = 0;
static int[,] stateTable = new int[,] {
// Err, Dot, Str, ID, New, Brk, Par, Cur, Using, digit
/*ERROR*/ { ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR},
/*START*/ { ERROR, DOT, ACCEPT, ACCEPT, ERROR, MORE, ACCEPT2, CURLY, ACCEPTNOMORE, ERROR},
/*DOT*/ { ERROR, ERROR, ACCEPT, ACCEPT, ERROR, MORE, ACCEPT, CURLY, ERROR, ACCEPT},
/*MORE*/ { ERROR, ERROR, ACCEPT, ACCEPT, ERROR, MORE, ACCEPT2, CURLY, ERROR, ACCEPT},
/*CURLY*/ { ERROR, ERROR, ERROR, ERROR, ERROR, CURLY2, ERROR, ERROR, ERROR, ERROR},
/*CURLY2*/ { ERROR, ERROR, ERROR, CURLY3, ERROR, ERROR, ERROR, ERROR, ERROR, CURLY3},
/*CURLY3*/ { ERROR, ERROR, ERROR, ERROR, ACCEPTNOMORE, ERROR, ERROR, ERROR, ERROR, ERROR},
/*ACCEPT*/ { ERROR, MORE, ERROR, ERROR, ACCEPT, ERROR, ERROR, ERROR, ACCEPTNOMORE, ERROR},
/*ACCEPTNOMORE*/ { ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR},
/*ACCEPT2*/ { ERROR, MORE, ERROR, ACCEPT, ACCEPT, ERROR, ERROR, ERROR, ERROR, ACCEPT},
};
#endregion
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -