1
0
mirror of https://github.com/aportelli/LatAnalyze.git synced 2025-04-11 03:20:46 +01:00

math compiler fixes and improvements, now working

This commit is contained in:
Antonin Portelli 2014-02-04 17:33:58 +00:00
parent 36bc0bc9b0
commit 50d21ae904
7 changed files with 249 additions and 146 deletions

2
.gitignore vendored
View File

@ -3,7 +3,7 @@
*.a *.a
*.so *.so
*.dylib *.dylib
examples/ex_test examples/exMathCompiler
sandbox/* sandbox/*
# Apple stuffs # Apple stuffs

View File

@ -15,10 +15,10 @@ endif
endif endif
noinst_PROGRAMS = \ noinst_PROGRAMS = \
ex_test exMathCompiler
ex_test_SOURCES = ex_test.cpp exMathCompiler_SOURCES = exMathCompiler.cpp
ex_test_CFLAGS = -g -O2 exMathCompiler_CFLAGS = -g -O2
ex_test_LDFLAGS = -L../latan/.libs -llatan exMathCompiler_LDFLAGS = -L../latan/.libs -llatan
ACLOCAL_AMFLAGS = -I .buildutils/m4 ACLOCAL_AMFLAGS = -I .buildutils/m4

View File

@ -1,5 +1,5 @@
#include <iostream> #include <iostream>
#include <latan/Function.hpp> #include <latan/Math.hpp>
#include <latan/MathCompiler.hpp> #include <latan/MathCompiler.hpp>
using namespace std; using namespace std;
@ -7,22 +7,31 @@ using namespace Latan;
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
MathCompiler C(argv[1]); string source;
if (argc != 2)
{
cerr << "usage: " << argv[0] << " <program>" << endl;
}
source = argv[1];
MathCompiler C(source);
VarTable vtable; VarTable vtable;
FunctionTable ftable; FunctionTable ftable;
stack<double> dstack; stack<double> dstack;
const VirtualProgram& P = C(); const VirtualProgram& P = C();
ftable["exp"] = &StdMath::exp; cout << "-- Source code:" << endl << source << endl << endl;
ftable["atan2"] = &StdMath::atan2; cout << "-- Abstract Syntax Tree:" << endl << *C.getAST() << endl;
cout << P << endl; cout << "-- Program:" << endl << P << endl;
StdMath::addStdMathFunc(ftable);
for (unsigned int i=0;i<P.size();++i) for (unsigned int i=0;i<P.size();++i)
{ {
(*(P[i]))(dstack,vtable,ftable); (*(P[i]))(dstack, vtable, ftable);
} }
if (!dstack.empty()) if (!dstack.empty())
{ {
cout << "result= " << dstack.top() << endl; cout << "-- Result: " << dstack.top() << endl;
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;

View File

@ -62,6 +62,23 @@ unsigned int MathNode::getNArg(void) const
return static_cast<unsigned int>(arg_.size()); 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) void MathNode::setName(const std::string &name)
{ {
name_ = name; name_ = name;
@ -72,16 +89,38 @@ void MathNode::pushArg(MathNode *node)
arg_.push_back(node); arg_.push_back(node);
} }
// operator //////////////////////////////////////////////////////////////////// // operators ///////////////////////////////////////////////////////////////////
const MathNode &MathNode::operator[](const unsigned int i) const const MathNode &MathNode::operator[](const unsigned int i) const
{ {
return *arg_[i]; return *arg_[i];
} }
// test //////////////////////////////////////////////////////////////////////// ostream &Latan::operator<<(ostream &out, const MathNode &n)
bool MathNode::isRoot(void) const
{ {
return (parent_ == NULL); 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;
} }
/****************************************************************************** /******************************************************************************
@ -228,10 +267,6 @@ 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")
VirtualProgram::VirtualProgram(void)
: vector<Instruction *>(0)
{}
ostream &Latan::operator<<(ostream &out, const VirtualProgram &prog) ostream &Latan::operator<<(ostream &out, const VirtualProgram &prog)
{ {
for (unsigned int i = 0; i < prog.size(); ++i) for (unsigned int i = 0; i < prog.size(); ++i)
@ -247,8 +282,8 @@ ostream &Latan::operator<<(ostream &out, const VirtualProgram &prog)
******************************************************************************/ ******************************************************************************/
// MathParserState constructor ///////////////////////////////////////////////// // MathParserState constructor /////////////////////////////////////////////////
MathCompiler::MathParserState::MathParserState(istream *stream, string *name, MathCompiler::MathParserState::MathParserState(istream *stream, string *name,
vector<MathNode *> *data) MathNode **data)
: ParserState<vector<MathNode *> >(stream, name, data) : ParserState<MathNode *>(stream, name, data)
{ {
initScanner(); initScanner();
} }
@ -264,11 +299,16 @@ MathCompiler::MathCompiler(void)
: code_(NULL) : code_(NULL)
, codeName_("<no_code>") , codeName_("<no_code>")
, state_(NULL) , state_(NULL)
, root_(NULL)
, gotReturn_(false)
, out_() , out_()
, status_(Status::none) , status_(Status::none)
{} {}
MathCompiler::MathCompiler(const std::string &code) MathCompiler::MathCompiler(const std::string &code)
: root_(NULL)
, gotReturn_(false)
, out_()
{ {
init(code); init(code);
} }
@ -279,6 +319,19 @@ MathCompiler::~MathCompiler(void)
reset(); reset();
} }
// access //////////////////////////////////////////////////////////////////////
const MathNode * MathCompiler::getAST(void) const
{
if (root_)
{
return root_;
}
else
{
return NULL;
}
}
// public methods ////////////////////////////////////////////////////////////// // public methods //////////////////////////////////////////////////////////////
void MathCompiler::init(const std::string &code) void MathCompiler::init(const std::string &code)
{ {
@ -288,7 +341,7 @@ void MathCompiler::init(const std::string &code)
} }
code_ = new stringstream(code); code_ = new stringstream(code);
codeName_ = "<string>"; codeName_ = "<string>";
state_ = new MathParserState(code_, &codeName_, &expr_); state_ = new MathParserState(code_, &codeName_, &root_);
status_ = Status::initialised; status_ = Status::initialised;
} }
@ -302,7 +355,16 @@ const VirtualProgram& MathCompiler::operator()(void)
} }
if (!(status_ & Status::compiled)) if (!(status_ & Status::compiled))
{ {
compile(expr_); if (root_)
{
gotReturn_ = false;
compile(*root_);
if (!gotReturn_)
{
LATAN_ERROR(Syntax, "expected 'return' in program '" +
codeName_ + "'");
}
}
status_ |= Status::compiled; status_ |= Status::compiled;
} }
@ -315,95 +377,114 @@ void MathCompiler::parse(void)
_math_parse(state_); _math_parse(state_);
} }
void MathCompiler::compile(const vector<MathNode *> &expr)
{
string lastNode;
for (unsigned int i = 0; i < expr.size(); ++i)
{
lastNode = expr[i]->getName();
if ((lastNode == "=")||(lastNode == "return"))
{
compile(*expr[i]);
if (lastNode == "return")
{
break;
}
}
}
if (lastNode != "return")
{
LATAN_ERROR(Syntax, "expected 'return' in program '" + codeName_ + "'");
}
}
#define IFNODE(name, nArg) if ((n.getName() == (name))&&(n.getNArg() == nArg)) #define IFNODE(name, nArg) if ((n.getName() == (name))&&(n.getNArg() == nArg))
#define ELIFNODE(name, nArg) else IFNODE(name, nArg) #define ELIFNODE(name, nArg) else IFNODE(name, nArg)
#define ELSE else #define ELSE else
void MathCompiler::compile(const MathNode& n) void MathCompiler::compile(const MathNode& n)
{ {
switch (n.getType()) if (!gotReturn_)
{ {
case MathNode::Type::cst: switch (n.getType())
out_.push_back(new Push(strTo<double>(n.getName()))); {
break; case MathNode::Type::cst:
case MathNode::Type::var: out_.push_back(new Push(strTo<double>(n.getName())));
out_.push_back(new Push(n.getName())); break;
break; case MathNode::Type::var:
case MathNode::Type::op: out_.push_back(new Push(n.getName()));
if (n.getName() == "=") break;
{ case MathNode::Type::op:
if (n[0].getType() == MathNode::Type::var) // semicolon
if (n.getName() == ";")
{ {
compile(n[1]); // compile relevant statements
if (n.isRoot()) for (unsigned int i = 0; i < n.getNArg(); ++i)
{ {
out_.push_back(new Pop(n[0].getName())); 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)
{
compile(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
compile(n[1]);
// pop instruction if at the end of a statement
if (hasSemicolonParent)
{
out_.push_back(new Pop(n[0].getName()));
}
// store instruction else
else
{
out_.push_back(new Store(n[0].getName()));
}
} }
else else
{ {
out_.push_back(new Store(n[0].getName())); LATAN_ERROR(Compilation, "invalid LHS for '='");
} }
} }
// arithmetic operators
else
{
for (unsigned int i = 0; i < n.getNArg(); ++i)
{
compile(n[i]);
}
IFNODE("-", 1) out_.push_back(new Neg);
ELIFNODE("+", 2) out_.push_back(new Add);
ELIFNODE("-", 2) out_.push_back(new Sub);
ELIFNODE("*", 2) out_.push_back(new Mul);
ELIFNODE("/", 2) out_.push_back(new Div);
ELIFNODE("^", 2) out_.push_back(new Pow);
ELSE LATAN_ERROR(Compilation, "unknown operator '"
+ n.getName() + "'");
}
break;
case MathNode::Type::keyw:
if (n.getName() == "return")
{
compile(n[0]);
gotReturn_ = true;
}
else else
{ {
LATAN_ERROR(Compilation, "invalid LHS for '='"); LATAN_ERROR(Compilation, "unknown keyword '" + n.getName()
+ "'");
} }
} break;
else case MathNode::Type::func:
{
for (unsigned int i = 0; i < n.getNArg(); ++i) for (unsigned int i = 0; i < n.getNArg(); ++i)
{ {
compile(n[i]); compile(n[i]);
} }
IFNODE("-", 1) out_.push_back(new Neg); out_.push_back(new Call(n.getName()));
ELIFNODE("+", 2) out_.push_back(new Add); break;
ELIFNODE("-", 2) out_.push_back(new Sub); default:
ELIFNODE("*", 2) out_.push_back(new Mul); LATAN_ERROR(Compilation,
ELIFNODE("/", 2) out_.push_back(new Div); "unknown node type (node named '" + n.getName()
ELIFNODE("^", 2) out_.push_back(new Pow); + "')");
ELSE LATAN_ERROR(Compilation, "unknown operator (node '" break;
+ n.getName() + "')"); }
}
break;
case MathNode::Type::keyw:
for (unsigned int i = 0; i < n.getNArg(); ++i)
{
compile(n[i]);
}
break;
case MathNode::Type::func:
for (unsigned int i = 0; i < n.getNArg(); ++i)
{
compile(n[i]);
}
out_.push_back(new Call(n.getName()));
break;
default:
LATAN_ERROR(Compilation,
"unknown node type (node '" + n.getName() + "')");
break;
} }
} }
@ -412,11 +493,7 @@ void MathCompiler::reset(void)
delete code_; delete code_;
codeName_ = "<no_code>"; codeName_ = "<no_code>";
delete state_; delete state_;
for (vector<MathNode *>::iterator i = expr_.begin(); i != expr_.end(); ++i) delete root_;
{
delete *i;
}
expr_.clear();
for (VirtualProgram::iterator i = out_.begin(); i != out_.end(); ++i) for (VirtualProgram::iterator i = out_.begin(); i != out_.end(); ++i)
{ {
delete *i; delete *i;

View File

@ -25,11 +25,12 @@ public:
public: public:
enum enum
{ {
cst = 0, undef = -1,
op = 1, cst = 0,
var = 2, op = 1,
keyw = 3, var = 2,
func = 4 keyw = 3,
func = 4
}; };
}; };
public: public:
@ -40,15 +41,18 @@ public:
// destructor // destructor
virtual ~MathNode(); virtual ~MathNode();
// access // access
const std::string& getName(void) const; const std::string& getName(void) const;
unsigned int getType(void) const; unsigned int getType(void) const;
unsigned int getNArg(void) const; unsigned int getNArg(void) const;
const MathNode * getParent(void) const;
unsigned int getLevel(void) const;
void setName(const std::string &name); void setName(const std::string &name);
void pushArg(MathNode *node); void pushArg(MathNode *node);
// operator // operator
const MathNode &operator[](const unsigned int i) const; const MathNode &operator[](const unsigned int i) const;
// test private:
bool isRoot(void) const; // IO
std::ostream &print(std::ostream &out) const;
private: private:
std::string name_; std::string name_;
unsigned int type_; unsigned int type_;
@ -56,6 +60,8 @@ private:
const MathNode * parent_; const MathNode * parent_;
}; };
std::ostream &operator<<(std::ostream &out, const MathNode &n);
/****************************************************************************** /******************************************************************************
* Virtual machine code classes * * Virtual machine code classes *
******************************************************************************/ ******************************************************************************/
@ -166,13 +172,10 @@ DECL_OP(Mul);
DECL_OP(Div); DECL_OP(Div);
DECL_OP(Pow); DECL_OP(Pow);
class VirtualProgram: public std::vector<Instruction *> // Virtual program type
{ typedef std::vector<Instruction *> VirtualProgram;
public:
VirtualProgram(void); std::ostream &operator<<(std::ostream &out, const VirtualProgram &program);
friend std::ostream &operator<<(std::ostream &out,
const VirtualProgram &program);
};
/****************************************************************************** /******************************************************************************
* Compiler class * * Compiler class *
@ -181,12 +184,12 @@ class MathCompiler
{ {
public: public:
// parser state // parser state
class MathParserState: public ParserState<std::vector<MathNode *> > class MathParserState: public ParserState<MathNode *>
{ {
public: public:
// constructor // constructor
explicit MathParserState(std::istream *stream, std::string *name, explicit MathParserState(std::istream *stream, std::string *name,
std::vector<MathNode *> *data); MathNode **data);
// destructor // destructor
virtual ~MathParserState(void); virtual ~MathParserState(void);
private: private:
@ -213,21 +216,24 @@ public:
MathCompiler(const std::string &code); MathCompiler(const std::string &code);
// destructor // destructor
~MathCompiler(void); ~MathCompiler(void);
// access
const MathNode * getAST(void) const;
// initialization // initialization
void init(const std::string &code); void init(const std::string &code);
// compilation
const VirtualProgram &operator()(void); const VirtualProgram &operator()(void);
private: private:
void parse(void); void parse(void);
void compile(const std::vector<MathNode *> &expr);
void compile(const MathNode &node); void compile(const MathNode &node);
void reset(void); void reset(void);
private: private:
std::istream *code_; std::istream *code_;
std::string codeName_; std::string codeName_;
MathParserState *state_; MathParserState *state_;
std::vector<MathNode *> expr_; MathNode *root_;
VirtualProgram out_; bool gotReturn_;
unsigned int status_; VirtualProgram out_;
unsigned int status_;
}; };
LATAN_END_CPPDECL LATAN_END_CPPDECL

View File

@ -41,10 +41,7 @@
DIGIT [0-9] DIGIT [0-9]
ALPHA [a-zA-Z_] ALPHA [a-zA-Z_]
FLOAT (({DIGIT}+(\.{DIGIT}*)?)|({DIGIT}*\.{DIGIT}+))([eE][+-]?{DIGIT}+)? FLOAT (({DIGIT}+(\.{DIGIT}*)?)|({DIGIT}*\.{DIGIT}+))([eE][+-]?{DIGIT}+)?
KEYWORD return SPECIAL [;,()+\-*/^={}]
PUNC [;,()]
OP [+\-*/^=]
PAR []
BLANK [ \t] BLANK [ \t]
%% %%
@ -53,9 +50,8 @@ BLANK [ \t]
strncpy(yylval->val_str,yytext,MAXIDLENGTH); strncpy(yylval->val_str,yytext,MAXIDLENGTH);
RETTOK(FLOAT); RETTOK(FLOAT);
} }
{OP} {RET(*yytext);} {SPECIAL} {RET(*yytext);}
{KEYWORD} {RET(*yytext);} return {RETTOK(RETURN);}
{PUNC} {RET(*yytext);}
{ALPHA}({ALPHA}|{DIGIT})* { {ALPHA}({ALPHA}|{DIGIT})* {
strncpy(yylval->val_str,yytext,MAXIDLENGTH); strncpy(yylval->val_str,yytext,MAXIDLENGTH);
RETTOK(ID); RETTOK(ID);

View File

@ -29,7 +29,7 @@
%token <val_char> ERR %token <val_char> ERR
%token <val_str> FLOAT %token <val_str> FLOAT
%token <val_str> ID %token <val_str> ID
%token <val_str> KEYWORD %token RETURN
%left '=' %left '='
%left '+' '-' %left '+' '-'
@ -37,8 +37,7 @@
%left '^' %left '^'
%nonassoc UMINUS %nonassoc UMINUS
%type <val_node> expr %type <val_node> stmt stmt_list expr func_args
%type <val_node> funcargs
%{ %{
int _math_lex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner); int _math_lex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner);
@ -60,21 +59,37 @@
program: program:
/* empty string */ /* empty string */
| program expr ';' {state->data->push_back($2);} | stmt_list {*(state->data) = $1;}
;
stmt:
';'
{$$ = new MathNode(";", MathNode::Type::op, 0);}
| expr ';'
{$$ = $1;}
| ID '=' expr ';'
{
$$ = new MathNode("=", MathNode::Type::op, 2, \
new MathNode($ID,MathNode::Type::var), $3);
}
| RETURN expr ';'
{$$ = new MathNode("return", MathNode::Type::keyw, 1, $2);}
| '{' stmt_list '}'
{$$ = $2;}
;
stmt_list:
stmt
{$$ = $1;}
| stmt_list stmt
{$$ = new MathNode(";", MathNode::Type::op, 2, $1, $2);}
; ;
expr: expr:
FLOAT FLOAT
{$$ = new MathNode($FLOAT, MathNode::Type::cst);} {$$ = new MathNode($FLOAT, MathNode::Type::cst);}
| ID | ID
{$$ = new MathNode($ID,MathNode::Type::var);} {$$ = new MathNode($ID, MathNode::Type::var);}
| ID '=' expr
{
$$ = new MathNode("=", MathNode::Type::op, 2, \
new MathNode($ID,MathNode::Type::var), $3);
}
| 'r' expr
{$$ = new MathNode("return", MathNode::Type::keyw, 1, $2);}
| '-' expr %prec UMINUS | '-' expr %prec UMINUS
{$$ = new MathNode("-", MathNode::Type::op, 1, $2);} {$$ = new MathNode("-", MathNode::Type::op, 1, $2);}
| expr '+' expr | expr '+' expr
@ -89,16 +104,16 @@ expr:
{$$ = new MathNode("^", MathNode::Type::op, 2, $1, $3);} {$$ = new MathNode("^", MathNode::Type::op, 2, $1, $3);}
| '(' expr ')' | '(' expr ')'
{$$ = $2;} {$$ = $2;}
| ID '(' funcargs ')' | ID '(' func_args ')'
{$$ = $3; $$->setName($ID);} {$$ = $3; $$->setName($ID);}
; ;
funcargs: func_args:
/* empty string */ /* empty string */
{$$ = new MathNode("", MathNode::Type::func);} {$$ = new MathNode("", MathNode::Type::func);}
| expr | expr
{$$ = new MathNode("", MathNode::Type::func, 1, $1);} {$$ = new MathNode("", MathNode::Type::func, 1, $1);}
| funcargs ',' expr | func_args ',' expr
{$$ = $1; $$->pushArg($3);} {$$ = $1; $$->pushArg($3);}
; ;