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

Langage Perl Discussion :

Comment définir des mots reservés dans une grammaire Perl6 ? [perl6]


Sujet :

Langage Perl

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Octobre 2016
    Messages
    39
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2016
    Messages : 39
    Par défaut Comment définir des mots reservés dans une grammaire Perl6 ?
    Bonjour,

    Encore une question la rédaction de grammaire en Perl6.

    Je prend conscience du besoin de définir des mots clés ( ou mots réservés) dans une grammaire. Par contre, je n'ai pas trouvé comment faire. Pourriez-vous m'indiquez comment ?

    Pour illustrer mon besoin, prenons le testcase suivant (simplification du parsing d'un ordre SQL, seul la clause from est défini) :

    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
    use Grammar::Tracer;
     
    grammar TEST {
     
     
    rule  TEST         { <from> <where> }
      rule  from              {:i FROM <selectedtable> [',' <selectedtable>]* }
        rule  selectedtable   {[<shema_name>'.']?<tablename>['@'<linkname>]? [<alias>]? }
            token shema_name  { <identifier> }
            regex tablename   { <identifier> }
            token linkname    { <identifier> }
            regex alias       { <identifier> }
            token identifier  {:i <ident>+ }
      rule where              {:i WHERE .* }
        regex comma   {',' }
    }
     
     
    my $fic = q:to/FIN_INI/;
    FROM table1 ,table2 t2  WHERE t1 = t2(+) 
    FIN_INI
     
     
    say TEST.parse($fic, rule => 'TEST');
    Ce code fonctionne bien et permet de récupérer l'AST :

    TEST
    | from
    | | selectedtable
    | | | shema_name
    | | | | identifier
    | | | | * MATCH "table1"
    | | | * MATCH "table1"
    | | | tablename
    | | | | identifier
    | | | | * MATCH "table1"
    | | | * MATCH "table1"
    | | | alias
    | | | | identifier
    | | | | * FAIL
    | | | * FAIL
    | | * MATCH "table1 "
    | | selectedtable
    | | | shema_name
    | | | | identifier
    | | | | * MATCH "table2"
    | | | * MATCH "table2"
    | | | tablename
    | | | | identifier
    | | | | * MATCH "table2"
    | | | * MATCH "table2"
    | | | alias
    | | | | identifier
    | | | | * MATCH "t2"
    | | | * MATCH "t2"
    | | * MATCH "table2 t2 "
    | * MATCH "FROM table1 ,table2 t2 "
    | where
    | * MATCH "WHERE t1 = t2(+) \n"
    * MATCH "FROM table1 ,table2 t2 WHERE t1 = t2(+) \n"

    「FROM table1 ,table2 t2 WHERE t1 = t2(+)

    from => 「FROM table1 ,table2 t2 」
    selectedtable => 「table1 」
    tablename => 「table1」
    identifier => 「table1」
    ident => 「table1」
    selectedtable => 「table2 t2 」
    tablename => 「table2」
    identifier => 「table2」
    ident => 「table2」
    alias => 「t2」
    identifier => 「t2」
    ident => 「t2」
    where => 「WHERE t1 = t2(+)



    Par contre, si au lieu de parser la chaine de caractère "FROM table1 ,table2 t2 WHERE t1 = t2(+) ", on parse "FROM table1 ,table2 WHERE t1 = t2(+) " alors cela ne marche plus :

    TEST
    | from
    | | selectedtable
    | | | shema_name
    | | | | identifier
    | | | | * MATCH "table1"
    | | | * MATCH "table1"
    | | | tablename
    | | | | identifier
    | | | | * MATCH "table1"
    | | | * MATCH "table1"
    | | | alias
    | | | | identifier
    | | | | * FAIL
    | | | * FAIL
    | | * MATCH "table1 "
    | | selectedtable
    | | | shema_name
    | | | | identifier
    | | | | * MATCH "table2"
    | | | * MATCH "table2"
    | | | tablename
    | | | | identifier
    | | | | * MATCH "table2"
    | | | * MATCH "table2"
    | | | alias
    | | | | identifier
    | | | | * MATCH "WHERE"
    | | | * MATCH "WHERE"
    | | * MATCH "table2 WHERE "
    | * MATCH "FROM table1 ,table2 WHERE "

    | where
    | * FAIL
    * FAIL
    Nil

    On voit, grace au tracer, que le mot clé WHERE a été consommé en tant qu'alias ...

    D'où mon besoin d'arriver à exprimer que WHERE est un mot réservé... A moins qu'une autre solution n'existe ?

    Merci beaucoup pour votre aide.
    Bien cordialement,

  2. #2
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Billets dans le blog
    1
    Par défaut
    Bonjour,

    le problème est que ta règle identifier utilisée pour définir quatre autres règles n'est pas assez discriminante, du coup elle reconnaît trop de choses. Mais si un alias peut être un identifiant à peu près quelconque, alors il n'y a pas trop de solution pour la rendre non discriminante.

    Il faut donc procéder autrement.

    Il est sans doute possible d'ajouter une assertion pour dire que l'alias ne doit pas être un "where" ou un 'WHERE", mais ça ne me paraît pas très satisfaisant.

    Du coup, la solution pourrait être d'autoriser le moteur de regex à faire un retour arrière pour trouver le "where" ou "WHERE" même s'il avait été initialement consommé par la règle alias. Donc, utiliser des règles de type regex au lieu de rule:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    rule  TEST           { <from> <where> }
    regex  from          {:i :s FROM <selectedtable> [',' <selectedtable>]* }
    regex selectedtable  {:s [<shema_name>'.']?<tablename>['@'<linkname>]? [<alias>]? }
    ...
    Note que je dois ajouter un adverbe :s (sigspace) pour garder le comportement sigspace d'une rule après en avoir fait une regex.

  3. #3
    Membre averti
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Octobre 2016
    Messages
    39
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2016
    Messages : 39
    Par défaut
    Merci encore pour ces explications très claires, toujours aussi rapide et judicieuse. Le tracer montre bien le retour arrière :

    TEST
    | from
    | | selectedtable
    | | | shema_name
    | | | | identifier
    | | | | * MATCH "table1"
    | | | * MATCH "table1"
    | | | tablename
    | | | | identifier
    | | | | * MATCH "table1"
    | | | * MATCH "table1"
    | | | alias
    | | | | identifier
    | | | | * FAIL
    | | | * FAIL
    | | * MATCH "table1 "
    | | selectedtable
    | | | shema_name
    | | | | identifier
    | | | | * MATCH "table2"
    | | | * MATCH "table2"
    | | | tablename
    | | | | identifier
    | | | | * MATCH "table2"
    | | | * MATCH "table2"
    | | | alias
    | | | | identifier
    | | | | * MATCH "WHERE"
    | | | * MATCH "WHERE"
    | | * MATCH "table2 WHERE "
    | * MATCH "FROM table1 ,table2 WHERE "
    | where
    | * FAIL
    | where
    | * MATCH "WHERE t1 = t2(+) \n"

    * MATCH "FROM table1 ,table2 WHERE t1 = t2(+) \n"

    Je me demande pourquoi vaut il mieux utiliser le retour arrière plutôt qu'une assertion permettant d'éliminer le mot clé WHERE de la classe des identifiers ? Est ce pour éviter que pour chaque identifier trouvé, on ne doive tester sa valeur avec la liste des mots clés ? Le retour arrière lui se fait uniquement lorsque le regex ne peut pas être évalué. Est ce la vrai raison ou bien y'en a t'il une autre ?

    Encore merci.
    Bien cordialement,

  4. #4
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Billets dans le blog
    1
    Par défaut
    Re assertions vs. retour arrière, en fait, c'est probablement discutable, c'est juste mon impression personnelle.

    Une assertion, ce n'est pas très flexible et ça devient a priori plus complexe dès qu'on veut gérer plusieurs mots; il me semble qu'une assertion sort un peu de la logique des grammaires et des regex, que c'est en quelque sorte une verrue procédurale au milieu d'un système de programmation essentiellement déclarative. Ce qui ne veut pas dire que je rejette les assertions, bien au contraire, c'est super pratique pour bien des choses difficiles à exprimer sous le forme de regex ou de règles.

    Dans le cas en question, utiliser le retour arrière me paraît être plus dans l'esprit des regex et des grammaires, donc plus satisfaisant intellectuellement. Mais peut-être qu'un expert des grammaires (ce que je ne suis pas du tout, je suis encore un modeste débutant dans ce domaine) aurait un avis contraire.

  5. #5
    Membre averti
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Octobre 2016
    Messages
    39
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2016
    Messages : 39
    Par défaut
    Merci beaucoup pour cet avis qui m'aide à mieux comprendre.
    J'avoue que je testerai bien l'assertion... mais je n'ai pas trouvé comment faire. Une idée ? Sinon ce n'est pas très grave, j'ai déjà une solution, c'est très bien.

    Merci encore.
    Bien cordialement,

  6. #6
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Billets dans le blog
    1
    Par défaut
    Le plus simple pour l'utilisation d'une assertion est peut-être une assertion de type code (code assertion), mais je m'aperçois que je n'ai apparemment pas décrit réellement ce type d'assertion dans mon tutoriel (il faudra que j'ajoute quelque chose), j'ai juste donné un exemple dans la section 4.2.4 Reconnaître une adresse IP.

    Dans ton cas, on peut faire par exemple ceci (je suis reparti du code de ton post d'origine):
    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
     
    use Grammar::Tracer;
     
    grammar TEST {
     
     
    rule  TEST         { <from> <where> }
      rule  from              {:i FROM <selectedtable> [',' <selectedtable>]* }
        rule  selectedtable   {[<shema_name>'.']?<tablename>['@'<linkname>]? [<alias>]? }
            token shema_name  { <identifier> }
            regex tablename   { <identifier> }
            token linkname    { <identifier> }
            regex alias       { <identifier> <!{ $<identifier> ~~ /:i where/ }> }
            token identifier  {:i <ident>+ } }>
      rule where              {:i WHERE .* }
        regex comma   {',' }
    }
    Le seul changement à ton code d'origine est dans la regex alias. qui précise que l'identifiant capturé par la règle alias ne doit pas reconnaître where (casse indifférente).

    Il y a des chances que cette solution avec assertion soit un peu plus rapide que celle consistant à remplacer des rules par des regex pour permettre le retour arrière (je n'ai pas vérifié), mais ça n'a pas forcément beaucoup d'importance.

    Sinon, une assertion avant (voir 2-10-1. Assertions avant) devrait aussi pouvoir faire l'affaire.

    Edit: Correction de l'assertion qui était fausse (c'était; <!{ $<identifier> !~~ /:i where/ >} }, avec mauvaise fermeture de l'assertion. Je corrige pour ceux qui voudraient tester le code.

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

Discussions similaires

  1. Réponses: 2
    Dernier message: 28/03/2008, 18h24
  2. Réponses: 5
    Dernier message: 06/02/2008, 16h01
  3. [C#] Comment insérer des retours chariot dans une chaine de caractère ?
    Par tazmania dans le forum Accès aux données
    Réponses: 4
    Dernier message: 30/10/2006, 09h27
  4. Réponses: 1
    Dernier message: 03/02/2006, 12h35
  5. Comment stocker des mots clés dans une bas Mysql
    Par renofx1 dans le forum SQL Procédural
    Réponses: 5
    Dernier message: 05/01/2006, 00h57

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