x86-64汇编多条件跳转处理及计算器运算优先级实现问题
处理x86-64汇编计算器的运算优先级问题
当前你的计算器代码仅按输入顺序从左到右执行运算,未遵循乘除优先级高于加减的规则。要解决这个问题,最经典的方案是双栈法——维护数字栈和运算符栈,通过优先级判断决定何时执行运算。
核心规则
- 数字栈:存储解析后的十进制数字
- 运算符栈:存储运算符,并按优先级管理栈内元素
- 优先级定义:
*、/优先级为2,+、-优先级为1 - 处理逻辑:
- 遇到数字:直接压入数字栈
- 遇到运算符:
- 若运算符栈为空,直接压入
- 若当前运算符优先级高于栈顶运算符,压入栈
- 若当前运算符优先级≤栈顶运算符,弹出栈顶运算符和数字栈的两个数字(注意顺序:后弹出的是左操作数),计算结果后压回数字栈,重复此步骤直到栈顶运算符优先级低于当前运算符,再压入当前运算符
- 遍历完输入后,依次弹出栈内运算符和对应数字计算,直到运算符栈为空,数字栈剩余的唯一值就是结果
修改后的汇编代码示例
;calculator.asm %macro convert 2 mov al, dl mov dl, 0 mov bl, %1 div bl add byte[result+%2], al %endmacro ; 栈操作宏:压入字节到栈,栈顶指针递减(x86栈向低地址增长) %macro push_byte 2 mov byte[%1 + %2 - 1], dl ; %1是栈基址,%2是栈顶指针当前值 dec %2 ; 更新栈顶指针 %endmacro ; 弹出字节从栈,栈顶指针递增 %macro pop_byte 2 inc %2 mov dl, byte[%1 + %2 - 1] %endmacro section .data msg db "Enter an equation: " input db "000000000", 10 ; 数字栈和运算符栈,初始栈顶指向栈底+1(空栈状态) num_stack db 0,0,0,0,0,0,0,0 num_top dq 8 op_stack db 0,0,0,0,0,0,0,0 op_top dq 8 result db 0,0,0 endLoop dq 9 ; 获取运算符优先级:dl=运算符,返回al=优先级 get_priority: cmp dl, '+' je prio1 cmp dl, '-' je prio1 cmp dl, '*' je prio2 cmp dl, '/' je prio2 prio1: mov al, 1 ret prio2: mov al, 2 ret ; 执行运算:弹出num栈两个数,op栈一个运算符,计算后压回num栈 execute_op: ; 弹出右操作数 pop_byte num_stack, qword[num_top] mov bl, dl ; 弹出左操作数 pop_byte num_stack, qword[num_top] mov al, dl ; 弹出运算符 pop_byte op_stack, qword[op_top] cmp dl, '+' je do_add cmp dl, '-' je do_sub cmp dl, '*' je do_mul cmp dl, '/' je do_div do_add: add al, bl jmp push_result do_sub: sub al, bl jmp push_result do_mul: mul bl jmp push_result do_div: div bl push_result: mov dl, al push_byte num_stack, qword[num_top] ret section .text global _start _start: ; 输出提示信息 mov rax, 1 mov rdi, 1 mov rsi, msg mov rdx, 19 syscall ; 读取输入 mov rax, 0 mov rdi, 0 mov rsi, input mov rdx, 10 syscall xor r10d, r10d parse_loop: ; 解析数字:连续数字合并(比如"123"转为123) xor eax, eax parse_digit: mov dl, byte[input+r10] cmp dl, '0' jb end_digit cmp dl, '9' ja end_digit ; 数字合并:当前值*10 + 新数字 imul eax, 10 sub dl, '0' add al, dl inc r10 jmp parse_digit end_digit: ; 将解析后的数字压入数字栈 mov dl, al push_byte num_stack, qword[num_top] ; 检查是否到输入末尾 cmp r10, qword[endLoop] je process_remaining_ops ; 读取运算符 mov dl, byte[input+r10] inc r10 operator_process: ; 如果运算符栈为空,直接压入 cmp qword[op_top], 8 je push_op ; 获取当前运算符优先级 call get_priority mov cl, al ; 获取栈顶运算符优先级 mov dl, byte[op_stack + qword[op_top]] call get_priority ; 比较优先级:当前优先级>栈顶则压入,否则先执行运算 cmp cl, al jg push_op call execute_op jmp operator_process push_op: mov dl, byte[input+r10-1] ; 刚才读取的运算符 push_byte op_stack, qword[op_top] jmp parse_loop ; 处理剩余的运算符 process_remaining_ops: cmp qword[op_top], 8 je done call execute_op jmp process_remaining_ops done: ; 弹出最终结果 pop_byte num_stack, qword[num_top] mov dl, al ; 转换为ASCII convert 100, 0 convert 10, 1 convert 1, 2 add byte[result+2], dl ; 补ASCII偏移 add byte[result], '0' add byte[result+1], '0' add byte[result+2], '0' ; 输出结果 mov rax, 1 mov rdi, 1 mov rsi, result mov rdx, 3 syscall ; 退出程序 mov rax, 60 mov rdi, 0 syscall
关键修改说明
- 新增数字栈和运算符栈,用宏实现栈的压入/弹出操作(用静态数组模拟栈,符合x86栈向低地址增长的特性)
- 实现多位数合并逻辑,支持多位数输入(原代码仅支持单数字)
- 新增
get_priority函数判断运算符优先级,execute_op函数统一处理运算逻辑,避免重复代码 - 按双栈规则处理运算符,确保乘除先于加减执行
- 遍历完输入后处理栈内剩余运算符,完成所有计算
内容的提问来源于stack exchange,提问作者rageatm
相关产品推荐
相关产品推荐

