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

math compiler support multi-expression code

This commit is contained in:
Antonin Portelli 2014-01-23 15:08:18 +01:00
parent 119c2bf31d
commit fa5ca7273c
4 changed files with 201 additions and 96 deletions

View File

@ -5,7 +5,7 @@ using namespace std;
using namespace Latan; using namespace Latan;
// Math Bison/Flex parser declaration // Math Bison/Flex parser declaration
int _math_parse(MathParserState* state); int _math_parse(MathCompiler::MathParserState* state);
/****************************************************************************** /******************************************************************************
* MathNode implementation * * MathNode implementation *
@ -14,6 +14,7 @@ int _math_parse(MathParserState* state);
MathNode::MathNode(const string &name, const unsigned int type) MathNode::MathNode(const string &name, const unsigned int type)
: name_(name) : name_(name)
, type_(type) , type_(type)
, parent_(NULL)
{} {}
MathNode::MathNode(const std::string &name, const unsigned int type,\ MathNode::MathNode(const std::string &name, const unsigned int type,\
@ -21,6 +22,7 @@ MathNode::MathNode(const std::string &name, const unsigned int type,\
: name_(name) : name_(name)
, type_(type) , type_(type)
, arg_(nArg) , arg_(nArg)
, parent_(NULL)
{ {
va_list va; va_list va;
@ -28,6 +30,7 @@ MathNode::MathNode(const std::string &name, const unsigned int type,\
for (unsigned int i = 0; i < nArg; ++i) for (unsigned int i = 0; i < nArg; ++i)
{ {
arg_[i] = va_arg(va, MathNode*); arg_[i] = va_arg(va, MathNode*);
arg_[i]->parent_ = this;
} }
va_end(va); va_end(va);
} }
@ -35,7 +38,7 @@ MathNode::MathNode(const std::string &name, const unsigned int type,\
// destructor ////////////////////////////////////////////////////////////////// // destructor //////////////////////////////////////////////////////////////////
MathNode::~MathNode(void) MathNode::~MathNode(void)
{ {
vector<MathNode*>::iterator i; vector<MathNode *>::iterator i;
for (i = arg_.begin(); i != arg_.end(); ++i) for (i = arg_.begin(); i != arg_.end(); ++i)
{ {
@ -65,21 +68,10 @@ const MathNode &MathNode::operator[](const unsigned int i) const
return *arg_[i]; return *arg_[i];
} }
/****************************************************************************** // test ////////////////////////////////////////////////////////////////////////
* MathParserState implementation * bool MathNode::isRoot(void) const
******************************************************************************/
// constructor /////////////////////////////////////////////////////////////////
MathParserState::MathParserState(std::istream *stream, std::string *name,
MathNode **data)
: ParserState<MathNode *>(stream, name, data)
{ {
initScanner(); return (parent_ == NULL);
}
// destructor //////////////////////////////////////////////////////////////////
MathParserState::~MathParserState(void)
{
destroyScanner();
} }
/****************************************************************************** /******************************************************************************
@ -146,9 +138,13 @@ Pop::Pop(const string &name)
: name_(name) : name_(name)
{} {}
void Pop::operator()(std::stack<double> &dStack, VarTable &vTable) void Pop::operator()(std::stack<double> &dStack, VarTable &vTable)
{ {
vTable[name_] = dStack.top(); if (!name_.empty())
{
vTable[name_] = dStack.top();
}
dStack.pop(); dStack.pop();
} }
@ -157,6 +153,24 @@ void Pop::print(std::ostream &out) const
out << CODE_MOD << "pop" << CODE_MOD << name_; out << CODE_MOD << "pop" << CODE_MOD << name_;
} }
Store::Store(const string &name)
: name_(name)
{}
void Store::operator()(std::stack<double> &dStack, VarTable &vTable)
{
if (!name_.empty())
{
vTable[name_] = dStack.top();
}
}
void Store::print(std::ostream &out) const
{
out << CODE_MOD << "store" << CODE_MOD << name_;
}
#define DEF_OP(name, nArg, exp, insName)\ #define DEF_OP(name, nArg, exp, insName)\
void name::operator()(stack<double> &dStack, VarTable &vTable __dumb)\ void name::operator()(stack<double> &dStack, VarTable &vTable __dumb)\
{\ {\
@ -174,8 +188,8 @@ void name::print(std::ostream &out) const\
} }
DEF_OP(Neg, 1, -x[0], "neg") DEF_OP(Neg, 1, -x[0], "neg")
DEF_OP(Add, 2, x[0]+x[1], "add") DEF_OP(Add, 2, x[0] + x[1], "add")
DEF_OP(Sub, 2, x[0]-x[1], "sub") DEF_OP(Sub, 2, x[0] - x[1], "sub")
DEF_OP(Mul, 2, x[0]*x[1], "mul") 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")
@ -197,12 +211,25 @@ ostream &Latan::operator<<(ostream &out, const VirtualProgram &prog)
/****************************************************************************** /******************************************************************************
* MathCompiler implementation * * MathCompiler implementation *
******************************************************************************/ ******************************************************************************/
// MathParserState constructor /////////////////////////////////////////////////
MathCompiler::MathParserState::MathParserState(istream *stream, string *name,
vector<MathNode *> *data)
: ParserState<vector<MathNode *> >(stream, name, data)
{
initScanner();
}
// MathParserState destructor //////////////////////////////////////////////////
MathCompiler::MathParserState::~MathParserState(void)
{
destroyScanner();
}
// constructors //////////////////////////////////////////////////////////////// // constructors ////////////////////////////////////////////////////////////////
MathCompiler::MathCompiler(void) MathCompiler::MathCompiler(void)
: code_(NULL) : code_(NULL)
, codeName_("<no_code>") , codeName_("<no_code>")
, state_(NULL) , state_(NULL)
, root_(NULL)
, out_() , out_()
, status_(Status::none) , status_(Status::none)
{} {}
@ -227,8 +254,8 @@ void MathCompiler::init(const std::string &code)
} }
code_ = new stringstream(code); code_ = new stringstream(code);
codeName_ = "<string>"; codeName_ = "<string>";
state_ = new MathParserState(code_, &codeName_, &root_); state_ = new MathParserState(code_, &codeName_, &expr_);
status_ |= Status::initialised; status_ = Status::initialised;
} }
const VirtualProgram& MathCompiler::operator()(void) const VirtualProgram& MathCompiler::operator()(void)
@ -236,10 +263,13 @@ const VirtualProgram& MathCompiler::operator()(void)
if (!(status_ & Status::parsed)) if (!(status_ & Status::parsed))
{ {
parse(); parse();
status_ |= Status::parsed;
status_ -= status_ & Status::compiled;
} }
if (!(status_ & Status::compiled)) if (!(status_ & Status::compiled))
{ {
compile(*root_); compile(expr_);
status_ |= Status::compiled;
} }
return out_; return out_;
@ -249,54 +279,97 @@ const VirtualProgram& MathCompiler::operator()(void)
void MathCompiler::parse(void) void MathCompiler::parse(void)
{ {
_math_parse(state_); _math_parse(state_);
status_ |= Status::parsed;
status_ -= status_ & Status::compiled;
} }
#define IFOP(name, nArg) if ((n.getName() == (name))&&(n.getNArg() == nArg)) void MathCompiler::compile(const vector<MathNode *> &expr)
#define ELIFOP(name, nArg) else IFOP(name, nArg) {
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 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()) switch (n.getType())
{ {
case MathNode::Type::Constant: case MathNode::Type::cst:
out_.push_back(new Push(strTo<double>(n.getName()))); out_.push_back(new Push(strTo<double>(n.getName())));
break; break;
case MathNode::Type::Variable: case MathNode::Type::var:
out_.push_back(new Push(n.getName())); out_.push_back(new Push(n.getName()));
break; break;
case MathNode::Type::Operator: case MathNode::Type::op:
if (n.getName() == "=")
{
compile(n[1]);
if (n.isRoot())
{
out_.push_back(new Pop(n[0].getName()));
}
else
{
out_.push_back(new Store(n[0].getName()));
}
}
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 (node '"
+ n.getName() + "')");
}
break;
case MathNode::Type::keyw:
for (unsigned int i = 0; i < n.getNArg(); ++i) for (unsigned int i = 0; i < n.getNArg(); ++i)
{ {
compile(n[i]); compile(n[i]);
} }
IFOP("-",1) out_.push_back(new Neg);
ELIFOP("+",2) out_.push_back(new Add);
ELIFOP("-",2) out_.push_back(new Sub);
ELIFOP("*",2) out_.push_back(new Mul);
ELIFOP("/",2) out_.push_back(new Div);
ELIFOP("^",2) out_.push_back(new Pow);
ELSE LATAN_ERROR(Compilation,
"unknown operator (node '" + n.getName() + "')");
break; break;
default: default:
LATAN_ERROR(Compilation, LATAN_ERROR(Compilation,
"unknown node type (node '" + n.getName() + "')"); "unknown node type (node '" + n.getName() + "')");
break; break;
} }
status_ |= Status::compiled;
} }
void MathCompiler::reset(void) void MathCompiler::reset(void)
{ {
VirtualProgram::iterator i;
delete code_; delete code_;
codeName_ = "<no_code>"; codeName_ = "<no_code>";
delete state_; delete state_;
delete root_; for (vector<MathNode *>::iterator i = expr_.begin(); i != expr_.end(); ++i)
for (i = out_.begin(); i != out_.end(); ++i) {
delete *i;
}
expr_.clear();
for (VirtualProgram::iterator i = out_.begin(); i != out_.end(); ++i)
{ {
delete *i; delete *i;
} }

View File

@ -24,9 +24,10 @@ public:
public: public:
enum enum
{ {
Constant = 0, cst = 0,
Operator = 1, op = 1,
Variable = 2 var = 2,
keyw = 3
}; };
}; };
public: public:
@ -40,27 +41,15 @@ public:
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;
// operators // operator
const MathNode &operator[](const unsigned int i) const; const MathNode &operator[](const unsigned int i) const;
// test
bool isRoot(void) const;
private: private:
// private members std::string name_;
std::string name_; unsigned int type_;
unsigned int type_; std::vector<MathNode *> arg_;
std::vector<MathNode*> arg_; const MathNode * parent_;
};
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);
}; };
/****************************************************************************** /******************************************************************************
@ -80,7 +69,7 @@ private:
virtual void print(std::ostream &out) const = 0; virtual void print(std::ostream &out) const = 0;
}; };
// push and pop // push, pop and store
class Push: public Instruction class Push: public Instruction
{ {
private: private:
@ -120,6 +109,19 @@ private:
std::string name_; std::string name_;
}; };
class Store: public Instruction
{
public:
//constructor
explicit Store(const std::string &name);
// instruction execution
virtual void operator()(std::stack<double> &dStack, VarTable &vTable);
private:
virtual void print(std::ostream& out) const;
private:
std::string name_;
};
// Float operations // Float operations
#define DECL_OP(name)\ #define DECL_OP(name)\
class name: public Instruction\ class name: public Instruction\
@ -150,7 +152,23 @@ public:
******************************************************************************/ ******************************************************************************/
class MathCompiler class MathCompiler
{ {
public:
// parser state
class MathParserState: public ParserState<std::vector<MathNode *> >
{
public:
// constructor
explicit MathParserState(std::istream *stream, std::string *name,
std::vector<MathNode *> *data);
// destructor
virtual ~MathParserState(void);
private:
// allocation/deallocation functions defined in MathLexer.lpp
virtual void initScanner(void);
virtual void destroyScanner(void);
};
private: private:
// status flags
class Status class Status
{ {
public: public:
@ -173,15 +191,16 @@ public:
const VirtualProgram &operator()(void); const VirtualProgram &operator()(void);
private: private:
void parse(void); void parse(void);
void compile(const MathNode& node); void compile(const std::vector<MathNode *> &expr);
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_;
MathNode *root_; std::vector<MathNode *> expr_;
VirtualProgram out_; VirtualProgram out_;
unsigned int status_; unsigned int status_;
}; };
LATAN_END_CPPDECL LATAN_END_CPPDECL

View File

@ -16,15 +16,15 @@
using namespace std; using namespace std;
using namespace Latan; using namespace Latan;
#define YY_EXTRA_TYPE MathParserState* #define YY_EXTRA_TYPE MathCompiler::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;\
yylloc->last_column = yylloc->first_column + yyleng - 1; yylloc->last_column = yylloc->first_column + yyleng - 1;
#define YY_INPUT(buf,result,max_size) \ #define YY_INPUT(buf, result, max_size) \
{ \ { \
(*yyextra->stream).read(buf,max_size);\ (*yyextra->stream).read(buf, max_size);\
result = (*yyextra->stream).gcount();\ result = (*yyextra->stream).gcount();\
} }
@ -41,7 +41,9 @@
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}+)?
OP [+\-*/^] KEYWORD return
END ;
OP [+\-*/^=]
PAR [()] PAR [()]
BLANK [ \t] BLANK [ \t]
@ -52,24 +54,26 @@ BLANK [ \t]
RETTOK(FLOAT); RETTOK(FLOAT);
} }
{OP} {RET(*yytext);} {OP} {RET(*yytext);}
{KEYWORD} {RET(*yytext);}
{PAR} {RET(*yytext);} {PAR} {RET(*yytext);}
{ALPHA}({ALPHA}|{DIGIT})* { {ALPHA}({ALPHA}|{DIGIT})* {
strncpy(yylval->val_str,yytext,MAXIDLENGTH); strncpy(yylval->val_str,yytext,MAXIDLENGTH);
RETTOK(ID); RETTOK(ID);
} }
{END} {RETTOK(END);}
<*>\n {yylloc->last_column = 0;} <*>\n {yylloc->last_column = 0;}
<*>{BLANK} <*>{BLANK}
<*>. {yylval->val_char = yytext[0]; RETTOK(ERR);} <*>. {yylval->val_char = yytext[0]; RETTOK(ERR);}
%% %%
void MathParserState::initScanner() void MathCompiler::MathParserState::initScanner()
{ {
yylex_init(&scanner); yylex_init(&scanner);
yyset_extra(this, scanner); yyset_extra(this, scanner);
} }
void MathParserState::destroyScanner() void MathCompiler::MathParserState::destroyScanner()
{ {
yylex_destroy(scanner); yylex_destroy(scanner);
} }

View File

@ -14,7 +14,7 @@
%locations %locations
%defines %defines
%error-verbose %error-verbose
%parse-param { Latan::MathParserState* state } %parse-param { Latan::MathCompiler::MathParserState *state }
%initial-action {yylloc.last_column = 0;} %initial-action {yylloc.last_column = 0;}
%lex-param { void* scanner } %lex-param { void* scanner }
@ -23,30 +23,34 @@
double val_double; double val_double;
char val_char; char val_char;
char val_str[MAXIDLENGTH]; char val_str[MAXIDLENGTH];
Latan::MathNode* val_nodept; Latan::MathNode *val_node;
} }
%token END
%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
%left '='
%left '+' '-' %left '+' '-'
%left '*' '/' %left '*' '/'
%left '^' %left '^'
%nonassoc UMINUS %nonassoc UMINUS
%type <val_nodept> expr %type <val_node> expr
%{ %{
int _math_lex(YYSTYPE* lvalp, YYLTYPE* llocp, void* scanner); int _math_lex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner);
void _math_error(YYLTYPE* locp, MathParserState* state, const char* err) void _math_error(YYLTYPE *locp, MathCompiler::MathParserState *state,
const char *err)
{ {
stringstream buf; stringstream buf;
buf << *state->streamName << ":" << locp->first_line << ":"\ buf << *(state->streamName) << ":" << locp->first_line << ":"\
<< locp->first_column << ": " << err; << locp->first_column << ": " << err;
LATAN_ERROR(Parsing,buf.str()); LATAN_ERROR(Parsing, buf.str());
} }
#define scanner state->scanner #define scanner state->scanner
@ -56,25 +60,30 @@
program: program:
/* empty string */ /* empty string */
| expr {*state->data = $1;} | program expr END {state->data->push_back($2);}
; ;
expr: expr:
FLOAT FLOAT
{$$ = new MathNode($FLOAT, MathNode::Type::Constant);} {$$ = new MathNode($FLOAT, MathNode::Type::cst);}
| ID | ID
{$$ = new MathNode($ID,MathNode::Type::Variable);} {$$ = new MathNode($ID,MathNode::Type::var);}
| 'r' expr
{$$ = new MathNode("return", MathNode::Type::keyw, 1, $2);}
| '-' expr %prec UMINUS | '-' expr %prec UMINUS
{$$ = new MathNode("-", MathNode::Type::Operator, 1,$2);} {$$ = new MathNode("-", MathNode::Type::op, 1, $2);}
| expr '=' expr
{$$ = new MathNode("=", MathNode::Type::op, 2, $1, $3);}
| expr '+' expr | expr '+' expr
{$$ = new MathNode("+", MathNode::Type::Operator, 2, $1, $3);} {$$ = new MathNode("+", MathNode::Type::op, 2, $1, $3);}
| expr '-' expr | expr '-' expr
{$$ = new MathNode("-", MathNode::Type::Operator, 2, $1, $3);} {$$ = new MathNode("-", MathNode::Type::op, 2, $1, $3);}
| expr '*' expr | expr '*' expr
{$$ = new MathNode("*", MathNode::Type::Operator, 2, $1, $3);} {$$ = new MathNode("*", MathNode::Type::op, 2, $1, $3);}
| expr '/' expr | expr '/' expr
{$$ = new MathNode("/", MathNode::Type::Operator, 2, $1, $3);} {$$ = new MathNode("/", MathNode::Type::op, 2, $1, $3);}
| expr '^' expr | expr '^' expr
{$$ = new MathNode("^", MathNode::Type::Operator, 2, $1, $3);} {$$ = new MathNode("^", MathNode::Type::op, 2, $1, $3);}
| '(' expr ')' {$$ = $2;} | '(' expr ')'
{$$ = $2;}
; ;