在Perl 6中传递数据以形成语法规则

时间:2017-10-21 08:34:26

标签: perl6

不确定atomic_fetch_add是否意味着要执行此类操作:我希望在运行时(将来使用文件中的数据)定义grammars。所以我写了一个简单的测试代码,正如预期的那样,它甚至都不会编译。

tokens

在Perl 6中做这些事情的最佳方式是什么?

2 个答案:

答案 0 :(得分:7)

要匹配数组的任何元素,只需在正则表达式中写入数组变量的名称(以@ sigil开头):

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

所以在你的用例中,唯一棘手的部分是将数组从创建它们的代码(例如通过解析数据文件)传递给需要它们的语法标记。

最简单的方法可能是使它们成为动态变量(由* twigil表示):

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;

另一种方法是将带有数组的Capture传递给方法.parseargs副词,然后将其传递给token TOP,从那里你可以然后使用<foo(...)><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

答案 1 :(得分:2)

你采取的方法可能有效,但你犯了三个错误。

作用域

词汇变量声明需要在编译器遇到它们之前以文本形式出现

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

回溯

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」

regex声明符与token声明符的效果完全相同,只是它默认为backtracking

您在\w+令牌中首次使用root会匹配整个输入'going',然后无法匹配@root的任何元素。然后,由于没有回溯,整体解析立即失败。

(不要认为你应该默认使用regex。依赖回溯会大大减慢解析速度,通常不需要它。)

调试

请参阅https://stackoverflow.com/a/19640657/1077672

这有效:

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>;

输出:

go