1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-24 08:32:34 +02:00

* partial support for string processing

* post-triggers should work
* minor improvements
This commit is contained in:
mateuszb 2011-05-17 19:24:18 +00:00
parent ef66982bbd
commit 53ce30f083
2 changed files with 144 additions and 56 deletions

View File

@ -21,6 +21,8 @@ namespace spirit = boost::spirit;
using namespace VERMInterpreter;
using namespace boost::assign;
typedef int TUnusedType;
namespace ERMPrinter
{
//console printer
@ -474,6 +476,8 @@ void ERMInterpreter::executeTrigger( VERMInterpreter::Trigger & trig, int funNum
curFunc->getParam(g) = g-1 < funParams.size() ? funParams[g-1] : 0;
}
}
else
curFunc = getFuncVars(0);
//skip the first line
LinePointer lp = trig.line;
@ -690,7 +694,7 @@ struct VRPerformer : StandardReceiverVisitor<IexpValStr>
break;
}
}
void operator()(TNormalBodyOption const& trig) const
void operator()(TNormalBodyOption const& trig) const OVERRIDE
{
switch(trig.optionCode)
{
@ -760,6 +764,32 @@ void VR_SPerformer::operator()(TStringConstant const& cmp) const
owner.identifier.setTo(cmp.str);
}
struct MAPerformer : StandardReceiverVisitor<TUnusedType>
{
MAPerformer(ERMInterpreter * _interpr) : StandardReceiverVisitor(_interpr, 0)
{}
using StandardReceiverVisitor<TUnusedType>::operator();
void operator()(TNormalBodyOption const& trig) const OVERRIDE
{
switch(trig.optionCode)
{
case 'A': //sgc monster attack
break;
case 'B': //spell?
break;
case 'P': //hit points
{
//TODO
}
break;
default:
break;
}
}
};
struct ConditionDisemboweler;
struct OBPerformer;
@ -858,6 +888,52 @@ struct ERMExpDispatch : boost::static_visitor<>
ERMExpDispatch(ERMInterpreter * _owner) : owner(_owner)
{}
struct HLP
{
ERMInterpreter * ei;
HLP(ERMInterpreter * interp) : ei(interp)
{}
int3 getPosFromIdentifier(ERM::Tidentifier tid, bool allowDummyFourth)
{
switch(tid.size())
{
case 1:
{
int num = ei->getIexp(tid[0]).getInt();
return int3(ei->ermGlobalEnv->getStandardVar(num),
ei->ermGlobalEnv->getStandardVar(num+1),
ei->ermGlobalEnv->getStandardVar(num+2));
}
break;
case 3:
case 4:
if(tid.size() == 4 && !allowDummyFourth)
throw EScriptExecError("4 items in identifier are not allowed for this receiver!");
return int3(ei->getIexp(tid[0]).getInt(),
ei->getIexp(tid[1]).getInt(),
ei->getIexp(tid[2]).getInt());
break;
default:
throw EScriptExecError("This receiver takes 1 or 3 items in identifier!");
break;
}
}
template <typename Visitor>
void performBody(const boost::optional<ERM::Tbody> & body, const Visitor& visitor)
{
if(body.is_initialized())
{
ERM::Tbody bo = body.get();
for(int g=0; g<bo.size(); ++g)
{
boost::apply_visitor(visitor, bo[g]);
}
}
}
};
void operator()(Ttrigger const& trig) const
{
throw EInterpreterError("Triggers cannot be executed!");
@ -867,39 +943,7 @@ struct ERMExpDispatch : boost::static_visitor<>
}
void operator()(Treceiver const& trig) const
{
struct HLP
{
ERMInterpreter * ei;
HLP(ERMInterpreter * interp) : ei(interp)
{}
int3 getPosFromIdentifier(ERM::Tidentifier tid, bool allowDummyFourth)
{
switch(tid.size())
{
case 1:
{
int num = ei->getIexp(tid[0]).getInt();
return int3(ei->ermGlobalEnv->getStandardVar(num),
ei->ermGlobalEnv->getStandardVar(num+1),
ei->ermGlobalEnv->getStandardVar(num+2));
}
break;
case 3:
case 4:
if(tid.size() == 4 && !allowDummyFourth)
throw EScriptExecError("4 items in identifirer are not allowed for this receiver!");
return int3(ei->getIexp(tid[0]).getInt(),
ei->getIexp(tid[1]).getInt(),
ei->getIexp(tid[2]).getInt());
break;
default:
throw EScriptExecError("This receiver takes 1 or 3 items in identifier!");
break;
}
}
};
HLP helper(owner);
if(trig.name == "VR")
{
//check condition
@ -918,14 +962,7 @@ struct ERMExpDispatch : boost::static_visitor<>
IexpValStr ievs = owner->getIexp(ident[0]);
//see body
if(trig.body.is_initialized())
{
ERM::Tbody bo = trig.body.get();
for(int g=0; g<bo.size(); ++g)
{
boost::apply_visitor(VRPerformer(owner, ievs), bo[g]);
}
}
helper.performBody(trig.body, VRPerformer(owner, ievs));
}
else
throw EScriptExecError("VR receiver must be used with exactly one identifier item!");
@ -962,6 +999,14 @@ struct ERMExpDispatch : boost::static_visitor<>
}
}
}
else if(trig.name == "MA")
{
if(trig.identifier.is_initialized())
{
throw EScriptExecError("MA receiver doesn't take the identifier!");
}
helper.performBody(trig.body, MAPerformer(owner));
}
else if(trig.name == "MO")
{
int3 objPos;
@ -981,17 +1026,7 @@ struct ERMExpDispatch : boost::static_visitor<>
ERM::Tidentifier tid = trig.identifier.get();
objPos = HLP(owner).getPosFromIdentifier(tid, false);
//execute body
if(trig.body.is_initialized())
{
ERM::Tbody bo = trig.body.get();
for(int g=0; g<bo.size(); ++g)
{
boost::apply_visitor(OBPerformer(owner, objPos), bo[g]);
}
}
else
throw EScriptExecError("OB receiver must have body!");
helper.performBody(trig.body, OBPerformer(owner, objPos));
}
else
throw EScriptExecError("OB receiver must have an identifier!");
@ -1374,7 +1409,7 @@ void ERMInterpreter::executeTriggerType(const char *trigger)
executeTriggerType(VERMInterpreter::TriggerType(trigger), true, TIDPattern());
}
ERM::Ttrigger ERMInterpreter::retrieveTrigger( ERM::TLine line )
ERM::TTriggerBase & ERMInterpreter::retrieveTrigger( ERM::TLine line )
{
if(line.which() == 1)
{
@ -1386,6 +1421,10 @@ ERM::Ttrigger ERMInterpreter::retrieveTrigger( ERM::TLine line )
{
return boost::get<ERM::Ttrigger>(tcm.cmd);
}
else if(tcm.cmd.which() == 3)
{
return boost::get<ERM::TPostTrigger>(tcm.cmd);
}
throw ELineProblem("Given line is not a trigger!");
}
throw ELineProblem("Given line is not a command!");
@ -1534,6 +1573,54 @@ void ERMInterpreter::setCurrentlyVisitedObj( int3 pos )
ermGlobalEnv->getStandardVar(1000) = pos.z;
}
struct StringProcessHLP
{
int extractNumber(const std::string & token)
{
return atoi(token.substr(1).c_str());
}
template <typename T>
void replaceToken(std::string ret, int tokenBegin, int tokenEnd, T val)
{
ret.replace(tokenBegin, tokenEnd, boost::lexical_cast<std::string>(val));
}
};
std::string ERMInterpreter::processERMString( std::string ermstring )
{
StringProcessHLP hlp;
std::string ret = ermstring;
int curPos = 0;
while((curPos = ret.find('%', curPos)) != std::string::npos)
{
curPos++;
int tokenEnd = ret.find(' ', curPos);
std::string token = ret.substr(curPos, tokenEnd - curPos);
if(token.size() == 0)
{
throw EScriptExecError("Empty token not allowed!");
}
switch(token[0])
{
case '%':
ret.erase(curPos);
break;
case 'F':
hlp.replaceToken(ret, curPos, tokenEnd, ermGlobalEnv->getFlag(hlp.extractNumber(token)));
break;
case 'V':
hlp.replaceToken(ret, curPos, tokenEnd, ermGlobalEnv->getStandardVar(hlp.extractNumber(token)));
break;
default:
throw EScriptExecError("Unrecognized token in string");
break;
}
}
return ret;
}
const std::string ERMInterpreter::triggerSymbol = "trigger";
const std::string ERMInterpreter::postTriggerSymbol = "postTrigger";
const std::string ERMInterpreter::defunSymbol = "defun";
@ -1573,7 +1660,7 @@ bool TriggerIdentifierMatch::tryMatch( Trigger * interptrig ) const
{
bool ret = true;
const ERM::Ttrigger & trig = ERMInterpreter::retrieveTrigger(ermEnv->retrieveLine(interptrig->line));
const ERM::TTriggerBase & trig = ERMInterpreter::retrieveTrigger(ermEnv->retrieveLine(interptrig->line));
if(trig.identifier.is_initialized())
{

View File

@ -486,7 +486,7 @@ class ERMInterpreter
std::map<VERMInterpreter::LinePointer, ERM::TLine> scripts;
std::map<VERMInterpreter::LexicalPtr, VERMInterpreter::Environment> lexicalEnvs;
ERM::TLine retrieveLine(VERMInterpreter::LinePointer linePtr) const;
static ERM::Ttrigger retrieveTrigger(ERM::TLine line);
static ERM::TTriggerBase & retrieveTrigger(ERM::TLine line);
VERMInterpreter::Environment * globalEnv;
VERMInterpreter::ERMEnvironment * ermGlobalEnv;
@ -512,6 +512,7 @@ class ERMInterpreter
static ERM::EVOtions getExpType(const ERM::TVOption & opt);
IexpValStr getVar(std::string toFollow, boost::optional<int> initVal) const;
std::string processERMString(std::string ermstring);
public:
typedef std::map< int, std::vector<int> > TIDPattern;