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 9 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. 147
      include/object.h
  6. 19
      include/parser.h
  7. 310
      src/deptree.cpp
  8. 27
      src/globals.cpp
  9. 59
      src/init.cpp
  10. 48
      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
#include <cctype>
#include <cfloat>
#include <deque>
#include <iostream>
#include <list>
#include <memory>
@ -10,7 +11,6 @@
#include <sstream>
#include <typeindex>
#include <typeinfo>
#include <vector>
#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 "<<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
bool Exist() const {return 0!=val.get();}
@ -280,7 +256,7 @@ public:
class EXPORT ObjectList: public ObjectBase
{
public:
typedef std::vector<ObjectBase*> ListValues;
typedef std::deque<ObjectBase*> ListValues;
private:
std::shared_ptr<ListValues> 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 "<<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
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*);

16
include/deptree.h

@ -12,7 +12,7 @@ class DepTree
typedef std::vector<DepTree*> LeafVector;
typedef std::map<std::string,DepTree*> DepTreeVars;
typedef std::set<DepTree*> NodeVector;
typedef std::set<DepTree*> CallStack;
typedef std::set<const DepTree*> 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);
};

20
include/globals.h

@ -1,25 +1,29 @@
#ifndef GLOBALS_H
#define GLOBALS_H
#include "dlfcn.h"
#include <dlfcn.h>
#include <map>
#include <string>
#include <vector>
#include "object.h"
// Variables definitions
typedef std::map<std::string,ObjectBase*> G_varsType;
extern G_varsType G_vars;
// Functions addresses
typedef std::multimap<std::string,Func> G_funcsType;
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
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<void*> G_libsType;

5
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);

147
include/object.h

@ -1,84 +1,111 @@
#ifndef OBJECT_H
#define OBJECT_H
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <inttypes.h>
#include <stack>
#include <stdio.h>
#include <string.h>
#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<struct incloc> 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."<<std::endl;
return new OId(&name);
if(TYPE_BEGINLIST==t || TYPE_ENDLIST==t) return;
if( (TYPE_VARIABLE==t || TYPE_FUNCTION==t || TYPE_MKPAIR==t) && nullptr!=s) name=s;
else type=TYPE_EMPTY;
}
bool Print() const override {return false;}
std::string Type() const override {return "IDENT";}
// Non-default overrides
std::string Dump() const override {return name;};
ObjectBase* Evaluate(bool* err) override
StackElem(Type t, const struct grammatic_location& loc, const std::string& s):type(t),obj(nullptr),location(loc)
{
COUT(ERROR)<<"Variable "<<name<<" still not defined."<<std::endl;
*err=true;
return 0;
if(TYPE_VARIABLE==t || TYPE_FUNCTION==t || TYPE_MKPAIR==t) name=s;
else type=TYPE_EMPTY;
}
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();
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<ObjectList>(p)) args=dynamic_cast<ObjectList*>(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<ObjectList>(p)) args=dynamic_cast<ObjectList*>(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."<<std::endl;
return new OFunc(&name,args->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<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

19
include/parser.h

@ -4,6 +4,7 @@
#include <stack>
#include <string>
#include <stdio.h>
#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<FILE*> fds;
std::stack<struct lexical_state> 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<struct incloc> incstack;
std::string filename;
};
#if !defined CONFLTYPE && !defined CONFLTYPE_IS_DECLARED
typedef struct grammatic_location CONFLTYPE;
#define CONFLTYPE_IS_DECLARED 1

310
src/deptree.cpp

@ -1,36 +1,43 @@
#include <stack>
#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;
if(G_vars.count(var)==0)
COUT(DEBUG)<<"DepTree::CreateNodeFromVar "<<v<<std::endl;
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;
}
UsedType ids;
UsedType ids=UsedVars(vars[v]);
vars[var]=this;
G_vars[var]->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 "<<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;
}
}
@ -50,41 +57,45 @@ int DepTree::CreateNodeFromVar(const std::string& var, DepTreeVars& vars, CallSt
return 0;
}
int DepTree::CreateNodeFromSP(DepTree::NodeType list, G_toType::size_type ind, DepTreeVars& vars)
// Creating PRINT or SAVE node
// 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)
{
COUT(ERROR)<<"Internal error, incorrect NodeType in DepTree::CreateNodeFromSP()."<<std::endl;
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;
DepTreeVars::const_iterator d;
int ret;
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);
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()<<"."<<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;
}
}
else
else // Variable already in tree. Just establish links.
{
childrens.insert(d->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; i<G_tosave.size(); i++)
for(auto& i:save)
{
auto n=*childrens.insert(new DepTree).first;
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;
}
for(G_toType::size_type i=0; i<G_toprint.size(); i++)
for(auto& i:print)
{
auto n=*childrens.insert(new DepTree).first;
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;
}
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<NodeVector::const_iterator> 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<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
void* TreeEvaluateM(void* arg)
{
struct timespec skip={0,10000000};
DepTree::thread_params* p=reinterpret_cast<DepTree::thread_params*>(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<ObjectList> ol(dynamic_cast<ObjectList*>(Evaluate(leaf->exe,&err))); // No check for return value, trust in grammatical parser
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;
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<ObjectList> ol(dynamic_cast<ObjectList*>(Evaluate(leaf->exe,&err))); // No check for return value, trust in grammatical parser
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;
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 "<<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;
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<DepTree::thread_params*>(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<ObjectList> ol(dynamic_cast<ObjectList*>(Evaluate(leaf->exe,&err))); // No check for return value, trust in grammatical parser
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;
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<ObjectList> ol(dynamic_cast<ObjectList*>(Evaluate(leaf->exe,&err))); // No check for return value, trust in grammatical parser
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;
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 "<<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;
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);
}

27
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();
}

59
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 "<<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)
int ParseConfigFile(const char* config, ExecType& tosave, ExecType& toprint, VarType& vars)
{
yyscan_t scanner;
struct lexical_extra extra;
@ -91,6 +39,9 @@ int ParseConfigFile(const char* config)
char* cwd=get_current_dir_name();
extra.state.curdir=cwd;
free(cwd);
extra.toprint=&toprint;
extra.tosave=&tosave;
extra.vars=&vars;
extra.ParsePath(config);
// Search paths begin from working directory
extra.includedirs=extra.moduledirs="./";
@ -164,4 +115,4 @@ std::ostream& COUT(debug_level dl)
if(dl>=SetDebugLevel(INTERNALREQUEST)) std::cout.clear();
else std::cout.setstate(std::cout.failbit);
return std::cout;
}
}

48
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 "<<options.config<<" ";
ret=ParseConfigFile(options.config); if(ret!=0) { ClearGlobals(); return 1;}
COUT(INFO)<<"Ok"<<std::endl;
if(G_tosave.size()==0 && G_toprint.size()==0)
{
COUT(WARNING)<<"No actions needed, exiting"<<std::endl;
ClearGlobals();
return 0;
}
VarType vars;
ExecType ToPrint, ToSave;
{
UsedType used, all;
for(auto& i:G_vars) all.insert(i.first);
unsigned int tot=G_vars.size();
COUT(INFO)<<"Parse config file "<<options.config<<" ";
ret=ParseConfigFile(options.config,ToSave,ToPrint,vars); if(ret!=0) { ClearGlobals(); return 1;}
COUT(INFO)<<"Ok"<<std::endl;
if(ToSave.size()==0 && ToPrint.size()==0)
{
COUT(WARNING)<<"No actions needed, exiting"<<std::endl;
ClearGlobals();
return 0;
}
DPTree=new DepTree;
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)<<"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 ";
ret=CheckFunctions(); if(ret!=0) { ClearGlobals(); delete DPTree; return 1;}
ret=DPTree->CheckFunctions(); if(ret!=0) goto end;
COUT(INFO)<<"Ok"<<std::endl;
if(options.dump) DumpConfig();
if(options.dump) DPTree->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"<<std::endl;
}
end:
ClearGlobals();
delete DPTree;
return 0;
if(nullptr!=DPTree) delete DPTree;
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<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
{
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 "<<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());
}
#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
@ -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 <ob> longidentifier
%type <ob> expression
%type <ob> object
%type <ob> pair
%type <ob> list
%type <expr> longidentifier
%type <expr> expression
%type <expr> object
%type <expr> pair
%type <expr> 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<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;}
| 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<ObjectList*>($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);}
;

3
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

Loading…
Cancel
Save