我该如何编写Raku正则表达式的别名?

10
我写了一个类似于这样的语法:
grammar StatementFormat {
    token TOP { (<plain> | '%' <placeholder>)* }

    token plain { <-[%]> }

    token placeholder {
        | <verb>
        | <noun>
        | <adverb>
    }

    token verb {
        'v'
        {
            # some actions
        }
    }

    token noun {
        'n'
        {
            # some actions
        }
    }

    token adverb {
        'a'
        {
            # some actions
        }
    }
}

所以我可以使用它来解析类似“someone %v %n %a”的字符串。
然而,我发现有很多像“%v %n %a”这样的用法,我想给它一个别名,比如“%b”,这样解析“someone %b”就相当于解析“someone %v %n %a”。
那么有没有办法做到这一点呢?
当然,token alias { 'b' { ... } }可以做到这一点。但是那样我需要重复那个动作代码。我想知道是否存在更简单的方法。
1个回答

11

那么,有一种显而易见的方法,就是将动作的代码放入子程序中,然后在b的别名中调用它们:

sub verb-action($/) { }
sub noun-action($/) { }
sub adverb-action($/) { }

grammar StatementFormat {
    # rest goes here

    token verb {
        'v'
        { verb-action($/) }
    }

    token noun {
        'n'
        { noun-action($/) }
    }

    token adverb {
        'a'
        { adverb-action($/) }
    }

    token alias {
        'b'
        {
            verb-action($/);
            noun-action($/);
            adverb-action($/);
        }
    }
}

但那样会有什么乐趣呢?

相反,我建议使用语法的内置操作对象特性

它是这样运行的:您需要一个包含操作作为方法的单独类,名称与语法操作相同:

class StatementFormatActions {
    method verb($/) { ... }
    method noun($/) { ... }
    method adverb($/) { ... }

}

当您调用parse时,需要传递该操作类的一个实例:

StatementFormat.parse($string, :actions(StatementFormatActions.new));

然后当你介绍alias标记时,你也可以介绍一个alias方法:

method alias($/) {
    self.verb($/);
    self.noun($/);
    self.adverb($/);
}

在这些操作中,您还可以调用 make$/.make(...) 方法将您的操作结果附加到匹配对象(然后在 $/.made 中可用),从而从解析树中填充AST。

(您可能还喜欢 我关于语法的书,其中包含若干示例和更深入的解释。抱歉打广告,无法抵制诱惑)。


谢谢,它有效。此外,我想知道在解析期间是否可以修改字符串。如果我可以用“%v %n %a”替换“%b”,那么实现别名就很容易了。但似乎Raku不支持这个功能。你认为这有用吗? - lovetomato
@lovetomato 在Raku中,字符串是不可变的,因此在解析时无法修改它。 - moritz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接