2014-02-22 2 views
6

Wie kann ich verhindern, dass der Boost Spirit Symbol Parser ein Schlüsselwort (Symbol) akzeptiert, wenn er mit einem gültigen Schlüsselwort (Symbol) beginnt. Ich möchte, dass das Konstrukt "ONEMORE" als Ganzes nicht analysiert und "ONE" nicht parsen kann, weil das ein gültiges Schlüsselwort ist und dann bei "MORE" fehlschlägt.Verhindern, dass der Boost Spirit Symbol Parser ein Schlüsselwort zu früh akzeptiert

Hier ist die aktuelle Ausgabe des Codes unter:

Keyword as a number: 1 
Keyword as a number: 2 
Keyword as a number: 1 
Invalid keyword: MORETHREE 

Und das ist es, was ich mag es sein:

Keyword as a number: 1 
Keyword as a number: 2 
Invalid keyword: ONEMORE 
Keyword as a number: 3 

Der Code ist nur ein Beispiel, den Punkt zu vermitteln.

#include <boost/config/warning_disable.hpp> 
#include <boost/spirit/include/qi.hpp> 
#include <iostream> 
#include <string> 

using namespace std; 
namespace qi = boost::spirit::qi; 
namespace ascii = boost::spirit::ascii; 

void printNumber(unsigned u) 
{ 
    cout << "Keyword as a number: " << u << endl; 
} 

void printInvalidKeyword(const string &s) 
{ 
    cout << "Invalid keyword: " << s << endl; 
} 

template <typename Iterator> 
struct keyword_parser : qi::grammar<Iterator, ascii::space_type> 
{ 
    struct mySymbols_ : qi::symbols<char, unsigned> 
    { 
     mySymbols_() 
     { 
      add 
      ("ONE" , 1) 
      ("TWO" , 2) 
      ("THREE" , 2) 
      ; 
     } 

    } mySymbols; 

    keyword_parser() : keyword_parser::base_type(start) 
    { 
     using qi::_1; 
     using qi::raw; 
     using ascii::char_; 

     start %= *(
        mySymbols[&printNumber] 
        | 
        invalid[&printInvalidKeyword] 
        ); 

     invalid = +char_; 

    } 

    qi::rule<Iterator, ascii::space_type> start; 
    qi::rule<Iterator, std::string(), ascii::space_type> invalid; 
}; 

int main() 
{ 
    using boost::spirit::ascii::space; 
    typedef std::string::const_iterator iterator_type; 
    typedef keyword_parser<iterator_type> keyword_parser; 

    std::string s = "ONE TWO ONEMORE THREE"; 
    iterator_type b = s.begin(); 
    iterator_type e = s.end(); 
    phrase_parse(b, e, keyword_parser(), space); 

    return 0; 
} 

Antwort

6

Blick auf qi::repository::distinct oder nehmen einige Maßnahmen selbst:

start %= *(
      keyword [cout << val("Keyword as a number: ") << _1 << endl] 
     | invalid [cout << val("Invalid keyword: ")  << _1 << endl] 
     ); 

keyword = mySymbols >> !(char_("a-zA-Z0-9_")); 

invalid = +ascii::graph; 

Die Regeln erklärt werden als

qi::rule<Iterator, ascii::space_type> start; 

// lexemes do not ignore embedded skippables 
qi::rule<Iterator, int()> keyword; 
qi::rule<Iterator, std::string()> invalid; 

es Siehe Live On Coliru

Drucke:

Keyword as a number: 1 
Keyword as a number: 2 
Invalid keyword: ONEMORE 
Keyword as a number: 2 

Voll Quelle:

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

using namespace std; 
namespace qi = boost::spirit::qi; 
namespace phx = boost::phoenix; 
namespace ascii = boost::spirit::ascii; 

template <typename Iterator> 
struct keyword_parser : qi::grammar<Iterator, ascii::space_type> 
{ 
    struct mySymbols_ : qi::symbols<char, unsigned> 
    { 
     mySymbols_() 
     { 
      add 
      ("ONE" , 1) 
      ("TWO" , 2) 
      ("THREE" , 2) 
      ; 
     } 

    } mySymbols; 

    keyword_parser() : keyword_parser::base_type(start) 
    { 
     using qi::_1; 
     using ascii::char_; 
     using phx::val; 

     start %= *(
        keyword [cout << val("Keyword as a number: ") << _1 << endl] 
       | invalid [cout << val("Invalid keyword: ")  << _1 << endl] 
       ); 

     keyword = mySymbols >> !(char_("a-zA-Z0-9_")); 

     invalid = +ascii::graph; 

    } 

    qi::rule<Iterator, ascii::space_type> start; 
    // lexemes do not ignore embedded skippables 
    qi::rule<Iterator, int()> keyword; 
    qi::rule<Iterator, std::string()/*IMPLICIT LEXEME:, ascii::space_type*/> invalid; 
}; 

int main() 
{ 
    using boost::spirit::ascii::space; 
    typedef std::string::const_iterator iterator_type; 
    typedef keyword_parser<iterator_type> keyword_parser; 

    std::string s = "ONE TWO ONEMORE THREE"; 
    iterator_type b = s.begin(); 
    iterator_type e = s.end(); 
    phrase_parse(b, e, keyword_parser(), space); 

    return 0; 
} 
+0

Manche Dinge sind einfach, wenn Sie es nicht :-) Thx sehen. – Halt

Verwandte Themen