1

精神属性的位置,我怎么去追踪?

一个简单的例子

template <typename Iterator>
bool trace_numbers(Iterator first, Iterator last)
{
    using boost::spirit::qi::double_;
    using boost::spirit::qi::phrase_parse;
    using boost::spirit::ascii::space;

    bool r = phrase_parse(first, last,

                          //  Begin grammar
                          (
                              double_ % ','
                          )
            ,
            //  End grammar
            space);

    if (first != last) // fail if we did not get a full match
        return false;
    return r;
}

我想跟踪“double_”的位置(行和列),我找到了line_pos_iterator但不知道如何使用它。我也找到了multi-pass,但不知道它是否可以用于跟踪位置(如果可以,怎么做?)。

4

1 回答 1

1

经过一番研究,我发现单独使用 spirit::lex 或将其与 spirit::qi 结合使用是一种解决方案。

#include <boost/config/warning_disable.hpp>
//[wcp_includes
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_statement.hpp>
#include <boost/spirit/include/phoenix_container.hpp>
//]

#include <iostream>
#include <string>
#include <vector>

namespace spiritParser
{

//[wcp_namespaces
using namespace boost::spirit;
using namespace boost::spirit::ascii;

//[wcp_token_ids
enum tokenids
{
    IDANY = lex::min_token_id + 10
};
//]

//[wcp_token_definition
template <typename Lexer>
struct number_position_track_tokens : lex::lexer<Lexer>
{
    number_position_track_tokens()
    {
        // define patterns (lexer macros) to be used during token definition
        // below
        this->self.add_pattern
            ("NUM", "[0-9]+")
        ;

        number = "{NUM}";    // reference the pattern 'NUM' as defined above

        this->self.add
            (number)          // no token id is needed here
            (".", IDANY)      // characters are usable as tokens as well
        ;
    }

    lex::token_def<std::string> number;
};
//]

template<typename Iterator>
struct numberGrammar : qi::grammar<Iterator>
{
    template <typename TokenDef>
    numberGrammar(TokenDef const &tok)
      : numberGrammar::base_type(start)
      , num(0), position(0)
    {
        using boost::phoenix::ref;
        using boost::phoenix::push_back;
        using boost::phoenix::size;
        //"34, 44, 55, 66, 77, 88"
        start =  *(   tok.number        [++ref(num),
                                         boost::phoenix::push_back(boost::phoenix::ref(numPosition), boost::phoenix::ref(position)),
                                         ref(position) += size(_1)
                                        ]
                  |   qi::token(IDANY)  [++ref(position)]
                  )
              ;
    }

    std::size_t num, position;
    std::vector<size_t> numPosition;
    qi::rule<Iterator> start;
};

void lex_word_count_1()
{
    using token_type = lex::lexertl::token<char const*, boost::mpl::vector<std::string> >;

    number_position_track_tokens<lexer_type> word_count;          // Our lexer
    numberGrammar<iterator_type> g (word_count);  // Our parser

    // read in the file int memory
    std::string str ("34, 44, 55, 66, 77, 88");
    char const* first = str.c_str();
    char const* last = &first[str.size()];       

    if (r) {
        std::cout << "nums: " << g.num << ", size: " << g.position <<std::endl;
        for(auto data : g.numPosition){
            std::cout<<"position : "<<data<<std::endl;
        }
    }
    else {
        std::string rest(first, last);
        std::cerr << "Parsing failed\n" << "stopped at: \""
                  << rest << "\"\n";
    }
}

    } 

这是文档Quickstart 3 - Counting Words Using a Parser with some alteration 中的示例。在我看来,对于像这样的小任务来说,这绝非易事。如果模式对 std::regex 来说不难描述;需要更快的速度或两者兼而有之,选择 spirit::lex 来跟踪简单模式的位置(如我展示的示例)是矫枉过正。

于 2013-10-23T04:12:29.237 回答