;; s2 calculator interpreter
;; 9 feb 2007

;; register convention
;; r31  stack pointer  (system)
;; r30  display
;; r29  link register
;; r28  return value
;; r27  evaluation stack (calculator)

.symbol
  tkNum   1
  tkAdd   2
  tkSub   3
  tkMul   4
  tkDiv   5
  tkF0    6
  tkF1    7
  tkF2    8
  tkF3    9
  tkF4    10
  tkF5    11
  tkF6    12
  tkF7    13
  tkF8    14
  tkF9    15
  tkEq    16
  tkLd    17
  tkEOL   18    ;; end of line token
  VALUE   901

.code 300
  jmp jF0       ;; marker for linker of special function

;; let r1 = t, r2 = test, trap 3 return value in r28
.code 0

:loop               ;; loop until end of line
  trap 3            ;; read()
  eq r2 r28 #tkEOL
  jt r2 exit
  mv r1 r28
  jal r29 eval
  jmp loop
:exit
  trap 0

;; let r1 be input, r2 = test, r3 = temp

:eval
  push r31 r29
  push r31 r3
  eq r2 r1 #tkNum
  jt r2 xNum
  eq r2 r1 #tkAdd
  jt r2 xAdd
  eq r2 r1 #tkSub
  jt r2 xSub
  eq r2 r1 #tkMul
  jt r2 xMul
  eq r2 r1 #tkDiv
  jt r2 xDiv
  eq r2 r1 #tkF0
  jt r2 xF0
  eq r2 r1 #tkF1
  jt r2 xF1
  eq r2 r1 #tkF2
  jt r2 xF2
  eq r2 r1 #tkF3
  jt r2 xF3
  eq r2 r1 #tkF4
  jt r2 xF4
  eq r2 r1 #tkF5
  jt r2 xF5
  eq r2 r1 #tkF6
  jt r2 xF6
  eq r2 r1 #tkF7
  jt r2 xF7
  eq r2 r1 #tkF8
  jt r2 xF8
  eq r2 r1 #tkF9
  jt r2 xF9
  eq r2 r1 #tkEq
  jt r2 xEq
  eq r2 r1 #tkLd
  jt r2 xLd
:return
  pop r31 r3
  pop r31 r29
  ret r29

:evalnxt        ;; read and eval next token
  push r31 r29
  trap 3
  mv r1 r28
  jal r29 eval
  pop r31 r29
  ret r29

:evaln          ;; read, eval var arg
  push r31 r29
  mv r3 #0
  trap 3
  mv r1 r28
:while
  eq r2 r1 #tkEq  ;; until found =
  jt r2 skip
  jal r29 eval
  trap 3
  mv r1 r28
  add r3 r3 #1
  jmp while
:skip
  push r27 r3   ;; push n
  pop r31 r29
  ret r29

:xNum               ;; push value
  ld r3 VALUE
  push r27 r3
  jmp return
:xAdd               ;; get another arg then add
  jal r29 evalnxt
  jal r29 fAdd
  push r27 r28      ;; push result
  jmp return
:xSub
  jal r29 evalnxt
  jal r29 fSub
  push r27 r28
  jmp return
:xMul
  jal r29 evalnxt
  jal r29 fMul
  push r27 r28
  jmp return
:xDiv
  jal r29 evalnxt
  jal r29 fDiv
  push r27 r28
  jmp return
:xEq
  pop r27 r30        ;; pop eval stack
  trap 1             ;; print to screen
  jmp return
:xLd
  trap 4
  jmp return

:xF0
  jal r29 jF0        ;; zero arg
  push r27 r28
  jmp return
:xF1
  jal r29 evalnxt    ;; one arg
  jal r29 jF1
  push r27 r28
  jmp return
:xF2
  jal r29 evalnxt
  jal r29 jF2
  push r27 r28
  jmp return
:xF3
  jal r29 evalnxt
  jal r29 jF3
  push r27 r28
  jmp return
:xF4
  jal r29 evalnxt	;; two arg
  jal r29 evalnxt
  jal r29 jF4
  push r27 r28
  jmp return
:xF5
  jal r29 evalnxt
  jal r29 evalnxt
  jal r29 jF5
  push r27 r28
  jmp return
:xF6
  jal r29 evalnxt
  jal r29 evalnxt
  jal r29 jF6
  push r27 r28
  jmp return
:xF7
  jal r29 evalnxt
  jal r29 evalnxt
  jal r29 jF7
  push r27 r28
  jmp return
:xF8
  jal r29 evaln     ;; var arg
  jal r29 jF8
  push r27 r28
  mv r30 r28
  trap 1
  jmp return
:xF9
  jal r29 evaln
  jal r29 jF9
  push r27 r28
  mv r30 r28
  trap 1
  jmp return

;; jump table to link dynamic load object

:jF0 jmp return
:jF1 jmp return
:jF2 jmp return
:jF3 jmp return
:jF4 jmp return
:jF5 jmp return
:jF6 jmp return
:jF7 jmp return
:jF8 jmp return
:jF9 jmp return

;; subroutine to do basic functions
;; use r1 r2, return result in r28

:fAdd
  push r31 r1
  push r31 r2
  pop r27 r2
  pop r27 r1
  add r28 r1 r2
  pop r31 r2
  pop r31 r1
  ret r29
:fSub
  push r31 r1
  push r31 r2
  pop r27 r2
  pop r27 r1
  sub r28 r1 r2
  pop r31 r2
  pop r31 r1
  ret r29
:fMul
  push r31 r1
  push r31 r2
  pop r27 r2
  pop r27 r1
  mul r28 r1 r2
  pop r31 r2
  pop r31 r1
  ret r29
:fDiv
  push r31 r1
  push r31 r2
  pop r27 r2
  pop r27 r1
  div r28 r1 r2
  pop r31 r2
  pop r31 r1
  ret r29

;; subroutines to do special functions

;; f0..f9

.end
