我正在关注在 http://compilers.iecc.com/crenshaw 上找到的 Jack Crenshaw 出色的 Let's Build a Compiler 教程。我正在使用 Easy68k http://www.easy68k.com/ 68000 编辑器/汇编器/模拟器测试生成的 68k 程序集。我已进入第 2 部分 http://compilers.iecc.com/crenshaw/tutor2.txt,但 Divide 程序对我来说无法正常工作。

...
{ Recognize and Translate a Divide }
procedure Divide;
begin
  Match('/');
  Factor;
  EmitLn('MOVE (SP)+,D1');
  EmitLn('DIVS D1,D0');
end;
...

如果我输入“8/2”作为测试,那么编译器会生成以下代码:
MOVE #8,D0
MOVE D0,-(SP)
MOVE #2,D0
MOVE (SP)+,D1
DIVS D1,D0

在我看来,它实际上是在计算 2/8(即它是错误的方式),因为之后留在 D0 中的值为 00020000。我可以通过将最后一行重写为 DIVS D0,D1 来解决这个问题,但这将结果保留在按照其他例程,D1 而不是 D0,在我看来,这样一项开创性的工作不太可能是不正确的。我已经在互联网上搜索过,但我看不到其他人遇到过这个问题。那是不是意味着:
1)我做错了 - 可能
2) jack 做错了——不太可能
3) Easy68k 模拟器做错了 - 不太可能
但是,我只是看不出我做错了什么。
请帮忙。

最佳答案

我想我可能已经破解了它。教程 http://compilers.iecc.com/crenshaw/tutor3.txt 第 3 条的 Divide 程序版本略有不同,虽然似乎没有解释,所以可能是错字。。第三条中的修订版是

{ Recognize and Translate a Divide }
procedure Divide;
begin
  Match('/');
  Factor;
  EmitLn('MOVE (SP)+,D1');
  EmitLn('EXS.L D0');
  EmitLn('DIVS D1,D0');
end;

注意添加的行
EmitLn('EXS.L D0');

这似乎是为了交换寄存器 D0 和 D1 的内容。现在虽然 Easy68k 似乎不喜欢“EXS.L D0”,但在检查 Easy68 文档后,我已将其更改为阅读
EmitLn('EXG D0,D1');

现在 Divide 程序起作用了。我不确定这是否特定于 Easy68k 或者为什么文章说 EXS.L 但至少它现在有效。欢呼!

关于assembly - Divide (DIVS) 对 jack crenshaw 不起作用,让我们构建一个编译器,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8882775/

10-15 10:59