Browse Source

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.
ObjPtr
Michael Uleysky 8 years ago
parent
commit
0e49a86bd6
  1. 64
      include/common.h
  2. 16
      include/deptree.h
  3. 20
      include/globals.h
  4. 5
      include/init.h
  5. 145
      include/object.h
  6. 19
      include/parser.h
  7. 310
      src/deptree.cpp
  8. 27
      src/globals.cpp
  9. 57
      src/init.cpp
  10. 38
      src/main.cpp
  11. 218
      src/object.cpp
  12. 95
      src/parser/grammatical.y
  13. 3
      src/parser/lexical.l

64
include/common.h

@ -2,6 +2,7 @@
#define COMMON_H #define COMMON_H
#include <cctype> #include <cctype>
#include <cfloat> #include <cfloat>
#include <deque>
#include <iostream> #include <iostream>
#include <list> #include <list>
#include <memory> #include <memory>
@ -10,7 +11,6 @@
#include <sstream> #include <sstream>
#include <typeindex> #include <typeindex>
#include <typeinfo> #include <typeinfo>
#include <vector>
#define EXPORT __attribute__ ((visibility ("default"))) #define EXPORT __attribute__ ((visibility ("default")))
@ -53,10 +53,6 @@ public:
// Virtual api with default functions. Modules types must not override them. // Virtual api with default functions. Modules types must not override them.
virtual std::string Dump() const {return "%"+Type()+"%";} 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 // Non-default overrides
std::string Dump() const override { return Name()+"="+val->Dump(); } 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 "<<Dump()<<std::endl;
return 0;
}
if(0==p) return 0;
val.reset(p);
return 0;
}
ObjectBase* ReplaceVar(const std::string& vname, ObjectBase* ob) override
{
auto p=val->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 // Own functions
bool Exist() const {return 0!=val.get();} bool Exist() const {return 0!=val.get();}
@ -280,7 +256,7 @@ public:
class EXPORT ObjectList: public ObjectBase class EXPORT ObjectList: public ObjectBase
{ {
public: public:
typedef std::vector<ObjectBase*> ListValues; typedef std::deque<ObjectBase*> ListValues;
private: private:
std::shared_ptr<ListValues> vals; std::shared_ptr<ListValues> vals;
@ -312,41 +288,6 @@ public:
if(vals->size()!=0) s.resize(s.length()-2); if(vals->size()!=0) s.resize(s.length()-2);
return s+")"; return s+")";
} }
ObjectBase* Evaluate(bool* err) override
{
ObjectBase* p;
for(auto& i: *vals)
{
p=i->Evaluate(err);
if(*err)
{
COUT(ERROR)<<" in list member "<<i->Dump()<<std::endl;
return 0;
}
if(0!=p)
{
delete i;
i=p;
}
}
return 0;
}
ObjectBase* ReplaceVar(const std::string& vname, ObjectBase* ob) override
{
ObjectBase* p;
for(auto& i: *vals)
{
p=i->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 // Own functions
const ObjectBase* At(ListValues::size_type i) const {return (*vals)[i];} const ObjectBase* At(ListValues::size_type i) const {return (*vals)[i];}
@ -373,6 +314,7 @@ public:
} }
ListValues::size_type Size() const {return vals->size();} ListValues::size_type Size() const {return vals->size();}
ObjectList* PushBack(ObjectBase* p) {vals->push_back(p); return this;} 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*); typedef ObjectBase* (*Func)(const ObjectList*);

16
include/deptree.h

@ -12,7 +12,7 @@ class DepTree
typedef std::vector<DepTree*> LeafVector; typedef std::vector<DepTree*> LeafVector;
typedef std::map<std::string,DepTree*> DepTreeVars; typedef std::map<std::string,DepTree*> DepTreeVars;
typedef std::set<DepTree*> NodeVector; typedef std::set<DepTree*> NodeVector;
typedef std::set<DepTree*> CallStack; typedef std::set<const DepTree*> CallStack;
enum NodeType {NOTDEF,ROOT,SAVE,PRINT,VAR}; enum NodeType {NOTDEF,ROOT,SAVE,PRINT,VAR};
typedef struct typedef struct
@ -26,19 +26,17 @@ class DepTree
pthread_mutex_t prsv_mtx; pthread_mutex_t prsv_mtx;
pthread_mutex_t tree_mtx; pthread_mutex_t tree_mtx;
} thread_params; } thread_params;
NodeVector parents; NodeVector parents;
NodeVector childrens; NodeVector childrens;
NodeType type; NodeType type;
G_toType::size_type index;
std::string name; std::string name;
mutable bool visited; ExecExpr exe;
int CreateNodeFromVar(const std::string& var, DepTreeVars& vars, CallStack& callstack); int CreateNodeFromVar(const std::string& v, VarType& vars, DepTreeVars& dvars, CallStack& callstack);
int CreateNodeFromSP(NodeType list, G_toType::size_type ind, DepTreeVars& vars); int CreateNodeFromSP(NodeType list, VarType& vars, ExecExpr& exp, DepTreeVars& dvars);
LeafVector FindLeafNodes() const; LeafVector FindLeafNodes() const;
public: public:
DepTree():type(DepTree::NOTDEF),visited(false) {} DepTree():type(DepTree::NOTDEF) {}
DepTree(const DepTree&) = delete; DepTree(const DepTree&) = delete;
~DepTree() ~DepTree()
{ {
@ -50,8 +48,10 @@ public:
} }
} }
int CreateGlobalTree(UsedType& used); int CreateTree(ExecType& save, ExecType& print, VarType& vars);
int EvaluateTree(unsigned int nthreads); int EvaluateTree(unsigned int nthreads);
void DumpTree() const;
int CheckFunctions() const;
friend void* TreeEvaluateM(void* arg); friend void* TreeEvaluateM(void* arg);
friend void* TreeEvaluate (void* arg); friend void* TreeEvaluate (void* arg);
}; };

20
include/globals.h

@ -1,25 +1,29 @@
#ifndef GLOBALS_H #ifndef GLOBALS_H
#define GLOBALS_H #define GLOBALS_H
#include "dlfcn.h" #include <dlfcn.h>
#include <map> #include <map>
#include <string> #include <string>
#include <vector> #include <vector>
#include "object.h" #include "object.h"
// Variables definitions
typedef std::map<std::string,ObjectBase*> G_varsType;
extern G_varsType G_vars;
// Functions addresses // Functions addresses
typedef std::multimap<std::string,Func> G_funcsType; typedef std::multimap<std::string,Func> G_funcsType;
extern G_funcsType G_funcs; extern G_funcsType G_funcs;
typedef std::vector<ObjectList*> G_toType; // Types for variables and printsave store
typedef std::map<std::string,ExecExpr> VarType;
typedef std::vector<ExecExpr> ExecType;
/*
// Variables definitions
extern G_VarType G_Vars;
// List of objects to save // List of objects to save
extern G_toType G_tosave; extern G_ExecType G_ToSave;
// List of objects to print // List of objects to print
extern G_toType G_toprint; extern G_ExecType G_ToPrint;
*/
// Loaded modules // Loaded modules
typedef std::vector<void*> G_libsType; typedef std::vector<void*> G_libsType;

5
include/init.h

@ -10,10 +10,7 @@ struct program_options
const char* config; const char* config;
}; };
int BuildDepTree(DepTree* deptree, UsedType& used); int ParseConfigFile(const char* config, ExecType& tosave, ExecType& toprint, VarType& vars);
int CheckFunctions();
void DumpConfig();
int ParseConfigFile(const char* config);
int ParseOptions(int argc, char** argv, struct program_options& options); int ParseOptions(int argc, char** argv, struct program_options& options);
int RegisterBuiltinFunctions(); int RegisterBuiltinFunctions();
debug_level SetDebugLevel(debug_level dl=INTERNALREQUEST); debug_level SetDebugLevel(debug_level dl=INTERNALREQUEST);

145
include/object.h

@ -1,84 +1,111 @@
#ifndef OBJECT_H #ifndef OBJECT_H
#define OBJECT_H #define OBJECT_H
#include <stdio.h>
#include <errno.h> #include <errno.h>
#include <string.h>
#include <inttypes.h> #include <inttypes.h>
#include <stack>
#include <stdio.h>
#include <string.h>
#include "common.h" #include "common.h"
// Class for storing identifiers // Bison location
class OId: public ObjectBase 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<struct incloc> incstack;
std::string filename;
};
class StackElem
{
StackElem()=delete;
StackElem(const StackElem&)=delete;
public: public:
OId(const std::string* t):name(*t) {} enum Type {TYPE_EMPTY,TYPE_BEGINLIST,TYPE_ENDLIST,TYPE_MKPAIR,TYPE_OBJECT,TYPE_VARIABLE,TYPE_FUNCTION};
~OId() {} StackElem(Type t, const struct grammatic_location& loc, const char* s=nullptr):type(t),obj(nullptr),location(loc)
// Pure virtual overrides
ObjectBase* Copy() const override
{ {
COUT(WARNING)<<"OId::Copy: this call must never be happens."<<std::endl; if(TYPE_BEGINLIST==t || TYPE_ENDLIST==t) return;
return new OId(&name); if( (TYPE_VARIABLE==t || TYPE_FUNCTION==t || TYPE_MKPAIR==t) && nullptr!=s) name=s;
else type=TYPE_EMPTY;
} }
bool Print() const override {return false;} StackElem(Type t, const struct grammatic_location& loc, const std::string& s):type(t),obj(nullptr),location(loc)
std::string Type() const override {return "IDENT";}
// Non-default overrides
std::string Dump() const override {return name;};
ObjectBase* Evaluate(bool* err) override
{ {
COUT(ERROR)<<"Variable "<<name<<" still not defined."<<std::endl; if(TYPE_VARIABLE==t || TYPE_FUNCTION==t || TYPE_MKPAIR==t) name=s;
*err=true; else type=TYPE_EMPTY;
return 0;
} }
ObjectBase* ReplaceVar(const std::string& vname, ObjectBase* ob) override StackElem(ObjectBase* o, const struct grammatic_location& loc):type(TYPE_OBJECT),obj(o),location(loc) {}
~StackElem() {if(TYPE_OBJECT==type) delete obj;}
StackElem(StackElem&& s):type(s.type),name(s.name),location(s.location)
{ {
if(vname==Name()) return ob->Copy(); if(TYPE_OBJECT==type)
else return 0; {
// 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 const ObjectBase* Object() const {return isObject()?obj:nullptr;}
class OFunc: public ObjectBase // Detach object
{ ObjectBase* PickObject()
std::string name;
ObjectList* args;
public:
OFunc(const std::string* t, ObjectBase* p):name(*t)
{ {
if(OBType<ObjectList>(p)) args=dynamic_cast<ObjectList*>(p); if(isObject())
else args=new ObjectList(p);
}
OFunc(const char* t, ObjectBase* p):name(t)
{ {
if(OBType<ObjectList>(p)) args=dynamic_cast<ObjectList*>(p); type=TYPE_EMPTY;
else args=new ObjectList(p); return obj;
}
else return nullptr;
} }
~OFunc() {if(args!=0) delete args;} bool ReplaceByObject(ObjectBase* ob)
// Pure virtual overrides
ObjectBase* Copy() const override
{ {
COUT(WARNING)<<"OFunc::Copy: this call must never be happens."<<std::endl; if(isObject()) {delete ob; return false;}
return new OFunc(&name,args->Copy()); type=TYPE_OBJECT;
obj=ob;
return true;
} }
bool Print() const override {return false;} std::string Name() const {return (isVar() || isFunc() || isMKPair())?name:std::string();}
std::string Type() const override {return "FUNC";} 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 private:
std::string Dump() const override {return Name()+args->Dump();}; Type type;
ObjectBase* Evaluate(bool* err) override; ObjectBase* obj;
ObjectBase* ReplaceVar(const std::string& vname, ObjectBase* ob) override {return args->ReplaceVar(vname,ob);} std::string name;
void UsedFuncs(UsedType& funcs) const override {funcs.insert(name); args->UsedFuncs(funcs);} struct grammatic_location location;
void UsedIdents(UsedType& ids) const override {args->UsedIdents(ids);}
// Own functions
std::string Name() const {return name;}
// void SetName(std::string s) {name=s;}
}; };
typedef std::list<StackElem> 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 #endif

19
include/parser.h

@ -4,6 +4,7 @@
#include <stack> #include <stack>
#include <string> #include <string>
#include <stdio.h> #include <stdio.h>
#include "globals.h"
// State of lexical parser (filename and position in file) // State of lexical parser (filename and position in file)
struct lexical_state struct lexical_state
@ -20,6 +21,8 @@ struct lexical_extra
struct lexical_state state; struct lexical_state state;
unsigned int maxinclevel; unsigned int maxinclevel;
int retcode; int retcode;
VarType *vars;
ExecType *tosave, *toprint;
std::stack<FILE*> fds; std::stack<FILE*> fds;
std::stack<struct lexical_state> states; std::stack<struct lexical_state> states;
~lexical_extra() ~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<struct incloc> incstack;
std::string filename;
};
#if !defined CONFLTYPE && !defined CONFLTYPE_IS_DECLARED #if !defined CONFLTYPE && !defined CONFLTYPE_IS_DECLARED
typedef struct grammatic_location CONFLTYPE; typedef struct grammatic_location CONFLTYPE;
#define CONFLTYPE_IS_DECLARED 1 #define CONFLTYPE_IS_DECLARED 1

310
src/deptree.cpp

@ -1,36 +1,43 @@
#include <stack> #include <stack>
#include "deptree.h" #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 "<<var<<std::endl; COUT(DEBUG)<<"DepTree::CreateNodeFromVar "<<v<<std::endl;
if(G_vars.count(var)==0) if(vars.count(v)==0)
{ {
COUT(ERROR)<<"Definition of variable "<<var<<" not found"<<std::endl; COUT(ERROR)<<"Definition of variable "<<v<<" not found"<<std::endl;
return 1; return 1;
} }
UsedType ids; UsedType ids=UsedVars(vars[v]);
vars[var]=this; dvars[v]=this;
G_vars[var]->UsedIdents(ids);
type=DepTree::VAR; type=DepTree::VAR;
name=var; name=v;
DepTreeVars::const_iterator d; DepTreeVars::const_iterator d;
int ret; int ret;
exe.splice(exe.begin(),vars[v]); // Move expression into node
callstack.insert(this); callstack.insert(this);
for(auto& i:ids) for(auto& i:ids)
{ {
d=vars.find(i); d=dvars.find(i);
if(d==vars.end()) if(d==dvars.end())
{ {
auto n=*childrens.insert(new DepTree).first; auto n=*childrens.insert(new DepTree).first;
n->parents.insert(this); n->parents.insert(this);
ret=n->CreateNodeFromVar(i,vars,callstack); ret=n->CreateNodeFromVar(i,vars,dvars,callstack);
if(ret!=0) if(ret!=0)
{ {
COUT(ERROR)<<" in definition of variable "<<name<<std::endl; const struct grammatic_location& loc=exe.back().Location();
COUT(ERROR)<<" in definition of variable "<<name<<" at line "<<loc.first_line<<", position "<<loc.first_column<<std::endl;
for(const auto& inc: loc.incstack) COUT(ERROR)<<" included from "<<inc.filename<<" at line "<<inc.line<<", position "<<inc.column<<std::endl;
return ret; return ret;
} }
} }
@ -50,41 +57,45 @@ int DepTree::CreateNodeFromVar(const std::string& var, DepTreeVars& vars, CallSt
return 0; return 0;
} }
// Creating PRINT or SAVE node
int DepTree::CreateNodeFromSP(DepTree::NodeType list, G_toType::size_type ind, DepTreeVars& vars) // list - type of node
// vars - definitions of variables
// exp - expression to print or save
// dvars - variables which are already in tree
int DepTree::CreateNodeFromSP(DepTree::NodeType list, VarType& vars, ExecExpr& exp, DepTreeVars& dvars)
{ {
if(list!=DepTree::SAVE && list!=DepTree::PRINT) if(list!=DepTree::SAVE && list!=DepTree::PRINT)
{ {
COUT(ERROR)<<"Internal error, incorrect NodeType in DepTree::CreateNodeFromSP()."<<std::endl; COUT(ERROR)<<"Internal error, incorrect NodeType in DepTree::CreateNodeFromSP()."<<std::endl;
return 2; return 2;
} }
COUT(DEBUG)<<"DepTree::CreateNodeFromSP "<<((list==DepTree::SAVE)?G_tosave:G_toprint)[ind]->Dump()<<std::endl;
std::set<std::string> ids; UsedType ids=UsedVars(exp);
CallStack callstack; CallStack callstack;
DepTreeVars::const_iterator d;
int ret;
type=list; type=list;
index=ind; exe.splice(exe.end(),exp); // Move expression into node
COUT(DEBUG)<<"DepTree::CreateNodeFromSP "<<DumpExpr(exe)<<std::endl;
if(type==DepTree::SAVE) G_tosave[index]->UsedIdents(ids); for(const auto& i:ids)
else if(type==DepTree::PRINT) G_toprint[index]->UsedIdents(ids);
DepTreeVars::const_iterator d;
int ret;
for(auto& i:ids)
{ {
d=vars.find(i); d=dvars.find(i); // Is variable already in tree?
if(d==vars.end()) if(dvars.end()==d) // No
{ {
auto n=*childrens.insert(new DepTree).first; auto n=*childrens.insert(new DepTree).first;
n->parents.insert(this); n->parents.insert(this);
ret=n->CreateNodeFromVar(i,vars,callstack); ret=n->CreateNodeFromVar(i,vars,dvars,callstack);
if(ret!=0) if(ret!=0)
{ {
COUT(ERROR)<<" in "<<((type==DepTree::SAVE)?"save":"print")<<" directive "<<((type==DepTree::SAVE)?G_tosave:G_toprint)[index]->Dump()<<"."<<std::endl; const struct grammatic_location& loc=exe.front().Location();
COUT(ERROR)<<" in "<<((type==DepTree::SAVE)?"save":"print")<<" directive at line "<<loc.first_line<<", position "<<loc.first_column<<std::endl;
for(const auto& inc: loc.incstack) COUT(ERROR)<<" included from "<<inc.filename<<" at line "<<inc.line<<", position "<<inc.column<<std::endl;
return ret; return ret;
} }
} }
else else // Variable already in tree. Just establish links.
{ {
childrens.insert(d->second); childrens.insert(d->second);
d->second->parents.insert(this); d->second->parents.insert(this);
@ -94,8 +105,8 @@ int DepTree::CreateNodeFromSP(DepTree::NodeType list, G_toType::size_type ind, D
return 0; return 0;
} }
// Create dependency tree from expressions to save and print and definitions ov variables
int DepTree::CreateGlobalTree(UsedType& used) int DepTree::CreateTree(ExecType& save, ExecType& print, VarType& vars)
{ {
if(parents.size()!=0) if(parents.size()!=0)
{ {
@ -103,43 +114,42 @@ int DepTree::CreateGlobalTree(UsedType& used)
return 2; return 2;
} }
DepTreeVars vars; DepTreeVars dvars;
type=DepTree::ROOT; type=DepTree::ROOT;
for(G_toType::size_type i=0; i<G_tosave.size(); i++) for(auto& i:save)
{ {
auto n=*childrens.insert(new DepTree).first; auto n=*childrens.insert(new DepTree).first;
n->parents.insert(this); n->parents.insert(this);
auto ret=n->CreateNodeFromSP(DepTree::SAVE,i,vars); auto ret=n->CreateNodeFromSP(DepTree::SAVE,vars,i,dvars);
if(ret!=0) return ret; if(ret!=0) return ret;
} }
for(G_toType::size_type i=0; i<G_toprint.size(); i++) for(auto& i:print)
{ {
auto n=*childrens.insert(new DepTree).first; auto n=*childrens.insert(new DepTree).first;
n->parents.insert(this); n->parents.insert(this);
auto ret=n->CreateNodeFromSP(DepTree::PRINT,i,vars); auto ret=n->CreateNodeFromSP(DepTree::PRINT,vars,i,dvars);
if(ret!=0) return ret; if(ret!=0) return ret;
} }
for(auto& i: vars) used.insert(i.first);
return 0; return 0;
} }
// Get list of nodes without dependencies
DepTree::LeafVector DepTree::FindLeafNodes() const DepTree::LeafVector DepTree::FindLeafNodes() const
{ {
LeafVector leafs; LeafVector leafs;
// Visited nodes
CallStack visited;
std::stack<NodeVector::const_iterator> path,ends; std::stack<NodeVector::const_iterator> path,ends;
NodeVector::const_iterator it,end; NodeVector::const_iterator it,end;
// define isvisited as reversion of last visited
bool isvisited=!visited;
// ascending to root // ascending to root
const DepTree* root=this; const DepTree* root=this;
while(root->parents.size()!=0) root=*(root->parents.begin()); while(root->parents.size()!=0) root=*(root->parents.begin());
const DepTree* curnode=root; const DepTree* curnode=root;
curnode->visited=isvisited; visited.insert(curnode);
it=curnode->childrens.begin(); it=curnode->childrens.begin();
end=curnode->childrens.end(); end=curnode->childrens.end();
@ -147,10 +157,10 @@ DepTree::LeafVector DepTree::FindLeafNodes() const
{ {
if(it!=end) if(it!=end)
{ {
if((*it)->visited==isvisited) {++it; continue;} if(visited.find(*it)!=visited.end()) {++it; continue;}
path.push(it); ends.push(end); path.push(it); ends.push(end);
curnode=(*it); curnode=(*it);
curnode->visited=isvisited; visited.insert(curnode);
it=curnode->childrens.begin(); it=curnode->childrens.begin();
end=curnode->childrens.end(); end=curnode->childrens.end();
if(it==end) leafs.push_back(const_cast<DepTree*>(curnode)); if(it==end) leafs.push_back(const_cast<DepTree*>(curnode));
@ -168,14 +178,102 @@ DepTree::LeafVector DepTree::FindLeafNodes() const
} }
// Dump tree contents
void DepTree::DumpTree() const
{
// Visited nodes
CallStack visited;
std::stack<NodeVector::const_iterator> 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" <<DumpExpr(curnode->exe)<<";"<<std::endl;
if(PRINT==curnode->type) COUT(NORMAL)<<"print"<<DumpExpr(curnode->exe)<<";"<<std::endl;
if(VAR==curnode->type) COUT(NORMAL)<<curnode->name<<"="<<DumpExpr(curnode->exe)<<";"<<std::endl;
it=curnode->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<NodeVector::const_iterator> 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 "<<se.Name()<<" at line "<<loc.first_line<<", position "<<loc.first_column<<std::endl;
for(const auto& inc: loc.incstack) COUT(ERROR)<<" included from "<<inc.filename<<" at line "<<inc.line<<", position "<<inc.column<<std::endl;
return 1;
}
it=curnode->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 // Multi-threaded version
void* TreeEvaluateM(void* arg) void* TreeEvaluateM(void* arg)
{ {
struct timespec skip={0,10000000}; struct timespec skip={0,10000000};
DepTree::thread_params* p=reinterpret_cast<DepTree::thread_params*>(arg); DepTree::thread_params* p=reinterpret_cast<DepTree::thread_params*>(arg);
DepTree* leaf; DepTree* leaf;
ObjectBase *ob,*eob;
ObjectList* ol;
bool err; bool err;
while(true) while(true)
@ -202,20 +300,16 @@ void* TreeEvaluateM(void* arg)
{ {
err=false; err=false;
// Begin critical section (access to G_toprint or G_tosave) std::unique_ptr<ObjectList> ol(dynamic_cast<ObjectList*>(Evaluate(leaf->exe,&err))); // No check for return value, trust in grammatical parser
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;
if(err) if(err)
{ {
COUT(ERROR)<<" in instruction save"<<ol->Dump()<<")"<<std::endl; const struct grammatic_location& loc=leaf->exe.front().Location();
COUT(ERROR)<<" in instruction save at line "<<loc.first_line<<", position "<<loc.first_column<<std::endl;
for(const auto& inc: loc.incstack) COUT(ERROR)<<" included from "<<inc.filename<<" at line "<<inc.line<<", position "<<inc.column<<std::endl;
p->exitcode=1; p->exitcode=1;
return 0; return 0;
} }
if(!Save(ol)) if(!Save(ol.get()))
{ {
p->exitcode=1; p->exitcode=1;
return 0; return 0;
@ -232,20 +326,16 @@ void* TreeEvaluateM(void* arg)
{ {
err=false; err=false;
// Begin critical section (access to G_toprint or G_tosave) std::unique_ptr<ObjectList> ol(dynamic_cast<ObjectList*>(Evaluate(leaf->exe,&err))); // No check for return value, trust in grammatical parser
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;
if(err) if(err)
{ {
COUT(ERROR)<<" in instruction print"<<ol->Dump()<<")"<<std::endl; const struct grammatic_location& loc=leaf->exe.front().Location();
COUT(ERROR)<<" in instruction print at line "<<loc.first_line<<", position "<<loc.first_column<<std::endl;
for(const auto& inc: loc.incstack) COUT(ERROR)<<" included from "<<inc.filename<<" at line "<<inc.line<<", position "<<inc.column<<std::endl;
p->exitcode=1; p->exitcode=1;
return 0; return 0;
} }
if(!Print(ol)) if(!Print(ol.get()))
{ {
p->exitcode=1; p->exitcode=1;
return 0; return 0;
@ -262,27 +352,20 @@ void* TreeEvaluateM(void* arg)
if(DepTree::VAR==leaf->type) if(DepTree::VAR==leaf->type)
{ {
// Begin critical section (access to G_vars) ObjectBase *eob;
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);
// Main working call // Main working call
err=false; err=false;
eob=ob->Evaluate(&err); eob=Evaluate(leaf->exe,&err);
if(err) if(err)
{ {
COUT(ERROR)<<" in definition of variable "<<leaf->name<<std::endl; const struct grammatic_location& loc=leaf->exe.front().Location();
COUT(ERROR)<<" in definition of variable "<<leaf->name<<" at line "<<loc.first_line<<", position "<<loc.first_column<<std::endl;
for(const auto& inc: loc.incstack) COUT(ERROR)<<" included from "<<inc.filename<<" at line "<<inc.line<<", position "<<inc.column<<std::endl;
p->exitcode=1; p->exitcode=1;
return 0; return 0;
} }
// eob is evaluated object
if(0!=eob) delete ob;
else eob=ob;
// Begin critical section (access to tree structure) // Begin critical section (access to tree structure)
pthread_mutex_lock(&p->tree_mtx); pthread_mutex_lock(&p->tree_mtx);
for(auto& i:leaf->parents) for(auto& i:leaf->parents)
@ -290,35 +373,7 @@ void* TreeEvaluateM(void* arg)
// leaf not children of anyone // leaf not children of anyone
i->childrens.erase(leaf); i->childrens.erase(leaf);
// Replace variable on eob // Replace variable on eob
if(DepTree::SAVE==i->type) ReplaceVar(i->exe,leaf->name,eob);
{
// 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);
}
// Begin critical section (access to leafs) // Begin critical section (access to leafs)
pthread_mutex_lock(&p->leaf_mtx); pthread_mutex_lock(&p->leaf_mtx);
@ -344,9 +399,8 @@ void* TreeEvaluate(void* arg)
{ {
DepTree::thread_params* p=reinterpret_cast<DepTree::thread_params*>(arg); DepTree::thread_params* p=reinterpret_cast<DepTree::thread_params*>(arg);
DepTree* leaf; DepTree* leaf;
ObjectBase *ob,*eob;
ObjectList* ol;
bool err; bool err;
while(0!=p->leafs.size()) while(0!=p->leafs.size())
{ {
// Select working node // Select working node
@ -357,16 +411,18 @@ void* TreeEvaluate(void* arg)
if(DepTree::SAVE==leaf->type) if(DepTree::SAVE==leaf->type)
{ {
err=false; err=false;
ol=G_tosave[leaf->index];
ol->Evaluate(&err); // For list Evaluate always return 0; std::unique_ptr<ObjectList> ol(dynamic_cast<ObjectList*>(Evaluate(leaf->exe,&err))); // No check for return value, trust in grammatical parser
if(err) if(err)
{ {
COUT(ERROR)<<" in instruction save"<<ol->Dump()<<")"<<std::endl; const struct grammatic_location& loc=leaf->exe.front().Location();
COUT(ERROR)<<" in instruction save at line "<<loc.first_line<<", position "<<loc.first_column<<std::endl;
for(const auto& inc: loc.incstack) COUT(ERROR)<<" included from "<<inc.filename<<" at line "<<inc.line<<", position "<<inc.column<<std::endl;
p->exitcode=1; p->exitcode=1;
return 0; return 0;
} }
// eob is evaluated object // eob is evaluated object
if(!Save(ol)) if(!Save(ol.get()))
{ {
p->exitcode=1; p->exitcode=1;
return 0; return 0;
@ -378,15 +434,17 @@ void* TreeEvaluate(void* arg)
if(DepTree::PRINT==leaf->type) if(DepTree::PRINT==leaf->type)
{ {
err=false; err=false;
ol=G_toprint[leaf->index];
ol->Evaluate(&err); // For list Evaluate always return 0; std::unique_ptr<ObjectList> ol(dynamic_cast<ObjectList*>(Evaluate(leaf->exe,&err))); // No check for return value, trust in grammatical parser
if(err) if(err)
{ {
COUT(ERROR)<<" in instruction print"<<ol->Dump()<<")"<<std::endl; const struct grammatic_location& loc=leaf->exe.front().Location();
COUT(ERROR)<<" in instruction print at line "<<loc.first_line<<", position "<<loc.first_column<<std::endl;
for(const auto& inc: loc.incstack) COUT(ERROR)<<" included from "<<inc.filename<<" at line "<<inc.line<<", position "<<inc.column<<std::endl;
p->exitcode=1; p->exitcode=1;
return 0; return 0;
} }
if(!Print(ol)) if(!Print(ol.get()))
{ {
p->exitcode=1; p->exitcode=1;
return 0; return 0;
@ -397,34 +455,26 @@ void* TreeEvaluate(void* arg)
if(DepTree::VAR==leaf->type) if(DepTree::VAR==leaf->type)
{ {
err=false; ObjectBase *eob;
ob=G_vars.at(leaf->name);
G_vars.erase(leaf->name);
// Main working call // Main working call
eob=ob->Evaluate(&err); err=false;
eob=Evaluate(leaf->exe,&err);
if(err) if(err)
{ {
COUT(ERROR)<<" in definition of variable "<<leaf->name<<std::endl; const struct grammatic_location& loc=leaf->exe.front().Location();
COUT(ERROR)<<" in definition of variable "<<leaf->name<<" at line "<<loc.first_line<<", position "<<loc.first_column<<std::endl;
for(const auto& inc: loc.incstack) COUT(ERROR)<<" included from "<<inc.filename<<" at line "<<inc.line<<", position "<<inc.column<<std::endl;
p->exitcode=1; p->exitcode=1;
return 0; return 0;
} }
// eob is evaluated object
if(0!=eob) delete ob;
else eob=ob;
//G_vars.erase(leaf->name);
for(auto& i:leaf->parents) for(auto& i:leaf->parents)
{ {
// leaf not children of anyone // leaf not children of anyone
i->childrens.erase(leaf); i->childrens.erase(leaf);
// Replace variable on eob // Replace variable on eob
if(DepTree::SAVE==i->type) G_tosave[i->index]->ReplaceVar(leaf->name,eob); // ReplaceVar always return 0 for ObjectList ReplaceVar(i->exe,leaf->name,eob);
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;}
}
// If node have no children, it's a new leaf node // 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); if(0==i->childrens.size() && DepTree::ROOT!=i->type) p->leafs.push_back(i);
} }

27
src/globals.cpp

@ -1,30 +1,29 @@
#include "globals.h" #include "globals.h"
// Variables definitions
G_varsType G_vars;
// Functions addresses // Functions addresses
G_funcsType G_funcs; G_funcsType G_funcs;
// Loaded modules
G_libsType G_libs;
/*
// Variables definitions
G_VarType G_Vars;
// List of objects to save // List of objects to save
G_toType G_tosave; G_ExecType G_ToSave;
// List of objects to print // List of objects to print
G_toType G_toprint; G_ExecType G_ToPrint;
*/
// Loaded modules
G_libsType G_libs;
void ClearGlobals() 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); for(auto& it:G_libs) dlclose(it);
G_vars.clear(); //G_Vars.clear();
G_tosave.clear(); //G_ToPrint.clear();
G_toprint.clear(); //G_ToSave.clear();
} }

57
src/init.cpp

@ -17,59 +17,7 @@ typedef void* yyscan_t;
#undef YYSTYPE #undef YYSTYPE
#undef YYLTYPE #undef YYLTYPE
int BuildDepTree(DepTree* deptree, UsedType& used) {return deptree->CreateGlobalTree(used);} int ParseConfigFile(const char* config, ExecType& tosave, ExecType& toprint, VarType& vars)
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 "<<f<<" in directive save"<<i->Dump()<<std::endl;
return 1;
}
funcs.clear();
}
for(auto& i:G_toprint)
{
i->UsedFuncs(funcs);
for(auto& f:funcs) if(G_funcs.find(f)==G_funcs.end())
{
COUT(ERROR)<<"Unknown function "<<f<<" in directive print"<<i->Dump()<<std::endl;
return 1;
}
funcs.clear();
}
for(auto& i:G_vars)
{
i.second->UsedFuncs(funcs);
for(auto& f:funcs) if(G_funcs.find(f)==G_funcs.end())
{
COUT(ERROR)<<"Unknown function "<<f<<" in definition of variable "<<i.first<<std::endl;
return 1;
}
funcs.clear();
}
return 0;
}
void DumpConfig()
{
for(auto& i: G_vars) COUT(NORMAL)<<i.first<<"="+i.second->Dump()<<";"<<std::endl;
for(auto& i: G_tosave) COUT(NORMAL)<<"save"<<i->Dump()<<";"<<std::endl;
for(auto& i: G_toprint) COUT(NORMAL)<<"print"<<i->Dump()<<";"<<std::endl;
}
int ParseConfigFile(const char* config)
{ {
yyscan_t scanner; yyscan_t scanner;
struct lexical_extra extra; struct lexical_extra extra;
@ -91,6 +39,9 @@ int ParseConfigFile(const char* config)
char* cwd=get_current_dir_name(); char* cwd=get_current_dir_name();
extra.state.curdir=cwd; extra.state.curdir=cwd;
free(cwd); free(cwd);
extra.toprint=&toprint;
extra.tosave=&tosave;
extra.vars=&vars;
extra.ParsePath(config); extra.ParsePath(config);
// Search paths begin from working directory // Search paths begin from working directory
extra.includedirs=extra.moduledirs="./"; extra.includedirs=extra.moduledirs="./";

38
src/main.cpp

@ -14,8 +14,8 @@ static void usage(const char* prg)
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
int ret; int ret=0;
DepTree* DPTree; DepTree* DPTree=nullptr;
struct program_options options; struct program_options options;
// Set default options // Set default options
@ -30,47 +30,43 @@ int main(int argc, char** argv)
if(options.help) {usage(argv[0]); return 0;} if(options.help) {usage(argv[0]); return 0;}
SetDebugLevel(options.dl); SetDebugLevel(options.dl);
RegisterBuiltinFunctions();
{
VarType vars;
ExecType ToPrint, ToSave;
COUT(INFO)<<"Parse config file "<<options.config<<" "; COUT(INFO)<<"Parse config file "<<options.config<<" ";
ret=ParseConfigFile(options.config); if(ret!=0) { ClearGlobals(); return 1;} ret=ParseConfigFile(options.config,ToSave,ToPrint,vars); if(ret!=0) { ClearGlobals(); return 1;}
COUT(INFO)<<"Ok"<<std::endl; COUT(INFO)<<"Ok"<<std::endl;
if(G_tosave.size()==0 && G_toprint.size()==0) if(ToSave.size()==0 && ToPrint.size()==0)
{ {
COUT(WARNING)<<"No actions needed, exiting"<<std::endl; COUT(WARNING)<<"No actions needed, exiting"<<std::endl;
ClearGlobals(); ClearGlobals();
return 0; return 0;
} }
{
UsedType used, all;
for(auto& i:G_vars) all.insert(i.first);
unsigned int tot=G_vars.size();
DPTree=new DepTree; DPTree=new DepTree;
COUT(INFO)<<"Building dependency tree "; COUT(INFO)<<"Building dependency tree ";
ret=BuildDepTree(DPTree,used); if(ret!=0) { ClearGlobals(); delete DPTree; return 1;} ret=DPTree->CreateTree(ToSave,ToPrint,vars);
if(ret!=0) goto end;
COUT(INFO)<<"Ok"<<std::endl; COUT(INFO)<<"Ok"<<std::endl;
COUT(INFO)<<"Remove unneeded definitions: ";
for(auto& i:all) if(used.count(i)==0) { delete G_vars[i]; G_vars.erase(i);};
COUT(INFO)<<(tot-G_vars.size())<<" removed, "<<G_vars.size()<<" remains."<<std::endl;
} }
RegisterBuiltinFunctions();
COUT(INFO)<<"Checking functions "; COUT(INFO)<<"Checking functions ";
ret=CheckFunctions(); if(ret!=0) { ClearGlobals(); delete DPTree; return 1;} ret=DPTree->CheckFunctions(); if(ret!=0) goto end;
COUT(INFO)<<"Ok"<<std::endl; COUT(INFO)<<"Ok"<<std::endl;
if(options.dump) DumpConfig(); if(options.dump) DPTree->DumpTree();
else else
{ {
COUT(INFO)<<"Evaluate tree "; 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"<<std::endl; COUT(INFO)<<"Ok"<<std::endl;
} }
end:
ClearGlobals(); ClearGlobals();
delete DPTree; if(nullptr!=DPTree) delete DPTree;
return 0; return (0==ret)?0:1;
} }

218
src/object.cpp

@ -6,6 +6,196 @@ template<> EXPORT std::string ObjectSimple<int64_t>::type="integer";
template<> EXPORT std::string ObjectSimple<double>::type="real"; template<> EXPORT std::string ObjectSimple<double>::type="real";
template<> EXPORT std::string ObjectSimple<std::string>::type="string"; template<> EXPORT std::string ObjectSimple<std::string>::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<std::string> 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<const ObjectList*>(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 "<<cse->Name()<<" at line "<<loc.first_line<<", position "<<loc.first_column<<std::endl;
for(const auto& inc: loc.incstack) COUT(ERROR)<<" included from "<<inc.filename<<" at line "<<inc.line<<", position "<<inc.column<<std::endl;
return nullptr;
}
// Replace function on returned value
cse->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 bool ObjectBase::Save(const char* fname) const
{ {
size_t size,offset=0,wr; size_t size,offset=0,wr;
@ -43,31 +233,3 @@ bool ObjectBase::Save(const char* fname) const
return true; return true;
} }
ObjectBase* OFunc::Evaluate(bool* err)
{
*err=false;
if(G_funcs.find(name)==G_funcs.end())
{
*err=true;
COUT(ERROR)<<"Function "<<name<< " not found"<<std::endl;
return 0;
}
args->Evaluate(err);
if(*err)
{
COUT(ERROR)<<" in function call "<<Dump()<<std::endl;
return 0;
}
ObjectBase* ret;
auto p=G_funcs.equal_range(name);
for(auto f=p.first;f!=p.second;f++)
{
ret=(*(f->second))(args);
if(ret!=0) return ret;
}
*err=true;
COUT(ERROR)<<"Function "<<name<<" can't evaluate expression "<<args->Dump()<<std::endl;
return 0;
}

95
src/parser/grammatical.y

@ -37,6 +37,13 @@ inline void conferror(const YYLTYPE& locp, yyscan_t sc, const std::string& str)
{ {
conferror(&locp,sc,str.c_str()); conferror(&locp,sc,str.c_str());
} }
#define EADD(to,from) {(to)->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 %union
@ -45,7 +52,7 @@ inline void conferror(const YYLTYPE& locp, yyscan_t sc, const std::string& str)
int64_t i; int64_t i;
double r; double r;
std::string* str; std::string* str;
ObjectBase* ob; ExecExpr* expr;
} }
%token ASSIGN OBRACE CBRACE ENDL DELIM %token ASSIGN OBRACE CBRACE ENDL DELIM
@ -68,11 +75,11 @@ inline void conferror(const YYLTYPE& locp, yyscan_t sc, const std::string& str)
%left '.' %left '.'
%precedence OBRACE CBRACE %precedence OBRACE CBRACE
%type <ob> longidentifier %type <expr> longidentifier
%type <ob> expression %type <expr> expression
%type <ob> object %type <expr> object
%type <ob> pair %type <expr> pair
%type <ob> list %type <expr> list
%destructor {} REAL INTEGER BOOL %destructor {} REAL INTEGER BOOL
%destructor {delete $$;} <*> %destructor {delete $$;} <*>
@ -101,72 +108,72 @@ dirline:
} }
line: 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 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"; 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"; $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"; | NAME OBRACE list CBRACE ENDL {COUT(DEBUG)<<" NAME OBRACE list CBRACE ENDL\n";
tolower($1); tolower($1);
ObjectList* ol=dynamic_cast<ObjectList*>($3); $3->push_front(SEBList(@2));
if(*$1=="save") G_tosave.push_back(ol); $3->push_back(SEEList(@4));
else if(*$1=="print") G_toprint.push_back(ol); 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 else
{ {
conferror(@1,scanner,"unknown statement "+(*$1)); conferror(@1,scanner,"unknown statement "+(*$1));
delete ol; delete $1; delete $3;
delete $1;
YYABORT; YYABORT;
} }
delete $1;} delete $1;}
| NAME OBRACE object CBRACE ENDL {COUT(DEBUG)<<" NAME OBRACE object CBRACE ENDL\n"; | NAME OBRACE object CBRACE ENDL {COUT(DEBUG)<<" NAME OBRACE object CBRACE ENDL\n";
tolower($1); tolower($1);
ObjectList* ol=new ObjectList($3); $3->push_front(SEBList(@2));
if(*$1=="save") G_tosave.push_back(ol); $3->push_back(SEEList(@4));
else if(*$1=="print") G_toprint.push_back(ol); 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 else
{ {
conferror(@1,scanner,"unknown statement "+(*$1)); conferror(@1,scanner,"unknown statement "+(*$1));
delete ol; delete $1; delete $3;
delete $1;
YYABORT; YYABORT;
} }
delete $1;} delete $1;}
; ;
list: list:
object object {COUT(DEBUG)<<" object object\n"; $$=(new ObjectList($1))->PushBack($2);} object object {COUT(DEBUG)<<" object object\n"; I($$); EADD($$,$1); EADD($$,$2);}
| list object {COUT(DEBUG)<<" list object\n"; dynamic_cast<ObjectList*>($1)->PushBack($2); $$=$1;} | list object {COUT(DEBUG)<<" list object\n"; I($$); EADD($$,$1); EADD($$,$2);}
; ;
pair: 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: object:
STRING {COUT(DEBUG)<<" STRING\n"; $$=new ObjectString($1); delete $1;} STRING {COUT(DEBUG)<<" STRING\n"; I($$); $$->push_back(StackElem(new ObjectString($1),@1)); delete $1;}
| BOOL {COUT(DEBUG)<<" BOOL\n"; $$=new ObjectBool($1);} | BOOL {COUT(DEBUG)<<" BOOL\n"; I($$); $$->push_back(StackElem(new ObjectBool($1),@1));}
| OBRACE list CBRACE {COUT(DEBUG)<<" OBRACE list CBRACE\n"; $$=$2;} | 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"; $$=$1;} | expression %prec ASSIGN {COUT(DEBUG)<<" expression\n"; I($$); EADD($$,$1);}
| pair {COUT(DEBUG)<<" pair\n"; $$=$1;} | pair {COUT(DEBUG)<<" pair\n"; I($$); EADD($$,$1);}
| OBRACE object CBRACE {COUT(DEBUG)<<" OBRACE object CBRACE\n"; $$=$2;} | OBRACE object CBRACE {COUT(DEBUG)<<" OBRACE object CBRACE\n"; I($$); EADD($$,$2);}
| object DELIM {COUT(DEBUG)<<" OBJECT DELIM\n"; $$=$1;} | object DELIM {COUT(DEBUG)<<" OBJECT DELIM\n"; I($$); EADD($$,$1);}
; ;
longidentifier: 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;} 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"; $$=new OFunc("GET",(new ObjectList($1))->PushBack(new ObjectString($3))); 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: expression:
IDENTIFIER {COUT(DEBUG)<<" IDENTIFIER\n"; $$=new OId($1); delete $1;} IDENTIFIER {COUT(DEBUG)<<" IDENTIFIER\n"; I($$); $$->push_back(SEVar($1,@1)); delete $1;}
| IDENTIFIER OBRACE object CBRACE {COUT(DEBUG)<<" IDENTIFIER OBRACE object CBRACE\n"; $$=new OFunc($1,$3); 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"; $$=new OFunc($1,$3); 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"; $$=$1;} | longidentifier {COUT(DEBUG)<<" longidentifier\n"; I($$); EADD($$,$1);}
| REAL {COUT(DEBUG)<<" REAL\n"; $$=new ObjectReal($1);} | REAL {COUT(DEBUG)<<" REAL\n"; I($$); $$->push_front(StackElem(new ObjectReal($1),@1));}
| INTEGER {COUT(DEBUG)<<" INTEGER\n"; $$=new ObjectInt($1);} | INTEGER {COUT(DEBUG)<<" INTEGER\n"; I($$); $$->push_front(StackElem(new ObjectInt($1),@1));}
| expression '-' expression {COUT(DEBUG)<<" -\n"; $$=new OFunc("SUB",(new ObjectList($1))->PushBack($3));} | 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"; $$=new OFunc("ADD",(new ObjectList($1))->PushBack($3));} | 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"; $$=new OFunc("DIV",(new ObjectList($1))->PushBack($3));} | 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"; $$=new OFunc("MUL",(new ObjectList($1))->PushBack($3));} | 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"; $$=new OFunc("POW",(new ObjectList($1))->PushBack($3));} | 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"; $$=new OFunc("NEG",$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"; $$=new OFunc("POS",$2);} | '+' 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"; $$=$2;} | OBRACE expression CBRACE {COUT(DEBUG)<<" OBRACE expression CBRACE\n"; I($$); EADD($$,$2);}
; ;

3
src/parser/lexical.l

@ -16,13 +16,12 @@
%{ %{
#include "common.h" #include "common.h"
#include "parser.h" #include "parser.h"
#include "object.h"
// flex use register keyword, but it deprecated in C++11. // flex use register keyword, but it deprecated in C++11.
#define register #define register
// Flex always think what bison types prefixed as YY, so we mast define right macroses // Flex always think what bison types prefixed as YY, so we mast define right macroses
#define YYSTYPE CONFSTYPE #define YYSTYPE CONFSTYPE
#define YYLTYPE CONFLTYPE #define YYLTYPE CONFLTYPE
// Some declarations in grammatical.h use ObjectBase
class ObjectBase;
#include "grammatical.h" #include "grammatical.h"
// Get rid of warning on unused function // Get rid of warning on unused function
#define YY_NO_INPUT #define YY_NO_INPUT

Loading…
Cancel
Save