我试图创建一个语法。到目前为止,这是我的代码:
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
答案 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
并且解析成功,它的返回值就是一个解析树。
更新:可能的解决方案
让我们完全避开行动,然后将其解析为树:
右。如果你想要的只是解析树,那么你就不需要一个行动课,你也不需要打电话给parse
或make
。
相反,如果您想要另一棵树,例如{{3}},那么您可能会发现使用内置的made
和make
例程很方便。如果您使用made
和make
,您可能会发现将它们与单独的操作类结合使用是合适的,而不是直接将它们嵌入到语法的规则/标记/正则表达式中。