mirror of
https://github.com/aportelli/LatAnalyze.git
synced 2024-11-10 00:45:36 +00:00
Math interpreter: rewriting of the compiler using AST with polymorphic nodes
This commit is contained in:
parent
1d59b50681
commit
3510898ee9
@ -23,125 +23,13 @@
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace Latan;
|
using namespace Latan;
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
* MathNode implementation *
|
|
||||||
******************************************************************************/
|
|
||||||
// constructors ////////////////////////////////////////////////////////////////
|
|
||||||
MathNode::MathNode(const string &name, const Type type)
|
|
||||||
: name_(name)
|
|
||||||
, type_(type)
|
|
||||||
, parent_(nullptr)
|
|
||||||
{}
|
|
||||||
|
|
||||||
MathNode::MathNode(const std::string &name, const Type type,\
|
|
||||||
const unsigned int nArg, ...)
|
|
||||||
: name_(name)
|
|
||||||
, type_(type)
|
|
||||||
, arg_(nArg)
|
|
||||||
, parent_(nullptr)
|
|
||||||
{
|
|
||||||
va_list va;
|
|
||||||
|
|
||||||
va_start(va, nArg);
|
|
||||||
for (unsigned int i = 0; i < nArg; ++i)
|
|
||||||
{
|
|
||||||
arg_[i].reset(va_arg(va, MathNode *));
|
|
||||||
arg_[i]->parent_ = this;
|
|
||||||
}
|
|
||||||
va_end(va);
|
|
||||||
}
|
|
||||||
|
|
||||||
// destructor //////////////////////////////////////////////////////////////////
|
|
||||||
MathNode::~MathNode(void)
|
|
||||||
{}
|
|
||||||
|
|
||||||
// access //////////////////////////////////////////////////////////////////////
|
|
||||||
const string &MathNode::getName(void) const
|
|
||||||
{
|
|
||||||
return name_;
|
|
||||||
}
|
|
||||||
|
|
||||||
MathNode::Type 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(unique_ptr<MathNode>(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 " << static_cast<int>(n.getType())
|
|
||||||
<< ")" << endl;
|
|
||||||
for (unsigned int i = 0; i < n.getNArg(); ++i)
|
|
||||||
{
|
|
||||||
out << n[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Instruction set *
|
* Instruction set *
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
#define CODE_WIDTH 6
|
#define CODE_WIDTH 6
|
||||||
#define CODE_MOD setw(CODE_WIDTH) << left
|
#define CODE_MOD setw(CODE_WIDTH) << left
|
||||||
|
|
||||||
Instruction::~Instruction(void)
|
// Instruction operator ////////////////////////////////////////////////////////
|
||||||
{}
|
|
||||||
|
|
||||||
ostream &Latan::operator<<(ostream& out, const Instruction& ins)
|
ostream &Latan::operator<<(ostream& out, const Instruction& ins)
|
||||||
{
|
{
|
||||||
ins.print(out);
|
ins.print(out);
|
||||||
@ -149,6 +37,7 @@ ostream &Latan::operator<<(ostream& out, const Instruction& ins)
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Push constructors ///////////////////////////////////////////////////////////
|
||||||
Push::Push(const double val)
|
Push::Push(const double val)
|
||||||
: type_(ArgType::Constant)
|
: type_(ArgType::Constant)
|
||||||
, val_(val)
|
, val_(val)
|
||||||
@ -161,6 +50,7 @@ Push::Push(const string &name)
|
|||||||
, name_(name)
|
, name_(name)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
// Push execution //////////////////////////////////////////////////////////////
|
||||||
void Push::operator()(RunContext &context) const
|
void Push::operator()(RunContext &context) const
|
||||||
{
|
{
|
||||||
if (type_ == ArgType::Constant)
|
if (type_ == ArgType::Constant)
|
||||||
@ -181,6 +71,7 @@ void Push::operator()(RunContext &context) const
|
|||||||
context.insIndex++;
|
context.insIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Push print //////////////////////////////////////////////////////////////////
|
||||||
void Push::print(ostream &out) const
|
void Push::print(ostream &out) const
|
||||||
{
|
{
|
||||||
out << CODE_MOD << "push";
|
out << CODE_MOD << "push";
|
||||||
@ -194,10 +85,12 @@ void Push::print(ostream &out) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pop constructor /////////////////////////////////////////////////////////////
|
||||||
Pop::Pop(const string &name)
|
Pop::Pop(const string &name)
|
||||||
: name_(name)
|
: name_(name)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
// Pop execution ///////////////////////////////////////////////////////////////
|
||||||
void Pop::operator()(RunContext &context) const
|
void Pop::operator()(RunContext &context) const
|
||||||
{
|
{
|
||||||
if (!name_.empty())
|
if (!name_.empty())
|
||||||
@ -208,15 +101,18 @@ void Pop::operator()(RunContext &context) const
|
|||||||
context.insIndex++;
|
context.insIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pop print ///////////////////////////////////////////////////////////////////
|
||||||
void Pop::print(ostream &out) const
|
void Pop::print(ostream &out) const
|
||||||
{
|
{
|
||||||
out << CODE_MOD << "pop" << CODE_MOD << name_;
|
out << CODE_MOD << "pop" << CODE_MOD << name_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store constructor ///////////////////////////////////////////////////////////
|
||||||
Store::Store(const string &name)
|
Store::Store(const string &name)
|
||||||
: name_(name)
|
: name_(name)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
// Store execution /////////////////////////////////////////////////////////////
|
||||||
void Store::operator()(RunContext &context) const
|
void Store::operator()(RunContext &context) const
|
||||||
{
|
{
|
||||||
if (!name_.empty())
|
if (!name_.empty())
|
||||||
@ -226,15 +122,18 @@ void Store::operator()(RunContext &context) const
|
|||||||
context.insIndex++;
|
context.insIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store print /////////////////////////////////////////////////////////////////
|
||||||
void Store::print(ostream &out) const
|
void Store::print(ostream &out) const
|
||||||
{
|
{
|
||||||
out << CODE_MOD << "store" << CODE_MOD << name_;
|
out << CODE_MOD << "store" << CODE_MOD << name_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Call constructor ////////////////////////////////////////////////////////////
|
||||||
Call::Call(const string &name)
|
Call::Call(const string &name)
|
||||||
: name_(name)
|
: name_(name)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
// Call execution //////////////////////////////////////////////////////////////
|
||||||
void Call::operator()(RunContext &context) const
|
void Call::operator()(RunContext &context) const
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -248,11 +147,13 @@ void Call::operator()(RunContext &context) const
|
|||||||
context.insIndex++;
|
context.insIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Call print //////////////////////////////////////////////////////////////////
|
||||||
void Call::print(ostream &out) const
|
void Call::print(ostream &out) const
|
||||||
{
|
{
|
||||||
out << CODE_MOD << "call" << CODE_MOD << name_;
|
out << CODE_MOD << "call" << CODE_MOD << name_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Math operations /////////////////////////////////////////////////////////////
|
||||||
#define DEF_OP(name, nArg, exp, insName)\
|
#define DEF_OP(name, nArg, exp, insName)\
|
||||||
void name::operator()(RunContext &context) const\
|
void name::operator()(RunContext &context) const\
|
||||||
{\
|
{\
|
||||||
@ -277,13 +178,199 @@ DEF_OP(Mul, 2, x[0]*x[1], "mul")
|
|||||||
DEF_OP(Div, 2, x[0]/x[1], "div")
|
DEF_OP(Div, 2, x[0]/x[1], "div")
|
||||||
DEF_OP(Pow, 2, pow(x[0],x[1]), "pow")
|
DEF_OP(Pow, 2, pow(x[0],x[1]), "pow")
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* ExprNode implementation *
|
||||||
|
******************************************************************************/
|
||||||
|
// ExprNode constructors ///////////////////////////////////////////////////////
|
||||||
|
ExprNode::ExprNode(const string &name)
|
||||||
|
: name_(name)
|
||||||
|
, parent_(nullptr)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// ExprNode access /////////////////////////////////////////////////////////////
|
||||||
|
const string &ExprNode::getName(void) const
|
||||||
|
{
|
||||||
|
return name_;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int ExprNode::getNArg(void) const
|
||||||
|
{
|
||||||
|
return static_cast<unsigned int>(arg_.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
const ExprNode * ExprNode::getParent(void) const
|
||||||
|
{
|
||||||
|
return parent_;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int ExprNode::getLevel(void) const
|
||||||
|
{
|
||||||
|
if (getParent())
|
||||||
|
{
|
||||||
|
return getParent()->getLevel() + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExprNode::setName(const std::string &name)
|
||||||
|
{
|
||||||
|
name_ = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExprNode::pushArg(ExprNode *node)
|
||||||
|
{
|
||||||
|
if (node)
|
||||||
|
{
|
||||||
|
node->parent_ = this;
|
||||||
|
arg_.push_back(unique_ptr<ExprNode>(node));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExprNode operators //////////////////////////////////////////////////////////
|
||||||
|
const ExprNode &ExprNode::operator[](const unsigned int i) const
|
||||||
|
{
|
||||||
|
return *arg_[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
ostream &Latan::operator<<(ostream &out, const ExprNode &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() << endl;
|
||||||
|
for (unsigned int i = 0; i < n.getNArg(); ++i)
|
||||||
|
{
|
||||||
|
out << n[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PUSH_INS(program, type, ...) \
|
||||||
|
program.push_back(unique_ptr<type>(new type(__VA_ARGS__)))
|
||||||
|
|
||||||
|
// VarNode compile /////////////////////////////////////////////////////////////
|
||||||
|
void VarNode::compile(Program &program) const
|
||||||
|
{
|
||||||
|
PUSH_INS(program, Push, getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
// CstNode compile /////////////////////////////////////////////////////////////
|
||||||
|
void CstNode::compile(Program &program) const
|
||||||
|
{
|
||||||
|
PUSH_INS(program, Push, strTo<double>(getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// SemicolonNode compile ///////////////////////////////////////////////////////
|
||||||
|
void SemicolonNode::compile(Program &program) const
|
||||||
|
{
|
||||||
|
auto &n = *this;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < getNArg(); ++i)
|
||||||
|
{
|
||||||
|
bool isAssign = isDerivedFrom<AssignNode>(&n[i]);
|
||||||
|
bool isSemiColumn = isDerivedFrom<SemicolonNode>(&n[i]);
|
||||||
|
bool isKeyword = isDerivedFrom<KeywordNode>(&n[i]);
|
||||||
|
|
||||||
|
if (isAssign||isSemiColumn||isKeyword)
|
||||||
|
{
|
||||||
|
n[i].compile(program);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssignNode compile //////////////////////////////////////////////////////////
|
||||||
|
void AssignNode::compile(Program &program) const
|
||||||
|
{
|
||||||
|
auto &n = *this;
|
||||||
|
|
||||||
|
if (isDerivedFrom<VarNode>(&n[0]))
|
||||||
|
{
|
||||||
|
bool hasSemicolonParent = isDerivedFrom<SemicolonNode>(getParent());
|
||||||
|
|
||||||
|
n[1].compile(program);
|
||||||
|
if (hasSemicolonParent)
|
||||||
|
{
|
||||||
|
PUSH_INS(program, Pop, n[0].getName());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PUSH_INS(program, Store, n[0].getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LATAN_ERROR(Compilation, "invalid LHS for '='");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MathOpNode compile //////////////////////////////////////////////////////////
|
||||||
|
#define IFNODE(name, nArg) if ((n.getName() == (name))&&(n.getNArg() == nArg))
|
||||||
|
#define ELIFNODE(name, nArg) else IFNODE(name, nArg)
|
||||||
|
#define ELSE else
|
||||||
|
|
||||||
|
void MathOpNode::compile(Program &program) const
|
||||||
|
{
|
||||||
|
auto &n = *this;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < n.getNArg(); ++i)
|
||||||
|
{
|
||||||
|
n[i].compile(program);
|
||||||
|
}
|
||||||
|
IFNODE("-", 1) PUSH_INS(program, Neg,);
|
||||||
|
ELIFNODE("+", 2) PUSH_INS(program, Add,);
|
||||||
|
ELIFNODE("-", 2) PUSH_INS(program, Sub,);
|
||||||
|
ELIFNODE("*", 2) PUSH_INS(program, Mul,);
|
||||||
|
ELIFNODE("/", 2) PUSH_INS(program, Div,);
|
||||||
|
ELIFNODE("^", 2) PUSH_INS(program, Pow,);
|
||||||
|
ELSE LATAN_ERROR(Compilation, "unknown operator '" + getName() + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
// FuncNode compile ////////////////////////////////////////////////////////////
|
||||||
|
void FuncNode::compile(Program &program) const
|
||||||
|
{
|
||||||
|
auto &n = *this;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < n.getNArg(); ++i)
|
||||||
|
{
|
||||||
|
n[i].compile(program);
|
||||||
|
}
|
||||||
|
PUSH_INS(program, Call, getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReturnNode compile ////////////////////////////////////////////////////////////
|
||||||
|
void ReturnNode::compile(Program &program) const
|
||||||
|
{
|
||||||
|
auto &n = *this;
|
||||||
|
|
||||||
|
n[0].compile(program);
|
||||||
|
program.push_back(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* MathInterpreter implementation *
|
* MathInterpreter implementation *
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
// MathParserState constructor /////////////////////////////////////////////////
|
// MathParserState constructor /////////////////////////////////////////////////
|
||||||
MathInterpreter::MathParserState::MathParserState
|
MathInterpreter::MathParserState::MathParserState
|
||||||
(istream *stream, string *name, std::unique_ptr<MathNode> *data)
|
(istream *stream, string *name, std::unique_ptr<ExprNode> *data)
|
||||||
: ParserState<std::unique_ptr<MathNode>>(stream, name, data)
|
: ParserState<std::unique_ptr<ExprNode>>(stream, name, data)
|
||||||
{
|
{
|
||||||
initScanner();
|
initScanner();
|
||||||
}
|
}
|
||||||
@ -300,7 +387,6 @@ MathInterpreter::MathInterpreter(void)
|
|||||||
, codeName_("<no_code>")
|
, codeName_("<no_code>")
|
||||||
, state_(nullptr)
|
, state_(nullptr)
|
||||||
, root_(nullptr)
|
, root_(nullptr)
|
||||||
, gotReturn_(false)
|
|
||||||
, status_(Status::none)
|
, status_(Status::none)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@ -309,7 +395,6 @@ MathInterpreter::MathInterpreter(const std::string &code)
|
|||||||
, codeName_("<string>")
|
, codeName_("<string>")
|
||||||
, state_(nullptr)
|
, state_(nullptr)
|
||||||
, root_(nullptr)
|
, root_(nullptr)
|
||||||
, gotReturn_(false)
|
|
||||||
, status_(Status::none)
|
, status_(Status::none)
|
||||||
{
|
{
|
||||||
setCode(code);
|
setCode(code);
|
||||||
@ -325,7 +410,7 @@ const Instruction * MathInterpreter::operator[](const unsigned int i) const
|
|||||||
return program_[i].get();
|
return program_[i].get();
|
||||||
}
|
}
|
||||||
|
|
||||||
const MathNode * MathInterpreter::getAST(void) const
|
const ExprNode * MathInterpreter::getAST(void) const
|
||||||
{
|
{
|
||||||
return root_.get();
|
return root_.get();
|
||||||
}
|
}
|
||||||
@ -345,6 +430,7 @@ void MathInterpreter::setCode(const std::string &code)
|
|||||||
code_.reset(new stringstream(code));
|
code_.reset(new stringstream(code));
|
||||||
codeName_ = "<string>";
|
codeName_ = "<string>";
|
||||||
state_.reset(new MathParserState(code_.get(), &codeName_, &root_));
|
state_.reset(new MathParserState(code_.get(), &codeName_, &root_));
|
||||||
|
program_.clear();
|
||||||
status_ = Status::initialised;
|
status_ = Status::initialised;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,139 +457,36 @@ void MathInterpreter::parse(void)
|
|||||||
// interpreter /////////////////////////////////////////////////////////////////
|
// interpreter /////////////////////////////////////////////////////////////////
|
||||||
void MathInterpreter::compile(void)
|
void MathInterpreter::compile(void)
|
||||||
{
|
{
|
||||||
|
bool gotReturn = false;
|
||||||
|
|
||||||
if (!(status_ & Status::parsed))
|
if (!(status_ & Status::parsed))
|
||||||
{
|
{
|
||||||
parse();
|
parse();
|
||||||
status_ |= Status::parsed;
|
status_ |= Status::parsed;
|
||||||
status_ -= status_ & Status::compiled;
|
status_ -= status_ & Status::compiled;
|
||||||
}
|
}
|
||||||
gotReturn_ = false;
|
|
||||||
if (root_)
|
if (root_)
|
||||||
{
|
{
|
||||||
compileNode(*root_);
|
root_->compile(program_);
|
||||||
|
for (unsigned int i = 0; i < program_.size(); ++i)
|
||||||
|
{
|
||||||
|
if (!program_[i])
|
||||||
|
{
|
||||||
|
gotReturn = true;
|
||||||
|
program_.resize(i);
|
||||||
|
program_.shrink_to_fit();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (!root_||!gotReturn_)
|
if (!root_||!gotReturn)
|
||||||
{
|
{
|
||||||
LATAN_ERROR(Syntax, "expected 'return' in program '" + codeName_ + "'");
|
LATAN_ERROR(Syntax, "expected 'return' in program '" + codeName_ + "'");
|
||||||
}
|
}
|
||||||
status_ |= Status::compiled;
|
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
|
|
||||||
|
|
||||||
#define PUSH_INS(type, ...) \
|
|
||||||
program_.push_back(unique_ptr<type>(new (type)(__VA_ARGS__)))
|
|
||||||
|
|
||||||
void MathInterpreter::compileNode(const MathNode& n)
|
|
||||||
{
|
|
||||||
if (!gotReturn_)
|
|
||||||
{
|
|
||||||
switch (n.getType())
|
|
||||||
{
|
|
||||||
case MathNode::Type::cst:
|
|
||||||
PUSH_INS(Push, strTo<double>(n.getName()));
|
|
||||||
break;
|
|
||||||
case MathNode::Type::var:
|
|
||||||
PUSH_INS(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(unique_ptr<Pop>(new Pop(n[0].getName())));
|
|
||||||
}
|
|
||||||
// store instruction else
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PUSH_INS(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) PUSH_INS(Neg,);
|
|
||||||
ELIFNODE("+", 2) PUSH_INS(Add,);
|
|
||||||
ELIFNODE("-", 2) PUSH_INS(Sub,);
|
|
||||||
ELIFNODE("*", 2) PUSH_INS(Mul,);
|
|
||||||
ELIFNODE("/", 2) PUSH_INS(Div,);
|
|
||||||
ELIFNODE("^", 2) PUSH_INS(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]);
|
|
||||||
}
|
|
||||||
PUSH_INS(Call, n.getName());
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LATAN_ERROR(Compilation,
|
|
||||||
"unknown node type (node named '" + n.getName()
|
|
||||||
+ "')");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// execution ///////////////////////////////////////////////////////////////////
|
// execution ///////////////////////////////////////////////////////////////////
|
||||||
void MathInterpreter::operator()(RunContext &context)
|
void MathInterpreter::operator()(RunContext &context)
|
||||||
{
|
{
|
||||||
|
@ -33,47 +33,6 @@
|
|||||||
|
|
||||||
BEGIN_NAMESPACE
|
BEGIN_NAMESPACE
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
* Expression node class *
|
|
||||||
******************************************************************************/
|
|
||||||
class MathNode
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum class Type
|
|
||||||
{
|
|
||||||
undef = -1,
|
|
||||||
cst = 0,
|
|
||||||
op = 1,
|
|
||||||
var = 2,
|
|
||||||
keyw = 3,
|
|
||||||
func = 4
|
|
||||||
};
|
|
||||||
public:
|
|
||||||
// constructors
|
|
||||||
MathNode(const std::string &name, const Type type);
|
|
||||||
MathNode(const std::string &name, const Type type,
|
|
||||||
const unsigned int nArg, ...);
|
|
||||||
// destructor
|
|
||||||
virtual ~MathNode();
|
|
||||||
// access
|
|
||||||
const std::string& getName(void) const;
|
|
||||||
Type 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_;
|
|
||||||
Type type_;
|
|
||||||
std::vector<std::unique_ptr<MathNode>> arg_;
|
|
||||||
const MathNode * parent_;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &out, const MathNode &n);
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Instruction classes *
|
* Instruction classes *
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
@ -92,7 +51,8 @@ struct RunContext
|
|||||||
class Instruction
|
class Instruction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~Instruction();
|
// destructor
|
||||||
|
virtual ~Instruction(void) = default;
|
||||||
// instruction execution
|
// instruction execution
|
||||||
virtual void operator()(RunContext &context) const = 0;
|
virtual void operator()(RunContext &context) const = 0;
|
||||||
friend std::ostream & operator<<(std::ostream &out, const Instruction &ins);
|
friend std::ostream & operator<<(std::ostream &out, const Instruction &ins);
|
||||||
@ -102,6 +62,9 @@ private:
|
|||||||
|
|
||||||
std::ostream & operator<<(std::ostream &out, const Instruction &ins);
|
std::ostream & operator<<(std::ostream &out, const Instruction &ins);
|
||||||
|
|
||||||
|
// Instruction container
|
||||||
|
typedef std::vector<std::unique_ptr<const Instruction>> Program;
|
||||||
|
|
||||||
// Push
|
// Push
|
||||||
class Push: public Instruction
|
class Push: public Instruction
|
||||||
{
|
{
|
||||||
@ -184,6 +147,59 @@ DECL_OP(Mul);
|
|||||||
DECL_OP(Div);
|
DECL_OP(Div);
|
||||||
DECL_OP(Pow);
|
DECL_OP(Pow);
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* Expression node classes *
|
||||||
|
******************************************************************************/
|
||||||
|
class ExprNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// constructors
|
||||||
|
ExprNode(const std::string &name);
|
||||||
|
// destructor
|
||||||
|
virtual ~ExprNode() = default;
|
||||||
|
// access
|
||||||
|
const std::string& getName(void) const;
|
||||||
|
unsigned int getNArg(void) const;
|
||||||
|
const ExprNode * getParent(void) const;
|
||||||
|
unsigned int getLevel(void) const;
|
||||||
|
void setName(const std::string &name);
|
||||||
|
void pushArg(ExprNode *node);
|
||||||
|
// operator
|
||||||
|
const ExprNode &operator[](const unsigned int i) const;
|
||||||
|
// compile
|
||||||
|
virtual void compile(Program &program) const = 0;
|
||||||
|
private:
|
||||||
|
std::string name_;
|
||||||
|
std::vector<std::unique_ptr<ExprNode>> arg_;
|
||||||
|
const ExprNode * parent_;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ostream &operator<<(std::ostream &out, const ExprNode &n);
|
||||||
|
|
||||||
|
#define DECL_NODE(base, name) \
|
||||||
|
class name: public base\
|
||||||
|
{\
|
||||||
|
public:\
|
||||||
|
using base::base;\
|
||||||
|
virtual void compile(Program &program) const;\
|
||||||
|
}
|
||||||
|
|
||||||
|
DECL_NODE(ExprNode, VarNode);
|
||||||
|
DECL_NODE(ExprNode, CstNode);
|
||||||
|
DECL_NODE(ExprNode, SemicolonNode);
|
||||||
|
DECL_NODE(ExprNode, AssignNode);
|
||||||
|
DECL_NODE(ExprNode, MathOpNode);
|
||||||
|
DECL_NODE(ExprNode, FuncNode);
|
||||||
|
|
||||||
|
class KeywordNode: public ExprNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using ExprNode::ExprNode;
|
||||||
|
virtual void compile(Program &program) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
DECL_NODE(KeywordNode, ReturnNode);
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Interpreter class *
|
* Interpreter class *
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
@ -192,12 +208,12 @@ class MathInterpreter
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// parser state
|
// parser state
|
||||||
class MathParserState: public ParserState<std::unique_ptr<MathNode>>
|
class MathParserState: public ParserState<std::unique_ptr<ExprNode>>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// constructor
|
// constructor
|
||||||
explicit MathParserState(std::istream *stream, std::string *name,
|
explicit MathParserState(std::istream *stream, std::string *name,
|
||||||
std::unique_ptr<MathNode> *data);
|
std::unique_ptr<ExprNode> *data);
|
||||||
// destructor
|
// destructor
|
||||||
virtual ~MathParserState(void);
|
virtual ~MathParserState(void);
|
||||||
private:
|
private:
|
||||||
@ -218,8 +234,6 @@ private:
|
|||||||
compiled = 1 << 2
|
compiled = 1 << 2
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
// instruction container
|
|
||||||
typedef std::vector<std::unique_ptr<const Instruction>> Program;
|
|
||||||
public:
|
public:
|
||||||
// constructors
|
// constructors
|
||||||
MathInterpreter(void);
|
MathInterpreter(void);
|
||||||
@ -228,7 +242,7 @@ public:
|
|||||||
~MathInterpreter(void);
|
~MathInterpreter(void);
|
||||||
// access
|
// access
|
||||||
const Instruction * operator[](const unsigned int i) const;
|
const Instruction * operator[](const unsigned int i) const;
|
||||||
const MathNode * getAST(void) const;
|
const ExprNode * getAST(void) const;
|
||||||
// initialization
|
// initialization
|
||||||
void setCode(const std::string &code);
|
void setCode(const std::string &code);
|
||||||
// interpreter
|
// interpreter
|
||||||
@ -246,15 +260,14 @@ private:
|
|||||||
// parser
|
// parser
|
||||||
void parse(void);
|
void parse(void);
|
||||||
// interpreter
|
// interpreter
|
||||||
void compileNode(const MathNode &node);
|
void compileNode(const ExprNode &node);
|
||||||
// execution
|
// execution
|
||||||
void execute(RunContext &context) const;
|
void execute(RunContext &context) const;
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<std::istream> code_;
|
std::unique_ptr<std::istream> code_;
|
||||||
std::string codeName_;
|
std::string codeName_;
|
||||||
std::unique_ptr<MathParserState> state_;
|
std::unique_ptr<MathParserState> state_;
|
||||||
std::unique_ptr<MathNode> root_;
|
std::unique_ptr<ExprNode> root_;
|
||||||
bool gotReturn_;
|
|
||||||
Program program_;
|
Program program_;
|
||||||
unsigned int status_;
|
unsigned int status_;
|
||||||
};
|
};
|
||||||
|
@ -42,7 +42,7 @@
|
|||||||
double val_double;
|
double val_double;
|
||||||
char val_char;
|
char val_char;
|
||||||
char val_str[MAXIDLENGTH];
|
char val_str[MAXIDLENGTH];
|
||||||
Latan::MathNode *val_node;
|
Latan::ExprNode *val_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
%token <val_char> ERR
|
%token <val_char> ERR
|
||||||
@ -70,6 +70,16 @@
|
|||||||
<< locp->first_column << ": " << err;
|
<< locp->first_column << ": " << err;
|
||||||
LATAN_ERROR(Parsing, buf.str());
|
LATAN_ERROR(Parsing, buf.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _math_warning(YYLTYPE *locp, MathInterpreter::MathParserState *state,
|
||||||
|
const char *err)
|
||||||
|
{
|
||||||
|
stringstream buf;
|
||||||
|
|
||||||
|
buf << *(state->streamName) << ":" << locp->first_line << ":"\
|
||||||
|
<< locp->first_column << ": " << err;
|
||||||
|
LATAN_WARNING(buf.str());
|
||||||
|
}
|
||||||
|
|
||||||
#define scanner state->scanner
|
#define scanner state->scanner
|
||||||
%}
|
%}
|
||||||
@ -83,16 +93,13 @@ program:
|
|||||||
|
|
||||||
stmt:
|
stmt:
|
||||||
';'
|
';'
|
||||||
{$$ = new MathNode(";", MathNode::Type::op, 0);}
|
{$$ = new SemicolonNode(";");}
|
||||||
| expr ';'
|
| expr ';'
|
||||||
{$$ = $1;}
|
{$$ = nullptr; _math_warning(&yylloc, state, "useless statement removed");}
|
||||||
| ID '=' expr ';'
|
| ID '=' expr ';'
|
||||||
{
|
{$$ = new AssignNode("="); $$->pushArg(new VarNode($ID)); $$->pushArg($3);}
|
||||||
$$ = new MathNode("=", MathNode::Type::op, 2, \
|
|
||||||
new MathNode($ID,MathNode::Type::var), $3);
|
|
||||||
}
|
|
||||||
| RETURN expr ';'
|
| RETURN expr ';'
|
||||||
{$$ = new MathNode("return", MathNode::Type::keyw, 1, $2);}
|
{$$ = new ReturnNode("return"); $$->pushArg($2);}
|
||||||
| '{' stmt_list '}'
|
| '{' stmt_list '}'
|
||||||
{$$ = $2;}
|
{$$ = $2;}
|
||||||
;
|
;
|
||||||
@ -101,26 +108,26 @@ stmt_list:
|
|||||||
stmt
|
stmt
|
||||||
{$$ = $1;}
|
{$$ = $1;}
|
||||||
| stmt_list stmt
|
| stmt_list stmt
|
||||||
{$$ = new MathNode(";", MathNode::Type::op, 2, $1, $2);}
|
{$$ = new SemicolonNode(";"); $$->pushArg($1); $$->pushArg($2);}
|
||||||
;
|
;
|
||||||
|
|
||||||
expr:
|
expr:
|
||||||
FLOAT
|
FLOAT
|
||||||
{$$ = new MathNode($FLOAT, MathNode::Type::cst);}
|
{$$ = new CstNode($FLOAT);}
|
||||||
| ID
|
| ID
|
||||||
{$$ = new MathNode($ID, MathNode::Type::var);}
|
{$$ = new VarNode($ID);}
|
||||||
| '-' expr %prec UMINUS
|
| '-' expr %prec UMINUS
|
||||||
{$$ = new MathNode("-", MathNode::Type::op, 1, $2);}
|
{$$ = new MathOpNode("-"); $$->pushArg($2);}
|
||||||
| expr '+' expr
|
| expr '+' expr
|
||||||
{$$ = new MathNode("+", MathNode::Type::op, 2, $1, $3);}
|
{$$ = new MathOpNode("+"); $$->pushArg($1); $$->pushArg($3);}
|
||||||
| expr '-' expr
|
| expr '-' expr
|
||||||
{$$ = new MathNode("-", MathNode::Type::op, 2, $1, $3);}
|
{$$ = new MathOpNode("-"); $$->pushArg($1); $$->pushArg($3);}
|
||||||
| expr '*' expr
|
| expr '*' expr
|
||||||
{$$ = new MathNode("*", MathNode::Type::op, 2, $1, $3);}
|
{$$ = new MathOpNode("*"); $$->pushArg($1); $$->pushArg($3);}
|
||||||
| expr '/' expr
|
| expr '/' expr
|
||||||
{$$ = new MathNode("/", MathNode::Type::op, 2, $1, $3);}
|
{$$ = new MathOpNode("/"); $$->pushArg($1); $$->pushArg($3);}
|
||||||
| expr '^' expr
|
| expr '^' expr
|
||||||
{$$ = new MathNode("^", MathNode::Type::op, 2, $1, $3);}
|
{$$ = new MathOpNode("^"); $$->pushArg($1); $$->pushArg($3);}
|
||||||
| '(' expr ')'
|
| '(' expr ')'
|
||||||
{$$ = $2;}
|
{$$ = $2;}
|
||||||
| ID '(' func_args ')'
|
| ID '(' func_args ')'
|
||||||
@ -129,9 +136,9 @@ expr:
|
|||||||
|
|
||||||
func_args:
|
func_args:
|
||||||
/* empty string */
|
/* empty string */
|
||||||
{$$ = new MathNode("", MathNode::Type::func);}
|
{$$ = new FuncNode("");}
|
||||||
| expr
|
| expr
|
||||||
{$$ = new MathNode("", MathNode::Type::func, 1, $1);}
|
{$$ = new FuncNode(""); $$->pushArg($1);}
|
||||||
| func_args ',' expr
|
| func_args ',' expr
|
||||||
{$$ = $1; $$->pushArg($3);}
|
{$$ = $1; $$->pushArg($3);}
|
||||||
;
|
;
|
||||||
|
Loading…
Reference in New Issue
Block a user