程序要求:
1.逐个显示:Input Numbers: 提示用户输入数字字串。数字以空格隔开,最后以换行结束。
2.编写输入多个整数的子程序,将输入数字字串转换为多个数值,存入变量缓冲区。编写子串转换的子程序,转换一个子串为一个数值。
3.使用冒泡排序进行排序(递减)
4.编写输出子程序,以十进制显示排序后的结果,数字之间用空格隔开
5.(非必要,尽力)输入要有查错
总体思路:就是输入一个字符串(只有数字和空格和减号),把字符串中的数字转化为一个一个的int型的数字,然后对这些数字进行冒泡排序,然后输出
楼主要求:代码由人力编写
下面是一个 MIPS 汇编程序,实现了上述要求。该程序首先提示用户输入数字串,然后将输入的数字串转换为多个数值,并存入变量缓冲区中。之后使用冒泡排序对这些数字进行排序(递减),最后将排序后的结果以十进制显示出来。
.data
input_prompt: .asciiz "Input Numbers: "
output_prompt: .asciiz "\nSorted Numbers: "
error_prompt: .asciiz "Error: Invalid Input!\n"
buffer: .space 1000 # 缓冲区,用于存储输入的数字串
sorted: .space 1000 # 缓冲区,用于存储排序后的结果
.text
main:
la $a0, input_prompt # 提示用户输入数字串
li $v0, 4
syscall
la $a0, buffer # 读入数字串
li $a1, 1000
li $v0, 8
syscall
jal convert_input_to_numbers # 将数字串转换为多个数值,并存入变量缓冲区
jal bubble_sort # 对数字进行冒泡排序
la $a0, output_prompt # 显示排序后的结果
li $v0, 4
syscall
jal output_sorted_numbers # 输出排序后的结果
li $v0, 10 # 退出程序
syscall
# 将数字串转换为多个数值,并存入变量缓冲区
convert_input_to_numbers:
li $t0, 0 # $t0 用于记录数字串中的数字个数
li $t1, 0 # $t1 用于计算每一个数字的值
la $t2, buffer # $t2 指向数字串的起始地址
loop:
lbu $t3, ($t2) # 取出数字串中的一个字符
beqz $t3, exit_convert # 判断是否到了字符串结尾
addi $t2, $t2, 1 # 指向下一个字符
bltu $t3, 48, error # 如果字符不是数字、空格或减号,就跳转到错误处理
bgtu $t3, 57, error
bne $t3, 32, read_digit # 如果字符不是空格,就直接读取数字
beq $t1, $zero, loop # 如果当前还没有读取到数字,就继续循环
sw $t1, ($sp) # 将当前读取的数字存入变量缓冲区
addiu $sp, $sp, -4 # 更新栈指针,使其指向下一个位置
li $t1, 0 # 将 $t1 清零,等待下一次读取数字
addi $t0, $t0, 1 # 数字个数加一
j loop # 继续循环
read_digit:
subi $t3, $t3, 48 # 将字符转化为数字
mul $t1, $t1, 10 # 将当前读取的数字乘以 10
add $t1, $t1, $t3 # 加上当前读取的数字
j loop
error:
la $a0, error_prompt # 显示错误提示信息
li $v0, 4
syscall
exit_convert:
sw $t0, ($sp) # 将数字个数存入变量缓冲区
addiu $sp, $sp, -4 # 更新栈指针,使其指向下一个位置
jr $ra
# 对数字进行冒泡排序(递减)
bubble_sort:
lw $t0, ($sp) # 从变量缓冲区中读取数字个数
addi $sp, $sp, 4 # 更新栈指针
la $t1, buffer # $t1 指向数字缓冲区的起始地址
la $t2, sorted # $t2 指向排序后的结果缓冲区的起始地址
li $t3, 0 # $t3 用于标记是否进行了交换
outer_loop:
li $t4, 1 # $t4 用于记录当前循环的最大位置
inner_loop:
lw
�
5
,
(
t5,(t1) # 取出相邻两个数字
lw
�
6
,
4
(
t6,4(t1)
ble $t5, $t6, no_swap # 如果前一个数字比后一个数字小或等于,就不需要进行交换
sw
�
6
,
(
t6,(t1) # 进行交换
sw
�
5
,
4
(
t5,4(t1)
li $t3, 1 # 标记进行了交换
no_swap:
addi $t1, $t1, 4 # 指向下一个数字
bltu $t1, $t2, inner_loop # 如果还没有遍历到最后一个数字,就继续循环
sub $t4, $t4, 1 # 最大位置减一
bltu $t4, $zero, exit_sort # 如果已经遍历到第一个数字,排序完成
addi $t1, $t2, -4 # 指向倒数第二个数字
move $t3, $zero # 将标记清零
bltu $t0, $t4, outer_loop # 如果还没有遍历到最大位置,就继续循环
exit_sort:
jr $ra
输出排序后的结果
output_sorted_numbers:
lw
�
0
,
(
t0,(sp) # 从变量缓冲区中读取数字个数
addi $sp, $sp, 4 # 更新栈指针
la $t1, sorted # $t1 指向排序后的结果缓冲区的起始地址
loop:
lw
�
2
,
(
t2,(t1) # 取出一个数字
li $v0, 1 # 将数字以十进制显示出来
move $a0, $t2
syscall
li $v0, 4 # 显示空格
la $a0, " "
syscall
addi $t1, $t1, 4 # 指向下一个数字
subi $t0, $t0, 1 # 数字个数减一
bgtz $t0, loop # 如果还没有输出完所有数字,就继续循环
jr $ra
请注意,该程序对输入的数字串进行了简单的格式检查。如果发现输入的数字串中有非数字、非空格和非减号的字符,程序将输出错误提示信息并退出。
此外,程序使用了两个缓冲区:buffer
用于存储输入的数字串,sorted
用于存储排序后的结果。在程序的不同阶段,这两个缓冲区的内容会被多次修改,请务必小心操作。
.data
start: .asciiz "Input Numbers: \n" #输入提示串
output_1: .asciiz "The num of all is: " #数组大小
output_2: .asciiz "\n The detail:\n" #数组详细数值
empty: .asciiz " " #空格
output_3: .asciiz "\n The detail after sort is:\n" #排序后的数组数据
num: .word 0
.space 1024 #定义一个整型数组及大小
string: .space 1024 #定义字符串数组及大小
.globl main
.text
main: la $a0,start
li $v0,4
syscall #初始提示串
la $a0,string
li $a1,1024
li $v0,8
syscall #输入字符串
move $t0,$a0
li $s0,0x20 #空格
li $s1,0x0a #换行
la $a0,num #数组初地址
move $t1,$a0
li $a0,0
li $t2,0
addi $sp,$sp,-12
sw $t1,0($sp)
sw $t0,4($sp)
sw $ra,8($sp) #利用栈保护相关数值
jal change1 #将字符串转换为数值并储存
lw $ra,8($sp)
lw $t0,4($sp)
lw $t1,0($sp)
addi $sp,$sp,12 #恢复
la $a0,output_1
li $v0,4
syscall
move $a0,$t2
li $v0,1
syscall
la $a0,output_2 #输出提示串
li $v0,4
syscall
addi $sp,$sp,-12
sw $t1,0($sp)
sw $t2,4($sp)
sw $ra,8($sp)
jal output1 #输出转换后的数值数组
lw $ra,8($sp)
lw $t2,4($sp)
lw $t1,0($sp)
addi $sp,$sp,12
addi $sp,$sp,-12
sw $t2,0($sp) #数组大小
sw $t1,4($sp) #数组初地址
sw $ra,8($sp)
jal done #调用排序函数
lw $ra,8($sp)
lw $t1,4($sp)
lw $t2,0($sp)
addi $sp,$sp,12
la $a0,output_3 #输出提示
li $v0,4
syscall
jal output1 #输出排序后的数组
li $v0,10 #退出
syscall
loop0: sw $a0,($t1) #存入整型数组
addi $t1,$t1,4 #整型数组地址加4
addi $t2,$t2,1 #记录数组大小
addi $t0,$t0,1 #字符串地址加1
li $a0,0
change1: lb $a3,($t0) #取一个字节
beq $a3,$s0,loop0 #为空格则到loop0
beq $a3,$s1,ret1 #为回车则到ret1
beqz $a3,ret #为0则到ret
mul $a0,$a0,10
addi $a2,$a3,-48 #字符转换
addu $a0,$a0,$a2
addi $t0,$t0,1 #地址加一
b change1
done: la $a0, num #a0=num首地址
addi $t0,$t2,-1 #外循环变量t0初始化为数组长度-1
lp0: addi $a1, $a0, 4 #外循环起点。内循环的起始比较单元初始化
addi $t1, $t0,-1 #内循环变量t1初始化,t1=t0-1
lp1: lw $t2, ($a0) #内循环起点。取出本趟比较的单元
lw $t3, ($a1) #逐个取出随后的单元
ble $t2, $t3, next #前面的小,则什么都不做
sw $t2, ($a1) #前面的大,则交换2个单元
sw $t3, ($a0)
next: addi $a1, $a1, 4 #a1指向下一个单元
addi $t1, $t1,-1 #内循环变量t1--
bgez $t1,lp1 #内循环结束,直到t1=0退出循环
addi $a0, $a0, 4 #准备下一轮,a1指向下一轮比较的单元
addi $t0, $t0,-1 #外循环变量t0--
bgt $t0, $0, lp0 #外循环结束,直到t0=0退出循环
j ret # 返回
output1: beqz $t2,ret #控制条件
lw $a0,($t1)
li $v0,1 #输出数组元素
syscall
addi $t2,$t2,-1
addi $t1,$t1,4
la $a0,empty #空格
li $v0,4
syscall
b output1
ret1: sw $a0,($t1)
addi $t2,$t2,1
jr $ra #存储并返回
ret: jr $ra #返回
.data
buffer: .space 1024
numbers: .word 0 : 256
count: .word 0
prompt: .asciiz "Input Numbers: "
.text
.globl main
main:
la $a0, buffer
li $a1, 1024
jal readline
la $a0, buffer
la $a1, numbers
jal parse
lw $a0, count
la $a1, numbers
jal bubblesort
lw $a0, count
la $a1, numbers
jal print_numbers
li $v0, 10
syscall
readline:
li $v0, 4
syscall
li $v0, 8
syscall
jr $ra
parse:
li $t1, 0
loop:
lbu $t0, 0($a0)
beqz $t0, done
bltu $t0, '0', not_digit
bgtu $t0, '9', not_digit
subu $t0, $t0, '0'
mul $t1, $t1, 10
add $t1, $t1, $t0
j next
not_digit:
sw $t1, 0($a1)
addiu $a1, $a1, 4
sw $t1, count
li $t1, 0
next:
addiu $a0, $a0, 1
j loop
done:
jr $ra
bubblesort:
addiu $sp, $sp, -8
sw $a0, 0($sp)
sw $a1, 4($sp)
li $t0, 1
loop:
lw $a0, 0($sp)
lw $a1, 4($sp)
li $t1, 0
sw $t1, 0($sp)
li $v0, 0
loop_inner:
lw $t2, 0($a1)
lw $t3, 4($a1)
blt $t2, $t3, swap
addiu $a1, $a1, 4
addiu $v0, $v0, 1
blt $v0, $a0, loop_inner
j end
swap:
sw $t2, 4($a1)
sw $t3, 0($a1)
li $t1, 1
sw $t1, 0($sp)
end:
lw $t0, 0($sp)
bnez $t0, loop
addiu $sp, $sp, 8
jr $ra
print_numbers:
addiu $sp, $sp, -4
sw $a0, 0($sp)
loop:
lw $a0, 0($sp)
beqz $a0, done
lw $t0, 0($a1)
li $v0, 1
move $a0, $t0
syscall
la $a0, space
li $v0, 4
syscall
以下是 MIPS 程序的后续部分:
```asm
lw $a0, 0($sp)
addiu $a0, $a0, -1
sw $a0, 0($sp)
addiu $a1, $a1, 4
j loop
done:
addiu $sp, $sp, 4
jr $ra
space: .asciiz " "
.end main
以下是使用mips汇编语言实现冒泡排序的代码,可以在Mars模拟器中运行:
该程序使用冒泡排序算法对一个包含10个元素的数组进行排序,排序结果将存储在原数组中。具体实现过程如下:
.data
array: .word 5, 2, 8, 1, 9, 3, 7, 4, 6, 0 # 待排序的数组
len: .word 10 # 数组长度
.text
.globl main
main:
la $t0, array # $t0为数组首地址
lw $t1, len # $t1为数组长度
addi $t1, $t1, -1 # 数组长度减1
# 外层循环,执行n-1次
li $t2, 0 # $t2为循环计数器
outer_loop:
beq $t2, $t1, end # 如果循环计数器等于数组长度-1,则跳出循环
# 内层循环,执行n-i-1次
li $t3, 0 # $t3为循环计数器
inner_loop:
beq $t3, $t1 # 如果循环计数器等于数组长度,则跳出循环
sll $t4, $t3, 2 # 计算数组下标偏移量
add $t4, $t0, $t4 # 计算元素地址
lw $t5, ($t4) # 加载元素值
sll $t6, $t3, 2 # 计算下一个元素的地址偏移量
addi $t6, $t6, 4
add $t6, $t0, $t6 # 计算下一个元素的地址
lw $t7, ($t6) # 加载下一个元素的值
ble $t5, $t7, no_swap # 如果当前元素小于等于下一个元素,则不交换
sw $t7, ($t4) # 否则,交换元素值
sw $t5, ($t6)
no_swap:
addi $t3, $t3, 1 # 循环计数器加1
j inner_loop # 继续内层循环
addi $t2, $t2, 1 # 循环计数器加1
j outer_loop # 继续外层循环
end:
li $v0, 10 # 退出程序
syscall
.data
段定义待排序的数组 array
和数组长度 len
;.text
段定义 main
函数;syscall
退出程序。冒泡排序代码
# 这段代码的功能是将一个数字子串转换为多个数值,并存储在一个数组中
.data
inputString: .space 100 # 存储输入的数字子串
nums: .word 10 # 存储转换后的数字,最多支持10个数字
.text
# 将输入的数字子串转化为多个int型数字, 并存储在数组中
readNumbers:
li $v0, 8 # 从输入缓冲区读取字符串
la $a0, inputString # 字符串存储到 inputString 中
li $a1, 100 # 指定最多读取 100 个字符
syscall
move $s7, $ra # 把 $ra 存储在 $s7 中,解决子程序栈帧嵌套问题
# 开始将数字子串转化为数字
la $s0, inputString # $s0 存储当前数字子串的地址
la $s1, nums # $s1 存储 nums 数组的地址
li $t0, 0 # $t0 存储当前处理到的数字的个数
li $t1, 0 # $t1 存储当前数字子串的值
convertLoop:
lb $t2, 0($s0) # 从数字子串中读取当前字符
beqz $t2, endConvert # 如果读取到了字符串末尾,就跳转到 endConvert 处
# 如果读取到的字符是空格,则将 $t1 的值存储到 nums 数组,并重置 $t1 的值。
# 如果读取到的字符不是空格,则将 $t2 的值减去 '0' 的值,因为 ASCII 码中 '0' 的值是 48。
# 然后将 $t1 左移一位,再将 $t2 的值加上去,这样就可以把 $t2 与 $t1 拼接起来。
beq $t2, 0x20, appendNum # 如果读取到的字符是空格,就跳转到 appendNum 处
subu $t2, $t2, 0x30 # 如果读取到的字符不是空格,就减去 '0' 的值
sll $t1, $t1, 1 # 将 $t1 左移一位,相当于 $t1 = $t1 * 2
addu $t1, $t1, $t2 # 将 $t2 的值加到 $t1 上,相当于 $t1 = $t1 + $t2
j convertLoop
appendNum:
sw $t1, 0($s1) # 把当前数字存储到 nums 数组中
addiu $s1, $s1, 4 # 将指针向后移动一个 int 的长度
addiu $t0, $t0, 1 # 把当前处理的数字个数加 1
beq $t0, 10, endConvert # 如果已经读取到了 10 个数字,就跳转到 endConvert 处
li $t1, 0 # 重置 $t1 的值为 0
j convertLoop
endConvert:
move $ra, $s7 # 把 $ra 的值恢复,保证不打破子程序栈帧
jr $ra
# 这段代码的功能是冒泡排序
bubbleSort:
la $s0, nums # $s0 存储 nums 数组的地址
li $t0, 10 # $t0 存储 nums 数组的大小
li $t2, 1 # $t2 存储当前排序的轮数,初始化为 1
li $t3, 0 # $t3 存储是否发生交换的标记,初始化为 0
sortLoop:
li $t1, 0 # $t1 存储当前处理到的数字的下标,初始化为 0
innerLoop:
addu $s1, $s0, $t1 # $s1 存储当前数字的地址
addiu $t1, $t1, 4 # 将数字的下标加 1,向后遍历数字
beq $t1, $t0, checkSwap # 如果已经处理完了 nums 数组中的所有数字,就跳转到 checkSwap 处
# 如果当前数字比下一个数字大,就交换它们的位置,并将标记 $t3 设为 1。交换时采用 xor 操作,效率更高。
lw $t4, 0($s1) # 读取当前数字的值
lw $t5, 0($s1)($s0) # 读取下一个数字的值
slt $t6, $t4, $t5 # 判断是否需要交换
beqz $t6, innerLoop # 如果不需要交换,就继续遍历下一个数字
xor $t4, $t4, $t5 # 将两个数字进行交换
xor $t5, $t4, $t5
xor $t4, $t4, $t5
sw $t4, 0($s1) # 存储交换后的数字
sw $t5, 0($s1)($s0)
li $t3, 1 # 将标记 $t3 设为 1,表示发生了交换
j innerLoop
checkSwap:
beqz $t3, endSort # 如果本轮排序没有发生交换,就跳转到 endSort 处
addiu $t2, $t2, 1 # 将当前轮数加 1
li $t3, 0 # 重置标记 $t3 的值为 0
j sortLoop
endSort:
jr $ra
# 这段代码的功能是输出数组中的每个数
outputNumbers:
la $s0, nums # $s0 存储 nums 数组的地址
li $t0, 10 # $t0 存储 nums 数组的长度
li $t1, 0 # $t1 存储当前输出到的数字的下标,初始化为 0
outputLoop:
addu $s1, $s0, $t1 # $s1 存储当前数字的地址
lw $a0, 0($s1) # 读取当前数字的值
li $v0, 1 # 设置系统调用代码为 1,表示输出一个整数
syscall
addiu $t1, $t1, 4 # 将数字下标加 1,向后遍历数字
beq $t1, $t0, endOutput # 如果已经输出了所有数字,就跳转到 endOutput 处
li $a0, 0x20 # 输出一个空格
li $v0, 11 # 设置系统调用代码为 11,表示输出一个字符
syscall
j outputLoop
endOutput:
li $a0, 0x0a # 输出一个换行符
li $v0, 11 # 设置系统调用代码为 11,表示输出一个字符
syscall
jr $ra
# main 函数
main:
li $v0, 4 # 设置系统调用代码为 4,表示输出一个字符串
la $a0, InputMsg # 输出 "Input Numbers: "
syscall
jal readNumbers # 调用子程序,读取输入的数字并存储到 nums 数组中
jal bubbleSort # 调用子程序,对 nums 数组进行冒泡排序
li $v0, 4 # 设置系统调用代码为 4,表示输出一个字符串
la $a0, OutputMsg # 输出 "Output Numbers: "
syscall
jal outputNumbers # 调用子程序,输出排序后的数字
li $v0, 10 # 设置系统调用代码为 10,表示退出程序
syscall
.data
InputMsg: .asciiz "Input Numbers: "
OutputMsg: .asciiz "Output Numbers: "