如何在perl6语法中缓存和使用缓存的正则表达式?

lov*_*ato 6 regex perl6

我的代码花了很多时间在正则表达式插值上.由于模式很少改变,我想缓存这些生成的正则表达式应该加快代码.但我无法找到一种正确的方法来缓存和使用缓存的正则表达式.

该代码用于解析一些算术表达式.由于允许用户定义新运算符,因此解析器必须准备好将新运算符添加到语法中.因此,解析器使用表来记录这些新运算符,并在运行时从表中生成正则表达式.

#! /usr/bin/env perl6

use v6.c;

# the parser may add new operators to this table on the fly.
my %operator-table = %(
    1 => $['"+"', '"-"'],
    2 => $['"*"', '"/"'],
    # ...
);

# original code, runnable but slow.
grammar Operator {
    token operator(Int $level) {
        <{%operator-table{$level}.join('|')}>
    }

    # ...
}

# usage:
say Operator.parse(
    '+',
    rule => 'operator',
    args => \(1)
);
# output:
# ?+?
Run Code Online (Sandbox Code Playgroud)

以下是一些实验:

# try to cache the generated regexes but not work.
grammar CachedOperator {
    my %cache-table = %();

    method operator(Int $level) {
        if (! %cache-table{$level}) {
            %cache-table.append(
                $level => rx { <{%operator-table{$level}.join('|')}> }
            )
        }

        %cache-table{$level}
    }
}

# test:
say CachedOperator.parse(
    '+',
    rule => 'operator',
    args => \(1)
);
# output:
# Nil
Run Code Online (Sandbox Code Playgroud)
# one more try
grammar CachedOperator_ {
    my %cache-table = %();

    token operator(Int $level) {
        <create-operator($level)>
    }

    method create-operator(Int $level) {
        if (! %cache-table{$level}) {
            %cache-table.append(
                $level => rx { <{%operator-table{$level}.join('|')}> }
            )
        }

        %cache-table{$level}    
    }
}

# test:
say CachedOperator_.parse(
    '+',
    rule => 'operator',
    args => \(1)
);
# compile error:
# P6opaque: no such attribute '$!pos' on type Match in a Regex when trying to get a value
Run Code Online (Sandbox Code Playgroud)

rai*_*iph 4

以下内容不会直接回答您的问题,但可能会引起您的兴趣。

用户定义的运算符

以下代码在 P6 中声明一个运算符:

sub prefix:<op> ($operand) { " $operand prefixed by op" }
Run Code Online (Sandbox Code Playgroud)

现在可以使用 new 运算符:

say op 42; # 42 prefixed by op
Run Code Online (Sandbox Code Playgroud)

涵盖了广泛的运算符位置和参数,包括关联性和优先级的选择、分组的括号等。因此,也许这是实现您正在实现的内容的合适方法。

虽然很慢,但也可能足够快了。此外,正如 Larry在 2017 年所说……

我们知道解析器中的某些地方比应有的速度慢,例如...各种词法分析器重新查看 Perl 6 程序中的各种字符,每个字符平均执行 5 或 6 次,这显然不是最理想的,我们知道如何解决它

...幸运的是,Jonathan 今年将致力于 P6 语法解析器。

DSL 和俚语

即使您对使用主语言声明用户定义运算符的能力不感兴趣,或者由于某种原因不能,也可能会感兴趣/使用使其工作的底层机制。以下是一些参考: