aboutsummaryrefslogblamecommitdiff
path: root/plusplus.s
blob: 02e6707bbfaf61db250f8abd4403513cf3884582 (plain) (tree)















































































                                              

                                    



















































































































































































































































                                                                                 
#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