在MIPS汇编中切换字符位置

nat*_*and 1 string assembly mips

我正打算打印出来

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.
Run Code Online (Sandbox Code Playgroud)

在内存中只使用此字符串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)
Run Code Online (Sandbox Code Playgroud)

但我不确定在MoveString标签中放入什么.我需要将字符String换成一个,然后减去x1 中的内容.我不知道该如何去做.谢谢你的帮助!

Jef*_*f E 5

一对夫妇首先注意到:

现在,解决问题.有两种方法可以做到这一点:1)旋转就地串并呼吁syscall 4各一次,或2)保持字符串,因为它是和打印一个字母的时间,用食指玩,而不是实现旋转效果.你已经选择了方法1,所以让我们继续.

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

for int index from 0 to 12
    copy letter from (index + 1) to index
Run Code Online (Sandbox Code Playgroud)

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

temp = letter[0]

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

letter[12] = temp
Run Code Online (Sandbox Code Playgroud)

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

我们知道这$a0将保留字符串的地址,所以让我们理所当然.我们至少需要一个临时注册 - 因为我们已经使用$t0x,所以我们用它$t1来保留第一个字母:

MoveString:
lb $t1, String
Run Code Online (Sandbox Code Playgroud)

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

li $t2, 0
Run Code Online (Sandbox Code Playgroud)

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

move $a1, $a0
Run Code Online (Sandbox Code Playgroud)

最后,我们需要知道字符串是怎么长的,所以让我们载入的另一个副本x$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
Run Code Online (Sandbox Code Playgroud)

现在我们可以开始循环了.我们需要将字母(只是一个字节)复制$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
Run Code Online (Sandbox Code Playgroud)

那应该是它.在那之后,我们可以减少x并回到PrintString:

sub $t0, $t0, 1
b PrintString
Run Code Online (Sandbox Code Playgroud)

无论如何,这不是最佳解决方案; 我确信一个真正的编译器和一些更好的编码可以在一半的指令中完成工作.但是既然你正在学习如何编写汇编,那么现在就不用担心微优化了.这是最终代码及其输出:

    .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
Run Code Online (Sandbox Code Playgroud)

输出:

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.
Run Code Online (Sandbox Code Playgroud)