Internal: refactored ZScriptTokenizer.ExpectToken for less redundancy

This commit is contained in:
ZZYZX 2017-01-17 10:19:48 +02:00
parent dc72c533ca
commit c1387a8e7e
4 changed files with 373 additions and 260 deletions

View file

@ -30,6 +30,6 @@ using CodeImp.DoomBuilder;
// Build Number
// Revision
//
[assembly: AssemblyVersion("2.3.0.2827")]
[assembly: AssemblyVersion("2.3.0.2828")]
[assembly: NeutralResourcesLanguageAttribute("en")]
[assembly: AssemblyHash("05a160b")]
[assembly: AssemblyHash("dc72c53")]

View file

@ -833,6 +833,7 @@ namespace CodeImp.DoomBuilder.ZDoom
}
// inject superclasses, since everything is parsed by now
Dictionary<int, ThingTypeInfo> things = General.Map.Config.GetThingTypes();
foreach (ZScriptClassStructure cls in allclasseslist)
{
ActorStructure actor = cls.Actor;
@ -843,7 +844,6 @@ namespace CodeImp.DoomBuilder.ZDoom
if (actor.baseclass == null)
{
//check if this class inherits from a class defined in game configuration
Dictionary<int, ThingTypeInfo> things = General.Map.Config.GetThingTypes();
string inheritclasscheck = inheritclass.ToLowerInvariant();
bool thingfound = false;

View file

@ -117,6 +117,7 @@ namespace CodeImp.DoomBuilder.ZDoom
{
private BinaryReader reader;
private Dictionary<string, ZScriptTokenType> namedtokentypes; // these are tokens that have precise equivalent in the enum (like operators)
private Dictionary<ZScriptTokenType, string> namedtokentypesreverse; // these are tokens that have precise equivalent in the enum (like operators)
private List<string> namedtokentypesorder; // this is the list of said tokens ordered by length.
public long LastPosition { get; private set; }
@ -125,6 +126,7 @@ namespace CodeImp.DoomBuilder.ZDoom
{
reader = br;
namedtokentypes = new Dictionary<string, ZScriptTokenType>();
namedtokentypesreverse = new Dictionary<ZScriptTokenType, string>();
namedtokentypesorder = new List<string>();
// initialize the token type list.
IEnumerable<ZScriptTokenType> tokentypes = Enum.GetValues(typeof(ZScriptTokenType)).Cast<ZScriptTokenType>();
@ -136,6 +138,7 @@ namespace CodeImp.DoomBuilder.ZDoom
if (attrs.Length == 0) continue;
//
namedtokentypes.Add(attrs[0].Value, tokentype);
namedtokentypesreverse.Add(tokentype, attrs[0].Value);
namedtokentypesorder.Add(attrs[0].Value);
}
@ -158,16 +161,366 @@ namespace CodeImp.DoomBuilder.ZDoom
}
}
private ZScriptToken TryReadWhitespace()
{
long cpos = LastPosition = reader.BaseStream.Position;
char c = reader.ReadChar();
//
string whitespace = " \r\t\u00A0";
// check whitespace
if (whitespace.Contains(c))
{
string ws_content = "";
ws_content += c;
while (true)
{
char cnext = reader.ReadChar();
if (whitespace.Contains(cnext))
{
ws_content += cnext;
continue;
}
reader.BaseStream.Position--;
break;
}
ZScriptToken tok = new ZScriptToken();
tok.Type = ZScriptTokenType.Whitespace;
tok.Value = ws_content;
return tok;
}
reader.BaseStream.Position = cpos;
return null;
}
private ZScriptToken TryReadIdentifier()
{
long cpos = LastPosition = reader.BaseStream.Position;
char c = reader.ReadChar();
// check identifier
if ((c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(c == '_'))
{
string id_content = "";
id_content += c;
while (true)
{
char cnext = reader.ReadChar();
if ((cnext >= 'a' && cnext <= 'z') ||
(cnext >= 'A' && cnext <= 'Z') ||
(cnext == '_') ||
(cnext >= '0' && cnext <= '9'))
{
id_content += cnext;
continue;
}
reader.BaseStream.Position--;
break;
}
ZScriptToken tok = new ZScriptToken();
tok.Type = ZScriptTokenType.Identifier;
tok.Value = id_content;
return tok;
}
reader.BaseStream.Position = cpos;
return null;
}
private ZScriptToken TryReadNumber()
{
long cpos = LastPosition = reader.BaseStream.Position;
char c = reader.ReadChar();
// check integer
if ((c >= '0' && c <= '9') || c == '.')
{
bool isint = true;
bool isdouble = (c == '.');
bool isexponent = false;
if (isdouble) // make sure next character is an integer, otherwise its probably a member access
{
char cnext = reader.ReadChar();
if (!(cnext >= '0' && cnext <= '9'))
{
isint = false;
reader.BaseStream.Position--;
}
}
if (isint)
{
bool isoctal = (c == '0');
bool ishex = false;
string i_content = "";
i_content += c;
while (true)
{
char cnext = reader.ReadChar();
if (!isdouble && (cnext == 'x') && i_content.Length == 1)
{
isoctal = false;
ishex = true;
}
else if ((cnext >= '0' && cnext <= '7') ||
(!isoctal && cnext >= '8' && cnext <= '9') ||
(ishex && ((cnext >= 'a' && cnext <= 'f') || (cnext >= 'A' && cnext <= 'F'))))
{
i_content += cnext;
}
else if (!ishex && !isdouble && !isexponent && cnext == '.')
{
isdouble = true;
isoctal = false;
i_content += '.';
}
else if (!isoctal && !ishex && !isexponent && (cnext == 'e' || cnext == 'E'))
{
isexponent = true;
isdouble = true;
i_content += 'e';
cnext = reader.ReadChar();
if (cnext == '-') i_content += '-';
else reader.BaseStream.Position--;
}
else
{
reader.BaseStream.Position--;
break;
}
}
ZScriptToken tok = new ZScriptToken();
tok.Type = (isdouble ? ZScriptTokenType.Double : ZScriptTokenType.Integer);
tok.Value = i_content;
try
{
if (ishex || isoctal || !isdouble)
{
int numbase = 10;
if (ishex) numbase = 16;
else if (isoctal) numbase = 8;
tok.ValueInt = Convert.ToInt32(tok.Value, numbase);
tok.ValueDouble = tok.ValueInt;
}
else if (isdouble)
{
string dval = (tok.Value[0] == '.') ? "0" + tok.Value : tok.Value;
tok.ValueDouble = Convert.ToDouble(dval);
tok.ValueInt = (int)tok.ValueDouble;
}
}
catch (Exception)
{
//throw new Exception(tok.ToString());
return null;
}
return tok;
}
}
reader.BaseStream.Position = cpos;
return null;
}
private ZScriptToken TryReadStringOrComment(bool allowstring, bool allowname, bool allowblock, bool allowline)
{
long cpos = LastPosition = reader.BaseStream.Position;
char c = reader.ReadChar();
switch (c)
{
case '/': // comment
{
if (!allowblock && !allowline) break;
char cnext = reader.ReadChar();
if (cnext == '/')
{
if (!allowline) break;
// line comment: read until newline but not including it
string cmt = "";
while (true)
{
cnext = reader.ReadChar();
if (cnext == '\n')
{
reader.BaseStream.Position--;
break;
}
cmt += cnext;
}
ZScriptToken tok = new ZScriptToken();
tok.Type = ZScriptTokenType.LineComment;
tok.Value = cmt;
return tok;
}
else if (cnext == '*')
{
if (!allowblock) break;
// block comment: read until closing sequence
string cmt = "";
while (true)
{
cnext = reader.ReadChar();
if (cnext == '*')
{
char cnext2 = reader.ReadChar();
if (cnext2 == '/')
break;
reader.BaseStream.Position--;
}
cmt += cnext;
}
ZScriptToken tok = new ZScriptToken();
tok.Type = ZScriptTokenType.BlockComment;
tok.Value = cmt;
return tok;
}
break;
}
case '"':
case '\'':
{
if ((c == '"' && !allowstring) || (c == '\'' && !allowname)) break;
ZScriptTokenType type = (c == '"' ? ZScriptTokenType.String : ZScriptTokenType.Name);
string s = "";
while (true)
{
// todo: parse escape sequences properly
char cnext = reader.ReadChar();
if (cnext == '\\') // escape sequence. right now, do nothing
{
cnext = reader.ReadChar();
s += cnext;
}
else if (cnext == c)
{
ZScriptToken tok = new ZScriptToken();
tok.Type = type;
tok.Value = s;
return tok;
}
else s += cnext;
}
}
}
reader.BaseStream.Position = cpos;
return null;
}
private ZScriptToken TryReadNamedToken()
{
long cpos = LastPosition = reader.BaseStream.Position;
// named tokens
char[] namedtoken_buf = reader.ReadChars(namedtokentypesorder[0].Length);
string namedtoken = new string(namedtoken_buf);
foreach (string namedtokentype in namedtokentypesorder)
{
if (namedtoken.StartsWith(namedtokentype))
{
// found the token.
reader.BaseStream.Position = cpos + namedtokentype.Length;
ZScriptToken tok = new ZScriptToken();
tok.Type = namedtokentypes[namedtokentype];
tok.Value = namedtokentype;
return tok;
}
}
reader.BaseStream.Position = cpos;
return null;
}
public ZScriptToken ExpectToken(params ZScriptTokenType[] oneof)
{
long cpos = reader.BaseStream.Position;
ZScriptToken tok = ReadToken();
if (tok == null) return null;
try
{
// try to expect whitespace
if (oneof.Contains(ZScriptTokenType.Whitespace))
{
ZScriptToken tok = TryReadWhitespace();
if (tok != null) return tok;
}
tok.IsValid = (oneof.Contains(tok.Type));
if (!tok.IsValid) reader.BaseStream.Position = cpos;
return tok;
// try to expect an identifier
if (oneof.Contains(ZScriptTokenType.Identifier))
{
ZScriptToken tok = TryReadIdentifier();
if (tok != null) return tok;
}
bool blinecomment = oneof.Contains(ZScriptTokenType.LineComment);
bool bblockcomment = oneof.Contains(ZScriptTokenType.BlockComment);
bool bstring = oneof.Contains(ZScriptTokenType.String);
bool bname = oneof.Contains(ZScriptTokenType.Name);
if (bstring || bname || bblockcomment || blinecomment)
{
// try to expect a string
ZScriptToken tok = TryReadStringOrComment(bstring, bname, bblockcomment, blinecomment);
if (tok != null) return tok;
}
// if we are expecting a number (double or int), try to read it
if (oneof.Contains(ZScriptTokenType.Integer) || oneof.Contains(ZScriptTokenType.Double))
{
ZScriptToken tok = TryReadNumber();
if (tok != null && oneof.Contains(tok.Type)) return tok;
}
// try to expect special tokens
// read max
char[] namedtoken_buf = reader.ReadChars(namedtokentypesorder[0].Length);
string namedtoken = new string(namedtoken_buf);
foreach (ZScriptTokenType expected in oneof)
{
// check if there is a value for this one
if (!namedtokentypesreverse.ContainsKey(expected))
continue;
string namedtokentype = namedtokentypesreverse[expected];
if (namedtoken.StartsWith(namedtokentype))
{
// found the token.
reader.BaseStream.Position = cpos + namedtokentype.Length;
ZScriptToken tok = new ZScriptToken();
tok.Type = namedtokentypes[namedtokentype];
tok.Value = namedtokentype;
return tok;
}
}
}
catch (IOException)
{
reader.BaseStream.Position = cpos;
return null;
}
// token was not found, try to read the token that was actually found and return that
reader.BaseStream.Position = cpos;
ZScriptToken invalid = ReadToken();
invalid.IsValid = false;
reader.BaseStream.Position = cpos;
return invalid;
}
// short_circuit only checks for string literals and "everything else", reporting "everything else" as invalid tokens
@ -177,273 +530,33 @@ namespace CodeImp.DoomBuilder.ZDoom
{
ZScriptToken tok;
long cpos = reader.BaseStream.Position; // I really hope we can rewind this <_<
char c = reader.ReadChar();
LastPosition = cpos;
//
string whitespace = " \r\t\u00A0";
// check whitespace
if (whitespace.Contains(c))
{
string ws_content = "";
ws_content += c;
while (true)
{
char cnext = reader.ReadChar();
if (whitespace.Contains(cnext))
{
ws_content += cnext;
continue;
}
reader.BaseStream.Position--;
break;
}
tok = new ZScriptToken();
tok.Type = ZScriptTokenType.Whitespace;
tok.Value = ws_content;
return tok;
}
tok = TryReadWhitespace();
if (tok != null) return tok;
if (!short_circuit)
{
// check identifier
if ((c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(c == '_'))
{
string id_content = "";
id_content += c;
while (true)
{
char cnext = reader.ReadChar();
if ((cnext >= 'a' && cnext <= 'z') ||
(cnext >= 'A' && cnext <= 'Z') ||
(cnext == '_') ||
(cnext >= '0' && cnext <= '9'))
{
id_content += cnext;
continue;
}
tok = TryReadIdentifier();
if (tok != null) return tok;
reader.BaseStream.Position--;
break;
}
tok = new ZScriptToken();
tok.Type = ZScriptTokenType.Identifier;
tok.Value = id_content;
return tok;
}
// check integer
if ((c >= '0' && c <= '9') || c == '.')
{
bool isint = true;
bool isdouble = (c == '.');
bool isexponent = false;
if (isdouble) // make sure next character is an integer, otherwise its probably a member access
{
char cnext = reader.ReadChar();
if (!(cnext >= '0' && cnext <= '9'))
{
isint = false;
reader.BaseStream.Position--;
}
}
if (isint)
{
bool isoctal = (c == '0');
bool ishex = false;
string i_content = "";
i_content += c;
while (true)
{
char cnext = reader.ReadChar();
if (!isdouble && (cnext == 'x') && i_content.Length == 1)
{
isoctal = false;
ishex = true;
}
else if ((cnext >= '0' && cnext <= '7') ||
(!isoctal && cnext >= '8' && cnext <= '9') ||
(ishex && ((cnext >= 'a' && cnext <= 'f') || (cnext >= 'A' && cnext <= 'F'))))
{
i_content += cnext;
}
else if (!ishex && !isdouble && !isexponent && cnext == '.')
{
isdouble = true;
isoctal = false;
i_content += '.';
}
else if (!isoctal && !ishex && !isexponent && (cnext == 'e' || cnext == 'E'))
{
isexponent = true;
isdouble = true;
i_content += 'e';
cnext = reader.ReadChar();
if (cnext == '-') i_content += '-';
else reader.BaseStream.Position--;
}
else
{
reader.BaseStream.Position--;
break;
}
}
tok = new ZScriptToken();
tok.Type = (isdouble ? ZScriptTokenType.Double : ZScriptTokenType.Integer);
tok.Value = i_content;
try
{
if (ishex || isoctal || !isdouble)
{
int numbase = 10;
if (ishex) numbase = 16;
else if (isoctal) numbase = 8;
tok.ValueInt = Convert.ToInt32(tok.Value, numbase);
tok.ValueDouble = tok.ValueInt;
}
else if (isdouble)
{
string dval = (tok.Value[0] == '.') ? "0" + tok.Value : tok.Value;
tok.ValueDouble = Convert.ToDouble(dval);
tok.ValueInt = (int)tok.ValueDouble;
}
}
catch (Exception)
{
//throw new Exception(tok.ToString());
return null;
}
return tok;
}
}
tok = TryReadNumber();
if (tok != null) return tok;
}
// check everything else
switch (c)
{
case '\n': // newline
{
ZScriptToken newline = new ZScriptToken();
newline.Type = ZScriptTokenType.Newline;
newline.Value += c;
return newline;
}
case '/': // comment
{
char cnext = reader.ReadChar();
if (cnext == '/')
{
// line comment: read until newline but not including it
string cmt = "";
while (true)
{
cnext = reader.ReadChar();
if (cnext == '\n')
{
reader.BaseStream.Position--;
break;
}
cmt += cnext;
}
tok = new ZScriptToken();
tok.Type = ZScriptTokenType.LineComment;
tok.Value = cmt;
return tok;
}
else if (cnext == '*')
{
// block comment: read until closing sequence
string cmt = "";
while (true)
{
cnext = reader.ReadChar();
if (cnext == '*')
{
char cnext2 = reader.ReadChar();
if (cnext2 == '/')
break;
reader.BaseStream.Position--;
}
cmt += cnext;
}
tok = new ZScriptToken();
tok.Type = ZScriptTokenType.BlockComment;
tok.Value = cmt;
return tok;
}
break;
}
case '"':
case '\'':
{
ZScriptTokenType type = (c == '"' ? ZScriptTokenType.String : ZScriptTokenType.Name);
string s = "";
while (true)
{
// todo: parse escape sequences properly
char cnext = reader.ReadChar();
if (cnext == '\\') // escape sequence. right now, do nothing
{
cnext = reader.ReadChar();
s += cnext;
}
else if (cnext == c)
{
tok = new ZScriptToken();
tok.Type = type;
tok.Value = s;
return tok;
}
else s += cnext;
}
}
}
reader.BaseStream.Position = cpos;
tok = TryReadStringOrComment(true, true, true, true);
if (tok != null) return tok;
if (!short_circuit)
{
// named tokens
char[] namedtoken_buf = reader.ReadChars(namedtokentypesorder[0].Length);
string namedtoken = new string(namedtoken_buf);
foreach (string namedtokentype in namedtokentypesorder)
{
if (namedtoken.StartsWith(namedtokentype))
{
// found the token.
reader.BaseStream.Position = cpos + namedtokentype.Length;
tok = new ZScriptToken();
tok.Type = namedtokentypes[namedtokentype];
tok.Value = namedtokentype;
return tok;
}
}
tok = TryReadNamedToken();
if (tok != null) return tok;
}
// token not found.
tok = new ZScriptToken();
tok.Type = ZScriptTokenType.Invalid;
tok.Value = "" + c;
tok.Value = "" + reader.ReadChar();
tok.IsValid = false;
reader.BaseStream.Position = cpos+1;
return tok;
}
catch (IOException)

View file

@ -29,5 +29,5 @@ using System.Resources;
// Build Number
// Revision
//
[assembly: AssemblyVersion("2.3.0.2827")]
[assembly: AssemblyVersion("2.3.0.2828")]
[assembly: NeutralResourcesLanguageAttribute("en")]