1 Kasım 2017 Çarşamba

spirit qi grammar struct

Giriş
Şu satırı dahil ederiz.
#include <boost/spirit/include/qi.hpp>
Daha rahat kullanmak için şu satırlar dahil edilir.
namespace qi = boost::spirit::qi;
namespace bs = boost::spirit;
Bazen şu satır da dahil edilir.
namespace ascii = boost::spirit::ascii;
Template Parametreleri
Birinci parametre parse edilecek iterator tipidir.
İkinci parametre doldurulması beklenen tipi belirtir, yani return type diyelim.
Üçüncü parametre token'ları ayırmak için kullanılacak parser'dır. Genelde qi::space_type kullanılır.

Iterator
Şöyle yaparız
std::string input = "...";
typedef std::string::const_iterator Iter;
MyGrammar<Iter,...> g;
Şöyle yaparız.
std::string input = "...";
auto it = input.begin();
MyGrammar<decltype(it),...>  g;
Skipper
Skipper olarak şöyle yapılır.
ascii::blank_type
Bazen de şöyle yapılır.
ascii::space_type
İkisi arasındaki farkı tam bilmiyorum. blank_type sanırım newline karakterini atlamaz ve okur, space_type ise atlar.

fusion
Şu satırı dahil ederiz.
#include <boost/fusion/include/adapt_struct.hpp>
Şu satırı dahil ederiz.
using namespace boost::fusion;
Elimizde şöyle bir yapı olsun.
struct Foo
{
  std::string field1;
  std::string field2;  std::string field3;};
Şöyle yaparız.
BOOST_FUSION_ADAPT_STRUCT(
  MyNameSpace::Foo,
  (std::string, field1)
  (std::string, field2)
  (std::string, field3)
)
qi::grammar struct - Iterator
Şöyle yaparız. Template parametresi olarak sadece iterator veririr. Diğer parametreler kodlanır.
template <typename It>
struct MyGrammar : qi::grammar<It, Attribute()> {
  MyGrammar() : MyGrammar::base_type(start) {
    start = qi::skip(qi::space) [ mainRule ];
    mainRule = /*....*/;
  }
private:
  qi::rule<It, Attribute()> start;
  qi::rule<It, Attribute(), qi::space_type> mainRule;
};
qi::grammar struct - Iterator + Skipper
Şöyle yaparız. Template parametresi olarak sadece iterator ve skipper verilir. Return type kodlanır.
template <typename Iterator, typename Skipper>
struct MyGrammar : qi::grammar<Iterator, Foo(), Skipper> {
  ...
};
qi::grammar struct - Iterator + Return Type + Skipper
Default parametreler verebiliriz. Şöyle yaparız.
template <typename Iterator, typename Result = std::vector<std::string> > 
struct MyGrammar : public qi::grammar<Iterator, Result(), bs::ascii::space_type> {
};
Default parametre verdiğimiz için sınıf sadece iterator tipi ile ilklendirilir. Şöyle yaparız
std::string input = "...";

auto it = input.begin();
my_grammar<decltype(it)> g;
Constructor - kural
Şöyle yaparız. Her kural = veya kural %= ile belirtilir. Farkını bilmiyorum.

Ayrıca her kural sınıfın private alanında tanımlanmalıdır.
MyGrammar() : MyGrammar::base_type(start) {
    start = ...;
}
private:
qi::rule<Iterator, Foo(), Skipper> start;
Eğer iki kural olsaydı şöyle yaparız. Bazı kurallar için Skipper tanımlanmayabiliyor. Sebebini bilmiyorum
token = ...;
start = ...;
private:
qi::rule<Iterator, Foo(), ascii::blank_type> start;
qi::rule<Iterator, std::string()> token;
kurallar % veya >> karakteri ile birleştirilir. Farkını bilmiyorum.

% karakteri ile şöyle yaparız.
start = token % ',';
token = ...;
>> karakteri ile şöyle yaparız.
token = ...;
start = "VARIABLE" >> text >> qi::eol;
Örnek
Şöyle yaparız.
template <typename It = std::string::const_iterator>
struct parser : qi::grammar<It, AST::Record()> {
  parser() : parser::base_type(start) {
    using namespace qi;

    start     = skip(blank) [record_];

    record_   = prefix_ >> fqdn_ >> int_ >> int_ >> int_ >> int_ >> sample_
                >> '[' >> sample_ >> ']' >> tolerance_;

    prefix_   = string("^+"); // or whatever you need to match here
    fqdn_     = +graph; // or whatever additional constraints you have
    sample_   = direction_ >> duration_;
    duration_ = (long_ >> units_) [ _val = _1 * _2 ];
    tolerance_= "+/-" >> duration_;

    BOOST_SPIRIT_DEBUG_NODES(
      (start)(record_)
      (prefix_)(fqdn_)(sample_)(duration_)(tolerance_)
    )
  }
  private:
    struct directions : qi::symbols<char, AST::TimeSample::Direction> {
     ...
    } direction_;
    struct units : qi::symbols<char, AST::clock::duration> {
        ...
    } units_;

    using Skipper = qi::blank_type;
    qi::rule<It, AST::Record()> start;
    qi::rule<It, AST::Record(), Skipper> record_;
    qi::rule<It, AST::TimeSample(), Skipper> sample_;
    qi::rule<It, AST::clock::duration(), Skipper> duration_, tolerance_;
    // lexemes:
    qi::rule<It, std::string()> prefix_;
    qi::rule<It, std::string()> fqdn_;
};
Örnek - grammer iki gramerden oluşuyor
Elimizde iki gramer olsun. İlk gramer büyük harfle başlayan stringler, ikincisi ise double'ları okur.
struct attr_1 {
    std::string a;
};
BOOST_FUSION_ADAPT_STRUCT(attr_1, (std::string, a))

struct attr_2 {
    double a;
};
BOOST_FUSION_ADAPT_STRUCT(attr_2, (double, a))

template <typename It = const char *>
struct grammar_1 : qi::grammar<It, attr_1()> {
  grammar_1() : grammar_1::base_type{ rule_ } { rule_ = qi::eps >> +ascii::upper; }

  private:
    qi::rule<It, attr_1()> rule_;
};

template <typename It = std::string::const_iterator>
struct grammar_2 : qi::grammar<It, attr_2()> {
  grammar_2() : grammar_2::base_type{ rule_ } { rule_ = qi::double_; }

  private:
    qi::rule<It, attr_2()> rule_;
};
Bu iki grameri içeren bir başka gramer yazmak için şöyle yaparız.
typedef boost::variant<attr_1, attr_2> attr_comp;

template <typename It = std::string::const_iterator>
struct grammar_comp : qi::grammar<It, attr_comp()> {
  grammar_comp() : grammar_comp::base_type{ rule_ } { rule_ = (g1_ | g2_); }

private:
  grammar_1<It> g1_;
  grammar_2<It> g2_;
   qi::rule<It, attr_comp()> rule_;
};
Constructor - kural + string
Şöyle yaparız.
MyGrammar() : MyGrammar::base_type(start, "MY") {  start = ...;
  token = ...;
}




Hiç yorum yok:

Yorum Gönder