https://github.com/akkartik/mu/blob/master/apps/mulisp.subx
  1 # Toy lisp interpreter
  2 #
  3 # To run:
  4 #   $ ./ntranslate 0*.subx apps/subx-common.subx apps/mulisp.subx
  5 #   $ ./a.elf
  6 #   42
  7 #   => 42
  8 #   ^D
  9 #   $
 10 
 11 == code
 12 
 13 Entry:  # run tests if necessary, a REPL if not
 14     # . prolog
 15     89/<- %ebp 4/r32/esp
 16     # initialize heap
 17     (new-segment Heap-size Heap)
 18     # if (argc <= 1) goto run-main
 19     81 7/subop/compare *ebp 1/imm32
 20     7e/jump-if-lesser-or-equal $run-main/disp8
 21     # if (argv[1] != "test")) goto run-main
 22     (kernel-string-equal? *(ebp+8) "test")  # => eax
 23     3d/compare-eax-and 0/imm32
 24     74/jump-if-equal $run-main/disp8
 25     #
 26     (run-tests)
 27     # syscall(exit, *Num-test-failures)
 28     8b/-> *Num-test-failures 3/r32/ebx
 29     eb/jump $main:end/disp8
 30 $run-main:
 31     (repl Stdin Stdout)
 32     # syscall(exit, 0)
 33     bb/copy-to-ebx 0/imm32
 34 $main:end:
 35     b8/copy-to-eax 1/imm32/exit
 36     cd/syscall 0x80/imm8
 37 
 38 # type cell = nil | num | char | symbol | pair | array | stream
 39 #     tag:    0     1     2       3       4       5       6
 40 # numbers start with a digit and are always in hex
 41 # characters start with a backslash
 42 # pairs start with '('
 43 # arrays start with '['
 44 # symbols start with anything else but quote, backquote, unquote or splice
 45 
 46 repl:  # in : (address buffered-file), out : (address buffered-file) -> <void>
 47     # . prolog
 48     55/push-ebp
 49     89/<- %ebp 4/r32/esp
 50     # . save registers
 51     50/push-eax
 52 $repl:loop:
 53     (lisp-read Stdin)  # => eax : (address cell)
 54     # if (eax == 0) break
 55     3d/compare-eax-and 0/imm32
 56     74/jump-if-equal $repl:end/disp8
 57     #
 58     (lisp-eval %eax)  # => eax : (address cell)
 59     (lisp-print Stdout %eax)
 60     # loop
 61     eb/jump $repl:loop/disp8
 62 $repl:end:
 63     # . restore registers
 64     58/pop-to-eax
 65     # . epilog
 66     89/<- %esp 5/r32/ebp
 67     5d/pop-to-ebp
 68     c3/return
 69 
 70 lisp-read:  # in : (address buffered-file) -> eax : (address cell)
 71     # . prolog
 72     55/push-ebp
 73     89/<- %ebp 4/r32/esp
 74     # . save registers
 75     # var s/ecx : (address stream) = new-stream(512)
 76     81 5/subop/subtract %esp 0x200/imm32
 77     68/push 0x200/imm32/size
 78     68/push 0/imm32/read
 79     68/push 0/imm32/write
 80     89/<- %ecx 4/r32/esp
 81     #
 82     (clear-stream %ecx)
 83     (read-line-buffered *(ebp+8) %ecx)
 84     # if (s->write == 0) return null
 85     81 7/subop/compare *ecx 0/imm32
 86     75/jump-if-not-equal $lisp-read:loop/disp8
 87     b8/copy-to-eax 0/imm32/eof
 88     eb/jump $lisp-read:end/disp8
 89 $lisp-read:loop:
 90     # return s
 91     89/<- %eax 1/r32/ecx
 92 $lisp-read:end:
 93     # . reclaim locals
 94     81 0/subop/add %esp 0x20c/imm32
 95     # . restore registers
 96     # . epilog
 97     89/<- %esp 5/r32/ebp
 98     5d/pop-to-ebp
 99     c3/return
100 
101 lisp-eval:  # in : (address cell) -> eax : (address cell)
102     # . prolog
103     55/push-ebp
104     89/<- %ebp 4/r32/esp
105     # . save registers
106     8b/-> *(ebp+8) 0/r32/eax
107 $lisp-eval:end:
108     # . restore registers
109     # . epilog
110     89/<- %esp 5/r32/ebp
111     5d/pop-to-ebp
112     c3/return
113 
114 lisp-print:  # out : (address buffered-file), x : (address cell)
115     # . prolog
116     55/push-ebp
117     89/<- %ebp 4/r32/esp
118     # . save registers
119     # write(x)
120     (write-buffered Stdout "=> ")
121     (write-stream-data Stdout *(ebp+0xc))
122     (flush Stdout)
123 $lisp-print:end:
124     # . restore registers
125     # . epilog
126     89/<- %esp 5/r32/ebp
127     5d/pop-to-ebp
128     c3/return
129 
130 == data
131 
132 Nil:
133   0/imm32/tag
134   0/imm32/data