2015-08-25 2 views
0

Я новичок в сборке MIPS, я хочу написать процедуру, которая берет адрес памяти строки и адрес памяти другой подпрограммы обратного вызова. Эта процедура будет проходить через каждую букву в строке и для каждой буквы вызовет подпрограмму (это печатает значение ASCII каждой буквы). Псевдо-код будет выглядеть примерно так:Вызов подпрограммы для каждого символа в строке - MIPS

string_for_each(string, subroutine) { 
    for_each_character_in_string { 
    subroutine(address_of(character)) 
    } 
} 

Это то, что мои рутинные выглядит как прямо сейчас:

string_for_each: 

    addi $sp, $sp, -4   # PUSH return address to caller 
    sw $ra, 0($sp) 

    jal loop 

    lw $ra, 0($sp)     # Pop return address to caller 
    addi $sp, $sp, 4 

    jr $ra 

loop: 

    lb $t1, 0($a0)     # Get current character 
    beq $t1, $zero, end_for_each # Done when reaching NULL character 
    jr $a1       # Call callback subroutine 
    addi $a0, $a0, 1    # Increment to get next character in string 
    j loop 

end_for_each: 

    jr $ra       # Return to caller 

Дело в том, что регистр $ a0 содержит адрес в строку, и $ a1 содержит адрес подпрограммы обратного вызова, а адрес текущего символа в строке, которая будет передана подпрограмме обратного вызова, также должна быть в $ a0. Как $ a0 может содержать как начальный адрес строки, так и текущий символ одновременно?

Подпрограмма обратного вызова:

ascii: 
    .data 
STR_the_ascii_value_is: 
    .asciiz "\nAscii('X') = " 

    .text 

    la $t0, STR_the_ascii_value_is 

    # Replace X with the input character 

    add $t1, $t0, 8 # Position of X 
    lb $t2, 0($a0) # Get the Ascii value 
    sb $t2, 0($t1) 

    # Print "The Ascii value of..." 

    add $a0, $t0, $zero 
    li $v0, 4 
    syscall 

    # Append the Ascii value 

    add $a0, $t2, $zero 
    li $v0, 1 
    syscall 


    jr $ra 
+0

_ «? Как $ a0 содержать как начальный адрес строки и текущий символ в то же время» _ Почему не только увеличивает '$ a0' в конце каждая итерация? – Michael

+0

Вам нужно будет сохранить '$ a0' и' $ a1' в другом месте (обычно стек) на время вызова подпрограммы. – Jester

+0

@Michael Да, я пытался что-то вроде этого, чтобы перебирать строку: фунтов \t $ t1, 0 ​​($ a0) Beq $ t1, $ ноль, конец Адди $ a0, $ a0, 1 ​​ Но текущий символ хранится в $ t1 таким образом? – froli

ответ

1

Вам нужно будет сохранить $a0 и $a1 в другом месте (обычно укладывают) на время вызова подпрограммы. Кроме того, ваш loop не является подпрограммой, нет причин для вызова, используя jal. С другой стороны, обратный вызов - это подпрограмма, вы должны позвонить ему, используя jalr. Что-то вдоль этих линий должно работать:

string_for_each: 

    addiu $sp, $sp, -12    # Need 3 locals for $a0, $a1 and $ra 
    sw $ra, 0($sp)     # Store $ra 
    sw $a1, 8($sp)     # Store $a1 

loop: 
    sw $a0, 4($sp)     # Store $a0 as it will be used for argument 
    lb $t0, 0($a0)     # Get current character 
    beq $t0, $zero, end_for_each # Done when reaching NULL character 
    jalr $a1      # Call callback subroutine 
    lw $a0, 4($sp)     # Reload $a0 
    lw $a1, 8($sp)     # $a1 could have changed (calling convention) 
    addi $a0, $a0, 1    # Increment to get next character in string 
    j loop 

end_for_each: 
    lw $ra, 0($sp)     # Reload return address to caller 
    addiu $sp, $sp, 12    # Free locals 
    jr $ra 
+0

А, я вижу! Это имеет больший смысл. Спасибо! – froli

+0

При запуске кода я получаю сообщение об ошибке «Исключение произошло на ПК = 0x0040027c», которое находится в строке 'lb $ t2, 0 ($ a0) # Получить значение Ascii' в подпрограмме обратного вызова (я добавил код для эта подпрограмма обратного вызова, '$ a1', в вопросе). За этим следует ошибка «Плохой адрес в данных/стеке: 0x00000041'. Я не уверен, что это значит, любая идея? Пробовал играть с кодом, но сообщения об ошибках остаются. – froli

+1

О, извините, я написал код, чтобы он передавал действительный символ, а не адрес обратного вызова. Исправлен код. – Jester

Смежные вопросы