SCC-用于DOS的小型C编译器

2020-09-24 21:24:33

SCC是一个有限的C编译器,可生成微小模型(即单段)DOS COM文件。它应该可以在大多数操作系统上运行,并且可以在具有128K RAM的DOS2.0+兼容系统(例如SDO)下自托管(编译器只使用64K,但是操作系统也需要具有生命力:)。

使用C99编译器编译scc.c并在scc.c上运行输出,这将生成scc.com,然后可以在DOS下运行(例如使用DOSBox或提供的模拟器),在那里它可以自编译:scc.com scc.c。然后可以对剩余的软件组件重复这些步骤。

如果启用了构建磁盘映像,并且找到了QEMU,则可以构建qemu_test目标来启动附加了大磁盘映像的QEMU。使用CMake变量QEMU_EXTRA_ARGS将额外参数传递给QMEU。

Sim.img是一个360K的磁盘映像,包含最小磁盘容量。它适合与非常旧的机器一起使用。

启动一个模拟器(如果你幸运的话,也可以是真正的模拟器),比如PCem、QEMU或优秀的在线PCjs。

(可选)在SDOS提示符下(#)键入build,然后按Enter键构建包含的软件。等待几分钟,让软件开始构建(或按几次4.77 MHz按钮以加快速度)。

使用uvi(一个微型vi克隆)编辑源代码,使用scpp进行预处理,使用scc进行编译,使用debug进行调试,使用sim86进行模拟。

UVI hello.c#编辑(按";i";进入插入模式,按Esc键退出。";:wq";编写&;退出)scpp hello.c#预处理以生成hello.iscc hello.i#Compilehello.com#运行

在您的主机系统上,您可以使用sim86-p hello.com来获取基本的性能信息(基本上是执行的内存访问次数)。

Lib.h包含一个极其基本的标准库和调用main的启动代码。在非SCC平台上,它改为包含相应的标头,从而允许在其他系统上编译相同的代码而无需修改。

如果您计划多次运行这些步骤,则可能需要使用这些步骤创建批处理文件。

如果您正在做任何非常有用的事情,那么您可能想要放弃预处理步骤,而构建您自己的标准库。

Void PutChar(Int Ch){_emit 0xB4_emit 0x02//MOV AH,2_emit 0x8A_emit 0x56_emit 0x04//MOV DL,[BP+4]_emit 0xCD_emit 0x21//int 0x21}void_start(){const char*s=";Hello DOS!\r\n";While(*s)PutChar(*s++);}。

这应该会让您对如何克服SCC的限制有一个(模糊的)概念(通过搜索_emit,您可以在lib.h和sim86.c中看到更多示例)。

你可能没有。如果你真的想编译DOS的C代码,看看DJGPP或OpenWatcom。这只是一个业余爱好项目,为我的另一个NIH项目SDOS/SASM创建编译器。

我希望保持简单,不太依赖内联汇编(读取:_emit语句)。SIM86必须使用64K以上的内存,因此有一条允许更大输出文件的明确途径,但目前我更喜欢降低内存使用量的挑战:)

对结构成员数量的任意限制(您可以在一定程度上更改这些限制)。

微型内存模型(即所有代码和数据必须位于单个64K段内)。假设CS=DS=ES=SS。(有关如何解决此限制的示例,请参阅SIM86)。

仅对初始化器提供基本支持(规则很复杂,但如果它不在测试套件中,则不受支持...)。

首先,确保源代码(尽最大可能)编译并与另一个C编译器一起工作。SCC假定源代码可以工作,并且只进行最少的检查。许多无效的C程序被接受,许多有效的C程序被拒绝(或编译错误!)。

在您的主机系统上使用模拟器(SIM86)-p还可以方便地反汇编所有到达的指令。

某些错误将报告为堆栈跟踪(见下文)。对于这些情况,您需要参考除COM文件之外生成的映射文件(即scc.com的scc.map)。

07A5#0786失败4844#4666 ParseDeclarator48E4#48D5 DoDecl4920#4908 ParseFirstDecl51FE#51F8 ParseExternalDefition5892#55F3 main03D5#03A2_start。

报告的行号超过了当前标记(这意味着可能跳过了大量空格/注释)。

如果使用了预处理程序,则需要手动反向工程预处理文件中的实际行(因为这是行号所指向的位置)。

在主机系统上运行SCC可能会提供行号,以便在scc.c中查找检查失败。

如果您可以在主机系统上重现该问题,则应该使用附加到SCC的调试器来了解问题发生的位置和原因。

如果您怀疑是编译器错误,您可能需要隔离问题并手动检查生成的代码。

除了一些小的例外,SCC是一个单遍编译器。它非常努力地只考虑当前的字符/令牌/(子)表达式来保存内存,而不是构建AST,而是直接输出响应表达式和语句的代码。

在这些约束下,SCC尝试生成稍微优化的代码。许多可能的优化没有执行,因为它们不会带来回报(这意味着它们不会在时间或大小上优化SCC本身)。

在进行地址修正时会进行一些小的优化,以补偿有限的优化。这些是仅有的向后看的优化。