用C++实现的SmallTalk-80

2020-05-25 23:15:42

欢迎使用在OS X、Windows和Linux上运行的Smalltalk-80系统的蓝皮书C++实现的My";by the Bluebook";C++。自从第一次在1981年8月的Byte杂志上读到关于Smalltalk的内容以来,我一直对它很感兴趣。那时,我们所有的都是运行速度很慢的8位计算机,4K内存的运行速度还不够快,不足以做任何有用的事情。当我通读这篇文章时,我惊呆了--这是一种未来主义的外星人技术,肯定超出了我的能力范围。1988年,在华盛顿大学就读期间,我接触到了两件令人难忘的技术:第一件是史蒂夫·乔布斯的NeXTcube,另一件是Tektronix(4400?)。运行Smalltalk-80的工作站。这两个都曾经是,现在仍然是令人惊叹的。我在NeXTcube的后代--MacBook Pro笔记本电脑上实现这个Smalltalk是再合适不过的了。

90年代末,我发现我在施乐帕洛帕克的英雄们重新组建了乐队,并释放了Squeak。我很高兴终于有了一个很好的系统来玩。但是,我并不在意外观和感觉,错过了我在Tektronix系统上体验到的极简主义。我还有一本蓝皮书和绿皮书,总是幻想着自己实现,但我无法访问使用的移植工具包。几年前,当我找到马里奥·沃尔奇科(Mario Wolczko)的网站http://www.wolczko.com/st80/时,情况发生了变化。他有施乐Release 2虚拟映像(从磁带上),还有操作手册和蓝皮书中的手写Smalltalk源!他也有他的实现,这是用ANSI C之前编写的,但是,尽管花了很多小时,我还是无法运行任何东西。然后我开始考虑自己实现。

我知道这不是一件容易的事,因为书中无疑会有错误。我也知道C++喜欢从零开始索引数组,而Smalltalk从1开始,所以肯定会有差分错误(有)。SmallTalk的运算符优先级与C/C++不同,因此我也对此保持警惕(值得称赞的是,除了少数例外,表达式中使用了括号,这不是问题)。然后是引用计数,所以可能也会有引用计数错误(有),最后内存是一堆16位字,所以您可能会意外地存储/获取错误的东西,而不会意识到这一点。最重要的是,Alto是大端系统,所以我必须决定如何处理(我按照Xerox指南的建议字节交换了虚拟映像--他们的指导很可靠,但他们忽略了字节交换浮点的需要)。

我从2019年12月下旬开始做这项工作,但几个月后才真正专注于这件事,直到科罗娜病毒来袭,我决定将自己隔离,以免将病毒传播给其他人。然后我认真地做了这件事。施乐移植工具包包括参考跟踪文件,您可以将其与您的系统进行比较。当我经过Trace2时,我感觉到一种难以置信的匆忙。在那之后,系统运行了一段时间,内存用完了。我不知道发生了什么(这是在我让展品正常工作之前)。为了获得可见性,我使用show:和error:选择器以及在堆栈上压入的看起来很大的字符串截取并记录了消息发送。果不其然,如果SmallTalk调试器能做到这一点,就会显示一个回溯字符串。但是,当屏幕被绘制成我可以转储到.pbm文件的形式时,我能够计算出我在哪里搞砸了,然后又感觉到了另一种快感,然后看看!之后,我使用SDL实现了对Smalltalk的主机图形支持,并实现了输入原语,这样我就有了一个可以正常工作的鼠标和键盘。我终于能够真正使用这个系统了。在这一点上,系统帮助我找到了其他问题!图形化的Smalltalk检查器和调试器真的帮我完成了繁重的任务,为我节省了无数个小时。该系统的弹性令人惊叹。

但是.。因为没有可用的文件系统支持(系统映像使用Alto文件系统类),所以我只能在源浏览器中看到反编译的代码(这仍然非常有用,您可以对其进行编辑--只是它没有显示您实际使用的临时名称,您的注释也会丢失)。嗯,我必须决定该怎么做。我是否应该尝试模仿Alto文件系统?我决定不这样做,并遵循Tektronix在绿皮书中使用的方法--我将FileDirectory、File和Page子类化,并创建了PosiFileDirectory、PosiFile和PosiPage。我启动了VSCode并为它们编写了一个实现,我可以将其复制并粘贴到我的Smalltalk中(我添加了一种将剪贴板中的字符粘贴到输入队列中的方法)。实现这些之后,我对它们进行了测试,满意之后,我使用Smalltalk-80和Smalltalk-80的文件流创建了SourceFiles数组。

按照书来构建东西的好处是,有书记录了如何使用系统以及它是如何工作的!

您需要安装SDL 2.0.12或更高版本。您可以从http://libsdl.org.下载。选择开发库.dmg并安装。然后,进入OSX文件夹并键入make。然后,您应该能够执行以下操作:

请参阅下面的命令行选项部分了解这意味着什么。如果您愿意,可以打开一个Xcode项目。

我已经包含了SDL 2.0.12头文件/二进制文件,所以您需要做的就是在WINDOWS目录中打开项目并点击Run。

您需要安装SDL 2.0.12或更高版本。您可以转到http://libsdl.org下载并自己构建它,也可以使用包管理器安装它。

然后,cd进入该项目的Linux子目录并键入make。然后,您应该能够执行以下操作:

Smalltalk应用程序的行为可以通过每个模块的头文件中的#Define设置进行自定义。

对象Memory#定义确定要使用的垃圾收集方案(蓝皮书中描述的所有方法都可用)。

这本书描述了一个简单但消耗堆栈空间的递归标记算法。如果定义了此符号,则使用该算法。如果不是,则使用更复杂、更智能的指针反转方法。

GC_MARK_SWEEP和GC_REF_COUNT标志不是互斥的。如果两者都已定义(并且它们都已定义),则将执行正常的引用计数,仅在内存耗尽或对象表已满时才执行完全垃圾回收。SmallTalk-80生成许多循环引用(例如,通过临时字段的MethodContext引用,通过发送者字段反向引用上下文的BlockContext)。Mark and Sweep Only方法将导致许多频繁的收集,因为在系统运行时,对象表将快速填充MethodContext和其他频繁分配的对象。因此,一些Smalltalk实现会回收上下文。

提供解释器#定义是为了允许包含/排除可选的原语以及一些有用的调试方法。如果未实现可选原语,则改为执行Smalltalk回退。这可能会对性能产生重大影响。

在Windows下运行时,我遇到了两个问题。首先,如果按住鼠标左键(例如,重新构建窗口时),鼠标光标不会可靠地改变。第二个问题是,鼠标光标在高分辨率显示器上非常小,即使设置了系统缩放选项来补偿也是如此。出于这些原因,我添加了让应用程序呈现鼠标光标而不是操作系统的选项。可以定义SOFTWARE_MOUSE_CURSOR来执行此操作。如果它是Windows版本,我会有条件地设置它。它可以在其他平台上工作,但没有必要,因为它们在没有它的情况下可以正常运行。

Smalltalk应用程序接受许多参数。唯一必需的参数是-directory path,它指定可以找到快照映像的目录。以下是完整的名单:

指定包含快照图像以及Smalltalk-80.source和Smalltalk-80.change文件的目录。目录中的任何其他文件都可以使用正常的文件/目录访问方法从Smalltalk-80访问。

打开垂直同步以使帧速率与监视器刷新率同步。这可以消除屏幕撕裂和其他伪像,但代价是一些输入延迟。

如果不使用vsync,则可以在向GPU呈现下一帧之后指定延迟。这对于降低CPU使用率,同时仍然享受不使用vsync的好处非常有用

指定显示应加倍。对有远见的人或在非常高分辨率的显示器上运行的人很有帮助