From efae9496be7fec29baeffacb5c458b3534e71584 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Tue, 29 Oct 2019 22:39:47 -0700 Subject: 5723 --- html/apps/mu.subx.html | 666 +++++++++++++++++++++++++++++++++++++++++++++ html/apps/mulisp.subx.html | 2 +- 2 files changed, 667 insertions(+), 1 deletion(-) create mode 100644 html/apps/mu.subx.html (limited to 'html/apps') diff --git a/html/apps/mu.subx.html b/html/apps/mu.subx.html new file mode 100644 index 00000000..e7d6bf0a --- /dev/null +++ b/html/apps/mu.subx.html @@ -0,0 +1,666 @@ + + + + +Mu - apps/mu.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/master/apps/mu.subx +
+  1 # Mu's level-2 language, also called Mu.
+  2 # http://akkartik.name/post/mu-2019-2
+  3 #
+  4 # To run:
+  5 #   $ ./ntranslate init.linux 0*.subx apps/mu.subx
+  6 
+  7 # A sketch of planned data structures. Still highly speculative.
+  8 == data
+  9 
+ 10 # A program is currently a linked list of functions
+ 11 Program:  # (address function)
+ 12   0/imm32
+ 13 
+ 14 # A function consists of:
+ 15 #   name: (address string)
+ 16 #   inputs: (address var-type)  # tbd
+ 17 #   outputs: (address var-type)  # tbd
+ 18 #   body: (address block)
+ 19 #   next: (address function)
+ 20 Function-next:
+ 21   0x10/imm32
+ 22 Function-size:
+ 23   0x14/imm32/20
+ 24 
+ 25 # A block is a list of statements:
+ 26 #     statements: (address statement)
+ 27 
+ 28 # A statement can be either a regular statement consisting of:
+ 29 #     name: (address string)
+ 30 #     inputs: (address var)
+ 31 #     outputs: (address var-r)
+ 32 # or a variable declaration on the stack:
+ 33 #     name: (address string)
+ 34 #     type: (address type-sexpr)
+ 35 # or a regular statement writing to a single new variable in a register:
+ 36 #     name: (address string)
+ 37 #     inputs: (address var)
+ 38 #     output: var-r
+ 39 # or a block of statements:
+ 40 #     statements: (address statement)
+ 41 
+ 42 # Kinds of local variable declarations:
+ 43 #   var f : (array foo 10)
+ 44 #   var f/ecx : int <- copy 0
+ 45 # Variables live in either the stack or a register.
+ 46 # Variables in the stack are auto-initialized.
+ 47 #   (This is non-trivial for arrays, and arrays inside structs... We'll see.)
+ 48 # Variables in register need a real instruction.
+ 49 
+ 50 # var is a variable declaration. e.g. `foo: (array int 3)`
+ 51 #   name: (address string)
+ 52 #   type: (address type-sexpr)
+ 53 
+ 54 # var-r is a variable declaration in a register. e.g. `foo/eax: (array int 3)`
+ 55 #   name: (address string)
+ 56 #   type: (address type-sexpr)
+ 57 #   reg: int [0..7]
+ 58 
+ 59 # type-sexpr is a tree of type identifiers. e.g. (array (address int) 3)
+ 60 # either
+ 61 #   id: type-identifier
+ 62 # or
+ 63 #   car: (address type-sexpr)
+ 64 #   cdr: (address type-sexpr)
+ 65 
+ 66 # Still todo:
+ 67 #   heap allocations (planned name: 'handle')
+ 68 #   user-defined types: 'type' for structs, 'choice' for unions
+ 69 #   short-lived 'address' type for efficiently writing inside nested structs
+ 70 
+ 71 == code
+ 72 
+ 73 Entry:
+ 74     # . prologue
+ 75     89/<- %ebp 4/r32/esp
+ 76     (new-segment Heap-size Heap)
+ 77     # if (argv[1] == "test') run-tests()
+ 78     {
+ 79       # if (argc <= 1) break
+ 80       81 7/subop/compare *ebp 1/imm32
+ 81       7e/jump-if-lesser-or-equal break/disp8
+ 82       # if (argv[1] != "test")) break
+ 83       (kernel-string-equal? *(ebp+8) "test")  # => eax
+ 84       3d/compare-eax-and 0/imm32
+ 85       74/jump-if-equal break/disp8
+ 86       #
+ 87       (run-tests)
+ 88       # syscall(exit, *Num-test-failures)
+ 89       8b/-> *Num-test-failures 3/r32/ebx
+ 90       eb/jump $mu-main:end/disp8
+ 91     }
+ 92     # otherwise convert Stdin
+ 93     (convert-mu Stdin Stdout)
+ 94     (flush Stdout)
+ 95     # syscall(exit, 0)
+ 96     bb/copy-to-ebx 0/imm32
+ 97 $mu-main:end:
+ 98     b8/copy-to-eax 1/imm32/exit
+ 99     cd/syscall 0x80/imm8
+100 
+101 convert-mu:  # in : (address buffered-file), out : (address buffered-file)
+102     # . prologue
+103     55/push-ebp
+104     89/<- %ebp 4/r32/esp
+105     #
+106     (parse-mu *(ebp+8))
+107     (check-mu-types)
+108     (emit-subx *(ebp+0xc))
+109 $convert-mu:end:
+110     # . epilogue
+111     89/<- %esp 5/r32/ebp
+112     5d/pop-to-ebp
+113     c3/return
+114 
+115 test-convert-empty-input:
+116     # empty input => empty output
+117     # . prologue
+118     55/push-ebp
+119     89/<- %ebp 4/r32/esp
+120     # setup
+121     (clear-stream _test-input-stream)
+122     (clear-stream _test-input-buffered-file->buffer)
+123     (clear-stream _test-output-stream)
+124     (clear-stream _test-output-buffered-file->buffer)
+125     #
+126     (convert-mu _test-input-buffered-file _test-output-buffered-file)
+127     (flush _test-output-buffered-file)
+128     (check-stream-equal _test-output-stream "" "F - test-convert-empty-input")
+129     # . epilogue
+130     89/<- %esp 5/r32/ebp
+131     5d/pop-to-ebp
+132     c3/return
+133 
+134 test-convert-function-skeleton:
+135     # empty function decl => function prologue and epilogue
+136     #   fn foo {
+137     #   }
+138     # =>
+139     #   foo:
+140     #     # . prologue
+141     #     55/push-ebp
+142     #     89/<- %ebp 4/r32/esp
+143     #     # . epilogue
+144     #     89/<- %esp 5/r32/ebp
+145     #     5d/pop-to-ebp
+146     #     c3/return
+147     # . prologue
+148     55/push-ebp
+149     89/<- %ebp 4/r32/esp
+150     # setup
+151     (clear-stream _test-input-stream)
+152     (clear-stream _test-input-buffered-file->buffer)
+153     (clear-stream _test-output-stream)
+154     (clear-stream _test-output-buffered-file->buffer)
+155     #
+156     (write _test-input-stream "fn foo {\n")
+157     (write _test-input-stream "}\n")
+158     # convert
+159     (convert-mu _test-input-buffered-file _test-output-buffered-file)
+160     (flush _test-output-buffered-file)
+161 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------
+167     # check output
+168     (check-next-stream-line-equal _test-output-stream "foo:"                  "F - test-convert-function-skeleton/0")
+169     (check-next-stream-line-equal _test-output-stream "# . prologue"          "F - test-convert-function-skeleton/1")
+170     (check-next-stream-line-equal _test-output-stream "55/push-ebp"           "F - test-convert-function-skeleton/2")
+171     (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp"  "F - test-convert-function-skeleton/3")
+172     (check-next-stream-line-equal _test-output-stream "# . epilogue"          "F - test-convert-function-skeleton/4")
+173     (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp"  "F - test-convert-function-skeleton/5")
+174     (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp"         "F - test-convert-function-skeleton/6")
+175     (check-next-stream-line-equal _test-output-stream "c3/return"             "F - test-convert-function-skeleton/7")
+176     # . epilogue
+177     89/<- %esp 5/r32/ebp
+178     5d/pop-to-ebp
+179     c3/return
+180 
+181 test-convert-multiple-function-skeletons:
+182     # multiple functions correctly organized into a linked list
+183     #   fn foo {
+184     #   }
+185     #   fn bar {
+186     #   }
+187     # =>
+188     #   foo:
+189     #     # . prologue
+190     #     55/push-ebp
+191     #     89/<- %ebp 4/r32/esp
+192     #     # . epilogue
+193     #     89/<- %esp 5/r32/ebp
+194     #     5d/pop-to-ebp
+195     #     c3/return
+196     #   bar:
+197     #     # . prologue
+198     #     55/push-ebp
+199     #     89/<- %ebp 4/r32/esp
+200     #     # . epilogue
+201     #     89/<- %esp 5/r32/ebp
+202     #     5d/pop-to-ebp
+203     #     c3/return
+204     # . prologue
+205     55/push-ebp
+206     89/<- %ebp 4/r32/esp
+207     # setup
+208     (clear-stream _test-input-stream)
+209     (clear-stream _test-input-buffered-file->buffer)
+210     (clear-stream _test-output-stream)
+211     (clear-stream _test-output-buffered-file->buffer)
+212     #
+213     (write _test-input-stream "fn foo {\n")
+214     (write _test-input-stream "}\n")
+215     (write _test-input-stream "fn bar {\n")
+216     (write _test-input-stream "}\n")
+217     # convert
+218     (convert-mu _test-input-buffered-file _test-output-buffered-file)
+219     (flush _test-output-buffered-file)
+220 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------
+226     # check first function
+227     (check-next-stream-line-equal _test-output-stream "foo:"                  "F - test-convert-multiple-function-skeletons/0")
+228     (check-next-stream-line-equal _test-output-stream "# . prologue"          "F - test-convert-multiple-function-skeletons/1")
+229     (check-next-stream-line-equal _test-output-stream "55/push-ebp"           "F - test-convert-multiple-function-skeletons/2")
+230     (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/3")
+231     (check-next-stream-line-equal _test-output-stream "# . epilogue"          "F - test-convert-multiple-function-skeletons/4")
+232     (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/5")
+233     (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/6")
+234     (check-next-stream-line-equal _test-output-stream "c3/return"             "F - test-convert-multiple-function-skeletons/7")
+235     # check second function
+236     (check-next-stream-line-equal _test-output-stream "bar:"                  "F - test-convert-multiple-function-skeletons/10")
+237     (check-next-stream-line-equal _test-output-stream "# . prologue"          "F - test-convert-multiple-function-skeletons/11")
+238     (check-next-stream-line-equal _test-output-stream "55/push-ebp"           "F - test-convert-multiple-function-skeletons/12")
+239     (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/13")
+240     (check-next-stream-line-equal _test-output-stream "# . epilogue"          "F - test-convert-multiple-function-skeletons/14")
+241     (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/15")
+242     (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/16")
+243     (check-next-stream-line-equal _test-output-stream "c3/return"             "F - test-convert-multiple-function-skeletons/17")
+244     # . epilogue
+245     89/<- %esp 5/r32/ebp
+246     5d/pop-to-ebp
+247     c3/return
+248 
+249 parse-mu:  # in : (address buffered-file)
+250     # pseudocode
+251     #   var curr-function = Program
+252     #   var line : (stream byte 512)
+253     #   var word-slice : slice
+254     #   while true                                  # line loop
+255     #     clear-stream(line)
+256     #     read-line-buffered(in, line)
+257     #     if (line->write == 0) break               # end of file
+258     #     while true                                # word loop
+259     #       word-slice = next-word-or-string(line)
+260     #       if slice-empty?(word-slice)             # end of line
+261     #         break
+262     #       else if slice-starts-with?(word-slice, "#")  # comment
+263     #         break                                 # end of line
+264     #       else if slice-equal(word-slice, "fn")
+265     #         var curr-function/ecx : (address function)
+266     #       else
+267     #         abort()
+268     #
+269     # . prologue
+270     55/push-ebp
+271     89/<- %ebp 4/r32/esp
+272     # . save registers
+273     50/push-eax
+274     51/push-ecx
+275     52/push-edx
+276     57/push-edi
+277     # var line/ecx : (stream byte 512)
+278     81 5/subop/subtract %esp 0x200/imm32
+279     68/push 0x200/imm32/length
+280     68/push 0/imm32/read
+281     68/push 0/imm32/write
+282     89/<- %ecx 4/r32/esp
+283     # var word-slice/edx : slice
+284     68/push 0/imm32/end
+285     68/push 0/imm32/start
+286     89/<- %edx 4/r32/esp
+287     # var curr-function/edi : (address function) = Program
+288     bf/copy-to-edi Program/imm32
+289     {
+290 $parse-mu:line-loop:
+291       (clear-stream %ecx)
+292       (read-line-buffered *(ebp+8) %ecx)
+293       # if (line->write == 0) break
+294       81 7/subop/compare *ecx 0/imm32
+295       0f 84/jump-if-equal break/disp32
+296 +--  6 lines: #?       # dump line ---------------------------------------------------------------------------------------------------------------------------
+302       { # word loop
+303 $parse-mu:word-loop:
+304         (next-word-or-string %ecx %edx)
+305         # if (slice-empty?(word-slice)) break
+306         (slice-empty? %edx)
+307         3d/compare-eax-and 0/imm32
+308         0f 85/jump-if-not-equal break/disp32
+309         # if (*word-slice->start == "#") break
+310         # . eax = *word-slice->start
+311         8b/-> *edx 0/r32/eax
+312         8a/copy-byte *eax 0/r32/AL
+313         81 4/subop/and %eax 0xff/imm32
+314         # . if (eax == '#') break
+315         3d/compare-eax-and 0x23/imm32/hash
+316         0f 84/jump-if-equal break/disp32
+317         # if slice-equal?(word-slice, "fn")
+318         {
+319           (slice-equal? %edx "fn")
+320           3d/compare-eax-and 0/imm32
+321           0f 84/jump-if-equal break/disp32
+322           # var new-function/eax : (address function) = populate-mu-function()
+323           (allocate Heap *Function-size)  # => eax
+324           (populate-mu-function-header %ecx %eax)
+325           (populate-mu-function-body *(ebp+8) %eax)
+326           # *curr-function = new-function
+327           89/<- *edi 0/r32/eax
+328           # curr-function = &new-function->next
+329           8d/address-> *(eax+0x10) 7/r32/edi
+330           e9/jump $parse-mu:word-loop/disp32
+331         }
+332         # otherwise abort
+333         e9/jump $parse-mu:abort/disp32
+334       } # end word loop
+335       e9/jump loop/disp32
+336     } # end line loop
+337 $parse-mu:end:
+338     # . reclaim locals
+339     81 0/subop/add %esp 0x214/imm32
+340     # . restore registers
+341     5f/pop-to-edi
+342     5a/pop-to-edx
+343     59/pop-to-ecx
+344     58/pop-to-eax
+345     # . epilogue
+346     89/<- %esp 5/r32/ebp
+347     5d/pop-to-ebp
+348     c3/return
+349 
+350 $parse-mu:abort:
+351     # error("unexpected top-level command: " word-slice "\n")
+352     (write-buffered Stderr "unexpected top-level command: ")
+353     (write-buffered Stderr %edx)
+354     (write-buffered Stderr "\n")
+355     (flush Stderr)
+356     # . syscall(exit, 1)
+357     bb/copy-to-ebx  1/imm32
+358     b8/copy-to-eax  1/imm32/exit
+359     cd/syscall  0x80/imm8
+360     # never gets here
+361 
+362 # errors considered:
+363 #   fn foo { {
+364 #   fn foo { }
+365 #   fn foo { } {
+366 #   fn foo  # no block
+367 populate-mu-function-header:  # first-line : (address stream byte), out : (address function)
+368     # . prologue
+369     55/push-ebp
+370     89/<- %ebp 4/r32/esp
+371     # . save registers
+372     50/push-eax
+373     51/push-ecx
+374     57/push-edi
+375     # edi = out
+376     8b/-> *(ebp+0xc) 7/r32/edi
+377     # var word-slice/ecx : slice
+378     68/push 0/imm32/end
+379     68/push 0/imm32/start
+380     89/<- %ecx 4/r32/esp
+381     # save function name
+382     (next-word *(ebp+8) %ecx)
+383     (slice-to-string Heap %ecx)  # => eax
+384     89/<- *edi 0/r32/eax
+385     # assert that next token is '{'
+386     (next-word *(ebp+8) %ecx)
+387     (slice-equal? %ecx "{")
+388     3d/compare-eax-and 0/imm32
+389     74/jump-if-equal $populate-mu-function-header:abort/disp8
+390     # assert that there's no further token
+391     {
+392       # word-slice = next-word(line)
+393       (next-word *(ebp+8) %ecx)
+394       # if (word-slice == '') break
+395       (slice-empty? %ecx)
+396       3d/compare-eax-and 0/imm32
+397       75/jump-if-not-equal break/disp8
+398       # if (slice-starts-with?(word-slice, "#")) break
+399       # . eax = *word-slice->start
+400       8b/-> *edx 0/r32/eax
+401       8a/copy-byte *eax 0/r32/AL
+402       81 4/subop/and %eax 0xff/imm32
+403       # . if (eax == '#') break
+404       3d/compare-eax-and 0x23/imm32/hash
+405       74/jump-if-equal break/disp8
+406       # otherwise abort
+407       eb/jump $populate-mu-function-header:abort/disp8
+408     }
+409 $populate-mu-function-header:end:
+410     # . reclaim locals
+411     81 0/subop/add %esp 8/imm32
+412     # . restore registers
+413     5f/pop-to-edi
+414     59/pop-to-ecx
+415     58/pop-to-eax
+416     # . epilogue
+417     89/<- %esp 5/r32/ebp
+418     5d/pop-to-ebp
+419     c3/return
+420 
+421 $populate-mu-function-header:abort:
+422     # error("function header not in form 'fn <name> {'")
+423     (write-buffered Stderr "function header not in form 'fn <name> {' -- '")
+424     (rewind-stream *(ebp+8))
+425     (write-stream 2 *(ebp+8))
+426     (write-buffered Stderr "'\n")
+427     (flush Stderr)
+428     # . syscall(exit, 1)
+429     bb/copy-to-ebx  1/imm32
+430     b8/copy-to-eax  1/imm32/exit
+431     cd/syscall  0x80/imm8
+432     # never gets here
+433 
+434 # errors considered:
+435 #   { abc
+436 populate-mu-function-body:  # in : (address buffered-file), out : (address function)
+437     # . prologue
+438     55/push-ebp
+439     89/<- %ebp 4/r32/esp
+440     # . save registers
+441     50/push-eax
+442     51/push-ecx
+443     52/push-edx
+444     53/push-ebx
+445     # var line/ecx : (stream byte 512)
+446     81 5/subop/subtract %esp 0x200/imm32
+447     68/push 0x200/imm32/length
+448     68/push 0/imm32/read
+449     68/push 0/imm32/write
+450     89/<- %ecx 4/r32/esp
+451     # var word-slice/edx : slice
+452     68/push 0/imm32/end
+453     68/push 0/imm32/start
+454     89/<- %edx 4/r32/esp
+455     # var open-curly-count/ebx : int = 1
+456     bb/copy-to-ebx 1/imm32
+457     { # line loop
+458 $populate-mu-function-body:line-loop:
+459       # if (open-curly-count == 0) break
+460       81 7/subop/compare %ebx 0/imm32
+461       0f 84/jump-if-equal break/disp32
+462       # line = read-line-buffered(in)
+463       (clear-stream %ecx)
+464       (read-line-buffered *(ebp+8) %ecx)
+465       # if (line->write == 0) break
+466       81 7/subop/compare *ecx 0/imm32
+467       0f 84/jump-if-equal break/disp32
+468       # word-slice = next-word(line)
+469       (next-word %ecx %edx)
+470       # if slice-empty?(word-slice)) continue
+471       (slice-empty? %ecx)
+472       3d/compare-eax-and 0/imm32
+473       75/jump-if-not-equal loop/disp8
+474       # if (slice-starts-with?(word-slice, '#') continue
+475       # . eax = *word-slice->start
+476       8b/-> *edx 0/r32/eax
+477       8a/copy-byte *eax 0/r32/AL
+478       81 4/subop/and %eax 0xff/imm32
+479       # . if (eax == '#') continue
+480       3d/compare-eax-and 0x23/imm32/hash
+481       74/jump-if-equal loop/disp8
+482       {
+483         # if slice-equal?(word-slice, "{") ++open-curly-count
+484         {
+485           (slice-equal? %ecx "{")
+486           3d/compare-eax-and 0/imm32
+487           74/jump-if-equal break/disp8
+488           43/increment-ebx
+489           eb/jump $curly-found:end/disp8
+490         }
+491         # else if slice-equal?(word-slice, "}") --open-curly-count
+492         {
+493           (slice-equal? %ecx "}")
+494           3d/compare-eax-and 0/imm32
+495           74/jump-if-equal break/disp8
+496           4b/decrement-ebx
+497           eb/jump $curly-found:end/disp8
+498         }
+499         # else break
+500         eb/jump $populate-mu-function-body:end/disp8
+501       }
+502       # - check for invalid tokens after curly
+503 $curly-found:end:
+504       # second-word-slice = next-word(line)
+505       (next-word %ecx %edx)
+506       # if slice-empty?(second-word-slice)) continue
+507       (slice-empty? %ecx)
+508       3d/compare-eax-and 0/imm32
+509       0f 85/jump-if-not-equal loop/disp32
+510       # if (slice-starts-with?(second-word-slice, '#') continue
+511       # . eax = *second-word-slice->start
+512       8b/-> *edx 0/r32/eax
+513       8a/copy-byte *eax 0/r32/AL
+514       81 4/subop/and %eax 0xff/imm32
+515       # . if (eax == '#') continue
+516       3d/compare-eax-and 0x23/imm32/hash
+517       0f 84/jump-if-equal loop/disp32
+518       # abort
+519       eb/jump $populate-mu-function-body:abort/disp8
+520     } # end line loop
+521 $populate-mu-function-body:end:
+522     # . reclaim locals
+523     81 0/subop/add %esp 0x214/imm32
+524     # . restore registers
+525     5b/pop-to-ebx
+526     5a/pop-to-edx
+527     59/pop-to-ecx
+528     58/pop-to-eax
+529     # . epilogue
+530     89/<- %esp 5/r32/ebp
+531     5d/pop-to-ebp
+532     c3/return
+533 
+534 $populate-mu-function-body:abort:
+535     # error("'{' or '}' should be on its own line, but got '")
+536     (write-buffered Stderr "'{' or '}' should be on its own line, but got '")
+537     (rewind-stream %ecx)
+538     (write-stream 2 %ecx)
+539     (write-buffered Stderr "'\n")
+540     (flush Stderr)
+541     # . syscall(exit, 1)
+542     bb/copy-to-ebx  1/imm32
+543     b8/copy-to-eax  1/imm32/exit
+544     cd/syscall  0x80/imm8
+545     # never gets here
+546 
+547 check-mu-types:
+548     # . prologue
+549     55/push-ebp
+550     89/<- %ebp 4/r32/esp
+551     #
+552 $check-types:end:
+553     # . epilogue
+554     89/<- %esp 5/r32/ebp
+555     5d/pop-to-ebp
+556     c3/return
+557 
+558 emit-subx:  # out : (address buffered-file)
+559     # . prologue
+560     55/push-ebp
+561     89/<- %ebp 4/r32/esp
+562     # . save registers
+563     50/push-eax
+564     51/push-ecx
+565     57/push-edi
+566     # edi = out
+567     8b/-> *(ebp+8) 7/r32/edi
+568     # var curr/ecx : (address function) = Program
+569     8b/-> *Program 1/r32/ecx
+570     {
+571       # if (curr == NULL) break
+572       81 7/subop/compare %ecx 0/imm32
+573       0f 84/jump-if-equal break/disp32
+574       (write-buffered %edi *ecx)
+575       (write-buffered %edi ":\n")
+576       (emit-subx-prologue %edi)
+577       (emit-subx-epilogue %edi)
+578       # curr = curr->next
+579       8b/-> *(ecx+0x10) 1/r32/ecx
+580       e9/jump loop/disp32
+581     }
+582 $emit-subx:end:
+583     # . restore registers
+584     5f/pop-to-edi
+585     59/pop-to-ecx
+586     58/pop-to-eax
+587     # . epilogue
+588     89/<- %esp 5/r32/ebp
+589     5d/pop-to-ebp
+590     c3/return
+591 
+592 emit-subx-prologue:  # out : (address buffered-file)
+593     # . prologue
+594     55/push-ebp
+595     89/<- %ebp 4/r32/esp
+596     #
+597     (write-buffered *(ebp+8) "# . prologue\n")
+598     (write-buffered *(ebp+8) "55/push-ebp\n")
+599     (write-buffered *(ebp+8) "89/<- %ebp 4/r32/esp\n")
+600     # . epilogue
+601     89/<- %esp 5/r32/ebp
+602     5d/pop-to-ebp
+603     c3/return
+604 
+605 emit-subx-epilogue:  # out : (address buffered-file)
+606     # . prologue
+607     55/push-ebp
+608     89/<- %ebp 4/r32/esp
+609     #
+610     (write-buffered *(ebp+8) "# . epilogue\n")
+611     (write-buffered *(ebp+8) "89/<- %esp 5/r32/ebp\n")
+612     (write-buffered *(ebp+8) "5d/pop-to-ebp\n")
+613     (write-buffered *(ebp+8) "c3/return\n")
+614     # . epilogue
+615     89/<- %esp 5/r32/ebp
+616     5d/pop-to-ebp
+617     c3/return
+
+ + + diff --git a/html/apps/mulisp.subx.html b/html/apps/mulisp.subx.html index ee20959a..3eaf0380 100644 --- a/html/apps/mulisp.subx.html +++ b/html/apps/mulisp.subx.html @@ -59,7 +59,7 @@ if ('onhashchange' in window) { 1 # Toy lisp interpreter. Incomplete. 2 # 3 # To run: - 4 # $ ./ntranslate init.linux 0*.subx apps/subx-params.subx apps/mulisp.subx + 4 # $ ./ntranslate init.linux 0*.subx apps/mulisp.subx 5 # $ ./a.elf 6 # 42 7 # => 42 -- cgit 1.4.1-2-gfad0