【问题标题】:How do you output the original unparsed code (as a comment) from a spirit parser你如何从精神解析器输出原始的未解析代码(作为注释)
【发布时间】:2012-02-03 23:09:06
【问题描述】:

给定输入字符串:A = 23; B = 5,我目前得到(预期的)输出:

Output: 0xa0000023
Output: 0xa0010005
-------------------------

我想看看这个:

Output: 0xa0000023           // A = 23
Output: 0xa0010005           // B = 5
-------------------------

核心代码行是:

statement   = eps[_val = 0x50000000] >> identifier[_val += _1<<16] >>
                     "=" >> hex[_val += (_1 & 0x0000FFFF)];

其中标识符是 qi::symbols 表查找。

我的其余代码如下所示:

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>

#include <iostream>
#include <iomanip>
#include <ios>
#include <string>
#include <complex>

namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;

struct reg16_ : qi::symbols<char,unsigned> {
    reg16_() {
        add ("A", 0) ("B", 1) ("C", 2) ("D", 3) ;
    }
} reg16;

template <typename Iterator>
struct dash_script_parser : qi::grammar<Iterator, std::vector<unsigned>(), ascii::space_type> {
    dash_script_parser() : dash_script_parser::base_type(start) {
        using qi::hex;
        using qi::_val;
        using qi::_1;
        using qi::eps;

        identifier %= reg16;

        start      %= (statement % ";" );
        statement   = eps[_val = 0x50000000] >> identifier[_val += _1<<16]>> "=" >> hex[_val += (_1 & 0x0000FFFF)];
    }
    qi::rule<Iterator, std::vector<unsigned>(), ascii::space_type> start;
    qi::rule<Iterator, unsigned(), ascii::space_type> statement;
    qi::rule<Iterator, unsigned()> identifier;
};

int
main()
{
    std::cout << "\t\tA parser for Spirit...\n\n" << "Type [q or Q] to quit\n\n";

    dash_script_parser<std::string::const_iterator> g;
    std::string str;
    while (getline(std::cin, str))

    {
        if (str.empty() || str[0] == 'q' || str[0] == 'Q') break;

        std::string::const_iterator iter = str.begin();
        std::string::const_iterator end = str.end();
        std::vector<unsigned> strs;
        bool r = phrase_parse(iter, end, g, boost::spirit::ascii::space, strs);
        if (r && iter == end) {
            for(std::vector<unsigned>::const_iterator it=strs.begin(); it<strs.end(); ++it)
                std::cout << "Output: 0x" << std::setw(8) << std::setfill('0') << std::hex <<*it << "\n";
        } else
            std::cout << "Parsing failed\n";
    }
    return 0;
}

【问题讨论】:

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


    【解决方案1】:

    更新一个更新的答案让我注意到了iter_pos(来自 Boost Spirit Repository):

    这与下面的基本相同,但没有“滥用”语义操作(使其更适合,尤其是自动属性传播。


    我的直觉表明,首先将语句隔离到原始源迭代器范围中,然后单独解析语句可能会更容易。这样一来,您就会在开头获得相应的源文本。

    除此之外,这是我测试过的一种方法,它不会过多地破坏您的示例代码:


    1。将属性类型设为结构

    将原语unsigned 替换为还包含源sn-p 的结构,逐字,作为string

    struct statement_t
    {
        unsigned    value;
        std::string source;
    };
    
    BOOST_FUSION_ADAPT_STRUCT(statement_t, (unsigned, value)(std::string, source));
    

    2。让解析器填充两个字段

    好消息是,您已经在使用语义操作,所以它只是在此基础上构建。请注意,结果不是很漂亮,并且会从转换为(融合的)仿函数中受益匪浅。但它非常清楚地展示了这项技术:

    start      %= (statement % ";" );
    statement   = qi::raw [ 
            raw[eps]      [ at_c<0>(_val)  = 0x50000000 ] 
            >> identifier [ at_c<0>(_val) += _1<<16 ]
            >> "=" >> hex [ at_c<0>(_val) += (_1 & 0x0000FFFF) ]
        ] 
        [ at_c<1>(_val) = construct<std::string>(begin(_1), end(_1)) ]
    ;
    

    3。打印

    所以,at_c&lt;0&gt;(_val) 对应于statement::valueat_c&lt;1&gt;(_val) 对应于statement::source。这个稍作修改的输出循环:

    for(std::vector<statement_t>::const_iterator it=strs.begin(); it<strs.end(); ++it)
        std::cout << "Output: 0x" << std::setw(8) << std::setfill('0') << std::hex << it->value << " // " << it->source << "\n";
    

    输出:

    Output: 0x50000023 // A = 23
    Output: 0x50010005 // B = 5
    

    完整样本

    #include <boost/config/warning_disable.hpp>
    #include <boost/spirit/include/qi.hpp>
    #include <boost/spirit/include/phoenix_core.hpp>
    #include <boost/spirit/include/phoenix_operator.hpp>
    #include <boost/spirit/include/phoenix_object.hpp>
    #include <boost/fusion/include/adapt_struct.hpp>
    #include <boost/fusion/include/io.hpp>
    
    #include <iostream>
    #include <iomanip>
    #include <ios>
    #include <string>
    #include <complex>
    
    namespace qi    = boost::spirit::qi;
    namespace ascii = boost::spirit::ascii;
    
    #include <boost/spirit/include/phoenix_fusion.hpp>
    #include <boost/spirit/include/phoenix_stl.hpp>
    namespace phx   = boost::phoenix;
    
    struct reg16_ : qi::symbols<char,unsigned> {
        reg16_() {
            add ("A", 0) ("B", 1) ("C", 2) ("D", 3) ;
        }
    } reg16;
    
    struct statement_t
    {
        unsigned    value;
        std::string source;
    };
    
    BOOST_FUSION_ADAPT_STRUCT(statement_t, (unsigned, value)(std::string, source));
    
    template <typename Iterator>
    struct dash_script_parser : qi::grammar<Iterator, std::vector<statement_t>(), ascii::space_type> {
        dash_script_parser() : dash_script_parser::base_type(start) {
            using qi::hex;
            using qi::_val;
            using qi::_1;
            using qi::eps;
            using qi::raw;
    
            identifier %= reg16;
    
            using phx::begin;
            using phx::end;
            using phx::at_c;
            using phx::construct;
    
            start      %= (statement % ";" );
            statement   = raw [ 
                    raw[eps]      [ at_c<0>(_val)  = 0x50000000 ] 
                    >> identifier [ at_c<0>(_val) += _1<<16 ]
                    >> "=" >> hex [ at_c<0>(_val) += (_1 & 0x0000FFFF) ]
                ] 
                [ at_c<1>(_val) = construct<std::string>(begin(_1), end(_1)) ]
            ;
        }
        qi::rule<Iterator, std::vector<statement_t>(), ascii::space_type> start;
        qi::rule<Iterator, statement_t(), ascii::space_type> statement;
        qi::rule<Iterator, unsigned()> identifier;
    };
    
    int
    main()
    {
        std::cout << "\t\tA parser for Spirit...\n\n" << "Type [q or Q] to quit\n\n";
    
        dash_script_parser<std::string::const_iterator> g;
        std::string str;
        while (getline(std::cin, str))
    
        {
            if (str.empty() || str[0] == 'q' || str[0] == 'Q') break;
    
            std::string::const_iterator iter = str.begin();
            std::string::const_iterator end = str.end();
            std::vector<statement_t> strs;
            bool r = phrase_parse(iter, end, g, boost::spirit::ascii::space, strs);
            if (r && iter == end) {
                for(std::vector<statement_t>::const_iterator it=strs.begin(); it<strs.end(); ++it)
                    std::cout << "Output: 0x" << std::setw(8) << std::setfill('0') << std::hex << it->value << " // " << it->source << "\n";
            } else
                std::cout << "Parsing failed\n";
        }
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多