4

我正在关注 Jack Crenshaw 在http://compilers.iecc.com/crenshaw上找到的优秀的 Let's Build a Compiler 教程。我正在使用 Easy68k http://www.easy68k.com/ 68000 editor/assembler/simulator 测试生成的 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)杰克做错了 - 不太可能 3)Easy68k 模拟器做错了 - 不太可能 但是我只是看不出我做错了什么。请帮忙。

4

1 回答 1

7

我想我可能已经破解了它。教程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');

现在除法程序起作用了。我不确定这是否特定于 Easy68k,或者为什么文章说 EXS.L,但至少现在可以使用。欢呼!

于 2012-01-16T22:03:23.570 回答