2017-10-21 70 views
6

Pas sûr que grammars sont destinés à faire de telles choses: Je veux tokens à définir dans l'exécution (à l'avenir - avec les données d'un fichier). J'ai donc écrit un code de test simple, et comme prévu, il ne serait même pas compilé.données Passing pour former des règles de grammaire en Perl 6

grammar Verb { 
    token TOP { 
    <root> 
    <ending> 
    } 
    token root { 
    (\w+) <?{ ~$0 (elem) @root }> 
    } 
    token ending { 
    (\w+) <?{ ~$0 (elem) @ending }> 
    } 
} 

my @root = <go jump play>; 
my @ending = <ing es s ed>; 

my $string = "going"; 
my $match = Verb.parse($string); 
.Str.say for $match<root>; 

Quelle est la meilleure façon de faire de telles choses dans Perl 6?

Répondre

6

Pour correspondre à l'un des éléments d'un tableau, il suffit d'écrire le nom de la variable tableau (en commençant par un @ Sigil) dans la regex:

my @root = <go jump play>; 
say "jumping" ~~/@root /;  # Matches 「jump」 
say "jumping" ~~/@root 'ing' /; # Matches 「jumping」 

Donc, dans votre cas d'utilisation, la la seule chose délicate est de passer les tableaux du code qui les crée (par exemple en analysant les fichiers de données) aux jetons de grammaire qui en ont besoin.

grammar Verb { 
    token TOP { 
     <root> 
     <ending> 
    } 
    token root { 
     @*root 
    } 
    token ending { 
     @*ending 
    } 
} 

my @*root = <go jump play>; 
my @*ending = <ing es s ed>; 

my $string = "going"; 
my $match = Verb.parse($string); 

say $match<root>.Str; 

Une autre façon serait de passer un Capture avec les tableaux à l'adverbe args de la méthode .parse qui:

La façon la plus simple serait sans doute de les rendre variables dynamiques (signifiées par le * twigil) les transmettra à token TOP, d'où vous pouvez à son tour les transmettre aux sous-règles en utilisant la syntaxe <foo(...)> ou <foo: ...>:

grammar Verb { 
    token TOP (@known-roots, @known-endings) { 
     <root: @known-roots> 
     <ending: @known-endings> 
    } 
    token root (@known) { 
     @known 
    } 
    token ending (@known) { 
     @known 
    } 
} 

my @root = <go jump play>; 
my @ending = <ing es s ed>; 

my $string = "going"; 
my $match = Verb.parse($string, args => \(@root, @ending)); 

say $match<root>.Str; # go 
+0

Wow, il est absolument merveilleux, correspondant surtout un tableau! –

2

L'approche que vous utilisiez aurait pu fonctionner mais vous avez fait trois erreurs.

portée

déclarations variables lexicales doivent apparaître textuellement avant le compilateur rencontre leur utilisation:

my $foo = 42; say $foo; # works 
say $bar; my $bar = 42; # compile time error 

Backtracking

say .parse: 'going' for 

    grammar using-token    {token TOP {   \w+ ing}}, # Nil 
    grammar using-regex-with-ratchet {regex TOP {:ratchet \w+ ing}}, # Nil 
    grammar using-regex    {regex TOP {   \w+ ing}}; # 「going」 

Le regex déclarateur a exactement le même effet que le token déclarant, sauf qu'il est par défaut de faire backtracking.

Votre première utilisation de \w+ dans le jeton root correspond à l'entrée entière 'going', qui ne parvient pas à correspondre à tout élément de @root. Et puis, parce qu'il n'y a pas de retour en arrière, l'analyse globale échoue immédiatement.

(Ne tenez pas cela pour signifier que vous devriez utiliser regex par défaut.) S'appuyer sur le backtracking peut ralentir massivement l'analyse et cela n'est généralement pas nécessaire.)

Debugging

Voir https://stackoverflow.com/a/19640657/1077672


Cela fonctionne:

my @root = <go jump play>; 
my @ending = <ing es s ed>; 

grammar Verb { 
    token TOP { 
    <root> 
    <ending> 
    } 
    regex root { 
    (\w+) <?{ ~$0 (elem) @root }> 
    } 
    token ending { 
    (\w+) <?{ ~$0 (elem) @ending }> 
    } 
} 

my $string = "going"; 
my $match = Verb.parse($string); 

.Str.say for $match<root>; 

sorties:

go 
+1

c'est un super commentaire! Après de nombreux tests aujourd'hui avec différents 'tokens' de type \ w +' suivis d'une terminaison, j'ai finalement compris que cela ne correspondrait pas sans retour arrière et changé 'token' en' regex'. –

+1

@evb Notez que l'on peut écrire 'regex root {' ou 'token root {:! Ratchet'. Ils signifient exactement la même chose. – raiph