我的代码在正则表达式插值上花费了大量时间。由于模式很少更改,我想将这些生成的正则表达式缓存起来可以加快代码的速度。但是我无法找出正确的方法来缓存和使用缓存的正则表达式。
该代码用于解析某些算术表达式。由于允许用户定义新的运算符,因此解析器必须准备好将新的运算符添加到语法中。因此,解析器使用表格记录这些新的运算符,并动态地从表格中生成正则表达式。
#! /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
答案 0 :(得分:4)
以下内容不能直接回答您的问题,但可能会引起您的兴趣。
以下代码在P6中声明一个运算符:
sub prefix:<op> ($operand) { " $operand prefixed by op" }
现在可以使用新的运算符了:
say op 42; # 42 prefixed by op
涵盖了范围广泛的操作员职位和联系方式,包括对关联性和优先级的选择,用于分组的括号等。因此,这也许是实现您要实现的目标的一种合适方法。
尽管速度很慢,但可能足够快。此外,作为拉里said in 2017 ...
我们知道解析器中某些地方的速度慢于应有的速度,例如...各种词法分析器会重新查看Perl 6程序中的各种字符,每个字符平均5到6次,这显然很深次优,我们知道如何解决
...并且很幸运,Jonathan will work on the P6 grammar parser this year。
即使您对使用主语言声明用户定义的运算符的能力不感兴趣,或者由于某种原因而不能使用,使它起作用的基本机制也可能会受到关注/使用。这里是一些参考:
Mouq的2014年要旨Slangs。
拉里·沃尔(Larry Wall)在Switching parsers and Slangs时的推测。