0

我的程序应该采用两个整数和一个运算符(除法、乘法、加法、减法)。如有必要,它会从那里计算答案和余数。

之后,它应该提示用户是否要进行另一个计算,使用 (y/n) 选项。如果是,它重新循环,如果不是,程序退出。出于某种原因,它不允许我输入 (y/n) 的选项,而只是跳过我的输入并直接终止。这是我的代码。(对不起初学者)

在我输入运算符之前,我还会收到“未知错误代码 45”(弹出窗口?)。

在此处输入图像描述

# SPIM Calculator
# Computer Organization

    .data
prompt:         .asciiz "Welcome to SPIM Calculator 1.0!\n"
first_prompt:   .asciiz "Enter the first number: "
second_prompt:  .asciiz "Enter the second number: "
operator:       .asciiz "Enter the operation (+, -, *, /), then press enter key: "
error_message:  .asciiz "\n\nArgument is invalid. Try again!\n\n"
sp:             .asciiz " "
nl:             .asciiz "\n"
eq:             .asciiz " = "
parl:           .asciiz "("
parr:           .asciiz ")"
again_prompt:   .asciiz "\nWould you like to do another calculation? ( y / n ) "
ended_message:  .asciiz "\nCalculations complete."

    .globl main
    .text

main:
    #initialize
    li $s0, 10

    # Prompt welcome
    li $v0, 4           # print string value 4
    la $a0, prompt      # loads address from memory
    syscall

loop:

    # display prompt for q.1
    li $v0, 4           # loads value 4 into register v0 which is op code for print string
    la $a0, first_prompt    # loads address from memory, stores it in argument register
    syscall             # reads register $v0 for op code, sees 4 and prints string located in $a0

    # get input
    li $v0, 5           # load op code for getting an integer from user into register $v0
    syscall             # reads it and puts in $t0
    move $s0, $v0       # $s0 saves it


    # display prompt for q.2
    li $v0, 4           # loads value 4 into register v0 which is op code for print string
    la $a0, second_prompt   # loads address from memory, stores it in argument register
    syscall             # reads register $v0 for op code, sees 4 and prints string located in $a0

    # get input
    li $v0, 5           # load op code for getting an integer from user into register $v0
    syscall             # reads it and puts in $v0
    move $s1, $v0       # $s1 saves it


    # display prompt for q.3
    li $v0, 4           # loads value 4 into register v0 which is op code for print string
    la $a0, operator    # loads address from memory, stores it in argument register
    syscall             # reads register $v0 for op code, sees 4 and prints string located in $a0

    #get input
    li $v0, 12          # load op code for getting an symbol from user into register $v0
    syscall             # reads it and puts in $t0
    move $s2, $v0       # $s0 saves it


    # check symbol and use if statements to go to correct part in program
    beq $s2, '*', Multiplication
    beq $s2, '/', Division
    beq $s2, '-', Subtraction
    beq $s2, '+', Addition

    # in case it is none of these
    li $v0, 4               # print string value 4
    la $a0, error_message   # loads address from memory
    syscall


Multiplication:

    # perform multiplication
    mult $s0, $s1
    mflo $s3    # moves product to $s3
    syscall

    jr Print

Division:

    # perform division
    divu $s0, $s1
    mflo $s3    # moves quotient to $s3
    mfhi $s4    # move remainder to $s4
    syscall

    jr Print

Subtraction:

    # perform subtraction
    sub $s3, $s0, $s1   # moves result to $s3
    syscall

    jr Print

Addition:

    # perform addition
    add $s3, $s0, $s1   # moves result to $s3
    syscall

    jr Print

Print:
    # print new line
    li $v0, 4
    la $a0, nl
    syscall

    # print first number
    li $v0, 1   # print int
    move $a0, $s0
    syscall

    # print space
    li $v0, 4
    la $a0, sp
    syscall

    # print operator
    li $v0, 11      # print operator
    move $a0, $s2
    syscall

    # print space
    li $v0, 4
    la $a0, sp
    syscall

    # print second number
    li $v0, 1       # print int
    move $a0, $s1
    syscall

    # print equals
    li $v0, 4
    la $a0, eq
    syscall

    # jump to printing specifically for division
    beq $s2, '/', Division_Print

    # print result
    li $v0, 1       # print int
    move $a0, $s3
    syscall

    # print new line
    li $v0, 4
    la $a0, nl
    syscall

    jr Again_Prompt

Division_Print:
    # print quotient
    li $v0, 1       # print int
    move $a0, $s3
    syscall

    # print space
    li $v0, 4
    la $a0, sp
    syscall

    # print left parenthesis
    li $v0, 4
    la $a0, parl
    syscall

    # print remainder
    li $v0, 1       # print int
    move $a0, $s4
    syscall

    # print right parenthesis
    li $v0, 4
    la $a0, parr
    syscall

    # print new line
    li $v0, 4
    la $a0, nl
    syscall

    jr Again_Prompt

Again_Prompt:
    # display prompt 
    li $v0, 4           # loads value 4 into register v0 which is op code for print string
    la $a0, again_prompt    # loads address from memory, stores it in argument register
    syscall             # reads register $v0 for op code, sees 4 and prints string located in $a0

    # get input
    li $v0, 12          # load op code for getting a character from user into register $v0
    syscall             # reads it and puts in $t0
    move $s6, $v0       # $s6 saves it

    # print new line
    li $v0, 4
    la $a0, nl
    syscall

    # determine whether or not to do another calculation
    beq $s6, 'y', loop
    beq $s6, 'n', Terminate

Terminate:
    li $v0, 4           # loads value 4 into register v0 which is op code for print string
    la $a0, ended_message   # loads address from memory, stores it in argument register
    syscall             # reads register $v0 for op code, sees 4 and prints string located in $a0
    jr $ra
4

1 回答 1

0

这里的问题是系统调用 12,或者更确切地说是导致人们使用它的错误假设。

暂时考虑系统调用 12(读取字符)的含义,它将从标准输入 1 字符返回。问题是这样的:

系统提示:What operation would you like to perform?,用户输入:+\n。因为标准输入是行缓冲的,所以用户必须按下回车键,这意味着当他们只想一个字符时,至少有两个字符被放入缓冲区。这意味着当您的程序继续执行下一个查询时:Do you want to go again?,缓冲区中仍然有一个字符:\n这就是第二个系统调用 12 返回的内容。

既然你理解了这个问题,我认为你可以解决它。最好的方法可能是将读取字符系统调用转换为读取字符串系统调用并检查输入的字符串。

作为一个宽松的规则,不要将系统调用 12 用于键盘的用户输入。

于 2013-10-01T02:05:15.110 回答