23 Mayıs 2016 Pazartesi

boost spirit

spirit x3
C++11 ile gelen özelliklerin kullanılabilmesini sağlar. Şöyle kullanılıyor.
namespace x3 = boost::spirit::x3;
Şu satırı dahil ederiz.
#include <boost/spirit/home/x3.hpp>
fusion
Parse işleminde struct gibi nesnelerin kolayca doldurulabilmesini sağlar. Şu satırı dahil ederiz.
#include <boost/fusion/adapted/struct.hpp>
Şöyle yaparız.
struct Point { double x, y, z; };

BOOST_FUSION_ADAPT_STRUCT(Point,x,y,z)
qi
boost spirit qi yazısına taşıdım.

eol
Satır sonunu belirtir.

qi::int_ - parser
qi::int_ ile şöyle yaparız.
char const* b = "66";
char const* e = b + strlen("66");
int32_t res = 0;
bool valid = boost::spirit::qi::parse(b, e, boost::spirit::qi::int_, res);
qi::int_parser<> ile şöyle yaparız.
int res = 0;
namespace qi = boost::spirit::qi;
bool valid = qi::parse(b, e, qi::int_parser<int, 10>(), res);
qi::lexeme
Verilen string'i birebir eşleşir. Şöyle yaparız.
qi::lexeme["self"]
omit
Belirtilen örüntüyü dikkate almaz.
omit[',' >> double_]
raw
Şöyle yaparız.
qi::raw[qi::lexeme["self"]]
seek
Belirtilen örüntüye kadar yürür.
seek[ eps >> 'x' >> 'y' >> 'z' >> eol ]
str_p - parser
Örnek ver.

qi::uint_ - parser
Semantic action tanımlanabilir. Şöyle yaparız.
auto not_greater_than_12345 = [](const unsigned& attr, auto&, bool& pass) {
  pass = !(attr > 12345U);
};
qi::uint_[not_greater_than_12345]
rule
Parser'ların arka arkaya sıralanması gibi düşünülebilir. Şöyle yaparız.
if_rule=str_p(IF)>>ch_p("(")>>if_mem>>*("and"|"or">>if_mem)>>ch_p(")");
grammar
grammar template olarak tanımlanabilir. Şöyle yaparız.
template <typename Iterator, typename Skipper>
struct grammar : qi::grammar<Iterator, MyType(), Skipper>
{
  ...
}
Şöyle yaparız.
template <typename Iterator>
struct grammar : qi::grammar<Iterator, MyType(),ascii::space_type>
{
  ...
}
constructor
struct içinde tanımlı bir qi::rule ata sınıfa geçilir. Şöyle yaparız.
template <typename Iterator, typename Skipper>
struct grammar : qi::grammar<Iterator, MyType(), Skipper>
{
  grammar() : grammar::base_type(object)
  {
    ..
  }
  private:
    qi::rule<Iterator, QVariant(), Skipper> object;
    ...
};
phrase_parse
Şöyle yaparız. Önce begin ve end iterator tanımlanır.
using It = std::string::const_iterator;
std::string input = "...";
It begin = input.begin(), end = input.end();
Daha sonra beklenen çıktı tipi ile çağrılır.
Foo foo;
bool ok = qi::phrase_parse
(begin, end, grammar<It, qi::space_type>{}, qi::space, foo);
Benzer metod x3 ile şöyle kullanılır. Önce begin ve end iterator tanımlanır. Bu sefer dosyadan okuma yapacağımız için memory mapped file tanımlıyoruz.
std::string const fname = ...;
boost::iostreams::mapped_file mm(fname);
Daha sonra bir vector tanımlarız.
std::vector<Point> v;
Ve dosyayı okuruz.
return phrase_parse(mm.begin(), mm.end(),
            ..., //grameri yazmadım
            blank, v);
Çağrı sonucunu şöyle işleriz.
auto f = input.begin(), l = input.end();

bool ok = qi::phrase_parse(f, l, grammar, qi::space);

if (ok)
  std::cout << "Parse success\n";
else
  std::cout << "Parse failed\n";

if (f!=l)
  std::cout << "Trailing unparsed input: '" << std::string(f, l) << "'\n";

parse metodu
Bu metod begin iterator + end iterator + rule + output şeklinde düşünülebilir.

Delimeter
Bir string'i delimeter/separator ile ikiye ayırma örneği şöyle. Biraz düzenli ifadeye benziyor.
*~char_ ile delimeter'a kadar tüme karakterleri alır. Daha sonra separator gelir. Takiben yine tüm karakterleri alıyor. Yakalanan karakterler left ve right stringlerine dolduruluyor.


#include <boost/spirit/include/qi.hpp>

struct misc {
  static void split(const std::string &input,
                    std::string &left, std::string &right, char separator)
  {
    using namespace boost::spirit::qi;

    parse(input.begin(), input.end(), *~char_(separator) >>
                                       separator >> *char_, left, right);
  }
};

Hiç yorum yok:

Yorum Gönder