2011-04-06 23:30:59 +03:00
# pragma once
2011-12-14 00:23:17 +03:00
2011-04-06 23:30:59 +03:00
# include "ERMParser.h"
2011-05-22 21:46:52 +03:00
# include "ERMScriptModule.h"
2011-04-06 23:30:59 +03:00
/*
* ERMInterpreter . h , part of VCMI engine
*
* Authors : listed in file AUTHORS in main folder
*
* License : GNU General Public License v2 .0 or later
* Full text of license available in license . txt file , in main folder
*
*/
2011-04-10 19:39:34 +03:00
namespace VERMInterpreter
{
using namespace ERM ;
//different exceptions that can be thrown during interpreting
class EInterpreterProblem : public std : : exception
{
std : : string problem ;
public :
const char * what ( ) const throw ( ) OVERRIDE
{
return problem . c_str ( ) ;
}
2011-04-16 20:39:38 +03:00
~ EInterpreterProblem ( ) throw ( )
{ }
2011-04-10 19:39:34 +03:00
EInterpreterProblem ( const std : : string & problemDesc ) : problem ( problemDesc )
{ }
} ;
struct ESymbolNotFound : public EInterpreterProblem
{
ESymbolNotFound ( const std : : string & sym ) :
EInterpreterProblem ( std : : string ( " Symbol \" " ) + sym + std : : string ( " \" not found! " ) )
{ }
} ;
struct EInvalidTrigger : public EInterpreterProblem
{
EInvalidTrigger ( const std : : string & sym ) :
EInterpreterProblem ( std : : string ( " Trigger \" " ) + sym + std : : string ( " \" is invalid! " ) )
{ }
} ;
2011-04-16 20:39:38 +03:00
struct EUsageOfUndefinedMacro : public EInterpreterProblem
{
EUsageOfUndefinedMacro ( const std : : string & macro ) :
EInterpreterProblem ( std : : string ( " Macro " ) + macro + " is undefined " )
{ }
} ;
2011-04-17 20:51:48 +03:00
struct EIexpProblem : public EInterpreterProblem
2011-04-16 20:39:38 +03:00
{
2011-04-17 20:51:48 +03:00
EIexpProblem ( const std : : string & desc ) :
2011-04-16 20:39:38 +03:00
EInterpreterProblem ( desc )
{ }
} ;
2011-04-21 23:06:42 +03:00
struct ELineProblem : public EInterpreterProblem
{
ELineProblem ( const std : : string & desc ) :
EInterpreterProblem ( desc )
{ }
} ;
2011-04-22 23:33:34 +03:00
struct EExecutionError : public EInterpreterProblem
{
EExecutionError ( const std : : string & desc ) :
EInterpreterProblem ( desc )
{ }
} ;
//internal interpreter error related to execution
struct EInterpreterError : public EExecutionError
{
EInterpreterError ( const std : : string & desc ) :
EExecutionError ( desc )
{ }
} ;
//wrong script
struct EScriptExecError : public EExecutionError
{
EScriptExecError ( const std : : string & desc ) :
EExecutionError ( desc )
{ }
} ;
2011-06-04 21:16:32 +03:00
//wrong script
struct EVermScriptExecError : public EScriptExecError
2011-04-10 19:39:34 +03:00
{
2011-06-04 21:16:32 +03:00
EVermScriptExecError ( const std : : string & desc ) :
EScriptExecError ( desc )
{ }
2011-04-10 19:39:34 +03:00
} ;
2011-06-04 21:16:32 +03:00
2011-04-10 19:39:34 +03:00
// All numeric variables are integer variables and have a range of -2147483647...+2147483647
// c stores game active day number //indirect variable
// d current value //not an actual variable but a modifier
// e1..e100 Function floating point variables //local
// e-1..e-100 Trigger local floating point variables //local
// 'f'..'t' Standard variables ('quick variables') //global
// v1..v1000 Standard variables //global
// w1..w100 Hero variables
// w101..w200 Hero variables
// x1..x16 Function parameters //local
// y1..y100 Function local variables //local
// y-1..y-100 Trigger-based local integer variables //local
// z1..z1000 String variables //global
// z-1..z-10 Function local string variables //local
struct TriggerLocalVars
{
static const int EVAR_NUM = 100 ; //number of evar locals
static const int YVAR_NUM = 100 ; //number of yvar locals
2011-04-22 23:33:34 +03:00
TriggerLocalVars ( ) ;
2011-05-02 21:39:57 +03:00
double & getEvar ( int num ) ;
int & getYvar ( int num ) ;
private :
double evar [ EVAR_NUM ] ; //negative indices
int yvar [ YVAR_NUM ] ;
2011-04-10 19:39:34 +03:00
} ;
struct FunctionLocalVars
{
static const int NUM_PARAMETERS = 16 ; //number of function parameters
static const int NUM_LOCALS = 100 ;
static const int NUM_STRINGS = 10 ;
static const int NUM_FLOATINGS = 100 ;
2011-12-14 00:23:17 +03:00
2011-05-02 21:39:57 +03:00
int & getParam ( int num ) ;
int & getLocal ( int num ) ;
std : : string & getString ( int num ) ;
double & getFloat ( int num ) ;
2011-05-12 23:49:37 +03:00
void reset ( ) ;
2011-05-02 21:39:57 +03:00
private :
int params [ NUM_PARAMETERS ] ; //x-vars
int locals [ NUM_LOCALS ] ; //y-vars
std : : string strings [ NUM_STRINGS ] ; //z-vars (negative indices)
2011-04-10 19:39:34 +03:00
double floats [ NUM_FLOATINGS ] ; //e-vars (positive indices)
} ;
struct ERMEnvironment
{
2011-04-22 23:33:34 +03:00
ERMEnvironment ( ) ;
2011-04-10 19:39:34 +03:00
static const int NUM_QUICKS = ' t ' - ' f ' + 1 ; //it should be 15
2011-05-15 21:21:07 +03:00
int & getQuickVar ( const char letter ) ; //'f' - 't' variables
2011-05-06 22:32:04 +03:00
int & getStandardVar ( int num ) ; //get v-variable
2011-05-02 21:39:57 +03:00
std : : string & getZVar ( int num ) ;
bool & getFlag ( int num ) ;
2011-04-10 19:39:34 +03:00
2011-05-14 16:20:19 +03:00
static const int NUM_STANDARDS = 10000 ;
2011-04-10 19:39:34 +03:00
static const int NUM_STRINGS = 1000 ;
2011-04-16 20:39:38 +03:00
std : : map < std : : string , ERM : : TVarExpNotMacro > macroBindings ;
2011-04-22 23:33:34 +03:00
static const int NUM_FLAGS = 1000 ;
2011-05-02 21:39:57 +03:00
private :
int quickVars [ NUM_QUICKS ] ; //referenced by letter ('f' to 't' inclusive)
int standardVars [ NUM_STANDARDS ] ; //v-vars
std : : string strings [ NUM_STRINGS ] ; //z-vars (positive indices)
2011-04-22 23:33:34 +03:00
bool flags [ NUM_FLAGS ] ;
2011-04-10 19:39:34 +03:00
} ;
struct TriggerType
{
//the same order of trigger types in this enum and in validTriggers array is obligatory!
enum ETrigType { AE , BA , BF , BG , BR , CM , CO , FU , GE , GM , HE , HL , HM , IP , LE , MF , MG , MM , MR ,
MW , OB , PI , SN , TH , TM } type ;
static ETrigType convertTrigger ( const std : : string & trig )
{
static const std : : string validTriggers [ ] = { " AE " , " BA " , " BF " , " BG " , " BR " , " CM " , " CO " , " FU " ,
" GE " , " GM " , " HE " , " HL " , " HM " , " IP " , " LE " , " MF " , " MG " , " MM " , " MR " , " MW " , " OB " , " PI " , " SN " ,
" TH " , " TM " } ;
for ( int i = 0 ; i < ARRAY_COUNT ( validTriggers ) ; + + i )
{
if ( validTriggers [ i ] = = trig )
return static_cast < ETrigType > ( i ) ;
}
throw EInvalidTrigger ( trig ) ;
}
2011-04-16 20:39:38 +03:00
bool operator < ( const TriggerType & t2 ) const
{
return type < t2 . type ;
}
2011-04-10 19:39:34 +03:00
TriggerType ( const std : : string & sym )
{
type = convertTrigger ( sym ) ;
}
} ;
struct FileInfo
{
std : : string filename ;
int length ;
} ;
struct LinePointer
{
const FileInfo * file ; //non-owning
int lineNum ;
2011-05-11 22:53:55 +03:00
int realLineNum ;
2011-04-16 20:39:38 +03:00
LinePointer ( ) : file ( NULL )
{ }
2011-05-11 22:53:55 +03:00
LinePointer ( const FileInfo * finfo , int line , int _realLineNum ) : file ( finfo ) , lineNum ( line ) ,
realLineNum ( _realLineNum )
2011-04-10 19:39:34 +03:00
{ }
//lexicographical order
bool operator < ( const LinePointer & rhs ) const
{
if ( file - > filename ! = rhs . file - > filename )
return file - > filename < rhs . file - > filename ;
return lineNum < rhs . lineNum ;
}
bool operator ! = ( const LinePointer & rhs ) const
{
return file - > filename ! = rhs . file - > filename | | lineNum ! = rhs . lineNum ;
}
LinePointer & operator + + ( )
{
+ + lineNum ;
return * this ;
}
bool isValid ( ) const
{
2011-04-16 20:39:38 +03:00
return file & & lineNum < file - > length ;
2011-04-10 19:39:34 +03:00
}
} ;
struct LexicalPtr
{
LinePointer line ; //where to start
std : : vector < int > entryPoints ; //defines how to pass to current location
bool operator < ( const LexicalPtr & sec ) const
{
if ( line ! = sec . line )
return line < sec . line ;
if ( entryPoints . size ( ) ! = sec . entryPoints . size ( ) )
return entryPoints . size ( ) < sec . entryPoints . size ( ) ;
for ( int g = 0 ; g < entryPoints . size ( ) ; + + g )
{
if ( entryPoints [ g ] < sec . entryPoints [ g ] )
return true ;
}
return false ;
}
} ;
//call stack, represents dynamic range
struct Stack
{
std : : vector < LexicalPtr > stack ;
} ;
struct Trigger
{
LinePointer line ;
TriggerLocalVars ermLocalVars ;
Stack * stack ; //where we are stuck at execution
2011-04-16 20:39:38 +03:00
Trigger ( ) : stack ( NULL )
{ }
2011-04-10 19:39:34 +03:00
} ;
2011-05-29 21:16:49 +03:00
//verm goodies
struct VSymbol
{
std : : string text ;
VSymbol ( const std : : string & txt ) : text ( txt )
{ }
} ;
2011-06-04 21:16:32 +03:00
struct VNode ;
struct VOptionList ;
2011-05-29 21:16:49 +03:00
struct VNIL
{ } ;
2011-06-04 21:16:32 +03:00
typedef boost : : variant < char , double , int , std : : string > TLiteral ;
2011-06-11 21:10:15 +03:00
//for operator <, but this one seems to be implemented in boost alerady
struct _opLTvis : boost : : static_visitor < bool >
{
const TLiteral & lhs ;
_opLTvis ( const TLiteral & _lhs ) : lhs ( _lhs )
{ }
template < typename OP >
bool operator ( ) ( OP const & rhs ) const
{
return boost : : get < OP > ( lhs ) < rhs ;
}
} ;
// bool operator<(const TLiteral & t1, const TLiteral & t2)
// {
// if(t1.type() == t2.type())
// {
// return boost::apply_visitor(_opLTvis(t1), t2);
// }
// throw EVermScriptExecError("These types are incomparable!");
// }
2011-05-29 21:16:49 +03:00
2011-06-11 21:10:15 +03:00
//for operator <=
struct _opLEvis : boost : : static_visitor < bool >
{
const TLiteral & lhs ;
_opLEvis ( const TLiteral & _lhs ) : lhs ( _lhs )
{ }
template < typename OP >
bool operator ( ) ( OP const & rhs ) const
{
return boost : : get < OP > ( lhs ) < = rhs ;
}
} ;
bool operator < = ( const TLiteral & t1 , const TLiteral & t2 ) ;
//operator >
struct _opGTvis : boost : : static_visitor < bool >
{
const TLiteral & lhs ;
_opGTvis ( const TLiteral & _lhs ) : lhs ( _lhs )
{ }
template < typename OP >
bool operator ( ) ( OP const & rhs ) const
{
2011-06-18 21:24:56 +03:00
return boost : : get < OP > ( lhs ) > rhs ;
2011-06-11 21:10:15 +03:00
}
} ;
bool operator > ( const TLiteral & t1 , const TLiteral & t2 ) ;
//operator >=
struct _opGEvis : boost : : static_visitor < bool >
{
const TLiteral & lhs ;
_opGEvis ( const TLiteral & _lhs ) : lhs ( _lhs )
{ }
template < typename OP >
bool operator ( ) ( OP const & rhs ) const
{
2011-06-18 21:24:56 +03:00
return boost : : get < OP > ( lhs ) > = rhs ;
2011-06-11 21:10:15 +03:00
}
} ;
bool operator > = ( const TLiteral & t1 , const TLiteral & t2 ) ;
2011-06-18 21:24:56 +03:00
//operator =
struct _opEQvis : boost : : static_visitor < bool >
{
const TLiteral & lhs ;
_opEQvis ( const TLiteral & _lhs ) : lhs ( _lhs )
{ }
template < typename OP >
bool operator ( ) ( OP const & rhs ) const
{
return boost : : get < OP > ( lhs ) = = rhs ;
}
} ;
2011-06-11 21:10:15 +03:00
//VFunc
struct VFunc ;
//VOption & stuff
typedef boost : : variant < VNIL , boost : : recursive_wrapper < VNode > , VSymbol , TLiteral , ERM : : Tcommand , boost : : recursive_wrapper < VFunc > > VOption ; //options in v-expression, VNIl should be the default
2011-05-29 21:16:49 +03:00
2011-06-04 21:16:32 +03:00
template < typename T , typename SecType >
T & getAs ( SecType & opt )
{
if ( opt . type ( ) = = typeid ( T ) )
return boost : : get < T > ( opt ) ;
else
throw EVermScriptExecError ( " Wrong type! " ) ;
}
template < typename T , typename SecType >
2011-06-10 15:49:31 +03:00
bool isA ( const SecType & opt )
2011-06-04 21:16:32 +03:00
{
if ( opt . type ( ) = = typeid ( T ) )
return true ;
else
return false ;
}
//why it doesn't work?
// template<typename TBasicVariant>
// struct IntVarinant : public TBasicVariant
// {
// template<typename T>
// bool isA() const
// {
// return type() == typeid(T);
// }
// template<typename T>
// T getAs()
// {
// if(isA<T>())
// return boost::get<T>(*this);
// else
// throw EVermScriptExecError("Getting improved variant with wrongly specified type");
// }
//
// IntVarinant(const VNode & val) : TBasicVariant(val)
// {}
// IntVarinant(const VNIL & val) : TBasicVariant(val)
// {}
// IntVarinant(const TLiteral & val) : TBasicVariant(val)
// {}
// IntVarinant(const VSymbol & val) : TBasicVariant(val)
// {}
// IntVarinant(const int & val) : TBasicVariant(val)
// {}
// IntVarinant(const char & val) : TBasicVariant(val)
// {}
// IntVarinant(const double & val) : TBasicVariant(val)
// {}
// IntVarinant(const ERM::Tcommand & val) : TBasicVariant(val)
// {}
// TBasicVariant & getAsPlaintVariant()
// {
// return *this;
// }
//
// IntVarinant()
// {}
// };
2011-06-11 21:10:15 +03:00
2011-06-04 21:16:32 +03:00
///main environment class, manages symbols
class Environment
{
private :
std : : map < std : : string , VOption > symbols ;
Environment * parent ;
public :
2011-06-11 21:10:15 +03:00
Environment ( ) : parent ( NULL )
{ }
void setPatent ( Environment * _parent ) ;
Environment * getPatent ( ) const ;
enum EIsBoundMode { GLOBAL_ONLY , LOCAL_ONLY , ANYWHERE } ;
bool isBound ( const std : : string & name , EIsBoundMode mode ) const ;
2011-06-04 21:16:32 +03:00
VOption & retrieveValue ( const std : : string & name ) ;
enum EUnbindMode { LOCAL , RECURSIVE_UNTIL_HIT , FULLY_RECURSIVE } ;
///returns true if symbol was really unbound
bool unbind ( const std : : string & name , EUnbindMode mode ) ;
void localBind ( std : : string name , const VOption & sym ) ;
2011-06-11 21:10:15 +03:00
void bindAtFirstHit ( std : : string name , const VOption & sym ) ; //if symbol is locally defines, it gets overwritten; otherwise it is bind globally
} ;
//this class just introduces a new dynamic range when instantiated, nothing more
class IntroduceDynamicEnv
{
public :
IntroduceDynamicEnv ( ) ;
~ IntroduceDynamicEnv ( ) ;
2011-06-04 21:16:32 +03:00
} ;
2011-05-29 21:16:49 +03:00
struct VermTreeIterator
{
private :
friend struct VOptionList ;
2011-06-11 21:10:15 +03:00
VOptionList * parent ;
enum Estate { NORM , CAR } state ;
2011-06-04 21:16:32 +03:00
int basePos ; //car/cdr offset
2011-05-29 21:16:49 +03:00
public :
2011-06-15 04:36:36 +03:00
VermTreeIterator ( VOptionList & _parent ) : parent ( & _parent ) , state ( NORM ) , basePos ( 0 )
2011-06-11 21:10:15 +03:00
{ }
VermTreeIterator ( ) : parent ( NULL ) , state ( NORM )
2011-05-29 21:16:49 +03:00
{ }
VermTreeIterator & operator = ( const VOption & opt ) ;
VermTreeIterator & operator = ( const std : : vector < VOption > & opt ) ;
VermTreeIterator & operator = ( const VOptionList & opt ) ;
2011-06-04 21:16:32 +03:00
VOption & getAsItem ( ) ;
2011-06-11 21:10:15 +03:00
VermTreeIterator getAsCDR ( ) ;
VOptionList getAsList ( ) ;
2011-06-04 21:16:32 +03:00
VOption & getIth ( int i ) ;
size_t size ( ) const ;
2011-06-11 21:10:15 +03:00
VermTreeIterator & operator = ( const VermTreeIterator & rhs )
{
if ( this = = & rhs )
{
return * this ;
}
parent = rhs . parent ;
state = rhs . state ;
basePos = rhs . basePos ;
return * this ;
}
2011-05-29 21:16:49 +03:00
} ;
2011-06-04 21:16:32 +03:00
struct VOptionList : public std : : vector < VOption >
2011-05-29 21:16:49 +03:00
{
2011-06-04 21:16:32 +03:00
private :
friend struct VermTreeIterator ;
public :
VermTreeIterator car ( ) ;
VermTreeIterator cdr ( ) ;
bool isNil ( ) const ;
2011-05-29 21:16:49 +03:00
} ;
2011-06-11 21:10:15 +03:00
struct VFunc
{
2011-06-18 21:24:56 +03:00
enum Eopt { DEFAULT , LT , GT , LE , GE , EQ , ADD , SUB , MULT , DIV , MOD } option ;
2011-06-11 21:10:15 +03:00
std : : vector < VSymbol > args ;
VOptionList body ;
2011-06-18 21:24:56 +03:00
bool macro ; //true - act as macro, false - act as function
VFunc ( const VOptionList & _body , bool asMacro = false ) : option ( DEFAULT ) , body ( _body ) , macro ( asMacro )
2011-06-11 21:10:15 +03:00
{ }
2011-06-18 21:24:56 +03:00
VFunc ( Eopt func ) : option ( func ) , macro ( false )
2011-06-11 21:10:15 +03:00
{ }
VFunc & operator = ( const VFunc & rhs )
{
if ( this = = & rhs )
{
return * this ;
}
args = rhs . args ;
body = rhs . body ;
return * this ;
}
VOption operator ( ) ( VermTreeIterator params ) ;
} ;
2011-05-29 21:16:49 +03:00
struct OptionConverterVisitor : boost : : static_visitor < VOption >
{
VOption operator ( ) ( ERM : : TVExp const & cmd ) const ;
VOption operator ( ) ( ERM : : TSymbol const & cmd ) const ;
VOption operator ( ) ( char const & cmd ) const ;
VOption operator ( ) ( double const & cmd ) const ;
VOption operator ( ) ( int const & cmd ) const ;
VOption operator ( ) ( ERM : : Tcommand const & cmd ) const ;
VOption operator ( ) ( ERM : : TStringConstant const & cmd ) const ;
} ;
struct VNode
{
private :
2011-06-18 21:24:56 +03:00
void processModifierList ( const std : : vector < TVModifier > & modifierList , bool asSymbol ) ;
2011-05-29 21:16:49 +03:00
public :
VOptionList children ;
VNode ( const ERM : : TVExp & exp ) ;
VNode ( const VOptionList & cdren ) ;
VNode ( const ERM : : TSymbol & sym ) ; //only in case sym has modifiers!
VNode ( const VOption & first , const VOptionList & rest ) ; //merges given arguments into [a, rest];
void setVnode ( const VOption & first , const VOptionList & rest ) ;
} ;
2011-06-11 21:10:15 +03:00
//v printer
void printVOption ( const VOption & opt ) ;
2011-04-10 19:39:34 +03:00
}
2011-04-17 20:51:48 +03:00
class ERMInterpreter ;
2011-04-16 20:39:38 +03:00
struct TriggerIdentifierMatch
{
bool allowNoIdetifier ;
std : : map < int , std : : vector < int > > matchToIt ; //match subidentifiers to these numbers
static const int MAX_SUBIDENTIFIERS = 16 ;
2011-04-17 20:51:48 +03:00
ERMInterpreter * ermEnv ;
2011-04-21 23:06:42 +03:00
bool tryMatch ( VERMInterpreter : : Trigger * interptrig ) const ;
2011-04-16 20:39:38 +03:00
} ;
2011-05-02 21:39:57 +03:00
struct IexpValStr
{
2011-05-06 22:32:04 +03:00
private :
2011-05-02 21:39:57 +03:00
union
{
int val ;
int * integervar ;
double * flvar ;
std : : string * stringvar ;
} val ;
2011-05-06 22:32:04 +03:00
public :
2011-05-22 21:46:52 +03:00
std : : string name ;
std : : string getName ( ) const ;
2011-05-02 21:39:57 +03:00
enum { WRONGVAL , INT , INTVAR , FLOATVAR , STRINGVAR } type ;
2011-05-06 22:32:04 +03:00
void setTo ( const IexpValStr & second ) ;
void setTo ( int val ) ;
2011-12-14 00:23:17 +03:00
void setTo ( double val ) ;
2011-05-06 22:32:04 +03:00
void setTo ( const std : : string & val ) ;
int getInt ( ) const ;
2011-12-14 00:23:17 +03:00
double getFloat ( ) const ;
2011-05-06 22:32:04 +03:00
std : : string getString ( ) const ;
IexpValStr ( ) : type ( WRONGVAL )
{ }
IexpValStr ( int _val ) : type ( INT )
{
val . val = _val ;
}
IexpValStr ( int * _val ) : type ( INTVAR )
{
val . integervar = _val ;
}
IexpValStr ( double * _val ) : type ( FLOATVAR )
{
val . flvar = _val ;
}
IexpValStr ( std : : string * _val ) : type ( STRINGVAR )
{
val . stringvar = _val ;
}
2011-05-07 18:13:56 +03:00
# define OPERATOR_DEFINITION_FULL(OPSIGN) \
template < typename T > \
IexpValStr operator OPSIGN ( const T & sec ) const \
{ \
IexpValStr ret = * this ; \
switch ( type ) \
{ \
case INT : \
case INTVAR : \
ret . setTo ( ret . getInt ( ) OPSIGN sec ) ; \
break ; \
case FLOATVAR : \
ret . setTo ( ret . getFloat ( ) OPSIGN sec ) ; \
break ; \
case STRINGVAR : \
ret . setTo ( ret . getString ( ) OPSIGN sec ) ; \
break ; \
} \
return ret ; \
} \
IexpValStr operator OPSIGN ( const IexpValStr & sec ) const \
{ \
IexpValStr ret = * this ; \
switch ( type ) \
{ \
case INT : \
case INTVAR : \
ret . setTo ( ret . getInt ( ) OPSIGN sec . getInt ( ) ) ; \
break ; \
case FLOATVAR : \
ret . setTo ( ret . getFloat ( ) OPSIGN sec . getFloat ( ) ) ; \
break ; \
case STRINGVAR : \
ret . setTo ( ret . getString ( ) OPSIGN sec . getString ( ) ) ; \
break ; \
} \
return ret ; \
} \
template < typename T > \
IexpValStr & operator OPSIGN # # = ( const T & sec ) \
{ \
* this = * this OPSIGN sec ; \
return * this ; \
}
# define OPERATOR_DEFINITION(OPSIGN) \
template < typename T > \
IexpValStr operator OPSIGN ( const T & sec ) const \
{ \
IexpValStr ret = * this ; \
switch ( type ) \
{ \
case INT : \
case INTVAR : \
ret . setTo ( ret . getInt ( ) OPSIGN sec ) ; \
break ; \
case FLOATVAR : \
ret . setTo ( ret . getFloat ( ) OPSIGN sec ) ; \
break ; \
} \
return ret ; \
} \
IexpValStr operator OPSIGN ( const IexpValStr & sec ) const \
{ \
IexpValStr ret = * this ; \
switch ( type ) \
{ \
case INT : \
case INTVAR : \
ret . setTo ( ret . getInt ( ) OPSIGN sec . getInt ( ) ) ; \
break ; \
case FLOATVAR : \
ret . setTo ( ret . getFloat ( ) OPSIGN sec . getFloat ( ) ) ; \
break ; \
} \
return ret ; \
} \
template < typename T > \
IexpValStr & operator OPSIGN # # = ( const T & sec ) \
{ \
* this = * this OPSIGN sec ; \
return * this ; \
}
# define OPERATOR_DEFINITION_INTEGER(OPSIGN) \
template < typename T > \
IexpValStr operator OPSIGN ( const T & sec ) const \
{ \
IexpValStr ret = * this ; \
switch ( type ) \
{ \
case INT : \
case INTVAR : \
ret . setTo ( ret . getInt ( ) OPSIGN sec ) ; \
break ; \
} \
return ret ; \
} \
IexpValStr operator OPSIGN ( const IexpValStr & sec ) const \
{ \
IexpValStr ret = * this ; \
switch ( type ) \
{ \
case INT : \
case INTVAR : \
ret . setTo ( ret . getInt ( ) OPSIGN sec . getInt ( ) ) ; \
break ; \
} \
return ret ; \
} \
template < typename T > \
IexpValStr & operator OPSIGN # # = ( const T & sec ) \
{ \
* this = * this OPSIGN sec ; \
return * this ; \
}
OPERATOR_DEFINITION_FULL ( + )
OPERATOR_DEFINITION ( - )
OPERATOR_DEFINITION ( * )
OPERATOR_DEFINITION ( / )
OPERATOR_DEFINITION_INTEGER ( % )
2011-05-02 21:39:57 +03:00
} ;
2011-05-22 21:46:52 +03:00
class ERMInterpreter : public CScriptingModule
2011-04-06 23:30:59 +03:00
{
2011-05-16 15:11:00 +03:00
/*not so*/ public :
// friend class ScriptScanner;
// friend class TriggerIdMatchHelper;
// friend class TriggerIdentifierMatch;
// friend class ConditionDisemboweler;
// friend struct LVL2IexpDisemboweler;
// friend struct VR_SPerformer;
// friend struct ERMExpDispatch;
// friend struct VRPerformer;
2011-04-16 20:39:38 +03:00
2011-04-10 19:39:34 +03:00
std : : vector < VERMInterpreter : : FileInfo * > files ;
2011-04-16 20:39:38 +03:00
std : : vector < VERMInterpreter : : FileInfo * > fileInfos ;
2011-04-10 19:39:34 +03:00
std : : map < VERMInterpreter : : LinePointer , ERM : : TLine > scripts ;
std : : map < VERMInterpreter : : LexicalPtr , VERMInterpreter : : Environment > lexicalEnvs ;
2011-05-22 21:46:52 +03:00
ERM : : TLine & retrieveLine ( VERMInterpreter : : LinePointer linePtr ) ;
static ERM : : TTriggerBase & retrieveTrigger ( ERM : : TLine & line ) ;
2011-04-10 19:39:34 +03:00
VERMInterpreter : : Environment * globalEnv ;
2011-04-16 20:39:38 +03:00
VERMInterpreter : : ERMEnvironment * ermGlobalEnv ;
2011-04-21 23:06:42 +03:00
typedef std : : map < VERMInterpreter : : TriggerType , std : : vector < VERMInterpreter : : Trigger > > TtriggerListType ;
TtriggerListType triggers , postTriggers ;
2011-05-03 17:45:57 +03:00
VERMInterpreter : : Trigger * curTrigger ;
VERMInterpreter : : FunctionLocalVars * curFunc ;
2011-05-06 22:32:04 +03:00
static const int TRIG_FUNC_NUM = 30000 ;
2011-12-14 00:23:17 +03:00
VERMInterpreter : : FunctionLocalVars funcVars [ TRIG_FUNC_NUM + 1 ] ; //+1 because we use [0] as a global set of y-vars
2011-05-14 16:20:19 +03:00
VERMInterpreter : : FunctionLocalVars * getFuncVars ( int funNum ) ; //0 is a global func-like set
2011-04-16 20:39:38 +03:00
2011-05-03 17:45:57 +03:00
IexpValStr getIexp ( const ERM : : TIexp & iexp ) const ;
2011-05-06 22:32:04 +03:00
IexpValStr getIexp ( const ERM : : TMacroUsage & macro ) const ;
IexpValStr getIexp ( const ERM : : TIdentifierInternal & tid ) const ;
2011-05-16 15:11:00 +03:00
IexpValStr getIexp ( const ERM : : TVarpExp & tid ) const ;
2011-05-22 21:46:52 +03:00
IexpValStr getIexp ( const ERM : : TBodyOptionItem & opit ) const ;
2011-04-10 19:39:34 +03:00
2011-04-16 20:39:38 +03:00
static const std : : string triggerSymbol , postTriggerSymbol , defunSymbol ;
2011-04-10 19:39:34 +03:00
void executeLine ( const VERMInterpreter : : LinePointer & lp ) ;
2011-06-24 00:42:30 +03:00
void executeLine ( const ERM : : TLine & line ) ;
2011-05-12 23:49:37 +03:00
void executeTrigger ( VERMInterpreter : : Trigger & trig , int funNum = - 1 , std : : vector < int > funParams = std : : vector < int > ( ) ) ;
2011-04-10 19:39:34 +03:00
static bool isCMDATrigger ( const ERM : : Tcommand & cmd ) ;
static bool isATrigger ( const ERM : : TLine & line ) ;
static ERM : : EVOtions getExpType ( const ERM : : TVOption & opt ) ;
2011-05-06 22:32:04 +03:00
IexpValStr getVar ( std : : string toFollow , boost : : optional < int > initVal ) const ;
2011-05-16 15:11:00 +03:00
2011-05-17 22:24:18 +03:00
std : : string processERMString ( std : : string ermstring ) ;
2011-05-16 15:11:00 +03:00
2011-06-04 21:16:32 +03:00
VERMInterpreter : : VOption eval ( VERMInterpreter : : VOption line , VERMInterpreter : : Environment * env = NULL ) ;
VERMInterpreter : : VOptionList evalEach ( VERMInterpreter : : VermTreeIterator list , VERMInterpreter : : Environment * env = NULL ) ;
2011-04-06 23:30:59 +03:00
public :
2011-05-07 18:13:56 +03:00
typedef std : : map < int , std : : vector < int > > TIDPattern ;
2011-05-10 01:20:47 +03:00
void executeInstructions ( ) ; //called when starting a new game, before most of the map settings are done
2011-05-14 16:20:19 +03:00
void executeTriggerType ( VERMInterpreter : : TriggerType tt , bool pre , const TIDPattern & identifier , const std : : vector < int > & funParams = std : : vector < int > ( ) ) ; //use this to run triggers
2011-05-10 01:20:47 +03:00
void executeTriggerType ( const char * trigger , int id ) ; //convenience version of above, for pre-trigger when there is only one argument
void executeTriggerType ( const char * trigger ) ; //convenience version of above, for pre-trigger when there are no args
2011-05-15 21:21:07 +03:00
void setCurrentlyVisitedObj ( int3 pos ) ; //sets v998 - v1000 to given value
2011-04-06 23:30:59 +03:00
void scanForScripts ( ) ;
2011-04-10 19:39:34 +03:00
2011-04-06 23:30:59 +03:00
enum EPrintMode { ALL , ERM_ONLY , VERM_ONLY } ;
void printScripts ( EPrintMode mode = ALL ) ;
2011-04-10 19:39:34 +03:00
void scanScripts ( ) ; //scans for functions, triggers etc.
ERMInterpreter ( ) ;
2011-05-02 21:39:57 +03:00
bool checkCondition ( ERM : : Tcondition cond ) ;
2011-06-27 19:03:03 +03:00
int getRealLine ( const VERMInterpreter : : LinePointer & lp ) ;
2011-05-22 21:46:52 +03:00
//overload CScriptingModule
virtual void heroVisit ( const CGHeroInstance * visitor , const CGObjectInstance * visitedObj , bool start ) OVERRIDE ;
virtual void init ( ) OVERRIDE ; //sets up environment etc.
2011-06-11 02:50:32 +03:00
virtual void executeUserCommand ( const std : : string & cmd ) OVERRIDE ;
2011-06-20 14:41:04 +03:00
virtual void giveInfoCB ( CPrivilagedInfoCallback * cb ) OVERRIDE ;
virtual void giveActionCB ( IGameEventRealizer * cb ) OVERRIDE ;
2011-06-11 02:50:32 +03:00
2011-05-22 21:46:52 +03:00
virtual void battleStart ( const CCreatureSet * army1 , const CCreatureSet * army2 , int3 tile , const CGHeroInstance * hero1 , const CGHeroInstance * hero2 , bool side ) OVERRIDE ;
const CGObjectInstance * getObjFrom ( int3 pos ) ;
template < typename T >
const T * getObjFromAs ( int3 pos )
{
const T * obj = dynamic_cast < const T * > ( getObjFrom ( pos ) ) ;
if ( obj )
return obj ;
else
2011-05-27 16:49:18 +03:00
throw VERMInterpreter : : EScriptExecError ( " Wrong cast attempted, object is not of a desired type! " ) ;
2011-05-22 21:46:52 +03:00
}
2011-06-20 14:41:04 +03:00
2011-04-11 01:06:05 +03:00
} ;