Q-journal 100 种语言 第 20 集:Forth

Q神日志 2023-06-22 13:33:41

堆栈在编程中无处不在,在幕后。

每当你用几乎任何语言调用任何函数时,它的参数都会被压入堆栈,一些关于程序在完成函数后应该返回到哪里的信息也是如此。该函数从堆栈中弹出该数据,完成后,它会弹出下一步应该去哪里的信息。这种从堆栈中推入和弹出是计算机所做的相当大的一部分。但是,很少有语言以任何方式公开堆栈。

第四是当堆栈是语言的核心时会发生什么。

你好世界!

不幸的是,我们已经遇到了第一个问题。Forth 诞生于 1970 年代,当时人们不相信 Strings。Forth Stack 由小单元格组成,每个单元格都足够容纳一个数字或一个地址,而字符串放不下。因此,字符串需要大量的特殊情况处理,而不是适合 Forth 计算模型。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>#! /usr/local/bin/gforth

." Hello, World!"
cr
bye
</code></span></span>

 

这里发生了很多事情:

  • Forth 不喜欢 Unix #!shebang 行,有一个 hack 可以绕过它,这涉及在后面添加一个空格#!以使 Unix 和 Forth 都满意。
  • cr命令打印新行
  • bye命令退出——你需要这样做,否则 Forth 将进入 repl;这是一个不寻常的默认值。
  • ."意思是“直到下一个引号并打印那里的任何东西”。这个字符串实际上不像通常的编程语言那样是一个对象。之后有额外的空格.",这是语法的一部分。

您当然可以将所有内容放在同一行,换行符在 Forth 中没有任何意义。

加倍数量

让我们朝着构建真正的功能迈出一小步。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>#! /usr/local/bin/gforth

( Function to double a number )

: double
  dup +
;

21 double .
cr bye
</code></span></span>

 

这里发生了一些事情:

  • ( ... )是一个评论 - 再一次,你需要那个空间(
  • : name ... ;定义一个函数 - 函数不接受参数或返回值,它们只是对堆栈做一些事情
  • double函数做了两件事:dup复制栈顶,并将+栈顶的两个数字相加

因此,让我们逐步跟踪发生了什么:

  • 21- 压栈21(栈现在21
  • double- 调用double函数
  • inside double-dup复制栈顶(栈现在21 21
  • 里面double-+添加前两个数字(堆栈现在42
  • double返回(堆栈仍然42
  • .打印栈顶的值(栈现在是空的)
  • cr打印新行(堆栈仍然是空的)
  • bye出口

这可能看起来真的很复杂,但像这样的步骤是在许多编程语言的幕后发生的。

斐波那契数列

让我们做一些更复杂的事情,斐波那契函数。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>#! /usr/local/bin/gforth

: fib recursive
  dup 2 <= if
    drop
    1
  else
    dup 1 - fib
    swap
    2 - fib
    +
  endif
;

20 fib . cr
bye
</code></span></span>

 

那是很多!可能是我们迄今为止最复杂的斐波那契函数。

您可能已经了解它的20 fib . cr bye作用 - 它使用fib参数调用20,然后打印结果,打印新行,然后退出。

让我们看看fib功能是做什么的。它有一个很大的if ... else ... endif,所以让我们看看检查这两种情况。fib只会在堆栈的顶部操作,我会指出...它下面可能有更多的东西,但fib不会触及任何东西。

如果栈顶为 1:

  • fib开始,堆栈是 ( ... 1)
  • dup复制最高值 ( ... 1 1)
  • 2推动2... 1 1 2)
  • <=比较堆栈上的前两个值并推送0false,或者令人惊讶的-1是 true ( ... 1 -1)
  • if去第一个分支 ( ... 1)
  • drop丢弃堆栈的顶部值 ( ...)
  • 1推动1... 1)
  • 函数返回,1将被视为返回值

如果栈顶是 20:

  • fib开始,堆栈是 ( ... 20)
  • dup复制最高值 ( ... 20 20)
  • 2推动2... 20 20 2)
  • <=比较堆栈上的前两个值并推送0false,或者令人惊讶的-1是 true ( ... 20 0)
  • if去第二个分支(... 20
  • dup复制最高值 ( ... 20 20)
  • 1推动1... 20 20 1)
  • -减去前两个值 ( ... 20 19)
  • fib19... 20 4181)的参数调用自己
  • swap交换栈顶的两个值 ( ... 4181 20)
  • 2推动2... 4181 20 2)
  • -减去前两个值 ( ... 4181 18)
  • fib18... 4181 2584)的参数调用自己
  • +添加前两个值 ( ... 6765)
  • 函数返回,6765将被视为返回值

环形

在前往不可避免的 FizzBu​​zz 的路上,让我们首先做一个简单的循环打印数字 1 到 11:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>#! /usr/local/bin/gforth

: ten-numbers
  11 1 do i . cr loop
;

ten-numbers
bye
</code></span></span>

 

do ... loop是循环。堆栈上的前两个数字是 limit 和 start。Limit 是循环停止的地方,所以它需要比最后一个索引高 1——有点像 Python 的range(1,11).

i将当前循环索引压入堆栈。然后我们打印它.并添加一个换行符cr

Forth 只支持函数内部的 this,因此我们必须将它包装在ten-numbers函数中。如果您尝试将其直接放入源代码或代表中,您会得到一个神秘的“解释仅编译词”。同样的故事if等等。

嘶嘶声

最后是 FizzBu​​zz!

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>#! /usr/local/bin/gforth

: divisible
  mod 0=
;

: fizz-buzz
  dup 15 divisible if
    drop
    ." FizzBuzz"
  else
    dup 5 divisible if
      drop
      ." Buzz"
    else
      dup 3 divisible if
        drop
        ." Fizz"
      else
        .
      endif
    endif
  endif
;

: fizz-buzz-loop
  101 1 do i fizz-buzz cr loop
;

fizz-buzz-loop
bye
</code></span></span>

 

  • 主程序只是调用fizz-buzz-loop
  • fizz-buzz-loop是一个从 1 到 100 的循环,fizz-buzz以索引作为参数调用
  • divisible返回 true (-1) 或 false (0) 取决于堆栈中的第二个数字是否可以被顶部的数字整除
  • fizz-buzz是一个三层嵌套if/else/endif——我不认为 Forth 有任何更简洁的方法来做到这一点
  • dup 15 divisible if如果堆栈顶部可以被 15 整除,则采用第一个分支,在其他地方进行第二个分支(对于 5 和 3 以此类推)
  • drop ." FizzBuzz"落在堆栈顶部并"FizzBuzz"改为打印
  • .取栈顶并打印

你应该使用 Forth 吗?

Forth 可能是“深奥语言”的有趣切入点。Forth 本身是一种真正严肃的语言,有一段时间在某些利基市场中获得了一定程度的普及,主要是在尺寸非常昂贵的情况下,如微控制器。使用像 Forth 这样的基于堆栈的语言进行一些编码练习可以让你为各种疯狂的深奥语言做好准备,比如 Befunge、Brainfuck 等等,因为基于堆栈的编程在那里很流行。

如果您想深入研究基于堆栈的虚拟机,如 JVM(和大多数虚拟机)或计算机体系结构(几乎所有虚拟机),稍微玩一下 Forth 也可能会很有趣。甚至大多数其他基于堆栈的系统都比 Forth 更少基于堆栈,但它可能是有用的实践。

对于严肃的编程,绝对不是。

...全文
43 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复
章节详细,涵盖大学文献检索课件资料 第一章 信息检索的基本知识 第一节 信息、知识、文献、情报 信息: 应用文字、数据和信号形式通过一定的传递和处理,来表现各相互联系的客观事物在运动变化中所具有特征性的内容的总称。 知识: 人们通过实践对客观事物极其运动过成和规律的认识。是人脑对客观事物传来的信息进行加工的过程。 文献: 是记录有知识的一切载体。也是将人类的知识用文字、符号、图形、声频、视频、信号等记录方式在甲骨、竹棉 纸张、感光材料、磁性材料等载体上记录下来而形成的。 情报:当文献中记录的知识一旦传递 到用户并为其所利用时,文献中被利用到的这部分知识就转化为情报。 关系:信息(知识(情报,文献)) 第二节 信息检索的目的和作用 1.通过科技文献检索能够打开人类知识宝库的钥匙。 2.通过科技文献检索能使科技工作者及时把握科技发展的动态和趋势。 3.通过科技文献检索能有助于开拓知识面,改善知识结构。 4.通过科技文献检索可避免科研重复,加快科研工作的进程. 5.通过科技文献检索能加强科技交流,促进技术合作。 第三节 科技文献的特点及类型 1.什么是科技文献? 含有知识内容的信息载体。 2.构成文献的三要素:知识内容、物质载体、记录手段。 3.文献的基本功能:存储知识信息、传播知识信息。 4. 科技文献的特点: 形式多、文多。数量多、增长快。交叉重复。失效快、寿命短。 5.科技文献的类型: 1:按文献的载体形式划分:印刷型、缩微型、声像型、电子型。 2:按文献的出版形式划分:科技图书、 科技期刊、 科技报告、会议文献、 专利文献、 学位论文、标准文献、 政府出版物、 产品样本、技术档案。 3:按文献被加工处理的深度划分:零次文献、一次文献、二次文献、三次文献。 第四节 信息检索及类型 信息检索:是指将文献信息按一定的方式组织、存储起来,并针对用户的需要查找出所需信息的过程。 信息检索的类型: 1.文献检索 2.数据检索 3.事项检索 一、什么是检索工具?用以存储、报道和查找文献信息的工具。 二、检索工具的特征:1.有丰富的文献记录。2.每条记录都必须具有各检索标识。 3.全部描述记录科学地组织成一个有机的整体。4.能够提供多检索途径。 三、信息检索工具的职能: 1.报道职能。 2.存储职能。3.检索职能。 四、检索工具的类型: 1.按检索方法划分:手工、机械 2.按收录的文献范围划分:综合性、 专业性、 单一性 3.按出版形式划分: 期刊式检索工具,单卷式检索工具,附录式检索工具,卡片式检索工具, 缩微制品、磁带、磁盘。 4.按收录文献对象和揭示文献方式划分:目录、题录、文摘(指示性、报道性)、 索引 五、检索工具的结构: 目次表、使用说明、正文部分、索引、附录部分。 第二节 信息检索语言 信息检索语言是用来描述文献特征和表达信息提问,沟通信息存储人员和信息检索者双方思想的一人工语言。 信息检索语言的分类:按描述文献特征划分; • 描述文献外部特征的检索语言:书名、刊名、篇名等著者名。号码(如报告号、专利号、序号等)文献类型,文献出版事项 • 描述文献内容特征的检索语言: 分类语言 主题语言(关键词语言、标题词语言、叙词语言) 第三节 信息检索原理及步骤 一、信息检索原理: 文献信息检索实际上包括文献的存储和文献的检索两个相互依存的过程。 二、信息检索的步骤: 1.分析研究课题: 2.选择检索工具: 3.确定检索途径:分类途径、主题途径、题名途径、著作途径、号码途径、其他途径。 4. 选择检索方法:常用法(顺查法、倒查法、抽查法)追溯法 综合法(或循环法) 5.查找文献线索:6.索取原始文献。 第三章 专利文献及其检索 第一节 专利的基本知识  什么是专利? 所谓专利是指一项技术性的创造发明在一定的年限和国家范围内受法律保护的技术专有权利。  专利的类型(发明专利、实用新型专利、外观设计专利)  取得专利的条件(新颖性、实用性、创造性)  专利的审批程序 我国专利的审批程序:(发明专利的审批程序)专利申请, 初步审查(形式审查),公布专利申请(早期公开),实质审查,审定并公告 , 公众异议 , 授予专利权,专利权无效请求 ,专利权终止 (实用新型专利和外观设计专利的审批程序)专利申请,初步审查(形式审查),审定并公告,公众异议,授予专利权 第二节 专利文献  专利文献的特点:1,新颖及时 2,技术可靠、详尽 3,内容广泛 4,格式统一 5,从复出版量大  中国专利文献的符号系统: 89年前 89年

6

社区成员

发帖
与我相关
我的任务
社区描述
分享
java-rocketmqpygame前端 个人社区 广东省·广州市
社区管理员
  • Q shen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧