3

我正在研究自我修改规则,并想知道语义到底是什么以及它们将如何工作。这是一个相当广泛的问题,但我将使用一个特定的“我将如何做到这一点”将其变成一个更集中的问题。 (^(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

该规则似乎已经更新,并且以相当“看似安全的方式”进行了更新(如果有任何安全之类的东西)。还有更多邪恶的版本:

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

在 Rebol 和 Red 中,得到:

[]
== false

我有点困惑它是如何不崩溃的。但是假设它以某种方式被防弹,有没有办法让第一个例子工作?

4

3 回答 3

2

这有效

>> 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
于 2015-04-03T08:16:18.673 回答
1

这可能有效:

>> 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
于 2015-04-02T15:43:45.953 回答
0

但假设它以某种方式被防弹......

在 R3-Alpha 中它没有,如果你不走运(例如通过导致系列展开),你可能会因为这样做而崩溃。请参阅#2214:“修改运行中的 PARSE 规则会导致执行超出规则 TAIL,可能会崩溃”

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

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

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

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

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

我有点困惑它是如何不崩溃的。

在 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

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

于 2016-10-03T18:01:55.470 回答