|
|
|
#include <stack>
|
|
|
|
#include "deptree.h"
|
|
|
|
|
|
|
|
int DepTree::CreateNodeFromVar(const std::string& var, UsedType& used, CallStack& callstack)
|
|
|
|
{
|
|
|
|
COUT(DEBUG)<<"DepTree::CreateNodeFromVar "<<var<<std::endl;
|
|
|
|
if(G_vars.count(var)==0)
|
|
|
|
{
|
|
|
|
COUT(ERROR)<<"Definition of variable "<<var<<" not found"<<std::endl;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
UsedType ids;
|
|
|
|
|
|
|
|
used.insert(var);
|
|
|
|
G_vars[var]->UsedIdents(ids);
|
|
|
|
type=DepTree::VAR;
|
|
|
|
name=var;
|
|
|
|
|
|
|
|
DepTree* d;
|
|
|
|
int ret;
|
|
|
|
callstack.insert(this);
|
|
|
|
for(auto& i:ids)
|
|
|
|
{
|
|
|
|
d=FindNodeByVar(i);
|
|
|
|
if(d==0)
|
|
|
|
{
|
|
|
|
auto n=*childrens.insert(new DepTree).first;
|
|
|
|
n->parents.insert(this);
|
|
|
|
ret=n->CreateNodeFromVar(i,used,callstack);
|
|
|
|
if(ret!=0)
|
|
|
|
{
|
|
|
|
COUT(ERROR)<<" in definition of variable "<<name<<std::endl;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(callstack.find(d)!=callstack.end())
|
|
|
|
{
|
|
|
|
COUT(ERROR)<<"Circular dependency of variable "<<name<<" from variable "<<i<<std::endl;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
childrens.insert(d);
|
|
|
|
d->parents.insert(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
callstack.erase(this);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int DepTree::CreateNodeFromSP(DepTree::NodeType list, G_toType::size_type ind, UsedType& used)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
CallStack callstack;
|
|
|
|
|
|
|
|
type=list;
|
|
|
|
index=ind;
|
|
|
|
|
|
|
|
if(type==DepTree::SAVE) G_tosave[index]->UsedIdents(ids);
|
|
|
|
else if(type==DepTree::PRINT) G_toprint[index]->UsedIdents(ids);
|
|
|
|
DepTree* d;
|
|
|
|
int ret;
|
|
|
|
for(auto& i:ids)
|
|
|
|
{
|
|
|
|
d=FindNodeByVar(i);
|
|
|
|
if(d==0)
|
|
|
|
{
|
|
|
|
auto n=*childrens.insert(new DepTree).first;
|
|
|
|
n->parents.insert(this);
|
|
|
|
ret=n->CreateNodeFromVar(i,used,callstack);
|
|
|
|
if(ret!=0)
|
|
|
|
{
|
|
|
|
COUT(ERROR)<<" in "<<((type==DepTree::SAVE)?"save":"print")<<" directive "<<((type==DepTree::SAVE)?G_tosave:G_toprint)[index]->Dump()<<"."<<std::endl;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
childrens.insert(d);
|
|
|
|
d->parents.insert(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int DepTree::CreateGlobalTree(UsedType& used)
|
|
|
|
{
|
|
|
|
if(parents.size()!=0)
|
|
|
|
{
|
|
|
|
COUT(ERROR)<<"Internal error, DepTree::CreateGlobalTree() call for non-root node."<<std::endl;
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
type=DepTree::ROOT;
|
|
|
|
for(G_toType::size_type i=0; i<G_tosave.size(); i++)
|
|
|
|
{
|
|
|
|
auto n=*childrens.insert(new DepTree).first;
|
|
|
|
n->parents.insert(this);
|
|
|
|
auto ret=n->CreateNodeFromSP(DepTree::SAVE,i,used);
|
|
|
|
if(ret!=0) return ret;
|
|
|
|
}
|
|
|
|
for(G_toType::size_type i=0; i<G_toprint.size(); i++)
|
|
|
|
{
|
|
|
|
auto n=*childrens.insert(new DepTree).first;
|
|
|
|
n->parents.insert(this);
|
|
|
|
auto ret=n->CreateNodeFromSP(DepTree::PRINT,i,used);
|
|
|
|
if(ret!=0) return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DepTree* DepTree::FindNodeByVarFromCurrent(const std::string& var) const
|
|
|
|
{
|
|
|
|
if(type==DepTree::VAR && name==var) return const_cast<DepTree*>(this);
|
|
|
|
|
|
|
|
DepTree* d;
|
|
|
|
for(auto& i:childrens)
|
|
|
|
{
|
|
|
|
d=i->FindNodeByVarFromCurrent(var);
|
|
|
|
if(d!=0) return d;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DepTree* DepTree::FindNodeByVar(const std::string& var) const
|
|
|
|
{
|
|
|
|
const DepTree* curnode=this;
|
|
|
|
while(curnode->parents.size()!=0) curnode=*(curnode->parents.begin());
|
|
|
|
return curnode->FindNodeByVarFromCurrent(var);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DepTree::LeafVector DepTree::FindLeafNodes() const
|
|
|
|
{
|
|
|
|
LeafVector leafs;
|
|
|
|
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;
|
|
|
|
it=curnode->childrens.begin();
|
|
|
|
end=curnode->childrens.end();
|
|
|
|
|
|
|
|
while(true)
|
|
|
|
{
|
|
|
|
if(it!=end)
|
|
|
|
{
|
|
|
|
if((*it)->visited==isvisited) {it++; continue;}
|
|
|
|
path.push(it); ends.push(end);
|
|
|
|
curnode=(*it);
|
|
|
|
curnode->visited=isvisited;
|
|
|
|
it=curnode->childrens.begin();
|
|
|
|
end=curnode->childrens.end();
|
|
|
|
if(it==end) leafs.push_back(const_cast<DepTree*>(curnode));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(path.size()==0) break;
|
|
|
|
it=path.top(); path.pop();
|
|
|
|
end=ends.top(); ends.pop();
|
|
|
|
it++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return leafs;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Multi-threaded version
|
|
|
|
void TreeEvaluate(std::mutex* mtx, int* errflag, DepTree::LeafVector* leafs, const DepTree* root)
|
|
|
|
{
|
|
|
|
// mtx[0] - mutex for manipulating with LeafVector
|
|
|
|
// mtx[1] - mutex for manipulating with tree
|
|
|
|
DepTree* leaf;
|
|
|
|
ObjectBase *ob,*eob;
|
|
|
|
ObjectList* ol;
|
|
|
|
bool err;
|
|
|
|
while(true)
|
|
|
|
{
|
|
|
|
// Begin locked section (errflag check, leafs manipulations)
|
|
|
|
mtx[0].lock();
|
|
|
|
// Is was error?
|
|
|
|
if(0!=errflag) {mtx[0].unlock(); return;}
|
|
|
|
// Is work finished?
|
|
|
|
if(0==root->childrens.size()) {mtx[0].unlock(); return;}
|
|
|
|
// Is jobs awaiting?
|
|
|
|
if(0==leafs->size()) {mtx[0].unlock(); std::this_thread::yield(); std::this_thread::sleep_for(std::chrono::milliseconds(100)); continue;}
|
|
|
|
// Select working node
|
|
|
|
leaf=*(leafs->begin());
|
|
|
|
// and remove its from list
|
|
|
|
leafs->erase(leafs->begin());
|
|
|
|
mtx[0].unlock();
|
|
|
|
// End locked section
|
|
|
|
|
|
|
|
if(DepTree::SAVE==leaf->type)
|
|
|
|
{
|
|
|
|
err=false;
|
|
|
|
ol=G_tosave[leaf->index];
|
|
|
|
ol->Evaluate(&err); // For list Evaluate always return 0;
|
|
|
|
if(err)
|
|
|
|
{
|
|
|
|
COUT(ERROR)<<" in instruction save"<<ol->Dump()<<")"<<std::endl;
|
|
|
|
*errflag=1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(!Save(ol))
|
|
|
|
{
|
|
|
|
mtx[0].lock();
|
|
|
|
*errflag=1;
|
|
|
|
mtx[0].unlock();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(DepTree::PRINT==leaf->type)
|
|
|
|
{
|
|
|
|
err=false;
|
|
|
|
ol=G_toprint[leaf->index];
|
|
|
|
ol->Evaluate(&err); // For list Evaluate always return 0;
|
|
|
|
if(err)
|
|
|
|
{
|
|
|
|
COUT(ERROR)<<" in instruction print"<<ol->Dump()<<")"<<std::endl;
|
|
|
|
*errflag=1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(!Print(ol))
|
|
|
|
{
|
|
|
|
mtx[0].lock();
|
|
|
|
*errflag=1;
|
|
|
|
mtx[0].unlock();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(DepTree::VAR==leaf->type)
|
|
|
|
{
|
|
|
|
err=false;
|
|
|
|
ob=G_vars.at(leaf->name);
|
|
|
|
// Main working call
|
|
|
|
eob=ob->Evaluate(&err);
|
|
|
|
if(err)
|
|
|
|
{
|
|
|
|
COUT(ERROR)<<" in definition of variable "<<leaf->name<<std::endl;
|
|
|
|
// Begin locked section (errflag set)
|
|
|
|
mtx[0].lock();
|
|
|
|
*errflag=1;
|
|
|
|
mtx[0].unlock();
|
|
|
|
// End locked section
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// eob is evaluated object
|
|
|
|
if(0!=eob) delete ob;
|
|
|
|
else eob=ob;
|
|
|
|
G_vars.erase(leaf->name); // Concurrent access is safe
|
|
|
|
// Begin locked section
|
|
|
|
mtx[1].lock();
|
|
|
|
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;}
|
|
|
|
}
|
|
|
|
// If node have no children, it's a new leaf node
|
|
|
|
if(0==i->childrens.size() && DepTree::ROOT!=i->type) leafs->push_back(i);
|
|
|
|
}
|
|
|
|
mtx[1].unlock();
|
|
|
|
// End locked section
|
|
|
|
leaf->parents.clear();
|
|
|
|
delete leaf;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Single-threaded version
|
|
|
|
void TreeEvaluate(int* errflag, DepTree::LeafVector* leafs)
|
|
|
|
{
|
|
|
|
DepTree* leaf;
|
|
|
|
ObjectBase *ob,*eob;
|
|
|
|
ObjectList* ol;
|
|
|
|
bool err;
|
|
|
|
while(0!=leafs->size())
|
|
|
|
{
|
|
|
|
// Select working node
|
|
|
|
leaf=*(leafs->begin());
|
|
|
|
// and remove its from list
|
|
|
|
leafs->erase(leafs->begin());
|
|
|
|
|
|
|
|
if(DepTree::SAVE==leaf->type)
|
|
|
|
{
|
|
|
|
err=false;
|
|
|
|
ol=G_tosave[leaf->index];
|
|
|
|
ol->Evaluate(&err); // For list Evaluate always return 0;
|
|
|
|
if(err)
|
|
|
|
{
|
|
|
|
COUT(ERROR)<<" in instruction save"<<ol->Dump()<<")"<<std::endl;
|
|
|
|
*errflag=1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// eob is evaluated object
|
|
|
|
if(!Save(ol))
|
|
|
|
{
|
|
|
|
*errflag=1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(DepTree::PRINT==leaf->type)
|
|
|
|
{
|
|
|
|
err=false;
|
|
|
|
ol=G_toprint[leaf->index];
|
|
|
|
ol->Evaluate(&err); // For list Evaluate always return 0;
|
|
|
|
if(err)
|
|
|
|
{
|
|
|
|
COUT(ERROR)<<" in instruction print"<<ol->Dump()<<")"<<std::endl;
|
|
|
|
*errflag=1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(!Print(ol))
|
|
|
|
{
|
|
|
|
*errflag=1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(DepTree::VAR==leaf->type)
|
|
|
|
{
|
|
|
|
err=false;
|
|
|
|
ob=G_vars.at(leaf->name);
|
|
|
|
// Main working call
|
|
|
|
eob=ob->Evaluate(&err);
|
|
|
|
if(err)
|
|
|
|
{
|
|
|
|
COUT(ERROR)<<" in definition of variable "<<leaf->name<<std::endl;
|
|
|
|
*errflag=1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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;}
|
|
|
|
}
|
|
|
|
// If node have no children, it's a new leaf node
|
|
|
|
if(0==i->childrens.size() && DepTree::ROOT!=i->type) leafs->push_back(i);
|
|
|
|
}
|
|
|
|
leaf->parents.clear();
|
|
|
|
delete leaf;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int DepTree::EvaluateTree()
|
|
|
|
{
|
|
|
|
int errflag=0;
|
|
|
|
LeafVector leafs=FindLeafNodes();
|
|
|
|
|
|
|
|
TreeEvaluate(&errflag,&leafs);
|
|
|
|
return errflag;
|
|
|
|
}
|