Habr公众对
我关于MS-DOS的自制XD Pascal编译器的
帖子的出乎意料的热烈欢迎使我产生了思考。 自从DOS虚拟机从Windows完全消失以来,我投入了大量精力的业余项目对我来说是沉重的负担,这是否令人烦恼? 反射的结果是
Windows的
XD Pascal编译器 。 也许他失去了一些怀旧的魅力,并失去了通过BIOS中断来处理图形幼稚的可能性。 但是,向Windows的过渡为该项目注入了新的活力,并为实现长期的梦想-自编译打开了道路。
和以前一样,我没有使用任何辅助工具来自动生成编译器。 这种固执的态度可能看起来很奇怪,但是该项目只有一个目标-我自己的荣幸,而其他工具只会成为障碍。 从这个意义上说,编译器是从头开始开发的。

在Windows上自编译的五个步骤
值得一提的是从DOS到Windows的主要任务:
可执行文件的头和节的形成。 除了对Portable Executable格式的正式描述之外,在这一阶段,
创建尽可能小的PE可执行文件的文章也成为了一个很好的帮助。 由于标头和节需要过程和变量的确切地址,并且只有在计算代码大小和全局数据后才能找到它们,因此编译必须分三步进行。 第一步,建立过程调用图,并标记“死”过程。 第二步,计算地址,代码和数据大小,并填写标题。 第三,生成代码。 这样的知识是无穷无尽的,特别是考虑到在每一遍,从词法分析开始,都要重新编译的所有阶段。 但是,它为编译器提供了非常简洁的源代码,并且不需要程序的任何中间表示。
附录:当前已实现可重定位代码的生成,编译是单遍完成。
新的代码生成器。 Windows编译要求用32位偏移量寄存器替换成对的段偏移量寄存器,并删除(并添加位置)前缀以更改操作数的长度(66h)和地址的长度(67h)。
声明Windows API外部函数的指令。 使用
external
指令声明的所有函数名称都输入到可执行文件的import部分的表中。 由于这些函数需要从右向左传递参数,因此我们必须手动反转所有此类函数的声明和调用中的参数顺序。 因此,不再需要通过编译器进行求逆。 为简单起见,XD Pascal中过程和函数的所有参数均以32位值形式传递; 幸运的是,该规则对Windows API函数也有效,因此与系统库的交互不会使传递参数的机制复杂化。
另外:现在将自动执行导入函数的参数顺序的反转。
从源代码中删除集合和中缀字符串操作。 该要求与自编译任务有关。 XD Pascal中任何表达式的计算都经过设计,以便所有中间结果均为32位长,并存储在堆栈中。 对于Pascal字符串和集合,此方法不可接受。 更确切地说,它允许集的大小最多为32个元素,但是这样的集实际上是没有用的。
另外:现在支持字符串操作,最多可设置256个元素。
包装程序。 自编译的思想导致对标准库中某些例程的调用包装。 对于由外部编译器(Delphi / Free Pascal)进行编译和自编译的情况,包装器签名是相同的; 包装程序有所不同。 因此,编译方法的所有细节都位于几个包装器中。 Pascal充斥着一些程序,这些程序经过仔细检查后,发现无法按照Pascal本身的规则来实现:
Read
,
Write
,
Move
等。 对于最常见的过程,包括
Write
,我做了一个例外,并实现了非典型的语言语法,但帕斯卡(Pascal)的任何鉴赏家都很熟悉。 对于大多数其他非典型过程,需要包装器。 因此,XD Pascal不能与Delphi或Free Pascal完全兼容,但这并不是什么大问题,因为即使Free Pascal本身处于与Delphi的兼容模式下,实际上仍然不兼容。
另外:现在实现了对无类型形式变量参数的支持。 这使得程序
FillChar
,
BlockWrite
,
Move
,
FillChar
与Delphi和Free Pascal兼容,从而从根本上减少了所需包装器的数量。
使用GUI编译程序
尽管具有象征意义,但自编译的任务仍然很有限:编译器是一个控制台程序,因此看起来不像Windows世界的成熟居民。 在使用窗口界面编译程序的方式上进行了一些创新:
指示编译器设置接口的类型。 接口的类型(控制台或图形)必须在可执行文件的单独标题字段中指定。 如您所知,在Delphi和Free Pascal中有一个指令
$APPTYPE
。 类似的
$A
指令出现在XD Pascal中。
该操作取程序和功能的地址。 在经典的Pascal中,没有完整的过程和函数指针-它们在某种程度上被过程类型所取代。 XD Pascal中未实现此类型。 即便如此,在我谦虚的项目中仍将
@
操作应用于过程似乎对我毫无用处。 但是,Windows API事件的处理是基于回调的,在这里,被调用处理程序过程地址的传输突然变得迫在眉睫。
另外: XD Pascal现在增加了对过程类型的完全支持。
明确指定链接库的名称。 对于控制台程序,从
KERNEL32.DLL
库导入Windows API函数就足够了。 带有
USER32.DLL
,
GDI32.DLL
等的GUI的程序。 有必要通过在其中添加库名称来扩展
external
指令的语法。
GUI演示结果如何
结果是一个非常简单的Windows自编译器。 不太可能将其与Free Pascal等强大的集体项目进行正确比较。 相反,他属于著名的业余爱好者
BeRo Tiny Pascal的体重类别。 与之相比,XD Pascal具有明显的优势:Pascal的语法更加严格并且可以控制错误,提供了完整的文件输入/输出,支持浮点数的运算,不依赖外部汇编程序,允许使用窗口接口编译程序。
接下来,我必须处理某些防病毒软件的误报-这是我在小型舒适的MS-DOS世界中没有想到的新问题。 如果幸运的话,XD Pascal和BeRo Tiny Pascal将会在MSTU上有关编译器设计过程的实验室研讨会中进行介绍。 N.E. 鲍曼