我如何在 Forth 中创建一个数组?

How do I create an array in Forth?

我知道,过去经常有人问这个问题,也许以前的 Stack Overflow 帖子中提供了相关信息。但是学习 Forth 是一项非常复杂的任务,重复有助于理解串联编程语言相对于 C 等替代语言的优势。

我从 Forth 教程中学到的是,Forth 没有提供创建二维数组的命令,但用户必须在程序中从头开始实现所有内容。我在 Forth 中发现了两个占用内存的选项。首先创建一个新词:

: namelist s” hello” s” world” ;

或者其次通过 CREATE 语句:

create temperature 10 allot
temperature 10 cells dump

到目前为止一切顺利;我们创建了一个包含 10 个单元格的数组,其中可以存储整数变量。但是,如果我需要保存浮点数呢?我必须始终将 float 转换为 int 还是可以将它们保存到普通单元格中?

另一个悬而未决的问题是如何在数组中存储字符串值。据我所知,一个字符串包含一个指针加上一个大小。所以理论上我只能在 10 个单元格数组中存储 5 个字符串,另外我需要在其他地方保存字符串本身的内存。这没有多大意义。

是否有某种更高的抽象可用于将值存储在数组中,从而可以用来编写易于阅读的程序?我的意思是,如果每个程序员都使用自己的 Forth 方法在内存中存储一​​些东西,其他程序员会发现很难阅读代码。

create 创建一个单词 returns 字典中缓冲区的地址(数据 space);它最初是零长度,所以你必须立即为它保留所需的 space。

allot预留了space,它是以地址为单位(通常是字节)来计算的,所以你必须以字节为单位来计算需要的大小。

例如:

create a 10 cells allot
create b 10 floats allot
它只是缓冲区,您仍然需要处理指针算法来获取或设置项目,例如:
0.35e  2 floats b +  f! \ store the float number into third item (0-based indexing)

在字典中创建浮点数数组的单词示例:

: create-floats-array ( length "name" -- ) create floats allot does> swap 1- floats + ;

10 create-floats-array c

0.35e  3 c f! \ store the float number into third item (1-based indexing)
3 c f@ f. \ print float number form third item

如果您需要很多数组和字符串,最好使用适当的库。 例如,参见 Cell array module and Dynamic text string module from Forth Foundation Library

您对字符串感到困惑。该字符串直接进入内存,该地址的内存分配给该字符串,并且它永远存在(除非您更改它)。

所以如果你想在分配的内存块中存储 5 ( c-addr u) 个字符串(称它为数组有点牵强),你可以将 c-addr 存储在单元格中 n 和单元格中的长度 u n+1.

如果您担心 10 个单元格太多 space(这真的没什么好担心的)并且只想使用 5 个单元格,您可以将字符串存储为计数字符串,使用类似C" - 计数的字符串在第一个字节中存储长度,随后的每个字节都是一个字符。

此外,您可以使用单词 ,(逗号)将当前 dp 的内容存储到字典中。

一个广义的 2darray 元素。以元素大小为参数

\ size is the per element multiplier
\ n size * is the per_row factor
\ m n size * * is the total space required

: 2darray  \ create>  m n size -- ; does> mix nix -- a
\  size is the number of bytes for one element
\  
  create  2dup * ,      \ multiplier to apply to m index 
          dup ,         \ multiplier to apply to n index
          * * allot     \ calculate total bytes and allot them
  does>  \ mix nix -- a 
    >r r@ cell+ @ *     \ offset from n index  
       swap r@ @ * +    \ offset with m index
   r> + 2 cells+        \ 2 cells offset for the 'admin' cells
;

例子

50 40 /float 2darray 50x40floats
50 40 2 cells 2darray 50x40stringpairs

甚至

20 constant /record
10 200 /record 2darray 2000records