【问题标题】:Calculator using 2 stacks使用 2 个堆栈的计算器
【发布时间】:2010-09-26 19:37:05
【问题描述】:

我有一个英特尔汇编任务。我需要编写一个使用 2 个堆栈的计算器。例如,我有一个像 23+4/2^4$ 这样的表达式。所以 $ 表示表达式的结尾。我要做的是有两个堆栈,一个用于数字,一个用于运算符,并根据运算符优先级推送和弹出它们。

我需要的是如何同时将 2 个堆栈用于两个不同的目的。只要我知道 esp 寄存器指示堆栈中变量弹出最后一个或推送一个新变量的位置。但是如果我只有一个 esp 寄存器,我怎么会有两个堆栈呢?

提前谢谢...

【问题讨论】:

    标签: assembly stack arithmetic-expressions


    【解决方案1】:

    我认为您正在寻找的是 Dijkstra 的分流算法。

    我在解释过程中没有使用堆栈解决它,仅在执行过程中,如in my blog. 所述

    至于做额外的筹码,这很容易。所有的堆栈实际上只是一个带有指向顶部和底部的指针的内存区域。每次按下时,顶部指针递增,每次弹出时,顶部指针递减。

    【讨论】:

      【解决方案2】:

      由于您的两个堆栈不是独立的,另一个想法是在单个堆栈上交错数据。例如,您可以对数字使用偶数词,对运算符使用奇数词。


      编辑:按照评论中的要求详细说明这个想法:我相信每次你推送一个运算符时,你都会推送它后面的数字(因为该数字后面可能会跟着一个更高优先级的运算符)。同样,每次弹出和运算符时,您都将弹出两个操作数并推送一个结果。所以操作符栈和操作数栈同时增长和缩小,因为最初的问题是如何在汇编代码中做到这一点,我建议他们可以在一个栈上共享交替的槽。 (如果这还不够详细,请告诉我,我会再次编辑。)

      【讨论】:

      • 我认为这是一个非常有趣的想法,需要进一步阐述。
      • 交错堆栈......这种聪明会让你陷入困境
      • 如果 OP 将此实现为 RPN,则运算符和操作数将不会 1:1 交错。例如,5 * (6 - 3) 将是 {6,3,-,5,} 甚至 {5,6,3,-,},我认为这是调车场算法会生成。
      【解决方案3】:

      或者,您可以使用可能工作的最简单方法™ 并在内存中实现您的两个执行堆栈;和上面一样,你只需要一个 TOP 指针和一些算术。

      【讨论】:

        【解决方案4】:

        那么,我这样创建两个堆栈是否正确:

        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:
        ...
        

        当然,cmets 是用于第一个循环的。

        顺便说一句,我得到一个“1>..\main.asm(46) : error A2149:byte register cannot be first operand”错误(push al)?怎么了?

        谢谢...

        【讨论】:

        • 如果在“add esp, ecx”和“sub esp, ecx”之间发生中断,你会遇到麻烦。相反,您必须维护两个指向堆栈的指针。一个可以是esp,另一个应该是ebp。
        • 至于你的错误(“字节寄存器不能是第一个操作数”),你必须推 eax,而不是 al。您只能推送全宽寄存器。 esp 应始终在机器字边界上对齐。
        【解决方案5】:

        假设表达式的长度为 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。

        【讨论】:

          【解决方案6】:

          所有这些答案都假设不存在运算符优先级之类的东西。显然,问题中提到的堆栈的使用暗示了与使用运算符优先级的计算有关的正确答案。

          这里有一个链接,它解释了您想要实现的目标。 http://epaperpress.com/oper/index.html

          【讨论】:

          • “所有这些答案都假设不存在运算符优先级”?什么 ?你是从哪里得出这个结论的?
          • 这个问题是著名的运算符优先级问题,由著名的中缀表示法解决。上面的答案似乎没有考虑堆栈,并谈到删除堆栈,这会破坏上述练习的目的。
          • 我想你不知道你在说什么
          猜你喜欢
          • 2017-08-18
          • 2011-01-04
          • 2016-01-23
          • 2015-09-15
          • 2017-03-29
          • 1970-01-01
          • 1970-01-01
          • 2012-06-26
          • 2020-02-22
          相关资源
          最近更新 更多