Utiliser lex et yacc dans vos programmes C/C++

Posté par  . Modéré par Pascal Terjan.
Étiquettes :
0
26
août
2004
Technologie
On a tous entendu parler un jour ou l'autre de lex et yacc, ne serait-ce que pour compiler certains logiciels ... mais à quoi peut servir cet ensemble d'outils ?

Entre autres, il vous sera très utile si votre programme C/C++ a par exemple recours à un fichier de données structurées et qu'il vous faut le parcourir, en vérifier sa validité, en extraire les données utiles etc... lex et yacc vous permettent de décrire la syntaxe du fichier (les mots clefs structurants) ainsi que sa grammaire (les enchaînements de mots clefs et l'exploitation des données parsées) dans un langage de haut niveau. Une fois ce travail accompli, ces deux outils génèrent une fonction C facilement intégrable dans votre projet C/C++.

Cet article se présente sous forme d'un tutoriel et permet de vite appréhender l'utilisation de lex et yacc par l'exemple. L'article n'aborde donc pas les aspects avancés de ces outils mais sachez qu'ils permettent de faire bien plus que ce qui y est décrit... d'ailleurs une des utilisations avancées les plus communes est la création de compilateurs.
À découvrir !

Aller plus loin

  • # Il faut s'accrocher

    Posté par  (site web personnel) . Évalué à 3.

    C'est clair que c'est vraiment puissant comme outils, mais faut vraiment y passer du temps avant de comprendre quoi que ce soit.

    Mais sinon, c'est vrai que pour faire une calculatrice faisant du calcul formel (simpliste quand même), ya rien de plus simple que ça.

    Créateurs de nouveaux langages (il doit bien rester encore le E++ ou le F++), amusez-vous !

    Forum Software Reviews: Comparez et testez les logiciels de forums Internet!

    • [^] # Re: Il faut s'accrocher

      Posté par  . Évalué à 3.

      c'est vrai que j'avais passer plusieurs nuit en essayant de comprendre puis j'ai laissé tombé par manque de temps. Allez, je m'y remets, de toutes facons, j'ai rien à faire entre 17 et 19 heures , c'est l'occasion d'approfondir mes connaissances.

      Malheureusement, c'est déjà bien complexe, il aurait été plus intéressant de commencer la doc en français.

      Merci pour la news
      • [^] # Re: Il faut s'accrocher

        Posté par  . Évalué à 2.

        A défaut on peut essayer de comprendre le OCamllex et le OCamlYacc... après un peu de théorie sur les grammaires LALR et ptet aussi des travaux pratiques sur une grammaire LL(k) ça devrait passer !
  • # Relativisons

    Posté par  . Évalué à 10.

    Ayant moi-meme ecrit des programmes avec lex et yacc, en particulier pour lire le fichier de conf, ayant moi-meme aussi ecrit un article un jour a ce sujet, voici mon experience...

    Pour une calculatrice, ou tout autre genre de compilateur, utilisez lex et yacc.

    Par contre, pour un fichier de configuration, il n'est pas trop complique de coder quelque chose qui sait lire clef=valeur. C'est plus simple, c'est moins difficile a maintenir, bref, c'est meilleur. Pour un fichier de configuration un peu plus complexe, preferez une syntaxe XML, et lisez la doc de libxml2 (ou expat). C'est bien plus simple a maintenir qu'un parseur en lex+yacc.

    Si vous devez faire quelque chose de simple avec des expressions rationnelles, ne pensez pas que lex ou yacc sont le seul moyen de faire cela en C (ou C++). Utilisez regcomp et regexec. Leur page de manuel est plus difficile a lire que ces outils a utililiser. Une fois la doc digeree, ca se programme bien, au risque meme parfois d'en abuser comme en Perl (a part qu'en Perl, c'est pas de l'abus) !

    Enfin, il est des cas ou lex&yacc sont l'outil adapte. Alors n'hesitez pas, utilisez-les.

    Le bonjour chez vous,
    Yves

    PS:

    regex_t preg;
    regmatch_t pmatch[N];
    char*une_chaine = "une chaine";

    /* compilation de l'expression */
    regcomp(&preg, "regexp (.*)", REG_EXTENDED);

    /* test de l'expression */
    if(!regexec(&preg, une_chaine, N, pmatch, 0)) {
    /* affichage du contenu des parentheses) */
    int i;
    char*tmp = strdup(une_chaine);
    for(i=1; i<=preg.re_nsub; i++) {
    strncpy(tmp, une_chaine+pmatch[i].rm_so,
    pmatch[i].rm_eo - pmatch[i].rm_so);
    printf("%s\n", tmp);
    }
    free(tmp);
    }


    PS2. J'ai pas teste. Si ca se trouve, ca marche pas mon code :)
    • [^] # Re: Relativisons

      Posté par  . Évalué à 2.

      Par contre, pour un fichier de configuration, il n'est pas trop complique de coder quelque chose qui sait lire clef=valeur. C'est plus simple, c'est moins difficile a maintenir, bref, c'est meilleur. Pour un fichier de configuration un peu plus complexe, preferez une syntaxe XML, et lisez la doc de libxml2 (ou expat). C'est bien plus simple a maintenir qu'un parseur en lex+yacc.
      Faut pas non plus généraliser. XML n'est pas la solution universelle idéale pour tous les fichiers de confs. Pour des trucs vraiment complexes et variés, style fichier de conf de MTA (je ne parle pas de sendmail.cf qui est un cas particulier), c'est mieux d'avoir un fichier très lisible, et dans ce cas lex & yacc sont vraiment parfaits pour le parser.
  • # Treecc

    Posté par  . Évalué à 4.

    Sans l'avoir jamais utilisé, il me semble qu'il y a une alternative très intéressante à lex et yacc (ou plutôt flex et bison) qui s'appelle treecc.

    http://www.southern-storm.com.au/treecc.html(...)
    • [^] # Re: Treecc

      Posté par  (site web personnel) . Évalué à 6.

      Moi j'utilise yapps:

      http://theory.stanford.edu/~amitp/Yapps/(...)

      Bon, l'inconveninent, c'est que c'est pour du python. Par contre, c'est vraiment extremement simple a utiliser (moins d'1h pour faire mon premier programme utile avec).

      Sinon, je suis tout a fait de l'avis de Yves plut haut:
      - pour un fichier de config, xxx=yyy suffit largement et se parse avec un e regexp. Plus c'est simple, plus ca marche: KISS

      - pour un exemple un poil plus elabore, mieux vaut plonger directement dans du xml bien que ce soit un peu verbeux plutot que d'ecrire son propre langage.

      J'ajouterai plusieurs choses:
      - pour stocker des fichiers de conf, on trouve un certain nombre de lib disponible de nos jours pour faire ca de facon beaucoup plus robuste que ce qu'on obtient en le faisant juste "comme ca"
      - les fichiers a la .ini sont a mon avis un modele tres simple a utiliser et tres efficace. C'est ce qui est utilise pour stocker tous les parametres de config de KDE.

      Faut voir que ecrire une grammaire reste une operation complexe qui doit etre reservee a des besoins hyper specifiques.
      • [^] # Re: Treecc

        Posté par  (site web personnel) . Évalué à 3.

        En Python tu as beaucoup plus simple pour des fichiers du type "clef = valeur" : tu exécute le fichier comme étant du code Python ! (fonction execfile).
        En plus ça permet d'avoir un langage de haut niveau si quelqu'un veut un fichier de configuration complexe.
        • [^] # Re: Treecc

          Posté par  . Évalué à 0.

          J'imagine que tu n'executes pas ca comme tel, mais que tu mets des protections, des fois que le fichier de conf contienne une coquille qui fasse planter le programme ?

          Meme systeme en Perl, je crois.

          En C avec glib:

          GHashTable *config = g_hash_table_new(g_str_hash, g_str_equal);
          FILE *fd = fopen(...);
          while(!feof(fd)) {
           char tmp[BUFSIZ];
           gchar**s;

           fgets (tmp, BUFSIZ, fd);
           s = g_strsplit_set(tmp,"=", 2);
           g_hash_table_insert(config, s[0], s[1]);
           g_free(s);
          }
          fclose(fd);


          Bah ouaih, un peu plus long, mais plus robuste si on ajoute la verification des erreurs eventuelles de fgets et de g_strplut_set :)

          Le bonjour chez vous,
          Yves

          PS. Code non teste, et en plus, vous voudrez surement virer tout ce qui suit un # en mettant un '\0' a la place indiquee par strchr(tmp, '#'); Et puis peut-etre aussi supprimer les espace avec g_strchug() ?
          • [^] # Re: Treecc

            Posté par  . Évalué à 2.

            tu ferais bien d'apprendre à te servir de fgets et de feof d'abord ... while(!feof()) donne un résultat erroné, feof est une fonction de caractérisation d'erreur, et non de détection. la seule manière de détecter FEOF, c'est de surveiller le retour de fgets qui signale toute erreur. À toi en suite de caractériser cette erreur (EOF, erreur I/O, etc) et de prendre une décision adéquate.
    • [^] # Re: Treecc

      Posté par  . Évalué à 8.

      Ce n'est pas une alternative, mais un programme complémentaire à utiliser conjointement avec yacc/bison pour générer et manipuler facilement les arbres de syntaxe abstraite à partir d'une entrée.

      Pour les alternatives à yacc/bison (LALR(1) + GLR pour bison), j'ai dans mes bookmarks :


      Il y a le sempiternel catalogue de comp.compilers ici : [http://www.idiom.com/free-compilers/(...)].
      • [^] # Re: Treecc

        Posté par  . Évalué à 4.

        Pour les fanatiques du C++ plein de templates de la mort qui tue la vie, il y a aussi Spirit ( http://www.boost.org/libs/spirit/(...) ). Ça permet de directement écrire le lexer/parser (et la construction de l'arbre syntaxique aussi je crois) en C++ (et à la compil, on sent un petit peu les templates ;).
      • [^] # Re: Treecc

        Posté par  . Évalué à 1.

        Y'a aussi l'excellent javacc .

        Les fichiers de grammaire reste très lisibles. Et avec eclipse, y'a la completion automatique grace a un petit plugin.

        https://javacc.dev.java.net(...)

        http://sourceforge.net/projects/eclipse-javacc(...)
        • [^] # Re: Treecc

          Posté par  . Évalué à 2.

          Y'a aussi l'excellent javacc .

          Je confirme. En plus il est très simple à prendre en main. Personellement je n'ai pas envie de mettre les mains dans du C pour traiter du texte à coup de char*. Donc Yacc/Lex c'est simpa mais depuis on a inventé Perl, Python, Java,...

          Dans le genre antlr est pas mal non plus mais le parseur généré a besoin du runtime d'Antlr pour fonctionner. C'est un peu lourd de devoir se trainer un gros .jar pour un tout petit parseur.
      • [^] # Re: Treecc

        Posté par  . Évalué à 1.

        CamlP4 est hors sujet, c'est un pre-processeur pour Caml.

        En Caml les générateurs de lexeurs et parseurs sont OCamlLex et OcamlYacc.

        Ils s'utilisent comme lex et yacc mais du fait de la programmation fonctionnelle ils sont plus intuitifs et ensuite l'utilisation de l'abre de syntaxe abstraite est largement facilitée.
        • [^] # CamlP4

          Posté par  . Évalué à 1.

          CamlP4 est plus qu'un pré-processeur comme celui de C. Il permet d'effectuer une analyse récursive descendante (LL(1))). Voir le tutorial [http://caml.inria.fr/camlp4/tutorial/(...)].

          OCamlYacc est lui un analyseur LALR(1) très conventionnel.
  • # mon avis

    Posté par  (site web personnel) . Évalué à 5.

    Le truc c'est qu'il faut pas mal de notion d'analyse gramamtical, parcque franchement quand yacc va sortir des erreurs shift/reduce, voilà quoi. Même en ayant suivit une formation adéquate, ces outils sont puissant mais très déroutant, et ne s'adresse pas aux amateurs à mon avis.

    Sinon y'a une alternative pour tous ceux qui ont besoin d'un fichier de donnée ou de config, rien ne vaut un document XML dont il existe de nombreux validateur (XML a été conçu aussi pour faciliter tous ces traitements grâce à une syntaxe générique), ou pour les gros fichiers de données un vrai SGBD (SQLite ou plus gros)

    A noter aussi que ces outils ont également été adapté pour être utilisé avec d'autres langage que C et C++, je pense notamment à Java.
    • [^] # Re: mon avis

      Posté par  . Évalué à 2.

      A la place de XML, vous pouvez aussi utiliser YAML, un langage VRAIMENT éditable et utilisable par les êtres humain.

      A ce sujet, XML a pêché dans ses objectifs. Si vous voulez la liste de ses défauts : http://www.concisexml.org/(...)

      De toute façon, inventer un nième langage pour le fichier de configuration (et éventuellement introduire des bugs), ça impose à l'utilisateur une fatigue supplémentaire qu'il n'est pas nécessaire de lui imposer. Si vous aimez XML, alors vive les standards :)

      Chucky
      • [^] # Re: mon avis

        Posté par  . Évalué à 2.

        "De toute façon, inventer un nième langage pour le fichier de configuration (et éventuellement introduire des bugs), ça impose à l'utilisateur une fatigue supplémentaire qu'il n'est pas nécessaire de lui imposer. Si vous aimez XML, alors vive les standards :)"

        Hum je suis pas d'accord. Pour etre grossier XML te dis que ton document aura la forme etc.

        Mais l'utilisateur a toujours a ingurgiter la DTD pour pouvoir l'utiliser. XML n'apporte donc strictement rien a l'utilisateur (hormis un fichier immonde pour les humains) mais au programmeur qui n'a pas a se faire chier et gerer le tout en 100 lignes de libxml2.
        • [^] # Re: mon avis

          Posté par  . Évalué à 1.

          Ton utilisateur pourra par contre avec un bon éditeur de fichier XML et une DTD ou un XS bien écrit.

          Il pourra avoir une completion automatique pour rédiger plus rapidement son fichier de conf.

          Un système validant que son fichier de conf est valide.

          Si ton XS est très bien fait, tu pourras y ajouter des balises a tes elements pour qu'il ait une mini-aide en ligne

          Si tu utilise les types des XS intéligeament, tu peux même envisager que ton utilisateur aura accès à des combobox ou des spinners pour les nombres.

          Deplus, l'interêt des fichiers XML est qu'il impose de structurer l'information sous la forme d'un arbre. Une organisation qui semble facile à assimiler par l'esprit humain et que bcp d'éditeur XML représente sous forme d'arbre allégé.

          Par contre pour offrir des fonctionnalités de scripting dans une application, je pense qu'il est mieux d'envisager d'utiliser des langages de scripts existants genre Perl, Python, Php, JavaScript qui posséde tous des éditeurs propre ou de passer à .Net ;-)

          Enfin, Ant montre que réaliser des scripts en XML est aussi possible.
    • [^] # Re: mon avis

      Posté par  . Évalué à 3.

      Il y a aussi lua ( http://www.lua.org(...) ) qui est pas mal et très léger pour scripter, entre autre, la configuration de son application.

      Il s'interface avec le C et le C++ (des surcouches comme lunar.h ou luabind facilitent pas mal le travail) mais aussi avec java (via luajava) et bien d'autre langage aussi.
      • [^] # Re: mon avis

        Posté par  . Évalué à 1.

        J'ai regardé lua récemment (parce que je cherche un moyen de rajouter des possibilités d'utiliser des scripts dans gnomemeeting), et ça avait effectivement l'air carrément facile à utiliser pour lire des fichiers de conf.

        Snark sur #gnomemeeting
        • [^] # Re: mon avis

          Posté par  (site web personnel) . Évalué à 2.

          Utiliser un langage qui s'execute pour stocker des donnes statiques, c'est tres risque. Tu vas faire tourner l'interpreteur lua juste pour lire ton fichier de conf ? Donc on peut faire un virus lua qu'on glisse dans ton fichier de conf !
          • [^] # Re: mon avis

            Posté par  . Évalué à 1.

            Je ne vois pas la faille de sécurité: l'exécutable tourne sous l'identité de l'utilisateur qui l'a lancé, et c'est aussi cet utilisateur qui a les droits sur le répertoire où se situe le fichier de conf... donc le trou est aussi gros que si on demande à l'utilisateur de sauver un script dans son $HOME et de l'exécuter!

            Gnomemeeting utilise gconf pour sa configuration ; je ne cherchais pas à modifier ça. Je me demandais (et je me demande toujours) quel langage utiliser pour dans gnomemeeting et pour faire quoi. Bref, que du prospectif. Pour l'instant, je suis occupé à faire un composant DBUS: ça on sait déjà à quoi ça peut servir :-)

            Snark sur #gnomemeeting
            • [^] # Re: mon avis

              Posté par  (site web personnel) . Évalué à 2.

              Pour ma part j'aime beaucoup le python pour e genre de chose...J'ai jamais essayer d'en "embarquer" dans une aplication, mais je ne tarderais sans doute pas à le faire...

              Et je peux vous dire que dans gimp, entre un python-fu et un script-fu, pour un débutant en scheme et en python, ben on a très très vite fait le choix!!!!

              PS: faites des plugins pour gimp, c'est facile et ça rend tellement service... ;)
    • [^] # Re: mon avis

      Posté par  (site web personnel) . Évalué à 1.

      Pour les fichiers de configs, je trouve qu'il y a rien de mieux que les ficheirs properties...

      Sinon, réaliser des traitements XML, je trouve ça super chiant donc pour ceux qui font du Java, vous avez xmlbeans qui transforme un fichier xsd en classe java.. vous manipulez ensuite les objets java crées et xmlbeans se charge de traduire en Xml :) c beau non ?

      http://about.me/straumat

      • [^] # Re: mon avis

        Posté par  (site web personnel) . Évalué à 1.

        Sauf que c'est beaucoup + chi*** d'écrire le fichier xsd que d'y aller direct avec sax comme un gros.
        • [^] # Re: mon avis

          Posté par  . Évalué à 1.

          C'est vrai que c'est chiant, mais dans un projet sérieu, les xsd sont écrits pendant l'étape de conception dont ils découlent naturelement.

          Les codeurs disposent alors des xsd, ce qui simplifie nettement leur tâche.
      • [^] # Re: mon avis

        Posté par  . Évalué à 1.

        Castor aussi c'est pas mal:
        http://www.castor.org/(...)
  • # en CAML light

    Posté par  (site web personnel) . Évalué à 2.

    Pour ceux qui ne comprennent pas les méandres de lexx et yacc, utilisez sont implementation en CAML light (dispo sur le site de l´INRIA) ou autre (sais pas). Elle est vraiment bien integree et tres agréable.
    • [^] # Re: en CAML light

      Posté par  (Mastodon) . Évalué à 4.

      Hmm question con: pourquoi ? C'est plus simple ? Parce que ce qui me semble complexe dans Yacc, ce n'est pas l'implémentation mais plutôt la théorie qui est derrière... et qui est donc logiquement la même que celle derrière le "Yacc" de Ocaml.
      • [^] # Re: en CAML light

        Posté par  (site web personnel) . Évalué à 1.

        disons que le fonctionnement de tokens et d'arbre syntaxique s'adapte a merveille avec CAML, un vrai plaisir. Autant j'avais eu du mal a capter Lexx et Yacc en C qu'en CAML c'était presque naturel.
  • # Lex et unicode

    Posté par  . Évalué à 2.

    Il y a qq années, je m'étais penché sur l'implémentation d'un parseur XML basé sur flex (juste pour m'amuser).

    J'avais tout de suite laissé tombé parce que selon la norme XML, le fichier peut être encodé en ASCII (ou tout jeu de caractères sur 8 bits -- Latin1, etc.), en UCS16, en UCS32 ou en UTF8. Et pour gérer UCS16 ou UCS32 il faut pouvoir gérer des wchar.

    Il me semble que flex supporte les char et les wchar, mais le choix devait être fait à la compilation, alors que pour parser un fichier XML, il faut déterminer l'encodage à la lecture, entre autres en se basant sur le fait que le fichier commence par <?, selon les recommendations du W3C.
    Intégrer la variabilité de l'encodage dans les expressions régulières était ingérable!

    Morale: lex et yacc font déjà beaucoup, mais ils ne peuvent pas tout faire.

    Rq: Tout ça date un peu, donc excusez les erreurs ou imprécisions.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.