Question

Dans plusieurs questions, j'ai lu des recommandations pour le Cadre de générateur d'analyseur syntaxique Spirit de boost.org , mais dans les commentaires, il y a des murmures en utilisant l'esprit qui ne sont pas heureux. Ces personnes voudront-elles se lever et expliquer au reste d'entre nous quels sont les inconvénients ou les inconvénients de l'utilisation de Spirit?

Était-ce utile?

La solution

C’est une bonne idée, et j’ai aimé; il était particulièrement utile d'apprendre à utiliser les modèles C ++.

Mais leur documentation recommande l'utilisation de spirit pour les analyseurs syntaxiques de taille petite à moyenne. Un analyseur syntaxique pour une langue complète prendrait une éternité à compiler. Je vais énumérer trois raisons.

  • Analyse sans scanner. Bien que ce soit plus simple, quand le retour en arrière est nécessaire, cela peut ralentir l’analyseur. C'est facultatif cependant - un lexer peut être intégré, voir le préprocesseur C construit avec Spirit. Une grammaire de ~ 300 lignes (comprenant les fichiers .h et .cpp) est compilée (non optimisée) en un fichier de 6M avec GCC. Les optimisations en ligne et maximales permettent de réduire ce nombre à environ 1,7 million de dollars.

  • Analyse lente - il n'y a pas de vérification statique de la grammaire, ni d'indication sur la nécessité d'une apparence excessive, ni de vérifier les erreurs élémentaires, telles que l'utilisation de la récursivité gauche (qui conduit à une récursion infinie en descente récursive) analyseurs syntaxiques grammaires LL). La récursivité de gauche n’est pas un bug vraiment difficile à localiser, mais une apparence excessive peut entraîner des temps d’exploration exponentiels.

  • Utilisation intensive de modèles - bien que cela présente certains avantages, cela a un impact sur les temps de compilation et la taille du code. De plus, la définition de la grammaire doit normalement être visible par tous les autres utilisateurs, ce qui a encore plus de temps de compilation. J'ai pu déplacer des grammaires vers des fichiers .cpp en ajoutant des instanciations de modèles explicites avec les bons paramètres, mais ce n'était pas facile.

UPDATE: ma réponse se limite à mon expérience avec Spirit Classic et non de Spirit V2. Je m'attendrais toujours à ce que Spirit soit fortement basé sur des modèles, mais maintenant je devine.

Autres conseils

In boost 1.41, une nouvelle version de Spirit est sur le point de sortir, et elle se démarque des pantalons: classic:

  

Après une longue période en version bêta (plus de 2   années avec Spirit 2.0), Spirit 2.1   sera enfin publié avec le   la prochaine version 1.41 de Boost. Le code   est très stable maintenant et est prêt pour   code de production. Nous travaillons dur   pour terminer la documentation à temps   pour Boost 1.41. Vous pouvez jeter un coup d'œil au   état actuel de la documentation   ici. Actuellement, vous pouvez trouver le code   et documentation dans le Boost SVN   tronc. Si vous avez un nouveau projet   impliquant Esprit, nous recommandons fortement   en commençant par Spirit 2.1 maintenant. Autorise moi   citer le message de OvermindDL du   Liste de diffusion Spirit:

     
    
      

Je peux commencer à ressembler à un bot avec       combien de fois je le dis, mais       Spirit.Classic est ancien, vous devriez       passer à Spirit2.1, il peut faire       tout ce que vous avez fait ci-dessus une excellente affaire       plus facile, beaucoup moins de code, et il       s'exécute plus vite. Par exemple,       Spirit2.1 peut construire votre AST complet       en ligne, pas de dépassement bizarre, pas besoin       pour construire par la suite, etc ...,       le tout comme une étape agréable et rapide. Vous       vraiment besoin de mettre à jour. Voir l'autre       messages de la journée passée pour des liens vers       docs et autres pour Spirit2.1. Esprit2.1       est actuellement dans Boost Trunk, mais       être officiellement publié avec Boost 1.41,       mais est par ailleurs complet.

    
  

Pour moi, le plus gros problème est que les expressions dans Spirit, vues par le compilateur ou le débogueur, sont plutôt longues (j'ai copié ci-dessous une partie d'une expression dans Spirit Classic). Ces expressions me font peur. Lorsque je travaille sur un programme qui utilise Spirit, j'ai peur d'utiliser Valgrind ou d'imprimer backtrace dans gdb.

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<

Voici ce que je n'aime pas à ce sujet:

  • la documentation est limitée. Il existe une grande page Web où & «Tout &»; est expliqué, mais les explications actuelles manquent de détails.

  • mauvaise génération d'AST. Les AST sont mal expliqués et, même après vous être heurté au mur pour comprendre le fonctionnement des modificateurs AST, il est difficile d’obtenir un AST facile à manipuler (c’est-à-dire qui correspond bien au domaine du problème)

  • Cela augmente énormément les temps de compilation, même pour les & "; moyennes &" grammaires de la taille

  • La syntaxe est trop lourde. En réalité, en C / C ++, vous devez dupliquer le code (c’est-à-dire entre déclaration et définition). Cependant, il semble que dans boost :: spirit, lorsque vous déclarez une grammaire & Lt; & Gt ;, vous devez répéter certaines choses 3 fois: D (lorsque vous voulez des AST, ce que je veux: D)

À part cela, je pense qu’ils ont fait un très bon travail avec l’analyseur, étant donné les limites du C ++. Mais je pense qu'ils devraient l'améliorer davantage. La page d'histoire décrit qu'il y avait un & Quot; dynamique & Quot; esprit avant le courant " statique " esprit; Je me demande à quel point la syntaxe était meilleure et plus rapide.

Je dirais que le plus gros problème est l’absence de diagnostic ou autre aide pour les problèmes de grammaire. Si votre grammaire est ambiguë, l’analyseur n’analysera peut-être pas ce à quoi vous vous attendez, et il n’ya aucun moyen efficace de le remarquer.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top