1
0
mirror of https://github.com/aportelli/LatAnalyze.git synced 2024-09-20 05:25:37 +01:00

general cleaning/consolidation of the math interpreter

This commit is contained in:
Antonin Portelli 2014-02-06 18:07:27 +00:00
parent 50d21ae904
commit ce6469cdd7
14 changed files with 1067 additions and 57 deletions

View File

@ -15,10 +15,15 @@ endif
endif endif
noinst_PROGRAMS = \ noinst_PROGRAMS = \
exMathCompiler exMathInterpreter \
exCompiledDoubleFunction
exMathCompiler_SOURCES = exMathCompiler.cpp exMathInterpreter_SOURCES = exMathInterpreter.cpp
exMathCompiler_CFLAGS = -g -O2 exMathInterpreter_CFLAGS = -g -O2
exMathCompiler_LDFLAGS = -L../latan/.libs -llatan exMathInterpreter_LDFLAGS = -L../latan/.libs -llatan
exCompiledDoubleFunction_SOURCES = exCompiledDoubleFunction.cpp
exCompiledDoubleFunction_CFLAGS = -g -O2
exCompiledDoubleFunction_LDFLAGS = -L../latan/.libs -llatan
ACLOCAL_AMFLAGS = -I .buildutils/m4 ACLOCAL_AMFLAGS = -I .buildutils/m4

View File

@ -0,0 +1,31 @@
#include <iostream>
#include <iomanip>
#include <latan/CompiledFunction.hpp>
using namespace std;
using namespace Latan;
int main(int argc, char* argv[])
{
string source;
if (argc != 2)
{
cerr << "usage: " << argv[0] << " <function>" << endl;
return EXIT_FAILURE;
}
source = argv[1];
CompiledDoubleFunction f(1, source);
cout << "-- Program:" << endl << f << endl;
cout << "-- Values:" << endl;
for (double x = 0.0; x < 10.0; x += 0.5)
{
cout << "f(" << right << setw(6) << strFrom<double>(x) << ")= "
<< f(x) << endl;
}
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,75 @@
#include <iostream>
#include <latan/Math.hpp>
#include <latan/MathInterpreter.hpp>
using namespace std;
using namespace Latan;
int main(int argc, char* argv[])
{
string source;
if (argc != 2)
{
cerr << "usage: " << argv[0] << " <program>" << endl;
return EXIT_FAILURE;
}
source = argv[1];
MathInterpreter interpreter(source);
RunContext context;
cout << "-- Source code:" << endl << source << endl << endl;
interpreter.compile();
cout << "-- Abstract Syntax Tree:" << endl;
if (interpreter.getAST())
{
cout << *interpreter.getAST() << endl;
}
else
{
cout << "<null>" << endl << endl;
}
cout << "-- Program:" << endl << interpreter << endl;
StdMath::addStdMathFunc(context.fTable);
interpreter(context);
if (!context.dStack.empty())
{
cout << "-- Result: " << context.dStack.top() << endl;
}
return EXIT_SUCCESS;
}
/*int main(void)
{
ASCIIFile F;
DMat A,B;
F.Open("foo.boot",FileMode::Read);
A = F.Read<DMat>("bla");
B = F.Read<DMat>("bli");
cout << A << endl;
cout << B << endl;
cout << A*B << endl;
return EXIT_SUCCESS;
}*/
/*
int main(void)
{
DMat m(2,2);
m(0,6) = 3;
m(1,0) = 2.5;
m(0,1) = -1;
m(1,1) = m(1,0) + m(0,1);
cout << "Here is the matrix m:\n" << m << endl;
DVec v(2);
v(0) = 4;
v(1) = v(0) - 1;
cout << "Here is the vector v:\n" << v << endl;
}
*/

View File

@ -0,0 +1,69 @@
#include <latan/CompiledFunction.hpp>
#include <latan/Math.hpp>
#include <latan/includes.hpp>
using namespace std;
using namespace Latan;
/******************************************************************************
* Compiled double function implementation *
******************************************************************************/
// constructor/destructor //////////////////////////////////////////////////////
CompiledDoubleFunction::CompiledDoubleFunction(const unsigned nArg)
: DoubleFunction(nArg)
{}
CompiledDoubleFunction::CompiledDoubleFunction(const unsigned nArg,
const string &code)
: DoubleFunction(nArg)
{
setCode(code);
}
CompiledDoubleFunction::~CompiledDoubleFunction(void)
{}
// access //////////////////////////////////////////////////////////////////////
void CompiledDoubleFunction::setCode(const string &code)
{
interpreter_.setCode(code);
StdMath::addStdMathFunc(context_.fTable);
}
// function call ///////////////////////////////////////////////////////////////
double CompiledDoubleFunction::operator()(vector<double> &arg)
{
double result;
if (arg.size() != getNArg())
{
LATAN_ERROR(Size, "function argument vector has a wrong size (got " +
strFrom(arg.size()) + ", expected " + strFrom(getNArg()) +
")");
}
for (unsigned int i = 0; i < getNArg(); ++i)
{
context_.vTable["x_" + strFrom(i)] = arg[i];
}
interpreter_(context_);
if (!context_.dStack.empty())
{
result = context_.dStack.top();
context_.dStack.pop();
}
else
{
result = 0.0;
LATAN_ERROR(Program, "program execution resulted in an empty stack");
}
return result;
}
// IO //////////////////////////////////////////////////////////////////////////
ostream &Latan::operator<<(ostream &out, CompiledDoubleFunction &f)
{
out << f.interpreter_;
return out;
}

View File

@ -0,0 +1,39 @@
#ifndef LATAN_COMPILED_FUNCTION_HPP_
#define LATAN_COMPILED_FUNCTION_HPP_
#include <latan/Global.hpp>
#include <latan/Function.hpp>
#include <latan/MathInterpreter.hpp>
#include <stack>
#include <vector>
#include <cstdarg>
LATAN_BEGIN_CPPDECL
/******************************************************************************
* Compiled double function class *
******************************************************************************/
class CompiledDoubleFunction: public DoubleFunction
{
public:
// constructor/destructor
explicit CompiledDoubleFunction(const unsigned nArg);
explicit CompiledDoubleFunction(const unsigned nArg,
const std::string &code);
virtual ~CompiledDoubleFunction(void);
// access
void setCode(const std::string &code);
// function call
using DoubleFunction::operator();
virtual double operator()(std::vector<double> &arg);
// IO
friend std::ostream &operator<<(std::ostream &out,
CompiledDoubleFunction &f);
private:
MathInterpreter interpreter_;
RunContext context_;
};
LATAN_END_CPPDECL
#endif

View File

@ -8,7 +8,7 @@
#define ERR_SUFF " (" + loc + ")" #define ERR_SUFF " (" + loc + ")"
#endif #endif
#define CONST_EXC(name,init) \ #define CONST_EXC(name, init) \
name::name(string msg, string loc)\ name::name(string msg, string loc)\
:init\ :init\
{} {}
@ -18,13 +18,16 @@ using namespace Latan;
using namespace Exceptions; using namespace Exceptions;
// logic errors // logic errors
CONST_EXC(Logic,logic_error(ERR_PREF+msg+ERR_SUFF)) CONST_EXC(Logic, logic_error(ERR_PREF+msg+ERR_SUFF))
CONST_EXC(Implementation,Logic("implementation error: "+msg,loc)) CONST_EXC(Definition, Logic("definition error: "+msg,loc))
CONST_EXC(Range,Logic("range error: "+msg,loc)) CONST_EXC(Implementation, Logic("implementation error: "+msg,loc))
CONST_EXC(Range, Logic("range error: "+msg,loc))
CONST_EXC(Size, Logic("size error: "+msg,loc))
// runtime errors // runtime errors
CONST_EXC(Runtime,runtime_error(ERR_PREF+msg+ERR_SUFF)) CONST_EXC(Runtime, runtime_error(ERR_PREF+msg+ERR_SUFF))
CONST_EXC(Compilation,Runtime("compilation error: "+msg,loc)) CONST_EXC(Compilation, Runtime("compilation error: "+msg,loc))
CONST_EXC(Io,Runtime("IO error: "+msg,loc)) CONST_EXC(Io, Runtime("IO error: "+msg,loc))
CONST_EXC(Parsing,Runtime(msg,loc)) CONST_EXC(Parsing, Runtime(msg,loc))
CONST_EXC(Syntax,Runtime("syntax error: "+msg,loc)) CONST_EXC(Program, Runtime(msg,loc))
CONST_EXC(Syntax, Runtime("syntax error: "+msg,loc))

View File

@ -10,7 +10,7 @@
+ strFrom<const char*>(__FILE__) + ":" + strFrom<int>(__LINE__) + strFrom<const char*>(__FILE__) + ":" + strFrom<int>(__LINE__)
#define LATAN_ERROR(exc,msg) throw(Exceptions::exc(msg,SRC_LOC)) #define LATAN_ERROR(exc,msg) throw(Exceptions::exc(msg,SRC_LOC))
#define DECL_EXC(name,base) \ #define DECL_EXC(name, base) \
class name: public base\ class name: public base\
{\ {\
public:\ public:\
@ -22,15 +22,18 @@ LATAN_BEGIN_CPPDECL
namespace Exceptions namespace Exceptions
{ {
// logic errors // logic errors
DECL_EXC(Logic,std::logic_error); DECL_EXC(Logic, std::logic_error);
DECL_EXC(Implementation,Logic); DECL_EXC(Definition, Logic);
DECL_EXC(Range,Logic); DECL_EXC(Implementation, Logic);
DECL_EXC(Range, Logic);
DECL_EXC(Size, Logic);
// runtime errors // runtime errors
DECL_EXC(Runtime,std::runtime_error); DECL_EXC(Runtime, std::runtime_error);
DECL_EXC(Compilation,Runtime); DECL_EXC(Compilation, Runtime);
DECL_EXC(Io,Runtime); DECL_EXC(Io, Runtime);
DECL_EXC(Parsing,Runtime); DECL_EXC(Parsing, Runtime);
DECL_EXC(Syntax,Runtime); DECL_EXC(Program, Runtime);
DECL_EXC(Syntax, Runtime);
} }
LATAN_END_CPPDECL LATAN_END_CPPDECL

View File

@ -34,7 +34,7 @@ Function::~Function(void)
{} {}
// access ////////////////////////////////////////////////////////////////////// // access //////////////////////////////////////////////////////////////////////
unsigned int Function::getNArg(void) unsigned int Function::getNArg(void) const
{ {
return nArg_; return nArg_;
} }
@ -77,5 +77,3 @@ double DoubleFunction::operator()(const double x0, ...)
return (*this)(buffer_); return (*this)(buffer_);
} }

View File

@ -16,9 +16,9 @@ class Function
public: public:
// constructor/destructor // constructor/destructor
explicit Function(const unsigned nArg); explicit Function(const unsigned nArg);
~Function(void); virtual ~Function(void);
// access // access
unsigned int getNArg(void); unsigned int getNArg(void) const;
private: private:
const unsigned int nArg_; const unsigned int nArg_;
}; };

View File

@ -25,6 +25,7 @@ BUILT_SOURCES = IoAsciiParser.hpp MathParser.hpp
lib_LTLIBRARIES = liblatan.la lib_LTLIBRARIES = liblatan.la
liblatan_la_SOURCES = \ liblatan_la_SOURCES = \
CompiledFunction.cpp\
Exceptions.cpp \ Exceptions.cpp \
Function.cpp \ Function.cpp \
Global.cpp \ Global.cpp \
@ -34,20 +35,21 @@ liblatan_la_SOURCES = \
IoAsciiLexer.lpp \ IoAsciiLexer.lpp \
Mat.cpp \ Mat.cpp \
Math.cpp \ Math.cpp \
MathCompiler.cpp \ MathInterpreter.cpp \
MathParser.ypp \ MathParser.ypp \
MathLexer.lpp \ MathLexer.lpp \
Sample.cpp \ Sample.cpp \
../config.h ../config.h
liblatan_ladir = $(pkgincludedir) liblatan_ladir = $(pkgincludedir)
liblatan_la_HEADERS = \ liblatan_la_HEADERS = \
CompiledFunction.hpp\
Function.hpp \ Function.hpp \
Global.hpp \ Global.hpp \
Io.hpp \ Io.hpp \
IoObject.hpp \ IoObject.hpp \
Mat.hpp \ Mat.hpp \
Math.hpp \ Math.hpp \
MathCompiler.hpp \ MathInterpreter.hpp \
Sample.hpp Sample.hpp
liblatan_la_CFLAGS = $(COM_CFLAGS) liblatan_la_CFLAGS = $(COM_CFLAGS)
liblatan_la_CXXFLAGS = $(COM_CXXFLAGS) liblatan_la_CXXFLAGS = $(COM_CXXFLAGS)

534
latan/MathInterpreter.cpp Normal file
View File

@ -0,0 +1,534 @@
#include <latan/MathInterpreter.hpp>
#include <latan/includes.hpp>
using namespace std;
using namespace Latan;
/******************************************************************************
* MathNode implementation *
******************************************************************************/
// constructor /////////////////////////////////////////////////////////////////
MathNode::MathNode(const string &name, const unsigned int type)
: name_(name)
, type_(type)
, parent_(NULL)
{}
MathNode::MathNode(const std::string &name, const unsigned int type,\
const unsigned int nArg, ...)
: name_(name)
, type_(type)
, arg_(nArg)
, parent_(NULL)
{
va_list va;
va_start(va, nArg);
for (unsigned int i = 0; i < nArg; ++i)
{
arg_[i] = va_arg(va, MathNode *);
arg_[i]->parent_ = this;
}
va_end(va);
}
// destructor //////////////////////////////////////////////////////////////////
MathNode::~MathNode(void)
{
vector<MathNode *>::iterator i;
for (i = arg_.begin(); i != arg_.end(); ++i)
{
delete *i;
}
}
// access //////////////////////////////////////////////////////////////////////
const string &MathNode::getName(void) const
{
return name_;
}
unsigned int MathNode::getType(void) const
{
return type_;
}
unsigned int MathNode::getNArg(void) const
{
return static_cast<unsigned int>(arg_.size());
}
const MathNode * MathNode::getParent(void) const
{
return parent_;
}
unsigned int MathNode::getLevel(void) const
{
if (getParent())
{
return getParent()->getLevel() + 1;
}
else
{
return 0;
}
}
void MathNode::setName(const std::string &name)
{
name_ = name;
}
void MathNode::pushArg(MathNode *node)
{
arg_.push_back(node);
}
// operators ///////////////////////////////////////////////////////////////////
const MathNode &MathNode::operator[](const unsigned int i) const
{
return *arg_[i];
}
ostream &Latan::operator<<(ostream &out, const MathNode &n)
{
unsigned int level = n.getLevel();
for (unsigned int i = 0; i <= level; ++i)
{
if (i == level)
{
out << "_";
}
else if (i == level - 1)
{
out << "|";
}
else
{
out << " ";
}
}
out << " " << n.getName() << " (type " << n.getType() << ")" << endl;
for (unsigned int i = 0; i < n.getNArg(); ++i)
{
out << n[i];
}
return out;
}
/******************************************************************************
* Instruction set *
******************************************************************************/
#define CODE_WIDTH 6
#define CODE_MOD setw(CODE_WIDTH) << left
Instruction::~Instruction(void)
{}
ostream &Latan::operator<<(ostream& out, const Instruction& ins)
{
ins.print(out);
return out;
}
Push::Push(const double val)
: type_(ArgType::Constant)
, val_(val)
, name_("")
{}
Push::Push(const string &name)
: type_(ArgType::Variable)
, val_(0.0)
, name_(name)
{}
void Push::operator()(RunContext &context) const
{
if (type_ == ArgType::Constant)
{
context.dStack.push(val_);
}
else
{
if (keyExists(name_, context.vTable))
{
context.dStack.push(context.vTable[name_]);
}
else
{
LATAN_ERROR(Range, "unknown variable '" + name_ + "'");
}
}
context.insIndex++;
}
void Push::print(std::ostream &out) const
{
out << CODE_MOD << "push";
if (type_ == ArgType::Constant)
{
out << CODE_MOD << val_;
}
else
{
out << CODE_MOD << name_;
}
}
Pop::Pop(const string &name)
: name_(name)
{}
void Pop::operator()(RunContext &context) const
{
if (!name_.empty())
{
context.vTable[name_] = context.dStack.top();
}
context.dStack.pop();
context.insIndex++;
}
void Pop::print(std::ostream &out) const
{
out << CODE_MOD << "pop" << CODE_MOD << name_;
}
Store::Store(const string &name)
: name_(name)
{}
void Store::operator()(RunContext &context) const
{
if (!name_.empty())
{
context.vTable[name_] = context.dStack.top();
}
context.insIndex++;
}
void Store::print(std::ostream &out) const
{
out << CODE_MOD << "store" << CODE_MOD << name_;
}
Call::Call(const string &name)
: name_(name)
{}
void Call::operator()(RunContext &context) const
{
if (keyExists(name_, context.fTable))
{
context.dStack.push((*context.fTable[name_])(context.dStack));
}
else
{
LATAN_ERROR(Range, "unknown function '" + name_ + "'");
}
context.insIndex++;
}
void Call::print(std::ostream &out) const
{
out << CODE_MOD << "call" << CODE_MOD << name_;
}
#define DEF_OP(name, nArg, exp, insName)\
void name::operator()(RunContext &context) const\
{\
double x[nArg];\
for (int i = 0; i < nArg; ++i)\
{\
x[nArg-1-i] = context.dStack.top();\
context.dStack.pop();\
}\
context.dStack.push(exp);\
context.insIndex++;\
}\
void name::print(std::ostream &out) const\
{\
out << CODE_MOD << insName;\
}
DEF_OP(Neg, 1, -x[0], "neg")
DEF_OP(Add, 2, x[0] + x[1], "add")
DEF_OP(Sub, 2, x[0] - x[1], "sub")
DEF_OP(Mul, 2, x[0]*x[1], "mul")
DEF_OP(Div, 2, x[0]/x[1], "div")
DEF_OP(Pow, 2, pow(x[0],x[1]), "pow")
/******************************************************************************
* MathInterpreter implementation *
******************************************************************************/
// MathParserState constructor /////////////////////////////////////////////////
MathInterpreter::MathParserState::MathParserState(istream *stream, string *name,
MathNode **data)
: ParserState<MathNode *>(stream, name, data)
{
initScanner();
}
// MathParserState destructor //////////////////////////////////////////////////
MathInterpreter::MathParserState::~MathParserState(void)
{
destroyScanner();
}
// constructors ////////////////////////////////////////////////////////////////
MathInterpreter::MathInterpreter(void)
: code_(NULL)
, codeName_("<no_code>")
, state_(NULL)
, root_(NULL)
, gotReturn_(false)
, status_(Status::none)
{}
MathInterpreter::MathInterpreter(const std::string &code)
: code_(NULL)
, codeName_("<string>")
, state_(NULL)
, root_(NULL)
, gotReturn_(false)
, status_(Status::none)
{
setCode(code);
}
// destructor //////////////////////////////////////////////////////////////////
MathInterpreter::~MathInterpreter(void)
{
reset();
}
// access //////////////////////////////////////////////////////////////////////
const Instruction * MathInterpreter::operator[](const unsigned int i) const
{
return program_[i];
}
const MathNode * MathInterpreter::getAST(void) const
{
if (root_)
{
return root_;
}
else
{
return NULL;
}
}
void MathInterpreter::push(const Instruction *i)
{
program_.push_back(i);
}
// initialization //////////////////////////////////////////////////////////////
void MathInterpreter::setCode(const std::string &code)
{
if (status_)
{
reset();
}
code_ = new stringstream(code);
codeName_ = "<string>";
state_ = new MathParserState(code_, &codeName_, &root_);
status_ = Status::initialised;
}
void MathInterpreter::reset(void)
{
InstructionContainer::iterator i;
delete code_;
codeName_ = "<no_code>";
delete state_;
delete root_;
for (i = program_.begin(); i != program_.end(); ++i)
{
delete *i;
}
program_.clear();
status_ = 0;
}
// parser //////////////////////////////////////////////////////////////////////
// Bison/Flex parser declaration
int _math_parse(MathInterpreter::MathParserState* state);
void MathInterpreter::parse(void)
{
_math_parse(state_);
}
// interpreter /////////////////////////////////////////////////////////////////
void MathInterpreter::compile(void)
{
if (!(status_ & Status::parsed))
{
parse();
status_ |= Status::parsed;
status_ -= status_ & Status::compiled;
}
gotReturn_ = false;
if (root_)
{
compileNode(*root_);
}
if (!root_||!gotReturn_)
{
LATAN_ERROR(Syntax, "expected 'return' in program '" + codeName_ + "'");
}
status_ |= Status::compiled;
}
#define IFNODE(name, nArg) if ((n.getName() == (name))&&(n.getNArg() == nArg))
#define ELIFNODE(name, nArg) else IFNODE(name, nArg)
#define ELSE else
void MathInterpreter::compileNode(const MathNode& n)
{
if (!gotReturn_)
{
switch (n.getType())
{
case MathNode::Type::cst:
program_.push_back(new Push(strTo<double>(n.getName())));
break;
case MathNode::Type::var:
program_.push_back(new Push(n.getName()));
break;
case MathNode::Type::op:
// semicolon
if (n.getName() == ";")
{
// compile relevant statements
for (unsigned int i = 0; i < n.getNArg(); ++i)
{
bool isAssign =
((n[i].getType() == MathNode::Type::op)&&
(n[i].getName() == "="));
bool isSemiColumn =
((n[i].getType() == MathNode::Type::op)&&
(n[i].getName() == ";"));
bool isKeyword =
(n[i].getType() == MathNode::Type::keyw);
if (isAssign||isSemiColumn||isKeyword)
{
compileNode(n[i]);
}
}
}
// assignment
else if (n.getName() == "=")
{
// variable assignement
if (n[0].getType() == MathNode::Type::var)
{
bool hasSemicolonParent = ((n.getParent() != NULL) &&
(n.getParent()->getType()
== MathNode::Type::op)&&
(n.getParent()->getName()
== ";"));
// compile the RHS
compileNode(n[1]);
// pop instruction if at the end of a statement
if (hasSemicolonParent)
{
program_.push_back(new Pop(n[0].getName()));
}
// store instruction else
else
{
program_.push_back(new Store(n[0].getName()));
}
}
else
{
LATAN_ERROR(Compilation, "invalid LHS for '='");
}
}
// arithmetic operators
else
{
for (unsigned int i = 0; i < n.getNArg(); ++i)
{
compileNode(n[i]);
}
IFNODE("-", 1) program_.push_back(new Neg);
ELIFNODE("+", 2) program_.push_back(new Add);
ELIFNODE("-", 2) program_.push_back(new Sub);
ELIFNODE("*", 2) program_.push_back(new Mul);
ELIFNODE("/", 2) program_.push_back(new Div);
ELIFNODE("^", 2) program_.push_back(new Pow);
ELSE LATAN_ERROR(Compilation, "unknown operator '"
+ n.getName() + "'");
}
break;
case MathNode::Type::keyw:
if (n.getName() == "return")
{
compileNode(n[0]);
gotReturn_ = true;
}
else
{
LATAN_ERROR(Compilation, "unknown keyword '" + n.getName()
+ "'");
}
break;
case MathNode::Type::func:
for (unsigned int i = 0; i < n.getNArg(); ++i)
{
compileNode(n[i]);
}
program_.push_back(new Call(n.getName()));
break;
default:
LATAN_ERROR(Compilation,
"unknown node type (node named '" + n.getName()
+ "')");
break;
}
}
}
// execution ///////////////////////////////////////////////////////////////////
void MathInterpreter::operator()(RunContext &context)
{
if (!(status_ & Status::compiled))
{
compile();
}
execute(context);
}
void MathInterpreter::execute(RunContext &context) const
{
context.insIndex = 0;
while (context.insIndex != program_.size())
{
(*(program_[context.insIndex]))(context);
}
}
// IO //////////////////////////////////////////////////////////////////////////
ostream &Latan::operator<<(ostream &out, const MathInterpreter &program)
{
for (unsigned int i = 0; i < program.program_.size(); ++i)
{
out << *(program.program_[i]) << endl;
}
return out;
}

251
latan/MathInterpreter.hpp Normal file
View File

@ -0,0 +1,251 @@
#ifndef LATAN_MATHCOMPILER_HPP_
#define LATAN_MATHCOMPILER_HPP_
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <stack>
#include <latan/Function.hpp>
#include <latan/Global.hpp>
#include <latan/ParserState.hpp>
#define MAXIDLENGTH 256
LATAN_BEGIN_CPPDECL
/******************************************************************************
* Parser classes *
******************************************************************************/
class MathNode
{
public:
class Type
{
public:
enum
{
undef = -1,
cst = 0,
op = 1,
var = 2,
keyw = 3,
func = 4
};
};
public:
// constructor
MathNode(const std::string &name, const unsigned int type);
MathNode(const std::string &name, const unsigned int type,
const unsigned int nArg, ...);
// destructor
virtual ~MathNode();
// access
const std::string& getName(void) const;
unsigned int getType(void) const;
unsigned int getNArg(void) const;
const MathNode * getParent(void) const;
unsigned int getLevel(void) const;
void setName(const std::string &name);
void pushArg(MathNode *node);
// operator
const MathNode &operator[](const unsigned int i) const;
private:
std::string name_;
unsigned int type_;
std::vector<MathNode *> arg_;
const MathNode * parent_;
};
std::ostream &operator<<(std::ostream &out, const MathNode &n);
/******************************************************************************
* Instruction classes *
******************************************************************************/
typedef std::map<std::string, double> VarTable;
typedef std::map<std::string, DoubleFunction *> FunctionTable;
struct RunContext
{
unsigned int insIndex;
std::stack<double> dStack;
VarTable vTable;
FunctionTable fTable;
};
// Abstract base
class Instruction
{
public:
virtual ~Instruction();
// instruction execution
virtual void operator()(RunContext &context) const = 0;
friend std::ostream& operator<<(std::ostream &out, const Instruction &ins);
private:
virtual void print(std::ostream &out) const = 0;
};
// Push
class Push: public Instruction
{
private:
class ArgType
{
public:
enum
{
Constant = 0,
Variable = 1
};
};
public:
//constructors
explicit Push(const double val);
explicit Push(const std::string &name);
// instruction execution
virtual void operator()(RunContext &context) const;
private:
virtual void print(std::ostream& out) const;
private:
unsigned int type_;
double val_;
std::string name_;
};
// Pop
class Pop: public Instruction
{
public:
//constructor
explicit Pop(const std::string &name);
// instruction execution
virtual void operator()(RunContext &context) const;
private:
virtual void print(std::ostream& out) const;
private:
std::string name_;
};
// Store
class Store: public Instruction
{
public:
//constructor
explicit Store(const std::string &name);
// instruction execution
virtual void operator()(RunContext &context) const;
private:
virtual void print(std::ostream& out) const;
private:
std::string name_;
};
// Call function
class Call: public Instruction
{
public:
//constructor
explicit Call(const std::string &name);
// instruction execution
virtual void operator()(RunContext &context) const;
private:
virtual void print(std::ostream& out) const;
private:
std::string name_;
};
// Floating point operations
#define DECL_OP(name)\
class name: public Instruction\
{\
public:\
virtual void operator()(RunContext &context) const;\
private:\
virtual void print(std::ostream &out) const;\
}
DECL_OP(Neg);
DECL_OP(Add);
DECL_OP(Sub);
DECL_OP(Mul);
DECL_OP(Div);
DECL_OP(Pow);
/******************************************************************************
* Compiler class *
******************************************************************************/
class MathInterpreter
{
public:
// parser state
class MathParserState: public ParserState<MathNode *>
{
public:
// constructor
explicit MathParserState(std::istream *stream, std::string *name,
MathNode **data);
// destructor
virtual ~MathParserState(void);
private:
// allocation/deallocation functions defined in MathLexer.lpp
virtual void initScanner(void);
virtual void destroyScanner(void);
};
private:
// status flags
class Status
{
public:
enum
{
none = 0,
initialised = 1 << 0,
parsed = 1 << 1,
compiled = 1 << 2
};
};
// instruction container
typedef std::vector<const Instruction *> InstructionContainer;
public:
// constructors
MathInterpreter(void);
MathInterpreter(const std::string &code);
// destructor
~MathInterpreter(void);
// access
const Instruction * operator[](const unsigned int i) const;
const MathNode * getAST(void) const;
// initialization
void setCode(const std::string &code);
// interpreter
void compile(void);
// execution
void operator()(RunContext &context);
// IO
friend std::ostream &operator<<(std::ostream &out,
const MathInterpreter &program);
private:
// initialization
void reset(void);
// access
void push(const Instruction *i);
// parser
void parse(void);
// interpreter
void compileNode(const MathNode &node);
// execution
void execute(RunContext &context) const;
private:
std::istream *code_;
std::string codeName_;
MathParserState *state_;
MathNode *root_;
bool gotReturn_;
InstructionContainer program_;
unsigned int status_;
};
LATAN_END_CPPDECL
#endif

View File

@ -7,7 +7,7 @@
%{ %{
#include <iostream> #include <iostream>
#include <latan/MathCompiler.hpp> #include <latan/MathInterpreter.hpp>
#include <latan/MathParser.hpp> #include <latan/MathParser.hpp>
#pragma GCC diagnostic ignored "-Wsign-compare" #pragma GCC diagnostic ignored "-Wsign-compare"
#pragma GCC diagnostic ignored "-Wunused-function" #pragma GCC diagnostic ignored "-Wunused-function"
@ -16,7 +16,7 @@
using namespace std; using namespace std;
using namespace Latan; using namespace Latan;
#define YY_EXTRA_TYPE MathCompiler::MathParserState * #define YY_EXTRA_TYPE MathInterpreter::MathParserState *
#define YY_USER_ACTION \ #define YY_USER_ACTION \
yylloc->first_line = yylloc->last_line = yylineno;\ yylloc->first_line = yylloc->last_line = yylineno;\
yylloc->first_column = yylloc->last_column + 1;\ yylloc->first_column = yylloc->last_column + 1;\
@ -62,13 +62,13 @@ return {RETTOK(RETURN);}
%% %%
void MathCompiler::MathParserState::initScanner() void MathInterpreter::MathParserState::initScanner()
{ {
yylex_init(&scanner); yylex_init(&scanner);
yyset_extra(this, scanner); yyset_extra(this, scanner);
} }
void MathCompiler::MathParserState::destroyScanner() void MathInterpreter::MathParserState::destroyScanner()
{ {
yylex_destroy(scanner); yylex_destroy(scanner);
} }

View File

@ -3,7 +3,7 @@
#include <sstream> #include <sstream>
#include <cstring> #include <cstring>
#include <latan/Global.hpp> #include <latan/Global.hpp>
#include <latan/MathCompiler.hpp> #include <latan/MathInterpreter.hpp>
using namespace std; using namespace std;
using namespace Latan; using namespace Latan;
@ -14,7 +14,7 @@
%locations %locations
%defines %defines
%error-verbose %error-verbose
%parse-param { Latan::MathCompiler::MathParserState *state } %parse-param { Latan::MathInterpreter::MathParserState *state }
%initial-action {yylloc.last_column = 0;} %initial-action {yylloc.last_column = 0;}
%lex-param { void* scanner } %lex-param { void* scanner }
@ -42,7 +42,7 @@
%{ %{
int _math_lex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner); int _math_lex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner);
void _math_error(YYLTYPE *locp, MathCompiler::MathParserState *state, void _math_error(YYLTYPE *locp, MathInterpreter::MathParserState *state,
const char *err) const char *err)
{ {
stringstream buf; stringstream buf;