无法使用Boost Spirit语法为std :: map<>使用已知密钥

时间:2018-01-09 23:02:14

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

我似乎正在经历一些带有提升精神的精神障碍,我无法忍受。我有一个相当简单的语法,我需要处理,我想将值放入一个结构,包含一个std :: map<>作为其中一名成员。这些对的关键名称是预先知道的,因此只允许使用这些名称。地图中可能有一对多的键,按任意顺序,每个键名都通过qi验证。

语法看起来像这样,作为一个例子。

test .|*|<hostname> add|modify|save ( key [value] key [value] ... ) ;

//
test . add ( a1 ex00
             a2 ex01
             a3 "ex02,ex03,ex04" );

//
test * modify ( m1 ex10
                m2 ex11
                m3 "ex12,ex13,ex14"
                m4 "abc def ghi" );


//
test 10.0.0.1 clear ( c1
                      c2
                      c3 );

在此示例中,“add”的键为a1,a2和a3,同样用于“修改”m1,m2,m3和m4,每个键必须包含一个值。对于“清除”,地图c1,c2和c3的键可能不包含值。另外,让我们说这个例子你最多可以有10个键(a1 ... a11,m1 ...... m11和c1 ... c11),可以按任何顺序使用它们的任何组合,他们相应的行动。这意味着您无法使用已知密钥c X 来添加&#34;添加&#34;或者 X 用于&#34;清除&#34;

结构遵循这种简单的模式

//
struct test
{
    std::string host;
    std::string action;
    std::map<std::string,std::string> option;
}

所以从上面的例子中,我希望结构包含...

// add ...
test.host = .
test.action = add
test.option[0].first = a1
test.option[0].second = ex00
test.option[1].first = a2
test.option[1].second = ex01
test.option[2].first = a3
test.option[2].second = ex02,ex03,ex04

// modify ...
test.host = *
test.action = modify
test.option[0].first = m1
test.option[0].second = ex10
test.option[1].first = m2
test.option[1].second = ex11
test.option[2].first = m3
test.option[2].second = ex12,ex13,ex14
test.option[2].first = m3
test.option[2].second = abc def ghi

// clear ...
test.host = *
test.action = 10.0.0.1
test.option[0].first = c1
test.option[0].second = 
test.option[1].first = c2
test.option[1].second = 
test.option[2].first = c3
test.option[2].second = 

我可以让每个独立的部分独立工作,但我似乎无法让他们一起工作。例如,我让主机和操作在没有地图&lt;&gt;。

的情况下工作

我已经调整了Sehehere)中之前发布的示例,试图让它工作(BTW:Sehe有一些很棒的例子,我一直在使用它就像文件一样。)

这是摘录(显然不起作用),但至少显示我要去的地方。

namespace ast {

    namespace qi = boost::spirit::qi;

    //
    using unused = qi::unused_type;

    //
    using string  = std::string;
    using strings = std::vector<string>;
    using list    = strings;
    using pair    = std::pair<string, string>;
    using map     = std::map<string, string>;

    //
    struct test
    {
        using preference = std::map<string,string>;

        string host;
        string action;
        preference option;
    };
}

//
BOOST_FUSION_ADAPT_STRUCT( ast::test,
                        ( std::string, host )
                        ( std::string, action ) )
                        ( ast::test::preference, option ) )

//
namespace grammar
{
    //
    template <typename It>
    struct parser
    {
        //
        struct skip : qi::grammar<It>
        {
            //
            skip() : skip::base_type( text )
            {
                using namespace qi;

                // handle all whitespace (" ", \t, ...)
                // along with comment lines/blocks
                //
                // comment blocks: /* ... */
                //                 // ...
                //                 -- ...
                //                 #  ...
                text = ascii::space
                    | ( "#"  >> *( char_ - eol )  >> ( eoi | eol ) ) // line comment
                    | ( "--" >> *( char_ - eol )  >> ( eoi | eol ) ) // ...
                    | ( "//" >> *( char_ - eol )  >> ( eoi | eol ) ) // ...
                    | ( "/*" >> *( char_ - "*/" ) >> "*/" );         // block comment

                //
                BOOST_SPIRIT_DEBUG_NODES( ( text ) )
            }

            //
            qi::rule<It> text;
        };
        //
        struct token
        {
            //
            token()
            {
                using namespace qi;

                // common
                string   = '"' >> *("\\" >> char_ | ~char_('"')) >> '"';
                identity = char_("a-zA-Z_") >> *char_("a-zA-Z0-9_");
                real     = double_;
                integer  = int_;

                //
                value    = ( string | identity );

                // ip target
                any      = '*';
                local    = ( char_('.') | fqdn );
                fqdn     =  +char_("a-zA-Z0-9.\\-" );   // consession

                ipv4     =  +as_string[ octet[ _pass = ( _1 >= 0 && _1 <= 255 ) ] >> '.'
                        >>             octet[ _pass = ( _1 >= 0 && _1 <= 255 ) ] >> '.'
                        >>             octet[ _pass = ( _1 >= 0 && _1 <= 255 ) ] >> '.'
                        >>             octet[ _pass = ( _1 >= 0 && _1 <= 255 ) ] ];

                //
                target   = ( any | local | fqdn | ipv4 );

                //
                pair     =  identity >> -( attr( ' ' ) >> value );
                map      =  pair >> *( attr( ' ' ) >> pair );
                list     =  *( value );

                //
                BOOST_SPIRIT_DEBUG_NODES( ( string )
                                        ( identity )
                                        ( value )
                                        ( real )
                                        ( integer )
                                        ( any )
                                        ( local )
                                        ( fqdn )
                                        ( ipv4 )
                                        ( target )
                                        ( pair )
                                        ( keyval )
                                        ( map )
                                        ( list ) )
            }

            //
            qi::rule<It, std::string()> string;
            qi::rule<It, std::string()> identity;
            qi::rule<It, std::string()> value;
            qi::rule<It, double()>      real;
            qi::rule<It, int()>         integer;
            qi::uint_parser<unsigned, 10, 1, 3> octet;

            qi::rule<It, std::string()> any;
            qi::rule<It, std::string()> local;
            qi::rule<It, std::string()> fqdn;
            qi::rule<It, std::string()> ipv4;
            qi::rule<It, std::string()> target;

            //
            qi::rule<It, ast::map()>  map;
            qi::rule<It, ast::pair()> pair;
            qi::rule<It, ast::pair()> keyval;
            qi::rule<It, ast::list()> list;
        };

    //
        struct test : token, qi::grammar<It, ast::test(), skip>
        {
            //
            test() : test::base_type( command_ )
            {
                using namespace qi;
                using namespace qr;

                auto kw = qr::distinct( copy( char_( "a-zA-Z0-9_" ) ) );

                // not sure how to enforce the "key" names!
                key_     = *( '(' >> *value >> ')' );
                // tried using token::map ... didn't work ...

                //
                add_     = ( ( "add"    >> attr( ' ' ) ) [ _val = "add" ] );
                modify_  = ( ( "modify" >> attr( ' ' ) ) [ _val = "modify" ] );
                clear_   = ( ( "clear"  >> attr( ' ' ) ) [ _val = "clear" ] );

                //
                action_  = ( add_ | modify_ | clear_ );


                /* *** can't get from A to B here ... not sure what to do *** */

                //
                command_ =  kw[ "test" ]
                        >> target
                        >> action_
                        >> ';';

                BOOST_SPIRIT_DEBUG_NODES( ( command_ )
                                        ( action_ )
                                        ( add_ )
                                        ( modify_ )
                                        ( clear_ ) )
            }

            //
            private:
                //
                using token::value;
                using token::target;
                using token::map;

                qi::rule<It, ast::test(), skip> command_;
                qi::rule<It, std::string(), skip> action_;

                //
                qi::rule<It, std::string(), skip> add_;
                qi::rule<It, std::string(), skip> modify_;
                qi::rule<It, std::string(), skip> clear_;
        };

    ...

    };
}

我希望这个问题不是太模糊,如果你需要一个问题的实例,我当然可以提供。非常感谢任何和所有的帮助,所以提前谢谢你!

0 个答案:

没有答案