2013-04-11 11:04:16 +00:00
using System.IO ;
2012-07-10 10:20:45 +00:00
using System.Collections.Generic ;
using System.Globalization ;
using CodeImp.DoomBuilder.ZDoom ;
using CodeImp.DoomBuilder.GZBuilder.Data ;
2012-07-12 22:34:12 +00:00
//mxd. ACS parser used to create ScriptItems for use in script editor's navigator
namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
2012-07-10 10:20:45 +00:00
{
2013-09-11 09:47:53 +00:00
internal sealed class AcsParserSE : ZDTextParser
{
internal delegate void IncludeDelegate ( AcsParserSE parser , string includefile ) ;
internal IncludeDelegate OnInclude ;
2015-04-28 08:31:06 +00:00
private readonly List < string > parsedlumps ;
2014-07-16 09:47:23 +00:00
private readonly List < string > includes ;
2015-04-28 08:31:06 +00:00
private readonly List < ScriptItem > namedscripts ;
private readonly List < ScriptItem > numberedscripts ;
2014-07-16 09:47:23 +00:00
private readonly List < ScriptItem > functions ;
2013-09-11 09:47:53 +00:00
2015-04-28 08:31:06 +00:00
internal List < ScriptItem > NamedScripts { get { return namedscripts ; } }
internal List < ScriptItem > NumberedScripts { get { return numberedscripts ; } }
2014-07-16 09:47:23 +00:00
internal List < ScriptItem > Functions { get { return functions ; } }
2015-04-28 08:31:06 +00:00
internal IEnumerable < string > Includes { get { return includes ; } }
2013-09-11 09:47:53 +00:00
2014-12-03 23:15:26 +00:00
internal AcsParserSE ( )
{
2015-04-28 08:31:06 +00:00
namedscripts = new List < ScriptItem > ( ) ;
numberedscripts = new List < ScriptItem > ( ) ;
2014-07-16 09:47:23 +00:00
functions = new List < ScriptItem > ( ) ;
2015-04-28 08:31:06 +00:00
parsedlumps = new List < string > ( ) ;
2013-09-11 09:47:53 +00:00
includes = new List < string > ( ) ;
}
2014-12-03 23:15:26 +00:00
public override bool Parse ( Stream stream , string sourcefilename )
{
2013-09-11 09:47:53 +00:00
return Parse ( stream , sourcefilename , false , false ) ;
}
2015-04-28 08:31:06 +00:00
public bool Parse ( Stream stream , string sourcefilename , bool processincludes , bool isinclude )
2014-12-03 23:15:26 +00:00
{
2013-09-11 09:47:53 +00:00
base . Parse ( stream , sourcefilename ) ;
//already parsed this?
2015-04-28 08:31:06 +00:00
if ( parsedlumps . Contains ( sourcefilename ) ) return false ;
parsedlumps . Add ( sourcefilename ) ;
2013-08-05 13:03:08 +00:00
if ( isinclude ) includes . Add ( sourcefilename ) ;
2015-04-28 08:31:06 +00:00
int bracelevel = 0 ;
2012-07-23 21:28:23 +00:00
2013-09-11 09:47:53 +00:00
// Keep local data
Stream localstream = datastream ;
string localsourcename = sourcename ;
BinaryReader localreader = datareader ;
2012-07-23 21:28:23 +00:00
2013-09-11 09:47:53 +00:00
// Continue until at the end of the stream
2014-12-03 23:15:26 +00:00
while ( SkipWhitespace ( true ) )
{
2013-09-11 09:47:53 +00:00
string token = ReadToken ( ) ;
2015-04-28 08:31:06 +00:00
if ( string . IsNullOrEmpty ( token ) ) continue ;
2012-07-10 10:20:45 +00:00
2015-04-28 08:31:06 +00:00
// Ignore inner scope stuff
if ( token = = "{" ) { bracelevel + + ; continue ; }
if ( token = = "}" ) { bracelevel - - ; continue ; }
if ( bracelevel > 0 ) continue ;
2012-07-10 10:20:45 +00:00
2015-04-28 08:31:06 +00:00
switch ( token . ToLowerInvariant ( ) )
{
case "script" :
2014-12-03 23:15:26 +00:00
{
2013-09-11 09:47:53 +00:00
SkipWhitespace ( true ) ;
2015-04-28 08:31:06 +00:00
int startpos = ( int ) stream . Position ;
2013-09-11 09:47:53 +00:00
token = ReadToken ( ) ;
2012-07-10 10:20:45 +00:00
2013-09-11 09:47:53 +00:00
//is it named script?
2014-12-03 23:15:26 +00:00
if ( token . IndexOf ( '"' ) ! = - 1 )
{
2015-04-28 08:31:06 +00:00
startpos + = 1 ;
2013-08-07 09:25:37 +00:00
//check if we have something like '"mycoolscript"(void)' as a token
if ( token . LastIndexOf ( '"' ) ! = token . Length - 1 )
token = token . Substring ( 0 , token . LastIndexOf ( '"' ) ) ;
2013-09-11 09:47:53 +00:00
token = StripTokenQuotes ( token ) ;
2015-04-28 08:31:06 +00:00
ScriptItem i = new ScriptItem ( 0 , token , startpos , isinclude ) ;
namedscripts . Add ( i ) ;
2014-12-03 23:15:26 +00:00
}
else //should be numbered script
{
2013-08-07 09:25:37 +00:00
//check if we have something like "999(void)" as a token
if ( token . Contains ( "(" ) ) token = token . Substring ( 0 , token . IndexOf ( "(" ) ) ;
2014-02-21 14:42:12 +00:00
int n ;
2014-12-03 23:15:26 +00:00
if ( int . TryParse ( token , NumberStyles . Integer , CultureInfo . InvariantCulture , out n ) )
{
2013-09-11 09:47:53 +00:00
//now find opening brace
2014-12-03 23:15:26 +00:00
do
{
2015-03-21 19:41:54 +00:00
if ( ! SkipWhitespace ( true ) ) break ;
2013-09-11 09:47:53 +00:00
token = ReadToken ( ) ;
2015-03-21 19:41:54 +00:00
} while ( ! string . IsNullOrEmpty ( token ) & & token ! = "{" ) ;
2013-09-11 09:47:53 +00:00
token = ReadLine ( ) ;
string name = "" ;
2015-04-28 08:31:06 +00:00
bracelevel = 1 ;
2013-09-11 09:47:53 +00:00
2015-03-21 19:41:54 +00:00
if ( ! string . IsNullOrEmpty ( token ) )
2014-12-03 23:15:26 +00:00
{
2015-04-28 08:31:06 +00:00
int commentstart = token . IndexOf ( "//" ) ;
if ( commentstart ! = - 1 ) //found comment
2014-12-03 23:15:26 +00:00
{
2015-04-28 08:31:06 +00:00
commentstart + = 2 ;
name = token . Substring ( commentstart , token . Length - commentstart ) . Trim ( ) ;
2013-09-11 09:47:53 +00:00
}
}
name = ( name . Length > 0 ? name + " [" + n + "]" : "Script " + n ) ;
2015-04-28 08:31:06 +00:00
ScriptItem i = new ScriptItem ( n , name , startpos , isinclude ) ;
numberedscripts . Add ( i ) ;
2013-09-11 09:47:53 +00:00
}
}
2015-04-28 08:31:06 +00:00
}
break ;
case "function" :
2014-12-03 23:15:26 +00:00
{
2014-07-16 09:47:23 +00:00
SkipWhitespace ( true ) ;
2015-04-28 08:31:06 +00:00
int startpos = ( int ) stream . Position ;
2014-07-16 09:47:23 +00:00
string funcname = ReadToken ( ) ; //read return type
SkipWhitespace ( true ) ;
funcname + = " " + ReadToken ( ) ; //read function name
//look for opening brace
2014-12-03 23:15:26 +00:00
if ( ! funcname . Contains ( "(" ) )
{
2014-07-16 09:47:23 +00:00
SkipWhitespace ( true ) ;
funcname + = " " + ReadToken ( ) ;
2014-12-03 23:15:26 +00:00
}
else
{
2014-07-16 09:47:23 +00:00
funcname = funcname . Replace ( "(" , " (" ) ;
}
//look for closing brace
2014-12-03 23:15:26 +00:00
if ( ! funcname . Contains ( ")" ) )
{
do
{
2015-03-21 19:41:54 +00:00
if ( ! SkipWhitespace ( true ) ) break ;
2014-07-16 09:47:23 +00:00
token = ReadToken ( ) ;
funcname + = " " + token ;
2015-03-21 19:41:54 +00:00
} while ( ! string . IsNullOrEmpty ( token ) & & ! token . Contains ( ")" ) ) ;
2014-07-16 09:47:23 +00:00
}
2015-04-28 08:31:06 +00:00
ScriptItem i = new ScriptItem ( 0 , funcname , startpos , isinclude ) ;
2014-07-16 09:47:23 +00:00
functions . Add ( i ) ;
2015-04-28 08:31:06 +00:00
}
break ;
2013-09-11 09:47:53 +00:00
2015-04-28 08:31:06 +00:00
default :
if ( processincludes & & ( token = = "#include" | | token = = "#import" ) )
2014-12-03 23:15:26 +00:00
{
2015-04-28 08:31:06 +00:00
SkipWhitespace ( true ) ;
string includelump = StripTokenQuotes ( ReadToken ( ) ) . ToLowerInvariant ( ) ;
2013-09-11 09:47:53 +00:00
2015-04-28 08:31:06 +00:00
if ( ! string . IsNullOrEmpty ( includelump ) )
{
string includename = Path . GetFileName ( includelump ) ;
2013-09-11 09:47:53 +00:00
2015-04-28 08:31:06 +00:00
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!" ) ;
}
2013-09-11 09:47:53 +00:00
}
2015-04-28 08:31:06 +00:00
break ;
2013-09-11 09:47:53 +00:00
}
}
return true ;
}
}
2012-07-10 14:14:53 +00:00
}