Giriş
Çoğu directive'ler [...] şeklindedir.
qi::as_string
Yakalanan değeri string'e çevirir. Şöyle yaparız.
Şöyle yaparız
Elimizde şöyle bir gramer olsun. identifier keyword olmayan ve _ veya alpha ile başlayıp ve n tane alnum veya _ ile devam eder. identifier() şeklinde sonlanır.
qi::hold
boost::optional parse etmek isteyelim
Açıklaması şöyle. İlk eşleşmeden sonra whitespace'in atlanmamasını sağlar.
Örnek
Şöyle yaparız.
Şöyle yaparız.
Şöyle yaparız.
Şöyle yaparız.
Şöyle yaparız.
Şöyle yaparız.
Şöyle yaparız
Örnek ver
qi::omit
Normalde out parametresi veren bir parser'ın vermemesini sağlar.
Örnek
Arka arkaya gelen ayraç ile ayrılmış listeyi parse etmek için % kullanılır.
Şöyle yaparız. Böylece sadece qi::space out parametresi yakalamaz.
Elimizde şöyle bir json olsun. productionYear değerini almak isteyelim.
Şöyle yaparız. include kuralına kadar tüm boşluğun atlanmasını sağlar.
Şöyle yaparız.
qi::raw
Anlamadım
qi::seeek
Eşleşme oluncaya kadar girdi üzerinde yürür. Şöyle yaparız.
Belirtilen karaketerin atlanmasını sağlar. [] içinde gramer verilir.
Örnek
qi::lexeme'in tersine whitespace'in atlanmasını sağlar. Şöyle yaparız
Şöyle yaparız.
Çoğu directive'ler [...] şeklindedir.
qi::as_string
Yakalanan değeri string'e çevirir. Şöyle yaparız.
struct StateStruct { std::string Name; float avalue; };
BOOST_FUSION_ADAPT_STRUCT(StateStruct, Name, avalue)
void print(StateStruct const& ss) { std::cout << "print: " << ss.Name << "\n"; }
namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;
using skipper_type = qi::space_type;
qi::rule<Iterator, StateStruct(), skipper_type> state;
state %=
( qi::as_string [ qi::lexeme[qi::char_("a-zA-Z") >> +qi::char_("-a-zA-Z0-9_")] ] >>
qi::float_
)
[ px::bind(&print, qi::_val) ]
;
qi::distinct
Şu satırı dahil ederiz.#include <boost/spirit/repository/include/qi_distinct.hpp>
Açıklaması şöyle. keyword tanımlamak için kullanılır.The distinct directive takes the subject parser inside the [] block instead of the(). Inside the () specify the exclusion to disallow at the boundary (most often a character set comprising identifier characters).Örnek
Şöyle yaparız
auto kw = distinct(qi::char_("a-zA-Z_0-9"));
module_definition = (kw["module"] >> ident >> '(' >> ident_list >> ')' >> ';');
ÖrnekElimizde şöyle bir gramer olsun. identifier keyword olmayan ve _ veya alpha ile başlayıp ve n tane alnum veya _ ile devam eder. identifier() şeklinde sonlanır.
template <typename It>
struct Grammar : qi::grammar<It> {
Grammar() : Grammar::base_type(start) {
using namespace qi;
auto kw = qr::distinct(copy(enc::alnum | L'_'));
start = skip(enc::space) [function_call];
function_call = identifier >> L'(' >> L')';
identifier = !keyword >> raw[(enc::alpha|L'_') >> *(enc::alnum|L'_')];
keyword = kw[ no_case[keywords] ];
BOOST_SPIRIT_DEBUG_NODES((start)(function_call)(identifier)(keyword));
}
private:
qi::rule<It> start;
qi::rule<It, enc::space_type> function_call;
// implicit lexemes
struct keywords_t : qi::symbols<wchar_t> {
keywords_t() {
this->add
(L"as")(L"class")(L"dim")(L"else")(L"end")(L"false")
(L"for")(L"function")(L"if")(L"new")(L"next")(L"sub")
(L"then")(L"to")(L"true");
}
} keywords;
qi::rule<It, std::string()> identifier, keyword;
};
qi::hold
boost::optional parse etmek isteyelim
typedef std::pair<boost::optional<std::string>, std::string> pair_type;
typedef std::vector<pair_type> pairs_type;
Şöyle yaparız.query = pair % ' ';
pair = -qi::hold[field >> ':'] >> value;
field = +qi::char_("a-zA-Z0-9");
value = +qi::char_("a-zA-Z0-9+-\\.");
qi::rule<Iterator, pairs_type()> query;
qi::rule<Iterator, pair_type()> pair;
qi::rule<Iterator, std::string()> field, value;
qi::lexemeAçıklaması şöyle. İlk eşleşmeden sonra whitespace'in atlanmamasını sağlar.
Açıklaması şöyleKeep in mind that lexeme[] pre-skips spaces. If this is not desired, use the no_skip directive instead.
That means that lexeme will apply skipper before the first match by the enclosed parser. no_skip doesn't do that. Imagine you parse " abc " . Using +char_ and space skipper, result is "abc". WIth lexeme[+char_] it's "abc ". With no_skip[+char_] it's " abc "Kullanımı şöyledir
qi::lexeme[...]
Özellikle anahtar kelimelerde işe yarar. lexeme kullanmazsak şu kelimeleri yanlışlıkla parse edebiliriz.Örnek
Şöyle yaparız.
SE L ECT ...
SELECTa ...
Ama aslında şunu istiyoruzdurSELECT ...
Dolayısıyla lexeme ile skipper'ın beraber kullanılması anlamsız.template <typename Iterator>
struct Grammar: qi::grammar<Iterator, std::vector<std::string>, ascii::space_type>
{
Grammar(): Grammar::base_type(ident_list)
{
ident = qi::lexeme[*qi::alnum];
ident_list = *ident;
}
...
qi::rule<Iterator, std::string, ascii::space_type> ident;
};
ÖrnekŞöyle yaparız.
token = qi::raw[ qi::lexeme[+(qi::alnum | '-')] ];
ÖrnekŞöyle yaparız.
std::string const input { "My list of ident"};
auto f = input.begin(), l = input.end();
std::list<std::string> result;
qi::phrase_parse(f, l, *qi::lexeme[+qi::graph], qi::space, result);
ÖrnekŞöyle yaparız.
quoted_string %= lexeme['"' > +(char_ - '"') > '"'];
ÖrnekŞöyle yaparız.
template <typename IT>
struct cppIdentifier : qi::grammar<IT, std::string(), qi::space_type>
{
cppIdentifier() : cppIdentifier::base_type(start)
{
start = qi::lexeme[char_("a-zA-Z_") >> *(char_("a-zA-Z0-9_"))];
}
qi::rule<IT, std::string(), qi::space_type> start;
};
ÖrnekŞöyle yaparız.
qi::lexeme[":[" >> +ascii::char_("0-9a-fA-F-")]
qi::nocaseŞöyle yaparız
qi::no_case [
qi::lit("my_cmd1") | qi::lit("my_cmd2")
];
Şöyle yaparız.qi::no_case [ -qi::int_ >> qi::lit("no") | "bad" ]
qi::noskipÖrnek ver
qi::omit
Normalde out parametresi veren bir parser'ın vermemesini sağlar.
Örnek
Arka arkaya gelen ayraç ile ayrılmış listeyi parse etmek için % kullanılır.
a % b
ile şu aynıdır.a >> *(omit[b] >> a)Örnek
Şöyle yaparız. Böylece sadece qi::space out parametresi yakalamaz.
-(qi::omit[+qi::space]
>> qi::lit("C:")
>> qi::int_
)
ÖrnekElimizde şöyle bir json olsun. productionYear değerini almak isteyelim.
auto data = {
"cars" : [
{
"name" : "BMW",
"engine" : 3.0
},
{
"name" : "Citroen",
"engine" : 3.6
},
{
"name" : "Ferrari",
"engine" : 4.2
}
],
"productionYear" : 1999
}
Şöyle yaparız.boost::spirit::qi::rule<std::string::const_iterator, int()> production_;
production_ = qi::omit[+(qi::char_ - "productionYear") >> "productionYear\""
>> ' ' >> ':' >> ' '] >> qi::int_;
Çıktı olarak şunu alırız1999
ÖrnekŞöyle yaparız. include kuralına kadar tüm boşluğun atlanmasını sağlar.
*(omit[*(char_ - include_)] >> include_)
ÖrnekŞöyle yaparız.
template <typename It>
struct FileFormat : qi::grammar<It, FormatData()> {
FileFormat() : FileFormat::base_type(start) {
using namespace qi;
signature = string("SIGN"); // 4 byte signature, just for example
header = repeat(16) [byte_]; // 16 byte header, same
payload %= omit[little_word[_len=_1]] >> repeat(_len) [byte_];
start = signature >> header >> payload;
//BOOST_SPIRIT_DEBUG_NODES((start)(signature)(header)(payload))
}
private:
qi::rule<It, FormatData()> start;
qi::rule<It, std::string()> signature, header;
qi::_a_type _len;
qi::rule<It, std::string(), qi::locals<uint16_t> > payload;
};
qi::raw
Anlamadım
qi::seeek
Eşleşme oluncaya kadar girdi üzerinde yürür. Şöyle yaparız.
namespace repo = boost::spirit::repository;
namespace ascii = boost::spirit::ascii;
std::ifstream in("C:/log.txt", std::ios_base::in);
in >> std::noskipws;//No white space skipping
boost::spirit::istream_iterator first(in);
boost::spirit::istream_iterator last;
bool result = qi::phrase_parse(first, last,
*repo::seek[qi::eol
>> +ascii::char_("0-9")
>> ":["
...
>> qi::eol],
ascii::blank,
messages);
qi::skip
Belirtilen karaketerin atlanmasını sağlar. [] içinde gramer verilir.
Örnek
qi::lexeme'in tersine whitespace'in atlanmasını sağlar. Şöyle yaparız
qi::rule<It, qi::space_type> b = "stuff" >> '{' >>
qi::skip(qi::blank) [ int_ >> int_] >> '}';
ÖrnekŞöyle yaparız.
struct Record {
int id;
std::string full_title;
int64_t some;
int64_t data;
};
BOOST_FUSION_ADAPT_STRUCT(Record, id, full_title, some, data)
namespace qi = boost::spirit::qi;
using It = std::string::const_iterator;
qi::rule<It, std::string()> quoted= '"' >> *('\\' >> qi::char_ | ~qi::char_('"')) >> '"';
qi::rule<It, Record()> parser= qi::skip(',') [qi::int_ >> quoted >> qi::int_ >> qi::int_];
std::string const line1(R"(1500,"Rev, H., Tintin, K.H. Ken",204400,350)");
Record record;
if (parse(line1.begin(), line1.end(), parser, record))
{
std::cout << "Parsed: \n";
std::cout << " record.id = " << record.id << "\n";
std::cout << " record.full_title = " << record.full_title << "\n";
std::cout << " record.some = " << record.some << "\n";
std::cout << " record.data = " << record.data << "\n";
}
Çıktı olarak şunu alırız.Parsed:
record.id = 1500
record.full_title = Rev, H., Tintin, K.H. Ken
record.some = 204400
record.data = 350