开发者

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!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜