Boost Spirit Qi Parser
-
Danke für die Hinweise. Ich werd's mit wohl an ein kalteren Tagen nochmal ansehen.
Erstaml geht es mir um die richtige und tatsächliche Reihenfolge der semantischen Aktionen. Es macht mich nur bisschen stutzig, weil ein anderes Programm genauso aufgebaut ist, allerdings verhält es sich korrekt, wie erwartet.
#include <iostream> #include <string> #include <boost/spirit/include/lex_lexertl.hpp> #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/phoenix_operator.hpp> #include <boost/spirit/include/phoenix_statement.hpp> #include <boost/spirit/include/phoenix_container.hpp> #include <boost/bind.hpp> #include <boost/ref.hpp> using namespace boost::spirit; using namespace boost::spirit::lex; using namespace boost::spirit::ascii; template<class Lexer> struct rules : lexer<Lexer> { rules() { this->self.add_pattern("DIGIT", "[0-9]"); this->self.add_pattern("PREFIX", "[-|+]"); digit = "{DIGIT}"; prefix = "{PREFIX}"; this->self.add(digit); this->self.add(prefix); } lex::token_def<std::string> digit, prefix; }; void m_digit() { std::cout << "digit" << std::endl; } void m_prefix() {std::cout << "prefix" << std::endl;} void m_pair() {std::cout << "pair" << std::endl;} void m_end() {std::cout << "end" << std::endl;} template<class Iterator> struct grammar : qi::grammar<Iterator> { template<class TokenDefinition> grammar(const TokenDefinition& td) : grammar::base_type(start) { using boost::bind; prefix = td.prefix [bind(m_prefix)] ; digit = td.digit [bind(m_digit)] ; pair = (prefix >> digit) [bind(m_pair)] ; start = pair [bind(m_end)] ; } qi::rule<Iterator> start, pair ,digit, prefix; }; int main() { typedef lexertl::token<char const*, boost::mpl::vector<std::string> > token_type; typedef lexertl::lexer<token_type> lexer_type; typedef rules<lexer_type>::iterator_type iterator_type; rules<lexer_type> my_lexer; grammar<iterator_type> my_parser(my_lexer); while(true) { std::string input; std::cin >> input; char const* first = input.c_str(); char const* last = &first[input.size()]; lex::tokenize_and_parse(first, last, my_lexer, my_parser); } std::cin.get(); }
-
Kannst Du bitte an Hand einer konkreten Eingabe-Zeichenkette zeigen, welches Ergebnis Du siehst und was Du eigentlich sehen wolltest?
Regards Hartmut
-
Ja gern

1. Version
Eingabe:
'Hallo' trueAusgabe:
stringErwartet:
string
bool
end2. Version
Eingabe:
+1Ausgabe:
prefix
digit
pair
endErwartet:
prefix
digit
pair
end
-
Zeus schrieb:
Ja gern

1. Version
Eingabe:
'Hallo' trueAusgabe:
stringErwartet:
string
bool
endWenn Du das Leerzeichen zwischen 'Hallo' und true wegläßt, dann bekommst Du die erwartete Ausgabe. Weder der Lexer, noch der Parser wissen etwas über ein einzelnes (oder auch mehrere) Leerzeichen, Deine Eingabe kann also nicht 'gematched' werden. Der Rückgabewert von lex::tokenize_and_parse is false (der Parser liefert diesen Fehler), zusätzlich ist nach dem Aufruf von tokenize_and_parse first != last, was darauf hinweist, daß die Eingabe nicht vollständig verarbeitet wurde.
Zeus schrieb:
2. Version
Eingabe:
+1Ausgabe:
prefix
digit
pair
endErwartet:
prefix
digit
pair
endHier stimmt ja alles

Regards Hartmut
-
Hmm ok,... *peinlich wegrennen*
In der Tat hab ich die Whitespaces nicht mehr gedacht. Ich weiß, wie ich die Sachen im Lexergenerator Flex einstellen, einfach eine leere Regeln ohne Aktion. Wie ist ein Spirit.Lex, ich hab ein wenig probiert und in die Dokumentation nachgesehen erstmal ohne Erfolg. Geht das nur mit eine Skip Grammar?
-
Zeus schrieb:
In der Tat hab ich die Whitespaces nicht mehr gedacht. Ich weiß, wie ich die Sachen im Lexergenerator Flex einstellen, einfach eine leere Regeln ohne Aktion. Wie ist ein Spirit.Lex, ich hab ein wenig probiert und in die Dokumentation nachgesehen erstmal ohne Erfolg. Geht das nur mit eine Skip Grammar?
Am einfachsten ist es wohl, dem Lexer zu sagen bestimmte Tokens zu ignorieren:
template<class Lexer> struct rules : lexer<Lexer> { rules() { using lex::_pass; using lex::pass_flags; this->self.add_pattern("DIGIT", "[0-9]"); this->self.add_pattern("PREFIX", "[-|+]"); digit = "{DIGIT}"; prefix = "{PREFIX}"; ws = "[ \t\n]"; this->self.add(digit); this->self.add(prefix); this->self += ws [_pass = pass_flags::pass_ignore]; } lex::token_def<std::string> digit, prefix; lex::token_def<> ws; };Die einzige Besonderheit ist, daß der verwendete Lexer vom Typ
lex::lexertl::actor_lexer<token_type>sein muß (ansonsten bekommst Du auf Grund der semantischen Aktion mehrere Compiler-Fehler).
Regards Hartmut
-
-
Zeus schrieb:
Bitte stelle mir das vollständige Programm zur Verfügung, ich schau es mir dann an.
Regards Hartmut
-
Vielen Danke, dass du dir so viele Mühe mit mir machst

Eingabe sind:
+1 Geht
+ 1 Geht nie#include <iostream> #include <string> #include <boost/spirit/include/lex_lexertl.hpp> #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/phoenix_operator.hpp> #include <boost/spirit/include/phoenix_statement.hpp> #include <boost/spirit/include/phoenix_container.hpp> #include <boost/bind.hpp> #include <boost/ref.hpp> using namespace boost::spirit; using namespace boost::spirit::lex; using namespace boost::spirit::ascii; template<class Lexer> struct rules : lexer<Lexer> { rules() { using lex::_pass; using lex::pass_flags; this->self.add_pattern("DIGIT", "[0-9]"); this->self.add_pattern("PREFIX", "[-|+]"); digit = "{DIGIT}"; prefix = "{PREFIX}"; //ws = "[ ]"; // Geht nicht //ws = "[\\ ]"; // Geht nicht //ws = "[\\\x20]"; // Geht nicht //ws = "[\x20]"; // Geht nicht ws = "[ \t\n]"; // Geht nicht //ws = "[x]"; // Geht this->self.add(digit); this->self.add(prefix); this->self += ws [_pass = pass_flags::pass_ignore]; } lex::token_def<std::string> digit, prefix; lex::token_def<> ws; }; void m_digit() { std::cout << "digit" << std::endl; } void m_prefix() {std::cout << "prefix" << std::endl;} void m_pair() {std::cout << "pair" << std::endl;} void m_end() {std::cout << "end" << std::endl;} template<class Iterator> struct grammar : qi::grammar<Iterator> { template<class TokenDefinition> grammar(const TokenDefinition& td) : grammar::base_type(start) { using boost::bind; prefix = td.prefix [bind(m_prefix)] ; digit = td.digit [bind(m_digit)] ; pair = (prefix >> digit) [bind(m_pair)] ; start = pair [bind(m_end)] ; } qi::rule<Iterator> start, pair ,digit, prefix; }; int main() { typedef lexertl::token<char const*, boost::mpl::vector<std::string> > token_type; typedef lexertl::actor_lexer<token_type> lexer_type; typedef rules<lexer_type>::iterator_type iterator_type; rules<lexer_type> my_lexer; grammar<iterator_type> my_parser(my_lexer); while(true) { std::string input; std::cin >> input; char const* first = input.c_str(); char const* last = &first[input.size()]; bool b = lex::tokenize_and_parse(first, last, my_lexer, my_parser); std::cout << "Parser says: " << b << std::endl; } std::cin.get(); }
-
Dein Problem liegt hier:
Zeus schrieb:
while(true) { std::string input; std::cin >> input; // ... }Es muß so aussehen:
std::string input; std::cin.unsetf(std::ios::skipws); while(std::getline(std::cin, input)) { // ... }Ansonsten spielt Dir der iostream einen Streich und der Lexer/Parser sieht immer nur die Eingabe bis zum nächsten Leerzeichen.
HTH
Regards Hartmut
-
Endlich kann ich Spaß mit Spirit haben :>
Danke ^^