Frage

In einigen Fragen habe ich Empfehlungen gesehen für die Geist Parser-Generator Rahmen von boost.org , aber dann in den Kommentaren murrt es von Menschen mit Geist, die nicht glücklich sind. Werden diese Leute vortreten bitte und an den Rest von uns erklären, was die Nachteile oder Nachteile sind Geist mit?

War es hilfreich?

Lösung

Es ist eine ziemlich coole Idee, und es hat mir gefallen; es war besonders nützlich, um wirklich zu lernen, wie C ++ Vorlagen.

Aber ihre Dokumentation empfiehlt die Verwendung von Geist für kleine bis mittelgroßen Parser. Ein Parser für eine vollständige Sprache würde ewig dauern zu kompilieren. Ich werde drei Gründe aufzulisten.

  • abtastlosen Parsing. Es ist zwar ziemlich einfacher, wenn Rückzieher erforderlich ist, den Parser verlangsamen. Es ist allerdings optional - ein Lexer könnte integriert werden, finden Sie in der C-Präprozessor mit Geist gebaut. Eine Grammatik von ~ 300 Zeilen (einschließlich .h und CPP-Dateien) kompiliert (nicht optimiert) in eine Datei von 6M mit GCC. Inlining und maximal Optimierungen werden, dass bis auf ~ 1,7m.

  • Langsam Parsing - es gibt keine statische Überprüfung der Grammatik, weder über die übermäßige Look-Ahead andeuten erforderlich, noch grundlegende Fehler zu überprüfen, wie zum Beispiel Verwendung von Linksrekursion (die in rekursiven Abstieg zu unendlicher Rekursion führen Parser LL Grammatiken). Linksrekursion ist keine wirklich schwer Fehler aufzuspüren, obwohl, aber übermäßige Look-Ahead könnte exponentiell Parsing Zeiten führen.

  • Schwere Vorlage Nutzung - während diese bestimmte Vorteile hat, diese Auswirkungen Kompilierungszeiten und Codegröße. Darüber hinaus muss die Grammatik Definition normalerweise für alle anderen Benutzer sichtbar sein, noch mehr Kompilierungszeiten auswirkt. Ich habe in der Lage gewesen, Grammatiken, um Dateien .cpp durch explizite Template-Instanziierungen mit den richtigen Parametern angeben, aber es war nicht einfach.

UPDATE: meine Antwort auf meine Erfahrung mit Geist klassischen beschränkt ist, nicht Geist V2. Ich würde immer noch Geist erwarte stark Template-basierte, zu sein, aber jetzt bin ich nur raten.

Andere Tipps

In Boost 1.41 eine neue Version des Geistes freigegeben wird, und es schlägt die Hose des Geistes :: Klassiker:

  

Nach einer langen Zeit in der Beta (mehr als 2   Jahre mit Spirit 2.0), Geist 2.1   wird schließlich mit der freigegeben werden   kommende Boost-1.41-Release. Der Code   jetzt sehr stabil ist und bereit ist, für   produktionscode. Wir arbeiten hart,   auf die Dokumentation in der Zeit Finishing   für Boost-1.41. Sie können an der peek   aktuelle Stand der Dokumentation   Hier. Derzeit können Sie den Code finden   und Dokumentation im Boost-SVN   Kofferraum. Wenn Sie ein neues Projekt   Geist, werten wir empfehlen   mit Geist beginnt jetzt 2.1. Erlaube mir   OvermindDL der Beitrag zu zitieren aus der   Geist-Mailingliste:

     
    
      

Ich mag wie ein Bot zu klingen beginnen mit       wie oft ich sage dies, aber       Spirit.Classic ist alt, sollten Sie       Umschalten auf Spirit2.1, kann es tun       tat alles, was Sie über ein hohes Maß       einfacher, Code viel weniger, und es       schneller ausgeführt. Zum Beispiel,       Spirit2.1 kann Ihren gesamten AST bauen       inline, nicht seltsam überwiegender, keine Notwendigkeit,       danach, etc zu bauen Dinge ...,       alle als eine schöne und schneller Schritt. Sie       wirklich zu aktualisieren. Sehen Sie die andere       Beiträge aus der Vergangenheit Tag für Links zu       docs und solche für Spirit2.1. Spirit2.1       ist derzeit in Boost-Trunk, wird aber       formal mit Boost-1.41 freigegeben werden,       aber ansonsten abgeschlossen.

    
  

Für mich das größte Problem ist, dass Ausdrücke in Geist, wie Compiler oder Debugger gesehen, ziemlich lang ist (I kopiert unter einen Teil von einem Ausdruck in Spirit Classic). Diese Ausdrücke erschrecken mich. Als ich an einem Programm arbeiten, das Geist verwendet, habe ich Angst, valgrind zu verwenden oder Backtrace in gdb zu drucken.

boost::spirit::classic::parser_result<boost::spirit::classic::action<boost::spirit::classic::sequence<boost::spirit::classic::action<boost::spirit::classic::action<optional_suffix_parser<char const*>, boost::spirit::classic::ref_actor<std::vector<std::string, std::allocator<std::string> >, boost::spirit::classic::clear_action> >, boost::spirit::classic::ref_actor<std::vector<int, std::allocator<int> >, boost::spirit::classic::clear_action> >, boost::spirit::classic::sequence<boost::spirit::classic::alternative<boost::spirit::classic::alternative<boost::spirit::classic::action<boost::spirit::classic::contiguous<boost::spirit::classic::sequence<boost::spirit::classic::alternative<boost::spirit::classic::chlit<char>, boost::spirit::classic::chlit<char> >, boost::spirit::classic::positive<boost::spirit::classic::alternative<boost::spirit::classic::alternative<boost::spirit::classic::alnum_parser, boost::spirit::classic::chlit<char> >, boost::spirit::classic::chlit<char> > > > >, boost::spirit::classic::ref_value_actor<std::vector<std::string, std::allocator<std::string> >, boost::spirit::classic::push_back_action> >, boost::spirit::classic::action<boost::spirit::classic::rule<boost::spirit::classic::scanner<char const*, boost::spirit::classic::scanner_policies<boost::spirit::classic::skipper_iteration_policy<boost::spirit::classic::iteration_policy>, boost::spirit::classic::match_policy, boost::spirit::classic::action_policy> >, boost::spirit::classic::nil_t, boost::spirit::classic::nil_t>, boost::spirit::classic::ref_const_ref_actor<std::vector<std::string, std::allocator<std::string> >, std::string, boost::spirit::classic::push_back_action> > >, boost::spirit::classic::contiguous<boost::spirit::classic::sequence<boost::spirit::classic::chlit<char>, boost::spirit::classic::action<boost::spirit::classic::uint_parser<unsigned int, 10, 1u, -1>, boost::spirit::classic::ref_value_actor<std::vector<int, std::allocator<int> >, boost::spirit::classic::push_back_action> > > > >, boost::spirit::classic::kleene_star<boost::spirit::classic::sequence<boost::spirit::classic::chlit<char>, boost::spirit::classic::alternative<boost::spirit::classic::alternative<boost::spirit::classic::action<boost::spirit::classic::contiguous<boost::spirit::classic::sequence<boost::spirit::classic::alternative<boost::spirit::classic::chlit<char>, boost::spirit::classic::chlit<char> >, boost::spirit::classic::positive<boost::spirit::classic::alternative<boost::spirit::classic::alternative<boost::spirit::classic::alnum_parser, boost::spirit::classic::chlit<char> >, boost::spirit::classic::chlit<char> > > > >, boost::spirit::classic::ref_value_actor<std::vector<std::string, std::allocator<std::string> >, boost::spirit::classic::push_back_action> >, boost::spirit::classic::action<boost::spirit::classic::rule<boost::spirit::classic::scanner<char const*, boost::spirit::classic::scanner_policies<boost::spirit::classic::skipper_iteration_policy<boost::spirit::classic::iteration_policy>, boost::spirit::classic::match_policy, boost::spirit::classic::action_policy> >, boost::spirit::classic::nil_t, boost::spirit::classic::nil_t>, boost::spirit::classic::ref_const_ref_actor<std::vector<std::string, std::allocator<std::string> >, std::string, boost::spirit::classic::push_back_action> > >, boost::spirit::classic::contiguous<boost::spirit::classic::sequence<boost::spirit::classic::chlit<char>, boost::spirit::classic::action<boost::spirit::classic::uint_parser<unsigned int, 10, 1u, -1>, boost::spirit::classic::ref_value_actor<std::vector<int, std::allocator<int> >, boost::spirit::classic::push_back_action> > > > > > > > >, void ()(char const, char const*)>, boost::spirit::classic::scanner<char const*, boost::spirit::classic::scanner_policies<boost::spirit::classic::skipper_iteration_policy<boost::spirit::classic::iteration_policy>, boost::spirit::classic::match_policy, boost::spirit::classic::action_policy> > >::type boost::spirit::classic::action<boost::spirit::classic::sequence<boost::spirit::classic::action<boost::spirit::classic::action<

Hier ist das, was Ich mag nicht darüber:

  • Die Dokumentation ist begrenzt. Es gibt eine große Web-Seite, wo „alles“ erklärt, aber die aktuellen Erklärungen fehlen in Details.

  • arme AST Generation. Äste sind schlecht erklärt und auch nach dem Kopf gegen die Wand schlagen, um zu verstehen, wie die AST-Modifikatoren arbeiten, ist es schwierig, ein leicht zu manipulieren AST (das heißt eine, die gut zu dem Problembereich abbildet) zu erhalten

  • Es erhöht die Übersetzungszeiten enorm, auch für "mittel" -groß Grammatiken

  • Syntax ist zu Schwergewicht. Es ist eine Tatsache des Lebens, die in C / C ++ Sie Code (das heißt zwischen Deklaration und Definition) kopieren müssen. Allerdings scheint es, dass in boost :: spirit, wenn Sie eine Grammatik <> deklarieren, müssen Sie einige Dinge, 3-mal wiederholen: D (wenn Sie Äste wollen, das ist es, was ich will: D)

Andere als diese, ich glaube, sie einen ziemlich guten Job mit dem Parser hat, die Grenzen von C ++ gegeben. Aber ich denke, sie sollten es mehr verbessern. Die Geschichte Seite beschreibt, dass es ein „dynamischer“ Geist vor dem aktuellen „statisch“ Geist war; Ich frage mich, wie viel schneller und wie viel besser Syntax hatte.

Ich würde sagen, das größte Problem das Fehlen einer Diagnose oder anderer Hilfe für Grammatik Probleme ist. Wenn Ihre Grammatik mehrdeutig ist, kann der Parser nicht analysieren, was Sie es erwarten, und es gibt keine gute Möglichkeit, dass zu bemerken.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top