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

Générateurs de compilateur Discussion :

Parser une ligne de commande.


Sujet :

Générateurs de compilateur

  1. #1
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2012
    Messages
    118
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2012
    Messages : 118
    Points : 40
    Points
    40
    Par défaut Parser une ligne de commande.
    Bonjour,
    Je souhaiterais avoir quelque conseils sur la découpe d'une ligne de commande.
    Le principe est donc de découper ma chaîne de caractère.
    Chaque commande correspond à une instruction que mon programme va exécuter. Par exemple (sur une boucle de read), ça feras pour additionner par exemple:
    add 5 8
    Cela aura pour effet d'additionner 5 et 8.
    Ma première intuition était de faire des pointeur sur fonction. J'isole le premier mot(add) pour savoir dans quelle fonction envoyer le reste de ma chaîne de caractère(5 8).
    Une fois à l'intérieur de ma fonction je reparse ma chaîne.
    Mon idée est donc de faire un tableau de structure du style:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    struct list {
        char *name;
        void (*func)(char *arg);
    };
    Voila je voudrais savoir si il y a d'autres meilleurs méthodes.
    Ps: J'ai déjà été confronter à ce genre de problème sans réellement faire un code propre. On m'a déjà parler de Lexer mais je n'ai jamais vraiment réussi à le mettre en place, ni vraiment bien compris .
    Merci de votre aide.

  2. #2
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Salut,

    Avant de te demander comment tu vas stocker la fonction associée à un mot-clé, il faut déjà être capable d'extraire le mot-clé et les autres éléments qui le suivent.

    Je viens de lire l'article Wikipédia sur l'analyse lexicale, c'est intéressant. Tu pourras y lire qu'il existe des générateurs de lexers, tels que flex. Tu pourras voir grâce une petite recherche sur le forum que des gens utilisent flex et bison pour faire de l'analyse de texte. Developpez et le net en général te donneront plein d'informations à leur sujet.

    As-tu beaucoup de commandes à parser ? Quelle est la complexité de ces commandes ? Si tu n'as que quelques commandes simples, tu peux peut-être faire quelque chose de "basique" à la main.

    Pourquoi cette idée de pointeurs sur fonction dans une structure ?

  3. #3
    Membre éclairé
    Inscrit en
    Décembre 2010
    Messages
    290
    Détails du profil
    Informations forums :
    Inscription : Décembre 2010
    Messages : 290
    Points : 719
    Points
    719
    Par défaut
    Comme le dit Bktero, si ce ne sont que quelque commandes simples, utiliser Flex Bison et autres Yacc parait quand même assez lourd (c'est un exercice très intéressant toutefois).
    Pour ma part, pour avoir écrit plusieurs petits interpréteurs de commande pour des systèmes embarqués, voilà ce que je fais habituellement :
    - je copie la chaîne en entrée (pour pouvoir la modifier)
    - je maintiens un tableau de pointeurs vers char
    - je parcours ma copie de la ligne de commande, en stockant dans mon tableau de pointeurs le début de chaque mot, et en écrivant un 0 à chaque fin de mot, pour terminer le token.
    L'idée, c'est à la fin d'avoir un tableau similaire au couple argv/argc.
    Ensuite, je cherche la fonction qui porte le nom inscrit dans argv[0] et je l'appelle en lui passant le tableau complet. L'équivalent de ma fonction 'add' est donc :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
     void my_add (int argc, char *argv[]);

  4. #4
    Membre expérimenté

    Homme Profil pro
    Collégien
    Inscrit en
    Juillet 2010
    Messages
    545
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Afghanistan

    Informations professionnelles :
    Activité : Collégien

    Informations forums :
    Inscription : Juillet 2010
    Messages : 545
    Points : 1 431
    Points
    1 431
    Par défaut
    Salut,

    J'utilise la même méthode que toi pour piloter un appareil de notre conception.
    Il se trouve qu'il existe une centaine de commande chez nous. Chaque commande est représenté par une chaine de caractères et possède possède 0 ou 1 ou plusieurs paramètre.

    Après avoir beaucoup bossé sur le sujet j'ai trouvé que la méthode la plus élégante pour gérer le truc est la suivante:

    Commence par créer la liste exhaustive des commandes par un type énumérée:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    /* Enumere les commandes de mon systeme*/
    typedef enum
    {
        CMD_NULL = 0,
        CMD_BOOTSECTOR,
        /* */
        N_CMDS
    }cmd_e;
    Définit une structure commande et une structure liste de commande

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    /* une commande est représentée uniquement par une chaine de caractère*/
    typedef struct
    {
        const char *    frmt;   /**the ASCII string that defines de the command*/
        size_t          len;    /**the length ASCII string that defines de the command*/
    }cmd_t;
    /* la liste des commandes du system*/
    typedef struct
    {
        cmd_t cmd[N_CMDS];  /** the commands are listed in a table*/
    }cmd_list_t;
    Définit ta règle de gestion de paramètres

    Code : 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
    /**
     *\return True quand un commande contient 1 ou plusieurs paramètres
     */
    static inline bool cmd_has_args(const cmd_t * const this)
    {   /* cmd has args when it ends with a space character */
        return (this->frmt[this->len-1] == ' ');
    }
     
    /**
     *\return un pointer sur le premier caractère des paramètres de la commande,
     * NULL si la commande n'a pas de paramètres
     */
    static inline const char * cmd_get_args(const cmd_t * const this,const char * buff)
    {   /* return the char after ' ', else NULL*/
        return cmd_has_args(this)?&buff[this->len-1]:NULL;
    }
    Définit une méthode pour créer a liste des commandes au démarrage du système

    Code : 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
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    /**
     *\return La chaine de caractère qui représente la commande
     */
    static const char * cmd2str(const cmd_e cmd)
    {
        switch(cmd)
        {                           
            case CMD_NULL                       : return "\r\n";break;
            case CMD_BOOTSECTOR                 : return "boot_sector ";break;
            default                             :
            {
                printf("WARNING: Debug Command %"PRIu32" has no format\n",(uint32_t)cmd);
                return "";
            }
        }/* end switch*/
    }/*end cmd2str*/
     
    /**
     *\return this
     */
    cmd_list_t * init_cmd_list(cmd_list_t * const this)
    {
        if(this)
        {
            for(cmd_e i = 0 ; i < N_CMDS ; i++)
            {
                this->cmd[i].frmt   = cmd2str(i);
                this->cmd[i].len    = strlen(this->cmd[i].frmt);
            }
        }
        return this;
    }
    Il reste a implémenter une méthode qui recherche une ou des commandes dans une chaine de caractère et l'exécute sur le système

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    size_t search_and_exe_cmd(my_System_t * const this,const char * const asciiCmds, const size_t asciiCmdsLen)
    Le but de cette organisation est de de pouvoir la liste des actions a effectuer pour chaque commande dans un switch case:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    static void system_cmd_execute(mySystem_t * const this,const cmd_e cmd,const char * const args)
    {
        /* execute te appropriate cmd*/
        switch(cmd)
        {
            case CMD_NULL       : printf("\r\nCOUCOU\n");break;
            case CMD_BOOTSECTOR : changer_secteur de boot(this,strtol(args,(char **)NULL,10))break;
            default             : printf("\r\nUNKONWN!!\n");
        }
    }

  5. #5
    Membre expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Points : 3 352
    Points
    3 352
    Par défaut
    Bonjour,

    c'est le genre de problème que l'on peut résoudre aussi bien en écrivant son propre parser qu'en utilisant des outils prévus pour comme flex/bison.
    Ensuite le choix va dépendre et de la taille et des exigences de ton projet. Si c'est un petit projet personnel le parser qui fonctionne suffisamment bien écrit pour l'occasion peut faire l'affaire. Si c'est un projet plus conséquent qui a vocation d'être distribué et utilisé par d'autres personnes alors utiliser flex/bison peut être recommandé pour la simple raison que ce sont des outils largement utilisés qui ont fait leurs preuves, malgré leur approche un peu sèche et vieillote.

    Le plus compliqué d'ailleurs ne sera pas tant de parser une ligne que de gérer les erreurs, ou de bien construire ton langage.

    Est-ce toi qui le crée ou bien te. le donne-t-on ?

  6. #6
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2012
    Messages
    118
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2012
    Messages : 118
    Points : 40
    Points
    40
    Par défaut
    En fait mon projet est assez simple, je fait des read qui correspondent à des instructions, par exemple j'ai un personnage et on peut lui demander de bouger à droite, par exemple:
    move right (pour bouger a droite)
    On pourrait également changer sont niveau:
    lvl n(numéro du joueur) +1 (on augmente 1 niveau au joueur numéro n)
    voila le but de mon programme.
    Je vais faire le technique de phi1981 qui me semble pas mal mais si vous avez des suggéstion n'hésitez pas. Merci.
    phil1981 quand tu dit :
    je parcours ma copie de la ligne de commande, en stockant dans mon tableau de pointeurs le début de chaque mot
    Tu veux dire chaque mot en fait non ? Par exemple pour "add 5 8" tu décompose "add", "5", "8".
    Mith06 j'ai un peu de mal à comprendre le code dsl, c'est du C ?

  7. #7
    Rédacteur
    Avatar de Franck.H
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2004
    Messages
    6 951
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2004
    Messages : 6 951
    Points : 12 462
    Points
    12 462
    Par défaut
    Le problème avec Flex/Bison c'est qu'il y a très très peu de tutoriels en français sur le net pour l'apprendre avec plus ou moins de détails. Je voulais toujours m'y mettre mais ce manque de support n'encourage en rien
    Mon Site
    Ma bibliothèque de gestion des chaînes de caractères en C

    L'imagination est plus importante que le savoir. A. Einstein

    Je ne répond à aucune question technique par MP, merci d'avance !

  8. #8
    Membre éclairé
    Inscrit en
    Décembre 2010
    Messages
    290
    Détails du profil
    Informations forums :
    Inscription : Décembre 2010
    Messages : 290
    Points : 719
    Points
    719
    Par défaut
    Citation Envoyé par shirohige Voir le message
    Tu veux dire chaque mot en fait non ? Par exemple pour "add 5 8" tu décompose "add", "5", "8".
    Oui je décompose la chaîne de caractères en "mots" en utilisant les blancs (espace ou tabulation) comme séparateurs.
    Certains traitements sont faciles à rajouter, comme par exemple autoriser une ligne comme celle-ci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    print "Hello the world"
    où tu considères que plusieurs mots entre guillemets sont à regrouper en un seul.

Discussions similaires

  1. Réponses: 11
    Dernier message: 20/12/2005, 16h29
  2. Parser une ligne saisie au clavier.
    Par Sylmandel dans le forum C++
    Réponses: 5
    Dernier message: 17/10/2005, 10h12
  3. [OCaml] Parser une ligne de commande
    Par Thanatos dans le forum Caml
    Réponses: 4
    Dernier message: 10/12/2004, 10h11
  4. lancer une mdb a partir d'une ligne de commande
    Par dpie dans le forum Access
    Réponses: 5
    Dernier message: 30/11/2004, 15h01
  5. [langage] Continuer a parser une ligne
    Par D[r]eadLock dans le forum Langage
    Réponses: 5
    Dernier message: 30/09/2002, 18h49

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