Boost.Spirit Parser crasht mit Segfault -
-
Hiho!
Ich versuche aus Spaß einen Parser mit Boost.Spirit.Qi für die verlinkte EBNF zu erstellen.
Ich bin gerade bei Aussage angekommen.Das Problem sind wohl entweder die zyklischen Abhängigkeiten oder einfach ein Fehler in Boost.Any, denn bei bestimmten Ausdrücken crasht das Programm mit einem Segfault (unten aufgelistet).
Mein Code bisher:
#define BOOST_LCAST_NO_WCHAR_ #include <boost/spirit/home/qi.hpp> #include <boost/spirit/include/qi_char_class.hpp> #include <string> inline void ensureUpperCase(std::string& str) { for(auto iter = str.begin();iter != str.end();++iter) *iter = std::toupper(*iter); } template <typename Iterator> struct Programm : boost::spirit::qi::grammar<Iterator, std::string()> { Programm() : Programm::base_type(expression) { using boost::spirit::ascii::char_; //////////////! ACHTUNG, HIER FÄNGT DAS WESENTLICHE AN! logic_or = "OR"; logic_and = "AND"; logic_not = "NOT"; binary_logic = logic_and | logic_or; unary_logic = logic_not; binary_logic_expr = expression >> binary_logic >> expression; unary_logic_expr = unary_logic >> expression; boolean = char_('T') | 'F'; character = boost::spirit::ascii::upper; index = char_('0') | '1' | '2' | '3' | '4' | '5' | '6' | '7'; variable = +character; expression = boolean | binary_logic_expr | unary_logic_expr | braced_expr | variable >> !index; braced_expr = '(' >> expression >> ')'; } typedef boost::spirit::qi::rule<Iterator, std::string()> str_rule; typedef boost::spirit::qi::rule<Iterator, char()> ch_rule; str_rule logic_or, logic_and, logic_not, binary_logic, unary_logic, binary_logic_expr, unary_logic_expr; ch_rule boolean, character, index; str_rule variable; str_rule expression, braced_expr; }; #include <iostream> int main() { for(Programm<std::string::const_iterator> parser;;) { std::string str; std::getline(std::cin, str); ensureUpperCase(str); std::string result; std::string::const_iterator iter = str.begin(), end = str.end(); bool res = boost::spirit::qi::parse(iter, end, parser, result); if(res && iter == end) std::cout << "Valid!"; else std::cout << "Invalid! Stopped at " << std::string(iter, end) << '\n';; std::cout << '\n'; } }Kompiliert sauber.
expressionist äquivalent zum im EBNF definierten Aussage.Folgende Ausdrücke bringen den Segfault (die sind eig. richtig):
- nott
- (t)
- var4
Der Segfault tritt in einer Boost.Any Funktion auf, die Templates sind da stark verschachtelt (unter anderem mit Boost.Fusion und
qi::rule).Folgende Ausdrücke bringen zwar nicht das Programm zum crashen, sind jedoch komischerweise als Falsch bewertet:
- tandt
Ich hoffe, jemand kann mir weiterhelfen (da ich keinen Plan mehr hab was ich noch machen soll), bestimmt mache ich einen einfachen Fehler...
MfG
-
Nur eine superdünne Vermutung, aber sind Code Generation von Boost.Spirit und Deiner Software sowie Calling Conventions gleich? Und ist auch die Debug- und nicht Release-LIB inkludiert? Solchartige Fehler hatte ich wegen solchen Geschichten vor kurzem en masse.
-
Danke schonmal, jedoch gibt es AFAIR überhaupt keine LIB für Spirit, oder?
-
Du erzeugst einen Stackoverflow, wenn expression boolean nicht matchen kann, dann binary_logic_expr zu matchen versucht und gleich wieder in den expression-Parser geht. So, wie deine Grammatik da steht, ist es keine LL-Grammatik, und du wirst sie umformulieren müssen, um sie mit Spirit zu parsen.
-
seldon schrieb:
Du erzeugst einen Stackoverflow, wenn expression boolean nicht matchen kann, dann binary_logic_expr zu matchen versucht und gleich wieder in den expression-Parser geht. So, wie deine Grammatik da steht, ist es keine LL-Grammatik, und du wirst sie umformulieren müssen, um sie mit Spirit zu parsen.
Wahnsinn! Hast Recht. Also lag es an der Rekursion. Was würd' ich bloß ohne Seldon machen...

Soll ich vielleicht einfach Boost.Regex nehmen?
-
Seldon, wie würdest du es denn machen? Also die ursprüngliche EBNF kann man mit Spirit nicht parsen?
-
Die Sprache, die du zu parsen versuchst, ist nicht regulär, also wird boost.regex dich nicht groß weiterbringen. Die ursprüngliche EBNF wird man wohl mit einem LR-Parsergenerator verarbeitet kriegen (wie bison oder yacc), aber Spirit baut ja im Grunde nichts anderes als einen Recdesc-Parser, also LL, und dort kann man halt keine linksrekursiven Regeln haben.
Das hier könnte dir bei der Umstellung helfen, wie wahrscheinlich auch ein Blick in dein Vorlesungsskript. Du erwartest aber hoffentlich nicht, dass ich dir deine Hausaufgaben abnehme.
-
seldon schrieb:
Du erwartest aber hoffentlich nicht, dass ich dir deine Hausaufgaben abnehme.
Niemals, das wäre nicht nur eine peinliche Schande, sondern außerdem ist das keine Hausaufgabe.
Danke für den Link!
-
Gut, was ich herausgefunden habe, ist dass die meisten LR-Parsergeneratoren Grammar-Files nutzen. Die sind komplex strukturiert; basil sieht gut aus. Sehe ich mir mal an.
-
@seldon: Du kennst nicht zufaellig eine Einfuehrung in Grammatiken und deren Grundbegriffe?

-
UltraGram ist klasse, und perfekt für meine Zwecke geeignet.

-
IIIIEEEEHH!!
UltraGrams Codegenerator produziert Code mit malloc/realloc/free!

Ich werde erstmal ein Viertelstündchen heulen. Darf sowas nicht jeden Tag machen.
-
Und was ist das bitte für ein OOP-Modell, in dem Klassen nicht mal ihre eigenen Abhängigkeiten bereitstellen? Jetzt muss ich einen Haufen Header einbinden -.-

-
Ich habe heute eine sehr wichtige Lektion gelernt. Acuh wenn Ultragram einen schönen Editor hatte, usw.
War Whalecalf doch so geil und hatte richtiges C++ auf Lager (inkl. Templates, C++-Streams, schön generisch alles, usw.).
-
Und wieder Blödsinn.
Da wirdstdund ein anderer Namespace mitten im Header geöffnet...
-
wie wärs einfach, wenn du die Grammatik umformulierst, sodass sie LL ist? das ist nicht so schwer.
-
otze schrieb:
wie wärs einfach, wenn du die Grammatik umformulierst, sodass sie LL ist? das ist nicht so schwer.
Na ich weiß nicht, ich will lieber noch einige Dutzend Stunden mit WhaleCalf verbringen

Ich versuch mich mal mit Umformulierung. Mal sehen, was bei rauskommt.
-
Der Trick ist, dass du das so mformulieren kannst, dass du erst etwas liest, was keine Aussage ist und erst dann ein "and" oder "or" optional folgt.
-
Sone schrieb:
[...] ich will lieber noch einige Dutzend Stunden mit WhaleCalf verbringen

... dann hast wenigstens keine Zeit im Forum zu nerven 
-
otze schrieb:
Der Trick ist, dass du das so mformulieren kannst, dass du erst etwas liest, was keine Aussage ist und erst dann ein "and" oder "or" optional folgt.
Und die Klammern und NOT. Also praktisch ein Baum:
NOT (T AND F)Wird zu
NOT //UND SCHLIEßLICH DAS / BRACED_EXPR //DANN DAS / AND // DANN DAS / \ T F //ZUERST LESEN (Oder Variable >> !Index)Oder geh ich wieder in die falsche Richtung?