将精神拆分规则提升为不同的标题

时间:2018-08-22 18:10:11

标签: c++ boost-spirit boost-spirit-qi

我想解析以下结构(为简单起见,我仅显示其中一半,但其余结构与所示结构相同):

*Point, name=1, mission=mission2, inherit_point=bla
*Sn
    22,-22.5
    22,22.5
    22,22.5
    22,22.5
    22,22.5
    22,22.5

*Material
    22.55,22.55,22.55
    22.55,22.55,22.55
*Kt
 1

*Output
    sequiv_fat, sequiv_propa

*End Point

每个部分(以*开头)将被解析为一个结构。主要部分Point将包含子部分Sn,Material和Output。它还将具有属性名称,任务和Inherited_point。

  • Sn部分将被解析为
    struct Sn { std::string name // "Sn" std::map<int,double> data; }

  • 材料成

    struct material { std::string name // "material" std::vector<double> data; }

  • 千吨

    struct Kt { std::string name; // "kt" int value; }

  • 输出

    struct Output { std::string name; //"output" std::vector<std::string> data; }

为了解析本节,我以经过修改的Boost Spirit为例。

我有一个很大的部分要分析,我正在考虑将语法规则分成几个单独的类。我的想法是为要解析的每个子节制定一个规则,并为解析Point节制定一条主要规则。
每个sub rule将被解析为其相应的结构。
要做到这一点,我需要将词法分析器传递给每个“子规则”,但我不知道这样做。

这是我所做的。

从语法定义中可以看到,规则Assigment_Rule2在单独的文件中定义,但是我不知道如何将词法分析器传递给该规则。而且它不会编译。

    #define BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT
#define BOOST_SPIRIT_DEBUG

#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/qi_real.hpp>
#include <boost/spirit/include/qi_eol.hpp>
#include <boost/spirit/include/phoenix.hpp>

#include <iostream>
#include <fstream>
#include <string>
#include <map>

#include "example.hpp"


using namespace boost::spirit;
using boost::phoenix::val;

///////////////////////////////////////////////////////////////////////////////
//  class definition
///////////////////////////////////////////////////////////////////////////////

namespace client {
    namespace qi = boost::spirit::qi;

    struct point
    {
        std::string name;
        std::string name2;
        std::string mission;
        std::string parent_point;
    };
}

BOOST_FUSION_ADAPT_STRUCT(client::point,
    (std::string, name),
    (std::string, name2),
    (std::string, mission),
    (std::string, parent_point)
)

namespace client {
    ///////////////////////////////////////////////////////////////////////////////
    //  Token id definitions
    ///////////////////////////////////////////////////////////////////////////////
    enum token_ids
    {
        ID_CONSTANT = 1000,
        ID_START_POINT,
        ID_END_POINT,
        ID_SN,
        ID_MATERIAL,
        ID_IDENTIFIER,
        ID_INTEGER,
        ID_FLOAT
    };

    ///////////////////////////////////////////////////////////////////////////////
    //  Token definitions
    ///////////////////////////////////////////////////////////////////////////////
    template <typename Lexer>
    struct example6_tokens : lex::lexer<Lexer>
    {
        example6_tokens()
        {
            // define the tokens to match
            identifier = "[a-zA-Z_][a-zA-Z0-9_]*";
            constant = "[0-9]+";
            float_value = "-?\\d+(\\.\\d+)?";

            this->self = lex::token_def<>('(') | ')' | '=' | ',' | '*';

            this->self.add
            (constant, ID_CONSTANT)
                ("Point", ID_START_POINT)
                ("End Point", ID_END_POINT)
                ("Sn", ID_SN)
                ("Material", ID_MATERIAL)
                (identifier, ID_IDENTIFIER)
                (float_value, ID_FLOAT)
                ;

            this->self("WS")
                = lex::token_def<>("[ \\t\\n]+")
                | "\\/\\*[^*]*\\*+([^/*][^*]*\\*+)*\\/"
                ;
        }

        lex::token_def<std::string> identifier;
        lex::token_def<unsigned int> constant;
        lex::token_def<double> float_value;
    };
}

///////////////////////////////////////////////////////////////////////////////
//  Grammar definition
///////////////////////////////////////////////////////////////////////////////

namespace client {

    template <typename Iterator, typename Lexer>
    struct example6_grammar
        : qi::grammar<Iterator, point(), qi::in_state_skipper<Lexer> >
    {
        template <typename TokenDef>
        example6_grammar(TokenDef const& tok)
            : example6_grammar::base_type(start)
        {
            using boost::spirit::_val;
            using boost::spirit::qi::eol;
            using qi::on_error;
            using qi::fail;
            using qi::debug;


            start
                =   '*' 
                    >> token(ID_START_POINT)
                    >> ','
                    >> assignment2
                    >> ','
                    >> assignment2
                    >> ','
                    >> assignment2
                    >> *statement 
                    >> '*' 
                    >> token(ID_END_POINT)
                ;

            statement
                = sn_stmt
                | material_stmt
                ;

            assignment
                = tok.identifier >> '=' >> expression
            ;

            sn_stmt = ('*' >> token(ID_SN) >> +pair)
                [
                    std::cout << val("sn statement to: ")
                    << _1 << "\n"
                ]
            ;

            material_stmt = ('*' >> token(ID_MATERIAL) >> +list)
                [
                    std::cout << val("material statement to: ")
                    << _1 << "\n"
                ]
            ;

            list = token(ID_FLOAT) % ',';

            pair
                = token(ID_CONSTANT) >> ',' >> token(ID_FLOAT)
                ;

            expression
                = tok.identifier[_val = _1]
                | tok.constant[_val = _1]
                ;

            sn_stmt.name("sn_stmt");
            material_stmt.name("material_stmt");
            debug(sn_stmt);
            debug(material_stmt);
        }

        typedef boost::variant<unsigned int, std::string> expression_type;

        qi::rule<Iterator, point(), qi::in_state_skipper<Lexer> > start;
        qi::rule<Iterator, qi::in_state_skipper<Lexer> > statement, material_stmt, pair, list, assignment;
        qi::rule<Iterator, qi::in_state_skipper<Lexer>> sn_stmt;

        qi::rule<Iterator, expression_type(), qi::in_state_skipper<Lexer> >  expression;
        Assigment_Rule2<Iterator> assignment2;
    };
}

///////////////////////////////////////////////////////////////////////////////
int main()
{
    typedef std::string::iterator base_iterator_type;

    typedef lex::lexertl::token<
        base_iterator_type, boost::mpl::vector<unsigned int, std::string, double>
    > token_type;

    typedef lex::lexertl::lexer<token_type> lexer_type;
    typedef client::example6_tokens<lexer_type> example6_tokens;
    typedef example6_tokens::iterator_type iterator_type;

    typedef client::example6_grammar<iterator_type, example6_tokens::lexer_def> example6_grammar;

    example6_tokens tokens;                         // Our lexer
    example6_grammar calc(tokens);                  // Our parser

    std::string str(read_from_file("ReadMe.txt"));

    std::string::iterator it = str.begin();
    iterator_type iter = tokens.begin(it, str.end());
    iterator_type end = tokens.end();

    std::string ws("WS");
    client::point my_point;

    bool r = qi::phrase_parse(iter, end, calc, qi::in_state(ws)[tokens.self], my_point);

    if (r && iter == end)
    {
        std::cout << "-------------------------\n";
        std::cout << "Parsing succeeded\n";
        std::cout << "-------------------------\n";
    }
    else
    {
        std::cout << "-------------------------\n";
        std::cout << "Parsing failed\n";
        std::cout << "-------------------------\n";
    }

    std::cout << "Bye... :-) \n\n";
    return 0;
}

BasicRules.hpp文件

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/qi_real.hpp>
#include <boost/spirit/include/qi_eol.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi_char_.hpp>
#include <boost/spirit/include/qi_lexeme.hpp>

using namespace boost::spirit;
using boost::phoenix::val;

namespace client {
    template <typename Iterator>
    struct Assigment_Rule2
        : qi::grammar<Iterator, std::string()>
    {
        Assigment_Rule2()
            : Assigment_Rule2::base_type(start)
        {
            using boost::spirit::double_;
            using boost::spirit::lexeme;
            using boost::spirit::ascii::char_;

            start = ( "2">> '=' >> "2" )
                [
                    _val = _2
                ]
            ;
        }

        qi::rule<Iterator, std::string()> start;
    };
}

如果有人能给我一些想法和一些起点,我将不胜感激。 谢谢。

0 个答案:

没有答案