UltimateZoneBuilder/Source/Core/GZBuilder/GZDoom/AcsParserSE.cs
MaxED c07df8f596 Changed, Thing and Linedef Edit Forms, script selector drop-downs: scripts from include files are now shown using different color and after the map scripts.
Fixed, Visual mode, UDMF: sector geometry cache was not updated after using "Match Brightness" and "Change Brightness" actions on ceilings, so the changes made by them were not visible when using Classic modes in "View Ceiling Textures" mode.
Fixed, Visual mode, UDMF: "Match Brightness" and "Change Brightness" actions set brightness incorrectly in some cases.
Fixed: ACS script names gathering logic was unable to process relative #include and #import paths (like '#import "..\acs\qtilt.acs"').
Updated ZDoom_DECORATE.cfg.
2015-02-24 13:38:35 +00:00

183 lines
No EOL
5.5 KiB
C#

using System.IO;
using System.Collections.Generic;
using System.Globalization;
using CodeImp.DoomBuilder.ZDoom;
using CodeImp.DoomBuilder.GZBuilder.Data;
//mxd. ACS parser used to create ScriptItems for use in script editor's navigator
namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
{
internal sealed class AcsParserSE : ZDTextParser
{
internal delegate void IncludeDelegate(AcsParserSE parser, string includefile);
internal IncludeDelegate OnInclude;
private readonly List<string> parsedLumps;
private readonly List<string> includes;
private readonly List<ScriptItem> namedScripts;
private readonly List<ScriptItem> numberedScripts;
private readonly List<ScriptItem> functions;
internal List<ScriptItem> NamedScripts { get { return namedScripts; } }
internal List<ScriptItem> NumberedScripts { get { return numberedScripts; } }
internal List<ScriptItem> Functions { get { return functions; } }
internal AcsParserSE()
{
namedScripts = new List<ScriptItem>();
numberedScripts = new List<ScriptItem>();
functions = new List<ScriptItem>();
parsedLumps = new List<string>();
includes = new List<string>();
}
internal List<string> Includes
{
get { return includes; }
}
public override bool Parse(Stream stream, string sourcefilename)
{
return Parse(stream, sourcefilename, false, false);
}
public bool Parse(Stream stream, string sourcefilename, bool processIncludes, bool isinclude)
{
base.Parse(stream, sourcefilename);
//already parsed this?
if (parsedLumps.Contains(sourcefilename)) return false;
parsedLumps.Add(sourcefilename);
if (isinclude) includes.Add(sourcefilename);
// Keep local data
Stream localstream = datastream;
string localsourcename = sourcename;
BinaryReader localreader = datareader;
// Continue until at the end of the stream
while (SkipWhitespace(true))
{
string token = ReadToken();
if (!string.IsNullOrEmpty(token))
{
token = token.ToLowerInvariant();
if (token == "script")
{
SkipWhitespace(true);
int startPos = (int)stream.Position;
token = ReadToken();
//is it named script?
if (token.IndexOf('"') != -1)
{
startPos += 1;
//check if we have something like '"mycoolscript"(void)' as a token
if(token.LastIndexOf('"') != token.Length - 1)
token = token.Substring(0, token.LastIndexOf('"'));
token = StripTokenQuotes(token);
ScriptItem i = new ScriptItem(0, token, startPos, isinclude);
namedScripts.Add(i);
}
else //should be numbered script
{
//check if we have something like "999(void)" as a token
if (token.Contains("(")) token = token.Substring(0, token.IndexOf("("));
int n;
if (int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out n))
{
//now find opening brace
do
{
SkipWhitespace(true);
token = ReadToken();
} while (token != "{");
token = ReadLine();
string name = "";
if (token.Length > 0)
{
int commentStart = token.IndexOf("//");
if (commentStart != -1) //found comment
{
commentStart += 2;
name = token.Substring(commentStart, token.Length - commentStart).Trim();
}
}
name = (name.Length > 0 ? name + " [" + n + "]" : "Script " + n);
ScriptItem i = new ScriptItem(n, name, startPos, isinclude);
numberedScripts.Add(i);
}
}
}
else if(token == "function")
{
SkipWhitespace(true);
int startPos = (int) stream.Position;
string funcname = ReadToken(); //read return type
SkipWhitespace(true);
funcname += " " + ReadToken(); //read function name
//look for opening brace
if (!funcname.Contains("("))
{
SkipWhitespace(true);
funcname += " " + ReadToken();
}
else
{
funcname = funcname.Replace("(", " (");
}
//look for closing brace
if(!funcname.Contains(")"))
{
do
{
SkipWhitespace(true);
token = ReadToken();
funcname += " " + token;
} while(!token.Contains(")"));
}
ScriptItem i = new ScriptItem(0, funcname, startPos, isinclude);
functions.Add(i);
}
else if (processIncludes && (token == "#include" || token == "#import"))
{
SkipWhitespace(true);
string includeLump = StripTokenQuotes(ReadToken()).ToLowerInvariant();
if (!string.IsNullOrEmpty(includeLump))
{
string includeName = Path.GetFileName(includeLump);
if (includeName == "zcommon.acs" || includeName == "common.acs" || includes.Contains(includeName))
continue;
// Callback to parse this file
if (OnInclude != null) OnInclude(this, includeLump.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar));
// Set our buffers back to continue parsing
datastream = localstream;
datareader = localreader;
sourcename = localsourcename;
}
else
{
General.ErrorLogger.Add(ErrorType.Error, "Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": got #include directive without include path!");
}
}
}
}
return true;
}
}
}