miduo_client/Assets/Scripts/LuaProfiler/Common/Parse/LLex.cs

950 lines
27 KiB
C#

#if UNITY_EDITOR
using System;
using System.Collections.Generic;
using System.Text;
using NumberStyles = System.Globalization.NumberStyles;
namespace UniLua
{
public class LLexException : Exception
{
public LLexException(string info) : base(info) { }
}
public enum TK
{
// reserved words
AND = 257,
BREAK,
CONTINUE,
DO,
ELSE,
ELSEIF,
END,
FALSE,
FOR,
FUNCTION,
GOTO,
IF,
IN,
LOCAL,
NIL,
NOT,
OR,
REPEAT,
RETURN,
THEN,
TRUE,
UNTIL,
WHILE,
// other terminal symbols
CONCAT,
DOTS,
EQ,
GE,
LE,
NE,
DBCOLON,
NUMBER,
STRING,
NAME,
EOS,
}
public class StringLoadInfo
{
public StringLoadInfo(string s)
{
Str = new StringBuilder(s);
Pos = 0;
}
public int ReadByte()
{
if (Pos >= Str.Length)
return -1;
else
return Str[Pos++];
}
public int PosChar
{
get
{
if (Pos >= Str.Length)
return (int)TK.EOS;
else
return Str[Pos];
}
}
public int PeekByte()
{
if (Pos >= Str.Length)
return -1;
else
return Str[Pos];
}
public void Replace(int start, int len, string value)
{
Str = Str.Remove(start, len);
Str = Str.Insert(start, value);
if ((start + len) <= Pos)
{
Pos = Pos - (len - value.Length);
}
}
public string ReadString(int startPos, int len)
{
char[] chars = new char[len];
for (int i = 0, imax = len; i < imax; i++)
{
chars[i] = Str[i + startPos];
}
return new string(chars);
}
public void InsertString(int startPos, string value)
{
Str = Str.Insert(startPos, value);
Pos += value.Length;
}
public string code
{
get
{
return Str.ToString();
}
}
private StringBuilder Str;
public int Pos;
}
public class BytesLoadInfo
{
public BytesLoadInfo(byte[] bytes)
{
Bytes = bytes;
Pos = 0;
}
public int ReadByte()
{
if (Pos >= Bytes.Length)
return -1;
else
return Bytes[Pos++];
}
public int PeekByte()
{
if (Pos >= Bytes.Length)
return -1;
else
return Bytes[Pos];
}
private byte[] Bytes;
private int Pos;
}
public abstract class Token
{
public abstract int TokenType { get; }
public bool EqualsToToken(Token other)
{
return TokenType == other.TokenType;
}
public bool EqualsToToken(int other)
{
return TokenType == other;
}
public bool EqualsToToken(TK other)
{
return TokenType == (int)other;
}
}
public class JumpToken : Token
{
public JumpToken(int pos)
{
Pos = pos;
}
public int Pos;
public override int TokenType
{
get { return -1; }
}
}
public class LiteralToken : Token
{
private int _Literal;
public LiteralToken(int literal)
{
_Literal = literal;
}
public override int TokenType
{
get { return _Literal; }
}
public override string ToString()
{
return string.Format("LiteralToken: {0}", (char)_Literal);
}
}
public class TypedToken : Token
{
private TK _Type;
public TypedToken(TK type)
{
_Type = type;
}
public override int TokenType
{
get { return (int)_Type; }
}
public override string ToString()
{
return string.Format("TypedToken: {0}", _Type);
}
}
public class StringToken : TypedToken
{
public string SemInfo;
public StringToken(string seminfo) : base(TK.STRING)
{
SemInfo = seminfo;
}
public override string ToString()
{
return string.Format("StringToken: {0}", SemInfo);
}
}
public class NameToken : TypedToken
{
public string SemInfo;
public NameToken(string seminfo) : base(TK.NAME)
{
SemInfo = seminfo;
}
public override string ToString()
{
return string.Format("NameToken: {0}", SemInfo);
}
}
public class NumberToken : TypedToken
{
public double SemInfo;
public NumberToken(double seminfo) : base(TK.NUMBER)
{
SemInfo = seminfo;
}
public override string ToString()
{
return string.Format("NumberToken: {0}", SemInfo);
}
}
public class LLex
{
public const char EOZ = Char.MaxValue;
public int pos
{
get
{
return LoadInfo.Pos;
}
}
private int Current;
public int LineNumber;
public int LastLine;
private StringLoadInfo LoadInfo;
public string Source;
public Token Token;
private Token LookAhead;
private StringBuilder _Saved;
private StringBuilder Saved
{
get
{
if (_Saved == null) { _Saved = new StringBuilder(); }
return _Saved;
}
}
private static Dictionary<string, TK> ReservedWordDict;
static LLex()
{
ReservedWordDict = new Dictionary<string, TK>();
ReservedWordDict.Add("and", TK.AND);
ReservedWordDict.Add("break", TK.BREAK);
ReservedWordDict.Add("continue", TK.CONTINUE);
ReservedWordDict.Add("do", TK.DO);
ReservedWordDict.Add("else", TK.ELSE);
ReservedWordDict.Add("elseif", TK.ELSEIF);
ReservedWordDict.Add("end", TK.END);
ReservedWordDict.Add("false", TK.FALSE);
ReservedWordDict.Add("for", TK.FOR);
ReservedWordDict.Add("function", TK.FUNCTION);
ReservedWordDict.Add("goto", TK.GOTO);
ReservedWordDict.Add("if", TK.IF);
ReservedWordDict.Add("in", TK.IN);
ReservedWordDict.Add("local", TK.LOCAL);
ReservedWordDict.Add("nil", TK.NIL);
ReservedWordDict.Add("not", TK.NOT);
ReservedWordDict.Add("or", TK.OR);
ReservedWordDict.Add("repeat", TK.REPEAT);
ReservedWordDict.Add("return", TK.RETURN);
ReservedWordDict.Add("then", TK.THEN);
ReservedWordDict.Add("true", TK.TRUE);
ReservedWordDict.Add("until", TK.UNTIL);
ReservedWordDict.Add("while", TK.WHILE);
}
public LLex(StringLoadInfo loadinfo, string name)
{
LoadInfo = loadinfo;
LineNumber = 1;
LastLine = 1;
Token = null;
LookAhead = null;
_Saved = null;
Source = name;
_Next();
}
public string code
{
get
{
return LoadInfo.code;
}
}
public void InsertString(int startPos, string value)
{
LoadInfo.InsertString(startPos, value);
}
public void Next()
{
LastLine = LineNumber;
if (LookAhead != null)
{
Token = LookAhead;
LookAhead = null;
}
else
{
Token = _Lex();
}
}
public Token GetLookAhead()
{
Utl.Assert(LookAhead == null);
LookAhead = _Lex();
return LookAhead;
}
public void Replace(int start, int end, string value)
{
LoadInfo.Replace(start, end + 1 - start, value);
}
public string ReadString(int start, int end)
{
int len = end - start + 1;
return LoadInfo.ReadString(start, len);
}
private void _Next()
{
var c = LoadInfo.ReadByte();
Current = (c == -1) ? EOZ : c;
}
private void _SaveAndNext()
{
Saved.Append((char)Current);
_Next();
}
private void _Save(char c)
{
Saved.Append(c);
}
private string _GetSavedString()
{
return Saved.ToString();
}
private void _ClearSaved()
{
_Saved = null;
}
private bool _CurrentIsNewLine()
{
return Current == '\n' || Current == '\r';
}
private bool _CurrentIsDigit()
{
return Char.IsDigit((char)Current);
}
private bool _CurrentIsXDigit()
{
return _CurrentIsDigit() ||
('A' <= Current && Current <= 'F') ||
('a' <= Current && Current <= 'f');
}
private bool _CurrentIsSpace()
{
return Char.IsWhiteSpace((char)Current);
}
private bool _CurrentIsAlpha()
{
return Char.IsLetter((char)Current);
}
private bool _IsReserved(string identifier, out TK type)
{
return ReservedWordDict.TryGetValue(identifier, out type);
}
public bool IsReservedWord(string name)
{
return ReservedWordDict.ContainsKey(name);
}
private void _IncLineNumber()
{
var old = Current;
_Next();
if (_CurrentIsNewLine() && Current != old)
_Next();
if (++LineNumber >= Int32.MaxValue)
_Error("chunk has too many lines");
}
private string _ReadLongString(int sep)
{
_SaveAndNext();
if (_CurrentIsNewLine())
_IncLineNumber();
while (true)
{
switch (Current)
{
case EOZ:
_LexError(_GetSavedString(),
"unfinished long string/comment",
(int)TK.EOS);
break;
case '[':
{
if (_SkipSep() == sep)
{
_SaveAndNext();
if (sep == 0)
{
_LexError(_GetSavedString(),
"nesting of [[...]] is deprecated",
(int)TK.EOS);
}
}
break;
}
case ']':
{
if (_SkipSep() == sep)
{
_SaveAndNext();
goto endloop;
}
break;
}
case '\n':
case '\r':
{
_Save('\n');
_IncLineNumber();
break;
}
default:
{
_SaveAndNext();
break;
}
}
}
endloop:
var r = _GetSavedString();
int len = r.Length - 2 * (2 + sep);
if (len <= 0)
{
return string.Empty;
}
else
{
return r.Substring(2 + sep, len);
}
}
private void _EscapeError(string info, string msg)
{
_LexError("\\" + info, msg, (int)TK.STRING);
}
private byte _ReadHexEscape()
{
int r = 0;
var c = new char[3] { 'x', (char)0, (char)0 };
// read two hex digits
for (int i = 1; i < 3; ++i)
{
_Next();
c[i] = (char)Current;
if (!_CurrentIsXDigit())
{
_EscapeError(new String(c, 0, i + 1),
"hexadecimal digit expected");
// error
}
r = (r << 4) + Int32.Parse(Current.ToString(),
NumberStyles.HexNumber);
}
return (byte)r;
}
private byte _ReadDecEscape()
{
int r = 0;
var c = new char[3];
// read up to 3 digits
int i = 0;
for (i = 0; i < 3 && _CurrentIsDigit(); ++i)
{
c[i] = (char)Current;
r = r * 10 + Current - '0';
_Next();
}
if (r > Byte.MaxValue)
_EscapeError(new String(c, 0, i),
"decimal escape too large");
return (byte)r;
}
private string _ReadString()
{
var del = Current;
_Next();
while (Current != del)
{
switch (Current)
{
case EOZ:
_Error("unfinished string");
continue;
case '\n':
case '\r':
_Error("unfinished string");
continue;
case '\\':
{
byte c;
_Next();
switch (Current)
{
case 'a': c = (byte)'\a'; break;
case 'b': c = (byte)'\b'; break;
case 'f': c = (byte)'\f'; break;
case 'n': c = (byte)'\n'; break;
case 'r': c = (byte)'\r'; break;
case 't': c = (byte)'\t'; break;
case 'v': c = (byte)'\v'; break;
case 'x': c = _ReadHexEscape(); break;
case '\n':
case '\r': _Save('\n'); _IncLineNumber(); continue;
case '\\':
case '\"':
case '\'': c = (byte)Current; break;
case EOZ: continue;
// zap following span of spaces
case 'z':
{
_Next(); // skip `z'
while (_CurrentIsSpace())
{
if (_CurrentIsNewLine())
_IncLineNumber();
else
_Next();
}
continue;
}
default:
{
if (!_CurrentIsDigit())
_EscapeError(Current.ToString(),
"invalid escape sequence");
// digital escape \ddd
c = _ReadDecEscape();
_Save((char)c);
continue;
// {
// c = (char)0;
// for(int i=0; i<3 && _CurrentIsDigit(); ++i)
// {
// c = (char)(c*10 + Current - '0');
// _Next();
// }
// _Save( c );
// }
// continue;
}
}
_Save((char)c);
_Next();
continue;
}
default:
_SaveAndNext();
continue;
}
}
_Next();
return _GetSavedString();
}
private double _ReadNumber()
{
var expo = new char[] { 'E', 'e' };
Utl.Assert(_CurrentIsDigit());
var first = Current;
_SaveAndNext();
if (first == '0' && (Current == 'X' || Current == 'x'))
{
expo = new char[] { 'P', 'p' };
_SaveAndNext();
}
for (; ; )
{
if (Current == expo[0] || Current == expo[1])
{
_SaveAndNext();
if (Current == '+' || Current == '-')
_SaveAndNext();
}
if (_CurrentIsXDigit() || Current == '.')
_SaveAndNext();
else
break;
}
double ret;
var str = _GetSavedString();
if (O_Str2Decimal(str, out ret))
{
return ret;
}
else
{
_Error("malformed number: " + str);
return 0.0;
}
}
public static bool O_Str2Decimal(string s, out double result)
{
result = 0.0;
if (s.Contains("n") || s.Contains("N")) // reject `inf' and `nan'
return false;
int pos = 0;
if (s.Contains("x") || s.Contains("X"))
result = Utl.StrX2Number(s, ref pos);
else
result = Utl.Str2Number(s, ref pos);
if (pos == 0)
return false; // nothing recognized
while (pos < s.Length && Char.IsWhiteSpace(s[pos])) ++pos;
return pos == s.Length; // OK if no trailing characters
}
// private float _ReadNumber()
// {
// do
// {
// _SaveAndNext();
// } while( _CurrentIsDigit() || Current == '.' );
// if( Current == 'E' || Current == 'e' )
// {
// _SaveAndNext();
// if( Current == '+' || Current == '-' )
// _SaveAndNext();
// }
// while( _CurrentIsAlpha() || _CurrentIsDigit() || Current == '_' )
// _SaveAndNext();
// float ret;
// if( !Single.TryParse( _GetSavedString(), out ret ) )
// _Error( "malformed number" );
// return ret;
// }
private void _Error(string error)
{
throw new Exception(string.Format("{0}:{1}: {2}", Source, LineNumber, error));
}
private void _LexError(string info, string msg, int tokenType)
{
// TODO
_Error(msg + ":" + info);
}
public void SyntaxError(string msg)
{
// TODO
_Error(msg);
}
private int _SkipSep()
{
int count = 0;
var boundary = Current;
_SaveAndNext();
while (Current == '=')
{
_SaveAndNext();
count++;
}
return (Current == boundary ? count : (-count) - 1);
}
private Token _Lex()
{
_ClearSaved();
while (true)
{
switch (Current)
{
case '\n':
case '\r':
{
var token = new JumpToken(pos);
_IncLineNumber();
return token;
}
case '-':
{
_Next();
if (Current != '-') return new LiteralToken('-');
// else is a long comment
_Next();
if (Current == '[')
{
int sep = _SkipSep();
_ClearSaved();
if (sep >= 0)
{
_ReadLongString(sep);
_ClearSaved();
return new JumpToken(pos);
}
}
// else is a short comment
while (!_CurrentIsNewLine() && Current != EOZ)
_Next();
return new JumpToken(pos);
}
case '[':
{
int sep = _SkipSep();
if (sep >= 0)
{
string seminfo = _ReadLongString(sep);
return new StringToken(seminfo);
}
else if (sep == -1) return new LiteralToken('[');
else _Error("invalid long string delimiter");
continue;
}
case '=':
{
_Next();
if (Current != '=') return new LiteralToken('=');
_Next();
return new TypedToken(TK.EQ);
}
case '<':
{
_Next();
if (Current != '=') return new LiteralToken('<');
_Next();
return new TypedToken(TK.LE);
}
case '>':
{
_Next();
if (Current != '=') return new LiteralToken('>');
_Next();
return new TypedToken(TK.GE);
}
case '~':
{
_Next();
if (Current != '=') return new LiteralToken('~');
_Next();
return new TypedToken(TK.NE);
}
case ':':
{
_Next();
if (Current != ':') return new LiteralToken(':');
_Next();
return new TypedToken(TK.DBCOLON); // new in 5.2 ?
}
case '"':
case '\'':
{
return new StringToken(_ReadString());
}
case '.':
{
_SaveAndNext();
if (Current == '.')
{
_SaveAndNext();
if (Current == '.')
{
_SaveAndNext();
return new TypedToken(TK.DOTS);
}
else
{
return new TypedToken(TK.CONCAT);
}
}
else if (!_CurrentIsDigit())
return new LiteralToken('.');
else
return new NumberToken(_ReadNumber());
}
case EOZ:
{
return new TypedToken(TK.EOS);
}
default:
{
if (_CurrentIsSpace())
{
var token = new JumpToken(pos);
_Next();
return token;
//continue;
}
else if (Current == ';')
{
var token = new JumpToken(pos);
_Next();
return token;
}
else if (_CurrentIsDigit())
{
return new NumberToken(_ReadNumber());
}
else if (_CurrentIsAlpha() || Current == '_')
{
do
{
_SaveAndNext();
} while (_CurrentIsAlpha() ||
_CurrentIsDigit() ||
Current == '_');
string identifier = _GetSavedString();
TK type;
if (_IsReserved(identifier, out type))
{
return new TypedToken(type);
}
else
{
return new NameToken(identifier);
}
}
else
{
var c = Current;
_Next();
return new LiteralToken(c);
}
}
}
}
}
}
}
#endif