How to create script interpreter with Boost C++
So... Are there any standard libs in boost for creating some scripts/xmls readers that would map that script into objects via some rool开发者_JS百科?
The Boost Spirit library should allow you to define a configuration format fairly easily.
If you want your classes to start up in a particular order, I think a script language is over-kill. What you need is a topographical sort.
What You Need
Boost has a topographical sort. You can also read up on a very-readable C# implementation that should be easy for you to move over to C++, if the boost library is a bit much for you. That can be found here.
What it does
Basically, you provide the sorting algorithm with your classes and then you add their dependencies (the sort algorithm views these as vertices and edges). Once you're done, you apply the algorithm. What you get out is what objects depend on what.
I've used this exact method when I had a bunch of subsystems that needed to be loaded, some of which relied on others, some didn't. The amount of subsystems was arbitrary and due to the plugin nature of the program, unknown at compile time.
I assigned each subsystem a unique identifier (incidentally, using boost::uuid
), and each subsystem listed the identifiers of other subsystems which relied on it. This was fed to the sorter and my initialization order came out the back end.
To help you on your way, here's some code (NOTE: At this point, I did not know that the boost library existed, this is my own implementation based on the C# code from the link I provided above.)
// class TopologicalSorter
template<typename TYPE> class TopologicalSorter
{
private:
std::vector<TYPE> m_Vertices;
std::vector<std::vector<TYPE> > m_Matrix;
std::vector<TYPE> m_Sorted;
TYPE m_nNumVerts;
TYPE m_nSize;
// private helpers
int noSuccessors()
{
bool isEdge;
for(TYPE row(0); row < m_nNumVerts; row++)
{
isEdge = false;
for(TYPE col(0); col < m_nNumVerts; col++)
{
if(m_Matrix[row][col] > 0) // edge to another?
{
isEdge = true;
break;
};
};
if(!isEdge)
return(row);
};
return(-1); // nope!
}; // eo noSuccessors
void deleteVertex(TYPE _vertex)
{
if(_vertex != m_nNumVerts - 1)
{
for(TYPE j(_vertex); j < m_nNumVerts - 1; j++)
m_Vertices[j] = m_Vertices[j + 1];
for(TYPE row(_vertex); row < m_nNumVerts - 1; row++)
moveRowUp(row, m_nNumVerts);
for(TYPE col(_vertex); col < m_nNumVerts - 1; col++)
moveColLeft(col, m_nNumVerts - 1);
};
--m_nNumVerts;
}; // eo deleteVertex
void moveRowUp(TYPE _row, TYPE _length)
{
for(TYPE col(0); col < _length; col++)
m_Matrix[_row][col] = m_Matrix[_row + 1][col];
}; // eo moveRowUp
void moveColLeft(TYPE _col, TYPE _length)
{
for(TYPE row(0); row < _length; row++)
m_Matrix[row][ _col] = m_Matrix[row][_col + 1];
}; // eo moveColLeft
public:
TopologicalSorter(TYPE _size) : m_nNumVerts(0)
, m_Vertices(_size)
, m_Matrix(_size)
, m_Sorted(_size)
, m_nSize(_size)
{
assert(_size > 0);
for(TYPE i(0); i < m_nSize; ++i)
{
for(TYPE j(0); j < m_nSize; ++j)
m_Matrix[i].push_back(0);
};
}; // eo ctor
~TopologicalSorter(){};
// public methods
TYPE addVertex(TYPE _vertex)
{
m_Vertices[m_nNumVerts++] = _vertex;
return(m_nNumVerts - 1);
}; // eo addVertex
void addEdge(TYPE _start, TYPE _end)
{
m_Matrix[_start][_end] = 1;
}; // eo addEdge
std::vector<TYPE> sort()
{
int currVertex;
while(m_nNumVerts)
{
currVertex = noSuccessors();
coreAssert(currVertex != -1, "Graph has cycles");
m_Sorted[m_nNumVerts - 1] = m_Vertices[currVertex];
deleteVertex(currVertex);
}; // eo while(m_nNumVerts)
return(std::move(m_Sorted));
}; // eo sort
}; // eo class TopologicalSorter
Now, this is how this was used with loading and initializing the subsystems (Uuid is just a typedef
for boost::uuids::uuid
)
// create a topological sorter:
utility::TopologicalSorter<ManagerVector_sz> sorter(m_Managers.size());
std::map<Uuid, ManagerVector_sz> indexes;
// add vertices and edges
for(ManagerVector_sz i(0); i < m_Managers.size(); ++i)
indexes.insert(std::pair<Uuid, ManagerVector_sz>(m_Managers[i]->getUuid(), sorter.addVertex(i)));
for(ManagerVector_sz i(0); i < m_Managers.size(); ++i)
{
if(m_Managers[i]->getDependencies().size())
{
for(ManagerVector_sz j(0); j < m_Managers[i]->getDependencies().size(); ++j)
sorter.addEdge(i, indexes[m_Managers[i]->getDependencies()[j]]);
};
};
// get the order in which we should initialise
m_SortedIndexes = sorter.sort();
// and initialise
ManagerVector* mv(&m_Managers);
std::for_each(m_SortedIndexes.rbegin(),
m_SortedIndexes.rend(),
[&mv](int i){mv->at(i)->initialise();});
Hope this helps and avoid an un-necessary script!
精彩评论