2013-10-02 4 views
4

Я хотел бы иметь возможность разбора числа, чтобы сохранить его исходный источник и отслеживать его положение в источнике, сохраняя его в самой структуре.синтаксический анализ синтаксиса с источником

Это то, что я до сих пор:

#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/spirit/home/support/iterators/line_pos_iterator.hpp> 
#include <boost/fusion/include/adapt_struct.hpp> 
#include <boost/fusion/include/io.hpp> 

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

#include <boost/spirit/include/phoenix_fusion.hpp> 
#include <boost/spirit/include/phoenix_stl.hpp> 

struct Position 
{ 
    Position() 
     : line(-1) 
    { 
    } 

    size_t line; 
}; 

struct Number : public Position 
{ 
    Number() 
     : Position() 
     , value(-1) 
     , source() 
    { 
    } 

    unsigned value; 
    std::string source; 
}; 

using namespace boost::spirit; 

BOOST_FUSION_ADAPT_STRUCT(Number, 
          (unsigned, value) 
          (std::string, source) 
          (size_t,  line) 
         ); 

template <typename Iterator> 
struct source_hex : qi::grammar<Iterator, Number()> 
{ 
    source_hex() : source_hex::base_type(start) 
    { 
     using qi::eps; 
     using qi::hex; 
     using qi::lit; 
     using qi::raw; 
     using qi::_val; 
     using qi::_1; 
     using ascii::char_; 

     namespace phx = boost::phoenix; 
     using phx::at_c; 
     using phx::begin; 
     using phx::end; 
     using phx::construct; 

     start = raw[ (lit("0x") | lit("0X")) 
        >> hex [at_c<0>(_val) = _1] 
        ][at_c<2>(_val) = get_line(begin(_1))] 
        [at_c<1>(_val) = construct<std::string>(begin(_1), end(_1))] 

     ; 
    } 

    qi::rule<Iterator, Number()> start; 
}; 

и тест-код:

typedef line_pos_iterator<std::string::const_iterator> Iterator; 
source_hex<Iterator> g; 
Iterator iter(str.begin()); 
Iterator end(str.end()); 

Number number; 
bool r = parse(iter, end, g, number); 
if (r && iter == end) { 
    std::cout << number.line << ": 0x" << std::setw(8) << std::setfill('0') << std::hex << number.value << " // " << number.source << "\n"; 
} else 
    std::cout << "Parsing failed\n"; 

, что я не получаю почему итератор на линии:

[at_c<2>(_val) = get_line(begin(_1))] 

не является параметром line_pos_iterator, даже это тот, который я использую для анализатора. Буду признателен за разъяснения, а также за идеи о том, как решить проблему - каким бы то ни было способом.

+1

и, очевидно, что я делаю полностью выключен - потому что get_line вызывается при построении грамматики – gsf

+1

вам нужно вызвать 'get_line' как«ленивый» функтор (актер Феникса). См. [Этот ответ] (http://stackoverflow.com/questions/8358975/cross-platform-way-to-get-line-number-of-an-ini-file-where-given-option-was-foun/ 8365427 # 8365427) для примера (анализатор Inifile), который использует его – sehe

ответ

6

Посмотрите

#include <boost/spirit/repository/include/qi_iter_pos.hpp> 

Это определяет анализатор, который непосредственно выставляет позицию в качестве атрибута. Позвольте мне добавить пример через несколько минут.

Редактировать Мне нелегко было обучить звуковой сигнал iter_pos в ваш образец без «принятия» вещей и изменения формата вашего типа данных. Я бы очень одобрил это (я бы старался полностью потерять семантические действия). Однако время ограничено.

Вот маленький помощник, который вы можете использовать, чтобы решить вашу проблему:

struct get_line_f 
{ 
    template <typename> struct result { typedef size_t type; }; 
    template <typename It> size_t operator()(It const& pos_iter) const 
    { 
     return get_line(pos_iter); 
    } 
}; 

^Полиморфный актер, использовать в качестве таковых:

start = raw[ qi::no_case["0x"] >> hex [at_c<0>(_val) = _1] ] 
       [ 
        at_c<1>(_val) = construct<std::string>(begin(_1), end(_1)), 
        at_c<2>(_val) = get_line_(begin(_1)) 
       ] 
    ; 

    // with 

boost::phoenix::function<get_line_f> get_line_; 

Примечание Я изменил несколько небольших точек.

Полностью работает демо с выходом: Live On Coliru