1

我正在尝试打印

Hello, world.
ello, world.H
llo, world.He
lo, world.Hel
o, world.Hell
, world.Hello
 world.Hello,
world.Hello,
orld.Hello, w
rld.Hello, wo
ld.Hello, wor
d.Hello, worl
.Hello, world
Hello, world.

仅在内存中使用此字符串String: .asciiz "Hello, world."。到目前为止,这是我的代码:

    .text
String:    .asciiz "Hello, world."
x:         .float 13

    .data 
Main:       lw $t0,x
            jal PrintString
            li $v0, 10
            syscall

PrintString:    la $a0,String
                li $v0,4
                syscall
                bgtz $t0, MoveString
                jr $ra

MoveString: (CODE)

但我不确定在 MoveString 标签中放什么。我需要将字符移String一位,然后将其中的内容减去x1。我不知道该怎么做。谢谢你的帮助!

4

1 回答 1

5

首先注意几点:

  • 你有.text并且.data混淆了
  • 继续在字符串末尾添加一个换行符,它会使显示更好一些:

    String:    .asciiz "Hello, world.\n"
    
  • 假设 13 用于字符串的长度,您应该使用整数而不是浮点数:

    x:         .word 13
    

现在,进入问题。有两种方法可以做到这一点:1)就地旋转字符串并syscall 4每次调用,或2)保持字符串原样并一次打印一个字母,而不是使用索引来实现旋转效果。您选择了方法 1,所以让我们开始吧。

首先编写一些伪代码。您需要一个子程序,它将存储的字符串$a0向左旋转一个字母。立即,您应该考虑某种循环遍历字符串中的每个字母:

for int index from 0 to 12
    copy letter from (index + 1) to index

但是等等:第一个字母会发生什么?它会被破坏。当我们到达终点时会发生什么?我们将把边界之外的东西复制String到最后一个字母槽。因此,让我们通过将第一个字母存储到临时寄存器来解决它:

temp = letter[0]

for int index from 0 to 11
    copy letter from (index + 1) to index

letter[12] = temp

这样更好;应该这样做。下一个问题:我们如何在 MIPS 中做到这一点?

我们知道$a0它将保存字符串的地址,所以让我们认为这是理所当然的。我们至少需要一个临时寄存器——因为我们已经在使用$t0for x,让我们用它$t1来保存第一个字母:

MoveString:
lb $t1, String

我们还需要一个索引寄存器,所以让我们使用$t2它。将其初始化为零:

li $t2, 0

为每个字母增加一次地址寄存器会很好,但我们不想破坏$a0,因为它会搞砸PrintString。所以让我们将它复制到$a1我们的循环中:

move $a1, $a0

最后,我们需要知道字符串有多长,所以让我们加载另一个副本xinto $t3

lb $t3, x
sub $t3, $t3, 1               ; We're only iterating over the first 12 letters,
                              ; since the last letter is done manually with temp

现在我们可以开始循环了。我们需要将字母(只是一个字节)从复制$a1 + 1$a1

MoveStringLoop:
lb $t4, 1($a1)                  ; Load the letter from (address + 1)
sb $t4, 0($a1)                  ; Store it to (address)
add $a1, $a1, 1                 ; Increment our address
add $t2, $t2, 1                 ; Increment our index
blt $t2, $t3, MoveStringLoop    ; Loop again if index < (length - 1)

sb $t1, 0($a1)                  ; Copy the temp letter to the end of the string

应该是这样的。之后,我们可以递减x并返回PrintString

sub $t0, $t0, 1
b PrintString

无论如何,这都不是最佳解决方案。我确信一个真正的编译器和一些更好的编码可以用一半的指令完成工作。但是由于您正在学习如何编写程序集,所以暂时不要担心微优化。这是最终代码及其输出:

    .data
String:    .asciiz "Hello, world.\n"
x:         .word 13

    .text 
Main:       lw $t0,x
            jal PrintString
            li $v0, 10
            syscall

PrintString:    la $a0,String
                li $v0,4
                syscall
                bgtz $t0, MoveString
                jr $ra

MoveString:
                lb $t1, String
                li $t2, 0
                move $a1, $a0
                lb $t3, x
                sub $t3, $t3, 1

MoveStringLoop:
                    lb $t4, 1($a1)
                    sb $t4, 0($a1)
                    add $a1, $a1, 1
                    add $t2, $t2, 1
                    blt $t2, $t3, MoveStringLoop

                sb $t1, 0($a1)

                sub $t0, $t0, 1
                b PrintString

输出:

Hello, world.
ello, world.H
llo, world.He
lo, world.Hel
o, world.Hell
, world.Hello
 world.Hello,
world.Hello,
orld.Hello, w
rld.Hello, wo
ld.Hello, wor
d.Hello, worl
.Hello, world
Hello, world.
于 2012-10-10T23:14:05.197 回答