c++ - Boost Spirit 中的名称表达式没有分配给规则

标签 c++ boost boost-spirit-qi

是否可以在没有分配给规则的情况下在 Boost Spirit 中命名表达式?

我知道您可以通过分配规则来命名它,例如:

using boost::spirit::standard::char_;
boost::spirit::qi::rule<> number = char_("0") | (char_("1-9") >> *char_("0-9"));
number.name("number");

这使得调试语法错误变得更加容易,因为您已经可以以正确的方式命名特定部分。

但是有可能以这种方式内联吗?

using boost::spirit::standard::char_;
boost::spirit::qi::rule<> twoDigits = char_("0-9") > name(char_("0-9"), "digit");

因此,如果它得到像“3a”这样的输入,那么异常会说它期望位置 2 有一个“数字”(这里它是位置 2 并不重要)。

另一种表达方式是:

using boost::spirit::standard::char_;
boost::spirit::qi::rule<> digit = char_("0-9");
digit.name("digit");
boost::spirit::qi::rule<> twoDigits = digit > digit;

我已经检查了源代码并发现该表达式有一个名为 what() 的函数,它返回一个 boost::spirit::info 对象,从中可以检索字符串表示形式。但我无法覆盖它,因为我不熟悉 Boost Proto 和 Boost Spirit 的内部结构。

最佳答案

这是一种使用自定义指令的方法。你可以看到关于如何做类似事情的很好的解释(它是一个解析器,而不是一个指令)here .

创建自定义解析器/指令的过程可以分为四个部分:

  1. 定义/创建终端以在 Spirit 表达式中使用。通常您会使用 BOOST_SPIRIT_TERMINAL除非你需要你的解析器/指令是 parser(whatever) 的形式/directive(whatever)[subject] .在这种情况下,您需要使用 BOOST_SPIRIT_TERMINAL_EX .这种情况特别奇怪,因为您需要与终端关联的状态,因此您需要定义一个派生自 terminal<tag::stateful_tag,...> 的结构。 .这通常不是必需的。我决定将所有这些放在命名空间 custom_directive 中但你也可以把它放在boost::spirit::qi里面.
  2. 启用你的解析器/指令。在这里你需要专门化 use_terminal (对于解析器)或 use_directive (对于指令)在命名空间内 boost::spirit .
  3. 创建实际的解析器/指令。这个解析器/指令需要三样东西:attribute<Context,Iterator>::type关联的元函数,说明你的解析器的属性是什么(在这种情况下,我只是通过了主题解析器的属性);一个parse具有进行真正解析的适当签名的成员函数(我再次推迟到主题解析器)和 what成员函数,这是我们真正感兴趣的修改,它返回您在构建时与终端关联的任何内容。我再次决定使用命名空间 custom_directive但你也可以把它放在boost::spirit::qi里面.
  4. 将终端与您的实际解析器/指令连接。这需要在 boost::spirit::qi 内并要求您专攻 make_directivemake_primitive使用您的终端标签并实例化您的实际解析器/指令。

Live on coliru

#include <iostream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>


//START OF expression_renamer.hpp

namespace custom_directive
{
    BOOST_SPIRIT_TERMINAL(rename_expression);

    struct expression_renamer: boost::spirit::terminal<boost::spirit::tag::stateful_tag<std::string, tag::rename_expression> >
    {
        typedef boost::spirit::tag::stateful_tag<std::string, tag::rename_expression> tag_type;

        expression_renamer(std::string const& p) : boost::spirit::terminal<tag_type>(p) {}
    };
}

namespace boost { namespace spirit
{
    template <>
    struct use_directive<qi::domain, boost::spirit::tag::stateful_tag<std::string, custom_directive::tag::rename_expression> >   // enables expression_renamer[p]
      : mpl::true_ {};
}}

namespace custom_directive
{
    template <typename Subject, typename Data>
    struct rename_directive : boost::spirit::qi::unary_parser<rename_directive<Subject,Data> >
    {
        typedef Subject subject_type;
        rename_directive(Subject const& subject_, Data const& data_)
          : subject(subject_),data(data_) {}

        template <typename Context, typename Iterator>
        struct attribute
        {
            typedef typename
                boost::spirit::traits::attribute_of<subject_type, Context, Iterator>::type
            type;
        };

        template <typename Iterator, typename Context
          , typename Skipper, typename Attribute>
        bool parse(Iterator& first, Iterator const& last, Context& context, Skipper const& skipper, Attribute& attr_) const
        {
            return subject.parse(first, last, context, skipper, attr_);
        }


        template <typename Context>
        boost::spirit::info what(Context& context) const
        {
            return boost::spirit::info(data);

        }

        Subject subject;
        Data data;
    };
}


// instantiation of the parser
namespace boost { namespace spirit { namespace qi 
{
      template<typename Data, typename Subject,typename Modifiers>
      struct make_directive<tag::stateful_tag<Data, custom_directive::tag::rename_expression>, Subject, Modifiers>
      {
        typedef custom_directive::rename_directive<Subject,Data> result_type;

        template<typename Terminal>
        result_type operator()(Terminal& term, Subject const& subject, unused_type) const 
        {
          typedef tag::stateful_tag<Data,
              custom_directive::tag::rename_expression> tag_type;
          using spirit::detail::get_stateful_data;
          return result_type(subject,get_stateful_data<tag_type>::call(term));
        }
      };
}}}


//END OF expression_renamer.hpp

template <typename Parser>
void parse(std::string const& str, Parser const& parser)
{
    std::cout << "Parsing: \"" << str << "\"" << " with `digit` `point` `digit`" << std::endl;
    std::string::const_iterator iter=str.begin(),end=str.end();

    boost::spirit::qi::parse(iter,end,parser);
}

int main()
{
    custom_directive::expression_renamer point("point");
    custom_directive::expression_renamer digit("digit");
    boost::spirit::qi::char_type char_;
    boost::spirit::qi::rule<std::string::const_iterator> twoDigitsWithPoint = char_("0-9") > point[char_('.')] > digit[char_("0-9")];
    boost::spirit::qi::on_error<boost::spirit::qi::fail>
        (
            twoDigitsWithPoint
          , std::cout
                << boost::phoenix::val("Error! Expecting ")
                << boost::spirit::qi::_4                               // what failed?
                << std::endl
        );
    parse("33",twoDigitsWithPoint);
    parse("3.a",twoDigitsWithPoint);

}

关于c++ - Boost Spirit 中的名称表达式没有分配给规则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33424589/

相关文章:

c++ - 根据非静态值对结构进行排序 (C++)

c++ - Boost::filesystem::is_empty() 为符号链接(symbolic link)返回 false

c++ - 找不到boost库

c++ - 提神气 : How to report parser warnings?

c++ - 将 qi::hex 解析器限制为 2 个字符

c++ - Android 上的简单 boost::spirit 语法 SIGSEGV

c++ - 使用 C++ 和 Windows API 的 udp 套接字

c++ - 在定义中使用 typedef 类型

c++ - 由于eof,在C++中读取文件两次?

c++ - 使用 gprof 和 boost