1
0
mirror of https://github.com/aportelli/LatAnalyze.git synced 2025-04-10 19:20:44 +01:00

Math interpreter: significant improvement of runtime context handling

This commit is contained in:
Antonin Portelli 2014-09-26 18:41:30 +01:00
parent 0fdd76b19d
commit bbeaec9ed3
6 changed files with 288 additions and 100 deletions

View File

@ -33,21 +33,21 @@ int main(int argc, char* argv[])
} }
cout << "-- Program:" << endl << interpreter << endl; cout << "-- Program:" << endl << interpreter << endl;
cout << "-- Variable table:" << endl; cout << "-- Variable table:" << endl;
for (auto &v: context.vTable) for (auto &v: context.getVariableTable())
{ {
cout << "'" << v.first << "': " << v.second << endl; cout << "'" << v.first << "': " << v.second << endl;
} }
cout << endl; cout << endl;
cout << "-- Function table:" << endl; cout << "-- Function table:" << endl;
for (auto &f: context.fTable) for (auto &f: context.getFunctionTable())
{ {
cout << "'" << f.first << "': " << f.second << endl; cout << "'" << f.first << "': " << f.second << endl;
} }
cout << endl; cout << endl;
interpreter(context); interpreter(context);
if (!context.dStack.empty()) if (!context.stack().empty())
{ {
cout << "-- Result: " << context.dStack.top() << endl; cout << "-- Result: " << context.stack().top() << endl;
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;

View File

@ -53,12 +53,12 @@ void CompiledDoubleFunction::compile(void) const
{ {
if (!*isCompiled_) if (!*isCompiled_)
{ {
interpreter_->compile(*(context_));
varAddress_->clear(); varAddress_->clear();
for (Index i = 0; i < getNArg(); ++i) for (Index i = 0; i < getNArg(); ++i)
{ {
varAddress_->push_back(context_->vTable.at("x_" + strFrom(i))); varAddress_->push_back(context_->addVariable("x_" + strFrom(i)));
} }
interpreter_->compile(*(context_));
*isCompiled_ = true; *isCompiled_ = true;
} }
} }
@ -71,13 +71,13 @@ double CompiledDoubleFunction::operator()(const double *arg) const
compile(); compile();
for (unsigned int i = 0; i < getNArg(); ++i) for (unsigned int i = 0; i < getNArg(); ++i)
{ {
context_->vMem[(*varAddress_)[i]] = arg[i]; context_->setVariable((*varAddress_)[i], arg[i]);
} }
(*interpreter_)(*context_); (*interpreter_)(*context_);
if (!context_->dStack.empty()) if (!context_->stack().empty())
{ {
result = context_->dStack.top(); result = context_->stack().top();
context_->dStack.pop(); context_->stack().pop();
} }
else else
{ {

View File

@ -56,17 +56,17 @@ void CompiledDoubleModel::compile(void) const
{ {
if (!*isCompiled_) if (!*isCompiled_)
{ {
interpreter_->compile(*(context_));
varAddress_->clear(); varAddress_->clear();
parAddress_->clear(); parAddress_->clear();
for (Index i = 0; i < getNArg(); ++i) for (Index i = 0; i < getNArg(); ++i)
{ {
varAddress_->push_back(context_->vTable.at("x_" + strFrom(i))); varAddress_->push_back(context_->addVariable("x_" + strFrom(i)));
} }
for (Index j = 0; j < getNPar(); ++j) for (Index j = 0; j < getNPar(); ++j)
{ {
parAddress_->push_back(context_->vTable.at("p_" + strFrom(j))); parAddress_->push_back(context_->addVariable("p_" + strFrom(j)));
} }
interpreter_->compile(*(context_));
*isCompiled_ = true; *isCompiled_ = true;
} }
} }
@ -80,17 +80,17 @@ double CompiledDoubleModel::operator()(const double *arg,
compile(); compile();
for (unsigned int i = 0; i < getNArg(); ++i) for (unsigned int i = 0; i < getNArg(); ++i)
{ {
context_->vMem[(*varAddress_)[i]] = arg[i]; context_->setVariable((*varAddress_)[i], arg[i]);
} }
for (unsigned int j = 0; j < getNPar(); ++j) for (unsigned int j = 0; j < getNPar(); ++j)
{ {
context_->vMem[(*parAddress_)[j]] = par[j]; context_->setVariable((*parAddress_)[j], par[j]);
} }
(*interpreter_)(*context_); (*interpreter_)(*context_);
if (!context_->dStack.empty()) if (!context_->stack().empty())
{ {
result = context_->dStack.top(); result = context_->stack().top();
context_->dStack.pop(); context_->stack().pop();
} }
else else
{ {

View File

@ -29,7 +29,6 @@ BEGIN_NAMESPACE
/****************************************************************************** /******************************************************************************
* compiled double model class * * compiled double model class *
******************************************************************************/ ******************************************************************************/
class CompiledDoubleModel: public DoubleModel class CompiledDoubleModel: public DoubleModel
{ {
public: public:

View File

@ -24,6 +24,193 @@
using namespace std; using namespace std;
using namespace Latan; using namespace Latan;
/******************************************************************************
* RunContext implementation *
******************************************************************************/
// access //////////////////////////////////////////////////////////////////////
unsigned int RunContext::addFunction(const string &name, DoubleFunction *init)
{
try
{
setFunction(name, init);
return getFunctionAddress(name);
}
catch (Exceptions::Definition)
{
unsigned int address = fTable_.size();
fMem_.push_back(init);
fTable_[name] = address;
return address;
}
}
unsigned int RunContext::addVariable(const string &name, double init)
{
try
{
setVariable(name, init);
return getVariableAddress(name);
}
catch (Exceptions::Definition)
{
unsigned int address = vTable_.size();
vMem_.push_back(init);
vTable_[name] = address;
return address;
}
}
DoubleFunction * RunContext::getFunction(const string &name) const
{
return getFunction(getFunctionAddress(name));
}
DoubleFunction * RunContext::getFunction(const unsigned int address) const
{
if (address >= fTable_.size())
{
LATAN_ERROR(Range, "function address " + strFrom(address)
+ " out of range");
return nullptr;
}
else
{
return fMem_[address];
}
}
unsigned int RunContext::getFunctionAddress(const string &name) const
{
try
{
return fTable_.at(name);
}
catch (out_of_range)
{
LATAN_ERROR(Definition, "undefined function '" + name + "'");
}
}
const RunContext::AddressTable & RunContext::getFunctionTable(void) const
{
return fTable_;
}
unsigned int RunContext::getInsIndex(void) const
{
return insIndex_;
}
double RunContext::getVariable(const string &name) const
{
return getVariable(getVariableAddress(name));
}
double RunContext::getVariable(const unsigned int address) const
{
if (address >= vTable_.size())
{
LATAN_ERROR(Range, "variable address " + strFrom(address)
+ " out of range");
return 0.;
}
else
{
return vMem_[address];
}
}
const RunContext::AddressTable & RunContext::getVariableTable(void) const
{
return vTable_;
}
unsigned int RunContext::getVariableAddress(const string &name) const
{
try
{
return vTable_.at(name);
}
catch (out_of_range)
{
LATAN_ERROR(Definition, "undefined variable '" + name + "'");
}
}
void RunContext::incrementInsIndex(const unsigned int inc)
{
setInsIndex(getInsIndex() + inc);
}
void RunContext::setFunction(const string &name, DoubleFunction *f)
{
setFunction(getFunctionAddress(name), f);
}
void RunContext::setFunction(const unsigned int address, DoubleFunction *f)
{
if (address >= fTable_.size())
{
LATAN_ERROR(Range, "function address " + strFrom(address)
+ " out of range");
}
else
{
fMem_[address] = f;
}
}
void RunContext::setInsIndex(const unsigned index)
{
insIndex_ = index;
}
void RunContext::setVariable(const string &name, const double value)
{
setVariable(getVariableAddress(name), value);
}
void RunContext::setVariable(const unsigned int address, const double value)
{
if (address >= vTable_.size())
{
LATAN_ERROR(Range, "variable address " + strFrom(address)
+ " out of range");
}
else
{
vMem_[address] = value;
}
}
stack<double> & RunContext::stack(void)
{
return dStack_;
}
// reset ///////////////////////////////////////////////////////////////////////
void RunContext::reset(void)
{
insIndex_ = 0;
while (!dStack_.empty())
{
dStack_.pop();
}
vMem_.clear();
fMem_.clear();
vTable_.clear();
fTable_.clear();
}
/****************************************************************************** /******************************************************************************
* Instruction set * * Instruction set *
******************************************************************************/ ******************************************************************************/
@ -58,20 +245,13 @@ void Push::operator()(RunContext &context) const
{ {
if (type_ == ArgType::Constant) if (type_ == ArgType::Constant)
{ {
context.dStack.push(val_); context.stack().push(val_);
} }
else else
{ {
try context.stack().push(context.getVariable(address_));
{
context.dStack.push(context.vMem[address_]);
}
catch (out_of_range)
{
LATAN_ERROR(Range, "unknown variable '" + name_ + "'");
}
} }
context.insIndex++; context.incrementInsIndex();
} }
// Push print ////////////////////////////////////////////////////////////////// // Push print //////////////////////////////////////////////////////////////////
@ -99,10 +279,10 @@ void Pop::operator()(RunContext &context) const
{ {
if (!name_.empty()) if (!name_.empty())
{ {
context.vMem[address_] = context.dStack.top(); context.setVariable(address_, context.stack().top());
} }
context.dStack.pop(); context.stack().pop();
context.insIndex++; context.incrementInsIndex();
} }
// Pop print /////////////////////////////////////////////////////////////////// // Pop print ///////////////////////////////////////////////////////////////////
@ -122,9 +302,9 @@ void Store::operator()(RunContext &context) const
{ {
if (!name_.empty()) if (!name_.empty())
{ {
context.vMem[address_] = context.dStack.top(); context.setVariable(address_, context.stack().top());
} }
context.insIndex++; context.incrementInsIndex();
} }
// Store print ///////////////////////////////////////////////////////////////// // Store print /////////////////////////////////////////////////////////////////
@ -142,15 +322,8 @@ Call::Call(const unsigned int address, const string &name)
// Call execution ////////////////////////////////////////////////////////////// // Call execution //////////////////////////////////////////////////////////////
void Call::operator()(RunContext &context) const void Call::operator()(RunContext &context) const
{ {
try context.stack().push((*context.getFunction(address_))(context.stack()));
{ context.incrementInsIndex();
context.dStack.push((*context.fMem[address_])(context.dStack));
}
catch (out_of_range)
{
LATAN_ERROR(Range, "unknown function '" + name_ + "'");
}
context.insIndex++;
} }
// Call print ////////////////////////////////////////////////////////////////// // Call print //////////////////////////////////////////////////////////////////
@ -166,11 +339,11 @@ void name::operator()(RunContext &context) const\
double x[nArg];\ double x[nArg];\
for (int i = 0; i < nArg; ++i)\ for (int i = 0; i < nArg; ++i)\
{\ {\
x[nArg-1-i] = context.dStack.top();\ x[nArg-1-i] = context.stack().top();\
context.dStack.pop();\ context.stack().pop();\
}\ }\
context.dStack.push(exp);\ context.stack().push(exp);\
context.insIndex++;\ context.incrementInsIndex();\
}\ }\
void name::print(ostream &out) const\ void name::print(ostream &out) const\
{\ {\
@ -283,26 +456,19 @@ catch (out_of_range)\
}\ }\
// VarNode compile ///////////////////////////////////////////////////////////// // VarNode compile /////////////////////////////////////////////////////////////
void VarNode::compile(Program &program, AddressTable &vTable, void VarNode::compile(Program &program, RunContext &context) const
AddressTable &fTable __unused) const
{ {
unsigned int address; PUSH_INS(program, Push, context.getVariableAddress(getName()), getName());
GET_ADDRESS(address, vTable, getName());
PUSH_INS(program, Push, address, getName());
} }
// CstNode compile ///////////////////////////////////////////////////////////// // CstNode compile /////////////////////////////////////////////////////////////
void CstNode::compile(Program &program, AddressTable &nextVAddress __unused, void CstNode::compile(Program &program, RunContext &context __unused) const
AddressTable &nextFAddress __unused) const
{ {
PUSH_INS(program, Push, strTo<double>(getName())); PUSH_INS(program, Push, strTo<double>(getName()));
} }
// SemicolonNode compile /////////////////////////////////////////////////////// // SemicolonNode compile ///////////////////////////////////////////////////////
void SemicolonNode::compile(Program &program, AddressTable &vTable, void SemicolonNode::compile(Program &program, RunContext &context) const
AddressTable &fTable) const
{ {
auto &n = *this; auto &n = *this;
@ -314,14 +480,13 @@ void SemicolonNode::compile(Program &program, AddressTable &vTable,
if (isAssign||isSemiColumn||isKeyword) if (isAssign||isSemiColumn||isKeyword)
{ {
n[i].compile(program, vTable, fTable); n[i].compile(program, context);
} }
} }
} }
// AssignNode compile ////////////////////////////////////////////////////////// // AssignNode compile //////////////////////////////////////////////////////////
void AssignNode::compile(Program &program, AddressTable &vTable, void AssignNode::compile(Program &program, RunContext &context) const
AddressTable &fTable) const
{ {
auto &n = *this; auto &n = *this;
@ -330,8 +495,8 @@ void AssignNode::compile(Program &program, AddressTable &vTable,
bool hasSemicolonParent = isDerivedFrom<SemicolonNode>(getParent()); bool hasSemicolonParent = isDerivedFrom<SemicolonNode>(getParent());
unsigned int address; unsigned int address;
n[1].compile(program, vTable, fTable); n[1].compile(program, context);
GET_ADDRESS(address, vTable, n[0].getName()); address = context.addVariable(n[0].getName());
if (hasSemicolonParent) if (hasSemicolonParent)
{ {
PUSH_INS(program, Pop, address, n[0].getName()); PUSH_INS(program, Pop, address, n[0].getName());
@ -352,14 +517,13 @@ void AssignNode::compile(Program &program, AddressTable &vTable,
#define ELIFNODE(name, nArg) else IFNODE(name, nArg) #define ELIFNODE(name, nArg) else IFNODE(name, nArg)
#define ELSE else #define ELSE else
void MathOpNode::compile(Program &program, AddressTable &vTable, void MathOpNode::compile(Program &program, RunContext &context) const
AddressTable &fTable) const
{ {
auto &n = *this; auto &n = *this;
for (Index i = 0; i < n.getNArg(); ++i) for (Index i = 0; i < n.getNArg(); ++i)
{ {
n[i].compile(program, vTable, fTable); n[i].compile(program, context);
} }
IFNODE("-", 1) PUSH_INS(program, Neg,); IFNODE("-", 1) PUSH_INS(program, Neg,);
ELIFNODE("+", 2) PUSH_INS(program, Add,); ELIFNODE("+", 2) PUSH_INS(program, Add,);
@ -371,27 +535,23 @@ void MathOpNode::compile(Program &program, AddressTable &vTable,
} }
// FuncNode compile //////////////////////////////////////////////////////////// // FuncNode compile ////////////////////////////////////////////////////////////
void FuncNode::compile(Program &program, AddressTable &vTable, void FuncNode::compile(Program &program, RunContext &context) const
AddressTable &fTable) const
{ {
auto &n = *this; auto &n = *this;
unsigned int address;
for (Index i = 0; i < n.getNArg(); ++i) for (Index i = 0; i < n.getNArg(); ++i)
{ {
n[i].compile(program, vTable, fTable); n[i].compile(program, context);
} }
GET_ADDRESS(address, fTable, getName()); PUSH_INS(program, Call, context.addFunction(getName()), getName());
PUSH_INS(program, Call, address, getName());
} }
// ReturnNode compile //////////////////////////////////////////////////////////// // ReturnNode compile ////////////////////////////////////////////////////////////
void ReturnNode::compile(Program &program, AddressTable &vTable, void ReturnNode::compile(Program &program, RunContext &context) const
AddressTable &fTable) const
{ {
auto &n = *this; auto &n = *this;
n[0].compile(program, vTable, fTable); n[0].compile(program, context);
program.push_back(nullptr); program.push_back(nullptr);
} }
@ -473,9 +633,9 @@ void MathInterpreter::parse(void)
#define ADD_FUNC(context, func)\ #define ADD_FUNC(context, func)\
try\ try\
{\ {\
(context).fMem[(context).fTable.at(#func)] = &STDMATH_NAMESPACE::func;\ (context).setFunction(#func, &STDMATH_NAMESPACE::func);\
}\ }\
catch (out_of_range)\ catch (Exceptions::Definition)\
{} {}
#define ADD_STDMATH_FUNCS(context)\ #define ADD_STDMATH_FUNCS(context)\
@ -534,9 +694,7 @@ void MathInterpreter::compile(RunContext &context)
{ {
if (root_) if (root_)
{ {
context.vTable.clear(); root_->compile(program_, context);
context.fTable.clear();
root_->compile(program_, context.vTable, context.fTable);
for (unsigned int i = 0; i < program_.size(); ++i) for (unsigned int i = 0; i < program_.size(); ++i)
{ {
if (!program_[i]) if (!program_[i])
@ -547,8 +705,6 @@ void MathInterpreter::compile(RunContext &context)
break; break;
} }
} }
context.vMem.resize(context.vTable.size());
context.fMem.resize(context.fTable.size());
ADD_STDMATH_FUNCS(context); ADD_STDMATH_FUNCS(context);
} }
if (!root_||!gotReturn) if (!root_||!gotReturn)
@ -573,10 +729,10 @@ void MathInterpreter::operator()(RunContext &context)
void MathInterpreter::execute(RunContext &context) const void MathInterpreter::execute(RunContext &context) const
{ {
context.insIndex = 0; context.setInsIndex(0);
while (context.insIndex != program_.size()) while (context.getInsIndex() != program_.size())
{ {
(*(program_[context.insIndex]))(context); (*(program_[context.getInsIndex()]))(context);
} }
} }

View File

@ -34,19 +34,55 @@
BEGIN_NAMESPACE BEGIN_NAMESPACE
/****************************************************************************** /******************************************************************************
* Instruction classes * * Class for runtime context *
******************************************************************************/ ******************************************************************************/
typedef std::map<std::string, unsigned int> AddressTable; class RunContext
struct RunContext
{ {
unsigned int insIndex; public:
std::stack<double> dStack; typedef std::map<std::string, unsigned int> AddressTable;
std::vector<double> vMem; public:
std::vector<DoubleFunction *> fMem; // constructor
AddressTable vTable, fTable; RunContext(void) = default;
// destructor
~RunContext(void) = default;
// access
unsigned int addFunction(const std::string &name,
DoubleFunction *init = nullptr);
unsigned int addVariable(const std::string &name,
const double init = 0.);
DoubleFunction * getFunction(const std::string &name) const;
DoubleFunction * getFunction(const unsigned int address) const;
unsigned int getFunctionAddress(const std::string &name) const;
const AddressTable & getFunctionTable(void) const;
unsigned int getInsIndex(void) const;
double getVariable(const std::string &name) const;
double getVariable(const unsigned int address) const;
unsigned int getVariableAddress(const std::string &name) const;
const AddressTable & getVariableTable(void) const;
void incrementInsIndex(const unsigned int inc = 1);
void setFunction(const std::string &name,
DoubleFunction *f);
void setFunction(const unsigned int address,
DoubleFunction *f);
void setInsIndex(const unsigned index);
void setVariable(const std::string &name,
const double value);
void setVariable(const unsigned int address,
const double value);
std::stack<double> & stack(void);
// reset
void reset(void);
private:
unsigned int insIndex_;
std::stack<double> dStack_;
std::vector<double> vMem_;
std::vector<DoubleFunction *> fMem_;
AddressTable vTable_, fTable_;
}; };
/******************************************************************************
* Instruction classes *
******************************************************************************/
// Abstract base // Abstract base
class Instruction class Instruction
{ {
@ -171,8 +207,7 @@ public:
// operator // operator
const ExprNode &operator[](const Index i) const; const ExprNode &operator[](const Index i) const;
// compile // compile
virtual void compile(Program &program, AddressTable &vTable, virtual void compile(Program &program, RunContext &context) const = 0;
AddressTable &fTable) const = 0;
private: private:
std::string name_; std::string name_;
std::vector<std::unique_ptr<ExprNode>> arg_; std::vector<std::unique_ptr<ExprNode>> arg_;
@ -186,8 +221,7 @@ class name: public base\
{\ {\
public:\ public:\
using base::base;\ using base::base;\
virtual void compile(Program &program, AddressTable &vTable,\ virtual void compile(Program &program, RunContext &context) const;\
AddressTable &fTable) const;\
} }
DECL_NODE(ExprNode, VarNode); DECL_NODE(ExprNode, VarNode);
@ -201,8 +235,7 @@ class KeywordNode: public ExprNode
{ {
public: public:
using ExprNode::ExprNode; using ExprNode::ExprNode;
virtual void compile(Program &program, AddressTable &vTable, virtual void compile(Program &program, RunContext &context) const = 0;
AddressTable &fTable) const = 0;
}; };
DECL_NODE(KeywordNode, ReturnNode); DECL_NODE(KeywordNode, ReturnNode);