gpt4 book ai didi

从语法中提取标记

转载 作者:行者123 更新时间:2023-12-04 06:52:46 25 4
gpt4 key购买 nike

今年我一直在解决 Perl6 中出现的代码问题,并试图使用语法来解析第 3 天的输入。

给定这种形式的输入:#1 @ 1,3: 4x4我创建的这个语法:

grammar Claim {
token TOP {
'#' <id> \s* '@' \s* <coordinates> ':' \s* <dimensions>
}

token digits {
<digit>+
}

token id {
<digits>
}

token coordinates {
<digits> ',' <digits>
}

token dimensions {
<digits> 'x' <digits>
}
}

say Claim.parse('#1 @ 1,3: 4x4');

我有兴趣从结果解析中提取匹配的实际标记,即坐标中的 id、x + y 和尺寸中的高度 + 宽度。我知道我可以从结果中提取它们 Match Claim.parse(<input>) 的对象,但我必须深入挖掘每个语法产生式以获得我需要的值,例如
say $match<id>.hash<digits>.<digit>;

这看起来有点乱,有没有更好的方法?

最佳答案

对于 the particular challenge you're solving ,使用语法就像使用大锤敲碎坚果。

就像@Scimon 说的,一个正则表达式就可以了。你可以通过适当的布局来保持它的可读性。您可以命名捕获并将它们全部保留在顶层:

/ ^
'#' $<id>=(\d+) ' '
'@ ' $<x>=(\d+) ',' $<y>=(\d+)
': ' $<w>=(\d+) x $<d>=(\d+)
$
/;

say ~$<id x y w d>; # 1 1 3 4 4

(前缀 ~ 在其右侧的值上调用 .Str。在 Match 对象上调用,它将字符串化为匹配的字符串。)

这样一来,您的问题仍然非常复杂,因为了解 P6 在这方面如何从简单的正则表达式(如上述)扩展到最大和最复杂的解析任务非常重要。这就是这个答案的其余部分所涵盖的内容,以您的示例为起点。

挖得不那么乱
say $match<id>.hash<digits>.<digit>; # [「1」]

this seems a little messy, is there a better way?



您的 say包括不必要的代码和输出嵌套。您可以简化为:
say ~$match<id> # 1

挖得更深,不那么乱

I am interested in extracting the actual tokens that were matched i.e. id, x + y from coordinates, and height + width from the dimensions from the resulting parse.



对于多个标记的匹配,您不再需要依赖 Perl 6 来猜测您的意思。 (当只有一个时,猜猜它猜你指的是哪一个。:))

一种方式来写你的 say获取 y协调:
say ~$match<coordinates><digits>[1] # 3

如果您想删除 <digits>您可以标记模式的哪些部分应存储在编号捕获列表中。一种方法是在这些部分周围加上括号:
token coordinates { (<digits>) ',' (<digits>) }

现在您无需提及 <digits> :
say ~$match<coordinates>[1] # 3

您还可以命名新的括号捕获:
token coordinates { $<x>=(<digits>) ',' $<y>=(<digits>) }

say ~$match<coordinates><y> # 3

预挖

I have to dig down through each grammar production to get the value I need



上述技术仍然深入到自动生成的解析树中,默认情况下,该解析树与语法规则调用层次结构中隐含的树精确对应。上述技术只是让你挖掘它的方式看起来有点浅。

另一个步骤是将挖掘工作作为解析过程的一部分进行,以便 say很简单。

您可以将一些代码直接内联到 TOP 中。 token 仅存储您制作的有趣数据。只需插入一个 {...}在适当的位置阻止(对于这种事情,这意味着 token 的结尾,因为您需要 token 模式已经完成其匹配工作):
my $made;
grammar Claim {
token TOP {
'#' <id> \s* '@' \s* <coordinates> ':' \s* <dimensions>
{ $made = ~($<id>, $<coordinatess><x y>, $<dimensions><digits>[0,1]) }
}
...

现在你可以只写:
say $made # 1 1 3 4 4

这说明您可以在任何规则的任何点编写任意代码——这是大多数解析形式及其相关工具无法实现的——并且代码可以访问此时的解析状态。

预挖不那么乱

内联代码又快又脏。使用变量也是如此。

存储数据的正常做法是改用 make 功能。这将根据给定规则构建的匹配对象挂起数据。然后可以使用 .made 检索它。方法。所以,而不是 $make =你会有:
{ make ~($<id>, $<coordinatess><x y>, $<dimensions><digits>[0,1]) }

现在你可以写:
say $match.made # 1 1 3 4 4

这样整洁多了。但还有更多。

解析树的稀疏子树

.oO(🎶 在想象中的 2019 年的第一天 Perl 6 Christmas Advent calendar 🎶 一个 StackOverflow 标题对我说...)

在上面的例子中,我构造了一个 .madeTOP 的有效载荷节点。对于较大的语法,通常形成 sparse subtree (我为此创造了一个术语,因为我找不到标准的现有术语)。

这个稀疏子树由 .made 组成 TOP 的有效载荷这是一个引用 .made 的数据结构低级规则的有效载荷反过来又引用了低级规则等,跳过了无趣的中间规则。

对此的规范用例是形成 Abstract Syntax Tree在解析了一些编程代码之后。

事实上, .made 有一个别名。 ,即 .ast :
say $match.ast # 1 1 3 4 4

虽然这使用起来很简单,但它也是完全通用的。 P6 使用 P6 语法来解析 P6 代码——然后使用这种机制构建一个 AST。

让一切变得优雅

为了可维护性和可重用性,您可以并且通常不应在规则末尾插入内联代码,而应使用 Action objects .

总之

有一系列通用机制可以从简单场景扩展到复杂场景,并且可以组合以最适合任何给定用例。

添加括号,就像我上面解释的那样,命名那些括号为零的捕获,如果这是深入分析树的一个很好的简化。

内联您希望在解析规则期间采取的任何操作。此时您可以完全访问解析状态。这对于从解析中轻松提取所需数据非常有用,因为您可以使用 make便利功能。并且您可以从语法中提取在成功匹配规则结束时要采取的所有操作,确保这是一个干净的代码解决方案,并且单个语法仍然可重复用于多个操作。

最后一件事。您可能希望修剪分析树以省略不必要的叶子细节(以减少内存消耗和/或简化分析树显示)。为此,请写信 <.foo> ,在规则名称前面带有一个点,以关闭该规则的默认自动捕获。

关于从语法中提取标记,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53711344/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com