diff --git a/examples/exMathInterpreter.cpp b/examples/exMathInterpreter.cpp index 0374c1d..c74797d 100644 --- a/examples/exMathInterpreter.cpp +++ b/examples/exMathInterpreter.cpp @@ -21,7 +21,7 @@ int main(int argc, char* argv[]) RunContext context; cout << "-- Source code:" << endl << source << endl << endl; - interpreter.compile(); + interpreter.compile(context); cout << "-- Abstract Syntax Tree:" << endl; if (interpreter.getAST()) { @@ -32,7 +32,18 @@ int main(int argc, char* argv[]) cout << "" << endl << endl; } cout << "-- Program:" << endl << interpreter << endl; - StdMath::addStdMathFunc(context.fTable); + cout << "-- Variable table:" << endl; + for (auto &v: context.vTable) + { + cout << "'" << v.first << "': " << v.second << endl; + } + cout << endl; + cout << "-- Function table:" << endl; + for (auto &f: context.fTable) + { + cout << "'" << f.first << "': " << f.second << endl; + } + cout << endl; interpreter(context); if (!context.dStack.empty()) { diff --git a/lib/CompiledFunction.cpp b/lib/CompiledFunction.cpp index bdf3776..b8181b8 100644 --- a/lib/CompiledFunction.cpp +++ b/lib/CompiledFunction.cpp @@ -44,7 +44,23 @@ void CompiledDoubleFunction::setCode(const string &code) { interpreter_.reset(new MathInterpreter(code)); context_.reset(new RunContext); - StdMath::addStdMathFunc(context_->fTable); + varAddress_.reset(new std::vector); + isCompiled_.reset(new bool(false)); +} + +// compile ///////////////////////////////////////////////////////////////////// +void CompiledDoubleFunction::compile(void) const +{ + if (!*isCompiled_) + { + interpreter_->compile(*(context_)); + varAddress_->clear(); + for (Index i = 0; i < getNArg(); ++i) + { + varAddress_->push_back(context_->vTable.at("x_" + strFrom(i))); + } + *isCompiled_ = true; + } } // function call /////////////////////////////////////////////////////////////// @@ -52,9 +68,10 @@ double CompiledDoubleFunction::operator()(const double *arg) const { double result; - for (Index i = 0; i < getNArg(); ++i) + compile(); + for (unsigned int i = 0; i < getNArg(); ++i) { - context_->vTable["x_" + strFrom(i)] = arg[i]; + context_->vMem[(*varAddress_)[i]] = arg[i]; } (*interpreter_)(*context_); if (!context_->dStack.empty()) @@ -74,7 +91,7 @@ double CompiledDoubleFunction::operator()(const double *arg) const // IO ////////////////////////////////////////////////////////////////////////// ostream & Latan::operator<<(ostream &out, CompiledDoubleFunction &f) { - f.interpreter_->compile(); + f.compile(); out << *(f.interpreter_); return out; diff --git a/lib/CompiledFunction.hpp b/lib/CompiledFunction.hpp index 9a1b532..4bbdb2f 100644 --- a/lib/CompiledFunction.hpp +++ b/lib/CompiledFunction.hpp @@ -46,8 +46,13 @@ public: friend std::ostream & operator<<(std::ostream &out, CompiledDoubleFunction &f); private: - std::shared_ptr interpreter_; - std::shared_ptr context_; + // compile + void compile(void) const; +private: + std::shared_ptr interpreter_; + std::shared_ptr context_; + std::shared_ptr> varAddress_; + std::shared_ptr isCompiled_; }; std::ostream & operator<<(std::ostream &out, CompiledDoubleFunction &f); diff --git a/lib/CompiledModel.cpp b/lib/CompiledModel.cpp index d3e104a..d4052b8 100644 --- a/lib/CompiledModel.cpp +++ b/lib/CompiledModel.cpp @@ -46,7 +46,29 @@ void CompiledDoubleModel::setCode(const std::string &code) { interpreter_.reset(new MathInterpreter(code)); context_.reset(new RunContext); - StdMath::addStdMathFunc(context_->fTable); + varAddress_.reset(new std::vector); + parAddress_.reset(new std::vector); + isCompiled_.reset(new bool(false)); +} + +// compile ///////////////////////////////////////////////////////////////////// +void CompiledDoubleModel::compile(void) const +{ + if (!*isCompiled_) + { + interpreter_->compile(*(context_)); + varAddress_->clear(); + parAddress_->clear(); + for (Index i = 0; i < getNArg(); ++i) + { + varAddress_->push_back(context_->vTable.at("x_" + strFrom(i))); + } + for (Index j = 0; j < getNPar(); ++j) + { + parAddress_->push_back(context_->vTable.at("p_" + strFrom(j))); + } + *isCompiled_ = true; + } } // function call /////////////////////////////////////////////////////////////// @@ -55,13 +77,14 @@ double CompiledDoubleModel::operator()(const double *arg, { double result; - for (Index i = 0; i < getNArg(); ++i) + compile(); + for (unsigned int i = 0; i < getNArg(); ++i) { - context_->vTable["x_" + strFrom(i)] = arg[i]; + context_->vMem[(*varAddress_)[i]] = arg[i]; } - for (Index j = 0; j < getNPar(); ++j) + for (unsigned int j = 0; j < getNPar(); ++j) { - context_->vTable["p_" + strFrom(j)] = par[j]; + context_->vMem[(*parAddress_)[j]] = par[j]; } (*interpreter_)(*context_); if (!context_->dStack.empty()) @@ -81,7 +104,7 @@ double CompiledDoubleModel::operator()(const double *arg, // IO ////////////////////////////////////////////////////////////////////////// ostream & Latan::operator<<(std::ostream &out, CompiledDoubleModel &m) { - m.interpreter_->compile(); + m.compile(); out << *(m.interpreter_); return out; diff --git a/lib/CompiledModel.hpp b/lib/CompiledModel.hpp index 420ba6d..85c626e 100644 --- a/lib/CompiledModel.hpp +++ b/lib/CompiledModel.hpp @@ -48,8 +48,13 @@ public: friend std::ostream & operator<<(std::ostream &out, CompiledDoubleModel &f); private: - std::shared_ptr interpreter_; - std::shared_ptr context_; + // compile + void compile(void) const; +private: + std::shared_ptr interpreter_; + std::shared_ptr context_; + std::shared_ptr> varAddress_, parAddress_; + std::shared_ptr isCompiled_; }; std::ostream & operator<<(std::ostream &out, CompiledDoubleModel &f); diff --git a/lib/Math.cpp b/lib/Math.cpp index ccaf267..99dcf06 100644 --- a/lib/Math.cpp +++ b/lib/Math.cpp @@ -90,63 +90,3 @@ DEF_STD_FUNC_2ARG(fmin) // Absolute value DEF_STD_FUNC_1ARG(fabs) - -#define ADD_FUNC(func) fTable[#func] = &STDMATH_NAMESPACE::func -void STDMATH_NAMESPACE::addStdMathFunc(FunctionTable &fTable) -{ - // Trigonometric functions - ADD_FUNC(cos); - ADD_FUNC(sin); - ADD_FUNC(tan); - ADD_FUNC(acos); - ADD_FUNC(asin); - ADD_FUNC(atan); - ADD_FUNC(atan2); - - // Hyperbolic functions - ADD_FUNC(cosh); - ADD_FUNC(sinh); - ADD_FUNC(tanh); - ADD_FUNC(acosh); - ADD_FUNC(asinh); - ADD_FUNC(atanh); - - // Exponential and logarithmic functions - ADD_FUNC(exp); - ADD_FUNC(log); - ADD_FUNC(log10); - ADD_FUNC(exp2); - ADD_FUNC(expm1); - ADD_FUNC(log1p); - ADD_FUNC(log2); - - // Power functions - ADD_FUNC(pow); - ADD_FUNC(sqrt); - ADD_FUNC(cbrt); - ADD_FUNC(hypot); - - // Error and gamma functions - ADD_FUNC(erf); - ADD_FUNC(erfc); - ADD_FUNC(tgamma); - ADD_FUNC(lgamma); - - // Rounding and remainder functions - ADD_FUNC(ceil); - ADD_FUNC(floor); - ADD_FUNC(fmod); - ADD_FUNC(trunc); - ADD_FUNC(round); - ADD_FUNC(rint); - ADD_FUNC(nearbyint); - ADD_FUNC(remainder); - - // Minimum, maximum, difference functions - ADD_FUNC(fdim); - ADD_FUNC(fmax); - ADD_FUNC(fmin); - - // Absolute value - ADD_FUNC(fabs); -} diff --git a/lib/Math.hpp b/lib/Math.hpp index 52d150b..8ceb763 100644 --- a/lib/Math.hpp +++ b/lib/Math.hpp @@ -95,9 +95,6 @@ DECL_STD_FUNC(fabs) namespace STDMATH_NAMESPACE { - // Add standard math functions to a table for the math compiler - void addStdMathFunc(FunctionTable &fTable); - // Constants const double pi = 3.1415926535897932384626433832795028841970; } diff --git a/lib/MathInterpreter.cpp b/lib/MathInterpreter.cpp index 5b4abfa..8dcdcf0 100644 --- a/lib/MathInterpreter.cpp +++ b/lib/MathInterpreter.cpp @@ -19,6 +19,7 @@ #include #include +#include using namespace std; using namespace Latan; @@ -41,12 +42,14 @@ ostream &Latan::operator<<(ostream& out, const Instruction& ins) Push::Push(const double val) : type_(ArgType::Constant) , val_(val) +, address_(0) , name_("") {} -Push::Push(const string &name) +Push::Push(const unsigned int address, const string &name) : type_(ArgType::Variable) , val_(0.0) +, address_(address) , name_(name) {} @@ -61,7 +64,7 @@ void Push::operator()(RunContext &context) const { try { - context.dStack.push(context.vTable.at(name_)); + context.dStack.push(context.vMem[address_]); } catch (out_of_range) { @@ -81,13 +84,14 @@ void Push::print(ostream &out) const } else { - out << CODE_MOD << name_; + out << CODE_MOD << name_ << " @v" << address_; } } // Pop constructor ///////////////////////////////////////////////////////////// -Pop::Pop(const string &name) -: name_(name) +Pop::Pop(const unsigned int address, const string &name) +: address_(address) +, name_(name) {} // Pop execution /////////////////////////////////////////////////////////////// @@ -95,7 +99,7 @@ void Pop::operator()(RunContext &context) const { if (!name_.empty()) { - context.vTable[name_] = context.dStack.top(); + context.vMem[address_] = context.dStack.top(); } context.dStack.pop(); context.insIndex++; @@ -104,12 +108,13 @@ void Pop::operator()(RunContext &context) const // Pop print /////////////////////////////////////////////////////////////////// void Pop::print(ostream &out) const { - out << CODE_MOD << "pop" << CODE_MOD << name_; + out << CODE_MOD << "pop" << CODE_MOD << name_ << " @v" << address_; } // Store constructor /////////////////////////////////////////////////////////// -Store::Store(const string &name) -: name_(name) +Store::Store(const unsigned int address, const string &name) +: address_(address) +, name_(name) {} // Store execution ///////////////////////////////////////////////////////////// @@ -117,7 +122,7 @@ void Store::operator()(RunContext &context) const { if (!name_.empty()) { - context.vTable[name_] = context.dStack.top(); + context.vMem[address_] = context.dStack.top(); } context.insIndex++; } @@ -125,12 +130,13 @@ void Store::operator()(RunContext &context) const // Store print ///////////////////////////////////////////////////////////////// void Store::print(ostream &out) const { - out << CODE_MOD << "store" << CODE_MOD << name_; + out << CODE_MOD << "store" << CODE_MOD << name_ << " @v" << address_; } // Call constructor //////////////////////////////////////////////////////////// -Call::Call(const string &name) -: name_(name) +Call::Call(const unsigned int address, const string &name) +: address_(address) +, name_(name) {} // Call execution ////////////////////////////////////////////////////////////// @@ -138,7 +144,7 @@ void Call::operator()(RunContext &context) const { try { - context.dStack.push((*context.fTable.at(name_))(context.dStack)); + context.dStack.push((*context.fMem[address_])(context.dStack)); } catch (out_of_range) { @@ -150,7 +156,7 @@ void Call::operator()(RunContext &context) const // Call print ////////////////////////////////////////////////////////////////// void Call::print(ostream &out) const { - out << CODE_MOD << "call" << CODE_MOD << name_; + out << CODE_MOD << "call" << CODE_MOD << name_ << " @f" << address_; } // Math operations ///////////////////////////////////////////////////////////// @@ -263,23 +269,40 @@ ostream &Latan::operator<<(ostream &out, const ExprNode &n) return out; } -#define PUSH_INS(program, type, ...) \ +#define PUSH_INS(program, type, ...)\ program.push_back(unique_ptr(new type(__VA_ARGS__))) +#define GET_ADDRESS(address, table, name)\ +try\ +{\ + address = (table).at(name);\ +}\ +catch (out_of_range)\ +{\ + address = static_cast((table).size());\ + (table)[(name)] = address;\ +}\ // VarNode compile ///////////////////////////////////////////////////////////// -void VarNode::compile(Program &program) const +void VarNode::compile(Program &program, AddressTable &vTable, + AddressTable &fTable __unused) const { - PUSH_INS(program, Push, getName()); + unsigned int address; + + GET_ADDRESS(address, vTable, getName()); + PUSH_INS(program, Push, address, getName()); + } // CstNode compile ///////////////////////////////////////////////////////////// -void CstNode::compile(Program &program) const +void CstNode::compile(Program &program, AddressTable &nextVAddress __unused, + AddressTable &nextFAddress __unused) const { PUSH_INS(program, Push, strTo(getName())); } // SemicolonNode compile /////////////////////////////////////////////////////// -void SemicolonNode::compile(Program &program) const +void SemicolonNode::compile(Program &program, AddressTable &vTable, + AddressTable &fTable) const { auto &n = *this; @@ -291,28 +314,31 @@ void SemicolonNode::compile(Program &program) const if (isAssign||isSemiColumn||isKeyword) { - n[i].compile(program); + n[i].compile(program, vTable, fTable); } } } // AssignNode compile ////////////////////////////////////////////////////////// -void AssignNode::compile(Program &program) const +void AssignNode::compile(Program &program, AddressTable &vTable, + AddressTable &fTable) const { auto &n = *this; if (isDerivedFrom(&n[0])) { bool hasSemicolonParent = isDerivedFrom(getParent()); + unsigned int address; - n[1].compile(program); + n[1].compile(program, vTable, fTable); + GET_ADDRESS(address, vTable, n[0].getName()); if (hasSemicolonParent) { - PUSH_INS(program, Pop, n[0].getName()); + PUSH_INS(program, Pop, address, n[0].getName()); } else { - PUSH_INS(program, Store, n[0].getName()); + PUSH_INS(program, Store, address, n[0].getName()); } } else @@ -326,13 +352,14 @@ void AssignNode::compile(Program &program) const #define ELIFNODE(name, nArg) else IFNODE(name, nArg) #define ELSE else -void MathOpNode::compile(Program &program) const +void MathOpNode::compile(Program &program, AddressTable &vTable, + AddressTable &fTable) const { auto &n = *this; for (Index i = 0; i < n.getNArg(); ++i) { - n[i].compile(program); + n[i].compile(program, vTable, fTable); } IFNODE("-", 1) PUSH_INS(program, Neg,); ELIFNODE("+", 2) PUSH_INS(program, Add,); @@ -344,23 +371,27 @@ void MathOpNode::compile(Program &program) const } // FuncNode compile //////////////////////////////////////////////////////////// -void FuncNode::compile(Program &program) const +void FuncNode::compile(Program &program, AddressTable &vTable, + AddressTable &fTable) const { auto &n = *this; + unsigned int address; for (Index i = 0; i < n.getNArg(); ++i) { - n[i].compile(program); + n[i].compile(program, vTable, fTable); } - PUSH_INS(program, Call, getName()); + GET_ADDRESS(address, fTable, getName()); + PUSH_INS(program, Call, address, getName()); } // ReturnNode compile //////////////////////////////////////////////////////////// -void ReturnNode::compile(Program &program) const +void ReturnNode::compile(Program &program, AddressTable &vTable, + AddressTable &fTable) const { auto &n = *this; - n[0].compile(program); + n[0].compile(program, vTable, fTable); program.push_back(nullptr); } @@ -439,7 +470,57 @@ void MathInterpreter::parse(void) } // interpreter ///////////////////////////////////////////////////////////////// -void MathInterpreter::compile(void) +#define ADD_FUNC(context, func)\ +try\ +{\ +(context).fMem[(context).fTable.at(#func)] = &STDMATH_NAMESPACE::func;\ +}\ +catch (out_of_range)\ +{} + +#define ADD_STDMATH_FUNCS(context)\ +ADD_FUNC(context, cos);\ +ADD_FUNC(context, sin);\ +ADD_FUNC(context, tan);\ +ADD_FUNC(context, acos);\ +ADD_FUNC(context, asin);\ +ADD_FUNC(context, atan);\ +ADD_FUNC(context, atan2);\ +ADD_FUNC(context, cosh);\ +ADD_FUNC(context, sinh);\ +ADD_FUNC(context, tanh);\ +ADD_FUNC(context, acosh);\ +ADD_FUNC(context, asinh);\ +ADD_FUNC(context, atanh);\ +ADD_FUNC(context, exp);\ +ADD_FUNC(context, log);\ +ADD_FUNC(context, log10);\ +ADD_FUNC(context, exp2);\ +ADD_FUNC(context, expm1);\ +ADD_FUNC(context, log1p);\ +ADD_FUNC(context, log2);\ +ADD_FUNC(context, pow);\ +ADD_FUNC(context, sqrt);\ +ADD_FUNC(context, cbrt);\ +ADD_FUNC(context, hypot);\ +ADD_FUNC(context, erf);\ +ADD_FUNC(context, erfc);\ +ADD_FUNC(context, tgamma);\ +ADD_FUNC(context, lgamma);\ +ADD_FUNC(context, ceil);\ +ADD_FUNC(context, floor);\ +ADD_FUNC(context, fmod);\ +ADD_FUNC(context, trunc);\ +ADD_FUNC(context, round);\ +ADD_FUNC(context, rint);\ +ADD_FUNC(context, nearbyint);\ +ADD_FUNC(context, remainder);\ +ADD_FUNC(context, fdim);\ +ADD_FUNC(context, fmax);\ +ADD_FUNC(context, fmin);\ +ADD_FUNC(context, fabs); + +void MathInterpreter::compile(RunContext &context) { bool gotReturn = false; @@ -449,34 +530,43 @@ void MathInterpreter::compile(void) status_ |= Status::parsed; status_ -= status_ & Status::compiled; } - if (root_) + if (!(status_ & Status::compiled)) { - root_->compile(program_); - for (unsigned int i = 0; i < program_.size(); ++i) + if (root_) { - if (!program_[i]) + context.vTable.clear(); + context.fTable.clear(); + root_->compile(program_, context.vTable, context.fTable); + for (unsigned int i = 0; i < program_.size(); ++i) { - gotReturn = true; - program_.resize(i); - program_.shrink_to_fit(); - break; + if (!program_[i]) + { + gotReturn = true; + program_.resize(i); + program_.shrink_to_fit(); + break; + } } + context.vMem.resize(context.vTable.size()); + context.fMem.resize(context.fTable.size()); + ADD_STDMATH_FUNCS(context); } - + if (!root_||!gotReturn) + { + LATAN_ERROR(Syntax, "expected 'return' in program '" + codeName_ + + "'"); + } + status_ |= Status::compiled; } - if (!root_||!gotReturn) - { - LATAN_ERROR(Syntax, "expected 'return' in program '" + codeName_ + "'"); - } - status_ |= Status::compiled; } + // execution /////////////////////////////////////////////////////////////////// void MathInterpreter::operator()(RunContext &context) { if (!(status_ & Status::compiled)) { - compile(); + compile(context); } execute(context); } diff --git a/lib/MathInterpreter.hpp b/lib/MathInterpreter.hpp index 4a72397..973a6c1 100644 --- a/lib/MathInterpreter.hpp +++ b/lib/MathInterpreter.hpp @@ -36,15 +36,15 @@ BEGIN_NAMESPACE /****************************************************************************** * Instruction classes * ******************************************************************************/ -typedef std::map VarTable; -typedef std::map FunctionTable; +typedef std::map AddressTable; struct RunContext { - unsigned int insIndex; - std::stack dStack; - VarTable vTable; - FunctionTable fTable; + unsigned int insIndex; + std::stack dStack; + std::vector vMem; + std::vector fMem; + AddressTable vTable, fTable; }; // Abstract base @@ -77,15 +77,16 @@ private: public: //constructors explicit Push(const double val); - explicit Push(const std::string &name); + explicit Push(const unsigned int address, const std::string &name); // instruction execution virtual void operator()(RunContext &context) const; private: virtual void print(std::ostream& out) const; private: - ArgType type_; - double val_; - std::string name_; + ArgType type_; + double val_; + unsigned int address_; + std::string name_; }; // Pop @@ -93,12 +94,13 @@ class Pop: public Instruction { public: //constructor - explicit Pop(const std::string &name); + explicit Pop(const unsigned int address, const std::string &name); // instruction execution virtual void operator()(RunContext &context) const; private: virtual void print(std::ostream& out) const; private: + unsigned int address_; std::string name_; }; @@ -107,12 +109,13 @@ class Store: public Instruction { public: //constructor - explicit Store(const std::string &name); + explicit Store(const unsigned int address, const std::string &name); // instruction execution virtual void operator()(RunContext &context) const; private: virtual void print(std::ostream& out) const; private: + unsigned int address_; std::string name_; }; @@ -121,12 +124,13 @@ class Call: public Instruction { public: //constructor - explicit Call(const std::string &name); + explicit Call(const unsigned int address, const std::string &name); // instruction execution virtual void operator()(RunContext &context) const; private: virtual void print(std::ostream& out) const; private: + unsigned int address_; std::string name_; }; @@ -167,7 +171,8 @@ public: // operator const ExprNode &operator[](const Index i) const; // compile - virtual void compile(Program &program) const = 0; + virtual void compile(Program &program, AddressTable &vTable, + AddressTable &fTable) const = 0; private: std::string name_; std::vector> arg_; @@ -181,7 +186,8 @@ class name: public base\ {\ public:\ using base::base;\ - virtual void compile(Program &program) const;\ + virtual void compile(Program &program, AddressTable &vTable,\ + AddressTable &fTable) const;\ } DECL_NODE(ExprNode, VarNode); @@ -195,7 +201,8 @@ class KeywordNode: public ExprNode { public: using ExprNode::ExprNode; - virtual void compile(Program &program) const = 0; + virtual void compile(Program &program, AddressTable &vTable, + AddressTable &fTable) const = 0; }; DECL_NODE(KeywordNode, ReturnNode); @@ -245,7 +252,7 @@ public: // initialization void setCode(const std::string &code); // interpreter - void compile(void); + void compile(RunContext &context); // execution void operator()(RunContext &context); // IO