IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

[C#] Parser code source C avec regex


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert
    Avatar de Aspic
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    3 905
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2005
    Messages : 3 905
    Par défaut [C#] Parser code source C avec regex
    Bonjour à tous,

    Je souhaiterais parser un code source C classique afin de récupérer les fonctions et le mettre dans un tableau :
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     
    // Exemple de code source à parser
    void 
    a(int p1, float p2)
    {
     
    }
     
    void b()
    {
        int p1=5;
        float p2 = 10.0;
        a(p1,p2);
    }
     
    int main()
    {
        int p1=5;
        float p2 = 10.0;
        a(p1,p2);
        b();
    }
    Je voudrais isoler chaque bloc de fonction et le mettre en mémoire :
    tab[0] = "void
    a(int p1, float p2)
    {

    }"

    tab[1] = "void b()
    {
    int p1=5;
    float p2 = 10.0;
    a(p1,p2);
    }"

    tab[2] = "int main()
    {
    int p1=5;
    float p2 = 10.0;
    a(p1,p2);
    b();
    }"
    Je ne suis pas du tout doué avec les regex, je sais utiliser la classe Regex en C# mais pour trouver l'expression régulière c'est autre chose

    Je pense qu'il faut définir un pattern du genre :
    (type_retour|void) (espaces|tabulations|saut ligne) nom_fonction (espaces|tabulations|saut ligne) (paramètres) (espaces|tabulations|saut ligne)
    {
    DU TEXTE
    }


    Enfin, je ne suis même pas sur. Pouvez vous m'aider ?

    Merci d'avance
    Qui ne tente rien n'a rien !
    Ce qui ne nous tue pas nous rends plus fort !!
    Mon projet ZELDA en C++/Allegro
    http://www.tutoworld.com - Le Forum -
    Mes ressources Dotnet (cours, sources, tutos)
    --------------------------------------------
    + + =

    Ne pas oublier le Tag !

  2. #2
    Membre confirmé

    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Juillet 2009
    Messages
    62
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur intégration

    Informations forums :
    Inscription : Juillet 2009
    Messages : 62
    Par défaut
    Je pense que l'approche via les les expressions régulières ne soit pas la plus adaptée pour ce type de problématique.

    Il faut plutôt voir du coté des parsers/analyseurs de textes tel que ANTLR

    A voir Tutoriel sur la mise en place d'une grammaire avec ANTLR

  3. #3
    Membre Expert Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Par défaut
    Pour la regex on peut tenter mais ça ne fonctionnera pas forcément. Le problème est que sans information de contexte on peut seulement chercher les formes "identifiant + identifiant + parenthèse gauche". Or même s'il ne m'en vient pas à l'esprit il y a peut-être des ambiguïtés, notamment du côté du préprocesseur (et comment gérer ce dernier d'ailleurs ?). Et si des infos de contexte sont nécessaires alors la regex ne peut pas gérer ça et il faut un parser "à pile" (pense au parsing d'expressions mises entre parenthèses).

    Autres contraintes: quid du code malformé et des caractères exotiques? Je doute que le C suive les catégories d'unicode, qui ne devait même pas exister à l'époque. Donc les catégories regex pourraient ne pas coller.

    Tout dépend donc des sources à parser et de ce qu'on veut exactement mais la regex peut se révéler insuffisante. Dans ce cas on peut tenter d'écrire un parsing manuel incluant un comptage de parenthèses (ce qui peut-être simple si on ne veut parser qu'une petite partie). Ou bien avoir recours à un parser generator comme suggéré par le moussel. Mais outre que cela ajoute une dépendance au projet, leur utilisation est malheureusement souvent fastidieuse et t'imposera d'apprendre le fonctionnement d'un générateur de parser. Un comble ! Cela dit c'est une compétence utile.


    Si au vu des contraintes que j'ai énumérées la regex peut fonctionner alors il suffit de concaténer comme suit :
    Identifiant: \w[\w\d]*
    Espaces, tab et sauts de ligne: ([\s\n]|(\r\n))*
    Pour le début: (\w[\w\d]*|void)

  4. #4
    Membre Expert
    Avatar de Aspic
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    3 905
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2005
    Messages : 3 905
    Par défaut
    Bonsoir,

    Effectivement il semble que l'approche regex ne soit pas la bonne.
    Alors j'avais déjà vu du côté de ANTLR mais il faudrait des semaines pour comprendre comment ca marche et cela rajoute une dépendance au projet.

    Au final même si le style de code à parser reste simple (on part du principe que le code est correct syntaxiquement et avec une imbrication { et } parfaite), je ne vois pas comment régler le problème des accolades à l'intérieur d'une fonction.

    Exemple :
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    void b()
    {
        int p1=5;
        float p2 = 10.0;
        a(p1,p2);
        if ( blabla) {
    
        }
        else {
            while (blabla)
            {
    
            }
        }
    } // <--- il faudrait s'arrêter à cette accolade dès qu'on a matché le prototype de la fonction...
    
    float autre_fonction() {}
    Impossible de dire avec une regex, je dois m'arrête à la "bonne" accolade (celle qui ferme la fonction)

    Ou alors j'ai loupé quelque chose...

    Merci à vous
    Qui ne tente rien n'a rien !
    Ce qui ne nous tue pas nous rends plus fort !!
    Mon projet ZELDA en C++/Allegro
    http://www.tutoworld.com - Le Forum -
    Mes ressources Dotnet (cours, sources, tutos)
    --------------------------------------------
    + + =

    Ne pas oublier le Tag !

  5. #5
    Membre Expert Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Par défaut
    Effectivement une regex ne peut traiter des structures récursives (tu peux bidouiller si la profondeur max de la récursion est connue et faible). J'avais zappé le fait que tu voulais également capturer le corps. Tu pourrais toujours bidouiller en utilisant la regex pour capturer l'en-tête puis utiliser une procédure manuelle pour trouver l'accolade de fin. Resteraient quand même le problème du préprocesseur et celui des chaînes de caractères qui pourraient contenir des accolades ou des motifs équivalents à des en-têtes de fonction.

    Bref, la regex est limitée mais avec un peu de bricolage et des sources simples ça peut marcher. Une solution manuelle sera un peu plus puissante mais à nouveau elle échouera face à certains cas particuliers, sauf à y passer beaucoup de temps pour créer un parser complet. Quant à antlr ça ne prend pas des semaines et ça reste la façon la plus rapide d'avoir un parser 100% compatible.

    Tout dépend des sources. Si tu peux bricoler, bricole.

  6. #6
    Membre Expert
    Avatar de Aspic
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    3 905
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2005
    Messages : 3 905
    Par défaut
    Citation Envoyé par DonQuiche Voir le message
    Resteraient quand même le problème du préprocesseur et celui des chaînes de caractères qui pourraient contenir des accolades ou des motifs équivalents à des en-têtes de fonction.
    Pour le préprocesseur, à tout hasard ca ne serait pas possible de récupérer un code intermédiaire où les #define sont remplacés juste avant la compilation ? (je pense à une option de gcc qui permettrait de sortir un fichier en code C mais avec une passe du préprocesseur ?)

    Pour les accolades dans une chaine de caractères, j'ai avait pensé on ne peut pas les virer avec une regex ? Voire même virer tout le texte dans les guillemets ? Exemple : printf("je fais foirer le parser { ahahahah"); devient printf(""); ou alors printf();
    Citation Envoyé par DonQuiche Voir le message
    Quant à antlr ça ne prend pas des semaines et ça reste la façon la plus rapide d'avoir un parser 100% compatible.
    Un jour, j'apprendrais ce nouvel outil, ca à vraiment l'air pas mal mais au premier abord (en regardant le tuto sur DVP), cela avait l'air compliqué...
    Pour l'instant étant donné que les sources sont simples, je continue en mode bricolage même si c'est pas bien à termes j'en suis conscient

    Citation Envoyé par Mat.M
    Ensuite là où je me suis arraché les cheveux de la tête c'est pour délimiter les blocs avec les accolades.
    Tu m'étonnes, je suis entrain de péter un câble dessus actuellement
    C'est clair que du VB.net aurait été plus simple
    Citation Envoyé par Mat.M
    Maintenant si on souhaite délimiter les blocs il faut empiler les blocs à l'aide d'une pile ; les blocs de fonctions et d'expressions délimités par des accolades doivent être symmétriques évidemment.
    Une pile permet de restituer le dernier élément empilé.
    Alors une pile, j'avais eu l'idée mais je n'ai pas trouvé comment faire au final. Dès que je trouve une accolade ouvrante, j'empile le code lu précédemment (de la précédente accolade ouvrante jusqu'à celle que je viens de trouver) et que je trouve une accolade fermante, je dépile le dernier élément mais au final comment reconstituer les blocs ?
    Avec un arbre binaire, je ne vois simplement pas comment on pourrait faire.
    Citation Envoyé par Mat.M
    ce que j'ai fait dans mon projet d'interpréteur c'est que le code source initialement en Javascript ( syntaxe proche du C donc ) est compilé dans un pseudo-code ( un peu comme l'Intermediate Language de .NET) et comme ça il est interprété linéairement par le module d'exécution.
    C'est toi qui a créé le pseudo-code ? Si oui, comment as tu fait ? Et je suppose que parser le pseudo-code était plus facile que le code source d'origine ?

    PS : Au final, ton projet a été terminé à 100% ?

    Merci beaucoup.
    Qui ne tente rien n'a rien !
    Ce qui ne nous tue pas nous rends plus fort !!
    Mon projet ZELDA en C++/Allegro
    http://www.tutoworld.com - Le Forum -
    Mes ressources Dotnet (cours, sources, tutos)
    --------------------------------------------
    + + =

    Ne pas oublier le Tag !

  7. #7
    Expert confirmé
    Avatar de Mat.M
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    8 532
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2006
    Messages : 8 532
    Par défaut
    Citation Envoyé par Aspic Voir le message
    Je souhaiterais parser un code source C classique afin de récupérer les fonctions et le mettre dans un tableau :
    je te souhaite un bon courage c'est assez ardu à faire...
    j'avais commencé à faire un interpréteur de langage genre Javascript,langage C pour mon projet ( que je souhaite commercialiser..) mais un jour j'ai vite changé pour faire un interpréteur BASIC.

    Ceci dit si je peux essayer de donner des tuyaux je peux
    Je n'utilise pas du tout les expressions régulières.
    J'analyse caractère par caractère pour voir si c'est un espace, un chiffre...
    Ensuite là où je me suis arraché les cheveux de la tête c'est pour délimiter les blocs avec les accolades.
    En Basic c'est plus facile étant donné que ça finit avec End Sub ou End Function
    Maintenant si on souhaite délimiter les blocs il faut empiler les blocs à l'aide d'une pile ; les blocs de fonctions et d'expressions délimités par des accolades doivent être symmétriques évidemment.
    Une pile permet de restituer le dernier élément empilé.


    Citation Envoyé par Aspic Voir le message
    Au final même si le style de code à parser reste simple (on part du principe que le code est correct syntaxiquement et avec une imbrication { et } parfaite), je ne vois pas comment régler le problème des accolades à l'intérieur d'une fonction.

    s
    pour analyser et délimiter les blocs on peut aussi éventuellement utiliser un arbre binaire; chaque noeud de l'arbre est en fait un bloc du source : par exemple pour une condition if , pour une boucle etc...

    ce que j'ai fait dans mon projet d'interpréteur c'est que le code source initialement en Javascript ( syntaxe proche du C donc ) est compilé dans un pseudo-code ( un peu comme l'Intermediate Language de .NET) et comme ça il est interprété linéairement par le module d'exécution.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Code source projet avec CORBA
    Par mourad1987 dans le forum CORBA
    Réponses: 1
    Dernier message: 30/04/2012, 13h13
  2. Réponses: 0
    Dernier message: 07/10/2011, 14h17
  3. parser code source jave pour obtenir un AST
    Par cdm1024 dans le forum Général Java
    Réponses: 1
    Dernier message: 10/08/2009, 09h19
  4. Réponses: 6
    Dernier message: 19/07/2007, 12h30

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo