/*
	This file is part of Warzone 2100.
	Copyright (C) 1999-2004  Eidos Interactive
	Copyright (C) 2005-2019  Warzone 2100 Project

	Warzone 2100 is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	Warzone 2100 is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with Warzone 2100; if not, write to the Free Software
	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
%{
/*
 * script.l
 *
 * Script file lexer.
 */
#include <physfs.h>
#include "lib/framework/physfs_ext.h"
#include "lib/framework/frame.h"
#include "lib/framework/string_ext.h"
#include "lib/script/interpreter.h"
#include "lib/script/parse.h"
#include "lib/script/script.h"

/* Get the Yacc definitions */
#if defined (WZ_CC_MSVC)
#include "script_parser.hpp"
#else
#include "script_parser.h"
#endif
// fwrite declared with warn_unused_result, resulting in mysterious errors in "%%" on some distros.
static inline bool no_warn_unused_result(int ignore) { if (ignore) {} return true; }
#define fwrite(a, b, c, d) no_warn_unused_result(fwrite(a, b, c, d))

/* Maximum length for any TEXT value */
#ifndef YYLMAX
#define YYLMAX	255
#endif

#if defined(YY_FLEX_SUBMINOR_VERSION) && YY_FLEX_SUBMINOR_VERSION == 33
extern int scr_get_lineno(void);
extern FILE *scr_get_in(void);
extern FILE *scr_get_out(void);
extern int scr_get_leng(void);
extern char *scr_get_text(void);
extern void scr_set_lineno(int line_number);
extern void scr_set_in(FILE* in_str);
extern void scr_set_out(FILE* out_str);
extern int scr_get_debug(void);
extern void scr_set_debug(int bdebug);
extern int scr_lex_destroy(void);
#endif

/* Store for any string values */
static char aText[TEXT_BUFFERS][YYLMAX];
static UDWORD currText=0;

// Note if we are in a comment
static bool inComment = false;

/* FLEX include buffer stack */
static YY_BUFFER_STATE include_stack[MAX_SCR_INCLUDE_DEPTH];

/* FLEX define buffer stack */
static YY_BUFFER_STATE macro_stack[MAX_SCR_MACRO_DEPTH];
static SCR_MACRO scr_macro[MAX_SCR_MACROS];

/* Script include files stack */
static unsigned int scr_include_stack_ptr = 0;
static PHYSFS_file* pScrInputFiles[MAX_SCR_INCLUDE_DEPTH];

/* Line count stack used with script includes */
static unsigned int scrInclLine[MAX_SCR_INCLUDE_DEPTH];

/* Script defines stack */
static unsigned int scr_num_macros;       /* Number of macros defined so far */
static int scr_macro_stack_ptr;  /* Pointer to the current flex macro input buffer */
static char *pScrMacroBuffer[MAX_SCR_MACRO_DEPTH];

#undef YY_INPUT
#define YY_INPUT(buf,result,max_size) \
	{ \
		if (PHYSFS_eof(pScrInputFiles[scr_include_stack_ptr])) \
		{ \
			buf[0] = EOF; \
			result = YY_NULL; \
		} \
		else \
		{ \
			result = WZ_PHYSFS_readBytes(pScrInputFiles[scr_include_stack_ptr], buf, max_size); \
			if (result == -1) \
			{ \
				buf[0] = EOF; \
				result = YY_NULL; \
			} \
		} \
	}

static YYSTYPE dummy;

/* Get the token type for a variable symbol */
static SDWORD scriptGetVarToken(VAR_SYMBOL *psVar)
{
	bool	object;

	// See if this is an object pointer
	if (!asScrTypeTab || psVar->type < VAL_USERTYPESTART)
	{
		object = false;
	}
	else
	{
		object = asScrTypeTab[psVar->type - VAL_USERTYPESTART].accessType == AT_OBJECT;
	}

	if (psVar->storage == ST_OBJECT)
	{
		/* This is an object member variable */
		if (object)
		{

			RULE("current variable is OBJ_OBJVAR");

			return OBJ_OBJVAR;
		}
		else
		{
			switch (psVar->type)
			{
			case VAL_BOOL:
				return BOOL_OBJVAR;
				break;
			case VAL_INT:
//			case VAL_FLOAT:

				RULE( "current variable is NUM_OBJVAR");

				return NUM_OBJVAR;
				break;
			default:

				RULE( "current variable is USER_OBJVAR");

				return USER_OBJVAR;
				break;
			}
		}
	}
	else if (psVar->dimensions > 0)
	{
		/* This is an array variable */
		if (object)
		{
			return OBJ_ARRAY;
		}
		else
		{
			switch (psVar->type)
			{
			case VAL_BOOL:
				return BOOL_ARRAY;
				break;
			case VAL_FLOAT:
				return FLOAT_ARRAY;
				break;
			case VAL_INT:
				return NUM_ARRAY;
				break;
			default:
				return VAR_ARRAY;
				break;
			}
		}
	}
	else
	{
		/* This is a standard variable */
		if (object)
		{

			RULE( "current variable is OBJ_VAR");

			return OBJ_VAR;
		}
		else
		{

			RULE( "ordinary var");

			switch (psVar->type)
			{
			case VAL_BOOL:
				return BOOL_VAR;
				break;
			case VAL_FLOAT:

				RULE( "VAL_FLOAT");

				return FLOAT_VAR;
				break;
			case VAL_INT:
				return NUM_VAR;
				break;
			case VAL_STRING:
				return STRING_VAR;
				break;
			default:
				return VAR;
				break;
			}
		}
	}
}

/* Get the token type for a constant symbol */
static SDWORD scriptGetConstToken(CONST_SYMBOL *psConst)
{
	bool	object;

	// See if this is an object constant
	if (!asScrTypeTab || psConst->type < VAL_USERTYPESTART)
	{
		object = false;
	}
	else
	{
		object = asScrTypeTab[psConst->type - VAL_USERTYPESTART].accessType == AT_OBJECT;
	}

	switch (psConst->type)
	{
	case VAL_BOOL:
		return BOOL_CONSTANT;
		break;
//	case VAL_FLOAT:
	case VAL_INT:
		return NUM_CONSTANT;
		break;
	case VAL_STRING:
		return STRING_CONSTANT;
		break;
	default:
		if (object)
		{
			//debug(LOG_SCRIPT, "scriptGetConstToken: OBJ_CONSTANT");
			return OBJ_CONSTANT;
		}
		else
		{
			return USER_CONSTANT;
		}
		break;
	}
}

/* Get the token type for a function symbol */
static SDWORD scriptGetFuncToken(FUNC_SYMBOL *psFunc)
{
	bool	object;

	// See if this is an object pointer
	if(psFunc->type >= VAL_USERTYPESTART)
	{
		object = asScrTypeTab[psFunc->type - VAL_USERTYPESTART].accessType == AT_OBJECT;

		if (object)
		{
			return OBJ_FUNC;
		}
	}
	switch (psFunc->type)
	{
	case VAL_BOOL:
		return BOOL_FUNC;
		break;
	case VAL_FLOAT:
		return FLOAT_FUNC;
		break;
	case VAL_INT:
		return NUM_FUNC;
		break;
	case VAL_STRING:
		return STRING_FUNC;
		break;
	case VAL_VOID:
		return FUNC;
		break;
	default:
		return USER_FUNC;
		break;
	}
}

/* Get the token type for a custom function symbol */
static SDWORD scriptGetCustomFuncToken(EVENT_SYMBOL *psFunc)
{
	bool	object;

	// See if this is an object pointer
	if (!asScrTypeTab || psFunc->retType < VAL_USERTYPESTART)
	{
		object = false;
	}
	else
	{
		object = asScrTypeTab[psFunc->retType - VAL_USERTYPESTART].accessType == AT_OBJECT;
	}

	if (object)
	{
		return OBJ_FUNC_CUST;
	}
	else
	{
		switch (psFunc->retType)
		{
		case VAL_BOOL:
			return BOOL_FUNC_CUST;
			break;
		case VAL_FLOAT:

			RULE( "current function is FLOAT_FUNC_CUST");

			return FLOAT_FUNC_CUST;
			break;
		case VAL_INT:

			RULE( "current function is NUM_FUNC_CUST");

			return NUM_FUNC_CUST;
			break;
		case VAL_STRING:
			return STRING_FUNC_CUST;
			break;
		case VAL_VOID:
			return VOID_FUNC_CUST;
			break;
		default:
			return USER_FUNC_CUST;
			break;
		}
	}
}

/* Look up defined macro and return new define buffer */
static bool scriptLoopUpMacro(const char *pMacro, char **ppMacroBody)
{
	unsigned int i;

	for (i = 0; i < scr_num_macros; ++i)
	{
		if(strcmp(pMacro, &(scr_macro[i].scr_define_macro[0]) ) == 0)
		{
			*ppMacroBody = (char *)malloc(MAXSTRLEN);
			strcpy( *ppMacroBody, &(scr_macro[i].scr_define_body[0]) );		//copy macro body into buffer so we can process it
			//*pMacroBody = &(scr_macro[i].scr_define_body[0]);	//return macro body
			return true;
		}
	}

	return false;
}

/* Return to the previous macto buffer */
static void popMacroStack(void)
{
	ASSERT(scr_macro_stack_ptr <= MAX_SCR_MACRO_DEPTH,
		"FLEX: macro stack pointer out of bounds: %d", scr_macro_stack_ptr);

	/* Free current macro buffer */
	free(pScrMacroBuffer[scr_macro_stack_ptr]);
	pScrMacroBuffer[scr_macro_stack_ptr] = NULL;

	/* Delete flex buffer */
	yy_delete_buffer( YY_CURRENT_BUFFER );

	/* Switch one level lower in the macro stack */
	yy_switch_to_buffer( macro_stack[scr_macro_stack_ptr - 1] );

	scr_macro_stack_ptr--;
}

/* Store macro name */
static void storeMacroName(const char *pMacroName)
{
	ASSERT(scr_num_macros < MAX_SCR_MACROS,
		"FLEX: macro count out of bounds: %u", scr_num_macros);

	/* Make sure this name isn't already reserved */
	if((scriptLookUpType(pMacroName, &dummy.tval)) ||
	(scriptLookUpVariable(pMacroName, &dummy.vSymbol)) ||
	(scriptLookUpConstant(pMacroName, &dummy.cSymbol)) ||
	(scriptLookUpFunction(pMacroName, &dummy.fSymbol)) ||
	(scriptLookUpCustomFunction(pMacroName, &dummy.eSymbol)) ||
	(scriptLookUpTrigger(pMacroName, &dummy.tSymbol)) ||
	(scriptLookUpEvent(pMacroName, &dummy.eSymbol)) ||
	(scriptLookUpCallback(pMacroName, &dummy.cbSymbol)))
	{
		scr_error("FLEX: macro name '%s' is already reserved", pMacroName);
	}

	/* Store define macro */
	sstrcpy(scr_macro[scr_num_macros].scr_define_macro, pMacroName);
}

/* Store macro body */
static void storeMacroBody(const char *pMacroBody)
{
	ASSERT(scr_num_macros < MAX_SCR_MACROS,
		"FLEX: macro count out of bounds: %u", scr_num_macros);

	/* Store macro body */
	sstrcpy(scr_macro[scr_num_macros].scr_define_body, pMacroBody);

	scr_num_macros++;
}

/* include directive encountered - push current buffer, set up new one */
static void pushInclude(const char *pIncludePath)
{
	PHYSFS_file* newInput;

	if ( scr_include_stack_ptr >= MAX_SCR_INCLUDE_DEPTH ){
		scr_error("FLEX: Includes nested too deeply" );
	}

	if(!PHYSFS_exists(pIncludePath)){
		scr_error("FLEX: '%s' include doesn't exist", pIncludePath );
	}

	/* Open include */
	newInput = PHYSFS_openRead(pIncludePath);

	if(!newInput){
		scr_error("FLEX: Couldn't open include: '%s'\n%s",
			pIncludePath, WZ_PHYSFS_getLastError() );
	}

	/* Push current flex buffer */
	include_stack[scr_include_stack_ptr] = YY_CURRENT_BUFFER;
	scr_include_stack_ptr++;

	ASSERT(scr_include_stack_ptr < MAX_SCR_INCLUDE_DEPTH,
		"FLEX: scr_include_stack_ptr out of bounds: %u", scr_include_stack_ptr);

	pScrInputFiles[scr_include_stack_ptr] = newInput;
}



%}

%option prefix="scr_"
%option nounput
%option yylineno
%option never-interactive

%x COMMENT
%x SLCOMMENT
%x QUOTE
%x _MACRO
%x _INCL
%x _INCL_END_QUOTE
%x _DEF_MACRO
%x _DEF_BODY_START
%x _DEF_BODY

_IDENTIFIER[a-zA-Z_][0-9_a-zA-Z_]*

%%

	/* Match keywords */
wait					return WAIT;
every					return EVERY;
trigger					return TRIGGER;
event					return EVENT;
inactive				return INACTIVE;
init					return INITIALISE;
link					return LINK;
ref						return REF;
return					return	RET;
function				return	lexFUNCTION;
"("int")"|"("INT")"			{ RULE(yytext); return TO_INT_CAST; }
"("float")"|"("FLOAT")"			{ RULE(yytext); return TO_FLOAT_CAST; }
public					{ scr_lval.stype = ST_PUBLIC; return STORAGE; }
private					{ scr_lval.stype = ST_PRIVATE; return STORAGE; }
local					{ scr_lval.stype = ST_LOCAL; return STORAGE; }
while					return WHILE;
if						return IF;
else					return ELSE;
exit					return EXIT;
pause					return PAUSE;

	/* Match type keywords */
void|VOID				{ scr_lval.tval = VAL_VOID; return _VOID; }
string|STRING				{ scr_lval.tval = VAL_STRING; return TYPE; }
bool|BOOL				{ scr_lval.tval = VAL_BOOL; return TYPE; }
int|INT					{ scr_lval.tval = VAL_INT; return TYPE; }
float|FLOAT				{ scr_lval.tval = VAL_FLOAT; return TYPE; }

	/* Match boolean values */
true|TRUE				{ scr_lval.bval = true; return BOOLEAN_T; }
false|FALSE				{ scr_lval.bval = false; return BOOLEAN_T; }

	/* Match increment/decrement operators */
"++"					{RULE("++"); return _INC; }
"--"					{RULE("++"); return _DEC; }

	/* Match boolean operators */
"=="					return BOOLEQUAL;
"!="					return NOTEQUAL;
">="					return GREATEQUAL;
"<="					return LESSEQUAL;
">"						return GREATER;
"<"						return LESS;
and|AND|"&&"				return _AND;
or|OR|"||"				return _OR;
not|NOT|"!"				return _NOT;

	/* Start of a #define */
"#define"[ \t]+				{ BEGIN (_DEF_MACRO); }

	/* Start of the #define macro name */
<_DEF_MACRO>{_IDENTIFIER}	{
								RULE("FLEX: matched define macro: '#define %s'", scr_text);

								/* Store macro name */
								storeMacroName(scr_text);

								BEGIN (_DEF_BODY_START);
							}

<_DEF_BODY_START>[ \t]+		{ BEGIN (_DEF_BODY); }	/* Eat space between macro and body */

<_DEF_BODY>[^\r\n]*			{	/* Anything until the end of the line is macro body */

								RULE("FLEX: matched define body: '#define %s %s' (%d)",
									scr_macro[scr_num_macros].scr_define_macro, scr_text, scr_num_macros + 1);

								/* Store macro body */
								storeMacroBody(scr_text);

								BEGIN (INITIAL);
							}

	/* Handle Includes */
"#include"[ \t]+\"			{ BEGIN (_INCL); }	/* Match '#include' and skip whitespace until quotation */

<_INCL>[^ \t\n\"]+   		{ 	/* got the include file name */
								RULE("FLEX: Opening include '%s' (scr_include_stack_ptr: %u)", scr_text, scr_include_stack_ptr);

								/* Set up new input buffer, push current one to stack */
								pushInclude(scr_text);

								/* Match the ending quote */
						        BEGIN(_INCL_END_QUOTE);
							}

<_INCL_END_QUOTE>\"			{
								int	line;
								char	*text;
								YY_BUFFER_STATE includeBuffer;

								ASSERT(scr_include_stack_ptr < MAX_SCR_INCLUDE_DEPTH,
									"FLEX:  scr_include_stack_ptr out of bounds: %u", scr_include_stack_ptr);

								ASSERT(pScrInputFiles[scr_include_stack_ptr] != NULL, "FLEX: failed to load include");

								RULE("FLEX: storing line number for include %u: ",
									scr_include_stack_ptr - 1, scr_lineno);

								/* Store the current line number in the current input buffer */
								scriptGetErrorData(&line, &text);
								scrInclLine[scr_include_stack_ptr - 1] = line;
								scr_lineno = 1;		//we are at the beginning of the first line in a new input now

								/* Create a new YY_BUFFER_STATE for this file */
								includeBuffer = yy_create_buffer(NULL, YY_BUF_SIZE);

								/* Switch to the new buffer */
								yy_switch_to_buffer(includeBuffer);

								BEGIN (INITIAL);
							}

<<EOF>> 						{
								RULE("FLEX: EOF: scr_include_stack_ptr: %u; scr_macro_stack_ptr: %d",
									scr_include_stack_ptr, scr_macro_stack_ptr);

								ASSERT(pScrInputFiles[scr_include_stack_ptr] != NULL, "FLEX: can't unload, buffer is NULL");

								if ( scr_include_stack_ptr == 0 )
								{
									/* We finished scanning top level script or macro */
									if(scr_macro_stack_ptr > 0)
									{
										RULE("FLEX: Finished parsing macro %d", scr_macro_stack_ptr);

										popMacroStack();
									}
									else	//both stacks are empty
									{
										RULE("FLEX: Finished parsing all input");
										yyterminate();
									}
								}
								else
								{
									/* First finish scanning all macros */
									if(scr_macro_stack_ptr > 0)
									{
										RULE("FLEX: Finished parsing macro %d in include %d",
											scr_macro_stack_ptr, scr_include_stack_ptr);

										popMacroStack();
									}
									else	//no macros, return to previous include
									{
										RULE("FLEX: returning from parsing include %u", scr_include_stack_ptr);

										/* Free include buffer */
										PHYSFS_close(pScrInputFiles[scr_include_stack_ptr]);
										pScrInputFiles[scr_include_stack_ptr] = NULL;

										/* Delete flex buffer */
										yy_delete_buffer( YY_CURRENT_BUFFER );

										/* Pop previous script file */
										yy_switch_to_buffer( include_stack[scr_include_stack_ptr - 1] );

										ASSERT(scr_include_stack_ptr != 0,
											"Can't restore line number of theprevious flex input");

										/* Restore line count of the previous buffer from the line count stack */
										scr_lineno = scrInclLine[scr_include_stack_ptr - 1];
										RULE("FLEX: restoring line number for include %u: ",
											scr_include_stack_ptr, scr_lineno);

										/* Go to the previous flex input buffer */
										scr_include_stack_ptr--;
									}
								}
					        }


	/* Match floating point numbers */
-?[0-9]*"."[0-9]+			{
								RULE( "float matched '%s'", scr_text);

								scr_lval.fval = (float)atof(scr_text);

								return FLOAT_T;
							}

	/* Match integer numbers */
-?[0-9]+					{ scr_lval.ival = atol(scr_text); return INTEGER; }

	/* Match identifiers */
{_IDENTIFIER}				{
								char* tmpMacroBuffer;
								RULE( "looking up '%s'", scr_text);

								/* See if this identifier has been defined as a type */
								if (scriptLookUpType(scr_text, &scr_lval.tval))	//STRUCTURESTAT etc
								{

									RULE( "'%s' is a user type", scr_text);

									return TYPE;
								}
								/* See if this identifier has been defined as a variable */
								else if (scriptLookUpVariable(scr_text, &scr_lval.vSymbol))
								{

									RULE( "'%s' is a var", scr_text);

									return scriptGetVarToken(scr_lval.vSymbol);
								}
								/* See if this identifier has been defined as a constant */
								else if (scriptLookUpConstant(scr_text, &scr_lval.cSymbol))
								{

									RULE( "'%s' is a constant", scr_text);

									return scriptGetConstToken(scr_lval.cSymbol);
								}
								/* See if this identifier has been defined as a function */
								else if (scriptLookUpFunction(scr_text, &scr_lval.fSymbol))
								{

									RULE( "'%s' is a function", scr_text);

									return scriptGetFuncToken(scr_lval.fSymbol);
								}

								/* See if this identifier has been defined as a custom function */
								else if (scriptLookUpCustomFunction(scr_text, &scr_lval.eSymbol))
								{

									RULE( "'%s' is a cust func", scr_text);

									return scriptGetCustomFuncToken(scr_lval.eSymbol);
								}

								else if (scriptLookUpTrigger(scr_text, &scr_lval.tSymbol))
								{

									RULE( "'%s' is a trigger", scr_text);

									return TRIG_SYM;
								}
								else if (scriptLookUpEvent(scr_text, &scr_lval.eSymbol))
								{

									RULE( "'%s' is an event", scr_text);

									return EVENT_SYM;
								}
								else if (scriptLookUpCallback(scr_text, &scr_lval.cbSymbol))
								{

									RULE( "'%s' is a callback", scr_text);

									return CALLBACK_SYM;
								}
								else if(scriptLoopUpMacro(scr_text, &tmpMacroBuffer))
								{
									RULE( "'%s' is a macro", scr_text);

									ASSERT(tmpMacroBuffer != NULL,
										"FLEX: failed to allocate memory for macro buffer %d", scr_macro_stack_ptr);

									ASSERT(scr_macro_stack_ptr >= 0 && scr_macro_stack_ptr < MAX_SCR_MACRO_DEPTH,
										"FLEX: flex macro buffer pointer out of bounds: %d", scr_macro_stack_ptr );

									/* Push current buffer we are processing;
									 * can be either macro buffer, include buffer or top level script
									 */
									macro_stack[scr_macro_stack_ptr] = YY_CURRENT_BUFFER;
									scr_macro_stack_ptr++;

									pScrMacroBuffer[scr_macro_stack_ptr] = tmpMacroBuffer; // Assign to the new input buffer

									/* Feed flex with the new macro buffer */
									yy_switch_to_buffer( yy_scan_string( pScrMacroBuffer[scr_macro_stack_ptr] ) );
								}
								else
								{
									RULE( "'%s' is an ident", scr_text);

									sstrcpy(aText[currText], scr_text);
									scr_lval.sval = aText[currText];
									currText = (currText + 1) % TEXT_BUFFERS;
									return IDENT;
								}
							}
	/* Strip macros */
"#"							{ BEGIN (_MACRO); }
<_MACRO>\n					{ BEGIN (INITIAL); }
<_MACRO>.					;

	/* Match quoted text */
\"							{ BEGIN (QUOTE); }
<QUOTE>\"					{ BEGIN (INITIAL); }
<QUOTE>[^\"\n]*				{
								sstrcpy(aText[currText], scr_text);
								scr_lval.sval = aText[currText];
								currText = (currText + 1) % TEXT_BUFFERS;
								//debug(LOG_SCRIPT, "%s is QTEXT", scr_text);
								return QTEXT;
							}

	/* Skip white space */
[ \t\n\x0d\x0a]				;

	/* Strip comments */
"/*"						{ inComment=true; BEGIN (COMMENT); }
<COMMENT>"*/" |
<COMMENT>"*/"\n				{ inComment=false; BEGIN (INITIAL); }
<COMMENT>. |
<COMMENT>\n					;

	/* Strip single line comments */
"//"						{ BEGIN (SLCOMMENT); }
<SLCOMMENT>\n				{ BEGIN (INITIAL); }
<SLCOMMENT>[^\n]*			;

	/* Match anything that's been missed and pass it as a char */
.							return scr_text[0];

%%

/* Set the current input file for the lexer */
void scriptSetInputFile(PHYSFS_file* fileHandle)
{
	YY_BUFFER_STATE inputScript;
	unsigned int i;

	/* Reset the lexer in case it's been used before */
	scr__flush_buffer( YY_CURRENT_BUFFER );

	/* Reset include stack */
	scr_include_stack_ptr = 0;

	/* Initialize include input files */
	for(i = 0; i < MAX_SCR_INCLUDE_DEPTH; ++i)
	{
		pScrInputFiles[i] = NULL;
		scrInclLine[i] = 0;
	}

	/* Set the initial input buffer */
	pScrInputFiles[0] = fileHandle;

	inputScript = yy_create_buffer(NULL, YY_BUF_SIZE);

	yy_switch_to_buffer(inputScript);

	/* Reset number of macros */
	scr_num_macros = 0;

	/* Reset macro stack */
	scr_macro_stack_ptr = 0;

	/* Initialize macro input buffers */
	for(i = 0; i < MAX_SCR_MACRO_DEPTH; ++i)
	{
		pScrMacroBuffer[i] = NULL;
	}
}

void scriptGetErrorData(int *pLine, char **ppText)
{
	*pLine = scr_lineno;
	*ppText = scr_text;
}

int scr_wrap(void)
{
	if (inComment)
	{
		debug( LOG_ERROR, "Warning: reached end of file in a comment" );
		abort();
	}
	return 1;
}


/* Older GNU Flex versions don't define yylex_destroy()
 * (and neither define a subminor version)
 */
#if !defined(YY_FLEX_SUBMINOR_VERSION) || (YY_FLEX_SUBMINOR_VERSION < 9)
int scr_lex_destroy(void)
{
	/* For non-reentrant C scanner only. */
	yy_delete_buffer(YY_CURRENT_BUFFER);
	yy_init = 1;
	return 0;
}
#endif
