我正在使用 Gforth 的解释器指令(非 ANS 标准)控制结构,如手册第 5.13.4 节解释器指令中所述。我基本上想使用循环词来创建包含文字的动态大小的单词。例如,我想出了这个定义:
: foo
[ 10 ] [FOR]
1
[NEXT]
;
然而,这会在[FOR]
后产生地址对齐异常(是的,我知道您根本不应该在 Forth 中使用 for 循环。这只是一个简单的例子)。
最后,事实证明,您必须将循环编写为单行代码,以确保它们的正确执行。所以做
: foo [ 10 [FOR] ] 1 [ [NEXT] ] ;
而是按预期工作。运行see foo
产量:
: foo
1 1 1 1 1 1 1 1 1 1 1 ; ok
这正是我想要的。
有没有办法在单词定义中获得新行?我想写的单词要复杂得多,对于演示文稿,我需要将它们更好地格式化。
最好使用直接词代替。例如
: ones ( n -- ) 0 ?do 1 postpone literal loop ; immediate
: foo ( -- ten ones ) [ 10 ] ones ;
SEE FOO
的结果与您的示例相同。 使用POSTPONE
,特别是使用Gforth的]] .. [[
语法,重复的代码可以随心所欲地复杂。
多行[FOR]
需要做四件事:
使用
REFILL
在后续行中阅读。保存读入行,因为您需要逐个评估它们以保留预期行的分析行为(例如来自注释:
)。
停止行读,并在匹配终止
[NEXT]
时循环。注意在
[NEXT]
后立即离开>IN,以便口译可以正常进行。
您可能仍会遇到某些代码问题,例如代码检查SOURCE-ID
。
有关使用 REFILL 跨多行解析的示例,以下是 Gerry 最近从 CLF 发布的代码:
: line, ( u1 caddr2 u2 -- u3 )
tuck here swap chars dup allot move +
;
: <text> ( "text" -- caddr u )
here 0
begin
refill
while
bl word count s" </text>" compare
while
0 >in ! source line, bl c, 1+
repeat then
;
这将收集<text>
和</text>
之间的所有内容,就像 HERE 文档一样,同时还添加了空格。为了以简单的方式保存各个行以供[FOR]
,我建议将 0 作为数据堆栈上的哨兵,然后在它上面放置SAVE-MEM
行。