mirror of
https://github.com/vcmi/vcmi.git
synced 2024-11-24 08:32:34 +02:00
* some progress in VERM interpreter
This commit is contained in:
parent
3241e7c8f8
commit
36fb9b0b6e
@ -402,11 +402,53 @@ void ERMInterpreter::printScripts( EPrintMode mode /*= EPrintMode::ALL*/ )
|
||||
}
|
||||
}
|
||||
|
||||
struct ScriptScanner : boost::static_visitor<>
|
||||
{
|
||||
ERMInterpreter * interpreter;
|
||||
LinePointer lp;
|
||||
|
||||
ScriptScanner(ERMInterpreter * interpr, const LinePointer & _lp) : interpreter(interpr), lp(_lp)
|
||||
{}
|
||||
|
||||
void operator()(TVExp const& cmd) const
|
||||
{
|
||||
//
|
||||
}
|
||||
void operator()(TERMline const& cmd) const
|
||||
{
|
||||
if(cmd.which() == 0) //TCommand
|
||||
{
|
||||
Tcommand tcmd = boost::get<Tcommand>(cmd);
|
||||
switch (tcmd.cmd.which())
|
||||
{
|
||||
case 0: //trigger
|
||||
{
|
||||
Trigger trig;
|
||||
trig.line = lp;
|
||||
interpreter->triggers[ TriggerType(boost::get<ERM::Ttrigger>(tcmd.cmd).name) ].push_back(trig);
|
||||
}
|
||||
break;
|
||||
case 3: //post trigger
|
||||
{
|
||||
Trigger trig;
|
||||
trig.line = lp;
|
||||
interpreter->postTriggers[ TriggerType(boost::get<ERM::TPostTrigger>(tcmd.cmd).name) ].push_back(trig);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
void ERMInterpreter::scanScripts()
|
||||
{
|
||||
for(std::map< LinePointer, ERM::TLine >::const_iterator it = scripts.begin(); it != scripts.end(); ++it)
|
||||
{
|
||||
|
||||
boost::apply_visitor(ScriptScanner(this, it->first), it->second);
|
||||
}
|
||||
}
|
||||
|
||||
@ -442,7 +484,7 @@ bool ERMInterpreter::isATrigger( const ERM::TLine & line )
|
||||
case SYMBOL:
|
||||
{
|
||||
//TODO: what about sym modifiers?
|
||||
//TOOD: macros
|
||||
//TOOD: macros?
|
||||
ERM::TSymbol sym = boost::get<ERM::TSymbol>(vexp.children[0]);
|
||||
return sym.sym == triggerSymbol || sym.sym == postTriggerSymbol;
|
||||
}
|
||||
@ -502,11 +544,176 @@ ERM::TLine ERMInterpreter::retrieveLine( LinePointer linePtr ) const
|
||||
return *scripts.find(linePtr);
|
||||
}
|
||||
|
||||
/////////
|
||||
//code execution
|
||||
|
||||
struct ERMExpDispatch : boost::static_visitor<>
|
||||
{
|
||||
void operator()(Ttrigger const& trig) const
|
||||
{
|
||||
//the first executed line, check if we should proceed
|
||||
}
|
||||
void operator()(Tinstruction const& trig) const
|
||||
{
|
||||
}
|
||||
void operator()(Treceiver const& trig) const
|
||||
{
|
||||
}
|
||||
void operator()(TPostTrigger const& trig) const
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct CommandExec : boost::static_visitor<>
|
||||
{
|
||||
void operator()(Tcommand const& cmd) const
|
||||
{
|
||||
boost::apply_visitor(ERMExpDispatch(), cmd.cmd);
|
||||
std::cout << "Line comment: " << cmd.comment << std::endl;
|
||||
}
|
||||
void operator()(std::string const& comment) const
|
||||
{
|
||||
//comment - do nothing
|
||||
}
|
||||
void operator()(spirit::unused_type const& nothing) const
|
||||
{
|
||||
//nothing - do nothing
|
||||
}
|
||||
};
|
||||
|
||||
struct LineExec : boost::static_visitor<>
|
||||
{
|
||||
void operator()(TVExp const& cmd) const
|
||||
{
|
||||
//printTVExp(cmd);
|
||||
}
|
||||
void operator()(TERMline const& cmd) const
|
||||
{
|
||||
boost::apply_visitor(CommandExec(), cmd);
|
||||
}
|
||||
};
|
||||
|
||||
/////////
|
||||
|
||||
void ERMInterpreter::executeLine( const LinePointer & lp )
|
||||
{
|
||||
boost::apply_visitor(LineExec(), scripts[lp]);
|
||||
}
|
||||
|
||||
void ERMInterpreter::init()
|
||||
{
|
||||
ermGlobalEnv = new ERMEnvironment();
|
||||
globalEnv = new Environment();
|
||||
//TODO: reset?
|
||||
}
|
||||
|
||||
struct ERMExecEnvironment
|
||||
{
|
||||
ERMEnvironment * ermGlobalEnv;
|
||||
Trigger * trigEnv;
|
||||
ERMExecEnvironment(ERMEnvironment * erm, Trigger * trig = NULL) : ermGlobalEnv(erm), trigEnv(trig)
|
||||
{}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct LVL2GetIexpDisemboweler : boost::static_visitor<>
|
||||
{
|
||||
T & out;
|
||||
const ERMExecEnvironment * env;
|
||||
LVL2GetIexpDisemboweler(T & ret, const ERMExecEnvironment * _env) : out(ret), env(_env) //writes value to given var
|
||||
{}
|
||||
|
||||
void processNotMacro(const TVarExpNotMacro & val) const
|
||||
{
|
||||
if(val.questionMark.is_initialized())
|
||||
throw EIexpGetterProblem("Question marks ('?') are not allowed in getter i-expressions");
|
||||
|
||||
//TODO: finish it
|
||||
}
|
||||
|
||||
void operator()(TVarExpNotMacro const& val) const
|
||||
{
|
||||
processNotMacro(val);
|
||||
}
|
||||
void operator()(TMacroUsage const& val) const
|
||||
{
|
||||
std::map<std::string, ERM::TVarExpNotMacro>::const_iterator it =
|
||||
env->ermGlobalEnv->macroBindings.find(val .macro);
|
||||
if(it == env->ermGlobalEnv->macroBindings.end())
|
||||
throw EUsageOfUndefinedMacro(val.macro);
|
||||
else
|
||||
processNotMacro(it->second);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct LVL1GetIexpDisemboweler : boost::static_visitor<>
|
||||
{
|
||||
T & out;
|
||||
const ERMExecEnvironment * env;
|
||||
LVL1GetIexpDisemboweler(T & ret, const ERMExecEnvironment * _env) : out(ret), env(_env) //writes value to given var
|
||||
{}
|
||||
void operator()(int const & constant) const
|
||||
{
|
||||
out = constant;
|
||||
}
|
||||
void operator()(TVarExp const & var) const
|
||||
{
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
T ERMInterpreter::getIexp( const ERM::TIexp & iexp, const Trigger * trig /*= NULL*/ ) const
|
||||
{
|
||||
T ret;
|
||||
boost::apply_visitor(LVL1GetIexpDisemboweler(ret, ERMExecEnvironment(ermGlobalEnv, trig)), iexp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const std::string ERMInterpreter::triggerSymbol = "trigger";
|
||||
const std::string ERMInterpreter::postTriggerSymbol = "postTrigger";
|
||||
const std::string ERMInterpreter::defunSymbol = "defun";
|
||||
|
||||
|
||||
struct TriggerIdMatchHelper : boost::static_visitor<>
|
||||
{
|
||||
int & ret;
|
||||
TriggerIdMatchHelper(int & b) : ret(b)
|
||||
{}
|
||||
|
||||
void operator()(TIexp const& iexp) const
|
||||
{
|
||||
|
||||
}
|
||||
void operator()(TArithmeticOp const& arop) const
|
||||
{
|
||||
//error?!?
|
||||
}
|
||||
};
|
||||
|
||||
bool TriggerIdentifierMatch::tryMatch( const ERM::Ttrigger & trig ) const
|
||||
{
|
||||
if(trig.identifier.is_initialized())
|
||||
{
|
||||
ERM::Tidentifier tid = trig.identifier.get();
|
||||
std::map< int, std::vector<int> >::const_iterator it = matchToIt.find(tid.size());
|
||||
if(it == matchToIt.end())
|
||||
return false;
|
||||
else
|
||||
{
|
||||
const std::vector<int> & pattern = it->second;
|
||||
for(int g=0; g<pattern.size(); ++g)
|
||||
{
|
||||
int val = -1;
|
||||
boost::apply_visitor(TriggerIdMatchHelper(val), tid[g]);
|
||||
return pattern[g] == val;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(allowNoIdetifier)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
#pragma once
|
||||
#include "../global.h"
|
||||
#include "ERMParser.h"
|
||||
#include <boost/smart_ptr.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
/*
|
||||
* ERMInterpreter.h, part of VCMI engine
|
||||
@ -27,7 +25,8 @@ namespace VERMInterpreter
|
||||
{
|
||||
return problem.c_str();
|
||||
}
|
||||
~EInterpreterProblem() throw();
|
||||
~EInterpreterProblem() throw()
|
||||
{}
|
||||
EInterpreterProblem(const std::string & problemDesc) : problem(problemDesc)
|
||||
{}
|
||||
};
|
||||
@ -46,6 +45,20 @@ namespace VERMInterpreter
|
||||
{}
|
||||
};
|
||||
|
||||
struct EUsageOfUndefinedMacro : public EInterpreterProblem
|
||||
{
|
||||
EUsageOfUndefinedMacro(const std::string & macro) :
|
||||
EInterpreterProblem(std::string("Macro ") + macro + " is undefined")
|
||||
{}
|
||||
};
|
||||
|
||||
struct EIexpGetterProblem : public EInterpreterProblem
|
||||
{
|
||||
EIexpGetterProblem(const std::string & desc) :
|
||||
EInterpreterProblem(desc)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
///main environment class, manages symbols
|
||||
class Environment
|
||||
@ -133,6 +146,13 @@ namespace VERMInterpreter
|
||||
|
||||
static const int YVAR_NUM = 100; //number of yvar locals
|
||||
int yvar[YVAR_NUM];
|
||||
TriggerLocalVars()
|
||||
{
|
||||
for(int g=0; g<EVAR_NUM; ++g)
|
||||
evar[g] = 0.0;
|
||||
for(int g=0; g<YVAR_NUM; ++g)
|
||||
yvar[g] = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct FunctionLocalVars
|
||||
@ -165,6 +185,8 @@ namespace VERMInterpreter
|
||||
|
||||
static const int NUM_STRINGS = 1000;
|
||||
std::string strings[NUM_STRINGS]; //z-vars (positive indices)
|
||||
|
||||
std::map<std::string, ERM::TVarExpNotMacro> macroBindings;
|
||||
};
|
||||
|
||||
struct TriggerType
|
||||
@ -186,6 +208,11 @@ namespace VERMInterpreter
|
||||
throw EInvalidTrigger(trig);
|
||||
}
|
||||
|
||||
bool operator<(const TriggerType & t2) const
|
||||
{
|
||||
return type < t2.type;
|
||||
}
|
||||
|
||||
TriggerType(const std::string & sym)
|
||||
{
|
||||
type = convertTrigger(sym);
|
||||
@ -204,6 +231,9 @@ namespace VERMInterpreter
|
||||
const FileInfo * file; //non-owning
|
||||
int lineNum;
|
||||
|
||||
LinePointer() : file(NULL)
|
||||
{}
|
||||
|
||||
LinePointer(const FileInfo * finfo, int line) : file(finfo), lineNum(line)
|
||||
{}
|
||||
|
||||
@ -227,7 +257,7 @@ namespace VERMInterpreter
|
||||
}
|
||||
bool isValid() const
|
||||
{
|
||||
return lineNum < file->length;
|
||||
return file && lineNum < file->length;
|
||||
}
|
||||
};
|
||||
|
||||
@ -265,22 +295,40 @@ namespace VERMInterpreter
|
||||
LinePointer line;
|
||||
TriggerLocalVars ermLocalVars;
|
||||
Stack * stack; //where we are stuck at execution
|
||||
Trigger() : stack(NULL)
|
||||
{}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
struct TriggerIdentifierMatch
|
||||
{
|
||||
bool allowNoIdetifier;
|
||||
std::map< int, std::vector<int> > matchToIt; //match subidentifiers to these numbers
|
||||
|
||||
static const int MAX_SUBIDENTIFIERS = 16;
|
||||
bool tryMatch(const ERM::Ttrigger & trig) const;
|
||||
};
|
||||
|
||||
class ERMInterpreter
|
||||
{
|
||||
friend class ScriptScanner;
|
||||
|
||||
std::vector<VERMInterpreter::FileInfo*> files;
|
||||
std::vector< boost::shared_ptr<VERMInterpreter::FileInfo> > fileInfos;
|
||||
std::vector< VERMInterpreter::FileInfo* > fileInfos;
|
||||
std::map<VERMInterpreter::LinePointer, ERM::TLine> scripts;
|
||||
std::map<VERMInterpreter::LexicalPtr, VERMInterpreter::Environment> lexicalEnvs;
|
||||
ERM::TLine retrieveLine(VERMInterpreter::LinePointer linePtr) const;
|
||||
|
||||
VERMInterpreter::Environment * globalEnv;
|
||||
std::map<VERMInterpreter::TriggerType, std::vector<VERMInterpreter::Trigger> > triggers;
|
||||
VERMInterpreter::ERMEnvironment * ermGlobalEnv;
|
||||
std::map<VERMInterpreter::TriggerType, std::vector<VERMInterpreter::Trigger> > triggers, postTriggers;
|
||||
|
||||
static const std::string triggerSymbol, postTriggerSymbol;
|
||||
|
||||
template<typename T> void setIexp(const ERM::TIexp & iexp, const T & val, VERMInterpreter::Trigger * trig = NULL);
|
||||
template<typename T> T getIexp(const ERM::TIexp & iexp, const VERMInterpreter::Trigger * trig = NULL) const;
|
||||
|
||||
static const std::string triggerSymbol, postTriggerSymbol, defunSymbol;
|
||||
|
||||
void executeLine(const VERMInterpreter::LinePointer & lp);
|
||||
void executeTrigger(VERMInterpreter::Trigger & trig);
|
||||
@ -288,6 +336,7 @@ class ERMInterpreter
|
||||
static bool isATrigger(const ERM::TLine & line);
|
||||
static ERM::EVOtions getExpType(const ERM::TVOption & opt);
|
||||
public:
|
||||
void init(); //sets up environment etc.
|
||||
void scanForScripts();
|
||||
|
||||
enum EPrintMode{ALL, ERM_ONLY, VERM_ONLY};
|
||||
|
@ -52,9 +52,10 @@ DLL_EXPORT void initDLL(CConsoleHandler *Console, std::ostream *Logfile)
|
||||
} HANDLE_EXCEPTION;
|
||||
|
||||
|
||||
// ERMInterpreter ei;
|
||||
ERMInterpreter ei;
|
||||
// ei.scanForScripts();
|
||||
// ei.printScripts();
|
||||
// //ei.printScripts();
|
||||
// ei.scanScripts();
|
||||
}
|
||||
|
||||
DLL_EXPORT void loadToIt(std::string &dest, const std::string &src, int &iter, int mode)
|
||||
|
Loading…
Reference in New Issue
Block a user