aboutsummaryrefslogtreecommitdiff
path: root/plusplus.s
diff options
context:
space:
mode:
Diffstat (limited to 'plusplus.s')
-rw-r--r--plusplus.s326
1 files changed, 326 insertions, 0 deletions
diff --git a/plusplus.s b/plusplus.s
new file mode 100644
index 0000000..d347a7f
--- /dev/null
+++ b/plusplus.s
@@ -0,0 +1,326 @@
+#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 $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