【问题标题】:Boost::spirit get value from non-terminalBoost::spirit 从非终端获取价值
【发布时间】:2013-08-26 22:05:28
【问题描述】:

我有这个,在我的 boost::spirit 语法中;

paren = (qi::token(LEFT_PAREN) >> character >> qi::token(RIGHT_PAREN)) [ build_paren ]
          ;
character = qi::token(CHARACTER) [ build_character]
          ;

这些被定义为;

qi::rule<Iterator> paren;
qi::rule<Iterator, char> character;

函数build_paren,具有以下原型(通过编译器转换错误找到);

void build_paren(boost::fusion::vector2<boost::iterator_range<__gnu_cxx::__normal_iterator<char*, std::basic_string<char>>>, boost::iterator_range<__gnu_cxx::__normal_iterator<char*, std::basic_string<char>>>> v)

这里的向量,包含两个字符串,分别是"(\0"")\0",这是我所期望的,但是我如何获得匹配字符的char

真的,我想要的 build_paran 函数原型是;

void build_paren(std::string left_paren, char character, std::string right_paren)

或者,同样的,但是 char 参数是列表中的最后一个参数。

【问题讨论】:

  • 问题: 1. 您确定要将语义操作用于诸如暴露字符属性之类的简单事情吗? 2.qi::token是什么?
  • 也可能很有趣:“Semantic actions are evil”?
  • @sehe:qi::token 的参数是一个枚举,它定义了我来自词法分析器的标记。我知道为此使用语义操作,目前是矫枉过正,但这只是一个玩具示例,在我开始实现完整的解析器之前获得基础知识!我计划在哪里递归地构建我的 AST。
  • 使用词法分析器改变了画面,虽然只是一点点。请务必在token_def&lt;Attr&gt;mpl::vector&lt;&gt; 支持的令牌属性列表中指定属性类型。也就是说,您仍然需要做出规则声明 qi::rule&lt;Iterator, char()&gt; 才能使其正常工作。
  • 我刚刚将解析器规则更改为char(),编译器现在希望build_paren 具有以下原型(如我所愿); void print_paren(boost::fusion::vector3&lt;boost::iterator_range&lt;__gnu_cxx::__normal_iterator&lt;char*, std::basic_string&lt;char&gt;&gt;&gt;, std::string, boost::iterator_range&lt;__gnu_cxx::__normal_iterator&lt;char*, std::basic_string&lt;char&gt;&gt;&gt;&gt; vec),但字符始终为 0

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


【解决方案1】:

你不必那么努力:)

Spirit 具有自动属性传播。实际上,我会说这是它的主要卖点。所以你可以:

char parsed_char;
bool ok = qi::phrase_parse(f,l, '(' >> qi::char_("0-9") >> ')', qi::space, parsed_char);

这将简单地将char_ 解析器组件的暴露属性 绑定到传递给可变参数属性引用 (parsed_char) > 解析 API (phrase_parse)。

下面是一个概括性的演示,展示了您可以通过多种方式来影响确切曝光的内容。解析器指令记录了暴露的确切内容,例如here, for the '%' list parser.

对于您的具体问题,您只需:

qi::rule<Iterator, char()> character;
qi::rule<Iterator, char()> parenthesized;

character     = qi::char_("0-9a-z_"); // or qi::alnum, qi::graph, qi::alpha etc...
parenthesized = '(' >> character >> ')';

注意重要的是,你需要说qi::rule&lt;Iterator, char()&gt;而不是qi::rule&lt;Iterator, char&gt;

示范

看到它Live on Coliru

#include <boost/spirit/include/qi.hpp>
#include <cassert>

namespace qi = boost::spirit::qi;

template<typename ParseExpr, typename... Attr>
void test(const std::string& input, const ParseExpr& p, Attr&... attrs)
{
    auto f = input.begin(), 
         l = input.end();

    bool ok = qi::phrase_parse(f,l, p, qi::space, attrs...);

    if (!ok)
        std::cerr << "parse failed at: '" << std::string(f,l) << "'\n";

    if (f!=l) 
        std::cerr << "trailing unparsed: '" << std::string(f,l) << "'\n";
}

int main()
{
    char parsed_char1, parsed_char2;
    int parsed_int;
    std::string parsed_str;

    test("( 0 )",                        // input
         '(' >> qi::char_("0-9") >> ')', // parser/grammar
         parsed_char1                     // output
    );
    assert(parsed_char1 == '0');

    test("( q 123 )", 
            '(' >> qi::graph >> qi::int_ >> ')', 
            parsed_char1, 
            parsed_int);
    assert(parsed_char1 == 'q');
    assert(parsed_int == 123);

    // parsing strings: with the skipper
    test("( hello world )", 
        '(' >> *~qi::char_(")") >> ')', 
        parsed_str = "");
    assert(parsed_str == "helloworld");

    // parsing strings: qi::char_ exposes the char
    test("( hello world )", 
        qi::char_('(') >>  *~qi::char_(")") >> qi::char_(')'), 
        parsed_char1, parsed_str = "", parsed_char2);
    assert(parsed_char1 == '(');
    assert(parsed_str == "helloworld");
    assert(parsed_char2 == ')');

    // parsing strings: qi::char_ exposes the char, chars get 'combined' into attribute
    test("( hello world )", 
        qi::char_('(') >>  *~qi::char_(")") >> qi::char_(')'), 
        parsed_str = "");
    assert(parsed_str == "(helloworld)");

    // parsing strings: as a lexeme
    test("( hello world )", 
        '(' >> qi::lexeme [ *~qi::char_(")") ] >> ')', 
        parsed_str = "");
    assert(parsed_str == "hello world ");

    // parsing strings: as bigger lexeme
    test("( hello world )", 
        qi::lexeme [ '(' >>  *~qi::char_(")") >> ')' ], 
        parsed_str = "");
    assert(parsed_str == " hello world ");

    // parsing anything as "raw" - exposes an iterator pair, but still 'converts' to a string!
    test("( hello 42 false )", 
        qi::raw [ '(' >>  qi::lexeme[*qi::graph] >> qi::int_ >> qi::bool_ >> ')' ], 
        parsed_str = "");
    assert(parsed_str == "( hello 42 false )");

    // note: this would fail to parse, because with the skipper, *qi::graph would eat "42 false )" as well:
    std::cout << "next parse should fail:\n";
    test("( hello 42 false )", qi::raw [ '(' >>  *qi::graph >> qi::int_ >> qi::bool_ >> ')' ]);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-27
    • 1970-01-01
    • 1970-01-01
    • 2016-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多