#define $hp $gp
#define $print_back $s0
#define $print_front $s1
#define $eval_back $s2
#define $eval_front $s3
.data
.align 2
CONS:
.word 2 # arity
.word 4 # name
.ascii "Cons"
.align 2
NIL:
.word 0 # arity
.word 3 # name
.ascii "Nil"
.align 2
INT:
.word 0x100 # arity
.word 3 # name
.ascii "Int"
.align 2
PRINTROOT:
.word root
.word 0 # to be filled in
EVALROOT:
.word root
.word 0 # to be filled in
.align 2
heap:
.text
main:
la $gp,heap
# NIL @ hp[0]
la $t0,NIL+2
sw $t0,($gp)
# INT 5 @ hp[4]
la $t0,INT+2
sw $t0,4($gp)
ori $t0,$0,5
sw $t0,8($gp)
# x = cons (INT 5) NIL @ hp[12]
la $t0,cons
sw $t0,12($gp)
addi $t0,$gp,4
sw $t0,16($gp)
addi $t0,$gp,0
sw $t0,20($gp)
# y = plusplus x x @ hp[24]
la $t0,plusplus
sw $t0,24($gp)
addi $t0,$gp,12
sw $t0,28($gp)
sw $t0,32($gp)
# z = plusplus y y @ hp[36]
la $t0,plusplus
sw $t0,36($gp)
addi $t0,$gp,24
sw $t0,40($gp)
sw $t0,44($gp)
# a = plusplus z z @ hp[48]
la $t0,plusplus
sw $t0,48($gp)
addi $t0,$gp,36
sw $t0,52($gp)
sw $t0,56($gp)
la $s0,PRINTROOT
addi $s1,$gp,48 # node to eval
sw $s1,4($s0)
jal driver
addi $gp,$gp,60
li $a0,'\n'
li $v0,11 # print_char
syscall
li $v0,10 # exit
syscall
driver:
addi $sp,$sp,-4
sw $ra,($sp)
print:
lw $t0,($s1)
andi $t0,$t0,2
bne $t0,$0,print_hnf
nop
la $s2,EVALROOT
addi $s3,$s1,0
sw $s3,4($s2)
jal eval
nop
addi $s1,$s3,0
print_hnf:
lw $t0,($s1)
la $t1,INT+2
beq $t0,$t1,print_int
lw $t1,2($t0) # name length
addi $t2,$t0,6 # name
add $t1,$t1,$t2
print_cons:
lw $t3,-2($t0) # arity
beq $t3,$0,print_cons_no_paren
li $a0,'('
li $v0,11 # print_char
syscall
print_cons_no_paren:
lb $a0,($t2)
li $v0,11 # print_char
syscall
addi $t2,$t2,1
bne $t1,$t2,print_cons_no_paren
nop
beq $t3,$0,print_rewind
li $a0,' '
li $v0,11 # print_char
syscall
# continue with printing the arguments
addi $t2,$s0,1
addi $s0,$s1,0
lw $s1,4($s1)
sw $t2,4($s0)
j print
nop
print_int:
lw $a0,4($s1)
li $v0,1 # print_int
syscall
j print_rewind
nop
print_rewind:
la $t5,PRINTROOT
beq $s0,$t5,print_rewind_root
addi $t0,$s0,0
addi $t1,$s0,0 # argument pointer
lw $t2,($t0)
lw $t2,-2($t2) # arity
print_rewind_loop:
addi $t1,$t1,4
lw $t3,($t1)
andi $t4,$t3,1
beq $t4,$0,print_rewind_loop
addi $t2,$t2,-1
# we have found the argument that was being printed
beq $t2,$0,print_rewind_done
# there is a next argument to print
li $a0,' '
li $v0,11 # print_char
syscall
sw $s1,($t1)
lw $s1,4($t1)
sw $t3,4($t1)
j print
nop
print_rewind_done:
# this node is fully printed; go up to the parent
li $a0,')'
li $v0,11 # print_char
syscall
xori $s0,$t3,1
sw $s1,($t1)
addi $s1,$t0,0
j print_rewind
nop
print_rewind_root:
lw $ra,($sp)
jr $ra
addi $sp,$sp,4
eval:
lw $t0,($s3)
# Exit early in case of hnf
andi $t1,$t0,2
bne $t1,$0,eval_rewind
# Walk through indirections
la $t1,indir
bne $t0,$t1,eval_indir_done
addi $t2,$s3,0
eval_indir:
lw $s3,4($s3)
lw $t0,($s3)
beq $t0,$t1,eval_indir
sw $s3,4($t2) # update original indir; optimizes chained indirs
# Check again for hnf
andi $t1,$t0,2
bne $t1,$0,eval_rewind
nop
eval_indir_done:
lw $t1,-4($t0) # load arity
lw $t2,-8($t0) # strictness
addi $t3,$s3,4 # argument pointer
eval_arg_loop:
beq $t1,$0,eval_args_done
andi $t4,$t2,1
bne $t4,$0,eval_arg_strict
srl $t2,$t2,1
addi $t1,$t1,-1
j eval_arg_loop
addi $t3,$t3,4
eval_arg_strict:
lw $t4,($t3)
lw $t4,($t4)
andi $t4,$t4,2
beq $t4,$0,eval_arg
addi $t1,$t1,-1
j eval_arg_loop
addi $t3,$t3,4
eval_arg:
lw $t4,($t3) # reverse pointers
addi $s2,$s2,1
sw $s2,($t3)
addi $s2,$s3,0
addi $s3,$t4,0
j eval # continue evaluating argument
nop
eval_args_done:
jr $t0
nop
eval_rewind:
la $t4,EVALROOT
beq $s2,$t4,eval_rewind_root
addi $t0,$s2,0
addi $t1,$s2,0
eval_rewind_loop:
addi $t1,$t1,4
lw $t2,($t1)
andi $t3,$t2,1
beq $t3,$0,eval_rewind_loop
nop
xori $s2,$t2,1
sw $s3,($t1)
addi $s3,$t0,0
j eval
nop
eval_rewind_root:
jr $ra
nop
.data
cycle_error:
.asciiz "error: cycle in spine detected\n"
.text
.word 0 # strictness
.word 1 # arity
root:
la $a0,cycle_error
li $v0,4 # print_string
syscall
break 0
.data
indir_error:
.asciiz "error: indirection evaluated\n"
.text
.word 0x1 # strictness
.word 1 # arity
indir:
# indirections are handled in eval
la $a0,indir_error
li $v0,4 # print_string
syscall
break 0
.word 0x1 # strict in 1st argument
.word 2 # arity
plusplus:
lw $t0,4($s3) # xs
lw $t1,($t0)
la $t2,NIL+2
beq $t1,$t2,plusplus_nil
nop
# TODO check heap space
lw $t1,4($t0) # hd xs
lw $t2,8($t0) # tl xs
lw $t3,8($s3) # ys
# Build node: (++ (tl xs) ys)
la $t0,plusplus
sw $t0,($gp)
sw $t2,4($gp)
sw $t3,8($gp)
# Build node: CONS (hd xs) (++ (tl xs) ys)
la $t0,CONS+2
sw $t0,12($gp)
sw $t1,16($gp)
sw $gp,20($gp)
# Update front and heap pointers
addi $s3,$gp,12
j eval
addi $gp,$gp,24
plusplus_nil:
# indirect to second argument
la $t0,indir
sw $t0,($s3)
lw $t0,8($s3)
sw $t0,4($s3)
addi $s3,$t0,0
j eval
nop
.word 0x3 # strict in 1st and 2nd argument
.word 2 # arity
cons:
# TODO check heap space
# Create new CONS node with same arguments
la $t0,CONS+2
lw $t1,4($s3)
lw $t2,8($s3)
sw $t0,($gp)
sw $t1,4($gp)
sw $t2,8($gp)
# Overwrite original cons node with indirection
la $t0,indir
sw $t0,($s3)
sw $gp,4($s3)
# Update front and heap pointers
addi $s3,$gp,0
j eval
addi $gp,$gp,12