2016-07-25 10 views
1

Я честно сдаюсь (как и многие другие передо мной), чтобы найти сам синтаксис этого еще довольно простого генератора boost-spirit- карма библиотека. Я хотел бы показать, до строки, так как многие белые пробелы как символов в строке:Как отображать столько пробелов, сколько символов в отображаемом значении символа перед ним

typedef enum {A, B, C} E; 

class EName : public ka::symbols<E, std::string> 
{ 
public: 
    EName() {add (A,"A") (B,"the B") (C,"a C");} 
}; 

class grm: public ka::grammar<iterator, E()> 
{ 
public: 
    grm():grm::base_type(start) 
    { 
     namespace phx = boost::phoenix; 
     namespace ka = boost::spirit::karma;   
     start = ka::duplicate[ka::repeat(phx::bind(&std::string::size,b))[ka::lit(' ')] << b]; 
    } 
private: 

    ka::rule<iterator,E()> start; 
    EName b; 
}; 

int main(int argc, char * argv[]) 
{ 
    grm g; 
    E e = A; 

    std::string generated; 
    std::back_insert_iterator<std::string> sink(generated); 
    ka::generate(sink,g,e); 
    std::cout << generated << "\n"; 
    generated.clear(); 
    e = B; 
    ka::generate(sink,g,e); 
    std::cout << generated << "\n"; 
    return 0; 
} 

Ожидаемый выход, таким образом, один пробел, затем «А» и на следующей строке 5 белых пространств с последующим «B» (так как «B» - строка из 5 символов).

Я понимаю, что, возможно, переменная «b» недоступна в контексте аргумента генератора ka::repeat()[] ... Я попробовал ka::_val вместо этого без успеха. На самом деле у меня недостаточно опыта работы с кармой, фениксом и слиянием, чтобы построить путь к ответу, хотя я, вероятно, имею доступ ко всей необходимой информации в документации. Поэтому я также хотел бы получить несколько намеков на то, как я могу прийти к ответу только по документации (или по вычету), а не по опыту.

UPDATE:

Я попытался с помощью атрибута ввергнуть без успеха:

namespace boost { 
    namespace spirit { 
     namespace traits { 
      template <> 
      struct transform_attribute<const E, std::string, ka::domain> 
      { 
       typedef std::string type; 
       static type pre(const E & e) { 
        EName s; 
        int num = s.find(e)->size(); 
        return std::string(num, ' '); 
       } 
      }; 
} } } 

следуют:

start = ka::attr_cast<std::string>(ka::string) << b; 

Но при этом это не компилировать.

+0

Вы заставить сделать это с помощью подталкивание? – Angelos

+0

Это мой вопрос. Я знаю, как это сделать без ускорения. – Heyji

ответ

1

Ваша проблема может быть разделена на две части:

  • Получить строку из значения перечислений.
  • Подготовить столько строк, сколько символов в этой строке.

Вторая часть проблемы довольно проста, используя right_align directive. Вы можете просто использовать:

prepend_spaces = ka::right_align(2*phx::size(ka::_val))[ka::string]; 

(Если вы хотите использовать что-то другое, кроме просто пробельных можно использовать второй параметр для right_align (например ka::right_align(2*phx::size(ka::_val),ka::lit('*'))[ka::string]))

Для первой части, вы могли бы сделать что-то с attr_cast, как вы показали. В приведенном ниже коде я использовал phx::bind, чтобы получить строку из таблицы символов.

Running on WandBox

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

#include <boost/spirit/include/karma.hpp> 
#include <boost/spirit/include/phoenix.hpp> 

namespace phx = boost::phoenix; 
namespace ka = boost::spirit::karma; 

typedef enum {A, B, C} E; 

class EName : public ka::symbols<E, std::string> 
{ 
public: 
    EName() {add (A,"A") (B,"the B") (C,"a C");} 
}; 

template <typename Iterator> 
class grm: public ka::grammar<Iterator, E()> 
{ 
public: 
    grm():grm::base_type(start) 
    { 

     prepend_spaces = ka::right_align(2*phx::size(ka::_val))[ka::string]; 
     start = prepend_spaces[ka::_1=phx::bind(&EName::at<E>,phx::ref(name),ka::_val)]; 
    } 
private: 

    ka::rule<Iterator,E()> start; 
    ka::rule<Iterator,std::string()> prepend_spaces; 
    EName name; 
}; 

int main(int argc, char * argv[]) 
{ 
    grm<std::back_insert_iterator<std::string> > g; 
    E e = A; 

    std::string generated; 
    std::back_insert_iterator<std::string> sink(generated); 
    ka::generate(sink,g,e); 
    std::cout << generated << "\n"; 
    generated.clear(); 
    e = B; 
    ka::generate(sink,g,e); 
    std::cout << generated << "\n"; 

    generated.clear(); 
    std::vector<E> v {A,B,C}; 
    ka::generate(sink,+g,v); 
    std::cout << generated << "\n"; 
    return 0; 
} 
+0

Ницца. Должен быть более короткий путь с чем-то вроде ka :: _ 1 = phx :: bind (& EName :: at, phx :: ref (name), ka :: _ val), но я не могу заставить его работать. – Heyji

+0

[This] (http://melpon.org/wandbox/permlink/l8U5r0fasq4fZ08c) был тем, что я имел в виду подходом, использующим «attr_cast» ('transform_attribute' на самом деле, поскольку' attr_cast', похоже, не требуется).Мне не понравился этот подход, потому что я видел много (возможно, уже разрешенных в текущей версии) проблем с 'attr_cast', особенно с Karma. – llonesmiz

1

Я был не так далеко, поэтому отправлю сюда свою первую рабочую попытку. Другие решения также приветствуются.

namespace ka = boost::spirit::karma;  

typedef enum {A, B, C} E; 

class EName : public ka::symbols<E, std::string> 
{ 
public: 
    EName() {add (A,"A") (B,"the B") (C,"a C");} 
}; 

namespace boost { 
    namespace spirit { 
     namespace traits { 
      template <> 
      struct transform_attribute<const E, std::string, ka::domain> 
      { 
       typedef std::string type; 
       static type pre(const E & e) { 
        EName s; 
        int num = s.find(e)->size(); 
        return std::string(num, ' '); 
       } 
      }; 
} } } 

class grm: public ka::grammar<iterator, E()> 
{ 
public: 
    grm():grm::base_type(start) 
    {  
     start = ka::duplicate[ka::attr_cast<std::string>(ka::string) << b]; 
    } 
private: 

    ka::rule<iterator,E()> start; 
    EName b; 
}; 

int main(int argc, char * argv[]) 
{ 
    grm g; 
    E e = A; 

    std::string generated; 
    std::back_insert_iterator<std::string> sink(generated); 
    ka::generate(sink,g,e); 
    std::cout << generated << "\n"; 
    generated.clear(); 
    e = B; 
    ka::generate(sink,g,e); 
    std::cout << generated << "\n"; 
    return 0; 
}