我有一个英特尔装配任务。我需要编写一个使用 2 个堆栈的计算器。例如,我有一个像 23+4/2^4$ 这样的表达式。所以 $ 表示表达式的结尾。我要做的是有两个堆栈,一个用于数字,一个用于运算符,并根据运算符优先级推送和弹出它们。
我需要的是如何同时将 2 个堆栈用于两个不同的目的。只要我知道 esp register 指示堆栈中变量弹出最后一个或推送一个新变量的位置。但是如果我只有一个 esp 寄存器,我怎么能有两个堆栈呢?
提前致谢...
我有一个英特尔装配任务。我需要编写一个使用 2 个堆栈的计算器。例如,我有一个像 23+4/2^4$ 这样的表达式。所以 $ 表示表达式的结尾。我要做的是有两个堆栈,一个用于数字,一个用于运算符,并根据运算符优先级推送和弹出它们。
我需要的是如何同时将 2 个堆栈用于两个不同的目的。只要我知道 esp register 指示堆栈中变量弹出最后一个或推送一个新变量的位置。但是如果我只有一个 esp 寄存器,我怎么能有两个堆栈呢?
提前致谢...
我认为您正在寻找的是 Dijkstra 的分流算法。
我在解释过程中没有使用堆栈就解决了这个问题,只在我的博客中描述的执行过程中解决了这个问题。
至于做额外的筹码,这很容易。所有的堆栈实际上只是一个带有指向顶部和底部的指针的内存区域。每次按下时,顶部指针递增,每次弹出时,顶部指针递减。
或者,您可以以最简单的方式可能会工作™ 并在内存中实现您的两个执行堆栈;如上所述,您只需要一个 TOP 指针和一些算术。
所有这些答案都假设不存在运算符优先级之类的东西。显然,问题中提到的堆栈的使用暗示了与使用运算符优先级的计算有关的正确答案。
这是一个链接,解释了您要实现的目标。 http://epaperpress.com/oper/index.html
假设表达式的长度为 L ,那么您的每个堆栈最多为 L,因此您最多需要 2L 内存。
将 ESP 增加 2L ,在 ESP 处你将有你的第一个堆栈的开始,在 ESP+L 你将有你的第二个堆栈的开始(应该注意这些堆栈都不会超过 L 因为表达式是长度L)。
调车场算法可以在各个地方找到。它所做的就是从中缀表示法
到后缀表示法的转换。在那之后,后缀符号的评估就不难了。
编辑:另外,为了操作 2 个堆栈,您需要将它们的堆栈指针存储在某处。
您可以使用 2 个您选择的寄存器,例如 EBX、ECX
使一个具有 ESP 值,另一个具有 ESP+L 值。每次您将使用一个堆栈或另一个堆栈时,您都必须使用适当的 EBX 或 ECX 或任何您可能保留 2 个堆栈指针的地方更新 ESP,因为 push 和 pop 将修改 ESP,您将希望他们修改 ESP 的版本需要而不是另一个。此外,当您完成弹出/推送时,您必须使用 ESP 的值更新 EBX/ECX。
由于您的两个堆栈不是独立的,因此另一个想法是将数据交错在单个堆栈上。例如,您可以将偶数字用于数字,将奇数字用于运算符。
编辑:按照评论中的要求详细说明这个想法:我相信每次你推送一个运算符时,你都会推送它后面的数字(因为该数字后面可能会跟着一个更高优先级的运算符)。同样,每次弹出和运算符时,您都将弹出两个操作数并推送一个结果。因此,操作符堆栈和操作数堆栈同时增长和缩小,并且由于最初的问题是如何在汇编代码中执行此操作,我建议他们可以在单个堆栈上共享交替的插槽。(如果这还不够详细,请告诉我,我会再次编辑。)
那么,我创建两个这样的堆栈是否正确:
mov ecx,256
L1: call ReadInt
push eax ;push the integer to where esp=1 points
add esp,ecx ;esp=1+256=257, now esp points to 257.
call ReadChar ;read operand
cmp al,endChar ;compare with end sign=$
je next
push al ;push operand to where esp=257 points
sub esp,ecx ;esp=257-256=1, now esp is in the original position
loop L1
next:
...
当然,评论是针对第一个循环的。
顺便说一句,我得到一个“1>..\main.asm(46):错误 A2149:字节寄存器不能是第一个操作数”错误(push al)?怎么了?
谢谢...