phrase_parse etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
phrase_parse etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

2 Ocak 2018 Salı

spirit x3 phrase_parse

Giriş
Şu satırı dahil ederiz.
#include <boost/spirit/home/x3.hpp>
Kolay kullanmak için şöyle yaparız.
namespace x3 = boost::spirit::x3;
phrase_parse metodu - iterator + grammar + fusion
Metoda iterator , grammar ve fusion nesnesi geçilir.

phrase_parse metodu - iterator + grammar + grammar + std::vector
Şöyle yaparız.  C++ include directivlerini bulmak için kullanılır.
Bu örnekte content tuhaf bir şekilde begin ve end iterator'lere çevriliyor. Ayrıca dördüncü parametre olarak x3::space yerine yeni bir grammer veriliyor.
using namespace boost::spirit::x3;

auto comment_ = space 
          | "//" >> *(char_ - eol) 
          | "/*" >> *(char_ - "*/")
          ;

auto name_ = rule<struct _, std::string> {} = lexeme[
          '<' >> *(char_ - '>' - eol) >> '>'
        | '"' >> *(char_ - '"' - eol) >> '"'
    ];

auto include_ = "#include" >> name_;

auto const content = [&]() -> std::string {
  std::ifstream file(fname);
  return { std::istreambuf_iterator<char>{file}, {} };//string to be parsed
}();

std::vector<std::string> headers;
/*bool ok = */phrase_parse(content.begin(), content.end(),
 *(omit[*(char_ - include_)] >> include_) , comment_, headers);

phrase_parse metodu - std::vector
Şöyle yaparız. fusion vector nesnesi iki defa double template alır.
#include <boost/fusion/container/vector.hpp>

boost::fusion::vector<double, double> p;
x3::phrase_parse(
        s.begin(), s.end(), 
        x3::double_ >> x3::double_, x3::space, 
        p
);
assert( boost::fusion::at_c<0>(p) == 1.2 );
assert( boost::fusion::at_c<1>(p) == 3.4 );
phrase_parse metodu - std::pair
Şu satırı dahil ederiz.
#include <boost/fusion/include/std_pair.hpp>
Örnek
Şöyle yaparız.
std::pair<double, double> p;
std::string input("1.0 2.0");
std::string::iterator input_pos = input.begin();
x3::phrase_parse(input_pos, input.end(),
  x3::double_ >> x3::double_,
  x3::space, p);
Örnek
Şöyle yaparız.
std::string test("1.1");
std::pair<int, int> d;

bool r = qi::phrase_parse(
        test.begin(),
        test.end(),
        qi::int_ >> '.' >> qi::int_,
        space,
        d
        );
Diğer
x3 phrase_parse metodu "variadic overload" yeteneği sunmuyor. Yani en fazla 5 parametre alabiliyor. Eski spirit gibi çalışması için şöyle yaparız.
auto myparse = [](auto& b, auto e, auto const& p, auto&... binds) {
  auto attr = std::tie(binds...);
  return x3::phrase_parse(b, e, p, x3::space, attr);
};

std::string const s = "3.2 4.5";

double d1, d2;
auto begin = s.begin(), end = s.end();

if (myparse(begin, end, x3::double_ >> x3::double_, d1, d2)) {
  std::cout << "Parsed: " << d1 << ", " << d2 << "\n";
} else {
  std::cout << "Parse failed\n";
}

29 Ekim 2017 Pazar

spirit qi phrase_parse metodu

Giriş
Şu satırı dahil ederiz.
#include <boost/spirit/include/qi.hpp>
Kolay kullanım için şu satırları dahil ederiz.
namespace spirit = boost::spirit;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
İmzası
Metodun imzası şöyle
template <typename Iterator, typename Expr, typename Skipper>
inline bool
phrase_parse(
    Iterator& first
  , Iterator last
  , Expr const& expr
  , Skipper const& skipper
  , BOOST_SCOPED_ENUM(skip_flag) post_skip = skip_flag::postskip);
Şöyle yaparız
boost::spirit::phrase_parse(begin, end, grammar, space, obj)
Iterator Parametresi
begin ve end iteratorlerinin backtracking yüzünden ForwardIterator olması gerekir.

Return Type
bool döner. Iterator'leri alırız.
iterator_type iter = input.begin();
iterator_type end  = input.end();
Şöyle yaparız.
std::string input;
if (phrase_parse(iter, end, ...)) {
  ...
}
Aynı zamanda iteratorler de değişir. Açıklaması şöyle
The first iterator is passed by reference. On a successful parse, the iterator is repositioned to the rightmost position consumed by the parser. If this becomes equal to last, the we have a full match, if not then we have a partial match. A partial match happens when the parser is only able to parse a portion of the input.
Şöyle yaparız.
std::cout << "Bytes left = " << std::distance(iter, end); 
std::cout << (iter == end) ? "SUCCEEDED" : "FAILED";
skip parser parametresi 
Bu parametre olarak genelde ascii::space yani qi::space kullanılır. Açıklaması şöyle
It is a very simple parser that simply recognizes whitespace. The skip parser is the one responsible for skipping characters in between parser elements such as double_ and char_
phrase_parse - out Struct
Birinci parametre iterator, ikinci parametre iterator, üçüncü parametre grammar, dördüncü parametre skipper, diğer parametreler sonuçlardır.
Örnek
Şöyle yaparız.
typedef std::string::const_iterator iterator_type;
MyParser myParser;
MyStruct myStruct;

std::string str = ...;

std::string::const_iterator begin_iter = storedString.begin();
std::string::const_iterator end_iter = storedString.end();
//Invoke the parser
bool r = phrase_parse(begin_iter, end_iter, myParser, ascii::space, myStruct);
if (r && begin_iter == end_iter)
{
    std::cout << "Parsing succeeded\n";
} else {
    std::cout << "Parsing failed\n";
}
phrase_parse - out param1 + out param2
Örnek
Elimizde şu girdiler olsun
nam12 = 34.24
nam56 = 43.65
Şöyle yaparız.
std::string input = ...;
std::string name;
double value;

using namespace boost::spirit::qi;
if (phrase_parse(input.begin(), input.end(),
  lexeme[+alnum] >> '=' >> double_, space, name, value))
  std::cout << "Parsed: name = '" << name << "' and value = " << value << "\n";
}
Çıktı olarak şunu alırız.
Parsed: name = 'nam12' and value = 34.24
Parsed: name = 'nam56' and value = 43.65
Örnek
Eliimizde şu generic kod olsun. Bu kod kaç tane out parametresi verilirse verilsin çalışır.
template <typename Parser,typename... Attrs>
void parse(const std::string& str, const Parser& parser, Attrs&... attrs)
{
  std::string::const_iterator iter=std::begin(str), end=std::end(str);
  bool result = qi::phrase_parse(iter,end,parser,qi::space,attrs...);
  if(result && iter==end) {
    std::cout << "Success.";
    int ignore[] = {(print(attrs),0)...};
    std::cout << "\n";
  } else {
    std::cout << "Something failed. Unparsed: \"" << std::string(iter,end) << "\"\n";
  }
}
Bu generic kodu sarmalayarak çağıran kodlar olsun
template <typename Parser>
void parse_with_nodes(const std::string& str, const Parser& parser) 
{
  std::vector<std::string> nodes;
  parse(str,parser,nodes);
}

template <typename Parser>
void parse_with_nodes_and_attr(const std::string& str, const Parser& parser) 
{
  std::vector<std::string> nodes;
  std::pair<std::string,double> attr_pair;
  parse(str,parser,nodes,attr_pair);
}
Elimizde şu iki gramer olsun.
qi::rule<std::string::const_iterator,std::string()> node=+qi::alnum;
qi::rule<std::string::const_iterator,std::pair<std::string,double>(),qi::space_type> attr=
  +qi::alpha >> '=' >> qi::double_;
Bu gramerleri karıştırarak kullanabiliriz. Şöyle yaparız.
parse_with_nodes("node1->node2", node % "->");

parse_with_nodes_and_attr("node1->node2 arrowsize=1.0", node % "->" >> attr);

parse_with_nodes("node1->node2", node >> +("->" >> node));

qi::rule<std::string::const_iterator,std::vector<std::string>(),qi::space_type>
  at_least_two_nodes = node >> +("->" >> node);
parse_with_nodes_and_attr("node1->node2 arrowsize=1.0", at_least_two_nodes >> attr);
phrase_parse - out param1 + out param2 + out param3
Elimizde 3 değişken olsun
int a, b;
boost::optional<int> c;
Şöyle yaparız.
if (!qi::phrase_parse(s.begin(), s.end(),
  qi::lit("A:") >> qi::int_ >> "B:" >> qi::int_ >> -("C:" >> qi::int_), qi::space,
  a, b, c)) {...}