我如何使用perl6语法创建一个解析树?

时间:2017-04-21 19:51:03

标签: parsing grammar perl6

我试图创建一个语法。到目前为止,这是我的代码:

use Text::Table::Simple; # zef install Text::Table::Simple

my $desc = q:to"FIN";
record person
        name string;
        age  int;
end-record
FIN

grammar rec {
        token TOP { <ws>* 'record' \s+ <rec-name> <field-descriptors> <ws> 'end-record' <ws> }  
        token rec-name { \S+ }
        token field-descriptors { <field-descriptor>* }
        token field-descriptor { <ws>* <field-name> <ws>+ <field-type> <ws>* ';' }
        token field-name { \S+ }
        token field-type { <[a..z]>+ }
        token ws { <[\r\n\t\ ]> }
}


class recActions {
        method field-descriptors($/) { $/.make: $/; }
        method field-descriptor($/) { $/.make: $/; }
        method field-name($/) { $/.make: $/ }
        method field-type($/) { $/.make: $/ }
}

my $r = rec.parse($desc, :actions(recActions));
#say $r;

my $inp = q:to"FIN";
adam    26
joe     23
mark    51
FIN

sub splitter($line) { 
        my @lst = split /\s+/, $line; 
}


sub matrixify(&splitter, $data)
{
        my @d = (split /\n/, (trim-trailing $data)).map( -> $x { splitter $x ; } );
        #@d.say;
        #my @cols = <name age>;
        #say lol2table(@cols, @d).join("\n");
        @d;
}

#my @cols =<A B>;
#my @rows = ([1,2], [3,4]);
#say lol2table(@cols, @rows).join("\n");

my @m = matrixify &splitter, $inp;

sub tabulate($rec-desc, @matrix)
{
        my $fds = $rec-desc<field-descriptors>;
        #say %fds<field-name>;
        say $fds;
        my @cols = $rec-desc.<field-descriptors>.map( -> $fd { say $fd; $fd.<field-name> ; 1;} );
        #say $rec-desc.<field-descriptors>;
        #say @cols;
}
tabulate $r, @m ;

我真的只想让语法从输入创建一个列表/哈希表树。代码的输出是:

「
    name string;
    age  int;」
 field-descriptor => 「
    name string;」
  ws => 「
」
  ws => 「   」
  field-name => 「name」
  ws => 「 」
  field-type => 「string」
 field-descriptor => 「
    age  int;」
  ws => 「
」
  ws => 「   」
  field-name => 「age」
  ws => 「 」
  ws => 「 」
  field-type => 「int」

看起来相当不错。 perl6似乎解码了field-descriptors由多个field-descriptor组成的事实,但它实际上似乎并没有将它们放入列表中。我可以say $fds;,但我无法say $fds[0];。为什么前者&#34;工作&#34;,但后者没有?

我必须承认对所发生的事情的理解相当薄弱。我会更好地使用规则而不是令牌吗?我真的需要一个动作课;我不能自动获得perl&#34;自动化&#34;为我填充解析树而不必指定一类操作?

更新:可能的解决方案

假设我们只想解析:

my $desc = q:to"FIN";
record person
    name string;
    age  int;
end-record
FIN

并报告我们找到的字段名称和类型。我将对上面写的语法进行略微简化:

grammar rec {
    token TOP { <ws>* 'record' \s+ <rec-name> <field-descriptor>+ <ws> 'end-record' <ws> }  
    token rec-name { \S+ }
    token field-descriptor { <ws>* <field-name> <ws>+ <field-type> <ws>* ';' }
    token field-name { \S+ }
    token field-type { <[a..z]>+ }
    token ws { <[\r\n\t\ ]> }
}

让我们完全避开行动,然后将其解析为树:

my $r1 = rec.parse($desc);

现在让我们检查一下我们的工作,并打印出我们解析过的每个字段的名称和类型:

for $r1<field-descriptor> -> $fd { say "Name: $fd<field-name>, Type: $fd<field-type>"; }

我们的产出符合我们的预期:

Name: name, Type: string
Name: age, Type: int

1 个答案:

答案 0 :(得分:2)

我知道你现在已经完成了所有的设定,但是这里的答案可以让其他人稍后阅读。

  

如何使用perl6语法创建一个解析树?

它尽可能简单:只需使用调用其中一个内置解析例程的返回值。

(提供解析成功appdir/public/stylesheets/style.css并且堂兄弟返回"How do I access the captures within a match?"。)

  

代码的输出......看起来相当不错。 perl6似乎正在解释字段描述符由多个字段描述符组成的事实,但它实际上似乎并没有将它们放入列表中。我可以说$ fds;,但我不能说$ fds [0] ;.为什么前者&#34;工作&#34;,但后者没有?

请参阅我对SO问题的回答Abstract Syntax Tree

  

我会更好地使用规则而不是令牌吗?

令牌和规则之间的唯一区别是解释您在令牌/规则中包含的裸空白的默认值。

令牌中的裸露空白被完全忽略。规则中的裸露空白表示&#34;此时输入中可能有空格&#34; 。)

  

我真的需要一个动作类[?]

没有

如果你想系统地发布处理解析树,那么只需要操作一个动作类。

  

我不能自动获得perl&#34;自动&#34;为我填充解析树而不必指定一类操作?

是。只要你调用parse并且解析成功,它的返回值就是一个解析树。

  

更新:可能的解决方案

     

让我们完全避开行动,然后将其解析为树:

右。如果你想要的只是解析树,那么你就不需要一个行动课,你也不需要打电话给parsemake

相反,如果您想要另一棵树,例如{{3}},那么您可能会发现使用内置的mademake例程很方便。如果您使用mademake,您可能会发现将它们与单独的操作类结合使用是合适的,而不是直接将它们嵌入到语法的规则/标记/正则表达式中。