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 ラベルに何を入れればよいかわかりません。文字を 1 つずつシフトし、そのString内容を 1 減算する必要がありxます。これを行う方法がわかりません。ご協力いただきありがとうございます!

4

1 に答える 1

5

最初にいくつかの注意事項:

  • あなたは持ってい.text.data混同しています
  • 文字列の最後に改行を追加すると、表示が少し見やすくなります。

    String:    .asciiz "Hello, world.\n"
    
  • 文字列の長さに 13 を使用すると仮定すると、float の代わりに整数を使用する必要があります。

    x:         .word 13
    

さて、問題に。これを行うには 2 つの方法があります。1) 文字列をその場で回転させ、syscall 4毎回呼び出すか、2) 文字列をそのままにして、一度に 1 文字ずつ出力し、代わりにインデックスを操作して回転効果を実現します。方法 1 を選択したので、それを使用します。

疑似コードを書くことから始めます。$a0に格納されている文字列を 1 文字左に回転させるサブルーチンが必要です。すぐに、文字列内の各文字を反復するある種のループについて考える必要があります。

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ので、当然のこととしましょう。少なくとも 1 つの一時レジスタが必要です。すでに$t0forを使用しているので、最初の文字を保持するためにx使用しましょう。$t1

MoveString:
lb $t1, String

インデックスレジスタも必要なので、それを使いましょう$t2。ゼロに初期化します。

li $t2, 0

アドレス レジスタを文字ごとに 1 つずつインクリメントするだけでよいのですが、$a0めちゃくちゃになるので上書きはしたくありませんPrintString$a1それをfor ループにコピーしましょう:

move $a1, $a0

最後に、文字列の長さを知る必要があるため、 の別のコピーをにロードしましょ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

これでループを開始できます。文字 (単なるバイト) を から にコピーする必要があり$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 に答える