7

当在 Forth 的堆栈上给定一个数字时,我尝试实现一个从数组中生成字符串的单词。

我第一次天真的尝试是:

create myarray s" Alpha" , s" Beta" , s" Charlie" ,

这被接受了,但它没有按预期工作——myarray @ type产生不一致的输出(而不是我天真的期望它可能会打印“Alpha”)。

在网上搜索时,我在Gforth 文档中发现使用创建的字符串s"的生命周期有限,这意味着我的 ansatz 从一开始就注定会失败。另一方面,根据Len 的 Forth 教程中的Forth 部分的数组,即使是常规对象的数组似乎也没有标准化。

<Update>显然,这对 Forth 来说不是一个小问题。网络上有一些库实现了缺少的字符串功能:FFLstr 模块)和Bernd Paysan 的字符串函数。这是一个很好的起点,尽管从那里到字符串数组仍然需要工作。</更新>

那么如何实现一个从给定数组返回字符串的单词呢?

4

2 回答 2

2

要寻址部分代码,请在堆栈上s"留下addr u地址和字符串的长度。,仅存储一个值,因此您不会以这种方式获得所需的结果。2,可能会这样做,因为这将存储代表字符串的两个堆栈项。完成此操作后,您也需要恢复这两个值,这2@就是您想要的。

我的重写看起来像这样:

create myarray s" Alpha" 2, s" Beta" 2, s" Charlie" 2,

\ Test
myarray 2@ type Alpha **ok**

获取数组的其他元素有点棘手。当您键入时,myarray您将获得该字典条目中数据的开始地址,然后您可以使用 2@ 获得前两个地址指向的内容(即“Alpha”的地址和长度)。如果你想要“测试版,你需要下一对地址。所以你可以使用

myarray 2 cells + \ increment the address by two cells

获取指向“Beta”的地址等等。因此,为了访问“Beta”,您将输入

myarray 2 cells + 2@ type Beta **ok**

我已经用 gforth 对此进行了测试,似乎一切正常,尽管我不确定如何严格测试持久性。

你的话需要能够根据堆栈上的内容来增加地址。你可能想进入更多的create does>东西。我可以给出一些指示,但我不想破坏发现的乐趣。

如果我跳过了太多关于这实际上意味着什么的细节,那就说吧,我会再试一次。


也许这太粗略了,但我不久前尝试过制作某种“字符串类型”。

: string                                    ( addr u "name" -- )
    create 2,                               \ add address and length to dict entry "name"
    does> dup cell+ @ swap @ ;              \ push addr u

\ Example
s" Some Words" string words **ok**
words type Some Words **ok**

它定义了一个具有您选择的名称的单词(在本例中为“words”),当它被解释时,它将推动字符串的长度和起始地址(在本例中为“some words”)。据我所知,当字符串在这样的定义中时,它是持久的。

这并不能完全回答您的问题,但可能会有所帮助。


我对持久字符串进行了另一次尝试,这绝对allot是字典条目中的记忆,只要该单词存在,它就会是安全的。在字符串“type”之前只存储s"创建的地址和长度,这只有在其他东西写入该内存区域之前才有用。这现在将字符串从s"创建它的位置复制到一个名为“name”的字典项中,保证它的持续时间与“name”本身一样长。

: string                                    ( addr u "name" -- )
    create                                  \ create dict entry called "name"
    dup >r here >r                          \ keep copies of string length and start of "name"'s memory
    dup 2 cells + allot                     \ allot memory for the number of chars/bytes of the string plus 2
                                            \ for the new addr u
    r@ 2 cells +                            \ Get the address two cells from the start the space for "name"
    swap cmove                              \ copy the string at addr u into the alloted space for "name"

    \ Now "name" looks like this: "name" -blank1- -blank2- "the text of the string at addr u"
    \ blank1 should be the address of the start of the the text = addr2 and blank2 should be u

    r@ dup 2 cells + swap !                 \ get the address of blank1, copy it, increment by 2 to get addr2
                                            \ and then store that in blank1
    r> cell+ r> swap !                      \ get address of blank1, increment to get address of blank2, then get u and
                                            \ store it in blank2

    \ Now "name" looks like this: "name" addr2 u "the text of the string at addr u"

    does> dup @ swap cell+ @ ;              \ push addr2 u

为了娱乐,我想如果没有有用的格式,我可能会展示这有多么没有意义

: string-no-comments         ( addr u "name" -- )
    create dup >r here >r dup 2 cells + allot r@
    2 cells + swap cmove r@ dup 2 cells + swap !
    r> cell+ r> swap ! does> dup @ swap cell+ @ ;
于 2012-01-05T19:01:09.643 回答
0

首先。您必须为字符串分配永久存储空间。在 ciforth(我的 Forth)中有一个单词 $,它在字典空间中执行此操作。

S" aap" $,

留下一个单元格计数的地址,后跟字符。 没有类似的标准词,你必须自己写。这是假设 ALLOCATE 不可用。使用它,以下代码将字符串指针临时保存到堆栈中:

0 s" Alpha" $, s" Beta" $, s" Charlie" $,

然后你必须将指针存储在一个数组中,因此哨兵0,以额外的辅助词为代价:

: ttt  BEGIN DUP WHILE , REPEAT DROP ;

进而

( CREATE string-array) ttt
HERE CONSTANT ttt-end

现在您可以按如下方式寻址字符串:

tt-end 2 CELLS -  ( @+ TYPE )

您可能需要添加辅助词。这是丑陋,繁琐且最重要的标准方法。

于 2021-11-28T15:58:57.140 回答