Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/157.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ boost::spirit:qi::rule或包含qi::rule作为解析结果的结构_C++_Parsing_Boost Spirit - Fatal编程技术网

C++ boost::spirit:qi::rule或包含qi::rule作为解析结果的结构

C++ boost::spirit:qi::rule或包含qi::rule作为解析结果的结构,c++,parsing,boost-spirit,C++,Parsing,Boost Spirit,我试图做的是在运行时从ABNF语法文件创建一个解析器。我已经在qi::语法中实现了所有ABNF规则,如下所示: typedef /*qi::rule or struct containing qi::rule*/ parserRule [...] //all other ABNF rules according to RFC 5234 rule = ( rulename[qi::_a = qi::_1] >

我试图做的是在运行时从ABNF语法文件创建一个解析器。我已经在qi::语法中实现了所有ABNF规则,如下所示:

typedef /*qi::rule or struct containing qi::rule*/ parserRule

    [...] //all other ABNF rules according to RFC 5234

    rule =
            (
                    rulename[qi::_a = qi::_1] >>
                    definedAs >>
                    elements[qi::_b = qi::_1] >>
                    cNl
            )[qi::_val = px::bind(&AbnfParserFactory::fromRule, &factory, qi::_a, qi::_b)];


    rulelist =
            +(
                    rule[px::push_back(qi::_a, qi::_1)] |
                    (*cWsp >> cNl)
             ) >>
             eps[qi::_val = px::bind(&AbnfParserFactory::fromRulelist, &factory, qi::_a)];


qi::rule<Iterator, std::map<std::string, parserRule>(), qi::locals<std::vector<parserRule> > >  rulelist;
qi::rule<Iterator, parserRule(), qi::locals<std::string>, qi::locals<parserRule> >              rule;
[...] // all other ABNF rules
问题是关于
parserRule
的类型

如果我使用qi::rule作为类型(就像我通常打算的那样),我将丢失在
ParserFactory
中分配的所有规则名称(就像
fromRule
中的规则名称)。我猜这是由spirit内部工作的方式造成的(
=
操作符总是创建一个新的未命名规则。而
=
用于分配px::bind函数结果)

但是,如果我试图将我的qi::rule封装到一个结构中以避免这个问题,我将无法再使用spirit调试编译代码。以下是我尝试过的:

typedef qi::rule<std::string::const_iterator, std::string()> FactoryRuleType;
struct parserRule
{
    FactoryRuleType mRule;
};

BOOST_FUSION_ADAPT_STRUCT(
 parserRule,
(FactoryRuleType, mRule)
)

[...] //rule definitions like above

debug(rule);
debug(rulelist);
[...] //debug all other rules
typedef qi::rule FactoryRuleType;
结构分析器
{
FactoryRuleType规则;
};
增强融合适应结构(
帕斯瑞尔,
(FactoryRuleType,mRule)
)
[…]//如上所述的规则定义
调试(规则);
调试(规则列表);
[…]//调试所有其他规则
这将给我一个编译错误的负载(这是一个很长的方式张贴在这里)。我花了好几天的时间试图解决这个问题,但没有任何运气。我希望我提到了足够的细节

感谢您的帮助

编译输出摘录:

/usr/include/boost/proto/operators.hpp:295:9: note:   template argument deduction/substitution failed:
/usr/include/boost/proto/operators.hpp: In substitution of ‘template<class Left, class Right> const typename boost::proto::detail::enable_binary<boost::proto::domainns_::deduce_domain, boost::proto::detail::not_a_grammar, boost::mpl::or_<boost::proto::is_extension<Arg>, boost::proto::is_extension<Right> >, boost::proto::tagns_::tag::shift_left, Left&, Right&>::type boost::proto::exprns_::operator<<(Left&, Right&) [with Left = std::basic_ostream<char>; Right = const boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >, std::basic_string<char>()> >]’:
/usr/include/boost/spirit/home/support/attributes.hpp:1226:17:   required from ‘static void boost::spirit::traits::print_attribute_debug<Out, T, Enable>::call_impl3(Out&, const T_&, mpl_::false_) [with T_ = boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >, std::basic_string<char>()> >; Out = std::basic_ostream<char>; T = boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >, std::basic_string<char>()> >; Enable = void; mpl_::false_ = mpl_::bool_<false>]’
/usr/include/boost/spirit/home/support/attributes.hpp:1242:67:   required from ‘static void boost::spirit::traits::print_attribute_debug<Out, T, Enable>::call_impl2(Out&, const T_&, mpl_::false_) [with T_ = boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >, std::basic_string<char>()> >; Out = std::basic_ostream<char>; T = boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >, std::basic_string<char>()> >; Enable = void; mpl_::false_ = mpl_::bool_<false>]’
/usr/include/boost/spirit/home/support/attributes.hpp:1277:52:   required from ‘static void boost::spirit::traits::print_attribute_debug<Out, T, Enable>::call_impl(Out&, const T_&, mpl_::true_) [with T_ = boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >, std::basic_string<char>()> >; Out = std::basic_ostream<char>; T = boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >, std::basic_string<char>()> >; Enable = void; mpl_::true_ = mpl_::bool_<true>]’
/usr/include/boost/spirit/home/support/attributes.hpp:1283:52:   required from ‘static void boost::spirit::traits::print_attribute_debug<Out, T, Enable>::call(Out&, const T&) [with Out = std::basic_ostream<char>; T = boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >, std::basic_string<char>()> >; Enable = void]’
/usr/include/boost/spirit/home/support/attributes.hpp:1303:53:   required from ‘void boost::spirit::traits::print_attribute(Out&, const T&) [with Out = std::basic_ostream<char>; T = boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >, std::basic_string<char>()> >]’
/usr/include/boost/spirit/home/support/attributes.hpp:1196:57:   [ skipping 34 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/usr/include/boost/function/function_template.hpp:722:7:   required from ‘boost::function4<R, T1, T2, T3, T4>::function4(Functor, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type) [with Functor = boost::spirit::qi::debug_handler<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >, boost::spirit::context<boost::fusion::cons<FactoryReturnType&, boost::fusion::nil>, boost::fusion::vector0<> >, boost::spirit::unused_type, boost::spirit::qi::simple_trace>; R = bool; T0 = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >&; T1 = const __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >&; T2 = boost::spirit::context<boost::fusion::cons<FactoryReturnType&, boost::fusion::nil>, boost::fusion::vector0<> >&; T3 = const boost::spirit::unused_type&; typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type = int]’
/usr/include/boost/function/function_template.hpp:1069:16:   required from ‘boost::function<R(T0, T1, T2, T3)>::function(Functor, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type) [with Functor = boost::spirit::qi::debug_handler<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >, boost::spirit::context<boost::fusion::cons<FactoryReturnType&, boost::fusion::nil>, boost::fusion::vector0<> >, boost::spirit::unused_type, boost::spirit::qi::simple_trace>; R = bool; T0 = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >&; T1 = const __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >&; T2 = boost::spirit::context<boost::fusion::cons<FactoryReturnType&, boost::fusion::nil>, boost::fusion::vector0<> >&; T3 = const boost::spirit::unused_type&; typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type = int]’
/usr/include/boost/function/function_template.hpp:1124:5:   required from ‘typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, boost::function<R(T0, T1, T2, T3)>&>::type boost::function<R(T0, T1, T2, T3)>::operator=(Functor) [with Functor = boost::spirit::qi::debug_handler<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >, boost::spirit::context<boost::fusion::cons<FactoryReturnType&, boost::fusion::nil>, boost::fusion::vector0<> >, boost::spirit::unused_type, boost::spirit::qi::simple_trace>; R = bool; T0 = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >&; T1 = const __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >&; T2 = boost::spirit::context<boost::fusion::cons<FactoryReturnType&, boost::fusion::nil>, boost::fusion::vector0<> >&; T3 = const boost::spirit::unused_type&; typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, boost::function<R(T0, T1, T2, T3)>&>::type = boost::function<bool(__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >&, const __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >&, boost::spirit::context<boost::fusion::cons<FactoryReturnType&, boost::fusion::nil>, boost::fusion::vector0<> >&, const boost::spirit::unused_type&)>&]’
/usr/include/boost/spirit/home/qi/nonterminal/debug_handler.hpp:122:13:   required from ‘void boost::spirit::qi::debug(boost::spirit::qi::rule<Iterator, T1, T2, T3, T4>&) [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >; T1 = FactoryReturnType(); T2 = boost::spirit::unused_type; T3 = boost::spirit::unused_type; T4 = boost::spirit::unused_type]’
../src/AbnfReader.hpp:350:14:   required from ‘AbnfRules<Iterator>::AbnfRules() [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >]’
../src/AbnfReader.cpp:27:12:   required from here
/usr/include/boost/proto/operators.hpp:295:9: error: no type named ‘type’ in ‘struct boost::proto::detail::enable_binary<boost::proto::domainns_::deduce_domain, boost::proto::detail::not_a_grammar, boost::mpl::or_<boost::proto::is_extension<std::basic_ostream<char> >, boost::proto::is_extension<const boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >, std::basic_string<char>()> > >, mpl_::bool_<false>, mpl_::bool_<false>, mpl_::bool_<false> >, boost::proto::tagns_::tag::shift_left, std::basic_ostream<char>&, const boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >, std::basic_string<char>()> >&>’
make: *** [src/AbnfReader.o] Error 1
/usr/include/boost/proto/operators.hpp:295:9:注意:模板参数推断/替换失败:

/usr/include/boost/proto/operators.hpp:用“模板const typename boost::proto::detail::enable_binary::type boost::proto::exprns_216;::operator”来代替“模板const typename boost::proto::detail::enable_binary::type boost::proto::exprns_216;::operator”这里有

  • 单元素自适应结构会带来问题,请参见:[链接]

  • 调试信息需要调试打印特性的专门化(可以追溯到
    ostream
    streaming)。显然,
    qi::rule
    没有这样做。所以,要么加上这个

    也许,只是也许你可以让包含的struct iostream能够避免它(但我担心融合适应可能会优先考虑。这是一次尝试)



  • 是的,你是对的。我必须在运行时动态编写语法。为了确保这是可能的,我已经编写了一系列测试代码片段,它们按照预期的方式工作

    • 直言不讳地说:精神不是实现这一目标的工具。Spirit是一个从“praser表达式”(表达式模板)生成静态编译语法的工具。整个目的是在编译时使用静态多态性并进行充分优化。我建议您创建一组运行时多态解析器组件(反过来,您可以使用Spirit:)来实现),并用它们来编写动态语法

      一种可能的中间立场是使用
      qi::lazy
      和一组预定义的不可变“atom”规则(因此不是动态组合的),并通过引用使用这些“atom”规则来组合解析器

    • 基本上,只要您不尝试动态组合表达式模板(而是现成的类型擦除的非终端),您就可以了

      如果你还需要更多,你很快就会到达乌兰巴托。有些时候,您可以使用
      boost::proto::deep_copy
      奋力拼搏,但这有其局限性


      • 嗯,这很尴尬。当我试图编写一个像sehe建议的SSCCE时,我发现我的方法实际上一直都在工作。为了解决这个问题,我经历了很多麻烦…:C

        这是一个我试图做的工作示例。虽然它有效,但这种行为仍然有点奇怪,这就是我认为它不能以这种方式工作的原因

        #include <boost/spirit/include/qi.hpp>
        #include <boost/spirit/include/phoenix.hpp>
        
        namespace qi = boost::spirit::qi;
        namespace px = boost::phoenix;
        namespace ascii = boost::spirit::ascii;
        
        typedef qi::rule<std::string::const_iterator, std::string()> parserRule;
        
        
        namespace std
        {
        std::ostream& operator<<(std::ostream& stream, const parserRule& val);
        }
        std::ostream& std::operator<<(std::ostream& stream, const parserRule& val)
        {
            stream << "RULE( " << val.name();
            stream << " )";
            return stream;
        }
        
        class Factory
        {
        public:
            Factory(){}
            parserRule createParser(std::string str)
            {
                parserRule r;
                r = qi::char_(str);
                r.name("FactoryRule");
                std::cout << r.name() << " now parses >" + str + "<" << std::end;
                return r;
            }
        };
        
        template <typename Iterator>
        struct TestGrammar : qi::grammar<Iterator, parserRule()>
        {
        
            TestGrammar() : TestGrammar::base_type(start, "Test grammar")
            {
                start = stringRule.alias();
                stringRule =    (
                        ascii::char_("'") >>
                        *(ascii::char_ - ascii::char_("'"))[qi::_a += qi::_1] >>
                        ascii::char_("'")
                )[qi::_val = px::bind(&Factory::createParser, &factory, qi::_a)];
        
                start.name("Start");
                stringRule.name("StringRule");
        
                qi::debug(start);       // shows "RULE( unnamed-rule )"
                qi::debug(stringRule);  // shows "RULE( unnamed-rule )"
            }
        
            qi::rule<Iterator, parserRule() > start;
            qi::rule<Iterator, parserRule(), qi::locals<std::string> > stringRule;
            Factory factory;
        };
        
        int main()
        {
            typedef std::string::const_iterator iterator_type;
            typedef TestGrammar<iterator_type> TGrammar;
        
        
            TGrammar test_parser;
        
            std::string test = "parse THIS!";
            std::string input = "'"+test+"'";
            parserRule result;
        
            std::string::const_iterator iter = input.begin();
            std::string::const_iterator end = input.end();
        
            bool r = parse(iter, end, test_parser, result);
        
            if (r && iter == end)
            {
                std::cout << "-------------------------\n";
                std::cout << "1st Parsing succeeded\n";
                std::cout << "-------------------------\n";
            }
            else
            {
                std::string rest(iter, end);
                std::cout << "-------------------------\n";
                std::cout << "1st Parsing failed\n";
                std::cout << "stopped at: \"" << rest << "\"\n";
                std::cout << "-------------------------\n";
            }
        
            iterator_type first(test.begin()), last(test.end());
        
            qi::debug(result); //shows correct rule name
            r = qi::phrase_parse(first, last, result, boost::spirit::ascii::space);
        
            if (r && iter == end)
            {
                std::cout << "-------------------------\n";
                std::cout << "2nd Parsing succeeded\n";
                std::cout << "-------------------------\n";
            }
            else
            {
                std::string rest(first, last);
                std::cout << "-------------------------\n";
                std::cout << "2nd Parsing failed\n";
                std::cout << "stopped at: \"" << rest << "\"\n";
                std::cout << "-------------------------\n";
            }
        }
        
        #包括
        #包括
        名称空间qi=boost::spirit::qi;
        名称空间px=boost::phoenix;
        名称空间ascii=boost::spirit::ascii;
        typedef qi::rule parserRule;
        名称空间标准
        {
        
        std::ostream&operatorI我不知道你想说什么。你能用一个简洁的方式演示你的问题吗?另外,我有一种感觉,你想动态地编写语法。这条路充满了危险,因为Boost Proto/Boost Phoenix的表达式模板不是为值语义设计的(他们宁愿只作为临时工生活)。您可以在我的答案中搜索关键字
        deep\u copy
        ,来了解您将遇到的许多问题。是的,您是对的。我必须在运行时动态编写语法。为了确保这一点可行,我已经编写了一系列测试片段,这些片段按照预期工作。因此我认为我的方法是可行的(虽然这可能不是最好的)。我会看看你的答案,如果我有时间的话,试着整理一下我的问题。谢谢
        #include <boost/spirit/include/qi.hpp>
        #include <boost/spirit/include/phoenix.hpp>
        
        namespace qi = boost::spirit::qi;
        namespace px = boost::phoenix;
        namespace ascii = boost::spirit::ascii;
        
        typedef qi::rule<std::string::const_iterator, std::string()> parserRule;
        
        
        namespace std
        {
        std::ostream& operator<<(std::ostream& stream, const parserRule& val);
        }
        std::ostream& std::operator<<(std::ostream& stream, const parserRule& val)
        {
            stream << "RULE( " << val.name();
            stream << " )";
            return stream;
        }
        
        class Factory
        {
        public:
            Factory(){}
            parserRule createParser(std::string str)
            {
                parserRule r;
                r = qi::char_(str);
                r.name("FactoryRule");
                std::cout << r.name() << " now parses >" + str + "<" << std::end;
                return r;
            }
        };
        
        template <typename Iterator>
        struct TestGrammar : qi::grammar<Iterator, parserRule()>
        {
        
            TestGrammar() : TestGrammar::base_type(start, "Test grammar")
            {
                start = stringRule.alias();
                stringRule =    (
                        ascii::char_("'") >>
                        *(ascii::char_ - ascii::char_("'"))[qi::_a += qi::_1] >>
                        ascii::char_("'")
                )[qi::_val = px::bind(&Factory::createParser, &factory, qi::_a)];
        
                start.name("Start");
                stringRule.name("StringRule");
        
                qi::debug(start);       // shows "RULE( unnamed-rule )"
                qi::debug(stringRule);  // shows "RULE( unnamed-rule )"
            }
        
            qi::rule<Iterator, parserRule() > start;
            qi::rule<Iterator, parserRule(), qi::locals<std::string> > stringRule;
            Factory factory;
        };
        
        int main()
        {
            typedef std::string::const_iterator iterator_type;
            typedef TestGrammar<iterator_type> TGrammar;
        
        
            TGrammar test_parser;
        
            std::string test = "parse THIS!";
            std::string input = "'"+test+"'";
            parserRule result;
        
            std::string::const_iterator iter = input.begin();
            std::string::const_iterator end = input.end();
        
            bool r = parse(iter, end, test_parser, result);
        
            if (r && iter == end)
            {
                std::cout << "-------------------------\n";
                std::cout << "1st Parsing succeeded\n";
                std::cout << "-------------------------\n";
            }
            else
            {
                std::string rest(iter, end);
                std::cout << "-------------------------\n";
                std::cout << "1st Parsing failed\n";
                std::cout << "stopped at: \"" << rest << "\"\n";
                std::cout << "-------------------------\n";
            }
        
            iterator_type first(test.begin()), last(test.end());
        
            qi::debug(result); //shows correct rule name
            r = qi::phrase_parse(first, last, result, boost::spirit::ascii::space);
        
            if (r && iter == end)
            {
                std::cout << "-------------------------\n";
                std::cout << "2nd Parsing succeeded\n";
                std::cout << "-------------------------\n";
            }
            else
            {
                std::string rest(first, last);
                std::cout << "-------------------------\n";
                std::cout << "2nd Parsing failed\n";
                std::cout << "stopped at: \"" << rest << "\"\n";
                std::cout << "-------------------------\n";
            }
        }
        
        FactoryRule now parses >parse THIS!<
        <Start>
          <try>'parse THIS!'</try>
          <StringRule>
            <try>'parse THIS!'</try>
            <success></success>
            <attributes>[[RULE( unnamed-rule )]]</attributes><locals>(parse THIS!)</locals>
          </StringRule>
          <success></success>
          <attributes>[[RULE( unnamed-rule )]]</attributes>
        </Start>
        -------------------------
        1st Parsing succeeded
        -------------------------
        <FactoryRule>
          <try>parse THIS!</try>
          <success>arse THIS!</success>
          <attributes>[[p]]</attributes>
        </FactoryRule>
        -------------------------
        2nd Parsing succeeded
        -------------------------