1
0
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:
Antonin Portelli 2014-02-18 18:11:08 +00:00
parent 1d59b50681
commit 3510898ee9
3 changed files with 308 additions and 305 deletions

View File

@ -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)
{ {

View File

@ -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_;
}; };

View File

@ -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);}
; ;