我正在关注杰克·克伦肖(Jack Crenshaw)在http://compilers.iecc.com/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)杰克做错了 - 不太可能 3)Easy68k仿真器做错了 - 不太可能 但是我只是看不出我做错了什么。 请帮忙。
答案 0 :(得分: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');
现在Divide程序正常运行。我不确定这是否特定于Easy68k或文章为什么说EXS.L,但至少它现在有效。乌拉!