【问题标题】:How to cache and use the cached regexes in perl6 grammar?如何在 perl6 语法中缓存和使用缓存的正则表达式?
【发布时间】:2019-01-19 12:12:46
【问题描述】:

我的代码在正则表达式插值上花费了大量时间。由于模式很少改变,我想缓存这些生成的正则表达式应该可以加快代码速度。但是我想不出一个正确的方法来缓存和使用缓存的正则表达式。

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

#! /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:
# 「+」

这里有一些实验:

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

【问题讨论】:

  • "# output: Nil" 见my SO answer about debugging grammars。 “# compile error: P6opaque: no such attribute '$!pos' on type Match in a Regex when trying to get a value” 我还没有理解您的代码或尝试运行它。但乍一看,您的代码似乎正在从语法中的方法返回正则表达式。但是the API is to return a Match object,是应用正则表达式的结果。也许我是误会了。我希望今晚晚些时候尝试运行它,也许我会更了解它。
  • @raiph 是的,我想返回一个正则表达式。好像我对语法有误解。
  • 终于回到了这个,但我太累了,今晚无法工作。希望我明天有时间。与此同时,可能会发布另一个关于在 Python 中运行 P6 或者更好的是在 Python 中运行 NQP 需要什么的 SO。 (更好,因为 NQP/nqp 会更快/更精简,并且可能对更多 Python 人来说更有趣,因为它基本上是一个 P6 正则表达式和 6model 引擎有点像 PCRECLOSish 引擎滚动的 P6 等价物合二为一)。

标签: regex raku


【解决方案1】:

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

用户定义的操作符

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

sub prefix:<op> ($operand) { " $operand prefixed by op" }

现在可以使用 new 运算符了:

say op 42; # 42 prefixed by op

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

虽然速度很慢,但可能已经足够快了。此外,作为拉里said in 2017 ...

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

...幸运的是Jonathan will work on the P6 grammar parser this year

DSL 和俚语

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

【讨论】:

  • 非常感谢您的建议。其实我想修改python的语法以支持用户定义的运算符。我可以在 python 代码中使用 perl6 吗?如果是这样,那就太好了。
  • 我不知道从 Python 调用 Rakudo(或 NQP 语法引擎,如果主要用途是语法,这将更快且完全可行)的方法类似于怎么能call Python from P6。但这会很好,不是吗?如果你有毅力,懂一点 C 语言,并与 P6 核心开发人员聊天,你也许可以做到这一点。 Stefan 在几个小时内启动了 Inline::Perl5,他在 3 minutes... 中解释了这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-17
  • 2012-09-12
  • 1970-01-01
  • 2012-08-13
  • 2015-08-05
  • 2010-09-09
相关资源
最近更新 更多