How to refer to previously matched items in a grammar?

Viewed 140

I am trying to parse a BibTeX author field, and split it into its separate authors. This will help me rewriting the initials of each author. Here is a minimal example:

use v6;

my $str = '{Rockhold, Mark L and Yarwood, RR and Selker, John S}';

grammar BibTexAuthor {
    token TOP {
        <all-text> 
    }
    token all-text {
        '{' <authors> '}' 
    }
    token authors { 
        [<author> [' and ' || <?before '}'>]]+
    }
    token author {
        [<-[\s}]> || [' ' <!before 'and '>]]+
    }
}

class BibTexAuthor-actions {
    method TOP($/) {
        say $/;
        print "First author = ";
        say $<author>.made[0];
        make $/.Str;
    }
    method all-text($/) {
        make $/.Str;
    }
    method authors($/) {
        make $/.Str;
    }
    method author($/) {
        make $/.Str;
    }
}
my $res = BibTexAuthor.parse( $str, actions => BibTexAuthor-actions.new).made;

Output:

「{Rockhold, Mark L and Yarwood, RR and Selker, John S}」
 all-text => 「{Rockhold, Mark L and Yarwood, RR and Selker, John S}」
  authors => 「Rockhold, Mark L and Yarwood, RR and Selker, John S」
   author => 「Rockhold, Mark L」
   author => 「Yarwood, RR」
   author => 「Selker, John S」
First author = Nil

Why am I not able to extract the first author in the TOP method?

2 Answers

Why am I not able to extract the first author in the TOP method?

Because you are not really extracting any data in the action methods. All you do is attach the string of the match to $/.made, which is not actually the data you want in the end.

If you want to have separate authors in the end, you should make an array of authors in the authors action method. For example:

use v6;

my $str = '{Rockhold, Mark L and Yarwood, RR and Selker, John S}';

grammar BibTexAuthor {
    token TOP {
        <all-text> 
    }
    token all-text {
        '{' <authors> '}' 
    }
    token authors { 
        [<author> [' and ' || <?before '}'>]]+
    }
    token author {
        [<-[\s}]> || [' ' <!before 'and '>]]+
    }
}

class BibTexAuthor-actions {
    method TOP($/) {
        make { authors => $<all-text>.made };
    }
    method all-text($/) {
        make $/<authors>.made;
    }
    method authors($/) {
        make $/<author>».made;
    }
    method author($/) {
        make $/.Str;
    }
}
my $res = BibTexAuthor.parse( $str, actions => BibTexAuthor-actions.new).made;

say $res.perl;

prints

${:authors($["Rockhold, Mark L", "Yarwood, RR", "Selker, John S"])}

so now the .made of the top-level match is a hash, where the authors key holds an array. If you want to access the first author, you can now say

say $res<authors>[0];

to get Rockhold, Mark L

$<all-text><authors><author>[0];

Note, that I have no idea how grammars work until now. I'm learning the language as you do.

But just by looking at the datastrucure it's easy to realize it's a tree and where in that tree the value you are looking for is.

You can output any datastructure by saying

dd $someStructure;
say $someStructure.perl;

and if you find that unreadable, you can try one of the Dumper Modules

Related