We can print one character at a time — one per syscall, using syscall #11. The character to print goes in $a0. To print a newline character without using a data declaration:
li $a0, 10 # $a0 == character to print: newline '\n' (linefeed, 0xA/10)
li $v0, 11 # syscall function code #11 -- print one character
syscall
Also, often we can include the newline character, '\n' at the beginning or end of another string that we already need to printed, so the newline doesn't necessarily have to be printed separately in its own syscall.
For example, let's do the equivalent of printf("sum: %d\n, avg: %d\n", sum, avg); This printf prints 2 lines of output, i.e. uses two newline characters:
Decomposing this we get:
la $a0, sum # "sum: "
li $v0, 4 # syscall function code #4 for print string
syscall # prints "sum: "
move $a0, $s0 # assume sum in $s0, move to $a0 for syscall
li $v0, 1 # syscall function code #1 for print integer
syscall
li $a0, avg # "\n, avg: "
li $v0, 4 # syscall function code #4 for print string
syscall
move $a0, $s1 # assume avg in $s1
li $v0, 1 # syscall function code #1 for print integer
syscall
li $a0, 10
li $v0, 11
syscall
.data
sum: .asciz "sum: "
avg: .asciz "\n, avg: "
This sequence prints 2 lines of output. The first '\n' newline is appended to the beginning of the prompt/introducing string "avg: ". The second newline is printed using a syscall #11, so the whole sequence doesn't require a separate "\n" data declaration.
The printf format string is decomposed into string literals as follows:
printf("sum: %d\n, avg: %d\n", sum, avg);
^---^ ^-------^ ^
lit1 lit2 lit3
lit1 is "sum: "; lit2 is "\n, avg: "; lit3 is one character so doesn't need data. You can see that lit2 contains the end of one line and the beginnig of another, together printed in one syscall. Between lit1 and lit2 and lit3 are syscall #1's to print integers.