2016-05-19 2 views
3

Wie kann ich einen Boost.Spirit-Parser erstellen, der nur Zahlen in einem bestimmten Bereich enthält?Nur bestimmte Zahlen mit Boost.Spirit analysieren

Betrachten Sie den einfachen Parser qi::uint_. Es entspricht allen vorzeichenlosen Ganzzahlen. Ist es möglich, einen Parser zu konstruieren, der mit den Zahlen 0 bis 12345, aber nicht 12346 und größer übereinstimmt?

Antwort

6

Eine Möglichkeit ist zum qi::uint_ Parser eine semantische Aktion anschließen, die das Attribut der Parser überprüft und setzt den dritten Parameter semantischen Aktion entsprechend:

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

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

namespace qi = boost::spirit::qi; 

int main() { 
    qi::rule<std::string::const_iterator, unsigned(), qi::ascii::space_type> rule; 

    const auto not_greater_than_12345 = [](const unsigned& attr, auto&, bool& pass) { 
    pass = !(attr > 12345U); 
    }; 
    rule %= qi::uint_[not_greater_than_12345]; 

    std::vector<std::string> numbers{"0", "123", "1234", "12345", "12346", "123456"}; 
    for (const auto& number : numbers) { 
    unsigned result; 
    auto iter = number.cbegin(); 
    if (qi::phrase_parse(iter, number.cend(), rule, qi::ascii::space, result) && 
     iter == number.cend()) { 
     std::cout << result << '\n'; // 0 123 1234 12345 
    } 
    } 
} 

Live on Wandbox

Die semantische Aktion kann prägnanter geschrieben werden mit the Phoenix placeholders _pass and _1:

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

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

namespace qi = boost::spirit::qi; 

int main() { 
    qi::rule<std::string::const_iterator, unsigned(), qi::ascii::space_type> rule; 

    rule %= qi::uint_[qi::_pass = !(qi::_1 > 12345U)]; 

    std::vector<std::string> numbers{"0", "123", "1234", "12345", "12346", "123456"}; 
    for (const auto& number : numbers) { 
    unsigned result; 
    auto iter = number.cbegin(); 
    if (qi::phrase_parse(iter, number.cend(), rule, qi::ascii::space, result) && 
     iter == number.cend()) { 
     std::cout << result << '\n'; // 0 123 1234 12345 
    } 
    } 
} 

Live on Wandbox


Von Semantic Actions with Parsers

Die möglichen Signaturen für Funktionen als semantische Aktionen verwendet werden sollen:

... 
template <typename Attrib, typename Context> 
void fa(Attrib& attr, Context& context, bool& pass); 

... Hier Attrib ist der Attributtyp des Parsers an den angeschlossenen semantische Aktion. ... Der dritte Parameter pass kann von der semantischen Aktion verwendet werden, um den zugehörigen Parser zum Fehlschlagen zu zwingen. Wenn pass auf false gesetzt ist, gibt der Aktionsparser sofort auch false zurück, während p nicht aufgerufen wird und keine Ausgabe generiert wird.