Замените каждый символ слова числом заглавных букв в этом слове. - PullRequest
0 голосов
/ 11 ноября 2018

Я хочу добиться поддержки нескольких слов.

например. abc AAAA cbAAaa => 000 4444 222222

На данный момент программа выполняет только преобразование первого слова.

Начиная с отладчика в симуляторе Mars, кажется, что он делает все циклы правильно. То же самое для значений регистров. (Может я что то упускаю) Я предполагаю, что слова должны быть короче, чем 10 символов.

Если кто-то может заметить ошибку, я был бы благодарен. Также, если у вас есть какие-либо советы по отладке этого или улучшения кода, не стесняйтесь сказать.

Мой код:

    .data
prompt: .asciiz "Enter a string: "
msgout: .asciiz "Output string: "
input:  .space  256
output: .space  256
    .text
    .globl main

main:
    li  $v0, 4          # Print enter a string prompt
    la  $a0, prompt     
    syscall

    li  $v0, 8          # Ask the user for the string they want to reverse
    la  $a0, input      # We'll store it in 'input'
    li  $a1, 256        # Only 256 chars/bytes allowed
    syscall

    la  $t2, ($a0)      # t2 - input string

    word:
        li  $t1, 0              # Normal counter
        li  $t5, 0              # Uppercase counter
        li  $t6, 0              # First letter of word
        j   word_countUppercase
        word_precountUppercase:
            addi    $t1, $t1, 1             # Add 1 to index to avoid space in next word
            la  $t6, ($t1)              # Set t6 to the first index of t2 (start of word)
            la  $t5, 0                  # $t5 - 0
        word_countUppercase:
            #addi   $t1, $t1, $t7
            add $t3, $t2, $t1               # $t2 is the base address for our 'input' array, add loop index
            lb  $t4, 0($t3)             # load a byte at a time according to counter

            beq     $t4, ' ', word_prereplace       # We found end of word
            bltu    $t4, ' ', word_prereplace       # We found end of string    

            addi    $t1, $t1, 1             # Advance our counter (i++)

            bltu    $t4, 'A', word_countUppercase
            bgtu    $t4, 'Z', word_countUppercase

            addi    $t5, $t5, 1                 # Advance our counter (i++)
            j   word_countUppercase

        word_prereplace:
            la  $t2, ($a0)              # t2 - input string
            la  $t1, ($t6)              # Normal counter
            addi $t5, $t5, '0'

            word_replace:
                add $t3, $t2, $t1           # $t2 is the base address for our 'input' array, add loop index
                lb  $t4, 0($t3)         # load a byte at a time according to counter    

                beq $t4, ' ', word_replaceExit  # end of the word
                bltu    $t4, ' ', exit          # We found end of string    

                sb  $t5, output($t1)        # Overwrite this byte address in memory 

                addi    $t1, $t1, 1             # Advance our counter (i++)
                j   word_replace
            word_replaceExit:
                j   word_precountUppercase



exit:
    li  $v0, 4          # Print msgout
    la  $a0, msgout
    syscall

    li  $v0, 4          # Print the output string!
    la  $a0, output
    syscall

    li  $v0, 10         # exit()
    syscall

Ответы [ 2 ]

0 голосов
/ 11 ноября 2018

РЕДАКТИРОВАТЬ: ответ на исходный вопрос состоял в том, что исходный код заполнял выходной буфер только байтами, соответствующими содержанию слов, но оставлял неопределенную память между ними, что обнуляется в симуляторе MARS, поэтому случайно был нулевой терминаторпосле первого слова, и служба «print string» в MARS действительно ожидает строки с нулевым символом в конце = было напечатано только первое слово.


Вот мой вариант для той же задачи, используя различные сочетания клавиш для выполнениято же самое в (незначительно) меньшем количестве инструкций (это все еще сложность O (N)).

Также я написал это таким образом, чтобы обеспечить правильную работу ввода с несколькими пробелами, начиная / заканчивая пробелом или пустым вводом (для «двух пробелов» при вводе он также выведет «два пробела») (я не проверял все это с вашим исходным кодом, поэтому я не говорю, что есть какая-то ошибка, кажется, она должна хорошо обрабатывать большинство из них,Я только что тщательно проверил только мой вариант):

# delayed branching should be OFF
.data
prompt: .asciiz "Enter a string: "
msgout: .asciiz "Output string: "
input:  .space  256
output: .space  256
    .text
    .globl main

main:
    li  $v0, 4          # Print enter a string prompt
    la  $a0, prompt
    syscall

    li  $v0, 8          # Ask the user for the string they want to reverse
    la  $a0, input      # We'll store it in 'input'
    li  $a1, 256        # Only 256 chars/bytes allowed
    syscall

    la    $a1, output
    # a0 = input, a1 = output
new_word:
    move  $t0, $zero    # t0 word length = 0
    li    $t1, '0'      # t1 uppercase counter = '0' (ASCII counter)
word_parse_loop:
    lbu   $t2, ($a0)    # next input character
    addi  $a0, $a0, 1   # advance input pointer
    bltu  $t2, 33, word_done   # end of word detected (space or newline)
      # "less than 33" to get shorter code than for "less/equal than 32"
    addi  $t0, $t0, 1   # ++word length
    # check if word character is uppercase letter
    addiu $t2, $t2, -65 # subtract 'A' => makes t2 = 0..25 for 'A'..'Z'
    sltiu $t3, $t2, 26  # t3 = (t2 < 26) ? 1 : 0
    add   $t1, $t1, $t3 # ++uppercase counter if uppercase detected
    j     word_parse_loop

word_output_fill:
    # loop to fill output with uppercase-counter (entry is "word_done" below)
    sb    $t1, ($a1)
    addi  $a1, $a1, 1
    addiu $t0, $t0, -1
word_done:
    # t0 = word length, t1 = uppercase ASCII counter, t2 = space, newline or less
    # a0 = next word (or beyond data), a1 = output pointer (to be written to)
    bnez  $t0, word_output_fill

    bltu  $t2, ' ', it_was_last_word
    # t2 == space, move onto next word in input (store space also in output)
    sb    $t2, ($a1)
    addi  $a1, $a1, 1
    j     new_word

it_was_last_word:
    # finish output data by storing zero terminator
    sb    $zero, ($a1)

    # output result
    li  $v0, 4          # Print msgout
    la  $a0, msgout
    syscall

    li  $v0, 4          # Print the output string!
    la  $a0, output
    syscall

    li  $v0, 10         # exit()
    syscall

Что нужно отметить («хитрости»?):

  • uppeСчетчик rcase начинается со значения 48 (символ для нуля), поэтому «счетчик» все время содержит цифру ASCII (для счета меньше 10, для 10+ он переходит к другим символам, кроме цифр) и готов кзаписывается в строку без какого-либо преобразования (так как счетчик нигде не используется как «целое число», вы можете оптимизировать преобразование следующим образом).
  • он последовательно проходит через ввод и вывод, никогда не читая некоторые данные дваждыили перенастройка позиции ввода / вывода, поэтому алгоритм, подобный этому, может работать также с данными, подобными «потоку» (он почти производит вывод 1: 1 для каждого входного символа, за исключением того, что вывод слегка задерживается «на слово», то есть он будет обрабатыватьвходной поток до «конца слова», затем создается целое выходное слово (эта архитектура может быть важна для некоторых входов / выходов, таких как магнитные ленты на входе и последовательный принтер на выходе).
  • проверка на A.Диапазон букв в верхнем регистре .Z использует только одно условие сравнения (буква 'A' вычитается из символасначала введите cter, нормализуя значение в 0..25 для заглавных букв, а все остальное, когда рассматривается как целое число без знака, должно иметь значение больше 25, поэтому для обнаружения всех заглавных букв достаточно одного < 26 теста.
  • счетчик в верхнем регистре обновляется каждый раз, добавляя либо 0, либо 1 (в зависимости от ранее упомянутого условия), что позволяет избежать дополнительных ветвлений в коде.Как правило, современные процессоры предпочитают больше кода без ветвления, поскольку они могут более агрессивно кэшировать / спекулировать впереди, поэтому в случаях, когда вероятность ветвления больше, чем 50%, вариант кода без ветвления обычно имеет лучшую производительность (для случаев, когда ветвлениенапример, 5-10% шансов, что ответвление от этого необычного условия и оставаться в очереди для общего случая может быть лучше, например, такие вещи, как «конец слова»).

Или, если у вас есть какие-либоДругой вопрос, касающийся конкретной части кода, не стесняйтесь задавать.

0 голосов
/ 11 ноября 2018

У меня были пустые пробелы в выводе, поэтому строка была: 111 [] 222 [] 1111, и print делала это с первым пустым пространством, поэтому 111 только.

Чтобы исправить это, я добавил этот код: (перед словом label)

li  $t1, 0                  # Normal counter
    rewriteoutput:
        add $t3, $t2, $t1           # $t2 is the base address for our 'input' array, add loop index
        lb  $t4, 0($t3)         # load a byte at a time according to counter

        bltu    $t4, ' ', word          # We found end of string

        sb  $t4, output($t1)        # Overwrite this byte address in memory
        addi    $t1, $t1, 1             # Advance our counter (i++)
        j rewriteoutput

Я знаю, что мы, вероятно, можем сделать это лучше, но не могу понять, почему я не могу сделать

sw $a0, output

вместо него (Ошибка во время выполнения: исключение времени выполнения в 0x0040002c: адрес магазина не выровнен по границе слова 0x10010121)

...