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

Mon programme Discussion :

[OpenSource][C++]Générateur de code C++


Sujet :

Mon programme

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre chevronné

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Par défaut [OpenSource][C++]Générateur de code C++
    Bonjour à vous,

    J'aimerais présenter un petit projet que j'ai en tête depuis quelques temps.

    Comme vous le savez sûrement si vous programmez en C++, il est parfois pénible de gérer à la fois les fichiers d'entête .h/.hpp et les fichiers d'implémentation .cpp.

    Par exemple, on doit (pour chaque classe si l'on est rigoureux) créer un couple .cpp/.h, alors que ces deux fichiers représentent une seule et même entité : la classe en question.
    Grâce à certains IDE comme Code::Blocks, on peut créer les deux à la fois et y placer un squelette de classe en quelques clicks, mais il reste toujours le besoin de les maintenir séparément : changer le .h revient souvent à changer le .cpp (et réciproquement, mais c'est plus rare).

    Du point de vue du langage, cette distinction entête/implémentation est absolument nécessaire, je ne le contredis pas.

    Mais n'est-il pas possible de générer ces deux fichiers à partir d'un seul ?
    On pourrait de fait réduire significativement le volume de code à maintenir, et simplifier les opérations de maintenance.

    J'ai donc programmé rapidement un "compilateur" capable de transformer un fichier ".mpp" ("m" pour "module") en deux fichiers .cpp et .hpp, directement compilables via gcc ou autre.

    Exemple (test.mpp) :
    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
    module class Test; // Nom de la classe à créer
     
    // Les dépendances de cette classe
    using std::string;
    using std::iostream;
     
    // Les variables membres sont listées directement
    string sMember;
     
    // ... tout comme les fonctions membres
    void MemberFunction(string s, float b)
    {
        cout << "MemberFunctionSet : " << s << endl;
        sMember = s;
    }
    ... produit le fichier d'entête (test.hpp) :
    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
    #ifndef TEST_INCLUDED
    #define TEST_INCLUDED
     
    #include <string>
     
    class Test
    {
    public :
     
        std::string sMember;
     
        void MemberFunction(std::string s, float b);
    };
     
    #endif
    ... et le fichier source (test.cpp) :
    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
    #include "Test.hpp"
     
    #include <iostream>
     
    using std::string;
    using std::cout;
    using std::cin;
    using std::cerr;
    using std::endl;
     
    void Test::MemberFunction(string s, float b)
    {
        cout << "MemberFunctionSet : " << s << endl;
        sMember = s;
    }

    Le code (cross-platform, pas de licence) est disponible à cette adresse :

    Les dépendances (bibliothèque utilitaire sous licence GNU, compiler les targets Win32 ou Linux) :

    L'exécutable (pour Windows XP) :


    Les fichiers projets sont seulement disponibles pour Code::Blocks. J'imagine qu'il doit exister un convertisseur pour les importer dans Visual et consorts.

    Le "pseudo-langage" utilisé dans les fichiers .mpp n'est pas encore totalement bien défini, il manque encore :
    • le support des classes et structures templates (pour les types, c'est bon)
    • le support de la bibliothèque standard
    • le support de la compilation conditionnelle (#ifdef ...)
    • un moyen simple d'interfacer des bibliothèques existantes sans avoir à les ré-écrire au format .mpp ? (mais pas sûr que ça vienne un jour)


    J'ai déjà intégré les features suivantes :
    • création d'une (ou plusieurs) classes et du couple .cpp/.hpp à partir d'un fichier .mpp
    • variable membres (tous types imaginables)
    • variables globales (définies à l'aide du mot clé "global")
    • initialisation des variables globales et statiques dans le .cpp
    • fonctions membres (statiques, virtuelles, purement virtuelles)
    • fonctions libres (définies à l'aide du mot clé "free")
    • constructeurs et destructeurs (mots clés "new" et "delete")
    • mot clé "using { ... }" pour rajouter manuellement du code au .cpp
    • mot clé "export { ... }" pour rajouter manuellement du code au .hpp
    • support des portées : private, public, protected
    • support de l'héritage (multiple, privé, public, etc)
    • support des namespaces (un seul par fichier .mpp)
    • support des dépendances ("using SomeModule;")
    • support des commentaires (non reportés dans les fichiers C++, sauf si contenus dans le corps d'une fonction)
    • support des commentaires de documentation (/// et /** */), reportés dans le fichier .hpp
    • analyse des types utilisés pour gérer proprement les dépendances (traduire : que doit-on mettre dans le .hpp ? un #include "..." ? une déclaration anticipée ? rien du tout ?)
    • support d'un fichier .mproj contenant les infos de compilation d'un ensemble de modules (la compilation d'un fichier .mpp seul est toujours possible)
    • utilisation de gcc en interne pour compiler et linker les fichiers .cpp issus d'un fichier .mproj (le code peut être facilement adapté pour n'importe quel autre compilateur)


    Comme vous pouvez le voir, ce "langage" se veut un poil moins généraliste que le C++ : il est plutôt orienté programmation avec classes et s'éloigne du C (pas ou peu de macros).
    Le but n'étant pas de faire un (C++)++, ce qui est complètement en dehors de mes compétences, mais juste de développer un outil intermédiaire pour faciliter l'écriture et la maintenance du code pour un style de programmation particulier.

    Ce qui est bon, c'est qu'on n'est pas dépendant du format ".mpp" : on peut toujours choisir de reprendre/distribuer le code C++ généré.

    Si vous avez des commentaires, n'hésitez pas
    Le code n'est probablement pas organisé au mieux, mais ça tourne pour le moment.

    Pour ceux que le détails techniques intéressent, la "compilation" se fait de la manière suivante :
    • création du module à compiler, avec son nom est ses namespaces
    • lectures des dépendances ("using UnModule;") :
      • recherche d'un fichier correspondant au module utilisé (Foo::Module -> foo_module.mpp)
      • parsing du fichier sans vérification des types qui apparaissent, ajout des nouveaux types et variables dans la base de donnée de ce module
    • parsing du fichier :
      • chaque type qui apparait est confronté avec la base de donnée des modules utilisés (plus les types de base), erreur si aucun ou plus de un résultat, sinon le type est "décoré" par tout ce qui est nécessaire : namespaces, classes parent, ..., et ajoute éventuellement une dépendance plus ou moins forte envers d'autre modules (déclaration anticipée si pointeur, inclusion du header si type "nu" ou template)
      • chaque type créé vient s'ajouter à la base de donnée des types du module
    • sérialization du module en code C++


    Pour "compiler" plus d'un fichier .mpp à la fois, il est probablement plus efficace de passer par un fichier projet .mproj.
    En effet, tout se passera dans une seule même unité de compilation : il n'y aura donc besoin de lire chaque module qu'une seule fois, peu importe combien de fois celui-ci est utilisé par les autres modules.

  2. #2
    Membre expérimenté
    Avatar de Chatanga
    Profil pro
    Inscrit en
    Décembre 2005
    Messages
    211
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2005
    Messages : 211
    Par défaut
    C'est ce genre de lourdeurs et limitations qui me fait préférer les langages modernes "orientés imports binaires" (Java, C#, Haskell, etc.) aux vieux langages "orientés includes sources" (C, C++, Objective C, etc.).

    Quoiqu'il en soit, j'aurais procédé différement pour automatiser la production de fichiers d'entêtes. Je me serais contenté de définir des macros vides nommées PUBLIC, PROTECTED et PRIVATE afin d'annoter mes fichiers "cpp", sans introduire un nouveau format "mpp" (ce qui ressemble beaucoup à un nouveau langage qui marcherait dans les pas du D). Par exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    PRIVATE string Test::sMember;
     
    PUBLIC void Test::MemberFunction(string s, float b)
    {
        cout << "MemberFunctionSet : " << s << endl;
        sMember = s;
    }
    Ca reste du code C++ valide et le pré-préprocesseur a les informations qui lui manque pour produire automatiquement les fichiers d'entêtes. En terme de parsing c'est relativement simple puisqu'on ignore les blocs d'implémentation. J'avais d'ailleurs fait un truc similaire en Ruby pour produire des Stubs / Skeletons à partir d'interfaces C++.

    Note : nested -> imbriqué.

  3. #3
    Membre chevronné

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Par défaut
    Je ne sais pas si ton exemple est réellement possible à parser.

    Un exemple simple (et c'est ce pour quoi j'ai utilisé les std::string dans mon bout de code) c'est la gestion des namespaces.
    Il est hors de question de coller un "using namespace std;" dans le fichier header, donc tous les types standards devraient être préfixés par "std::".
    Ca rajoute une lourdeur qui rendrait probablement le tout pas très intéressant comparé au C++ seul.

    C'est ce genre de lourdeurs et limitations qui me fait préférer les langages modernes "orientés imports binaires" (Java, C#, Haskell, etc.) aux vieux langages "orientés includes sources" (C, C++, Objective C, etc.).
    Je ne pense pas que ça soit une limitation, au contraire je dirais que c'est presque trop permissif C'est d'ailleurs une des forces du C et du C++. Mais une lourdeur oui, clairement.
    Il faudra que je jette un œil au Haskell un de ces jours, j'en entend beaucoup parler et souvent en bien.

  4. #4
    Membre expérimenté
    Avatar de Chatanga
    Profil pro
    Inscrit en
    Décembre 2005
    Messages
    211
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2005
    Messages : 211
    Par défaut
    Citation Envoyé par Kalith Voir le message
    Je ne sais pas si ton exemple est réellement possible à parser.

    Un exemple simple (et c'est ce pour quoi j'ai utilisé les std::string dans mon bout de code) c'est la gestion des namespaces.
    Il est hors de question de coller un "using namespace std;" dans le fichier header, donc tous les types standards devraient être préfixés par "std::".
    Ca rajoute une lourdeur qui rendrait probablement le tout pas très intéressant comparé au C++ seul.
    Les using n'ont effectivement rien à faire dans les ".h". Dans ma solution, il suffirait toutefois de les préciser dans les seuls prototypes, même si ça reste un peu lourd. La solution pour s'en débarasser serait cependant la même que dans ton approche où tu proposes de gérer "en dur" ce genre de cas (p. ex string => std::string). Solution qui pourrait tout aussi bien s'appliquer à mon approche.

    Citation Envoyé par Kalith Voir le message
    Je ne pense pas que ça soit une limitation, au contraire je dirais que c'est presque trop permissif C'est d'ailleurs une des forces du C et du C++. Mais une lourdeur oui, clairement.
    C'est en effet plus correct de dire ça et c'est un peu là que réside le compromis de langages comme Java : simplifier en retirant des possibilités pas vraiment utilisées. D'ailleurs B. Soustroup avait émis un souhait dans ce sens pour un C++ 2.0 (et sauf erreur de ma part, relativement à la notion de modules en C++).

  5. #5
    Membre chevronné

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Par défaut
    Dans ma solution, il suffirait toutefois de les préciser dans les seuls prototypes, même si ça reste un peu lourd.
    Ca donnerait surtout une syntaxe irrégulière, et pourrait dérouter un débutant.
    La solution que j'utilise n'est pas exactement codée "en dur". A termes, le but est de supporter n'importe quel namespace (boost, MyLibrary, ...) grâce au concept de "dépendance".
    Par exemple le "using std::string" dans le .mpp n'a pas le même sens qu'un "using std::string" en C++ : il indique que le module "Test" dépend du module "std::string", lequel met à disposition la classe "string" dans le namespace "std". C'est cette dernière information qui est codée en dur dans mon programme, rien de plus.

    D'ailleurs B. Soustroup avait émis un souhait dans ce sens pour un C++ 2.0 (et sauf erreur de ma part, relativement à la notion de modules en C++).
    Ah je n'avais pas fait attention à ça. J'ai beaucoup suivit la discussion sur les concepts (et j'ai été déçu de les voir retirés du lot), mais j'ai dû passer à côté des modules... J'irai voir quand j'aurai le temps, merci

  6. #6
    Membre expérimenté
    Avatar de Chatanga
    Profil pro
    Inscrit en
    Décembre 2005
    Messages
    211
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2005
    Messages : 211
    Par défaut
    Citation Envoyé par Kalith Voir le message
    J'ai beaucoup suivit la discussion sur les concepts (et j'ai été déçu de les voir retirés du lot), mais j'ai dû passer à côté des modules... J'irai voir quand j'aurai le temps, merci
    Il s'agissait d'une réponse de B. Soustroup à la question de savoir ce qu'il aimerait faire si on lui donnait la possibilité de faire un nouveau C++ (2.0 plutôt que C++ x0), sans soucis de rétro-compatibilité. Et, après vérification, aucune allusion à des modules en C++.

    Dans mes recherches, je suis toutefois tombé là dessus : http://os.inf.tu-dresden.de/~hohmuth/prj/preprocess. Les espaces de nommages n'y sont cependant pas gérés...

Discussions similaires

  1. [andromda]Infos sur andromda, générateur de code JAVA
    Par ugos dans le forum EDI et Outils pour Java
    Réponses: 5
    Dernier message: 08/09/2009, 15h30
  2. [Sunopsis] et les ETL générateur de code ?
    Par manuaccess10 dans le forum ODI (ex-Sunopsis)
    Réponses: 5
    Dernier message: 20/12/2006, 12h54
  3. Générateur de code
    Par jojo. dans le forum Mode d'emploi & aide aux nouveaux
    Réponses: 1
    Dernier message: 21/04/2006, 10h24
  4. Réponses: 4
    Dernier message: 21/02/2006, 19h45
  5. [Info][API]Générateur de code
    Par Archangelo dans le forum API standards et tierces
    Réponses: 6
    Dernier message: 24/07/2005, 14h59

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