From fa5ca7273cd7725babc164d421c0b6f372151eda Mon Sep 17 00:00:00 2001 From: Antonin Portelli Date: Thu, 23 Jan 2014 15:08:18 +0100 Subject: [PATCH] math compiler support multi-expression code --- latan/MathCompiler.cpp | 159 ++++++++++++++++++++++++++++++----------- latan/MathCompiler.hpp | 79 ++++++++++++-------- latan/MathLexer.lpp | 16 +++-- latan/MathParser.ypp | 43 ++++++----- 4 files changed, 201 insertions(+), 96 deletions(-) diff --git a/latan/MathCompiler.cpp b/latan/MathCompiler.cpp index d24a68d..25c8b5a 100644 --- a/latan/MathCompiler.cpp +++ b/latan/MathCompiler.cpp @@ -5,7 +5,7 @@ using namespace std; using namespace Latan; // Math Bison/Flex parser declaration -int _math_parse(MathParserState* state); +int _math_parse(MathCompiler::MathParserState* state); /****************************************************************************** * MathNode implementation * @@ -14,6 +14,7 @@ int _math_parse(MathParserState* state); MathNode::MathNode(const string &name, const unsigned int type) : name_(name) , type_(type) +, parent_(NULL) {} MathNode::MathNode(const std::string &name, const unsigned int type,\ @@ -21,6 +22,7 @@ MathNode::MathNode(const std::string &name, const unsigned int type,\ : name_(name) , type_(type) , arg_(nArg) +, parent_(NULL) { 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) { arg_[i] = va_arg(va, MathNode*); + arg_[i]->parent_ = this; } va_end(va); } @@ -35,7 +38,7 @@ MathNode::MathNode(const std::string &name, const unsigned int type,\ // destructor ////////////////////////////////////////////////////////////////// MathNode::~MathNode(void) { - vector::iterator i; + vector::iterator 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]; } -/****************************************************************************** - * MathParserState implementation * - ******************************************************************************/ -// constructor ///////////////////////////////////////////////////////////////// -MathParserState::MathParserState(std::istream *stream, std::string *name, - MathNode **data) -: ParserState(stream, name, data) +// test //////////////////////////////////////////////////////////////////////// +bool MathNode::isRoot(void) const { - initScanner(); -} - -// destructor ////////////////////////////////////////////////////////////////// -MathParserState::~MathParserState(void) -{ - destroyScanner(); + return (parent_ == NULL); } /****************************************************************************** @@ -146,9 +138,13 @@ Pop::Pop(const string &name) : name_(name) {} + void Pop::operator()(std::stack &dStack, VarTable &vTable) { - vTable[name_] = dStack.top(); + if (!name_.empty()) + { + vTable[name_] = dStack.top(); + } dStack.pop(); } @@ -157,6 +153,24 @@ void Pop::print(std::ostream &out) const out << CODE_MOD << "pop" << CODE_MOD << name_; } +Store::Store(const string &name) +: name_(name) +{} + + +void Store::operator()(std::stack &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)\ void name::operator()(stack &dStack, VarTable &vTable __dumb)\ {\ @@ -174,8 +188,8 @@ void name::print(std::ostream &out) const\ } DEF_OP(Neg, 1, -x[0], "neg") -DEF_OP(Add, 2, x[0]+x[1], "add") -DEF_OP(Sub, 2, x[0]-x[1], "sub") +DEF_OP(Add, 2, x[0] + x[1], "add") +DEF_OP(Sub, 2, x[0] - x[1], "sub") DEF_OP(Mul, 2, x[0]*x[1], "mul") DEF_OP(Div, 2, x[0]/x[1], "div") DEF_OP(Pow, 2, pow(x[0],x[1]), "pow") @@ -197,12 +211,25 @@ ostream &Latan::operator<<(ostream &out, const VirtualProgram &prog) /****************************************************************************** * MathCompiler implementation * ******************************************************************************/ +// MathParserState constructor ///////////////////////////////////////////////// +MathCompiler::MathParserState::MathParserState(istream *stream, string *name, + vector *data) +: ParserState >(stream, name, data) +{ + initScanner(); +} + +// MathParserState destructor ////////////////////////////////////////////////// +MathCompiler::MathParserState::~MathParserState(void) +{ + destroyScanner(); +} + // constructors //////////////////////////////////////////////////////////////// MathCompiler::MathCompiler(void) : code_(NULL) , codeName_("") , state_(NULL) -, root_(NULL) , out_() , status_(Status::none) {} @@ -227,8 +254,8 @@ void MathCompiler::init(const std::string &code) } code_ = new stringstream(code); codeName_ = ""; - state_ = new MathParserState(code_, &codeName_, &root_); - status_ |= Status::initialised; + state_ = new MathParserState(code_, &codeName_, &expr_); + status_ = Status::initialised; } const VirtualProgram& MathCompiler::operator()(void) @@ -236,10 +263,13 @@ const VirtualProgram& MathCompiler::operator()(void) if (!(status_ & Status::parsed)) { parse(); + status_ |= Status::parsed; + status_ -= status_ & Status::compiled; } if (!(status_ & Status::compiled)) { - compile(*root_); + compile(expr_); + status_ |= Status::compiled; } return out_; @@ -249,54 +279,97 @@ const VirtualProgram& MathCompiler::operator()(void) void MathCompiler::parse(void) { _math_parse(state_); - status_ |= Status::parsed; - status_ -= status_ & Status::compiled; } -#define IFOP(name, nArg) if ((n.getName() == (name))&&(n.getNArg() == nArg)) -#define ELIFOP(name, nArg) else IFOP(name, nArg) +void MathCompiler::compile(const vector &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 ELIFNODE(name, nArg) else IFNODE(name, nArg) #define ELSE else void MathCompiler::compile(const MathNode& n) { switch (n.getType()) { - case MathNode::Type::Constant: + case MathNode::Type::cst: out_.push_back(new Push(strTo(n.getName()))); break; - case MathNode::Type::Variable: + case MathNode::Type::var: out_.push_back(new Push(n.getName())); 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) { 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; default: LATAN_ERROR(Compilation, "unknown node type (node '" + n.getName() + "')"); break; } - status_ |= Status::compiled; } void MathCompiler::reset(void) { - VirtualProgram::iterator i; - delete code_; codeName_ = ""; delete state_; - delete root_; - for (i = out_.begin(); i != out_.end(); ++i) + for (vector::iterator i = expr_.begin(); i != expr_.end(); ++i) + { + delete *i; + } + expr_.clear(); + for (VirtualProgram::iterator i = out_.begin(); i != out_.end(); ++i) { delete *i; } diff --git a/latan/MathCompiler.hpp b/latan/MathCompiler.hpp index 6950973..61a8a0b 100644 --- a/latan/MathCompiler.hpp +++ b/latan/MathCompiler.hpp @@ -24,9 +24,10 @@ public: public: enum { - Constant = 0, - Operator = 1, - Variable = 2 + cst = 0, + op = 1, + var = 2, + keyw = 3 }; }; public: @@ -40,27 +41,15 @@ public: const std::string& getName(void) const; unsigned int getType(void) const; unsigned int getNArg(void) const; - // operators + // operator const MathNode &operator[](const unsigned int i) const; + // test + bool isRoot(void) const; private: - // private members - std::string name_; - unsigned int type_; - std::vector arg_; -}; - -class MathParserState: public ParserState -{ -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); + std::string name_; + unsigned int type_; + std::vector arg_; + const MathNode * parent_; }; /****************************************************************************** @@ -80,7 +69,7 @@ private: virtual void print(std::ostream &out) const = 0; }; -// push and pop +// push, pop and store class Push: public Instruction { private: @@ -120,6 +109,19 @@ private: std::string name_; }; +class Store: public Instruction +{ +public: + //constructor + explicit Store(const std::string &name); + // instruction execution + virtual void operator()(std::stack &dStack, VarTable &vTable); +private: + virtual void print(std::ostream& out) const; +private: + std::string name_; +}; + // Float operations #define DECL_OP(name)\ class name: public Instruction\ @@ -150,7 +152,23 @@ public: ******************************************************************************/ class MathCompiler { +public: + // parser state + class MathParserState: public ParserState > + { + public: + // constructor + explicit MathParserState(std::istream *stream, std::string *name, + std::vector *data); + // destructor + virtual ~MathParserState(void); + private: + // allocation/deallocation functions defined in MathLexer.lpp + virtual void initScanner(void); + virtual void destroyScanner(void); + }; private: + // status flags class Status { public: @@ -173,15 +191,16 @@ public: const VirtualProgram &operator()(void); private: void parse(void); - void compile(const MathNode& node); + void compile(const std::vector &expr); + void compile(const MathNode &node); void reset(void); private: - std::istream *code_; - std::string codeName_; - MathParserState *state_; - MathNode *root_; - VirtualProgram out_; - unsigned int status_; + std::istream *code_; + std::string codeName_; + MathParserState *state_; + std::vector expr_; + VirtualProgram out_; + unsigned int status_; }; LATAN_END_CPPDECL diff --git a/latan/MathLexer.lpp b/latan/MathLexer.lpp index 0f6f49c..4f6e53c 100644 --- a/latan/MathLexer.lpp +++ b/latan/MathLexer.lpp @@ -16,15 +16,15 @@ using namespace std; using namespace Latan; - #define YY_EXTRA_TYPE MathParserState* + #define YY_EXTRA_TYPE MathCompiler::MathParserState * #define YY_USER_ACTION \ yylloc->first_line = yylloc->last_line = yylineno;\ yylloc->first_column = yylloc->last_column + 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();\ } @@ -41,7 +41,9 @@ DIGIT [0-9] ALPHA [a-zA-Z_] FLOAT (({DIGIT}+(\.{DIGIT}*)?)|({DIGIT}*\.{DIGIT}+))([eE][+-]?{DIGIT}+)? -OP [+\-*/^] +KEYWORD return +END ; +OP [+\-*/^=] PAR [()] BLANK [ \t] @@ -52,24 +54,26 @@ BLANK [ \t] RETTOK(FLOAT); } {OP} {RET(*yytext);} +{KEYWORD} {RET(*yytext);} {PAR} {RET(*yytext);} {ALPHA}({ALPHA}|{DIGIT})* { strncpy(yylval->val_str,yytext,MAXIDLENGTH); RETTOK(ID); } +{END} {RETTOK(END);} <*>\n {yylloc->last_column = 0;} <*>{BLANK} <*>. {yylval->val_char = yytext[0]; RETTOK(ERR);} %% -void MathParserState::initScanner() +void MathCompiler::MathParserState::initScanner() { yylex_init(&scanner); yyset_extra(this, scanner); } -void MathParserState::destroyScanner() +void MathCompiler::MathParserState::destroyScanner() { yylex_destroy(scanner); } diff --git a/latan/MathParser.ypp b/latan/MathParser.ypp index 3b55026..be60b0d 100644 --- a/latan/MathParser.ypp +++ b/latan/MathParser.ypp @@ -14,7 +14,7 @@ %locations %defines %error-verbose -%parse-param { Latan::MathParserState* state } +%parse-param { Latan::MathCompiler::MathParserState *state } %initial-action {yylloc.last_column = 0;} %lex-param { void* scanner } @@ -23,30 +23,34 @@ double val_double; char val_char; char val_str[MAXIDLENGTH]; - Latan::MathNode* val_nodept; + Latan::MathNode *val_node; } +%token END %token ERR %token FLOAT %token ID +%token KEYWORD +%left '=' %left '+' '-' %left '*' '/' %left '^' %nonassoc UMINUS -%type expr +%type 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; - buf << *state->streamName << ":" << locp->first_line << ":"\ + buf << *(state->streamName) << ":" << locp->first_line << ":"\ << locp->first_column << ": " << err; - LATAN_ERROR(Parsing,buf.str()); + LATAN_ERROR(Parsing, buf.str()); } #define scanner state->scanner @@ -56,25 +60,30 @@ program: /* empty string */ - | expr {*state->data = $1;} + | program expr END {state->data->push_back($2);} ; expr: FLOAT - {$$ = new MathNode($FLOAT, MathNode::Type::Constant);} + {$$ = new MathNode($FLOAT, MathNode::Type::cst);} | 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 - {$$ = 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 - {$$ = new MathNode("+", MathNode::Type::Operator, 2, $1, $3);} + {$$ = new MathNode("+", MathNode::Type::op, 2, $1, $3);} | expr '-' expr - {$$ = new MathNode("-", MathNode::Type::Operator, 2, $1, $3);} + {$$ = new MathNode("-", MathNode::Type::op, 2, $1, $3);} | expr '*' expr - {$$ = new MathNode("*", MathNode::Type::Operator, 2, $1, $3);} + {$$ = new MathNode("*", MathNode::Type::op, 2, $1, $3);} | expr '/' expr - {$$ = new MathNode("/", MathNode::Type::Operator, 2, $1, $3);} + {$$ = new MathNode("/", MathNode::Type::op, 2, $1, $3);} | expr '^' expr - {$$ = new MathNode("^", MathNode::Type::Operator, 2, $1, $3);} - | '(' expr ')' {$$ = $2;} + {$$ = new MathNode("^", MathNode::Type::op, 2, $1, $3);} + | '(' expr ')' + {$$ = $2;} ;