From 0e49a86bd6f69e0eba2fe880ca69eccaf71941ec Mon Sep 17 00:00:00 2001 From: Michael Uleysky Date: Fri, 5 Aug 2016 13:32:38 +1000 Subject: [PATCH] Rewrite parser and evaluator. 1) Use plain representation of expressions instead of recursive objects. 2) Make G_tosave, G_toprint and G_vars local. 3) DepTree nodes contains expressions itself instead of references on global objects. 4) Location tracking of errors. --- include/common.h | 64 +------- include/deptree.h | 16 +- include/globals.h | 20 ++- include/init.h | 5 +- include/object.h | 147 +++++++++++-------- include/parser.h | 19 +-- src/deptree.cpp | 310 +++++++++++++++++++++++---------------- src/globals.cpp | 27 ++-- src/init.cpp | 59 +------- src/main.cpp | 48 +++--- src/object.cpp | 218 +++++++++++++++++++++++---- src/parser/grammatical.y | 95 ++++++------ src/parser/lexical.l | 3 +- 13 files changed, 576 insertions(+), 455 deletions(-) diff --git a/include/common.h b/include/common.h index b9479d3..02dea26 100644 --- a/include/common.h +++ b/include/common.h @@ -2,6 +2,7 @@ #define COMMON_H #include #include +#include #include #include #include @@ -10,7 +11,6 @@ #include #include #include -#include #define EXPORT __attribute__ ((visibility ("default"))) @@ -53,10 +53,6 @@ public: // Virtual api with default functions. Modules types must not override them. virtual std::string Dump() const {return "%"+Type()+"%";} - virtual ObjectBase* Evaluate(bool* err) {*err=false; return 0;} - virtual ObjectBase* ReplaceVar(const std::string& vname, ObjectBase* ob) {return 0;} - virtual void UsedFuncs(UsedType& funcs) const {} - virtual void UsedIdents(UsedType& ids) const {} }; @@ -237,26 +233,6 @@ public: // Non-default overrides std::string Dump() const override { return Name()+"="+val->Dump(); } - ObjectBase* Evaluate(bool* err) override - { - auto p=val->Evaluate(err); - if(*err) - { - COUT(ERROR)<<" in pair "<ReplaceVar(vname,ob); - if(0!=p) val.reset(p); - return 0; - } - void UsedFuncs(UsedType& funcs) const override {return val->UsedFuncs(funcs);} - void UsedIdents(UsedType& ids) const override {return val->UsedIdents(ids);} // Own functions bool Exist() const {return 0!=val.get();} @@ -280,7 +256,7 @@ public: class EXPORT ObjectList: public ObjectBase { public: - typedef std::vector ListValues; + typedef std::deque ListValues; private: std::shared_ptr vals; @@ -312,41 +288,6 @@ public: if(vals->size()!=0) s.resize(s.length()-2); return s+")"; } - ObjectBase* Evaluate(bool* err) override - { - ObjectBase* p; - for(auto& i: *vals) - { - p=i->Evaluate(err); - if(*err) - { - COUT(ERROR)<<" in list member "<Dump()<ReplaceVar(vname,ob); - if(0!=p) - { - delete i; - i=p; - } - } - return 0; - } - void UsedFuncs(UsedType& funcs) const override {for(auto& i: *vals) i->UsedFuncs(funcs);} - void UsedIdents(UsedType& ids) const override {for(auto& i: *vals) i->UsedIdents(ids);} // Own functions const ObjectBase* At(ListValues::size_type i) const {return (*vals)[i];} @@ -373,6 +314,7 @@ public: } ListValues::size_type Size() const {return vals->size();} ObjectList* PushBack(ObjectBase* p) {vals->push_back(p); return this;} + ObjectList* PushFront(ObjectBase* p) {vals->push_front(p); return this;} }; typedef ObjectBase* (*Func)(const ObjectList*); diff --git a/include/deptree.h b/include/deptree.h index 50107f1..5f0f52b 100644 --- a/include/deptree.h +++ b/include/deptree.h @@ -12,7 +12,7 @@ class DepTree typedef std::vector LeafVector; typedef std::map DepTreeVars; typedef std::set NodeVector; - typedef std::set CallStack; + typedef std::set CallStack; enum NodeType {NOTDEF,ROOT,SAVE,PRINT,VAR}; typedef struct @@ -26,19 +26,17 @@ class DepTree pthread_mutex_t prsv_mtx; pthread_mutex_t tree_mtx; } thread_params; - NodeVector parents; NodeVector childrens; NodeType type; - G_toType::size_type index; std::string name; - mutable bool visited; + ExecExpr exe; - int CreateNodeFromVar(const std::string& var, DepTreeVars& vars, CallStack& callstack); - int CreateNodeFromSP(NodeType list, G_toType::size_type ind, DepTreeVars& vars); + int CreateNodeFromVar(const std::string& v, VarType& vars, DepTreeVars& dvars, CallStack& callstack); + int CreateNodeFromSP(NodeType list, VarType& vars, ExecExpr& exp, DepTreeVars& dvars); LeafVector FindLeafNodes() const; public: - DepTree():type(DepTree::NOTDEF),visited(false) {} + DepTree():type(DepTree::NOTDEF) {} DepTree(const DepTree&) = delete; ~DepTree() { @@ -50,8 +48,10 @@ public: } } - int CreateGlobalTree(UsedType& used); + int CreateTree(ExecType& save, ExecType& print, VarType& vars); int EvaluateTree(unsigned int nthreads); + void DumpTree() const; + int CheckFunctions() const; friend void* TreeEvaluateM(void* arg); friend void* TreeEvaluate (void* arg); }; diff --git a/include/globals.h b/include/globals.h index f1309d8..63f24b9 100644 --- a/include/globals.h +++ b/include/globals.h @@ -1,25 +1,29 @@ #ifndef GLOBALS_H #define GLOBALS_H -#include "dlfcn.h" +#include #include #include #include #include "object.h" -// Variables definitions -typedef std::map G_varsType; -extern G_varsType G_vars; - // Functions addresses typedef std::multimap G_funcsType; extern G_funcsType G_funcs; -typedef std::vector G_toType; +// Types for variables and printsave store +typedef std::map VarType; +typedef std::vector ExecType; + +/* +// Variables definitions +extern G_VarType G_Vars; + // List of objects to save -extern G_toType G_tosave; +extern G_ExecType G_ToSave; // List of objects to print -extern G_toType G_toprint; +extern G_ExecType G_ToPrint; +*/ // Loaded modules typedef std::vector G_libsType; diff --git a/include/init.h b/include/init.h index 727ebc5..2b3b215 100644 --- a/include/init.h +++ b/include/init.h @@ -10,10 +10,7 @@ struct program_options const char* config; }; -int BuildDepTree(DepTree* deptree, UsedType& used); -int CheckFunctions(); -void DumpConfig(); -int ParseConfigFile(const char* config); +int ParseConfigFile(const char* config, ExecType& tosave, ExecType& toprint, VarType& vars); int ParseOptions(int argc, char** argv, struct program_options& options); int RegisterBuiltinFunctions(); debug_level SetDebugLevel(debug_level dl=INTERNALREQUEST); diff --git a/include/object.h b/include/object.h index 8ced9ec..5b25dac 100644 --- a/include/object.h +++ b/include/object.h @@ -1,84 +1,111 @@ #ifndef OBJECT_H #define OBJECT_H -#include #include -#include #include +#include +#include +#include #include "common.h" -// Class for storing identifiers -class OId: public ObjectBase +// Bison location +struct grammatic_location { - std::string name; + struct incloc + { + int line,column; + std::string filename; + }; + int first_line; + int first_column; + int last_line; + int last_column; + std::list incstack; + std::string filename; +}; +class StackElem +{ + StackElem()=delete; + StackElem(const StackElem&)=delete; public: - OId(const std::string* t):name(*t) {} - ~OId() {} - // Pure virtual overrides - ObjectBase* Copy() const override + enum Type {TYPE_EMPTY,TYPE_BEGINLIST,TYPE_ENDLIST,TYPE_MKPAIR,TYPE_OBJECT,TYPE_VARIABLE,TYPE_FUNCTION}; + StackElem(Type t, const struct grammatic_location& loc, const char* s=nullptr):type(t),obj(nullptr),location(loc) { - COUT(WARNING)<<"OId::Copy: this call must never be happens."<Copy(); - else return 0; + if(TYPE_OBJECT==type) + { + // Simple copy of pointer + obj=s.obj; + // Prevent destruction of ObjectBase in StackElem destructor + s.type=TYPE_EMPTY; + } } - void UsedIdents(UsedType& ids) const override {ids.insert(name);} - - // Own functions - std::string Name() const {return name;} -// void SetName(const std::string& s) {name=s;} -}; -// Class for storing functions -class OFunc: public ObjectBase -{ - std::string name; - ObjectList* args; -public: - OFunc(const std::string* t, ObjectBase* p):name(*t) - { - if(OBType(p)) args=dynamic_cast(p); - else args=new ObjectList(p); - } - OFunc(const char* t, ObjectBase* p):name(t) + const ObjectBase* Object() const {return isObject()?obj:nullptr;} + // Detach object + ObjectBase* PickObject() { - if(OBType(p)) args=dynamic_cast(p); - else args=new ObjectList(p); + if(isObject()) + { + type=TYPE_EMPTY; + return obj; + } + else return nullptr; } - ~OFunc() {if(args!=0) delete args;} - // Pure virtual overrides - ObjectBase* Copy() const override + bool ReplaceByObject(ObjectBase* ob) { - COUT(WARNING)<<"OFunc::Copy: this call must never be happens."<Copy()); + if(isObject()) {delete ob; return false;} + type=TYPE_OBJECT; + obj=ob; + return true; } - bool Print() const override {return false;} - std::string Type() const override {return "FUNC";} + std::string Name() const {return (isVar() || isFunc() || isMKPair())?name:std::string();} + bool isObject() const {return (TYPE_OBJECT==type);} + bool isVar() const {return (TYPE_VARIABLE==type);} + bool isFunc() const {return (TYPE_FUNCTION==type);} + bool isBList() const {return (TYPE_BEGINLIST==type);} + bool isEList() const {return (TYPE_ENDLIST==type);} + bool isMKPair() const {return (TYPE_MKPAIR==type);} + const struct grammatic_location& Location() const {return location;} + Type T() const {return type;} - // Non-default overrides - std::string Dump() const override {return Name()+args->Dump();}; - ObjectBase* Evaluate(bool* err) override; - ObjectBase* ReplaceVar(const std::string& vname, ObjectBase* ob) override {return args->ReplaceVar(vname,ob);} - void UsedFuncs(UsedType& funcs) const override {funcs.insert(name); args->UsedFuncs(funcs);} - void UsedIdents(UsedType& ids) const override {args->UsedIdents(ids);} - - // Own functions - std::string Name() const {return name;} -// void SetName(std::string s) {name=s;} +private: + Type type; + ObjectBase* obj; + std::string name; + struct grammatic_location location; }; +typedef std::list ExecExpr; + +inline StackElem SEBList(const struct grammatic_location& loc) {return StackElem(StackElem::TYPE_BEGINLIST,loc);} +inline StackElem SEEList(const struct grammatic_location& loc) {return StackElem(StackElem::TYPE_ENDLIST,loc);} +inline StackElem SEObj(ObjectBase* o, const struct grammatic_location& loc) {return StackElem(o,loc);} +inline StackElem SEMKPair(const std::string& s, const struct grammatic_location& loc) {return StackElem(StackElem::TYPE_MKPAIR,loc,s);} +inline StackElem SEVar(const std::string& s, const struct grammatic_location& loc) {return StackElem(StackElem::TYPE_VARIABLE,loc,s);} +inline StackElem SEFunc(const std::string& s, const struct grammatic_location& loc) {return StackElem(StackElem::TYPE_FUNCTION,loc,s);} +inline StackElem SEMKPair(const std::string* s, const struct grammatic_location& loc) {return StackElem(StackElem::TYPE_MKPAIR,loc,*s);} +inline StackElem SEVar(const std::string* s, const struct grammatic_location& loc) {return StackElem(StackElem::TYPE_VARIABLE,loc,*s);} +inline StackElem SEFunc(const std::string* s, const struct grammatic_location& loc) {return StackElem(StackElem::TYPE_FUNCTION,loc,*s);} + +std::string DumpExprE(const ExecExpr& exp); +std::string DumpExpr(const ExecExpr& exp); +UsedType UsedVars(const ExecExpr& exp); +UsedType UsedFuncs(const ExecExpr& exp); +ObjectBase* Evaluate(ExecExpr& exp, bool* err); +//inline void ReplaceVar(ExecExpr& exp, const std::string& var, ObjectBase* ob) {for(auto& se: exp) if(se.isVar() && var==se.Name()) se.ReplaceByObject(ob);} +void ReplaceVar(ExecExpr& exp, const std::string& var, const ObjectBase* ob);// {for(auto& se: exp) if(se.isVar() && var==se.Name()) se.ReplaceByObject(ob);} + #endif diff --git a/include/parser.h b/include/parser.h index 3ae130b..524128f 100644 --- a/include/parser.h +++ b/include/parser.h @@ -4,6 +4,7 @@ #include #include #include +#include "globals.h" // State of lexical parser (filename and position in file) struct lexical_state @@ -20,6 +21,8 @@ struct lexical_extra struct lexical_state state; unsigned int maxinclevel; int retcode; + VarType *vars; + ExecType *tosave, *toprint; std::stack fds; std::stack states; ~lexical_extra() @@ -35,22 +38,6 @@ struct lexical_extra } }; -// Bison location -struct grammatic_location -{ - struct incloc - { - int line,column; - std::string filename; - }; - int first_line; - int first_column; - int last_line; - int last_column; - std::list incstack; - std::string filename; -}; - #if !defined CONFLTYPE && !defined CONFLTYPE_IS_DECLARED typedef struct grammatic_location CONFLTYPE; #define CONFLTYPE_IS_DECLARED 1 diff --git a/src/deptree.cpp b/src/deptree.cpp index 07568d6..da842fc 100644 --- a/src/deptree.cpp +++ b/src/deptree.cpp @@ -1,36 +1,43 @@ #include #include "deptree.h" -int DepTree::CreateNodeFromVar(const std::string& var, DepTreeVars& vars, CallStack& callstack) +// Create variable node +// v - variable name +// vars - definitions of variables +// dvars - variables which are already in tree +// callstack - path in tree used for detections of loops. +int DepTree::CreateNodeFromVar(const std::string& v, VarType& vars, DepTree::DepTreeVars& dvars, DepTree::CallStack& callstack) { - COUT(DEBUG)<<"DepTree::CreateNodeFromVar "<UsedIdents(ids); + dvars[v]=this; type=DepTree::VAR; - name=var; - + name=v; DepTreeVars::const_iterator d; int ret; + + exe.splice(exe.begin(),vars[v]); // Move expression into node callstack.insert(this); for(auto& i:ids) { - d=vars.find(i); - if(d==vars.end()) + d=dvars.find(i); + if(d==dvars.end()) { auto n=*childrens.insert(new DepTree).first; n->parents.insert(this); - ret=n->CreateNodeFromVar(i,vars,callstack); + ret=n->CreateNodeFromVar(i,vars,dvars,callstack); if(ret!=0) { - COUT(ERROR)<<" in definition of variable "<Dump()< ids; + UsedType ids=UsedVars(exp); CallStack callstack; + DepTreeVars::const_iterator d; + int ret; type=list; - index=ind; + exe.splice(exe.end(),exp); // Move expression into node + COUT(DEBUG)<<"DepTree::CreateNodeFromSP "<UsedIdents(ids); - else if(type==DepTree::PRINT) G_toprint[index]->UsedIdents(ids); - DepTreeVars::const_iterator d; - int ret; - for(auto& i:ids) + for(const auto& i:ids) { - d=vars.find(i); - if(d==vars.end()) + d=dvars.find(i); // Is variable already in tree? + if(dvars.end()==d) // No { auto n=*childrens.insert(new DepTree).first; n->parents.insert(this); - ret=n->CreateNodeFromVar(i,vars,callstack); + ret=n->CreateNodeFromVar(i,vars,dvars,callstack); if(ret!=0) { - COUT(ERROR)<<" in "<<((type==DepTree::SAVE)?"save":"print")<<" directive "<<((type==DepTree::SAVE)?G_tosave:G_toprint)[index]->Dump()<<"."<second); d->second->parents.insert(this); @@ -94,8 +105,8 @@ int DepTree::CreateNodeFromSP(DepTree::NodeType list, G_toType::size_type ind, D return 0; } - -int DepTree::CreateGlobalTree(UsedType& used) +// Create dependency tree from expressions to save and print and definitions ov variables +int DepTree::CreateTree(ExecType& save, ExecType& print, VarType& vars) { if(parents.size()!=0) { @@ -103,43 +114,42 @@ int DepTree::CreateGlobalTree(UsedType& used) return 2; } - DepTreeVars vars; + DepTreeVars dvars; type=DepTree::ROOT; - for(G_toType::size_type i=0; iparents.insert(this); - auto ret=n->CreateNodeFromSP(DepTree::SAVE,i,vars); + auto ret=n->CreateNodeFromSP(DepTree::SAVE,vars,i,dvars); if(ret!=0) return ret; } - for(G_toType::size_type i=0; iparents.insert(this); - auto ret=n->CreateNodeFromSP(DepTree::PRINT,i,vars); + auto ret=n->CreateNodeFromSP(DepTree::PRINT,vars,i,dvars); if(ret!=0) return ret; } - for(auto& i: vars) used.insert(i.first); - return 0; } - +// Get list of nodes without dependencies DepTree::LeafVector DepTree::FindLeafNodes() const { LeafVector leafs; + // Visited nodes + CallStack visited; std::stack path,ends; NodeVector::const_iterator it,end; - // define isvisited as reversion of last visited - bool isvisited=!visited; + // ascending to root const DepTree* root=this; while(root->parents.size()!=0) root=*(root->parents.begin()); const DepTree* curnode=root; - curnode->visited=isvisited; + visited.insert(curnode); it=curnode->childrens.begin(); end=curnode->childrens.end(); @@ -147,10 +157,10 @@ DepTree::LeafVector DepTree::FindLeafNodes() const { if(it!=end) { - if((*it)->visited==isvisited) {++it; continue;} + if(visited.find(*it)!=visited.end()) {++it; continue;} path.push(it); ends.push(end); curnode=(*it); - curnode->visited=isvisited; + visited.insert(curnode); it=curnode->childrens.begin(); end=curnode->childrens.end(); if(it==end) leafs.push_back(const_cast(curnode)); @@ -168,14 +178,102 @@ DepTree::LeafVector DepTree::FindLeafNodes() const } +// Dump tree contents +void DepTree::DumpTree() const +{ + // Visited nodes + CallStack visited; + std::stack path,ends; + NodeVector::const_iterator it,end; + + // ascending to root + const DepTree* root=this; + while(root->parents.size()!=0) root=*(root->parents.begin()); + + const DepTree* curnode=root; + visited.insert(curnode); + it=curnode->childrens.begin(); + end=curnode->childrens.end(); + + while(true) + { + if(it!=end) + { + if(visited.find(*it)!=visited.end()) {++it; continue;} + path.push(it); ends.push(end); + curnode=(*it); + visited.insert(curnode); + if(SAVE==curnode->type) COUT(NORMAL)<<"save" <exe)<<";"<type) COUT(NORMAL)<<"print"<exe)<<";"<type) COUT(NORMAL)<name<<"="<exe)<<";"<childrens.begin(); + end=curnode->childrens.end(); + } + else + { + if(path.size()==0) break; + it=path.top(); path.pop(); + end=ends.top(); ends.pop(); + ++it; + } + } +} + + +// Check if all functions are defined +int DepTree::CheckFunctions() const +{ + // Visited nodes + CallStack visited; + std::stack path,ends; + NodeVector::const_iterator it,end; + + // ascending to root + const DepTree* root=this; + while(root->parents.size()!=0) root=*(root->parents.begin()); + + const DepTree* curnode=root; + visited.insert(curnode); + it=curnode->childrens.begin(); + end=curnode->childrens.end(); + + while(true) + { + if(it!=end) + { + if(visited.find(*it)!=visited.end()) {++it; continue;} + path.push(it); ends.push(end); + curnode=(*it); + visited.insert(curnode); + for(const auto& se: curnode->exe) if(StackElem::TYPE_FUNCTION==se.T() && G_funcs.find(se.Name())==G_funcs.end()) + { + const struct grammatic_location& loc=se.Location(); + COUT(ERROR)<<"Unknown function "<childrens.begin(); + end=curnode->childrens.end(); + } + else + { + if(path.size()==0) break; + it=path.top(); path.pop(); + end=ends.top(); ends.pop(); + ++it; + } + } + return 0; +} + + // Multi-threaded version void* TreeEvaluateM(void* arg) { struct timespec skip={0,10000000}; DepTree::thread_params* p=reinterpret_cast(arg); DepTree* leaf; - ObjectBase *ob,*eob; - ObjectList* ol; bool err; while(true) @@ -202,20 +300,16 @@ void* TreeEvaluateM(void* arg) { err=false; - // Begin critical section (access to G_toprint or G_tosave) - pthread_mutex_lock(&p->prsv_mtx); - ol=G_tosave[leaf->index]; - // End critical section - pthread_mutex_unlock(&p->prsv_mtx); - - ol->Evaluate(&err); // For list Evaluate always return 0; + std::unique_ptr ol(dynamic_cast(Evaluate(leaf->exe,&err))); // No check for return value, trust in grammatical parser if(err) { - COUT(ERROR)<<" in instruction save"<Dump()<<")"<exe.front().Location(); + COUT(ERROR)<<" in instruction save at line "<exitcode=1; return 0; } - if(!Save(ol)) + if(!Save(ol.get())) { p->exitcode=1; return 0; @@ -232,20 +326,16 @@ void* TreeEvaluateM(void* arg) { err=false; - // Begin critical section (access to G_toprint or G_tosave) - pthread_mutex_lock(&p->prsv_mtx); - ol=G_toprint[leaf->index]; - // End critical section - pthread_mutex_unlock(&p->prsv_mtx); - - ol->Evaluate(&err); // For list Evaluate always return 0; + std::unique_ptr ol(dynamic_cast(Evaluate(leaf->exe,&err))); // No check for return value, trust in grammatical parser if(err) { - COUT(ERROR)<<" in instruction print"<Dump()<<")"<exe.front().Location(); + COUT(ERROR)<<" in instruction print at line "<exitcode=1; return 0; } - if(!Print(ol)) + if(!Print(ol.get())) { p->exitcode=1; return 0; @@ -262,27 +352,20 @@ void* TreeEvaluateM(void* arg) if(DepTree::VAR==leaf->type) { - // Begin critical section (access to G_vars) - pthread_mutex_lock(&p->vars_mtx); - ob=G_vars.at(leaf->name); - G_vars.erase(leaf->name); - // End critical section - pthread_mutex_unlock(&p->vars_mtx); + ObjectBase *eob; // Main working call err=false; - eob=ob->Evaluate(&err); + eob=Evaluate(leaf->exe,&err); if(err) { - COUT(ERROR)<<" in definition of variable "<name<exe.front().Location(); + COUT(ERROR)<<" in definition of variable "<name<<" at line "<exitcode=1; return 0; } - // eob is evaluated object - if(0!=eob) delete ob; - else eob=ob; - // Begin critical section (access to tree structure) pthread_mutex_lock(&p->tree_mtx); for(auto& i:leaf->parents) @@ -290,35 +373,7 @@ void* TreeEvaluateM(void* arg) // leaf not children of anyone i->childrens.erase(leaf); // Replace variable on eob - if(DepTree::SAVE==i->type) - { - // Begin critical section (access to G_toprint or G_tosave) - pthread_mutex_lock(&p->prsv_mtx); - G_tosave[i->index]->ReplaceVar(leaf->name,eob); // ReplaceVar always return 0 for ObjectList - // End critical section - pthread_mutex_unlock(&p->prsv_mtx); - } - if(DepTree::PRINT==i->type) - { - // Begin critical section (access to G_toprint or G_tosave) - pthread_mutex_lock(&p->prsv_mtx); - G_toprint[i->index]->ReplaceVar(leaf->name,eob); // ReplaceVar always return 0 for ObjectList - // End critical section - pthread_mutex_unlock(&p->prsv_mtx); - } - if(DepTree::VAR==i->type) - { - // Begin critical section (access to G_vars) - pthread_mutex_lock(&p->vars_mtx); - ob=G_vars[i->name]->ReplaceVar(leaf->name,eob); - if(0!=ob) - { - delete G_vars[i->name]; - G_vars[i->name]=ob; - } - // End critical section - pthread_mutex_unlock(&p->vars_mtx); - } + ReplaceVar(i->exe,leaf->name,eob); // Begin critical section (access to leafs) pthread_mutex_lock(&p->leaf_mtx); @@ -344,9 +399,8 @@ void* TreeEvaluate(void* arg) { DepTree::thread_params* p=reinterpret_cast(arg); DepTree* leaf; - ObjectBase *ob,*eob; - ObjectList* ol; bool err; + while(0!=p->leafs.size()) { // Select working node @@ -357,16 +411,18 @@ void* TreeEvaluate(void* arg) if(DepTree::SAVE==leaf->type) { err=false; - ol=G_tosave[leaf->index]; - ol->Evaluate(&err); // For list Evaluate always return 0; + + std::unique_ptr ol(dynamic_cast(Evaluate(leaf->exe,&err))); // No check for return value, trust in grammatical parser if(err) { - COUT(ERROR)<<" in instruction save"<Dump()<<")"<exe.front().Location(); + COUT(ERROR)<<" in instruction save at line "<exitcode=1; return 0; } // eob is evaluated object - if(!Save(ol)) + if(!Save(ol.get())) { p->exitcode=1; return 0; @@ -378,15 +434,17 @@ void* TreeEvaluate(void* arg) if(DepTree::PRINT==leaf->type) { err=false; - ol=G_toprint[leaf->index]; - ol->Evaluate(&err); // For list Evaluate always return 0; + + std::unique_ptr ol(dynamic_cast(Evaluate(leaf->exe,&err))); // No check for return value, trust in grammatical parser if(err) { - COUT(ERROR)<<" in instruction print"<Dump()<<")"<exe.front().Location(); + COUT(ERROR)<<" in instruction print at line "<exitcode=1; return 0; } - if(!Print(ol)) + if(!Print(ol.get())) { p->exitcode=1; return 0; @@ -397,34 +455,26 @@ void* TreeEvaluate(void* arg) if(DepTree::VAR==leaf->type) { - err=false; - ob=G_vars.at(leaf->name); - G_vars.erase(leaf->name); + ObjectBase *eob; + // Main working call - eob=ob->Evaluate(&err); + err=false; + eob=Evaluate(leaf->exe,&err); if(err) { - COUT(ERROR)<<" in definition of variable "<name<exe.front().Location(); + COUT(ERROR)<<" in definition of variable "<name<<" at line "<exitcode=1; return 0; } - // eob is evaluated object - if(0!=eob) delete ob; - else eob=ob; - //G_vars.erase(leaf->name); for(auto& i:leaf->parents) { // leaf not children of anyone i->childrens.erase(leaf); // Replace variable on eob - if(DepTree::SAVE==i->type) G_tosave[i->index]->ReplaceVar(leaf->name,eob); // ReplaceVar always return 0 for ObjectList - if(DepTree::PRINT==i->type) G_toprint[i->index]->ReplaceVar(leaf->name,eob); - if(DepTree::VAR==i->type) - { - ob=G_vars[i->name]->ReplaceVar(leaf->name,eob); - if(0!=ob) {delete G_vars[i->name]; G_vars[i->name]=ob;} - } + ReplaceVar(i->exe,leaf->name,eob); // If node have no children, it's a new leaf node if(0==i->childrens.size() && DepTree::ROOT!=i->type) p->leafs.push_back(i); } diff --git a/src/globals.cpp b/src/globals.cpp index 947ca61..1931f7b 100644 --- a/src/globals.cpp +++ b/src/globals.cpp @@ -1,30 +1,29 @@ #include "globals.h" -// Variables definitions -G_varsType G_vars; - // Functions addresses G_funcsType G_funcs; +// Loaded modules +G_libsType G_libs; + +/* +// Variables definitions +G_VarType G_Vars; + // List of objects to save -G_toType G_tosave; +G_ExecType G_ToSave; // List of objects to print -G_toType G_toprint; - -// Loaded modules -G_libsType G_libs; +G_ExecType G_ToPrint; +*/ void ClearGlobals() { - for(auto& it:G_vars) delete it.second; - for(auto& it:G_tosave) delete it; - for(auto& it:G_toprint) delete it; for(auto& it:G_libs) dlclose(it); - G_vars.clear(); - G_tosave.clear(); - G_toprint.clear(); + //G_Vars.clear(); + //G_ToPrint.clear(); + //G_ToSave.clear(); } diff --git a/src/init.cpp b/src/init.cpp index 0701819..cad5ec1 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -17,59 +17,7 @@ typedef void* yyscan_t; #undef YYSTYPE #undef YYLTYPE -int BuildDepTree(DepTree* deptree, UsedType& used) {return deptree->CreateGlobalTree(used);} - - -int CheckFunctions() -{ - UsedType funcs; - - for(auto& i:G_tosave) - { - i->UsedFuncs(funcs); - for(auto& f:funcs) if(G_funcs.find(f)==G_funcs.end()) - { - COUT(ERROR)<<"Unknown function "<Dump()<UsedFuncs(funcs); - for(auto& f:funcs) if(G_funcs.find(f)==G_funcs.end()) - { - COUT(ERROR)<<"Unknown function "<Dump()<UsedFuncs(funcs); - for(auto& f:funcs) if(G_funcs.find(f)==G_funcs.end()) - { - COUT(ERROR)<<"Unknown function "<Dump()<<";"<Dump()<<";"<=SetDebugLevel(INTERNALREQUEST)) std::cout.clear(); else std::cout.setstate(std::cout.failbit); return std::cout; -} \ No newline at end of file +} diff --git a/src/main.cpp b/src/main.cpp index 63e340b..a91a29a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,8 +14,8 @@ static void usage(const char* prg) int main(int argc, char** argv) { - int ret; - DepTree* DPTree; + int ret=0; + DepTree* DPTree=nullptr; struct program_options options; // Set default options @@ -30,47 +30,43 @@ int main(int argc, char** argv) if(options.help) {usage(argv[0]); return 0;} SetDebugLevel(options.dl); + RegisterBuiltinFunctions(); - COUT(INFO)<<"Parse config file "<CreateTree(ToSave,ToPrint,vars); + if(ret!=0) goto end; COUT(INFO)<<"Ok"<CheckFunctions(); if(ret!=0) goto end; COUT(INFO)<<"Ok"<DumpTree(); else { COUT(INFO)<<"Evaluate tree "; - ret=DPTree->EvaluateTree(options.threads); if(ret!=0) { ClearGlobals(); delete DPTree; return 1;} + ret=DPTree->EvaluateTree(options.threads); if(ret!=0) goto end; COUT(INFO)<<"Ok"< EXPORT std::string ObjectSimple::type="integer"; template<> EXPORT std::string ObjectSimple::type="real"; template<> EXPORT std::string ObjectSimple::type="string"; +std::string DumpExprE(const ExecExpr& exp) +{ + std::string ret; + for(const auto& i: exp) + { + ret+="Element: "; + switch(i.T()) + { + case(StackElem::TYPE_BEGINLIST): {ret+="("; break;} + case(StackElem::TYPE_ENDLIST): {ret+=")"; break;} + case(StackElem::TYPE_MKPAIR): {ret+="MKPAIR: "+i.Name(); break;} + case(StackElem::TYPE_OBJECT): {ret+="OBJECT: "+i.Object()->Type()+" "+i.Object()->Dump(); break;} + case(StackElem::TYPE_VARIABLE): {ret+="VARIABLE: "+i.Name(); break;} + case(StackElem::TYPE_FUNCTION): {ret+="FUNCTION: "+i.Name(); break;} + default: ret+=" %ERROR% "; + } + ret+="\n"; + ret+="Location: "+i.Location().filename+" "+ToString(i.Location().first_line)+" "+ToString(i.Location().first_column)+" "+ToString(i.Location().incstack.size())+"\n\n"; + } + return ret; +} + +std::string DumpExpr(const ExecExpr& exp) +{ + std::list stack; + std::string ret; + for(const auto& i: exp) + { + switch(i.T()) + { + case(StackElem::TYPE_BEGINLIST): {stack.push_back("("); break;} + case(StackElem::TYPE_ENDLIST): {stack.push_back(")"); break;} + case(StackElem::TYPE_MKPAIR): + { + if(")"!=stack.back()) {auto s=stack.crbegin(); s++; stack.insert(s.base(),i.Name()+"=");} + else + { + ret.clear(); + uint n=0; + for(auto s=stack.crbegin(); s!=stack.crend();++s) + { + if(ret[0]!=')' && *s!="(" && *s!=")") ret=(*s)+","+ret; + else ret=(*s)+ret; + if(")"==*s) n++; + if("("==*s) + { + n--; + if(0==n) + { + stack.erase((++s).base(),stack.end()); + stack.push_back(i.Name()+"="+ret); + break; + } + } + } + } + break; + } + case(StackElem::TYPE_OBJECT): {stack.push_back(i.Object()->Dump()); break;} + case(StackElem::TYPE_VARIABLE): {stack.push_back(i.Name()); break;} + case(StackElem::TYPE_FUNCTION): + { + ret.clear(); + uint n=0; + for(auto s=stack.crbegin(); s!=stack.crend();++s) + { + if(ret[0]!=')' && *s!="(" && *s!=")") ret=(*s)+","+ret; + else ret=(*s)+ret; + if(")"==*s) n++; + if("("==*s) + { + n--; + if(0==n) + { + stack.erase((++s).base(),stack.end()); + stack.push_back(i.Name()+ret); + break; + } + } + } + break; // Never reach this line + } + default: stack.push_back(" %ERROR% "); + } + } + ret.clear(); + for(const auto& s: stack) + { + if('('==ret.back() || '='==ret.back() || ')'==s.front() || ret.empty()) ret+=s; + else ret+=","+s; + } + return ret; +} + +UsedType UsedVars(const ExecExpr& exp) +{ + UsedType ret; + for(const auto& i: exp) if(StackElem::TYPE_VARIABLE==i.T()) ret.insert(i.Name()); + return ret; +} + +UsedType UsedFuncs(const ExecExpr& exp) +{ + UsedType ret; + for(const auto& i: exp) if(StackElem::TYPE_FUNCTION==i.T()) ret.insert(i.Name()); + return ret; +} + +ObjectBase* Evaluate(ExecExpr& exp, bool* err) +{ + ExecExpr::iterator cse=exp.begin(); + while(cse!=exp.end()) + { + switch(cse->T()) + { + case(StackElem::TYPE_ENDLIST): // Making list + { + ObjectList* ol=new ObjectList; + ExecExpr::iterator bl,el; + bl=el=cse++; + bl--; + // Reverse iteration to fill list. We know that BEGINLIST exists before ENDLIST, because grammatical parser already check it. + while(StackElem::TYPE_BEGINLIST!=bl->T()) {ol->PushFront(bl->PickObject()); bl--;} + // Remove all elements from BEGINLIST to ENDLIST, but not ENDLIST itself + exp.erase(bl,el); + // Replace ENDLIST by ObjectList + el->ReplaceByObject(ol); + // Go to next element + continue; + } + case(StackElem::TYPE_MKPAIR): + { + // Previous element must be OBJECT. We don't check this, we trust in grammatical parser. + ExecExpr::iterator pr=cse; + pr--; + cse->ReplaceByObject(new ObjectPair(cse->Name(),pr->PickObject())); + // Remove previous element + exp.erase(pr); + // Go to next element + cse++; continue; + } + case(StackElem::TYPE_FUNCTION): + { + // Previous element must be OBJECT with type ObjectList. We don't check this, we trust in grammatical parser. + ExecExpr::iterator pr=cse; + pr--; + const ObjectList* arg=dynamic_cast(pr->Object()); + ObjectBase* res; + + // Functions check already done, we know that our function exists. + // Sequentally call all functions with given name + auto bounds=G_funcs.equal_range(cse->Name()); + for(auto f=bounds.first; f!=bounds.second; ++f) + { + res=(*(f->second))(arg); + if(res!=nullptr) break; + } + // Remove previous element + exp.erase(pr); + + // Error handling + if(nullptr==res) + { + const struct grammatic_location& loc=cse->Location(); + *err=true; // Raise error flag + COUT(ERROR)<<"Can't evaluate function "<Name()<<" at line "<ReplaceByObject(res); + // Go to next element + cse++; continue; + } + default: {cse++; continue;} // Other cases leads to undefined behavior (VARIABLE or EMPTY) or doesn't require any action, so, skip. + } + } + // After all, our list contains only one object. + ObjectBase* ret=exp.begin()->PickObject(); + exp.clear(); + return ret; +} + +void ReplaceVar(ExecExpr& exp, const std::string& var, const ObjectBase* ob) +{ + for(auto& se: exp) + if(se.isVar() && var==se.Name()) + se.ReplaceByObject(ob->Copy()); +} + bool ObjectBase::Save(const char* fname) const { size_t size,offset=0,wr; @@ -43,31 +233,3 @@ bool ObjectBase::Save(const char* fname) const return true; } - -ObjectBase* OFunc::Evaluate(bool* err) -{ - *err=false; - if(G_funcs.find(name)==G_funcs.end()) - { - *err=true; - COUT(ERROR)<<"Function "<Evaluate(err); - if(*err) - { - COUT(ERROR)<<" in function call "<second))(args); - if(ret!=0) return ret; - } - *err=true; - COUT(ERROR)<<"Function "<Dump()<splice((to)->end(),*(from)); delete (from);} +#define EADDV(to,from) {(to).splice((to).end(),*(from)); delete (from);} +#define I(i) {(i)=new ExecExpr;} +#define G_Vars (*(confget_extra(scanner)->vars)) +#define G_ToPrint (confget_extra(scanner)->toprint) +#define G_ToSave (confget_extra(scanner)->tosave) %} %union @@ -45,7 +52,7 @@ inline void conferror(const YYLTYPE& locp, yyscan_t sc, const std::string& str) int64_t i; double r; std::string* str; - ObjectBase* ob; + ExecExpr* expr; } %token ASSIGN OBRACE CBRACE ENDL DELIM @@ -68,11 +75,11 @@ inline void conferror(const YYLTYPE& locp, yyscan_t sc, const std::string& str) %left '.' %precedence OBRACE CBRACE -%type longidentifier -%type expression -%type object -%type pair -%type list +%type longidentifier +%type expression +%type object +%type pair +%type list %destructor {} REAL INTEGER BOOL %destructor {delete $$;} <*> @@ -101,72 +108,72 @@ dirline: } line: - NAME ASSIGN object ENDL {COUT(DEBUG)<<" NAME ASSIGN object ENDL\n"; if(G_vars.count(*$1)!=0) delete G_vars[*$1]; G_vars[*$1]=$3; delete $1;} - | NAME ASSIGN list ENDL {COUT(DEBUG)<<" NAME ASSIGN list ENDL\n"; if(G_vars.count(*$1)!=0) delete G_vars[*$1]; G_vars[*$1]=$3; delete $1;} + NAME ASSIGN object ENDL {COUT(DEBUG)<<" NAME ASSIGN object ENDL\n"; EADDV(G_Vars[*$1],$3); delete $1;} + | NAME ASSIGN list ENDL {COUT(DEBUG)<<" NAME ASSIGN list ENDL\n"; $3->push_front(SEBList(@3)); $3->push_back(SEEList(@4)); EADDV(G_Vars[*$1],$3); delete $1;} | NAME OBRACE list CBRACE ENDL {COUT(DEBUG)<<" NAME OBRACE list CBRACE ENDL\n"; tolower($1); - ObjectList* ol=dynamic_cast($3); - if(*$1=="save") G_tosave.push_back(ol); - else if(*$1=="print") G_toprint.push_back(ol); + $3->push_front(SEBList(@2)); + $3->push_back(SEEList(@4)); + if(*$1=="save") {G_ToSave->emplace_back(); EADDV(G_ToSave->back(),$3);} + else if(*$1=="print") {G_ToPrint->emplace_back(); EADDV(G_ToPrint->back(),$3);} else { conferror(@1,scanner,"unknown statement "+(*$1)); - delete ol; - delete $1; + delete $1; delete $3; YYABORT; } delete $1;} | NAME OBRACE object CBRACE ENDL {COUT(DEBUG)<<" NAME OBRACE object CBRACE ENDL\n"; tolower($1); - ObjectList* ol=new ObjectList($3); - if(*$1=="save") G_tosave.push_back(ol); - else if(*$1=="print") G_toprint.push_back(ol); + $3->push_front(SEBList(@2)); + $3->push_back(SEEList(@4)); + if(*$1=="save") {G_ToSave->emplace_back(); EADDV(G_ToSave->back(),$3);} + else if(*$1=="print") {G_ToPrint->emplace_back(); EADDV(G_ToPrint->back(),$3);} else { conferror(@1,scanner,"unknown statement "+(*$1)); - delete ol; - delete $1; + delete $1; delete $3; YYABORT; } delete $1;} ; list: - object object {COUT(DEBUG)<<" object object\n"; $$=(new ObjectList($1))->PushBack($2);} - | list object {COUT(DEBUG)<<" list object\n"; dynamic_cast($1)->PushBack($2); $$=$1;} + object object {COUT(DEBUG)<<" object object\n"; I($$); EADD($$,$1); EADD($$,$2);} + | list object {COUT(DEBUG)<<" list object\n"; I($$); EADD($$,$1); EADD($$,$2);} ; pair: - IDENTIFIER ASSIGN object {COUT(DEBUG)<<" IDENTIFIER ASSIGN object\n"; $$=new ObjectPair($1,$3); delete $1;} + IDENTIFIER ASSIGN object {COUT(DEBUG)<<" IDENTIFIER ASSIGN object "<<*$1<<"\n"; I($$); EADD($$,$3); $$->push_back(SEMKPair($1,@1)); delete $1;} ; object: - STRING {COUT(DEBUG)<<" STRING\n"; $$=new ObjectString($1); delete $1;} - | BOOL {COUT(DEBUG)<<" BOOL\n"; $$=new ObjectBool($1);} - | OBRACE list CBRACE {COUT(DEBUG)<<" OBRACE list CBRACE\n"; $$=$2;} - | expression %prec ASSIGN {COUT(DEBUG)<<" expression\n"; $$=$1;} - | pair {COUT(DEBUG)<<" pair\n"; $$=$1;} - | OBRACE object CBRACE {COUT(DEBUG)<<" OBRACE object CBRACE\n"; $$=$2;} - | object DELIM {COUT(DEBUG)<<" OBJECT DELIM\n"; $$=$1;} + STRING {COUT(DEBUG)<<" STRING\n"; I($$); $$->push_back(StackElem(new ObjectString($1),@1)); delete $1;} + | BOOL {COUT(DEBUG)<<" BOOL\n"; I($$); $$->push_back(StackElem(new ObjectBool($1),@1));} + | OBRACE list CBRACE {COUT(DEBUG)<<" OBRACE list CBRACE\n"; I($$); $$->push_front(SEBList(@1)); EADD($$,$2); $$->push_back(SEEList(@3));} + | expression %prec ASSIGN {COUT(DEBUG)<<" expression\n"; I($$); EADD($$,$1);} + | pair {COUT(DEBUG)<<" pair\n"; I($$); EADD($$,$1);} + | OBRACE object CBRACE {COUT(DEBUG)<<" OBRACE object CBRACE\n"; I($$); EADD($$,$2);} + | object DELIM {COUT(DEBUG)<<" OBJECT DELIM\n"; I($$); EADD($$,$1);} ; longidentifier: - IDENTIFIER '.' IDENTIFIER {COUT(DEBUG)<<" IDENTIFIER DOT IDENTIFIER\n"; $$=new OFunc("GET",(new ObjectList(new OId($1)))->PushBack(new ObjectString($3))); delete $1; delete $3;} - | longidentifier '.' IDENTIFIER {COUT(DEBUG)<<" longidentifier '.' IDENTIFIER\n"; $$=new OFunc("GET",(new ObjectList($1))->PushBack(new ObjectString($3))); delete $3;} + IDENTIFIER '.' IDENTIFIER {COUT(DEBUG)<<" IDENTIFIER DOT IDENTIFIER\n"; I($$); $$->push_front(SEBList(@1)); $$->push_back(SEVar($1,@1)); $$->push_back(SEObj(new ObjectString($3),@3)); $$->push_back(SEEList(@1)); $$->push_back(SEFunc("GET",@2)); delete $1; delete $3;} + | longidentifier '.' IDENTIFIER {COUT(DEBUG)<<" longidentifier '.' IDENTIFIER\n"; I($$); $$->push_front(SEBList(@1)); EADD($$,$1); $$->push_back(SEObj(new ObjectString($3),@3)); $$->push_back(SEEList(@1)); $$->push_back(SEFunc("GET",@2)); delete $3;} expression: - IDENTIFIER {COUT(DEBUG)<<" IDENTIFIER\n"; $$=new OId($1); delete $1;} - | IDENTIFIER OBRACE object CBRACE {COUT(DEBUG)<<" IDENTIFIER OBRACE object CBRACE\n"; $$=new OFunc($1,$3); delete $1;} - | IDENTIFIER OBRACE list CBRACE {COUT(DEBUG)<<" IDENTIFIER OBRACE list CBRACE\n"; $$=new OFunc($1,$3); delete $1;} - | longidentifier {COUT(DEBUG)<<" longidentifier\n"; $$=$1;} - | REAL {COUT(DEBUG)<<" REAL\n"; $$=new ObjectReal($1);} - | INTEGER {COUT(DEBUG)<<" INTEGER\n"; $$=new ObjectInt($1);} - | expression '-' expression {COUT(DEBUG)<<" -\n"; $$=new OFunc("SUB",(new ObjectList($1))->PushBack($3));} - | expression '+' expression {COUT(DEBUG)<<" +\n"; $$=new OFunc("ADD",(new ObjectList($1))->PushBack($3));} - | expression '/' expression {COUT(DEBUG)<<" /\n"; $$=new OFunc("DIV",(new ObjectList($1))->PushBack($3));} - | expression '*' expression {COUT(DEBUG)<<" *\n"; $$=new OFunc("MUL",(new ObjectList($1))->PushBack($3));} - | expression '^' expression {COUT(DEBUG)<<" ^\n"; $$=new OFunc("POW",(new ObjectList($1))->PushBack($3));} - | '-' expression %prec UNARY {COUT(DEBUG)<<" unary -\n"; $$=new OFunc("NEG",$2);} - | '+' expression %prec UNARY {COUT(DEBUG)<<" unary +\n"; $$=new OFunc("POS",$2);} - | OBRACE expression CBRACE {COUT(DEBUG)<<" OBRACE expression CBRACE\n"; $$=$2;} + IDENTIFIER {COUT(DEBUG)<<" IDENTIFIER\n"; I($$); $$->push_back(SEVar($1,@1)); delete $1;} + | IDENTIFIER OBRACE object CBRACE {COUT(DEBUG)<<" IDENTIFIER OBRACE object CBRACE\n"; I($$); $$->push_front(SEBList(@2)); EADD($$,$3); $$->push_back(SEEList(@4)); $$->push_back(SEFunc($1,@1)); delete $1;} + | IDENTIFIER OBRACE list CBRACE {COUT(DEBUG)<<" IDENTIFIER OBRACE list CBRACE\n"; I($$); $$->push_front(SEBList(@2)); EADD($$,$3); $$->push_back(SEEList(@4)); $$->push_back(SEFunc($1,@1)); delete $1;} + | longidentifier {COUT(DEBUG)<<" longidentifier\n"; I($$); EADD($$,$1);} + | REAL {COUT(DEBUG)<<" REAL\n"; I($$); $$->push_front(StackElem(new ObjectReal($1),@1));} + | INTEGER {COUT(DEBUG)<<" INTEGER\n"; I($$); $$->push_front(StackElem(new ObjectInt($1),@1));} + | expression '-' expression {COUT(DEBUG)<<" -\n"; I($$); $$->push_front(SEBList(@1)); EADD($$,$1); EADD($$,$3); $$->push_back(SEEList(@3)); $$->push_back(SEFunc("SUB",@2));} + | expression '+' expression {COUT(DEBUG)<<" +\n"; I($$); $$->push_front(SEBList(@1)); EADD($$,$1); EADD($$,$3); $$->push_back(SEEList(@3)); $$->push_back(SEFunc("ADD",@2));} + | expression '/' expression {COUT(DEBUG)<<" /\n"; I($$); $$->push_front(SEBList(@1)); EADD($$,$1); EADD($$,$3); $$->push_back(SEEList(@3)); $$->push_back(SEFunc("DIV",@2));} + | expression '*' expression {COUT(DEBUG)<<" *\n"; I($$); $$->push_front(SEBList(@1)); EADD($$,$1); EADD($$,$3); $$->push_back(SEEList(@3)); $$->push_back(SEFunc("MUL",@2));} + | expression '^' expression {COUT(DEBUG)<<" ^\n"; I($$); $$->push_front(SEBList(@1)); EADD($$,$1); EADD($$,$3); $$->push_back(SEEList(@3)); $$->push_back(SEFunc("POW",@2));} + | '-' expression %prec UNARY {COUT(DEBUG)<<" unary -\n"; I($$); $$->push_front(SEBList(@1)); EADD($$,$2); $$->push_back(SEEList(@2)); $$->push_back(SEFunc("NEG",@1));} + | '+' expression %prec UNARY {COUT(DEBUG)<<" unary +\n"; I($$); $$->push_front(SEBList(@1)); EADD($$,$2); $$->push_back(SEEList(@2)); $$->push_back(SEFunc("POS",@1));} + | OBRACE expression CBRACE {COUT(DEBUG)<<" OBRACE expression CBRACE\n"; I($$); EADD($$,$2);} ; diff --git a/src/parser/lexical.l b/src/parser/lexical.l index b331362..332399b 100644 --- a/src/parser/lexical.l +++ b/src/parser/lexical.l @@ -16,13 +16,12 @@ %{ #include "common.h" #include "parser.h" +#include "object.h" // flex use register keyword, but it deprecated in C++11. #define register // Flex always think what bison types prefixed as YY, so we mast define right macroses #define YYSTYPE CONFSTYPE #define YYLTYPE CONFLTYPE -// Some declarations in grammatical.h use ObjectBase -class ObjectBase; #include "grammatical.h" // Get rid of warning on unused function #define YY_NO_INPUT