如何实现字符串数组?

发布于 2024-12-23 10:38:46 字数 1089 浏览 4 评论 0原文

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

我的第一个天真的尝试是:

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

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

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

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

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

I tried to implement a word that produces a string from an array when given a number on the stack in Forth.

My first naive attempt was:

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

This was accepted, but it did not work as expected — myarray @ type produces inconsistent output (instead of my naive expectation that it might print "Alpha").

When searching the web, I found in Gforth documentation that a string created with s" has a limited lifetime which means that my ansatz is bound to fail from the beginning. On the other hand, even arrays of regular objects seem to be not standardized according to Arrays in Forth section in Len's Forth Tutorial.

<Update> Apparently, this is not a trivial problem with Forth. There are libraries on the web that implement missing string functionality: FFL (str module) and String Functions by Bernd Paysan. This is a good starting point, although it still requires work to go from there to an array of strings. </Update>

So how can I implement a word that returns a string from a given array?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

痴骨ら 2024-12-30 10:38:46

为了寻址部分代码,s" 在堆栈上留下 addr u、地址和字符串长度。, 仅存储一个值,因此您不会以这种方式获得所需的结果,因为这会存储表示该字符串的两个堆栈项。完成后,您需要获取这两个值。 的。

也回来了,所以 2@ 就是你想要 看起来像这样:

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

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

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

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**

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

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


我对持久字符串进行了另一次尝试,这个字符串肯定在字典条目中分配内存,并且只要该单词存在,它就是安全的。之前,字符串“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+ @ ;

To address parts of your code, s" leaves addr u on the stack, an address and the length of the string. , only stores one value so you won't get the desired results that way. 2, might do it as that would store both of the stack items that represent the string. Once you have done that you need to get both values back too so 2@ is what you want.

My rewrite would look like this:

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

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

Getting at the other elements of your array is a bit trickier. When you type myarray you get the address of the start of the data in that dictionary entry, and you can then use 2@ to get the the things that the first two addresses point to (which are the address and length of "Alpha"). If you want "Beta you need the next pair of addresses. So you can use

myarray 2 cells + \ increment the address by two cells

To get the addresses that point to "Beta" and so on. So in order to access "Beta" you would enter

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

I have tested this with gforth and it seems to all work, although I am not sure how to rigorously test for persistence.

Your word would need to be able to do the address incrementing based on what is on the stack to start with. You might want to get into some more create does> stuff. I can give some pointers but I don't want to spoil the fun of discovery.

If I am skipping too many details of what this actually means just say, and I will try again.


Maybe this is too crude, but I had a go at making a "string type" of sorts a while ago.

: 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**

It defines a word with a name of your choosing (in this case "words") that will push length and start address of your string (in this case "some words") when it is interpreted. As far as I know when the string is in a definition like this it is persistent.

This doesn't answer you question fully, but it might help.


I have had another go at a persistent string, this one definitely allots memory within a dictionary entry and will be safe as long as that word exists. Before the string "type" only stored the address and length that s" created which is only any good until something else writes over that region of memory. This now copies the string from where s" creates it into a dictionary item called "name" where it is guaranteed to last as long as "name" itself.

: 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

For amusement, I thought I might show how little sense this makes without helpful formatting

: 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+ @ ;
梦初启 2024-12-30 10:38:46

首先。您必须为字符串分配永久存储。在 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 )

您可能想要添加辅助词。
这是丑陋的、麻烦的,也是最重要的标准方法。

Firstly. You must ALLOT permanent storage to the strings. In ciforth (my Forth) there is the word $, that does this in the dictionary space.

S" aap" $,

leaves an address with one cell count, followed by characters.
There is no standard word that does similar, you have to write it yourself. This is assuming ALLOCATE is not available.
Using this the following code saves string pointers temporarily to the stack:

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

Then you must store there pointers in an array, hence the sentinel 0, at the expense of an extra auxiliary word:

: ttt  BEGIN DUP WHILE , REPEAT DROP ;

And then

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

Now you can address strings as follows:

tt-end 2 CELLS -  ( @+ TYPE )

You may want add auxiliary words.
This is ugly, cumbersome and far and foremost standard way to do it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文