如何从精神解析器输出原始的未解析code(作为注释) [英] How do you output the original unparsed code (as a comment) from a spirit parser

查看:172
本文介绍了如何从精神解析器输出原始的未解析code(作为注释)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

 输出:0xa0000023
输出:0xa0010005
-------------------------

我想看看这个:

 输出:0xa0000023 // A = 23
输出:0xa0010005 // B = 5
-------------------------

code的芯线是:

 语句= EPS [_val = 0x50000000]>>标识符[_val + = _1<< 16>>
                     =>>六角[_val + =(_1&安培; 0x0000FFFF)];

在哪里标识符是补气::符号表查找。

我的code的其余部分是这样的:

 的#include<升压/配置/ warning_disable.hpp>
#包括LT&;升压/精神/有/ qi.hpp>
#包括LT&;升压/精神/有/ phoenix_core.hpp>
#包括LT&;升压/精神/有/ phoenix_operator.hpp>
#包括LT&;升压/精神/有/ phoenix_object.hpp>
#包括LT&;升压/融合/有/ adapt_struct.hpp>
#包括LT&;升压/融合/有/ io.hpp>#包括LT&;&iostream的GT;
#包括LT&;&了iomanip GT;
#包括LT&; iOS和GT;
#包括LT&;串GT;
#包括LT&;络合物GT;命名空间补气=的boost ::精神::补气;
命名空间ASCII =的boost ::精神:: ASCII;结构reg16_:补气::符号<字符型,无符号> {
    reg16_(){
        加(A,0)(B,1)(C,2)(D,3);
    }
} reg16;模板< typename的迭代器>
结构dash_script_parser:补气::语法<迭代器,的std ::矢量<&符号GT;(),ASCII ::空间类型> {
    dash_script_parser():dash_script_parser :: base_type(开始){
        使用气::十六进制;
        使用气:: _ VAL;
        使用气:: _ 1;
        使用气:: EPS;        标识%= reg16;        启动(%)=(声明%;);
        [_val = 0x50000000] GT声明= EPS;>标识符[_val + = _1<< 16>> =>>六角[_val + =(_1&安培; 0x0000FFFF)];
    }
    齐::规则<迭代器,的std ::矢量<&符号GT;(),ASCII ::空间类型>开始;
    齐::规则<迭代器,无符号(),ASCII ::空间类型>声明;
    齐::规则<迭代器,无符号()>标识符;
};INT
主要()
{
    性病::法院LT&;< \\ t \\ TA解析器精神... ​​\\ n \\ n<< 键入[q或Q]退出\\ n \\ n;    dash_script_parser<的std ::字符串::为const_iterator> G;
    性病::字符串str;
    而(函数getline(给std :: cin,STR))    {
        如果(str.empty()||海峡[0] =='Q'||海峡[0] =='Q')打破;        标准::字符串::为const_iterator ITER = str.begin();
        标准::字符串::为const_iterator结束= str.end();
        的std ::矢量<&符号GT;可疑交易报告;
        BOOL R = phrase_parse(ITER,最后,克,提振精神:: :: ASCII ::空间,可疑交易报告);
        如果(R&安培;&安培; ITER ==结束){
            对于(的std ::矢量<&符号GT; ::为const_iterator吧= strs.begin();它< strs.end(); ++吧)
                性病::法院LT&;< 输出:0X<<的std ::运输及工务局局长(8)LT;<的std :: setfill(0)LT;<性病::十六进制<< *它<< \\ n;
        }其他
            性病::法院LT&;< 分析失败\\ n;
    }
    返回0;
}


解决方案

更新:一种新的答案带来了 iter_pos 来我的注意力(从升压精神库):

这基本上做同样如下,但没有'滥用'语义动作(使其更加适合,尤其是自动属性传播。


我的直觉说,它可能会更容易隔离的语句为原始源迭代器的范围,然后再解析单独的语句。这样的话,你必须在启动相应的源文本。

有了这样的方式,这里是我测试而不会破坏你的样品code太多工作的方法:


1。使属性键入一个struct

替换原始的无符号与还包含源代码片段的结构体,的逐字的,作为一个字符串

 结构statement_t
{
    无符号值;
    标准::字符串来源;
};BOOST_FUSION_ADAPT_STRUCT(statement_t,(无符号值)(标准::字符串,源));


2。使解析器填补这两个领域

的好处是,你已经在使用语义动作,所以它仅仅是建立了上。注意,结果不是很pretty,并且将被转换成(稠合)算符巨大好处。但它表明该技术很清楚:

 启动(%)=(声明%;);
声明=补气生:: [
        原料[EPS] [at_c&℃,GT;(_ VAL)= 0x50000000]
        >>标识符[at_c&℃,GT;(_ VAL)+ = _1&所述;&下; 16]
        >> =>>六角[at_c&℃,GT;(_ VAL)+ =(_1&放大器; 0x0000FFFF)]
    ]
    [at_c< 1 GT;(_ VAL)=构建<标准::字符串>(开始(_1),端(_1))]
;


3。打印

因此​​, at_c℃的>(_ VAL)对应语句::值 at_c< 1 GT;(_ VAL)对应语句::源。这个稍微修改输出回路:

 为(的std ::矢量<&statement_t GT; ::为const_iterator吧= strs.begin();它< strs.end(); ++吧)
    性病::法院LT&;< 输出:0X<<的std ::运输及工务局局长(8)LT;<的std :: setfill(0)LT;<性病::十六进制<< IT-> VALUE<< //<< IT->源<< \\ n;

输出:

 输出:0x50000023 // A = 23
输出:0x50010005 // B = 5


全样本

 的#include<升压/配置/ warning_disable.hpp>
#包括LT&;升压/精神/有/ qi.hpp>
#包括LT&;升压/精神/有/ phoenix_core.hpp>
#包括LT&;升压/精神/有/ phoenix_operator.hpp>
#包括LT&;升压/精神/有/ phoenix_object.hpp>
#包括LT&;升压/融合/有/ adapt_struct.hpp>
#包括LT&;升压/融合/有/ io.hpp>#包括LT&;&iostream的GT;
#包括LT&;&了iomanip GT;
#包括LT&; iOS和GT;
#包括LT&;串GT;
#包括LT&;络合物GT;命名空间补气=的boost ::精神::补气;
命名空间ASCII =的boost ::精神:: ASCII;#包括LT&;升压/精神/有/ phoenix_fusion.hpp>
#包括LT&;升压/精神/有/ phoenix_stl.hpp>
命名空间PHX =提振::凤;结构reg16_:补气::符号<字符型,无符号> {
    reg16_(){
        加(A,0)(B,1)(C,2)(D,3);
    }
} reg16;结构statement_t
{
    无符号值;
    标准::字符串来源;
};BOOST_FUSION_ADAPT_STRUCT(statement_t,(无符号值)(标准::字符串,源));模板< typename的迭代器>
结构dash_script_parser:补气::语法<迭代器,的std ::矢量<&statement_t GT;(),ASCII ::空间类型> {
    dash_script_parser():dash_script_parser :: base_type(开始){
        使用气::十六进制;
        使用气:: _ VAL;
        使用气:: _ 1;
        使用气:: EPS;
        采用补气生::;        标识%= reg16;        使用PHX ::开始;
        使用PHX ::结束;
        使用PHX :: at_c;
        使用PHX ::建设;        启动(%)=(声明%;);
        声明=原[
                原料[EPS] [at_c&℃,GT;(_ VAL)= 0x50000000]
                >>标识符[at_c&℃,GT;(_ VAL)+ = _1&所述;&下; 16]
                >> =>>六角[at_c&℃,GT;(_ VAL)+ =(_1&放大器; 0x0000FFFF)]
            ]
            [at_c< 1 GT;(_ VAL)=构建<标准::字符串>(开始(_1),端(_1))]
        ;
    }
    齐::规则<迭代器,的std ::矢量<&statement_t GT;(),ASCII ::空间类型>开始;
    齐::规则<迭代器,statement_t(),ASCII ::空间类型>声明;
    齐::规则<迭代器,无符号()>标识符;
};INT
主要()
{
    性病::法院LT&;< \\ t \\ TA解析器精神... ​​\\ n \\ n<< 键入[q或Q]退出\\ n \\ n;    dash_script_parser<的std ::字符串::为const_iterator> G;
    性病::字符串str;
    而(函数getline(给std :: cin,STR))    {
        如果(str.empty()||海峡[0] =='Q'||海峡[0] =='Q')打破;        标准::字符串::为const_iterator ITER = str.begin();
        标准::字符串::为const_iterator结束= str.end();
        的std ::矢量<&statement_t GT;可疑交易报告;
        BOOL R = phrase_parse(ITER,最后,克,提振精神:: :: ASCII ::空间,可疑交易报告);
        如果(R&安培;&安培; ITER ==结束){
            对于(的std ::矢量<&statement_t GT; ::为const_iterator吧= strs.begin();它< strs.end(); ++吧)
                性病::法院LT&;< 输出:0X<<的std ::运输及工务局局长(8)LT;<的std :: setfill(0)LT;<性病::十六进制<< IT-> VALUE<< //<< IT->源<< \\ n;
        }其他
            性病::法院LT&;< 分析失败\\ n;
    }
    返回0;
}

Given the input string: A = 23; B = 5, I currently get the (expected) output:

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

I would like to see this instead:

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

The core line of code is:

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

Where identifier is a qi::symbols table lookup.

The rest of my code looks like this:

#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;
}

解决方案

Update A newer answer brought iter_pos to my attention (from Boost Spirit Repository):

This basically does the same as below, but without 'abusing' semantic actions (making it a much better fit, especially with automatic attribute propagation.


My gut feeling says that it will probably be easier to isolate statements into raw source iterator ranges first, and then parse the statements in isolation. That way, you'll have the corresponding source text at the start.

With that out of the way, here is an approach I tested to work without subverting your sample code too much:


1. Make the attribute type a struct

Replace the primitive unsigned with a struct that also contains the source snippet, verbatim, as a string:

struct statement_t
{
    unsigned    value;
    std::string source;
};

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


2. Make the parser fill both fields

The good thing is, you were already using semantic actions, so it is merely building onto that. Note that the result is not very pretty, and would benefit hugely from being converted into a (fused) functor. But it shows the technique very clearly:

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. Print

So, at_c<0>(_val) corresponds to statement::value, and at_c<1>(_val) corresponds to statement::source. This slightly modified output loop:

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";

outputs:

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


Full sample

#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;
}

这篇关于如何从精神解析器输出原始的未解析code(作为注释)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆