Rebol/Red中关于自修改解析规则的规则是什么?

What are the rules about self-modifying parse rules in Rebol/Red?

我正在查看自修改规则并想知道语义到底是什么以及它们将如何工作。这是一个相当宽泛的问题,但我会使用一个特定的 "how would I do this" 来将它变成一个更有针对性的问题。 (^(64) 是小写 "d" 的十六进制 ascii,因此找不到)

rule: ["a" "b" (insert find rule "^(64)" "c" probe rule) "d" "e"]
parse "abcde" rule

如果我 运行 那,我得到(在 Rebol 和 Red 中):

["a" "b" (insert find rule "d" "c" probe rule) "c" "d" "e"]
== false

规则好像更新了,更新的还算"safe-seeming way"(如果有安全的话)。还有更多邪恶版本:

rule: ["a" "b" (clear rule probe rule) "d" "e"]
parse "abcde" rule

在 Rebol 和 Red 中得到:

[]
== false

我有点困惑它怎么不崩溃。但是假设它以某种方式得到了防弹,有没有办法让第一个例子起作用?

这可能有效:

>> rule: ["a" "b" m: (insert find rule "^(64)" "c" probe rule) skip "d" "e"]

>> rule: ["a" "b" m: (insert find rule "^(64)" "c" probe rule m: next m) :m "d" "e"]
>> parse "abcde" rule
["a" "b" m: (insert find rule "d" "c" probe rule m: next m) :m "c" "d" "e"]
== true

这个有效

>> rule: ["a" "b"  (insert first find rule block! "c" probe rule ) [] "d" "e"]
== ["a" "b" (insert first find rule block! "c" probe rule) [] "d" "e"]
>> parse "abcde" rule
["a" "b" (insert first find rule block! "c" probe rule) ["c"] "d" "e"]
== true

因为第一层规则元素的数量和规则光标的位置没有改变。第二层似乎在入口处加载。

这个也行

>> rule: ["a" "b"   (insert first find rule "d" "c" probe rule )  "d" "e"]
== ["a" "b" (insert first find rule "d" "c" probe rule) "d" "e"]
>> parse "abcde" rule
["a" "b" (insert first find rule "d" "c" probe rule) "cd" "e"]
== true

在自修改规则的一般形式中,您使用变体较低级别的规则,您可以更改或替换

sub_rule: []
rule: ["a" "b" (sub_rule: "c" probe rule) sub_rule "d" "e"]

parse "abcde" rule
["a" "b" (sub_rule: "c" probe rule) sub_rule "d" "e"]
 == true

But assuming it's been bulletproofed somehow...

在 R3-Alpha 中没有,如果您不走运(例如导致系列扩展),您可能会因此而崩溃。参见 #2214: "Modifying running PARSE rule leads to execution beyond rule TAIL, possible crash"

因此您应该修改 PARSE 当前正在处理的规则。但是,如果该规则当时不是 运行,您可以修改规则中的嵌套规则:

 subrule: ["c"]
 rule: ["a" (insert subrule "b") subrule]
 parse "abc" rule

这在 Ren-C build 中通过在解析器遍历规则时锁定规则以防止修改而形式化。解析器的另一种方法是测试规则中每次提取的长度,如果超过长度则中止。虽然这可以防止崩溃,但这会导致复杂和狡猾的行为——并通过支付支票来降低性能。

(出于类似的原因,在 Ren-C 中,您也不能修改当前正在使用 DO 执行的块。但是通过修改不是 运行 的嵌套括号组,您可以完成与上面的 PARSE 相同的解决方法。)

rule: ["a" "b" (clear rule probe rule) "d" "e"]
parse "abcde" rule

I'm sort of confused how it doesn't crash.

在 Rebol 的 R3-Alpha 中,这种特殊情况不会崩溃或抱怨,因为它不会回收系列中的内存 除非它扩展并需要新的分配。它只是在系列的头部位置写入一个终止符(覆盖 "a")并调整缓存长度。 PARSE 忽略长度,只查找 END 标记。所以它继续前进,直到找到陈旧的旧结束标记。

要看到这一点,您也可以尝试:

>> rule: ["a" "b" (clear rule) "c" "d" "e"]
== ["a" "b" (clear rule) "c" "d" "e"]

>> parse "abcde" rule
== true

您基本上是在使用垃圾内存中的值。