1

所以我试图在 MIPS 中创建 Sprintf。问题是,我不确定如何处理 %d、%c 等的所有情况。

因此,即使我确实识别 % 我如何识别下一个字符?我的意思是,所以我在寄存器 $a3 中有 %。li $a3, '%'

但是,我没有足够的寄存器用于 $d、%c、%b 等。

我将如何检查所有这些?

######################################################################
# spf-main.s
# 
# This is the main function that tests the sprintf function

# The "data" segment is a static memory area where we can 
# allocate and initialize memory for our program to use.
# This is separate from the stack or the heap, and the allocation
# cannot be changed once the program starts. The program can
# write data to this area, though.
    .data

# Note that the directives in this section will not be 
# translated into machine language. They are instructions 
# to the assembler, linker, and loader to set aside (and 
# initialize) space in the static memory area of the program. 
# The labels work like pointers-- by the time the code is 
# run, they will be replaced with appropriate addresses.

# For this program, we will allocate a buffer to hold the
# result of your sprintf function. The asciiz blocks will
# be initialized with null-terminated ASCII strings.

buffer: .space  20000           # 2000 bytes of empty space 
                    # starting at address 'buffer'

format: .asciiz "string: %s, unsigned dec: %u, hex: 0x%x, char: %c, dec: %d, bin: %b, percent: %%\n"
                    # null-terminated string of 
                    # ascii bytes.  Note that the 
                    # \n counts as one byte: a newline 
                    # character.
str:    .asciiz "thirty-nine"       # null-terminated string at
                    # address 'str'
chrs:   .asciiz " characters:\n"    # null-terminated string at 
                    # address 'chrs'
strpd:  .asciiz "%d"        # null-terminated string at 
strpc:  .asciiz "%c"        # null-terminated string at 
strpb:  .asciiz "%b"        # null-terminated string at     
strpu:  .asciiz "%u"        # null-terminated string at
strpx:  .asciiz "%x"        # null-terminated string at 
strpo:  .asciiz "%o"        # null-terminated string at 
strps:  .asciiz "%s"        # null-terminated string at 
strpp:  .asciiz "%%"        # null-terminated string at 
strpi:  .asciiz "%"     # null-terminated string at 



# The "text" of the program is the assembly code that will
# be run. This directive marks the beginning of our program's
# text segment.

    .text

# The sprintf procedure (really just a block that starts with the
# label 'sprintf') will be declared later.  This is like a function
# prototype in C.

    .globl sprintf

# The special label called "__start" marks the start point
# of execution. Later, the "done" pseudo-instruction will make
# the program terminate properly.   

main:
    addi    $sp,$sp,-36 # reserve stack space

    # $v0 = sprintf(buffer, format, str, 255, 255, 111, -255, -255)

    la  $a0,buffer  # arg 0 <- buffer
    la  $a1,format  # arg 1 <- format
    la  $a2,str     # arg 2 <- str

    addi    $a3,$0,255  # arg 3 <- 255
    sw  $a3,16($sp) # arg 4 <- 255

    addi    $t0,$0,111
    sw  $t0,20($sp) # arg 5 <- 111 ('o', as a character)

    addi    $t0,$0,-255
    sw  $t0,24($sp) # arg 6 <- -255

    addi    $t0,$0,255  
    sw  $t0,28($sp) # arg 7 <- 255

    sw  $ra,32($sp) # save return address
    jal sprintf     # $v0 = sprintf(...)

    # print the return value from sprintf using
    # putint()

    add $a0,$v0,$0  # $a0 <- $v0
    jal putint      # putint($a0)

    ## output the string 'chrs' then 'buffer' (which
    ## holds the output of sprintf)
    li  $v0, 4  
    la      $a0, chrs
    syscall
    #puts   chrs        # output string chrs

    li  $v0, 4
    la  $a0, buffer
    syscall
    #puts   buffer      # output string buffer

    addi    $sp,$sp,36  # restore stack
    li  $v0, 10     # terminate program
    syscall

# putint writes the number in $a0 to the console
# in decimal. It uses the special command
# putc to do the output.

# Note that putint, which is recursive, uses an abbreviated
# stack. putint was written very carefully to make sure it
# did not disturb the stack of any other functions. Fortunately,
# putint only calls itself and putc, so it is easy to prove
# that the optimization is safe. Still, we do not recommend 
# taking shortcuts like the ones used here.

# HINT: You should read and understand the body of putint,
# because you will be doing some similar conversions
# in your own code.

putint: addi    $sp,$sp,-8  # get 2 words of stack
    sw  $ra,0($sp)  # store return address

    # The number is printed as follows:
    # It is successively divided by the base (10) and the 
    # reminders are printed in the reverse order they were found
    # using recursion.

    remu    $t0,$a0,10  # $t0 <- $a0 % 10
    addi    $t0,$t0,'0' # $t0 += '0' ($t0 is now a digit character)
    divu    $a0,$a0,10  # $a0 /= 10
    beqz    $a0,onedig  # if( $a0 != 0 ) { 
    sw  $t0,4($sp)  #   save $t0 on our stack
    jal putint      #   putint() (putint will deliberately use and modify $a0)
    lw  $t0,4($sp)  #   restore $t0
                            # } 
onedig: move    $a0, $t0
    li  $v0, 11
    syscall         # putc #$t0
    #putc   $t0     # output the digit character $t0
    lw  $ra,0($sp)  # restore return address
    addi    $sp,$sp, 8  # restore stack
    jr  $ra     # return





    #sprintf!
#$a0 has the pointer to the buffer to be printed to
#$a1 has the pointer to the format string
#$a2 and $a3 have (possibly) the first two substitutions for the format string
#the rest are on the stack
#return the number of characters (ommitting the trailing '\0') put in the buffer

        .text

sprintf:
    addi $sp, $sp, -12
    sw $ra, 8($sp)
    sw $s1, 4($sp)
    sw $s2, 0($sp)







    li $a3, '%'     



        li      $s0, 0          # len = 1
        la      $s1, ($a1)        # s = str
test:
        lb      $s2, 0($s1)     # c = *s
        beqz    $s2, done       # if c == '\0', branch to "done"
     #   beq    $s2, $a3, percent

        addi    $s0, $s0, 1     # len = len + 1
        addi    $s1, $s1, 1     # s = s + 1
        j       test

percent:
     li $v0, 4    # print_string    
    la $a0, str 
    syscall



done:
     #   li      $v0, 1          # syscall code: print_int
     #   move    $a0, $s0
     #   syscall
       li      $v0, 11         # syscall code: print_char
        li      $a0, 10         # pass newline character
        syscall


        add $v0,$0, $s0
        lw $ra, 8($sp)
        lw $s1, 4($sp)
    lw $s2, 0($sp)
    addi $sp, $sp, 12

        jr      $ra
4

1 回答 1

0

您需要一个循环来检查sprintf函数内的下一个字符。此循环应扫描下一个字符,将其与您将使用的可用字符列表进行比较,然后分支到必要的功能,其中包括返回循环以防万一%%

于 2016-07-30T21:17:52.830 回答