From 78357b8852626b510527f3b8d770a7dd8956fcc7 Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Fri, 16 Jul 2021 08:38:43 -0700 Subject: . --- html/linux/apps/advent2017/1a.mu.html | 131 +++++ html/linux/apps/advent2020/1a.mu.html | 165 +++++++ html/linux/apps/advent2020/1b.mu.html | 181 +++++++ html/linux/apps/advent2020/2a.mu.html | 159 ++++++ html/linux/apps/advent2020/2b.mu.html | 190 +++++++ html/linux/apps/advent2020/3a.mu.html | 175 +++++++ html/linux/apps/advent2020/3b.mu.html | 205 ++++++++ html/linux/apps/advent2020/4a.mu.html | 142 ++++++ html/linux/apps/advent2020/4b.mu.html | 381 +++++++++++++++ html/linux/apps/advent2020/5a.mu.html | 146 ++++++ html/linux/apps/advent2020/5b.mu.html | 148 ++++++ html/linux/apps/arith.mu.html | 326 +++++++++++++ html/linux/apps/crenshaw2-1.subx.html | 621 +++++++++++++++++++++++ html/linux/apps/crenshaw2-1b.subx.html | 815 +++++++++++++++++++++++++++++++ html/linux/apps/ex1.mu.html | 77 +++ html/linux/apps/ex1.subx.html | 79 +++ html/linux/apps/ex10.subx.html | 132 +++++ html/linux/apps/ex11.subx.html | 421 ++++++++++++++++ html/linux/apps/ex12.subx.html | 104 ++++ html/linux/apps/ex13.subx.html | 87 ++++ html/linux/apps/ex14.subx.html | 88 ++++ html/linux/apps/ex2.mu.html | 83 ++++ html/linux/apps/ex2.subx.html | 79 +++ html/linux/apps/ex3.2.mu.html | 98 ++++ html/linux/apps/ex3.mu.html | 84 ++++ html/linux/apps/ex3.subx.html | 98 ++++ html/linux/apps/ex4.subx.html | 99 ++++ html/linux/apps/ex5.subx.html | 101 ++++ html/linux/apps/ex6.subx.html | 96 ++++ html/linux/apps/ex7.subx.html | 159 ++++++ html/linux/apps/ex8.subx.html | 123 +++++ html/linux/apps/ex9.subx.html | 114 +++++ html/linux/apps/factorial.mu.html | 125 +++++ html/linux/apps/factorial.subx.html | 217 ++++++++ html/linux/apps/factorial2.subx.html | 185 +++++++ html/linux/apps/factorial3.subx.html | 142 ++++++ html/linux/apps/factorial4.subx.html | 150 ++++++ html/linux/apps/hello.mu.html | 72 +++ html/linux/apps/parse-int.mu.html | 114 +++++ html/linux/apps/print-file.mu.html | 104 ++++ html/linux/apps/raytracing/1.mu.html | 95 ++++ html/linux/apps/raytracing/2.mu.html | 153 ++++++ html/linux/apps/raytracing/3.mu.html | 554 +++++++++++++++++++++ html/linux/apps/raytracing/color.mu.html | 100 ++++ html/linux/apps/raytracing/ray.mu.html | 86 ++++ html/linux/apps/raytracing/vec.mu.html | 201 ++++++++ html/linux/apps/rpn.mu.html | 215 ++++++++ html/linux/apps/texture.mu.html | 126 +++++ html/linux/apps/tui.mu.html | 98 ++++ 49 files changed, 8644 insertions(+) create mode 100644 html/linux/apps/advent2017/1a.mu.html create mode 100644 html/linux/apps/advent2020/1a.mu.html create mode 100644 html/linux/apps/advent2020/1b.mu.html create mode 100644 html/linux/apps/advent2020/2a.mu.html create mode 100644 html/linux/apps/advent2020/2b.mu.html create mode 100644 html/linux/apps/advent2020/3a.mu.html create mode 100644 html/linux/apps/advent2020/3b.mu.html create mode 100644 html/linux/apps/advent2020/4a.mu.html create mode 100644 html/linux/apps/advent2020/4b.mu.html create mode 100644 html/linux/apps/advent2020/5a.mu.html create mode 100644 html/linux/apps/advent2020/5b.mu.html create mode 100644 html/linux/apps/arith.mu.html create mode 100644 html/linux/apps/crenshaw2-1.subx.html create mode 100644 html/linux/apps/crenshaw2-1b.subx.html create mode 100644 html/linux/apps/ex1.mu.html create mode 100644 html/linux/apps/ex1.subx.html create mode 100644 html/linux/apps/ex10.subx.html create mode 100644 html/linux/apps/ex11.subx.html create mode 100644 html/linux/apps/ex12.subx.html create mode 100644 html/linux/apps/ex13.subx.html create mode 100644 html/linux/apps/ex14.subx.html create mode 100644 html/linux/apps/ex2.mu.html create mode 100644 html/linux/apps/ex2.subx.html create mode 100644 html/linux/apps/ex3.2.mu.html create mode 100644 html/linux/apps/ex3.mu.html create mode 100644 html/linux/apps/ex3.subx.html create mode 100644 html/linux/apps/ex4.subx.html create mode 100644 html/linux/apps/ex5.subx.html create mode 100644 html/linux/apps/ex6.subx.html create mode 100644 html/linux/apps/ex7.subx.html create mode 100644 html/linux/apps/ex8.subx.html create mode 100644 html/linux/apps/ex9.subx.html create mode 100644 html/linux/apps/factorial.mu.html create mode 100644 html/linux/apps/factorial.subx.html create mode 100644 html/linux/apps/factorial2.subx.html create mode 100644 html/linux/apps/factorial3.subx.html create mode 100644 html/linux/apps/factorial4.subx.html create mode 100644 html/linux/apps/hello.mu.html create mode 100644 html/linux/apps/parse-int.mu.html create mode 100644 html/linux/apps/print-file.mu.html create mode 100644 html/linux/apps/raytracing/1.mu.html create mode 100644 html/linux/apps/raytracing/2.mu.html create mode 100644 html/linux/apps/raytracing/3.mu.html create mode 100644 html/linux/apps/raytracing/color.mu.html create mode 100644 html/linux/apps/raytracing/ray.mu.html create mode 100644 html/linux/apps/raytracing/vec.mu.html create mode 100644 html/linux/apps/rpn.mu.html create mode 100644 html/linux/apps/texture.mu.html create mode 100644 html/linux/apps/tui.mu.html (limited to 'html/linux/apps') diff --git a/html/linux/apps/advent2017/1a.mu.html b/html/linux/apps/advent2017/1a.mu.html new file mode 100644 index 00000000..88f60dbc --- /dev/null +++ b/html/linux/apps/advent2017/1a.mu.html @@ -0,0 +1,131 @@ + + + + +Mu - linux/apps/advent2017/1a.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/advent2017/1a.mu +
+ 1 # Advent of code 2017, problem 1a
+ 2 #   https://adventofcode.com/2017/day/1
+ 3 #
+ 4 # Mu solution by Sumeet Agarwal and Kartik Agaram
+ 5 #   https://archive.org/details/2021-06-02-akkartik-sumeet
+ 6 #
+ 7 # To build on Linux:
+ 8 #   $ git clone https://github.com/akkartik/mu
+ 9 #   $ cd mu/linux
+10 #   $ ./translate apps/advent2017/1a.mu            # emits a.elf
+11 # To run on Linux:
+12 #   Download https://adventofcode.com/2017/day/1/input
+13 #   $ ./a.elf < input
+14 # Type in the number returned at https://adventofcode.com/2017/day/1
+15 
+16 fn main -> _/ebx: int {
+17   var input_stream: (stream byte 0x8000)
+18   var input_stream_addr/esi: (addr stream byte) <- address input_stream
+19 
+20   var sum/edi: int <- copy 0
+21   read-line-from-real-keyboard input_stream_addr
+22 
+23   var temp/eax: int <- read_digit input_stream_addr
+24   var first_digit/ebx: int <- copy temp
+25   var this_digit/edx: int <- copy temp
+26 
+27   {
+28     var done?/eax: boolean <- stream-empty? input_stream_addr
+29     compare done?, 1
+30     break-if-=
+31 
+32     var next_digit/eax: int <- read_digit input_stream_addr
+33     # hacky newline check
+34     compare next_digit, 0
+35     break-if-<
+36 
+37     {
+38       compare this_digit, next_digit
+39       break-if-!=
+40       sum <- add this_digit
+41     }
+42 
+43     this_digit <- copy next_digit
+44 
+45     loop
+46   }
+47 
+48   # the last iteration will need to compare the last number to the first
+49   {
+50     compare this_digit, first_digit
+51     break-if-!=
+52     sum <- add this_digit
+53   }
+54 
+55   print-int32-decimal 0, sum
+56 
+57   return 0/ok
+58 }
+59 
+60 fn read_digit input_stream_addr: (addr stream byte) -> _/eax: int {
+61   var next_digit/eax: byte <- read-byte input_stream_addr
+62   next_digit <- subtract 0x30
+63   var next_digit/eax: int <- copy next_digit
+64   return next_digit
+65 }
+
+ + + diff --git a/html/linux/apps/advent2020/1a.mu.html b/html/linux/apps/advent2020/1a.mu.html new file mode 100644 index 00000000..e75fe8fc --- /dev/null +++ b/html/linux/apps/advent2020/1a.mu.html @@ -0,0 +1,165 @@ + + + + +Mu - linux/apps/advent2020/1a.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/advent2020/1a.mu +
+ 1 # https://adventofcode.com/2020/day/1
+ 2 #
+ 3 # To run (on Linux):
+ 4 #   $ git clone https://github.com/akkartik/mu
+ 5 #   $ cd mu
+ 6 #   $ ./translate apps/advent2020/1a.mu
+ 7 #   $ ./a.elf < input
+ 8 #   found
+ 9 #   1353 667
+10 #   902451
+11 #
+12 # You'll need to register to download the 'input' file for yourself.
+13 
+14 fn main -> _/ebx: int {
+15   # data structure
+16   var numbers-storage: (array int 0x100)  # 256 ints
+17   var numbers/esi: (addr array int) <- address numbers-storage
+18   var numbers-index/ecx: int <- copy 0
+19   # phase 1: parse each line from stdin and add it to numbers
+20   {
+21     var line-storage: (stream byte 0x100)  # 256 bytes
+22     var line/edx: (addr stream byte) <- address line-storage
+23     {
+24 #?       print-string 0, "== iter\n"
+25       # read line from stdin
+26       clear-stream line
+27       read-line-from-real-keyboard line
+28       # if line is empty (not even a newline), quit
+29       var done?/eax: boolean <- stream-empty? line
+30       compare done?, 0/false
+31       break-if-!=
+32 #?       print-stream-to-real-screen line
+33       # convert line to int and append it to numbers
+34       var n/eax: int <- parse-decimal-int-from-stream line
+35 #?       print-int32-decimal 0, n
+36 #?       print-string 0, "\n"
+37       var dest/ebx: (addr int) <- index numbers, numbers-index
+38       copy-to *dest, n
+39       numbers-index <- increment
+40 #?       print-string 0, "== "
+41 #?       print-int32-decimal 0, numbers-index
+42 #?       print-string 0, "\n"
+43       loop
+44     }
+45   }
+46   # phase 2: for each number in the array, check if 2020-it is in the rest of
+47   # the array
+48   var i/eax: int <- copy 0
+49   {
+50     compare i, numbers-index
+51     break-if->=
+52     var src/ebx: (addr int) <- index numbers, i
+53 #?     print-int32-decimal 0, *src
+54 #?     print-string 0, "\n"
+55     var target/ecx: int <- copy 0x7e4  # 2020
+56     target <- subtract *src
+57     {
+58       var found?/eax: boolean <- find-after numbers, i, target
+59       compare found?, 0/false
+60       break-if-=
+61       print-string 0, "found\n"
+62       print-int32-decimal 0, *src
+63       print-string 0, " "
+64       print-int32-decimal 0, target
+65       print-string 0, "\n"
+66       target <- multiply *src
+67       print-int32-decimal 0, target
+68       print-string 0, "\n"
+69       return 0/success
+70     }
+71     i <- increment
+72     loop
+73   }
+74   return 1/not-found
+75 }
+76 
+77 fn find-after _numbers: (addr array int), start: int, _target: int -> _/eax: boolean {
+78   var numbers/esi: (addr array int) <- copy _numbers
+79   var target/edi: int <- copy _target
+80   var len/ecx: int <- length numbers
+81   var i/eax: int <- copy start
+82   i <- increment
+83   {
+84     compare i, len
+85     break-if->=
+86     var src/edx: (addr int) <- index numbers, i
+87     # if *src == target, return true
+88     compare *src, target
+89     {
+90       break-if-!=
+91       return 1/true
+92     }
+93     i <- increment
+94     loop
+95   }
+96   return 0/false
+97 }
+
+ + + diff --git a/html/linux/apps/advent2020/1b.mu.html b/html/linux/apps/advent2020/1b.mu.html new file mode 100644 index 00000000..4346642b --- /dev/null +++ b/html/linux/apps/advent2020/1b.mu.html @@ -0,0 +1,181 @@ + + + + +Mu - linux/apps/advent2020/1b.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/advent2020/1b.mu +
+  1 # https://adventofcode.com/2020/day/1
+  2 #
+  3 # To run (on Linux):
+  4 #   $ git clone https://github.com/akkartik/mu
+  5 #   $ cd mu
+  6 #   $ ./translate apps/advent2020/1b.mu
+  7 #   $ ./a.elf < input
+  8 #   found
+  9 #   143 407 1470
+ 10 #   85555470
+ 11 #
+ 12 # You'll need to register to download the 'input' file for yourself.
+ 13 
+ 14 fn main -> _/ebx: int {
+ 15   # data structure
+ 16   var numbers-storage: (array int 0x100)  # 256 ints
+ 17   var numbers/esi: (addr array int) <- address numbers-storage
+ 18   var numbers-index/ecx: int <- copy 0
+ 19   # phase 1: parse each line from stdin and add it to numbers
+ 20   {
+ 21     var line-storage: (stream byte 0x100)  # 256 bytes
+ 22     var line/edx: (addr stream byte) <- address line-storage
+ 23     {
+ 24 #?       print-string 0, "== iter\n"
+ 25       # read line from stdin
+ 26       clear-stream line
+ 27       read-line-from-real-keyboard line
+ 28       # if line is empty (not even a newline), quit
+ 29       var done?/eax: boolean <- stream-empty? line
+ 30       compare done?, 0/false
+ 31       break-if-!=
+ 32 #?       print-stream-to-real-screen line
+ 33       # convert line to int and append it to numbers
+ 34       var n/eax: int <- parse-decimal-int-from-stream line
+ 35 #?       print-int32-decimal 0, n
+ 36 #?       print-string 0, "\n"
+ 37       var dest/ebx: (addr int) <- index numbers, numbers-index
+ 38       copy-to *dest, n
+ 39       numbers-index <- increment
+ 40 #?       print-string 0, "== "
+ 41 #?       print-int32-decimal 0, numbers-index
+ 42 #?       print-string 0, "\n"
+ 43       loop
+ 44     }
+ 45   }
+ 46   # phase 2: for every pair of distinct numbers, check if the rest of the
+ 47   # array has 2020-it
+ 48   var i/edi: int <- copy 0
+ 49   {
+ 50     compare i, numbers-index
+ 51     break-if->=
+ 52     # for j from i+1 to end
+ 53     var j/edx: int <- copy i
+ 54     j <- increment
+ 55     {
+ 56       compare j, numbers-index
+ 57       break-if->=
+ 58       {
+ 59         compare i, j
+ 60         break-if-=
+ 61         var target/ebx: int <- copy 0x7e4  # 2020
+ 62         var src/edi: (addr int) <- index numbers, i
+ 63         target <- subtract *src
+ 64         var src2/ecx: (addr int) <- index numbers, j
+ 65         target <- subtract *src2
+ 66         {
+ 67           var found?/eax: boolean <- find-after numbers, j, target
+ 68           compare found?, 0/false
+ 69           break-if-=
+ 70           print-string 0, "found\n"
+ 71           print-int32-decimal 0, *src
+ 72           print-string 0, " "
+ 73           print-int32-decimal 0, *src2
+ 74           print-string 0, " "
+ 75           print-int32-decimal 0, target
+ 76           print-string 0, "\n"
+ 77           target <- multiply *src
+ 78           target <- multiply *src2
+ 79           print-int32-decimal 0, target
+ 80           print-string 0, "\n"
+ 81           return 0/success
+ 82         }
+ 83       }
+ 84       j <- increment
+ 85       loop
+ 86     }
+ 87     i <- increment
+ 88     loop
+ 89   }
+ 90   return 1/not-found
+ 91 }
+ 92 
+ 93 fn find-after _numbers: (addr array int), start: int, _target: int -> _/eax: boolean {
+ 94   var numbers/esi: (addr array int) <- copy _numbers
+ 95   var target/edi: int <- copy _target
+ 96   var len/ecx: int <- length numbers
+ 97   var i/eax: int <- copy start
+ 98   i <- increment
+ 99   {
+100     compare i, len
+101     break-if->=
+102     var src/edx: (addr int) <- index numbers, i
+103     # if *src == target, return true
+104     compare *src, target
+105     {
+106       break-if-!=
+107       return 1/true
+108     }
+109     i <- increment
+110     loop
+111   }
+112   return 0/false
+113 }
+
+ + + diff --git a/html/linux/apps/advent2020/2a.mu.html b/html/linux/apps/advent2020/2a.mu.html new file mode 100644 index 00000000..2e6e3488 --- /dev/null +++ b/html/linux/apps/advent2020/2a.mu.html @@ -0,0 +1,159 @@ + + + + +Mu - linux/apps/advent2020/2a.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/advent2020/2a.mu +
+ 1 # https://adventofcode.com/2020/day/2
+ 2 #
+ 3 # To run (on Linux):
+ 4 #   $ git clone https://github.com/akkartik/mu
+ 5 #   $ cd mu
+ 6 #   $ ./translate apps/advent2020/2a.mu
+ 7 #   $ ./a.elf < input
+ 8 #
+ 9 # You'll need to register to download the 'input' file for yourself.
+10 
+11 fn main -> _/ebx: int {
+12   var valid-password-count/edi: int <- copy 0
+13   var line-storage: (stream byte 0x100)  # 256 bytes
+14   var line/edx: (addr stream byte) <- address line-storage
+15   var slice-storage: slice
+16   var slice/ecx: (addr slice) <- address slice-storage
+17   {
+18     # read line from stdin
+19     clear-stream line
+20     read-line-from-real-keyboard line
+21     # if line is empty (not even a newline), quit
+22     var done?/eax: boolean <- stream-empty? line
+23     compare done?, 0/false
+24     break-if-!=
+25     print-stream-to-real-screen line
+26     # slice = next-token(line, '-')
+27     next-token line, 0x2d, slice
+28     # start = parse-int(slice)
+29     var _start/eax: int <- parse-decimal-int-from-slice slice
+30     var start/ebx: int <- copy _start
+31     var dash/eax: byte <- read-byte line  # skip '-'
+32     # slice = next-token(line, ' ')
+33     next-token line, 0x20, slice
+34     var _end/eax: int <- parse-decimal-int-from-slice slice
+35     var end/esi: int <- copy _end
+36     print-int32-decimal 0, start
+37     print-string 0, " "
+38     print-int32-decimal 0, end
+39     print-string 0, "\n"
+40     # letter = next non-space
+41     skip-chars-matching-whitespace line
+42     var letter/eax: byte <- read-byte line
+43     # skip some stuff
+44     {
+45       var colon/eax: byte <- read-byte line  # skip ':'
+46     }
+47     skip-chars-matching-whitespace line
+48     # now check the rest of the line
+49     var valid?/eax: boolean <- valid? start, end, letter, line
+50     compare valid?, 0/false
+51     {
+52       break-if-=
+53       print-string 0, "valid!\n"
+54       valid-password-count <- increment
+55     }
+56     loop
+57   }
+58   print-int32-decimal 0, valid-password-count
+59   print-string 0, "\n"
+60   return 0
+61 }
+62 
+63 fn valid? start: int, end: int, letter: byte, password: (addr stream byte) -> _/eax: boolean {
+64   var letter-count/edi: int <- copy 0
+65   # for every c in password
+66   #   if (c == letter)
+67   #     ++letter-count
+68   {
+69     var done?/eax: boolean <- stream-empty? password
+70     compare done?, 0/false
+71     break-if-!=
+72     var c/eax: byte <- read-byte password
+73     compare c, letter
+74     {
+75       break-if-!=
+76       letter-count <- increment
+77     }
+78     loop
+79   }
+80   # return (start <= letter-count <= end)
+81   compare letter-count, start
+82   {
+83     break-if->=
+84     return 0/false
+85   }
+86   compare letter-count, end
+87   {
+88     break-if-<=
+89     return 0/false
+90   }
+91   return 1/true
+92 }
+
+ + + diff --git a/html/linux/apps/advent2020/2b.mu.html b/html/linux/apps/advent2020/2b.mu.html new file mode 100644 index 00000000..604e06bb --- /dev/null +++ b/html/linux/apps/advent2020/2b.mu.html @@ -0,0 +1,190 @@ + + + + +Mu - linux/apps/advent2020/2b.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/advent2020/2b.mu +
+  1 # https://adventofcode.com/2020/day/2
+  2 #
+  3 # To run (on Linux):
+  4 #   $ git clone https://github.com/akkartik/mu
+  5 #   $ cd mu
+  6 #   $ ./translate apps/advent2020/2b.mu
+  7 #   $ ./a.elf < input
+  8 #
+  9 # You'll need to register to download the 'input' file for yourself.
+ 10 
+ 11 fn main -> _/ebx: int {
+ 12   var valid-password-count/edi: int <- copy 0
+ 13   var line-storage: (stream byte 0x100)  # 256 bytes
+ 14   var line/edx: (addr stream byte) <- address line-storage
+ 15   var slice-storage: slice
+ 16   var slice/ecx: (addr slice) <- address slice-storage
+ 17   {
+ 18     # read line from stdin
+ 19     clear-stream line
+ 20     read-line-from-real-keyboard line
+ 21     # if line is empty (not even a newline), quit
+ 22     var done?/eax: boolean <- stream-empty? line
+ 23     compare done?, 0/false
+ 24     break-if-!=
+ 25     print-stream-to-real-screen line
+ 26     # slice = next-token(line, '-')
+ 27     next-token line, 0x2d, slice
+ 28     # pos1 = parse-int(slice)
+ 29     var _pos1/eax: int <- parse-decimal-int-from-slice slice
+ 30     var pos1/ebx: int <- copy _pos1
+ 31     var dash/eax: byte <- read-byte line  # skip '-'
+ 32     # slice = next-token(line, ' ')
+ 33     next-token line, 0x20, slice
+ 34     var _pos2/eax: int <- parse-decimal-int-from-slice slice
+ 35     var pos2/esi: int <- copy _pos2
+ 36     print-int32-decimal 0, pos1
+ 37     print-string 0, " "
+ 38     print-int32-decimal 0, pos2
+ 39     print-string 0, "\n"
+ 40     compare pos1, pos2
+ 41     {
+ 42       break-if-<=
+ 43       print-string 0, "out of order!\n"
+ 44       return 1
+ 45     }
+ 46     # letter = next non-space
+ 47     skip-chars-matching-whitespace line
+ 48     var letter/eax: byte <- read-byte line
+ 49     # skip some stuff
+ 50     {
+ 51       var colon/eax: byte <- read-byte line  # skip ':'
+ 52     }
+ 53     skip-chars-matching-whitespace line
+ 54     # now check the rest of the line
+ 55     var valid?/eax: boolean <- valid? pos1, pos2, letter, line
+ 56     compare valid?, 0/false
+ 57     {
+ 58       break-if-=
+ 59       print-string 0, "valid!\n"
+ 60       valid-password-count <- increment
+ 61     }
+ 62     loop
+ 63   }
+ 64   print-int32-decimal 0, valid-password-count
+ 65   print-string 0, "\n"
+ 66   return 0
+ 67 }
+ 68 
+ 69 # ideally password would be a random-access array
+ 70 # we'll just track an index
+ 71 # one benefit: we can easily start at 1
+ 72 fn valid? pos1: int, pos2: int, letter: byte, password: (addr stream byte) -> _/eax: boolean {
+ 73   var i/esi: int <- copy 1
+ 74   var letter-count/edi: int <- copy 0
+ 75   # while password stream isn't empty
+ 76   #   c = read byte from password
+ 77   #   if (c == letter)
+ 78   #     if (i == pos1)
+ 79   #       ++letter-count
+ 80   #     if (i == pos2)
+ 81   #       ++letter-count
+ 82   #     ++i
+ 83   {
+ 84 #?     print-string 0, "  "
+ 85 #?     print-int32-decimal 0, i
+ 86 #?     print-string 0, "\n"
+ 87     var done?/eax: boolean <- stream-empty? password
+ 88     compare done?, 0/false
+ 89     break-if-!=
+ 90     var c/eax: byte <- read-byte password
+ 91 #?     {
+ 92 #?       var c2/eax: int <- copy c
+ 93 #?       print-int32-decimal 0, c2
+ 94 #?       print-string 0, "\n"
+ 95 #?     }
+ 96     compare c, letter
+ 97     {
+ 98       break-if-!=
+ 99       compare i, pos1
+100       {
+101         break-if-!=
+102         letter-count <- increment
+103 #?         print-string 0, "  hit\n"
+104       }
+105       compare i, pos2
+106       {
+107         break-if-!=
+108         letter-count <- increment
+109 #?         print-string 0, "  hit\n"
+110       }
+111     }
+112     i <- increment
+113     loop
+114   }
+115   # return (letter-count == 1)
+116   compare letter-count, 1
+117   {
+118     break-if-!=
+119     return 1/true
+120   }
+121   return 0/false
+122 }
+
+ + + diff --git a/html/linux/apps/advent2020/3a.mu.html b/html/linux/apps/advent2020/3a.mu.html new file mode 100644 index 00000000..09d7f160 --- /dev/null +++ b/html/linux/apps/advent2020/3a.mu.html @@ -0,0 +1,175 @@ + + + + +Mu - linux/apps/advent2020/3a.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/advent2020/3a.mu +
+  1 # https://adventofcode.com/2020/day/3
+  2 #
+  3 # To run (on Linux):
+  4 #   $ git clone https://github.com/akkartik/mu
+  5 #   $ cd mu
+  6 #   $ ./translate apps/advent2020/3a.mu
+  7 #   $ ./a.elf < input
+  8 #
+  9 # You'll need to register to download the 'input' file for yourself.
+ 10 
+ 11 fn main -> _/ebx: int {
+ 12   # represent trees in a 2D array of ints
+ 13   # wasteful since each tree is just one bit
+ 14   var trees-storage: (array int 0x2800)  # 10k ints
+ 15   var trees/esi: (addr array int) <- address trees-storage
+ 16   var trees-length/ecx: int <- copy 0
+ 17   var num-rows: int
+ 18   var width: int
+ 19   # phase 1: parse each row of trees from stdin
+ 20   {
+ 21     var line-storage: (stream byte 0x40)  # 64 bytes
+ 22     var line/edx: (addr stream byte) <- address line-storage
+ 23     {
+ 24       # read line from stdin
+ 25       clear-stream line
+ 26       read-line-from-real-keyboard line
+ 27       # if line is empty (not even a newline), quit
+ 28       var done?/eax: boolean <- stream-empty? line
+ 29       compare done?, 0/false
+ 30       break-if-!=
+ 31       # wastefully recompute width on every line
+ 32       # zero error-checking; we assume input lines are all equally long
+ 33       copy-to width, 0
+ 34       # turn each byte into a tree and append it
+ 35       $main:line-loop: {
+ 36         var done?/eax: boolean <- stream-empty? line
+ 37         compare done?, 0/false
+ 38         break-if-!=
+ 39 #?         print-int32-decimal 0, num-rows
+ 40 #?         print-string 0, " "
+ 41 #?         print-int32-decimal 0, width
+ 42 #?         print-string 0, "\n"
+ 43         var dest/ebx: (addr int) <- index trees, trees-length
+ 44         var c/eax: byte <- read-byte line
+ 45         # newline comes only at end of line
+ 46         compare c, 0xa/newline
+ 47         break-if-=
+ 48         # '#' = tree
+ 49         compare c, 0x23/hash
+ 50         {
+ 51           break-if-!=
+ 52           copy-to *dest, 1
+ 53         }
+ 54         # anything else = no tree
+ 55         {
+ 56           break-if-=
+ 57           copy-to *dest, 0
+ 58         }
+ 59         increment width
+ 60         trees-length <- increment
+ 61         loop
+ 62       }
+ 63       increment num-rows
+ 64       loop
+ 65     }
+ 66   }
+ 67   # phase 2: compute
+ 68   print-int32-decimal 0, num-rows
+ 69   print-string 0, "x"
+ 70   print-int32-decimal 0, width
+ 71   print-string 0, "\n"
+ 72   var row/ecx: int <- copy 0
+ 73   var col/edx: int <- copy 0
+ 74   var num-trees-hit/edi: int <- copy 0
+ 75   {
+ 76     compare row, num-rows
+ 77     break-if->=
+ 78     var curr/eax: int <- index2d trees, row, col, width
+ 79     compare curr, 0
+ 80     {
+ 81       break-if-=
+ 82       num-trees-hit <- increment
+ 83     }
+ 84     # right 3, down 1
+ 85     col <- add 3
+ 86     row <- add 1
+ 87     loop
+ 88   }
+ 89   print-int32-decimal 0, num-trees-hit
+ 90   print-string 0, "\n"
+ 91   return 0
+ 92 }
+ 93 
+ 94 fn index2d _arr: (addr array int), _row: int, _col: int, width: int -> _/eax: int {
+ 95   # handle repeating columns of trees
+ 96   var dummy/eax: int <- copy 0
+ 97   var col/edx: int <- copy 0
+ 98   dummy, col <- integer-divide _col, width
+ 99   # compute index
+100   var index/eax: int <- copy _row
+101   index <- multiply width
+102   index <- add col
+103   # look up array
+104   var arr/esi: (addr array int) <- copy _arr
+105   var src/eax: (addr int) <- index arr, index
+106   return *src
+107 }
+
+ + + diff --git a/html/linux/apps/advent2020/3b.mu.html b/html/linux/apps/advent2020/3b.mu.html new file mode 100644 index 00000000..ff64117f --- /dev/null +++ b/html/linux/apps/advent2020/3b.mu.html @@ -0,0 +1,205 @@ + + + + +Mu - linux/apps/advent2020/3b.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/advent2020/3b.mu +
+  1 # https://adventofcode.com/2020/day/3
+  2 #
+  3 # To run (on Linux):
+  4 #   $ git clone https://github.com/akkartik/mu
+  5 #   $ cd mu
+  6 #   $ ./translate apps/advent2020/3a.mu
+  7 #   $ ./a.elf < input
+  8 #
+  9 # You'll need to register to download the 'input' file for yourself.
+ 10 
+ 11 fn main -> _/ebx: int {
+ 12   # represent trees in a 2D array of ints
+ 13   # wasteful since each tree is just one bit
+ 14   var trees-storage: (array int 0x2800)  # 10k ints
+ 15   var trees/esi: (addr array int) <- address trees-storage
+ 16   var trees-length/ecx: int <- copy 0
+ 17   var num-rows: int
+ 18   var width: int
+ 19   # phase 1: parse each row of trees from stdin
+ 20   {
+ 21     var line-storage: (stream byte 0x40)  # 64 bytes
+ 22     var line/edx: (addr stream byte) <- address line-storage
+ 23     {
+ 24       # read line from stdin
+ 25       clear-stream line
+ 26       read-line-from-real-keyboard line
+ 27       # if line is empty (not even a newline), quit
+ 28       var done?/eax: boolean <- stream-empty? line
+ 29       compare done?, 0/false
+ 30       break-if-!=
+ 31       # wastefully recompute width on every line
+ 32       # zero error-checking; we assume input lines are all equally long
+ 33       copy-to width, 0
+ 34       # turn each byte into a tree and append it
+ 35       $main:line-loop: {
+ 36         var done?/eax: boolean <- stream-empty? line
+ 37         compare done?, 0/false
+ 38         break-if-!=
+ 39 #?         print-int32-decimal 0, num-rows
+ 40 #?         print-string 0, " "
+ 41 #?         print-int32-decimal 0, width
+ 42 #?         print-string 0, "\n"
+ 43         var dest/ebx: (addr int) <- index trees, trees-length
+ 44         var c/eax: byte <- read-byte line
+ 45         # newline comes only at end of line
+ 46         compare c, 0xa/newline
+ 47         break-if-=
+ 48         # '#' = tree
+ 49         compare c, 0x23/hash
+ 50         {
+ 51           break-if-!=
+ 52           copy-to *dest, 1
+ 53         }
+ 54         # anything else = no tree
+ 55         {
+ 56           break-if-=
+ 57           copy-to *dest, 0
+ 58         }
+ 59         increment width
+ 60         trees-length <- increment
+ 61         loop
+ 62       }
+ 63       increment num-rows
+ 64       loop
+ 65     }
+ 66   }
+ 67   # phase 2: compute
+ 68   var product/edi: int <- copy 1
+ 69   var result/eax: int <- num-trees-hit trees, width, num-rows, 1, 1
+ 70   print-int32-decimal 0, result
+ 71   print-string 0, " x "
+ 72   product <- multiply result
+ 73   var result/eax: int <- num-trees-hit trees, width, num-rows, 3, 1
+ 74   print-int32-decimal 0, result
+ 75   print-string 0, " x "
+ 76   product <- multiply result
+ 77   var result/eax: int <- num-trees-hit trees, width, num-rows, 5, 1
+ 78   print-int32-decimal 0, result
+ 79   print-string 0, " x "
+ 80   product <- multiply result
+ 81   var result/eax: int <- num-trees-hit trees, width, num-rows, 7, 1
+ 82   print-int32-decimal 0, result
+ 83   print-string 0, " x "
+ 84   product <- multiply result
+ 85   var result/eax: int <- num-trees-hit trees, width, num-rows, 1, 2
+ 86   print-int32-decimal 0, result
+ 87   print-string 0, " = "
+ 88   product <- multiply result
+ 89   print-int32-hex 0, product
+ 90   print-string 0, "\n"
+ 91   return 0
+ 92 }
+ 93 
+ 94 fn num-trees-hit trees: (addr array int), width: int, num-rows: int, right: int, down: int -> _/eax: int {
+ 95 #?   print-string 0, "== "
+ 96 #?   print-int32-decimal 0, right
+ 97 #?   print-string 0, " "
+ 98 #?   print-int32-decimal 0, down
+ 99 #?   print-string 0, "\n"
+100   var row/ecx: int <- copy 0
+101   var col/edx: int <- copy 0
+102   var num-trees-hit/edi: int <- copy 0
+103   {
+104     compare row, num-rows
+105     break-if->=
+106 #?     print-int32-decimal 0, col
+107 #?     print-string 0, "\n"
+108     var curr/eax: int <- index2d trees, row, col, width
+109     compare curr, 0
+110     {
+111       break-if-=
+112       num-trees-hit <- increment
+113     }
+114     col <- add right
+115     row <- add down
+116     loop
+117   }
+118   return num-trees-hit
+119 }
+120 
+121 fn index2d _arr: (addr array int), _row: int, _col: int, width: int -> _/eax: int {
+122   # handle repeating columns of trees
+123   var dummy/eax: int <- copy 0
+124   var col/edx: int <- copy 0
+125   dummy, col <- integer-divide _col, width
+126 #?   print-string 0, "  "
+127 #?   print-int32-decimal 0, col
+128 #?   print-string 0, "\n"
+129   # compute index
+130   var index/eax: int <- copy _row
+131   index <- multiply width
+132   index <- add col
+133   # look up array
+134   var arr/esi: (addr array int) <- copy _arr
+135   var src/eax: (addr int) <- index arr, index
+136   return *src
+137 }
+
+ + + diff --git a/html/linux/apps/advent2020/4a.mu.html b/html/linux/apps/advent2020/4a.mu.html new file mode 100644 index 00000000..6f477717 --- /dev/null +++ b/html/linux/apps/advent2020/4a.mu.html @@ -0,0 +1,142 @@ + + + + +Mu - linux/apps/advent2020/4a.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/advent2020/4a.mu +
+ 1 # https://adventofcode.com/2020/day/4
+ 2 #
+ 3 # To run (on Linux):
+ 4 #   $ git clone https://github.com/akkartik/mu
+ 5 #   $ cd mu
+ 6 #   $ ./translate apps/advent2020/4a.mu
+ 7 #   $ ./a.elf < input
+ 8 #
+ 9 # You'll need to register to download the 'input' file for yourself.
+10 
+11 fn main -> _/ebx: int {
+12   var curr-passport-field-count/esi: int <- copy 0
+13   var valid-passport-count/edi: int <- copy 0
+14   var line-storage: (stream byte 0x100)  # 256 bytes
+15   var line/ecx: (addr stream byte) <- address line-storage
+16   var slice-storage: slice
+17   var slice/edx: (addr slice) <- address slice-storage
+18   $main:line-loop: {
+19     # read line from stdin
+20     clear-stream line
+21     read-line-from-real-keyboard line
+22     # if line is empty (not even a newline), quit
+23     var done?/eax: boolean <- stream-empty? line
+24     compare done?, 0/false
+25     break-if-!=
+26     print-stream-to-real-screen line
+27     # if line has just a newline, process passport
+28     skip-chars-matching-whitespace line
+29     var new-passport?/eax: boolean <- stream-empty? line
+30     {
+31       compare new-passport?, 0/false
+32       break-if-=
+33       compare curr-passport-field-count, 7
+34       {
+35         break-if-!=
+36         valid-passport-count <- increment
+37         print-string 0, "=> "
+38         print-int32-decimal 0, valid-passport-count
+39         print-string 0, "\n"
+40       }
+41       curr-passport-field-count <- copy 0
+42       loop $main:line-loop
+43     }
+44     $main:word-loop: {
+45       next-word line, slice
+46       var done?/eax: boolean <- slice-empty? slice
+47       compare done?, 0/false
+48       break-if-!=
+49       print-string 0, "  "
+50       print-slice-to-real-screen slice
+51       # treat cid as optional
+52       var optional?/eax: boolean <- slice-starts-with? slice, "cid:"
+53       compare optional?, 0/false
+54       {
+55         break-if-!=
+56         # otherwise assume there are no invalid fields and no duplicate fields
+57         curr-passport-field-count <- increment
+58         print-string 0, " => "
+59         print-int32-decimal 0, curr-passport-field-count
+60       }
+61       print-string 0, "\n"
+62       loop
+63     }
+64     loop
+65   }
+66   # process final passport
+67   compare curr-passport-field-count, 7
+68   {
+69     break-if-!=
+70     valid-passport-count <- increment
+71   }
+72   print-int32-decimal 0, valid-passport-count
+73   print-string 0, "\n"
+74   return 0
+75 }
+
+ + + diff --git a/html/linux/apps/advent2020/4b.mu.html b/html/linux/apps/advent2020/4b.mu.html new file mode 100644 index 00000000..47538296 --- /dev/null +++ b/html/linux/apps/advent2020/4b.mu.html @@ -0,0 +1,381 @@ + + + + +Mu - linux/apps/advent2020/4b.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/advent2020/4b.mu +
+  1 # https://adventofcode.com/2020/day/4
+  2 #
+  3 # To run (on Linux):
+  4 #   $ git clone https://github.com/akkartik/mu
+  5 #   $ cd mu
+  6 #   $ ./translate apps/advent2020/4b.mu
+  7 #   $ ./a.elf < input
+  8 #
+  9 # You'll need to register to download the 'input' file for yourself.
+ 10 
+ 11 fn main -> _/ebx: int {
+ 12   var curr-passport-field-count/esi: int <- copy 0
+ 13   var valid-passport-count/edi: int <- copy 0
+ 14   var line-storage: (stream byte 0x100)  # 256 bytes
+ 15   var line/ecx: (addr stream byte) <- address line-storage
+ 16   var key-slice-storage: slice
+ 17   var key-slice/edx: (addr slice) <- address key-slice-storage
+ 18   var val-slice-storage: slice
+ 19   var val-slice/ebx: (addr slice) <- address val-slice-storage
+ 20   $main:line-loop: {
+ 21     # read line from stdin
+ 22     clear-stream line
+ 23     read-line-from-real-keyboard line
+ 24     # if line is empty (not even a newline), quit
+ 25     var done?/eax: boolean <- stream-empty? line
+ 26     compare done?, 0/false
+ 27     break-if-!=
+ 28     print-stream-to-real-screen line
+ 29     # if line has just a newline, process passport
+ 30     skip-chars-matching-whitespace line
+ 31     var new-passport?/eax: boolean <- stream-empty? line
+ 32     {
+ 33       compare new-passport?, 0/false
+ 34       break-if-=
+ 35       compare curr-passport-field-count, 7
+ 36       {
+ 37         break-if-!=
+ 38         valid-passport-count <- increment
+ 39         print-string 0, "=> "
+ 40         print-int32-decimal 0, valid-passport-count
+ 41         print-string 0, "\n"
+ 42       }
+ 43       curr-passport-field-count <- copy 0
+ 44       loop $main:line-loop
+ 45     }
+ 46     $main:word-loop: {
+ 47       skip-chars-matching-whitespace line
+ 48       var done?/eax: boolean <- stream-empty? line
+ 49       compare done?, 0/false
+ 50       break-if-!=
+ 51       next-token line, 0x3a, key-slice  # ':'
+ 52       var dummy/eax: byte <- read-byte line  # skip ':'
+ 53       next-raw-word line, val-slice
+ 54       print-slice-to-real-screen key-slice
+ 55       print-string 0, " : "
+ 56       print-slice-to-real-screen val-slice
+ 57       print-string 0, "\n"
+ 58       # treat cid as optional
+ 59       var cid?/eax: boolean <- slice-equal? key-slice, "cid"
+ 60       compare cid?, 0/false
+ 61       loop-if-!=
+ 62       # increment field count
+ 63       curr-passport-field-count <- increment
+ 64       # - validate fields one by one, setting curr-passport-field-count to impossibly high value to signal invalid
+ 65       # byr
+ 66       {
+ 67         var byr?/eax: boolean <- slice-equal? key-slice, "byr"
+ 68         compare byr?, 0/false
+ 69         break-if-=
+ 70         # 1920 <= byr <= 2002
+ 71         var byr/eax: int <- parse-decimal-int-from-slice val-slice
+ 72         compare byr, 0x780  # 1920
+ 73         {
+ 74           break-if->=
+ 75           print-string 0, "invalid\n"
+ 76           curr-passport-field-count <- copy 8
+ 77         }
+ 78         compare byr, 0x7d2  # 2002
+ 79         {
+ 80           break-if-<=
+ 81           print-string 0, "invalid\n"
+ 82           curr-passport-field-count <- copy 8
+ 83         }
+ 84       }
+ 85       # iyr
+ 86       {
+ 87         var iyr?/eax: boolean <- slice-equal? key-slice, "iyr"
+ 88         compare iyr?, 0/false
+ 89         break-if-=
+ 90         # 2010 <= iyr <= 2020
+ 91         var iyr/eax: int <- parse-decimal-int-from-slice val-slice
+ 92         compare iyr, 0x7da  # 2010
+ 93         {
+ 94           break-if->=
+ 95           print-string 0, "invalid\n"
+ 96           curr-passport-field-count <- copy 8
+ 97         }
+ 98         compare iyr, 0x7e4  # 2020
+ 99         {
+100           break-if-<=
+101           print-string 0, "invalid\n"
+102           curr-passport-field-count <- copy 8
+103         }
+104       }
+105       # eyr
+106       {
+107         var eyr?/eax: boolean <- slice-equal? key-slice, "eyr"
+108         compare eyr?, 0/false
+109         break-if-=
+110         # 2020 <= eyr <= 2030
+111         var eyr/eax: int <- parse-decimal-int-from-slice val-slice
+112         compare eyr, 0x7e4  # 2020
+113         {
+114           break-if->=
+115           print-string 0, "invalid\n"
+116           curr-passport-field-count <- copy 8
+117         }
+118         compare eyr, 0x7ee  # 2030
+119         {
+120           break-if-<=
+121           print-string 0, "invalid\n"
+122           curr-passport-field-count <- copy 8
+123         }
+124       }
+125       # hgt
+126       {
+127         var hgt?/eax: boolean <- slice-equal? key-slice, "hgt"
+128         compare hgt?, 0/false
+129         break-if-=
+130         # convert val
+131         var s: (handle array byte)
+132         var s2/eax: (addr handle array byte) <- address s
+133         _slice-to-string val-slice, s2
+134         var s3/eax: (addr array byte) <- lookup *s2
+135         var s4/ebx: (addr array byte) <- copy s3
+136         # check suffix
+137         var start/edx: int <- length s4
+138         start <- subtract 2  # luckily both 'in' and 'cm' have the same length
+139         {
+140           var suffix-h: (handle array byte)
+141           var suffix-ah/ecx: (addr handle array byte) <- address suffix-h
+142           substring s4, start, 2, suffix-ah
+143           var suffix/eax: (addr array byte) <- lookup *suffix-ah
+144           {
+145             var match?/eax: boolean <- string-equal? suffix, "in"
+146             compare match?, 0/false
+147             break-if-=
+148             # if suffix is "in", 59 <= val <= 96
+149             var num-h: (handle array byte)
+150             var num-ah/ecx: (addr handle array byte) <- address num-h
+151             substring s4, 0, start, num-ah
+152             var num/eax: (addr array byte) <- lookup *num-ah
+153             var val/eax: int <- parse-decimal-int num
+154             compare val, 0x3b  # 59
+155             {
+156               break-if->=
+157           print-string 0, "invalid\n"
+158               curr-passport-field-count <- copy 8
+159             }
+160             compare val, 0x60  # 96
+161             {
+162               break-if-<=
+163           print-string 0, "invalid\n"
+164               curr-passport-field-count <- copy 8
+165             }
+166             loop $main:word-loop
+167           }
+168           {
+169             var match?/eax: boolean <- string-equal? suffix, "cm"
+170             compare match?, 0/false
+171             break-if-=
+172             # if suffix is "cm", 150 <= val <= 193
+173             var num-h: (handle array byte)
+174             var num-ah/ecx: (addr handle array byte) <- address num-h
+175             substring s4, 0, start, num-ah
+176             var num/eax: (addr array byte) <- lookup *num-ah
+177             var val/eax: int <- parse-decimal-int num
+178             compare val, 0x96  # 150
+179             {
+180               break-if->=
+181           print-string 0, "invalid\n"
+182               curr-passport-field-count <- copy 8
+183             }
+184             compare val, 0xc1  # 193
+185             {
+186               break-if-<=
+187           print-string 0, "invalid\n"
+188               curr-passport-field-count <- copy 8
+189             }
+190             loop $main:word-loop
+191           }
+192           print-string 0, "invalid\n"
+193           curr-passport-field-count <- copy 8
+194           loop $main:word-loop
+195         }
+196       }
+197       # hcl
+198       {
+199         var hcl?/eax: boolean <- slice-equal? key-slice, "hcl"
+200         compare hcl?, 0/false
+201         break-if-=
+202         # convert val
+203         var s: (handle array byte)
+204         var s2/eax: (addr handle array byte) <- address s
+205         _slice-to-string val-slice, s2
+206         var s3/eax: (addr array byte) <- lookup *s2
+207         # check length
+208         var len/ebx: int <- length s3
+209         compare len, 7
+210         {
+211           break-if-=
+212           print-string 0, "invalid\n"
+213           curr-passport-field-count <- copy 8
+214           loop $main:word-loop
+215         }
+216         # check first byte
+217         {
+218           var c/eax: (addr byte) <- index s3, 0
+219           var c2/eax: byte <- copy-byte *c
+220           compare c2, 0x23/hash
+221           break-if-=
+222           print-string 0, "invalid2\n"
+223           curr-passport-field-count <- copy 8
+224           loop $main:word-loop
+225         }
+226         # check remaining bytes
+227         var i/ebx: int <- copy 1  # skip 0
+228         {
+229           compare i, 7
+230           break-if->=
+231           var c/eax: (addr byte) <- index s3, i
+232           {
+233             var c2/eax: byte <- copy-byte *c
+234             var valid?/eax: boolean <- hex-digit? c2
+235             compare valid?, 0
+236             loop-if-= $main:word-loop
+237           }
+238           i <- increment
+239           loop
+240         }
+241       }
+242       # ecl
+243       {
+244         var ecl?/eax: boolean <- slice-equal? key-slice, "ecl"
+245         compare ecl?, 0/false
+246         break-if-=
+247         var amb?/eax: boolean <- slice-equal? val-slice, "amb"
+248         compare amb?, 0/false
+249         loop-if-!= $main:word-loop
+250         var blu?/eax: boolean <- slice-equal? val-slice, "blu"
+251         compare blu?, 0/false
+252         loop-if-!= $main:word-loop
+253         var brn?/eax: boolean <- slice-equal? val-slice, "brn"
+254         compare brn?, 0/false
+255         loop-if-!= $main:word-loop
+256         var gry?/eax: boolean <- slice-equal? val-slice, "gry"
+257         compare gry?, 0/false
+258         loop-if-!= $main:word-loop
+259         var grn?/eax: boolean <- slice-equal? val-slice, "grn"
+260         compare grn?, 0/false
+261         loop-if-!= $main:word-loop
+262         var hzl?/eax: boolean <- slice-equal? val-slice, "hzl"
+263         compare hzl?, 0/false
+264         loop-if-!= $main:word-loop
+265         var oth?/eax: boolean <- slice-equal? val-slice, "oth"
+266         compare oth?, 0/false
+267         loop-if-!= $main:word-loop
+268         print-string 0, "invalid\n"
+269         curr-passport-field-count <- copy 8
+270       }
+271       # pid
+272       {
+273         var pid?/eax: boolean <- slice-equal? key-slice, "pid"
+274         compare pid?, 0/false
+275         break-if-=
+276         # convert val
+277         var s: (handle array byte)
+278         var s2/eax: (addr handle array byte) <- address s
+279         _slice-to-string val-slice, s2
+280         var s3/eax: (addr array byte) <- lookup *s2
+281         # check length
+282         var len/eax: int <- length s3
+283         compare len, 9
+284         {
+285           break-if-=
+286           print-string 0, "invalid\n"
+287           curr-passport-field-count <- copy 8
+288           loop $main:word-loop
+289         }
+290         # check valid decimal int
+291         # parse-decimal-int-from-slice currently returns 0 on invalid parse,
+292         # which isn't ideal but suffices for our purposes
+293         var val/eax: int <- parse-decimal-int-from-slice val-slice
+294         compare val, 0
+295         {
+296           break-if->
+297           print-string 0, "invalid\n"
+298           curr-passport-field-count <- copy 8
+299         }
+300       }
+301       loop
+302     }
+303     loop
+304   }
+305   # process final passport
+306   compare curr-passport-field-count, 7
+307   {
+308     break-if-!=
+309     valid-passport-count <- increment
+310   }
+311   print-int32-decimal 0, valid-passport-count
+312   print-string 0, "\n"
+313   return 0
+314 }
+
+ + + diff --git a/html/linux/apps/advent2020/5a.mu.html b/html/linux/apps/advent2020/5a.mu.html new file mode 100644 index 00000000..3c3b535d --- /dev/null +++ b/html/linux/apps/advent2020/5a.mu.html @@ -0,0 +1,146 @@ + + + + +Mu - linux/apps/advent2020/5a.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/advent2020/5a.mu +
+ 1 # https://adventofcode.com/2020/day/5
+ 2 #
+ 3 # To run (on Linux):
+ 4 #   $ git clone https://github.com/akkartik/mu
+ 5 #   $ cd mu
+ 6 #   $ ./translate apps/advent2020/5a.mu
+ 7 #   $ ./a.elf < input
+ 8 #
+ 9 # You'll need to register to download the 'input' file for yourself.
+10 
+11 fn main -> _/ebx: int {
+12   var line-storage: (stream byte 0x10)  # 16 bytes is enough
+13   var line/edx: (addr stream byte) <- address line-storage
+14   var max-seat-id/edi: int <- copy 0
+15   {
+16     # read line from stdin
+17     clear-stream line
+18     read-line-from-real-keyboard line
+19     print-stream-to-real-screen line
+20     # if line is empty (not even a newline), quit
+21     var done?/eax: boolean <- stream-empty? line
+22     compare done?, 0/false
+23     break-if-!=
+24     # process line
+25     var seat-id/eax: int <- convert-from-binary line
+26     compare seat-id, max-seat-id
+27     {
+28       break-if-<=
+29       max-seat-id <- copy seat-id
+30     }
+31     loop
+32   }
+33   print-int32-decimal 0, max-seat-id
+34   print-string 0, "\n"
+35   return 0
+36 }
+37 
+38 fn convert-from-binary in: (addr stream byte) -> _/eax: int {
+39   var result/edi: int <- copy 0
+40   var i/ecx: int <- copy 9  # loop counter and also exponent
+41   {
+42     compare i, 0
+43     break-if-<
+44     var c/eax: byte <- read-byte in
+45 #?     print-string 0, "char: "
+46 #?     {
+47 #?       var c2/eax: int <- copy c
+48 #?       print-int32-hex 0, c2
+49 #?     }
+50 #?     print-string 0, "\n"
+51     var bit/edx: int <- copy 0
+52     {
+53       compare c, 0x42/B
+54       break-if-!=
+55       bit <- copy 1
+56     }
+57     {
+58       compare c, 0x52/R
+59       break-if-!=
+60       bit <- copy 1
+61     }
+62 #?     print-string 0, "bit: "
+63 #?     print-int32-decimal 0, bit
+64 #?     print-string 0, "\n"
+65     var bit-value/eax: int <- repeated-shift-left bit, i
+66 #?     print-string 0, "bit value: "
+67 #?     print-int32-decimal 0, bit-value
+68 #?     print-string 0, "\n"
+69     result <- add bit-value
+70 #?     print-string 0, "result: "
+71 #?     print-int32-decimal 0, result
+72 #?     print-string 0, "\n"
+73     i <- decrement
+74     loop
+75   }
+76   print-int32-decimal 0, result
+77   print-string 0, "\n"
+78   return result
+79 }
+
+ + + diff --git a/html/linux/apps/advent2020/5b.mu.html b/html/linux/apps/advent2020/5b.mu.html new file mode 100644 index 00000000..b5e1892f --- /dev/null +++ b/html/linux/apps/advent2020/5b.mu.html @@ -0,0 +1,148 @@ + + + + +Mu - linux/apps/advent2020/5b.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/advent2020/5b.mu +
+ 1 # https://adventofcode.com/2020/day/5
+ 2 #
+ 3 # To run (on Linux):
+ 4 #   $ git clone https://github.com/akkartik/mu
+ 5 #   $ cd mu
+ 6 #   $ ./translate apps/advent2020/5b.mu
+ 7 #   $ ./a.elf < input
+ 8 #
+ 9 # You'll need to register to download the 'input' file for yourself.
+10 
+11 fn main -> _/ebx: int {
+12   var pass-storage: (array int 0x400)  # 1k ints
+13   var pass/esi: (addr array int) <- address pass-storage
+14   # phase 1: populate pass array
+15   var line-storage: (stream byte 0x10)  # 16 bytes is enough
+16   var line/edx: (addr stream byte) <- address line-storage
+17   {
+18     # read line from stdin
+19     clear-stream line
+20     read-line-from-real-keyboard line
+21     # if line is empty (not even a newline), quit
+22     var done?/eax: boolean <- stream-empty? line
+23     compare done?, 0/false
+24     break-if-!=
+25     # process line
+26     var seat-id/eax: int <- convert-from-binary line
+27     var dest/eax: (addr int) <- index pass, seat-id
+28     copy-to *dest, 1
+29     loop
+30   }
+31   # phase 2: skip empty seats
+32   var i/eax: int <- copy 0
+33   {
+34     compare i, 0x400
+35     break-if->=
+36     var src/ecx: (addr int) <- index pass, i
+37     compare *src, 0
+38     break-if-!=
+39     i <- increment
+40     loop
+41   }
+42   # phase 3: skip non-empty seats
+43   {
+44     compare i, 0x400
+45     break-if->=
+46     var src/ecx: (addr int) <- index pass, i
+47     compare *src, 0
+48     break-if-=
+49     i <- increment
+50     loop
+51   }
+52   print-int32-decimal 0, i
+53   print-string 0, "\n"
+54   return 0
+55 }
+56 
+57 fn convert-from-binary in: (addr stream byte) -> _/eax: int {
+58   var result/edi: int <- copy 0
+59   var i/ecx: int <- copy 9  # loop counter and also exponent
+60   {
+61     compare i, 0
+62     break-if-<
+63     var c/eax: byte <- read-byte in
+64     var bit/edx: int <- copy 0
+65     {
+66       compare c, 0x42/B
+67       break-if-!=
+68       bit <- copy 1
+69     }
+70     {
+71       compare c, 0x52/R
+72       break-if-!=
+73       bit <- copy 1
+74     }
+75     var bit-value/eax: int <- repeated-shift-left bit, i
+76     result <- add bit-value
+77     i <- decrement
+78     loop
+79   }
+80   return result
+81 }
+
+ + + diff --git a/html/linux/apps/arith.mu.html b/html/linux/apps/arith.mu.html new file mode 100644 index 00000000..fb6a9194 --- /dev/null +++ b/html/linux/apps/arith.mu.html @@ -0,0 +1,326 @@ + + + + +Mu - linux/apps/arith.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/arith.mu +
+  1 # Integer arithmetic using conventional precedence.
+  2 #
+  3 # Follows part 2 of Jack Crenshaw's "Let's build a compiler!"
+  4 #   https://compilers.iecc.com/crenshaw
+  5 #
+  6 # Limitations:
+  7 #   No division yet.
+  8 #
+  9 # To build:
+ 10 #   $ ./translate apps/arith.mu
+ 11 #
+ 12 # Example session:
+ 13 #   $ ./a.elf
+ 14 #   press ctrl-c or ctrl-d to exit
+ 15 #   > 1
+ 16 #   1
+ 17 #   > 1+1
+ 18 #   2
+ 19 #   > 1 + 1
+ 20 #   2
+ 21 #   > 1+2 +3
+ 22 #   6
+ 23 #   > 1+2 *3
+ 24 #   7
+ 25 #   > (1+2) *3
+ 26 #   9
+ 27 #   > 1 + 3*4
+ 28 #   13
+ 29 #   > ^D
+ 30 #   $
+ 31 #
+ 32 # Error handling is non-existent. This is just a prototype.
+ 33 
+ 34 fn main -> _/ebx: int {
+ 35   enable-keyboard-immediate-mode
+ 36   var look/esi: grapheme <- copy 0  # lookahead
+ 37   var n/eax: int <- copy 0  # result of each expression
+ 38   print-string 0/screen, "press ctrl-c or ctrl-d to exit\n"
+ 39   # read-eval-print loop
+ 40   {
+ 41     # print prompt
+ 42     print-string 0/screen, "> "
+ 43     # read and eval
+ 44     n, look <- simplify  # we explicitly thread 'look' everywhere
+ 45     # if (look == 0) break
+ 46     compare look, 0
+ 47     break-if-=
+ 48     # print
+ 49     print-int32-decimal 0/screen, n
+ 50     print-string 0/screen, "\n"
+ 51     #
+ 52     loop
+ 53   }
+ 54   enable-keyboard-type-mode
+ 55   return 0
+ 56 }
+ 57 
+ 58 fn simplify -> _/eax: int, _/esi: grapheme {
+ 59   # prime the pump
+ 60   var look/esi: grapheme <- get-char
+ 61   # do it
+ 62   var result/eax: int <- copy 0
+ 63   result, look <- expression look
+ 64   return result, look
+ 65 }
+ 66 
+ 67 fn expression _look: grapheme -> _/eax: int, _/esi: grapheme {
+ 68   var look/esi: grapheme <- copy _look
+ 69   # read arg
+ 70   var result/eax: int <- copy 0
+ 71   result, look <- term look
+ 72   $expression:loop: {
+ 73     # while next non-space char in ['+', '-']
+ 74     look <- skip-spaces look
+ 75     {
+ 76       var continue?/eax: boolean <- add-or-sub? look
+ 77       compare continue?, 0/false
+ 78       break-if-= $expression:loop
+ 79     }
+ 80     # read operator
+ 81     var op/ecx: grapheme <- copy 0
+ 82     op, look <- operator look
+ 83     # read next arg
+ 84     var second/edx: int <- copy 0
+ 85     look <- skip-spaces look
+ 86     {
+ 87       var tmp/eax: int <- copy 0
+ 88       tmp, look <- term look
+ 89       second <- copy tmp
+ 90     }
+ 91     # reduce
+ 92     $expression:perform-op: {
+ 93       {
+ 94         compare op, 0x2b/+
+ 95         break-if-!=
+ 96         result <- add second
+ 97         break $expression:perform-op
+ 98       }
+ 99       {
+100         compare op, 0x2d/minus
+101         break-if-!=
+102         result <- subtract second
+103         break $expression:perform-op
+104       }
+105     }
+106     loop
+107   }
+108   look <- skip-spaces look
+109   return result, look
+110 }
+111 
+112 fn term _look: grapheme -> _/eax: int, _/esi: grapheme {
+113   var look/esi: grapheme <- copy _look
+114   # read arg
+115   look <- skip-spaces look
+116   var result/eax: int <- copy 0
+117   result, look <- factor look
+118   $term:loop: {
+119     # while next non-space char in ['*', '/']
+120     look <- skip-spaces look
+121     {
+122       var continue?/eax: boolean <- mul-or-div? look
+123       compare continue?, 0/false
+124       break-if-= $term:loop
+125     }
+126     # read operator
+127     var op/ecx: grapheme <- copy 0
+128     op, look <- operator look
+129     # read next arg
+130     var second/edx: int <- copy 0
+131     look <- skip-spaces look
+132     {
+133       var tmp/eax: int <- copy 0
+134       tmp, look <- factor look
+135       second <- copy tmp
+136     }
+137     # reduce
+138     $term:perform-op: {
+139       {
+140         compare op, 0x2a/*
+141         break-if-!=
+142         result <- multiply second
+143         break $term:perform-op
+144       }
+145 #?       {
+146 #?         compare op, 0x2f/slash
+147 #?         break-if-!=
+148 #?         result <- divide second  # not in Mu yet
+149 #?         break $term:perform-op
+150 #?       }
+151     }
+152     loop
+153   }
+154   return result, look
+155 }
+156 
+157 fn factor _look: grapheme -> _/eax: int, _/esi: grapheme {
+158   var look/esi: grapheme <- copy _look  # should be a no-op
+159   look <- skip-spaces look
+160   # if next char is not '(', parse a number
+161   compare look, 0x28/open-paren
+162   {
+163     break-if-=
+164     var result/eax: int <- copy 0
+165     result, look <- num look
+166     return result, look
+167   }
+168   # otherwise recurse
+169   look <- get-char  # '('
+170   var result/eax: int <- copy 0
+171   result, look <- expression look
+172   look <- skip-spaces look
+173   look <- get-char  # ')'
+174   return result, look
+175 }
+176 
+177 fn mul-or-div? c: grapheme -> _/eax: boolean {
+178   compare c, 0x2a/*
+179   {
+180     break-if-!=
+181     return 1/true
+182   }
+183   compare c, 0x2f/slash
+184   {
+185     break-if-!=
+186     return 1/true
+187   }
+188   return 0/false
+189 }
+190 
+191 fn add-or-sub? c: grapheme -> _/eax: boolean {
+192   compare c, 0x2b/+
+193   {
+194     break-if-!=
+195     return 1/true
+196   }
+197   compare c, 0x2d/minus
+198   {
+199     break-if-!=
+200     return 1/true
+201   }
+202   return 0/false
+203 }
+204 
+205 fn operator _look: grapheme -> _/ecx: grapheme, _/esi: grapheme {
+206   var op/ecx: grapheme <- copy _look
+207   var look/esi: grapheme <- get-char
+208   return op, look
+209 }
+210 
+211 fn num _look: grapheme -> _/eax: int, _/esi: grapheme {
+212   var look/esi: grapheme <- copy _look
+213   var result/edi: int <- copy 0
+214   {
+215     var first-digit/eax: int <- to-decimal-digit look
+216     result <- copy first-digit
+217   }
+218   {
+219     look <- get-char
+220     # done?
+221     var digit?/eax: boolean <- decimal-digit? look
+222     compare digit?, 0/false
+223     break-if-=
+224     # result *= 10
+225     {
+226       var ten/eax: int <- copy 0xa
+227       result <- multiply ten
+228     }
+229     # result += digit(look)
+230     var digit/eax: int <- to-decimal-digit look
+231     result <- add digit
+232     loop
+233   }
+234   return result, look
+235 }
+236 
+237 fn skip-spaces _look: grapheme -> _/esi: grapheme {
+238   var look/esi: grapheme <- copy _look  # should be a no-op
+239   {
+240     compare look, 0x20
+241     break-if-!=
+242     look <- get-char
+243     loop
+244   }
+245   return look
+246 }
+247 
+248 fn get-char -> _/esi: grapheme {
+249   var look/eax: grapheme <- read-key-from-real-keyboard
+250   print-grapheme-to-real-screen look
+251   compare look, 4
+252   {
+253     break-if-!=
+254     print-string 0/screen, "^D\n"
+255     syscall_exit
+256   }
+257   return look
+258 }
+
+ + + diff --git a/html/linux/apps/crenshaw2-1.subx.html b/html/linux/apps/crenshaw2-1.subx.html new file mode 100644 index 00000000..191ff721 --- /dev/null +++ b/html/linux/apps/crenshaw2-1.subx.html @@ -0,0 +1,621 @@ + + + + +Mu - linux/apps/crenshaw2-1.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/crenshaw2-1.subx +
+  1 # Port of https://github.com/akkartik/crenshaw/blob/master/tutor2.1.pas
+  2 # which corresponds to the section "single digits" in https://compilers.iecc.com/crenshaw/tutor2.txt
+  3 # except that we support hex digits.
+  4 #
+  5 # To run:
+  6 #   $ bootstrap/bootstrap translate [01]*.subx apps/crenshaw2-1.subx -o crenshaw2-1
+  7 #   $ echo '3'  |bootstrap/bootstrap run crenshaw2-1
+  8 # Expected output:
+  9 #   # syscall(exit, 3)
+ 10 #   bb/copy-to-ebx  3/imm32
+ 11 #   b8/copy-to-eax  1/imm32/exit
+ 12 #   cd/syscall  0x80/imm8
+ 13 #
+ 14 # To run the generated output:
+ 15 #   $ echo '3'  |bootstrap/bootstrap run crenshaw2-1 > z1.subx
+ 16 #   $ bootstrap/bootstrap translate z1.subx -o z1
+ 17 #   $ bootstrap/bootstrap run z1
+ 18 #   $ echo $?
+ 19 #   3
+ 20 #
+ 21 # Stdin must contain just a single hex digit. Other input will print an error:
+ 22 #   $ echo 'xyz'  |bootstrap/bootstrap run crenshaw2-1
+ 23 #   Error: integer expected
+ 24 #
+ 25 # Names in this file sometimes follow Crenshaw's original rather than my usual
+ 26 # naming conventions.
+ 27 
+ 28 == code
+ 29 #   instruction                     effective address                                                   register    displacement    immediate
+ 30 # . op          subop               mod             rm32          base        index         scale       r32
+ 31 # . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
+ 32 
+ 33 Entry:  # run tests if necessary, call 'compile' if not
+ 34     # . prologue
+ 35     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 36 
+ 37     # initialize heap
+ 38     # . Heap = new-segment(Heap-size)
+ 39     # . . push args
+ 40     68/push  Heap/imm32
+ 41     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Heap-size/disp32                  # push *Heap-size
+ 42     # . . call
+ 43     e8/call  new-segment/disp32
+ 44     # . . discard args
+ 45     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 46 
+ 47     # - if argc > 1 and argv[1] == "test", then return run_tests()
+ 48     # if (argc <= 1) goto run-main
+ 49     81          7/subop/compare     1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0/disp8         1/imm32           # compare *ebp
+ 50     7e/jump-if-<=  $run-main/disp8
+ 51     # if (!kernel-string-equal?(argv[1], "test")) goto run-main
+ 52     # . eax = kernel-string-equal?(argv[1], "test")
+ 53     # . . push args
+ 54     68/push  "test"/imm32
+ 55     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+ 56     # . . call
+ 57     e8/call  kernel-string-equal?/disp32
+ 58     # . . discard args
+ 59     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 60     # . if (eax == false) goto run-main
+ 61     3d/compare-eax-and  0/imm32/false
+ 62     74/jump-if-=  $run-main/disp8
+ 63     # run-tests()
+ 64     e8/call  run-tests/disp32
+ 65     # syscall(exit, *Num-test-failures)
+ 66     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/ebx   Num-test-failures/disp32          # copy *Num-test-failures to ebx
+ 67     eb/jump  $main:end/disp8
+ 68 $run-main:
+ 69     # - otherwise read a program from stdin and emit its translation to stdout
+ 70     # . compile(Stdin, 1/stdout, 2/stderr, ed)
+ 71     # . . push args
+ 72     68/push  0/imm32/exit-descriptor
+ 73     68/push  2/imm32/stderr
+ 74     68/push  1/imm32/stdout
+ 75     68/push  Stdin/imm32
+ 76     # . . call
+ 77     e8/call  compile/disp32
+ 78     # . . discard args
+ 79     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+ 80     # syscall(exit, 0)
+ 81     bb/copy-to-ebx  0/imm32
+ 82 $main:end:
+ 83     e8/call  syscall_exit/disp32
+ 84 
+ 85 # the main entry point
+ 86 compile:  # in: (addr buffered-file), out: fd or (addr stream byte), err: fd or (addr stream byte), ed: (addr exit-descriptor)
+ 87     # . prologue
+ 88     55/push-ebp
+ 89     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 90     # . save registers
+ 91     50/push-eax
+ 92     51/push-ecx
+ 93     # prime the pump
+ 94     # . Look = get-char(in)
+ 95     # . . push args
+ 96     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8      .                    # push *(ebp+8)
+ 97     # . . call
+ 98     e8/call  get-char/disp32
+ 99     # . . discard args
+100     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+101     # var num/ecx: (stream byte 7)
+102     # Numbers can be 32 bits or 8 hex bytes long. One of them will be in 'Look', so we need space for 7 bytes.
+103     # Sizing the stream just right buys us overflow-handling for free inside 'get-num'.
+104     # Add 12 bytes for 'read', 'write' and 'size' fields, for a total of 19 bytes, or 0x13 in hex.
+105     # The stack pointer is no longer aligned, so dump_stack() can be misleading past this point.
+106     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x13/imm32        # subtract from esp
+107     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+108     # initialize the stream
+109     # . num->size = 7
+110     c7          0/subop/copy        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           8/disp8         7/imm32           # copy to *(ecx+8)
+111     # . clear-stream(num)
+112     # . . push args
+113     51/push-ecx
+114     # . . call
+115     e8/call  clear-stream/disp32
+116     # . . discard args
+117     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+118     # read a digit from 'in' into 'num'
+119     # . get-num(in, num, err, ed)
+120     # . . push args
+121     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
+122     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
+123     51/push-ecx/num
+124     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8      .                    # push *(ebp+8)
+125     # . . call
+126     e8/call  get-num/disp32
+127     # . . discard args
+128     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+129     # render 'num' into the following template on 'out':
+130     #   bb/copy-to-ebx  _num_
+131     #   b8/copy-to-eax  1/imm32/exit
+132     #   cd/syscall  0x80/imm8
+133     #
+134     # . write(out, "bb/copy-to-ebx  ")
+135     # . . push args
+136     68/push  "bb/copy-to-ebx  "/imm32
+137     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+138     # . . call
+139     e8/call  write/disp32
+140     # . . discard args
+141     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+142     # . write-stream(out, num)
+143     # . . push args
+144     51/push-ecx/num
+145     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+146     # . . call
+147     e8/call  write-stream/disp32
+148     # . . discard args
+149     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+150     # . write(out, Newline)
+151     # . . push args
+152     68/push  Newline/imm32
+153     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+154     # . . call
+155     e8/call  write/disp32
+156     # . . discard args
+157     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+158     # . write(out, "b8/copy-to-eax  1/imm32/exit\n")
+159     # . . push args
+160     68/push  "b8/copy-to-eax  1/imm32/exit\n"/imm32
+161     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+162     # . . call
+163     e8/call  write/disp32
+164     # . . discard args
+165     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+166     # . write(out, "cd/syscall  0x80/imm8\n")
+167     # . . push args
+168     68/push  "cd/syscall  0x80/imm8\n"/imm32
+169     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+170     # . . call
+171     e8/call  write/disp32
+172     # . . discard args
+173     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+174 $compile:end:
+175     # . restore registers
+176     59/pop-to-ecx
+177     58/pop-to-eax
+178     # . epilogue
+179     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+180     5d/pop-to-ebp
+181     c3/return
+182 
+183 # Read a single digit into 'out'. Abort if there are none, or if there is no
+184 # space in 'out'.
+185 # Input comes from the global variable 'Look' (first byte) and the argument
+186 # 'in' (rest). We leave the next byte from 'in' into 'Look' on exit.
+187 get-num:  # in: (addr buffered-file), out: (addr stream byte), err: fd or (addr stream byte), ed: (addr exit-descriptor)
+188     # pseudocode:
+189     #   if (!digit?(Look)) expected(ed, err, "integer")
+190     #   if out->write >= out->size
+191     #     write(err, "Error: too many digits in number\n")
+192     #     stop(ed, 1)
+193     #   out->data[out->write] = LSB(Look)
+194     #   ++out->write
+195     #   Look = get-char(in)
+196     #
+197     # registers:
+198     #   in: esi
+199     #   out: edi
+200     #   out->write: ecx (cached copy; need to keep in sync)
+201     #   out->size: edx
+202     #   temporaries: eax, ebx
+203     # We can't allocate Look to a register because it gets written implicitly in
+204     # get-char in each iteration of the loop. (Thereby demonstrating that it's
+205     # not the right interface for us. But we'll keep it just to follow Crenshaw.)
+206     #
+207     # . prologue
+208     55/push-ebp
+209     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+210     # - if (digit?(Look)) expected(ed, err, "integer")
+211     # . eax = digit?(Look)
+212     # . . push args
+213     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Look/disp32     .                 # push *Look
+214     # . . call
+215     e8/call  digit?/disp32
+216     # . . discard args
+217     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+218     # . if (eax == false)
+219     3d/compare-eax-and  0/imm32/false
+220     75/jump-if-!=  $get-num:main/disp8
+221     # . expected(ed, err, "integer")
+222     # . . push args
+223     68/push  "integer"/imm32
+224     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
+225     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
+226     # . . call
+227     e8/call  expected/disp32  # never returns
+228     # . . discard args
+229     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+230 $get-num:main:
+231     # - otherwise read a digit
+232     # . save registers
+233     50/push-eax
+234     51/push-ecx
+235     52/push-edx
+236     53/push-ebx
+237     56/push-esi
+238     57/push-edi
+239     # read necessary variables to registers
+240     # esi = in
+241     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
+242     # edi = out
+243     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   0xc/disp8       .                 # copy *(ebp+12) to edi
+244     # ecx = out->write
+245     8b/copy                         0/mod/indirect  7/rm32/edi    .           .             .           1/r32/ecx   .               .                 # copy *edi to ecx
+246     # edx = out->size
+247     8b/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           2/r32/edx   8/disp8         .                 # copy *(edi+8) to edx
+248 $get-num:loop:
+249     # if (out->write >= out->size) error
+250     39/compare                      3/mod/direct    2/rm32/edx    .           .             .           1/r32/ecx   .               .                 # compare edx with ecx
+251     7d/jump-if-<  $get-num:stage2/disp8
+252     # . error(ed, err, msg)  # TODO: show full number
+253     # . . push args
+254     68/push  "get-num: too many digits in number"/imm32
+255     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
+256     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
+257     # . . call
+258     e8/call  error/disp32  # never returns
+259     # . . discard args
+260     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+261 $get-num:stage2:
+262     # out->data[out->write] = LSB(Look)
+263     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    7/base/edi  1/index/ecx   .           3/r32/ebx   0xc/disp8       .                 # copy edi+ecx+12 to ebx
+264     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Look/disp32     .                 # copy *Look to eax
+265     88/copy-byte                    0/mod/indirect  3/rm32/ebx    .           .             .           0/r32/AL    .               .                 # copy byte at AL to *ebx
+266     # ++out->write
+267     41/increment-ecx
+268     # Look = get-char(in)
+269     # . . push args
+270     56/push-esi
+271     # . . call
+272     e8/call  get-char/disp32
+273     # . . discard args
+274     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+275 $get-num:loop-end:
+276     # persist necessary variables from registers
+277     89/copy                         0/mod/indirect  7/rm32/edi    .           .             .           1/r32/ecx   .               .                 # copy ecx to *edi
+278 $get-num:end:
+279     # . restore registers
+280     5f/pop-to-edi
+281     5e/pop-to-esi
+282     5b/pop-to-ebx
+283     5a/pop-to-edx
+284     59/pop-to-ecx
+285     58/pop-to-eax
+286     # . epilogue
+287     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+288     5d/pop-to-ebp
+289     c3/return
+290 
+291 test-get-num-reads-single-digit:
+292     # - check that get-num returns first character if it's a digit
+293     # This test uses exit-descriptors. Use ebp for setting up local variables.
+294     55/push-ebp
+295     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+296     # clear all streams
+297     # . clear-stream(_test-stream)
+298     # . . push args
+299     68/push  _test-stream/imm32
+300     # . . call
+301     e8/call  clear-stream/disp32
+302     # . . discard args
+303     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+304     # . clear-stream($_test-buffered-file->buffer)
+305     # . . push args
+306     68/push  $_test-buffered-file->buffer/imm32
+307     # . . call
+308     e8/call  clear-stream/disp32
+309     # . . discard args
+310     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+311     # . clear-stream(_test-output-stream)
+312     # . . push args
+313     68/push  _test-output-stream/imm32
+314     # . . call
+315     e8/call  clear-stream/disp32
+316     # . . discard args
+317     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+318     # . clear-stream(_test-error-stream)
+319     # . . push args
+320     68/push  _test-error-stream/imm32
+321     # . . call
+322     e8/call  clear-stream/disp32
+323     # . . discard args
+324     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+325     # initialize 'in'
+326     # . write(_test-stream, "3")
+327     # . . push args
+328     68/push  "3"/imm32
+329     68/push  _test-stream/imm32
+330     # . . call
+331     e8/call  write/disp32
+332     # . . discard args
+333     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+334     # initialize exit-descriptor 'ed' for the call to 'get-num' below
+335     # . var ed/eax: exit-descriptor
+336     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # subtract from esp
+337     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           4/r32/esp   .               .                 # copy esp to eax
+338     # . tailor-exit-descriptor(ed, 16)
+339     # . . push args
+340     68/push  0x10/imm32/nbytes-of-args-for-get-num
+341     50/push-eax/ed
+342     # . . call
+343     e8/call  tailor-exit-descriptor/disp32
+344     # . . discard args
+345     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+346     # prime the pump
+347     # . get-char(_test-buffered-file)
+348     # . . push args
+349     68/push  _test-buffered-file/imm32
+350     # . . call
+351     e8/call  get-char/disp32
+352     # . . discard args
+353     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+354     # get-num(in, out, err, ed)
+355     # . . push args
+356     50/push-eax/ed
+357     68/push  _test-error-stream/imm32
+358     68/push  _test-output-stream/imm32
+359     68/push  _test-buffered-file/imm32
+360     # . . call
+361     e8/call  get-num/disp32
+362     # registers except esp may be clobbered at this point
+363     # . . discard args
+364     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+365     # check-ints-equal(*_test-output-stream->data, '3', msg)
+366     # . . push args
+367     68/push  "F - test-get-num-reads-single-digit"/imm32
+368     68/push  0x33/imm32
+369     b8/copy-to-eax  _test-output-stream/imm32
+370     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           0xc/disp8       .                 # push *(eax+12)
+371     # . . call
+372     e8/call  check-ints-equal/disp32
+373     # . . discard args
+374     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+375     # . reclaim locals
+376     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+377     5d/pop-to-ebp
+378     c3/return
+379 
+380 test-get-num-aborts-on-non-digit-in-Look:
+381     # - check that get-num returns first character if it's a digit
+382     # This test uses exit-descriptors. Use ebp for setting up local variables.
+383     55/push-ebp
+384     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+385     # clear all streams
+386     # . clear-stream(_test-stream)
+387     # . . push args
+388     68/push  _test-stream/imm32
+389     # . . call
+390     e8/call  clear-stream/disp32
+391     # . . discard args
+392     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+393     # . clear-stream($_test-buffered-file->buffer)
+394     # . . push args
+395     68/push  $_test-buffered-file->buffer/imm32
+396     # . . call
+397     e8/call  clear-stream/disp32
+398     # . . discard args
+399     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+400     # . clear-stream(_test-output-stream)
+401     # . . push args
+402     68/push  _test-output-stream/imm32
+403     # . . call
+404     e8/call  clear-stream/disp32
+405     # . . discard args
+406     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+407     # . clear-stream(_test-error-stream)
+408     # . . push args
+409     68/push  _test-error-stream/imm32
+410     # . . call
+411     e8/call  clear-stream/disp32
+412     # . . discard args
+413     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+414     # initialize 'in'
+415     # . write(_test-stream, "3")
+416     # . . push args
+417     68/push  "3"/imm32
+418     68/push  _test-stream/imm32
+419     # . . call
+420     e8/call  write/disp32
+421     # . . discard args
+422     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+423     # initialize exit-descriptor 'ed' for the call to 'get-num' below
+424     # . var ed/eax: exit-descriptor
+425     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # subtract from esp
+426     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           4/r32/esp   .               .                 # copy esp to eax
+427     # . tailor-exit-descriptor(ed, 16)
+428     # . . push args
+429     68/push  0x10/imm32/nbytes-of-args-for-get-num
+430     50/push-eax/ed
+431     # . . call
+432     e8/call  tailor-exit-descriptor/disp32
+433     # . . discard args
+434     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+435     # *don't* prime the pump
+436     # get-num(in, out, err, ed)
+437     # . . push args
+438     50/push-eax/ed
+439     68/push  _test-error-stream/imm32
+440     68/push  _test-output-stream/imm32
+441     68/push  _test-buffered-file/imm32
+442     # . . call
+443     e8/call  get-num/disp32
+444     # registers except esp may be clobbered at this point
+445     # . . discard args
+446     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+447     # check that get-num tried to call exit(1)
+448     # . check-ints-equal(ed->value, 2, msg)  # i.e. stop was called with value 1
+449     # . . push args
+450     68/push  "F - test-get-num-aborts-on-non-digit-in-Look"/imm32
+451     68/push  2/imm32
+452     # . . push ed->value
+453     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
+454     # . . call
+455     e8/call  check-ints-equal/disp32
+456     # . . discard args
+457     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+458     # . reclaim locals
+459     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+460     5d/pop-to-ebp
+461     c3/return
+462 
+463 ## helpers
+464 
+465 # write(f, "Error: "+s+" expected\n") then stop(ed, 1)
+466 expected:  # ed: (addr exit-descriptor), f: fd or (addr stream byte), s: (addr array byte)
+467     # . prologue
+468     55/push-ebp
+469     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+470     # write(f, "Error: ")
+471     # . . push args
+472     68/push  "Error: "/imm32
+473     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+474     # . . call
+475     e8/call  write/disp32
+476     # . . discard args
+477     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+478     # write(f, s)
+479     # . . push args
+480     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
+481     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+482     # . . call
+483     e8/call  write/disp32
+484     # . . discard args
+485     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+486     # write(f, " expected\n")
+487     # . . push args
+488     68/push  " expected\n"/imm32
+489     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+490     # . . call
+491     e8/call  write/disp32
+492     # . . discard args
+493     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+494     # stop(ed, 1)
+495     # . . push args
+496     68/push  1/imm32
+497     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+498     # . . call
+499     e8/call  stop/disp32
+500     # should never get past this point
+501 $expected:dead-end:
+502     # . epilogue
+503     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+504     5d/pop-to-ebp
+505     c3/return
+506 
+507 # read a byte from 'f', and save it in 'Look'
+508 get-char:  # f: (addr buffered-file)
+509     # . prologue
+510     55/push-ebp
+511     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+512     # . save registers
+513     50/push-eax
+514     # eax = read-byte-buffered(f)
+515     # . . push args
+516     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+517     # . . call
+518     e8/call  read-byte-buffered/disp32
+519     # . . discard args
+520     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+521     # save eax to Look
+522     89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Look/disp32     .                 # copy eax to *Look
+523 $get-char:end:
+524     # . restore registers
+525     58/pop-to-eax
+526     # . epilogue
+527     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+528     5d/pop-to-ebp
+529     c3/return
+530 
+531 digit?:  # c: int -> eax: boolean
+532     # . prologue
+533     55/push-ebp
+534     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+535     # eax = false
+536     b8/copy-to-eax  0/imm32
+537     # if (c < '0') return false
+538     81          7/subop/compare     1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         0x30/imm32        # compare *(ebp+8)
+539     7c/jump-if-<  $digit?:end/disp8
+540     # if (c > '9') return false
+541     81          7/subop/compare     1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         0x39/imm32        # compare *(ebp+8)
+542     7f/jump-if->  $digit?:end/disp8
+543     # otherwise return true
+544     b8/copy-to-eax  1/imm32
+545 $digit?:end:
+546     # . epilogue
+547     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+548     5d/pop-to-ebp
+549     c3/return
+550 
+551 == data
+552 
+553 Look:  # (char with some extra padding)
+554     0/imm32
+555 
+556 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/crenshaw2-1b.subx.html b/html/linux/apps/crenshaw2-1b.subx.html new file mode 100644 index 00000000..8a50be2c --- /dev/null +++ b/html/linux/apps/crenshaw2-1b.subx.html @@ -0,0 +1,815 @@ + + + + +Mu - linux/apps/crenshaw2-1b.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/crenshaw2-1b.subx +
+  1 # Port of https://github.com/akkartik/crenshaw/blob/master/tutor2.1.pas
+  2 # which corresponds to the section "single digits" in https://compilers.iecc.com/crenshaw/tutor2.txt
+  3 # except that we support hex numbers of multiple digits.
+  4 #
+  5 # To run:
+  6 #   $ bootstrap/bootstrap translate [01]*.subx apps/crenshaw2-1b.subx -o crenshaw2-1b
+  7 #   $ echo '1a'  |bootstrap/bootstrap run crenshaw2-1b
+  8 # Expected output:
+  9 #   # syscall(exit, 1a)
+ 10 #   bb/copy-to-ebx  3/imm32
+ 11 #   b8/copy-to-eax  1/imm32/exit
+ 12 #   cd/syscall  0x80/imm8
+ 13 #
+ 14 # To run the generated output:
+ 15 #   $ echo '1a'  |bootstrap/bootstrap run crenshaw2-1b > z1.subx
+ 16 #   $ bootstrap/bootstrap translate z1.subx -o z1
+ 17 #   $ bootstrap/bootstrap run z1
+ 18 #   $ echo $?
+ 19 #   26  # 0x1a in decimal
+ 20 #
+ 21 # Stdin must contain just a single hex digit. Other input will print an error:
+ 22 #   $ echo 'xyz'  |bootstrap/bootstrap run crenshaw2-1b
+ 23 #   Error: integer expected
+ 24 #
+ 25 # Names in this file sometimes follow Crenshaw's original rather than my usual
+ 26 # naming conventions.
+ 27 
+ 28 == code
+ 29 #   instruction                     effective address                                                   register    displacement    immediate
+ 30 # . op          subop               mod             rm32          base        index         scale       r32
+ 31 # . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
+ 32 
+ 33 Entry:  # run tests if necessary, call 'compile' if not
+ 34     # . prologue
+ 35     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 36 
+ 37     # initialize heap
+ 38     # . Heap = new-segment(Heap-size)
+ 39     # . . push args
+ 40     68/push  Heap/imm32
+ 41     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Heap-size/disp32                  # push *Heap-size
+ 42     # . . call
+ 43     e8/call  new-segment/disp32
+ 44     # . . discard args
+ 45     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 46 
+ 47     # - if argc > 1 and argv[1] == "test", then return run_tests()
+ 48     # if (argc <= 1) goto run-main
+ 49     81          7/subop/compare     1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0/disp8         1/imm32           # compare *ebp
+ 50     7e/jump-if-<=  $run-main/disp8
+ 51     # if (!kernel-string-equal?(argv[1], "test")) goto run-main
+ 52     # . eax = kernel-string-equal?(argv[1], "test")
+ 53     # . . push args
+ 54     68/push  "test"/imm32
+ 55     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+ 56     # . . call
+ 57     e8/call  kernel-string-equal?/disp32
+ 58     # . . discard args
+ 59     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 60     # . if (eax == false) goto run-main
+ 61     3d/compare-eax-and  0/imm32/false
+ 62     74/jump-if-=  $run-main/disp8
+ 63     # run-tests()
+ 64     e8/call  run-tests/disp32
+ 65     # syscall(exit, *Num-test-failures)
+ 66     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/ebx   Num-test-failures/disp32          # copy *Num-test-failures to ebx
+ 67     eb/jump  $main:end/disp8
+ 68 $run-main:
+ 69     # - otherwise read a program from stdin and emit its translation to stdout
+ 70     # . compile(Stdin, 1/stdout, 2/stderr, 0)
+ 71     # . . push args
+ 72     68/push  0/imm32/exit-descriptor
+ 73     68/push  2/imm32/stderr
+ 74     68/push  1/imm32/stdout
+ 75     68/push  Stdin/imm32
+ 76     # . . call
+ 77     e8/call  compile/disp32
+ 78     # . . discard args
+ 79     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+ 80     # syscall(exit, 0)
+ 81     bb/copy-to-ebx  0/imm32
+ 82 $main:end:
+ 83     e8/call  syscall_exit/disp32
+ 84 
+ 85 # the main entry point
+ 86 compile:  # in: (addr buffered-file), out: fd or (addr stream byte), err: fd or (addr stream byte), ed: (addr exit-descriptor)
+ 87     # . prologue
+ 88     55/push-ebp
+ 89     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 90     # . save registers
+ 91     50/push-eax
+ 92     51/push-ecx
+ 93     # prime the pump
+ 94     # . Look = get-char(in)
+ 95     # . . push args
+ 96     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8      .                    # push *(ebp+8)
+ 97     # . . call
+ 98     e8/call  get-char/disp32
+ 99     # . . discard args
+100     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+101     # var num/ecx: (stream byte 7)
+102     # Numbers can be 32 bits or 8 hex bytes long. One of them will be in 'Look', so we need space for 7 bytes.
+103     # Sizing the stream just right buys us overflow-handling for free inside 'get-num'.
+104     # Add 12 bytes for 'read', 'write' and 'size' fields, for a total of 19 bytes, or 0x13 in hex.
+105     # The stack pointer is no longer aligned, so dump_stack() can be misleading past this point.
+106     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x13/imm32        # subtract from esp
+107     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+108     # initialize the stream
+109     # . num->size = 7
+110     c7          0/subop/copy        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           8/disp8         7/imm32           # copy to *(ecx+8)
+111     # . clear-stream(num)
+112     # . . push args
+113     51/push-ecx
+114     # . . call
+115     e8/call  clear-stream/disp32
+116     # . . discard args
+117     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+118     # read a digit from 'in' into 'num'
+119     # . get-num(in, num, err, ed)
+120     # . . push args
+121     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
+122     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
+123     51/push-ecx/num
+124     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8      .                    # push *(ebp+8)
+125     # . . call
+126     e8/call  get-num/disp32
+127     # . . discard args
+128     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+129     # render 'num' into the following template on 'out':
+130     #   bb/copy-to-ebx  _num_
+131     #   b8/copy-to-eax  1/imm32/exit
+132     #   cd/syscall  0x80/imm8
+133     #
+134     # . write(out, "bb/copy-to-ebx  ")
+135     # . . push args
+136     68/push  "bb/copy-to-ebx  "/imm32
+137     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+138     # . . call
+139     e8/call  write/disp32
+140     # . . discard args
+141     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+142     # . write-stream(out, num)
+143     # . . push args
+144     51/push-ecx/num
+145     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+146     # . . call
+147     e8/call  write-stream/disp32
+148     # . . discard args
+149     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+150     # . write(out, Newline)
+151     # . . push args
+152     68/push  Newline/imm32
+153     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+154     # . . call
+155     e8/call  write/disp32
+156     # . . discard args
+157     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+158     # . write(out, "b8/copy-to-eax  1/imm32/exit\n")
+159     # . . push args
+160     68/push  "b8/copy-to-eax  1/imm32/exit\n"/imm32
+161     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+162     # . . call
+163     e8/call  write/disp32
+164     # . . discard args
+165     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+166     # . write(out, "cd/syscall  0x80/imm8\n")
+167     # . . push args
+168     68/push  "cd/syscall  0x80/imm8\n"/imm32
+169     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+170     # . . call
+171     e8/call  write/disp32
+172     # . . discard args
+173     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+174 $compile:end:
+175     # . restore registers
+176     59/pop-to-ecx
+177     58/pop-to-eax
+178     # . epilogue
+179     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+180     5d/pop-to-ebp
+181     c3/return
+182 
+183 # Read a sequence of digits into 'out'. Abort if there are none, or if there is
+184 # no space in 'out'.
+185 # Input comes from the global variable 'Look' (first byte) and the argument
+186 # 'in' (rest). We leave the next byte from 'in' into 'Look' on exit.
+187 get-num:  # in: (addr buffered-file), out: (addr stream byte), err: fd or (addr stream byte), ed: (addr exit-descriptor)
+188     # pseudocode:
+189     #   if (!digit?(Look)) expected(ed, err, "integer")
+190     #   do
+191     #     if out->write >= out->size
+192     #       write(err, "Error: too many digits in number\n")
+193     #       stop(ed, 1)
+194     #     out->data[out->write] = LSB(Look)
+195     #     ++out->write
+196     #     Look = get-char(in)
+197     #   while digit?(Look)
+198     # This is complicated because I don't want to hard-code the error strategy in
+199     # a general helper like write-byte-buffered. Maybe I should just create a
+200     # local helper.
+201     #
+202     # within the loop we'll try to keep things in registers:
+203     #   in: esi
+204     #   out: edi
+205     #   out->write: ecx (cached copy; need to keep in sync)
+206     #   out->size: edx
+207     #   temporaries: eax, ebx
+208     # We can't allocate Look to a register because it gets written implicitly in
+209     # get-char in each iteration of the loop. (Thereby demonstrating that it's
+210     # not the right interface for us. But we'll keep it just to follow Crenshaw.)
+211     #
+212     # . prologue
+213     55/push-ebp
+214     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+215     # - if (digit?(Look)) expected(ed, err, "integer")
+216     # . eax = digit?(Look)
+217     # . . push args
+218     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Look/disp32     .                 # push *Look
+219     # . . call
+220     e8/call  digit?/disp32
+221     # . . discard args
+222     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+223     # . if (eax == false)
+224     3d/compare-eax-and  0/imm32/false
+225     75/jump-if-!=  $get-num:main/disp8
+226     # . expected(ed, err, "integer")
+227     # . . push args
+228     68/push  "integer"/imm32
+229     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
+230     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
+231     # . . call
+232     e8/call  expected/disp32  # never returns
+233     # . . discard args
+234     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+235 $get-num:main:
+236     # - otherwise read a digit
+237     # . save registers
+238     50/push-eax
+239     51/push-ecx
+240     52/push-edx
+241     53/push-ebx
+242     56/push-esi
+243     57/push-edi
+244     # read necessary variables to registers
+245     # esi = in
+246     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
+247     # edi = out
+248     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   0xc/disp8       .                 # copy *(ebp+12) to edi
+249     # ecx = out->write
+250     8b/copy                         0/mod/indirect  7/rm32/edi    .           .             .           1/r32/ecx   .               .                 # copy *edi to ecx
+251     # edx = out->size
+252     8b/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           2/r32/edx   8/disp8         .                 # copy *(edi+8) to edx
+253 $get-num:loop:
+254     # if (out->write >= out->size) error
+255     39/compare                      3/mod/direct    2/rm32/edx    .           .             .           1/r32/ecx   .               .                 # compare edx with ecx
+256     7d/jump-if-<  $get-num:loop-stage2/disp8
+257     # . error(ed, err, msg)  # TODO: show full number
+258     # . . push args
+259     68/push  "get-num: too many digits in number"/imm32
+260     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
+261     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
+262     # . . call
+263     e8/call  error/disp32  # never returns
+264     # . . discard args
+265     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+266 $get-num:loop-stage2:
+267     # out->data[out->write] = LSB(Look)
+268     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    7/base/edi  1/index/ecx   .           3/r32/ebx   0xc/disp8       .                 # copy edi+ecx+12 to ebx
+269     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Look/disp32     .                 # copy *Look to eax
+270     88/copy-byte                    0/mod/indirect  3/rm32/ebx    .           .             .           0/r32/AL    .               .                 # copy byte at AL to *ebx
+271     # ++out->write
+272     41/increment-ecx
+273     # Look = get-char(in)
+274     # . . push args
+275     56/push-esi
+276     # . . call
+277     e8/call  get-char/disp32
+278     # . . discard args
+279     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+280     # if (digit?(Look)) loop
+281     # . eax = digit?(Look)
+282     # . . push args
+283     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Look/disp32     .                 # push *Look
+284     # . . call
+285     e8/call  digit?/disp32
+286     # . . discard args
+287     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+288     # . if (eax != false) loop
+289     3d/compare-eax-and  0/imm32/false
+290     0f 85/jump-if-!=  $get-num:loop/disp32
+291 $get-num:loop-end:
+292     # persist necessary variables from registers
+293     89/copy                         0/mod/indirect  7/rm32/edi    .           .             .           1/r32/ecx   .               .                 # copy ecx to *edi
+294 $get-num:end:
+295     # . restore registers
+296     5f/pop-to-edi
+297     5e/pop-to-esi
+298     5b/pop-to-ebx
+299     5a/pop-to-edx
+300     59/pop-to-ecx
+301     58/pop-to-eax
+302     # . epilogue
+303     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+304     5d/pop-to-ebp
+305     c3/return
+306 
+307 test-get-num-reads-single-digit:
+308     # - check that get-num returns first character if it's a digit
+309     # This test uses exit-descriptors. Use ebp for setting up local variables.
+310     55/push-ebp
+311     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+312     # clear all streams
+313     # . clear-stream(_test-stream)
+314     # . . push args
+315     68/push  _test-stream/imm32
+316     # . . call
+317     e8/call  clear-stream/disp32
+318     # . . discard args
+319     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+320     # . clear-stream($_test-buffered-file->buffer)
+321     # . . push args
+322     68/push  $_test-buffered-file->buffer/imm32
+323     # . . call
+324     e8/call  clear-stream/disp32
+325     # . . discard args
+326     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+327     # . clear-stream(_test-output-stream)
+328     # . . push args
+329     68/push  _test-output-stream/imm32
+330     # . . call
+331     e8/call  clear-stream/disp32
+332     # . . discard args
+333     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+334     # . clear-stream(_test-error-stream)
+335     # . . push args
+336     68/push  _test-error-stream/imm32
+337     # . . call
+338     e8/call  clear-stream/disp32
+339     # . . discard args
+340     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+341     # initialize 'in'
+342     # . write(_test-stream, "3")
+343     # . . push args
+344     68/push  "3"/imm32
+345     68/push  _test-stream/imm32
+346     # . . call
+347     e8/call  write/disp32
+348     # . . discard args
+349     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+350     # initialize exit-descriptor 'ed' for the call to 'get-num' below
+351     # . var ed/eax: exit-descriptor
+352     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # subtract from esp
+353     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           4/r32/esp   .               .                 # copy esp to eax
+354     # . tailor-exit-descriptor(ed, 16)
+355     # . . push args
+356     68/push  0x10/imm32/nbytes-of-args-for-get-num
+357     50/push-eax/ed
+358     # . . call
+359     e8/call  tailor-exit-descriptor/disp32
+360     # . . discard args
+361     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+362     # prime the pump
+363     # . get-char(_test-buffered-file)
+364     # . . push args
+365     68/push  _test-buffered-file/imm32
+366     # . . call
+367     e8/call  get-char/disp32
+368     # . . discard args
+369     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+370     # get-num(in, out, err, ed)
+371     # . . push args
+372     50/push-eax/ed
+373     68/push  _test-error-stream/imm32
+374     68/push  _test-output-stream/imm32
+375     68/push  _test-buffered-file/imm32
+376     # . . call
+377     e8/call  get-num/disp32
+378     # registers except esp may be clobbered at this point
+379     # . . discard args
+380     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+381     # check-ints-equal(*_test-output-stream->data, '3', msg)
+382     # . . push args
+383     68/push  "F - test-get-num-reads-single-digit"/imm32
+384     68/push  0x33/imm32
+385     b8/copy-to-eax  _test-output-stream/imm32
+386     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           0xc/disp8       .                 # push *(eax+12)
+387     # . . call
+388     e8/call  check-ints-equal/disp32
+389     # . . discard args
+390     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+391     # . reclaim locals
+392     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+393     5d/pop-to-ebp
+394     c3/return
+395 
+396 test-get-num-aborts-on-non-digit-in-Look:
+397     # - check that get-num returns first character if it's a digit
+398     # This test uses exit-descriptors. Use ebp for setting up local variables.
+399     55/push-ebp
+400     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+401     # clear all streams
+402     # . clear-stream(_test-stream)
+403     # . . push args
+404     68/push  _test-stream/imm32
+405     # . . call
+406     e8/call  clear-stream/disp32
+407     # . . discard args
+408     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+409     # . clear-stream($_test-buffered-file->buffer)
+410     # . . push args
+411     68/push  $_test-buffered-file->buffer/imm32
+412     # . . call
+413     e8/call  clear-stream/disp32
+414     # . . discard args
+415     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+416     # . clear-stream(_test-output-stream)
+417     # . . push args
+418     68/push  _test-output-stream/imm32
+419     # . . call
+420     e8/call  clear-stream/disp32
+421     # . . discard args
+422     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+423     # . clear-stream(_test-error-stream)
+424     # . . push args
+425     68/push  _test-error-stream/imm32
+426     # . . call
+427     e8/call  clear-stream/disp32
+428     # . . discard args
+429     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+430     # initialize 'in'
+431     # . write(_test-stream, "3")
+432     # . . push args
+433     68/push  "3"/imm32
+434     68/push  _test-stream/imm32
+435     # . . call
+436     e8/call  write/disp32
+437     # . . discard args
+438     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+439     # initialize exit-descriptor 'ed' for the call to 'get-num' below
+440     # . var ed/eax: exit-descriptor
+441     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # subtract from esp
+442     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           4/r32/esp   .               .                 # copy esp to eax
+443     # . tailor-exit-descriptor(ed, 16)
+444     # . . push args
+445     68/push  0x10/imm32/nbytes-of-args-for-get-num
+446     50/push-eax/ed
+447     # . . call
+448     e8/call  tailor-exit-descriptor/disp32
+449     # . . discard args
+450     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+451     # *don't* prime the pump
+452     # get-num(in, out, err, ed)
+453     # . . push args
+454     50/push-eax/ed
+455     68/push  _test-error-stream/imm32
+456     68/push  _test-output-stream/imm32
+457     68/push  _test-buffered-file/imm32
+458     # . . call
+459     e8/call  get-num/disp32
+460     # registers except esp may be clobbered at this point
+461     # . . discard args
+462     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+463     # check that get-num tried to call exit(1)
+464     # . check-ints-equal(ed->value, 2, msg)  # i.e. stop was called with value 1
+465     # . . push args
+466     68/push  "F - test-get-num-aborts-on-non-digit-in-Look"/imm32
+467     68/push  2/imm32
+468     # . . push ed->value
+469     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
+470     # . . call
+471     e8/call  check-ints-equal/disp32
+472     # . . discard args
+473     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+474     # . reclaim locals
+475     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+476     5d/pop-to-ebp
+477     c3/return
+478 
+479 test-get-num-reads-multiple-digits:
+480     # - check that get-num returns all initial digits until it encounters a non-digit
+481     # This test uses exit-descriptors. Use ebp for setting up local variables.
+482     55/push-ebp
+483     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+484     # clear all streams
+485     # . clear-stream(_test-stream)
+486     # . . push args
+487     68/push  _test-stream/imm32
+488     # . . call
+489     e8/call  clear-stream/disp32
+490     # . . discard args
+491     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+492     # . clear-stream($_test-buffered-file->buffer)
+493     # . . push args
+494     68/push  $_test-buffered-file->buffer/imm32
+495     # . . call
+496     e8/call  clear-stream/disp32
+497     # . . discard args
+498     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+499     # . clear-stream(_test-output-stream)
+500     # . . push args
+501     68/push  _test-output-stream/imm32
+502     # . . call
+503     e8/call  clear-stream/disp32
+504     # . . discard args
+505     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+506     # . clear-stream(_test-error-stream)
+507     # . . push args
+508     68/push  _test-error-stream/imm32
+509     # . . call
+510     e8/call  clear-stream/disp32
+511     # . . discard args
+512     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+513     # initialize 'in'
+514     # . write(_test-stream, "3456 x")
+515     # . . push args
+516     68/push  "3456"/imm32
+517     68/push  _test-stream/imm32
+518     # . . call
+519     e8/call  write/disp32
+520     # . . discard args
+521     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+522     # initialize exit-descriptor 'ed' for the call to 'get-num' below
+523     # . var ed/eax: exit-descriptor
+524     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # subtract from esp
+525     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           4/r32/esp   .               .                 # copy esp to eax
+526     # . tailor-exit-descriptor(ed, 16)
+527     # . . push args
+528     68/push  0x10/imm32/nbytes-of-args-for-get-num
+529     50/push-eax/ed
+530     # . . call
+531     e8/call  tailor-exit-descriptor/disp32
+532     # . . discard args
+533     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+534     # prime the pump
+535     # . get-char(_test-buffered-file)
+536     # . . push args
+537     68/push  _test-buffered-file/imm32
+538     # . . call
+539     e8/call  get-char/disp32
+540     # . . discard args
+541     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+542     # get-num(in, out, err, ed)
+543     # . . push args
+544     50/push-eax/ed
+545     68/push  _test-error-stream/imm32
+546     68/push  _test-output-stream/imm32
+547     68/push  _test-buffered-file/imm32
+548     # . . call
+549     e8/call  get-num/disp32
+550     # registers except esp may be clobbered at this point
+551     # . . discard args
+552     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+553     # check-ints-equal(*_test-output-stream->data, '3456', msg)
+554     # . . push args
+555     68/push  "F - test-get-num-reads-multiple-digits"/imm32
+556     68/push  0x36353433/imm32
+557     b8/copy-to-eax  _test-output-stream/imm32
+558     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           0xc/disp8       .                 # push *(eax+12)
+559     # . . call
+560     e8/call  check-ints-equal/disp32
+561     # . . discard args
+562     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+563     # . reclaim locals
+564     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+565     5d/pop-to-ebp
+566     c3/return
+567 
+568 test-get-num-reads-multiple-digits-followed-by-nondigit:
+569     # - check that get-num returns all initial digits until it encounters a non-digit
+570     # This test uses exit-descriptors. Use ebp for setting up local variables.
+571     55/push-ebp
+572     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+573     # clear all streams
+574     # . clear-stream(_test-stream)
+575     # . . push args
+576     68/push  _test-stream/imm32
+577     # . . call
+578     e8/call  clear-stream/disp32
+579     # . . discard args
+580     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+581     # . clear-stream($_test-buffered-file->buffer)
+582     # . . push args
+583     68/push  $_test-buffered-file->buffer/imm32
+584     # . . call
+585     e8/call  clear-stream/disp32
+586     # . . discard args
+587     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+588     # . clear-stream(_test-output-stream)
+589     # . . push args
+590     68/push  _test-output-stream/imm32
+591     # . . call
+592     e8/call  clear-stream/disp32
+593     # . . discard args
+594     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+595     # . clear-stream(_test-error-stream)
+596     # . . push args
+597     68/push  _test-error-stream/imm32
+598     # . . call
+599     e8/call  clear-stream/disp32
+600     # . . discard args
+601     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+602     # initialize 'in'
+603     # . write(_test-stream, "3456 x")
+604     # . . push args
+605     68/push  "3456 x"/imm32
+606     68/push  _test-stream/imm32
+607     # . . call
+608     e8/call  write/disp32
+609     # . . discard args
+610     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+611     # initialize exit-descriptor 'ed' for the call to 'get-num' below
+612     # . var ed/eax: exit-descriptor
+613     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # subtract from esp
+614     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           4/r32/esp   .               .                 # copy esp to eax
+615     # . tailor-exit-descriptor(ed, 16)
+616     # . . push args
+617     68/push  0x10/imm32/nbytes-of-args-for-get-num
+618     50/push-eax/ed
+619     # . . call
+620     e8/call  tailor-exit-descriptor/disp32
+621     # . . discard args
+622     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+623     # prime the pump
+624     # . get-char(_test-buffered-file)
+625     # . . push args
+626     68/push  _test-buffered-file/imm32
+627     # . . call
+628     e8/call  get-char/disp32
+629     # . . discard args
+630     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+631     # get-num(in, out, err, ed)
+632     # . . push args
+633     50/push-eax/ed
+634     68/push  _test-error-stream/imm32
+635     68/push  _test-output-stream/imm32
+636     68/push  _test-buffered-file/imm32
+637     # . . call
+638     e8/call  get-num/disp32
+639     # registers except esp may be clobbered at this point
+640     # . . discard args
+641     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+642     # check-ints-equal(*_test-output-stream->data, '3456', msg)
+643     # . . push args
+644     68/push  "F - test-get-num-reads-multiple-digits-followed-by-nondigit"/imm32
+645     68/push  0x36353433/imm32
+646     b8/copy-to-eax  _test-output-stream/imm32
+647     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           0xc/disp8       .                 # push *(eax+12)
+648     # . . call
+649     e8/call  check-ints-equal/disp32
+650     # . . discard args
+651     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+652     # . reclaim locals
+653     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+654     5d/pop-to-ebp
+655     c3/return
+656 
+657 ## helpers
+658 
+659 # write(f, "Error: "+s+" expected\n") then stop(ed, 1)
+660 expected:  # ed: (addr exit-descriptor), f: fd or (addr stream byte), s: (addr array byte)
+661     # . prologue
+662     55/push-ebp
+663     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+664     # write(f, "Error: ")
+665     # . . push args
+666     68/push  "Error: "/imm32
+667     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+668     # . . call
+669     e8/call  write/disp32
+670     # . . discard args
+671     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+672     # write(f, s)
+673     # . . push args
+674     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
+675     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+676     # . . call
+677     e8/call  write/disp32
+678     # . . discard args
+679     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+680     # write(f, " expected\n")
+681     # . . push args
+682     68/push  " expected\n"/imm32
+683     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+684     # . . call
+685     e8/call  write/disp32
+686     # . . discard args
+687     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+688     # stop(ed, 1)
+689     # . . push args
+690     68/push  1/imm32
+691     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+692     # . . call
+693     e8/call  stop/disp32
+694     # should never get past this point
+695 $expected:dead-end:
+696     # . epilogue
+697     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+698     5d/pop-to-ebp
+699     c3/return
+700 
+701 # read a byte from 'f', and save it in 'Look'
+702 get-char:  # f: (addr buffered-file)
+703     # . prologue
+704     55/push-ebp
+705     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+706     # . save registers
+707     50/push-eax
+708     # eax = read-byte-buffered(f)
+709     # . . push args
+710     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+711     # . . call
+712     e8/call  read-byte-buffered/disp32
+713     # . . discard args
+714     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+715     # save eax to Look
+716     89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Look/disp32     .                 # copy eax to *Look
+717 $get-char:end:
+718     # . restore registers
+719     58/pop-to-eax
+720     # . epilogue
+721     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+722     5d/pop-to-ebp
+723     c3/return
+724 
+725 digit?:  # c: int -> eax: boolean
+726     # . prologue
+727     55/push-ebp
+728     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+729     # eax = false
+730     b8/copy-to-eax  0/imm32
+731     # if (c < '0') return false
+732     81          7/subop/compare     1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         0x30/imm32        # compare *(ebp+8)
+733     7c/jump-if-<  $digit?:end/disp8
+734     # if (c > '9') return false
+735     81          7/subop/compare     1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         0x39/imm32        # compare *(ebp+8)
+736     7f/jump-if->  $digit?:end/disp8
+737     # otherwise return true
+738     b8/copy-to-eax  1/imm32
+739 $digit?:end:
+740     # . epilogue
+741     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+742     5d/pop-to-ebp
+743     c3/return
+744 
+745 == data
+746 
+747 Look:  # (char with some extra padding)
+748     0/imm32
+749 
+750 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/ex1.mu.html b/html/linux/apps/ex1.mu.html new file mode 100644 index 00000000..bf1644a4 --- /dev/null +++ b/html/linux/apps/ex1.mu.html @@ -0,0 +1,77 @@ + + + + +Mu - linux/apps/ex1.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex1.mu +
+ 1 # First example: return the answer to the Ultimate Question of Life, the
+ 2 # Universe, and Everything.
+ 3 #
+ 4 # Same as https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html
+ 5 #
+ 6 # To run:
+ 7 #   $ ./translate apps/ex1.mu
+ 8 #   $ ./a.elf
+ 9 # Expected result:
+10 #   $ echo $?
+11 #   42
+12 
+13 fn main -> _/ebx: int {
+14   return 0x2a  # Mu requires hexadecimal
+15 }
+
+ + + diff --git a/html/linux/apps/ex1.subx.html b/html/linux/apps/ex1.subx.html new file mode 100644 index 00000000..678f74c9 --- /dev/null +++ b/html/linux/apps/ex1.subx.html @@ -0,0 +1,79 @@ + + + + +Mu - linux/apps/ex1.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex1.subx +
+ 1 # First example: return the answer to the Ultimate Question of Life, the
+ 2 # Universe, and Everything.
+ 3 #
+ 4 # Same as https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html
+ 5 #
+ 6 # To run:
+ 7 #   $ bootstrap/bootstrap translate apps/ex1.subx -o ex1
+ 8 #   $ bootstrap/bootstrap run ex1
+ 9 # Expected result:
+10 #   $ echo $?
+11 #   42
+12 
+13 == code
+14 
+15 Entry:
+16 # exit(42)
+17 bb/copy-to-ebx  0x2a/imm32  # 42 in hex
+18 e8/call  syscall_exit/disp32
+19 
+20 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/ex10.subx.html b/html/linux/apps/ex10.subx.html new file mode 100644 index 00000000..c359244c --- /dev/null +++ b/html/linux/apps/ex10.subx.html @@ -0,0 +1,132 @@ + + + + +Mu - linux/apps/ex10.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex10.subx +
+ 1 # String comparison: return 1 iff the two args passed in at the commandline are equal.
+ 2 #
+ 3 # To run:
+ 4 #   $ bootstrap/bootstrap translate apps/ex10.subx -o ex10
+ 5 #   $ bootstrap/bootstrap run ex10 abc abd
+ 6 # Expected result:
+ 7 #   $ echo $?
+ 8 #   0  # false
+ 9 
+10 == code
+11 #   instruction                     effective address                                                   register    displacement    immediate
+12 # . op          subop               mod             rm32          base        index         scale       r32
+13 # . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
+14 
+15 Entry:  # return argv-equal(argv[1], argv[2])
+16 #       At the start of a SubX program:
+17 #         argc: *esp
+18 #         argv[0]: *(esp+4)
+19 #         argv[1]: *(esp+8)
+20 #         ...
+21     # . prologue
+22     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+23     # argv-equal(argv[1], argv[2])
+24     # . . push argv[2]
+25     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+26     # . . push argv[1]
+27     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+28     # . . call
+29     e8/call argv-equal/disp32
+30     # exit(eax)
+31     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to ebx
+32     e8/call  syscall_exit/disp32
+33 
+34 # compare two null-terminated ascii strings
+35 # reason for the name: the only place we should have null-terminated ascii strings is from commandline args
+36 argv-equal:  # (s1, s2): null-terminated ascii strings -> eax: boolean
+37     # initialize s1 (ecx) and s2 (edx)
+38     8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/esp  4/index/none  .           1/r32/ecx   4/disp8         .                 # copy *(esp+4) to ecx
+39     8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/esp  4/index/none  .           2/r32/edx   8/disp8         .                 # copy *(esp+8) to edx
+40 $argv-equal:loop:
+41     # c1/eax, c2/ebx = *s1, *s2
+42     b8/copy-to-eax  0/imm32
+43     8a/copy-byte                    0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/AL    .               .                 # copy byte at *ecx to AL
+44     bb/copy-to-ebx  0/imm32
+45     8a/copy-byte                    0/mod/indirect  2/rm32/edx    .           .             .           3/r32/BL    .               .                 # copy byte at *edx to BL
+46     # if (c1 == 0) break
+47     3d/compare-eax-and  0/imm32/null
+48     74/jump-if-=  $argv-equal:break/disp8
+49     # if (c1 != c2) return false
+50     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # compare eax and ebx
+51     75/jump-if-!=  $argv-equal:false/disp8
+52     # ++s1, ++s2
+53     41/increment-ecx
+54     42/increment-edx
+55     # end while
+56     eb/jump  $argv-equal:loop/disp8
+57 $argv-equal:break:
+58     # if (c2 == 0) return true
+59     81          7/subop/compare     3/mod/direct    3/rm32/ebx    .           .             .           .           .               0/imm32/null      # compare ebx
+60     75/jump-if-!=  $argv-equal:false/disp8
+61 $argv-equal:success:
+62     b8/copy-to-eax  1/imm32
+63     c3/return
+64     # return false
+65 $argv-equal:false:
+66     b8/copy-to-eax  0/imm32
+67     c3/return
+68 
+69 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/ex11.subx.html b/html/linux/apps/ex11.subx.html new file mode 100644 index 00000000..f101f852 --- /dev/null +++ b/html/linux/apps/ex11.subx.html @@ -0,0 +1,421 @@ + + + + +Mu - linux/apps/ex11.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex11.subx +
+  1 # Null-terminated vs size-prefixed ascii strings.
+  2 #
+  3 # By default we create strings with a 4-byte size prefix rather than a null suffix.
+  4 # However we still need null-prefixed strings when interacting with the Linux
+  5 # kernel in a few places. This layer implements a function for comparing
+  6 # a null-terminated 'kernel string' with a size-prefixed 'SubX string'.
+  7 #
+  8 # To run:
+  9 #   $ bootstrap/bootstrap translate apps/ex11.subx -o ex11
+ 10 #   $ bootstrap/bootstrap run ex11  # runs a series of tests
+ 11 #   ......  # all tests pass
+ 12 #
+ 13 # (We can't yet run the tests when given a "test" commandline argument,
+ 14 # because checking for it would require the function being tested! Breakage
+ 15 # would cause tests to not run, rather than to fail as we'd like.)
+ 16 
+ 17 == code
+ 18 #   instruction                     effective address                                                   register    displacement    immediate
+ 19 # . op          subop               mod             rm32          base        index         scale       r32
+ 20 # . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
+ 21 
+ 22 Entry:  # run all tests
+ 23     e8/call  run-tests/disp32  # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'.
+ 24     # exit(eax)
+ 25     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to ebx
+ 26     e8/call  syscall_exit/disp32
+ 27 
+ 28 # compare a null-terminated ascii string with a more idiomatic size-prefixed byte array
+ 29 # reason for the name: the only place we should have null-terminated ascii strings is from commandline args
+ 30 kernel-string-equal?:  # s: null-terminated ascii string, benchmark: size-prefixed ascii string -> eax: boolean
+ 31     # pseudocode:
+ 32     #   n = benchmark->size
+ 33     #   s1 = s
+ 34     #   s2 = benchmark->data
+ 35     #   i = 0
+ 36     #   while i < n
+ 37     #     c1 = *s1
+ 38     #     c2 = *s2
+ 39     #     if (c1 == 0) return false
+ 40     #     if (c1 != c2) return false
+ 41     #     ++s1, ++s2, ++i
+ 42     #   return *s1 == 0
+ 43     #
+ 44     # registers:
+ 45     #   i: ecx
+ 46     #   n: edx
+ 47     #   s1: edi
+ 48     #   s2: esi
+ 49     #   c1: eax
+ 50     #   c2: ebx
+ 51     #
+ 52     # . prologue
+ 53     55/push-ebp
+ 54     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 55     # . save registers
+ 56     51/push-ecx
+ 57     52/push-edx
+ 58     53/push-ebx
+ 59     56/push-esi
+ 60     57/push-edi
+ 61     # s1/edi = s
+ 62     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   8/disp8         .                 # copy *(ebp+8) to edi
+ 63     # n/edx = benchmark->size
+ 64     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   0xc/disp8       .                 # copy *(ebp+12) to edx
+ 65     8b/copy                         0/mod/indirect  2/rm32/edx    .           .             .           2/r32/edx   .               .                 # copy *edx to edx
+ 66     # s2/esi = benchmark->data
+ 67     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   0xc/disp8       .                 # copy *(ebp+12) to esi
+ 68     81          0/subop/add         3/mod/direct    6/rm32/esi    .           .             .           .           .               4/imm32           # add to esi
+ 69     # i/ecx = c1/eax = c2/ebx = 0
+ 70     b9/copy-to-ecx  0/imm32/exit
+ 71     b8/copy-to-eax  0/imm32
+ 72     bb/copy-to-ebx  0/imm32
+ 73 $kernel-string-equal?:loop:
+ 74     # if (i >= n) break
+ 75     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
+ 76     7d/jump-if->=  $kernel-string-equal?:break/disp8
+ 77     # c1 = *s1
+ 78     8a/copy-byte                    0/mod/indirect  7/rm32/edi    .           .             .           0/r32/AL    .               .                 # copy byte at *edi to AL
+ 79     # c2 = *s2
+ 80     8a/copy-byte                    0/mod/indirect  6/rm32/esi    .           .             .           3/r32/BL    .               .                 # copy byte at *esi to BL
+ 81     # if (c1 == 0) return false
+ 82     3d/compare-eax-and  0/imm32/null
+ 83     74/jump-if-=  $kernel-string-equal?:false/disp8
+ 84     # if (c1 != c2) return false
+ 85     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # compare eax and ebx
+ 86     75/jump-if-!=  $kernel-string-equal?:false/disp8
+ 87     # ++i
+ 88     41/increment-ecx
+ 89     # ++s1
+ 90     47/increment-edi
+ 91     # ++s2
+ 92     46/increment-esi
+ 93     eb/jump  $kernel-string-equal?:loop/disp8
+ 94 $kernel-string-equal?:break:
+ 95     # return *s1 == 0
+ 96     8a/copy-byte                    0/mod/indirect  7/rm32/edi    .           .             .           0/r32/AL    .               .                 # copy byte at *edi to AL
+ 97     3d/compare-eax-and  0/imm32/null
+ 98     75/jump-if-!=  $kernel-string-equal?:false/disp8
+ 99 $kernel-string-equal?:true:
+100     b8/copy-to-eax  1/imm32
+101     eb/jump  $kernel-string-equal?:end/disp8
+102 $kernel-string-equal?:false:
+103     b8/copy-to-eax  0/imm32
+104 $kernel-string-equal?:end:
+105     # . restore registers
+106     5f/pop-to-edi
+107     5e/pop-to-esi
+108     5b/pop-to-ebx
+109     5a/pop-to-edx
+110     59/pop-to-ecx
+111     # . epilogue
+112     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+113     5d/pop-to-ebp
+114     c3/return
+115 
+116 # - tests
+117 
+118 test-compare-null-kernel-string-with-empty-array:
+119     # eax = kernel-string-equal?(Null-kernel-string, "")
+120     # . . push args
+121     68/push  ""/imm32
+122     68/push  Null-kernel-string/imm32
+123     # . . call
+124     e8/call  kernel-string-equal?/disp32
+125     # . . discard args
+126     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+127     # check-ints-equal(eax, 1, msg)
+128     # . . push args
+129     68/push  "F - test-compare-null-kernel-string-with-empty-array"/imm32
+130     68/push  1/imm32/true
+131     50/push-eax
+132     # . . call
+133     e8/call  check-ints-equal/disp32
+134     # . . discard args
+135     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+136     c3/return
+137 
+138 test-compare-null-kernel-string-with-non-empty-array:
+139     # eax = kernel-string-equal?(Null-kernel-string, "Abc")
+140     # . . push args
+141     68/push  "Abc"/imm32
+142     68/push  Null-kernel-string/imm32
+143     # . . call
+144     e8/call  kernel-string-equal?/disp32
+145     # . . discard args
+146     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+147     # check-ints-equal(eax, 0, msg)
+148     # . . push args
+149     68/push  "F - test-compare-null-kernel-string-with-non-empty-array"/imm32
+150     68/push  0/imm32/false
+151     50/push-eax
+152     # . . call
+153     e8/call  check-ints-equal/disp32
+154     # . . discard args
+155     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+156     c3/return
+157 
+158 test-compare-kernel-string-with-equal-array:
+159     # eax = kernel-string-equal?(_test-Abc-kernel-string, "Abc")
+160     # . . push args
+161     68/push  "Abc"/imm32
+162     68/push  _test-Abc-kernel-string/imm32
+163     # . . call
+164     e8/call  kernel-string-equal?/disp32
+165     # . . discard args
+166     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+167     # check-ints-equal(eax, 1, msg)
+168     # . . push args
+169     68/push  "F - test-compare-kernel-string-with-equal-array"/imm32
+170     68/push  1/imm32/true
+171     50/push-eax
+172     # . . call
+173     e8/call  check-ints-equal/disp32
+174     # . . discard args
+175     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+176     c3/return
+177 
+178 test-compare-kernel-string-with-inequal-array:
+179     # eax = kernel-string-equal?(_test-Abc-kernel-string, "Adc")
+180     # . . push args
+181     68/push  "Adc"/imm32
+182     68/push  _test-Abc-kernel-string/imm32
+183     # . . call
+184     e8/call  kernel-string-equal?/disp32
+185     # . . discard args
+186     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+187     # check-ints-equal(eax, 0, msg)
+188     # . . push args
+189     68/push  "F - test-compare-kernel-string-with-equal-array"/imm32
+190     68/push  0/imm32/false
+191     50/push-eax
+192     # . . call
+193     e8/call  check-ints-equal/disp32
+194     # . . discard args
+195     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+196     c3/return
+197 
+198 test-compare-kernel-string-with-empty-array:
+199     # eax = kernel-string-equal?(_test-Abc-kernel-string, "")
+200     # . . push args
+201     68/push  ""/imm32
+202     68/push  _test-Abc-kernel-string/imm32
+203     # . . call
+204     e8/call  kernel-string-equal?/disp32
+205     # . . discard args
+206     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+207     # check-ints-equal(eax, 0, msg)
+208     # . . push args
+209     68/push  "F - test-compare-kernel-string-with-equal-array"/imm32
+210     68/push  0/imm32/false
+211     50/push-eax
+212     # . . call
+213     e8/call  check-ints-equal/disp32
+214     # . . discard args
+215     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+216     c3/return
+217 
+218 test-compare-kernel-string-with-shorter-array:
+219     # eax = kernel-string-equal?(_test-Abc-kernel-string, "Ab")
+220     # . . push args
+221     68/push  "Ab"/imm32
+222     68/push  _test-Abc-kernel-string/imm32
+223     # . . call
+224     e8/call  kernel-string-equal?/disp32
+225     # . . discard args
+226     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+227     # check-ints-equal(eax, 0, msg)
+228     # . . push args
+229     68/push  "F - test-compare-kernel-string-with-shorter-array"/imm32
+230     68/push  0/imm32/false
+231     50/push-eax
+232     # . . call
+233     e8/call  check-ints-equal/disp32
+234     # . . discard args
+235     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+236     c3/return
+237 
+238 test-compare-kernel-string-with-longer-array:
+239     # eax = kernel-string-equal?(_test-Abc-kernel-string, "Abcd")
+240     # . . push args
+241     68/push  "Abcd"/imm32
+242     68/push  _test-Abc-kernel-string/imm32
+243     # . . call
+244     e8/call  kernel-string-equal?/disp32
+245     # . . discard args
+246     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+247     # check-ints-equal(eax, 0, msg)
+248     # . . push args
+249     68/push  "F - test-compare-kernel-string-with-longer-array"/imm32
+250     68/push  0/imm32/false
+251     50/push-eax
+252     # . . call
+253     e8/call  check-ints-equal/disp32
+254     # . . discard args
+255     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+256     c3/return
+257 
+258 # - helpers
+259 
+260 # print msg to stderr if a != b, otherwise print "."
+261 check-ints-equal:  # (a: int, b: int, msg: (addr array byte)) -> boolean
+262     # . prologue
+263     55/push-ebp
+264     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+265     # . save registers
+266     51/push-ecx
+267     53/push-ebx
+268     # load args into eax, ebx and ecx
+269     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   8/disp8         .                 # copy *(ebp+8) to eax
+270     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           3/r32/ebx   0xc/disp8       .                 # copy *(ebp+12) to ebx
+271     # if (eax == b/ebx) print('.') and return
+272     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # compare eax and ebx
+273     75/jump-if-unequal  $check-ints-equal:else/disp8
+274     # . write-stderr('.')
+275     # . . push args
+276     68/push  "."/imm32
+277     # . . call
+278     e8/call  write-stderr/disp32
+279     # . . discard args
+280     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+281     # . return
+282     eb/jump  $check-ints-equal:end/disp8
+283     # otherwise print(msg)
+284 $check-ints-equal:else:
+285     # copy msg into ecx
+286     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x10/disp8       .                # copy *(ebp+16) to ecx
+287     # print(ecx)
+288     # . . push args
+289     51/push-ecx
+290     # . . call
+291     e8/call  write-stderr/disp32
+292     # . . discard args
+293     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+294     # print newline
+295     # . . push args
+296     68/push  Newline/imm32
+297     # . . call
+298     e8/call  write-stderr/disp32
+299     # . . discard args
+300     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+301 $check-ints-equal:end:
+302     # . restore registers
+303     5b/pop-to-ebx
+304     59/pop-to-ecx
+305     # end
+306     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+307     5d/pop-to-ebp
+308     c3/return
+309 
+310 write-stderr:  # s: (addr array byte) -> <void>
+311     # . prologue
+312     55/push-ebp
+313     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+314     # . save registers
+315     50/push-eax
+316     51/push-ecx
+317     52/push-edx
+318     53/push-ebx
+319     # syscall(write, 2/stderr, (data) s+4, (size) *s)
+320     # . . fd = 2 (stderr)
+321     bb/copy-to-ebx  2/imm32
+322     # . . x = s+4
+323     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
+324     81          0/subop/add         3/mod/direct    1/rm32/ecx    .           .             .           .           .               4/imm32           # add to ecx
+325     # . . size = *s
+326     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   8/disp8         .                 # copy *(ebp+8) to edx
+327     8b/copy                         0/mod/indirect  2/rm32/edx    .           .             .           2/r32/edx   .               .                 # copy *edx to edx
+328     # . . syscall
+329     e8/call  syscall_write/disp32
+330     # . restore registers
+331     5b/pop-to-ebx
+332     5a/pop-to-edx
+333     59/pop-to-ecx
+334     58/pop-to-eax
+335     # . end
+336     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+337     5d/pop-to-ebp
+338     c3/return
+339 
+340 == data
+341 
+342 Newline:
+343     # size
+344     1/imm32
+345     # data
+346     0a/newline
+347 
+348 # for kernel-string-equal tests
+349 Null-kernel-string:
+350     00/null
+351 
+352 _test-Abc-kernel-string:
+353     41/A 62/b 63/c 00/null
+354 
+355 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/ex12.subx.html b/html/linux/apps/ex12.subx.html new file mode 100644 index 00000000..12b09331 --- /dev/null +++ b/html/linux/apps/ex12.subx.html @@ -0,0 +1,104 @@ + + + + +Mu - linux/apps/ex12.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex12.subx +
+ 1 # Example showing mmap syscall.
+ 2 # Create a new segment using mmap, save the address, write to it.
+ 3 #
+ 4 # To run:
+ 5 #   $ bootstrap/bootstrap translate apps/ex12.subx -o ex12
+ 6 #   $ bootstrap/bootstrap run ex12
+ 7 # You shouldn't get a segmentation fault.
+ 8 
+ 9 == code
+10 #   instruction                     effective address                                                   register    displacement    immediate
+11 # . op          subop               mod             rm32          base        index         scale       r32
+12 # . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
+13 
+14 Entry:
+15     # mmap(Mmap-new-segment->len)
+16     bb/copy-to-ebx  Mmap-new-segment/imm32
+17     e8/call  syscall_mmap/disp32
+18 
+19     # write to *eax to check that we have access to the newly-allocated segment
+20     c7          0/subop/copy        0/mod/direct    0/rm32/eax    .           .             .           .           .               0x34/imm32        # copy to *eax
+21 
+22     # exit(eax)
+23     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to ebx
+24     e8/call  syscall_exit/disp32
+25 
+26 == data
+27 
+28 # various constants used here were found in the Linux sources (search for file mman-common.h)
+29 Mmap-new-segment:  # type mmap_arg_struct
+30     # addr
+31     0/imm32
+32     # len
+33     0x100/imm32
+34     # protection flags
+35     3/imm32  # PROT_READ | PROT_WRITE
+36     # sharing flags
+37     0x22/imm32  # MAP_PRIVATE | MAP_ANONYMOUS
+38     # fd
+39     -1/imm32  # since MAP_ANONYMOUS is specified
+40     # offset
+41     0/imm32  # since MAP_ANONYMOUS is specified
+42 
+43 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/ex13.subx.html b/html/linux/apps/ex13.subx.html new file mode 100644 index 00000000..c0181b6c --- /dev/null +++ b/html/linux/apps/ex13.subx.html @@ -0,0 +1,87 @@ + + + + +Mu - linux/apps/ex13.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex13.subx +
+ 1 # Compare 3 and 3.
+ 2 #
+ 3 # To run:
+ 4 #   $ bootstrap/bootstrap translate apps/ex13.subx -o ex13
+ 5 #   $ bootstrap/bootstrap run ex13
+ 6 # Expected result:
+ 7 #   $ echo $?
+ 8 #   1
+ 9 
+10 == code
+11 #   instruction                     effective address                                                   register    displacement    immediate
+12 # . op          subop               mod             rm32          base        index         scale       r32
+13 # . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
+14 
+15 Entry:
+16     b8/copy-to-eax  3/imm32
+17     3d/compare-eax-and  3/imm32
+18     0f 94/set-if-=                  3/mod/direct    3/rm32/ebx    .           .             .           .           .               .                 # set ebx to ZF
+19     81 4/subop/and                  3/mod/direct    3/rm32/ebx    .           .             .           .           .               0xff/imm32        # AND with eax
+20 
+21 $exit:
+22     # exit(ebx)
+23     e8/call  syscall_exit/disp32
+24 
+25 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/ex14.subx.html b/html/linux/apps/ex14.subx.html new file mode 100644 index 00000000..fd76cdc3 --- /dev/null +++ b/html/linux/apps/ex14.subx.html @@ -0,0 +1,88 @@ + + + + +Mu - linux/apps/ex14.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex14.subx +
+ 1 # Multiply 2 numbers.
+ 2 #
+ 3 # To run:
+ 4 #   $ bootstrap/bootstrap translate apps/ex14.subx -o ex14
+ 5 #   $ bootstrap/bootstrap run ex14
+ 6 # Expected result:
+ 7 #   $ echo $?
+ 8 #   6
+ 9 
+10 == code
+11 #   instruction                     effective address                                                   register    displacement    immediate
+12 # . op          subop               mod             rm32          base        index         scale       r32
+13 # . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
+14 
+15 Entry:
+16     b8/copy-to-eax  1/imm32
+17     b9/copy-to-ecx  2/imm32
+18     bb/copy-to-ebx  3/imm32
+19 
+20     69/multiply                     3/mod/direct    1/rm32/ecx    .           .             .           3/r32/ebx                   3/imm32           # ebx = ecx * 3
+21 
+22 $exit:
+23     # exit(ebx)
+24     e8/call  syscall_exit/disp32
+25 
+26 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/ex2.mu.html b/html/linux/apps/ex2.mu.html new file mode 100644 index 00000000..48ee0e00 --- /dev/null +++ b/html/linux/apps/ex2.mu.html @@ -0,0 +1,83 @@ + + + + +Mu - linux/apps/ex2.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex2.mu +
+ 1 # Add 3 and 4, and return the result in the exit code.
+ 2 #
+ 3 # To run:
+ 4 #   $ ./translate apps/ex2.mu
+ 5 #   $ ./a.elf
+ 6 # Expected result:
+ 7 #   $ echo $?
+ 8 #   7
+ 9 
+10 fn main -> _/ebx: int {
+11   var result/eax: int <- do-add 3 4
+12   return result
+13 }
+14 
+15 fn do-add a: int, b: int -> _/eax: int {
+16   var result/ecx: int <- copy a
+17   result <- add b
+18   return result
+19 }
+
+ + + diff --git a/html/linux/apps/ex2.subx.html b/html/linux/apps/ex2.subx.html new file mode 100644 index 00000000..519b4b73 --- /dev/null +++ b/html/linux/apps/ex2.subx.html @@ -0,0 +1,79 @@ + + + + +Mu - linux/apps/ex2.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex2.subx +
+ 1 # Add 3 and 4, and return the result in the exit code.
+ 2 #
+ 3 # To run:
+ 4 #   $ bootstrap/bootstrap translate apps/ex2.subx -o ex2
+ 5 #   $ bootstrap/bootstrap run ex2
+ 6 # Expected result:
+ 7 #   $ echo $?
+ 8 #   2
+ 9 
+10 == code
+11 
+12 Entry:
+13 # ebx = 3
+14 bb/copy-to-ebx  3/imm32
+15 # add 4 to ebx
+16 81 0/subop/add 3/mod/direct 3/rm32/ebx 4/imm32
+17 # exit(ebx)
+18 e8/call  syscall_exit/disp32
+19 
+20 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/ex3.2.mu.html b/html/linux/apps/ex3.2.mu.html new file mode 100644 index 00000000..98c6a027 --- /dev/null +++ b/html/linux/apps/ex3.2.mu.html @@ -0,0 +1,98 @@ + + + + +Mu - linux/apps/ex3.2.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex3.2.mu +
+ 1 # Unnecessarily use an array to sum 1..10
+ 2 #
+ 3 # To run:
+ 4 #   $ ./translate apps/ex3.2.mu
+ 5 #   $ ./a.elf
+ 6 #   $ echo $?
+ 7 #   55
+ 8 
+ 9 fn main -> _/ebx: int {
+10   # populate a
+11   var a: (array int 0xb)  # 11; we waste index 0
+12   var i/ecx: int <- copy 1
+13   {
+14     compare i, 0xb
+15     break-if->=
+16     var x/eax: (addr int) <- index a, i
+17     copy-to *x, i
+18     i <- increment
+19     loop
+20   }
+21   # sum
+22   var result/edx: int <- copy 0
+23   i <- copy 1
+24   {
+25     compare i, 0xb
+26     break-if->=
+27     var x/eax: (addr int) <- index a, i
+28     result <- add *x
+29     i <- increment
+30     loop
+31   }
+32   return result
+33 }
+
+ + + diff --git a/html/linux/apps/ex3.mu.html b/html/linux/apps/ex3.mu.html new file mode 100644 index 00000000..9da58562 --- /dev/null +++ b/html/linux/apps/ex3.mu.html @@ -0,0 +1,84 @@ + + + + +Mu - linux/apps/ex3.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex3.mu +
+ 1 # Add the first 10 numbers, and return the result in the exit code.
+ 2 #
+ 3 # To run:
+ 4 #   $ ./translate ex3.mu
+ 5 #   $ ./a.elf
+ 6 # Expected result:
+ 7 #   $ echo $?
+ 8 #   55
+ 9 
+10 fn main -> _/ebx: int {
+11   var result/ebx: int <- copy 0
+12   var i/eax: int <- copy 1
+13   {
+14     compare i, 0xa
+15     break-if->
+16     result <- add i
+17     i <- increment
+18     loop
+19   }
+20   return result
+21 }
+
+ + + diff --git a/html/linux/apps/ex3.subx.html b/html/linux/apps/ex3.subx.html new file mode 100644 index 00000000..0810bdc8 --- /dev/null +++ b/html/linux/apps/ex3.subx.html @@ -0,0 +1,98 @@ + + + + +Mu - linux/apps/ex3.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex3.subx +
+ 1 # Add the first 10 numbers, and return the result in the exit code.
+ 2 #
+ 3 # To run:
+ 4 #   $ bootstrap/bootstrap translate apps/ex3.subx -o ex3
+ 5 #   $ bootstrap/bootstrap run ex3
+ 6 # Expected result:
+ 7 #   $ echo $?
+ 8 #   55
+ 9 
+10 == code
+11 #   instruction                     effective address                                                   register    displacement    immediate
+12 # . op          subop               mod             rm32          base        index         scale       r32
+13 # . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
+14 
+15 Entry:
+16     # result: ebx = 0
+17     bb/copy-to-ebx  0/imm32
+18     # counter: ecx = 1
+19     b9/copy-to-ecx  1/imm32
+20 
+21 $loop:
+22     # if (counter > 10) break
+23     81          7/subop/compare     3/mod/direct    1/rm32/ecx    .           .             .           .           .               0xa/imm32         # compare ecx
+24     7f/jump-if->  $exit/disp8
+25     # result += counter
+26     01/add                          3/mod/direct    3/rm32/ebx    .           .             .           1/r32/ecx   .               .                 # add ecx to ebx
+27     # ++counter
+28     41/increment-ecx
+29     # loop
+30     eb/jump  $loop/disp8
+31 
+32 $exit:
+33     # exit(ebx)
+34     e8/call  syscall_exit/disp32
+35 
+36 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/ex4.subx.html b/html/linux/apps/ex4.subx.html new file mode 100644 index 00000000..1b3bd941 --- /dev/null +++ b/html/linux/apps/ex4.subx.html @@ -0,0 +1,99 @@ + + + + +Mu - linux/apps/ex4.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex4.subx +
+ 1 # Read a character from stdin, save it to a global, write it to stdout.
+ 2 #
+ 3 # To run:
+ 4 #   $ bootstrap/bootstrap translate apps/ex4.subx -o ex4
+ 5 #   $ bootstrap/bootstrap run ex4
+ 6 
+ 7 == data
+ 8 
+ 9 # the global variable we save to
+10 X:
+11     0/imm32  # space for read() to write to
+12 
+13 == code
+14 
+15 Entry:
+16 # read(stdin, X, 1)
+17 # . fd = 0 (stdin)
+18 bb/copy-to-ebx  0/imm32
+19 # . data = X (location to write result to)
+20 b9/copy-to-ecx  X/imm32
+21 # . size = 1 character
+22 ba/copy-to-edx  1/imm32
+23 # . syscall
+24 e8/call  syscall_read/disp32
+25 
+26 # write(stdout, X, 1)
+27 # . fd = 1 (stdout)
+28 bb/copy-to-ebx  1/imm32
+29 # . initialize X (location to read from)
+30 b9/copy-to-ecx  X/imm32
+31 # . size = 1 character
+32 ba/copy-to-edx  1/imm32
+33 # . syscall
+34 e8/call  syscall_write/disp32
+35 
+36 # exit(ebx)
+37 e8/call  syscall_exit/disp32
+38 
+39 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/ex5.subx.html b/html/linux/apps/ex5.subx.html new file mode 100644 index 00000000..949e207c --- /dev/null +++ b/html/linux/apps/ex5.subx.html @@ -0,0 +1,101 @@ + + + + +Mu - linux/apps/ex5.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex5.subx +
+ 1 # Read a character from stdin, save it to a local on the stack, write it to stdout.
+ 2 #
+ 3 # To run:
+ 4 #   $ bootstrap/bootstrap translate apps/ex5.subx -o ex5
+ 5 #   $ bootstrap/bootstrap run ex5
+ 6 
+ 7 == code
+ 8 #   instruction                     effective address                                                   register    displacement    immediate
+ 9 # . op          subop               mod             rm32          base        index         scale       r32
+10 # . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
+11 
+12 Entry:
+13 
+14     # allocate x on the stack
+15     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # subtract from esp
+16 
+17     # read(stdin, x, 1)
+18     # . fd = 0 (stdin)
+19     bb/copy-to-ebx  0/imm32
+20     # . data = x (location to write result to)
+21     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    4/base/esp  4/index/none              1/r32/ecx   4/disp8         .                 # copy esp+4 to ecx
+22     # . size = 1 character
+23     ba/copy-to-edx  1/imm32
+24     # . syscall
+25     e8/call  syscall_read/disp32
+26 
+27     # syscall(write, stdout, x, 1)
+28     # . fd = 1 (stdout)
+29     bb/copy-to-ebx  1/imm32
+30     # . data = x (location to read from)
+31     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    4/base/esp  4/index/none              1/r32/ecx   4/disp8         .                 # copy esp+4 to ecx
+32     # . size = 1 character
+33     ba/copy-to-edx  1/imm32
+34     # . syscall
+35     e8/call  syscall_write/disp32
+36 
+37     # exit(ebx)
+38     e8/call  syscall_exit/disp32
+39 
+40 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/ex6.subx.html b/html/linux/apps/ex6.subx.html new file mode 100644 index 00000000..5aa4fd53 --- /dev/null +++ b/html/linux/apps/ex6.subx.html @@ -0,0 +1,96 @@ + + + + +Mu - linux/apps/ex6.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex6.subx +
+ 1 # Print out a (global variable) string to stdout.
+ 2 #
+ 3 # To run:
+ 4 #   $ bootstrap/bootstrap translate apps/ex6.subx -o ex6
+ 5 #   $ bootstrap/bootstrap run ex6
+ 6 #   Hello, world!
+ 7 
+ 8 == code
+ 9 
+10 # . op          subop               mod             rm32          base        index         scale       r32
+11 # . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
+12 
+13 Entry:
+14     # write(stdout, X, Size)
+15     # . fd = 1 (stdout)
+16     bb/copy-to-ebx  1/imm32
+17     # . initialize X (location to write result to)
+18     b9/copy-to-ecx  X/imm32
+19     # . initialize Size
+20     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           2/r32/edx   Size/disp32     .                 # copy *Size to edx
+21     # . syscall
+22     e8/call  syscall_write/disp32
+23 
+24     # exit(ebx)
+25     e8/call  syscall_exit/disp32
+26 
+27 == data
+28 
+29 Size:  # size of string
+30     0x0d/imm32  # 13
+31 X:  # string to print
+32     48 65 6c 6c 6f 20 77 6f 72 6c 64 21 0a       00
+33 #   H  e  l  l  o  ␣  w  o  r  l  d  !  newline  null
+34 
+35 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/ex7.subx.html b/html/linux/apps/ex7.subx.html new file mode 100644 index 00000000..b2a87263 --- /dev/null +++ b/html/linux/apps/ex7.subx.html @@ -0,0 +1,159 @@ + + + + +Mu - linux/apps/ex7.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex7.subx +
+ 1 # Example showing file syscalls.
+ 2 #
+ 3 # Create a file, open it for writing, write a character to it, close it, open
+ 4 # it for reading, read a character from it, close it, delete it, and return
+ 5 # the character read.
+ 6 #
+ 7 # To run:
+ 8 #   $ bootstrap/bootstrap translate apps/ex7.subx -o ex7
+ 9 #   $ bootstrap/bootstrap run ex7
+10 # Expected result:
+11 #   $ echo $?
+12 #   97
+13 
+14 == code
+15 #   instruction                     effective address                                                   register    displacement    immediate
+16 # . op          subop               mod             rm32          base        index         scale       r32
+17 # . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
+18 
+19 Entry:
+20     # creat(Filename)
+21     bb/copy-to-ebx  Filename/imm32
+22     b9/copy-to-ecx  0x180/imm32/fixed-perms
+23     e8/call  syscall_creat/disp32
+24 
+25     # stream = open(Filename, O_WRONLY, 0)  # we can't use 'fd' because it looks like a hex byte
+26     bb/copy-to-ebx  Filename/imm32
+27     b9/copy-to-ecx  1/imm32/wronly
+28     ba/copy-to-edx  0x180/imm32/fixed-perms
+29     e8/call  syscall_open/disp32
+30     # save stream
+31     bb/copy-to-ebx  Stream/imm32
+32     89/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to *ebx
+33 
+34     # write(Stream, "a", 1)
+35     # . load stream
+36     bb/copy-to-ebx  Stream/imm32
+37     8b/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # copy *ebx to ebx
+38     # .
+39     b9/copy-to-ecx  A/imm32
+40     ba/copy-to-edx  1/imm32/size
+41     e8/call  syscall_write/disp32
+42 
+43     # close(Stream)
+44     # . load stream
+45     bb/copy-to-ebx  Stream/imm32
+46     8b/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # copy *ebx to ebx
+47     # .
+48     e8/call  syscall_close/disp32
+49 
+50     # stream = open(Filename, O_RDONLY, 0)
+51     bb/copy-to-ebx  Filename/imm32
+52     b9/copy-to-ecx  0/imm32/rdonly
+53     ba/copy-to-edx  0x180/imm32/fixed-perms
+54     e8/call  syscall_open/disp32
+55     # . save Stream
+56     bb/copy-to-ebx  Stream/imm32
+57     89/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to *ebx
+58 
+59     # read(Stream, B, 1)
+60     # . load stream
+61     bb/copy-to-ebx  Stream/imm32
+62     8b/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # copy *ebx to ebx
+63     # .
+64     b9/copy-to-ecx  B/imm32
+65     ba/copy-to-edx  1/imm32/size
+66     e8/call  syscall_read/disp32
+67 
+68     # close(Stream)
+69     # . load stream
+70     bb/copy-to-ebx  Stream/imm32
+71     8b/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # copy *ebx to ebx
+72     #
+73     e8/call  syscall_close/disp32
+74 
+75     # unlink(filename)
+76     bb/copy-to-ebx  Filename/imm32
+77     e8/call  syscall_unlink/disp32
+78 
+79     # exit(b)
+80     # . load b
+81     bb/copy-to-ebx  B/imm32
+82     8b/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # copy *ebx to ebx
+83     #
+84     e8/call  syscall_exit/disp32
+85 
+86 == data
+87 
+88 Stream:
+89     0/imm32
+90 A:
+91     61/imm32/A
+92 B:
+93     0/imm32
+94 Filename:
+95     2e 66 6f 6f 00 00 00 00
+96 #   .  f  o  o  null
+97 
+98 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/ex8.subx.html b/html/linux/apps/ex8.subx.html new file mode 100644 index 00000000..86d16571 --- /dev/null +++ b/html/linux/apps/ex8.subx.html @@ -0,0 +1,123 @@ + + + + +Mu - linux/apps/ex8.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex8.subx +
+ 1 # Example reading commandline arguments: compute length of first arg.
+ 2 #
+ 3 # To run:
+ 4 #   $ bootstrap/bootstrap translate apps/ex8.subx -o ex8
+ 5 #   $ bootstrap/bootstrap run ex8 abc de fghi
+ 6 # Expected result:
+ 7 #   $ echo $?
+ 8 #   3  # length of 'abc'
+ 9 #
+10 # At the start of a SubX program:
+11 #   argc: *esp
+12 #   argv[0]: *(esp+4)
+13 #   argv[1]: *(esp+8)
+14 #   ...
+15 # Locals start from esp-4 downwards.
+16 
+17 == code
+18 #   instruction                     effective address                                                   register    displacement    immediate
+19 # . op          subop               mod             rm32          base        index         scale       r32
+20 # . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
+21 
+22 Entry:
+23     # . prologue
+24     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+25     # eax = ascii-length(argv[1])
+26     # . . push args
+27     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+28     # . . call
+29     e8/call  ascii-length/disp32
+30     # . . discard args
+31     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+32 
+33     # exit(eax)
+34     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to ebx
+35     e8/call  syscall_exit/disp32
+36 
+37 ascii-length:  # s: (addr array byte) -> n/eax
+38     # edx = s
+39     8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/esp  4/index/none  .           2/r32/edx   4/disp8         .                 # copy *(esp+4) to edx
+40     # var result/eax = 0
+41     b8/copy-to-eax  0/imm32
+42 $ascii-length:loop:
+43     # var c/ecx = *s
+44     8a/copy-byte                    0/mod/*         2/rm32/edx    .           .             .           1/r32/CL    .               .                 # copy byte at *edx to CL
+45     # if (c == '\0') break
+46     81          7/subop/compare     3/mod/direct    1/rm32/ecx    .           .             .           .           .               0/imm32/null      # compare ecx
+47     74/jump-if-=  $ascii-length:end/disp8
+48     # ++s
+49     42/increment-edx
+50     # ++result
+51     40/increment-eax
+52     # loop
+53     eb/jump  $ascii-length:loop/disp8
+54 $ascii-length:end:
+55     # return eax
+56     c3/return
+57 
+58 == data
+59 
+60 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/ex9.subx.html b/html/linux/apps/ex9.subx.html new file mode 100644 index 00000000..3a79d9d9 --- /dev/null +++ b/html/linux/apps/ex9.subx.html @@ -0,0 +1,114 @@ + + + + +Mu - linux/apps/ex9.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/ex9.subx +
+ 1 # Example showing arg order on the stack.
+ 2 #
+ 3 # Show difference between ascii codes of first letter of first arg and first
+ 4 # letter of second arg.
+ 5 #
+ 6 # To run:
+ 7 #   $ bootstrap/bootstrap translate apps/ex9.subx -o ex9
+ 8 #   $ bootstrap/bootstrap run ex9 z x
+ 9 # Expected result:
+10 #   $ echo $?
+11 #   2
+12 #
+13 # At the start of a SubX program:
+14 #   argc: *esp
+15 #   argv[0]: *(esp+4)
+16 #   argv[1]: *(esp+8)
+17 #   ...
+18 # Locals start from esp-4 downwards.
+19 
+20 == code
+21 #   instruction                     effective address                                                   register    displacement    immediate
+22 # . op          subop               mod             rm32          base        index         scale       r32
+23 # . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
+24 
+25 Entry:
+26     # . prologue
+27     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+28     # ascii-difference(argv[1], argv[2])
+29     # . . push argv[2]
+30     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+31     # . . push argv[1]
+32     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+33     # . . call
+34     e8/call  ascii-difference/disp32
+35     # . . discard args
+36     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+37     # exit(eax)
+38     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to ebx
+39     e8/call  syscall_exit/disp32
+40 
+41 ascii-difference:  # (s1, s2): null-terminated ascii strings
+42     # a = first letter of s1 (ecx)
+43     8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/esp  4/index/none  .           0/r32/eax   4/disp8         .                 # copy *(esp+4) to eax
+44     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           0/r32/eax   .               .                 # copy *eax to eax
+45     # b = first letter of s2 (edx)
+46     8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/esp  4/index/none  .           1/r32/ecx   8/disp8                           # copy *(esp+8) to ecx
+47     8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           1/r32/ecx   .               .                 # copy *ecx to ecx
+48     # a-b
+49     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
+50     c3/return
+51 
+52 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/factorial.mu.html b/html/linux/apps/factorial.mu.html new file mode 100644 index 00000000..3e626b6d --- /dev/null +++ b/html/linux/apps/factorial.mu.html @@ -0,0 +1,125 @@ + + + + +Mu - linux/apps/factorial.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/factorial.mu +
+ 1 # compute the factorial of 5, and return the result in the exit code
+ 2 #
+ 3 # To run:
+ 4 #   $ ./translate apps/factorial.mu
+ 5 #   $ ./a.elf
+ 6 #   $ echo $?
+ 7 #   120
+ 8 #
+ 9 # You can also run the automated test suite:
+10 #   $ ./a.elf test
+11 # Expected output:
+12 #   ........
+13 # Every '.' indicates a passing test. Failing tests get a 'F'.
+14 # There's only one test in this file, but you'll also see tests running from
+15 # Mu's standard library.
+16 #
+17 # Compare factorial4.subx
+18 
+19 fn factorial n: int -> _/eax: int {
+20   compare n, 1
+21   # if (n <= 1) return 1
+22   {
+23     break-if->
+24     return 1
+25   }
+26   # n > 1; return n * factorial(n-1)
+27   var tmp/ecx: int <- copy n
+28   tmp <- decrement
+29   var result/eax: int <- factorial tmp
+30   result <- multiply n
+31   return result
+32 }
+33 
+34 fn test-factorial {
+35   var result/eax: int <- factorial 5
+36   check-ints-equal result, 0x78, "F - test-factorial"
+37 }
+38 
+39 fn main args-on-stack: (addr array addr array byte) -> _/ebx: int {
+40   var args/eax: (addr array addr array byte) <- copy args-on-stack
+41   # len = length(args)
+42   var len/ecx: int <- length args
+43   # if (len <= 1) return factorial(5)
+44   compare len, 1
+45   {
+46     break-if->
+47     var exit-status/eax: int <- factorial 5
+48     return exit-status
+49   }
+50   # if (args[1] == "test") run-tests()
+51   var tmp2/ecx: (addr addr array byte) <- index args, 1
+52   var tmp3/eax: boolean <- string-equal? *tmp2, "test"
+53   compare tmp3, 0
+54   {
+55     break-if-=
+56     run-tests
+57     # TODO: get at Num-test-failures somehow
+58   }
+59   return 0
+60 }
+
+ + + diff --git a/html/linux/apps/factorial.subx.html b/html/linux/apps/factorial.subx.html new file mode 100644 index 00000000..c8f08ab6 --- /dev/null +++ b/html/linux/apps/factorial.subx.html @@ -0,0 +1,217 @@ + + + + +Mu - linux/apps/factorial.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/factorial.subx +
+  1 ## compute the factorial of 5, and print the result
+  2 #
+  3 # To run:
+  4 #   $ bootstrap/bootstrap translate [01]*.subx apps/factorial.subx -o factorial
+  5 #   $ bootstrap/bootstrap run factorial
+  6 # Expected result:
+  7 #   $ echo $?
+  8 #   120
+  9 #
+ 10 # You can also run the automated test suite:
+ 11 #   $ bootstrap/bootstrap run factorial test
+ 12 # Expected output:
+ 13 #   ........
+ 14 # Every '.' indicates a passing test. Failing tests get a 'F'.
+ 15 
+ 16 == code
+ 17 #   instruction                     effective address                                                   register    displacement    immediate
+ 18 # . op          subop               mod             rm32          base        index         scale       r32
+ 19 # . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
+ 20 
+ 21 factorial:  # n: int -> _/eax: int
+ 22     # . prologue
+ 23     55/push-ebp
+ 24     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 25     51/push-ecx
+ 26     # if (n <= 1) return 1
+ 27     b8/copy-to-eax  1/imm32
+ 28     81          7/subop/compare     1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         1/imm32           # compare *(ebp+8)
+ 29     7e/jump-if-<=  $factorial:end/disp8
+ 30     # var ecx: int = n-1
+ 31     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
+ 32     49/decrement-ecx
+ 33     # var eax: int = factorial(n-1)
+ 34     # . . push args
+ 35     51/push-ecx
+ 36     # . . call
+ 37     e8/call  factorial/disp32
+ 38     # . . discard args
+ 39     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 40     # return n * factorial(n-1)
+ 41     f7          4/subop/multiply    1/mod/*+disp8   5/rm32/ebp    .           .                                     8/disp8         .                 # multiply *(ebp+8) into eax
+ 42     # TODO: check for overflow
+ 43 $factorial:end:
+ 44     # restore registers
+ 45     59/pop-to-ecx
+ 46     # . epilogue
+ 47     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 48     5d/pop-to-ebp
+ 49     c3/return
+ 50 
+ 51 test-factorial:
+ 52     # factorial(5)
+ 53     # . . push args
+ 54     68/push  5/imm32
+ 55     # . . call
+ 56     e8/call  factorial/disp32
+ 57     # . . discard args
+ 58     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 59     # check-ints-equal(eax, 120, msg)
+ 60     # . . push args
+ 61     68/push  "F - test-factorial"/imm32
+ 62     68/push  0x78/imm32/expected-120
+ 63     50/push-eax
+ 64     # . . call
+ 65     e8/call  check-ints-equal/disp32
+ 66     # . . discard args
+ 67     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 68     # end
+ 69     c3/return
+ 70 
+ 71 Entry:  # run tests if necessary, compute `factorial(5)` if not
+ 72     # . prologue
+ 73     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 74 
+ 75     # initialize heap (needed by tests elsewhere)
+ 76     # . Heap = new-segment(Heap-size)
+ 77     # . . push args
+ 78     68/push  Heap/imm32
+ 79     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Heap-size/disp32                  # push *Heap-size
+ 80     # . . call
+ 81     e8/call  new-segment/disp32
+ 82     # . . discard args
+ 83     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 84 
+ 85     # if (argc <= 1) return factorial(5)
+ 86 $run-main:
+ 87     81          7/subop/compare     1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0/disp8         1/imm32           # compare *ebp
+ 88     7f/jump-if->  $main:run-tests/disp8
+ 89     # eax = factorial(5)
+ 90     # . . push args
+ 91     68/push  5/imm32
+ 92     # . . call
+ 93     e8/call  factorial/disp32
+ 94     # . . discard args
+ 95     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 96     # var buffer/ecx: (stream byte 10)  # number of decimal digits a 32-bit number can have
+ 97     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0xa/imm32         # subtract from esp
+ 98     68/push  0xa/imm32/decimal-digits-in-32bit-number
+ 99     68/push  0/imm32/read
+100     68/push  0/imm32/write
+101     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+102     # write-int32-decimal(buffer, eax)
+103     # . . push args
+104     50/push-eax
+105     51/push-ecx
+106     # . . call
+107     e8/call  write-int32-decimal/disp32
+108     # . . discard args
+109     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+110     # write-stream(stderr, buffer)
+111     # . . push args
+112     51/push-ecx
+113     68/push  2/imm32/stderr
+114     # . . call
+115     e8/call  write-stream/disp32
+116     # . . discard args
+117     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+118     # write(stderr, Newline)
+119     # . . push args
+120     68/push  Newline/imm32
+121     68/push  2/imm32/stderr
+122     # . . call
+123     e8/call  write/disp32
+124     # . . discard args
+125     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+126     #
+127     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to ebx
+128     eb/jump  $main:end/disp8
+129 $main:run-tests:
+130     # otherwise if first arg is "test", then return run_tests()
+131     # if (!kernel-string-equal?(argv[1], "test")) goto do-nothing
+132     # . eax = kernel-string-equal?(argv[1], "test")
+133     # . . push args
+134     68/push  "test"/imm32
+135     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+136     # . . call
+137     e8/call  kernel-string-equal?/disp32
+138     # . . discard args
+139     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+140     # . if (eax == false) goto do-nothing
+141     3d/compare-eax-and  0/imm32/false
+142     74/jump-if-=  $main:do-nothing/disp8
+143     # run-tests()
+144     e8/call  run-tests/disp32
+145     # exit(*Num-test-failures)
+146     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/ebx   Num-test-failures/disp32          # copy *Num-test-failures to ebx
+147     eb/jump  $main:end/disp8
+148 $main:do-nothing:
+149     bb/copy-to-ebx  0/imm32
+150 $main:end:
+151     e8/call  syscall_exit/disp32
+152 
+153 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/linux/apps/factorial2.subx.html b/html/linux/apps/factorial2.subx.html new file mode 100644 index 00000000..72331748 --- /dev/null +++ b/html/linux/apps/factorial2.subx.html @@ -0,0 +1,185 @@ + + + + +Mu - linux/apps/factorial2.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/factorial2.subx +
+  1 ## compute the factorial of 5, and return the result in the exit code
+  2 #
+  3 # Uses syntax sugar for:
+  4 #   rm32 operands
+  5 #
+  6 # To run:
+  7 #   $ ./translate_subx init.linux [01]*.subx apps/factorial2.subx -o factorial
+  8 #   $ bootstrap/bootstrap run factorial
+  9 # Expected result:
+ 10 #   $ echo $?
+ 11 #   120
+ 12 #
+ 13 # You can also run the automated test suite:
+ 14 #   $ bootstrap/bootstrap run factorial test
+ 15 # Expected output:
+ 16 #   ........
+ 17 # Every '.' indicates a passing test. Failing tests get a 'F'.
+ 18 #
+ 19 # Compare factorial.subx
+ 20 
+ 21 == code
+ 22 
+ 23 factorial:  # n: int -> _/eax: int
+ 24     # . prologue
+ 25     55/push-ebp
+ 26     89/<- %ebp 4/r32/esp
+ 27     # save registers
+ 28     51/push-ecx
+ 29     # if (n <= 1) return 1
+ 30     b8/copy-to-eax 1/imm32
+ 31     81 7/subop/compare *(ebp+8) 1/imm32
+ 32     7e/jump-if-<= $factorial:end/disp8
+ 33     # n > 1; return n * factorial(n-1)
+ 34     8b/-> *(ebp+8) 1/r32/ecx
+ 35     49/decrement-ecx
+ 36     # var tmp/eax: int = factorial(n-1)
+ 37     # . . push args
+ 38     51/push-ecx
+ 39     # . . call
+ 40     e8/call factorial/disp32
+ 41     # . . discard args
+ 42     81 0/subop/add %esp 4/imm32
+ 43     # return n * tmp
+ 44     f7 4/subop/multiply-into-eax *(ebp+8)
+ 45     # TODO: check for overflow
+ 46 $factorial:end:
+ 47     # restore registers
+ 48     59/pop-to-ecx
+ 49     # . epilogue
+ 50     89/<- %esp 5/r32/ebp
+ 51     5d/pop-to-ebp
+ 52     c3/return
+ 53 
+ 54 test-factorial:
+ 55     # factorial(5)
+ 56     # . . push args
+ 57     68/push 5/imm32
+ 58     # . . call
+ 59     e8/call factorial/disp32
+ 60     # . . discard args
+ 61     81 0/subop/add %esp 4/imm32
+ 62     # check-ints-equal(eax, 120, msg)
+ 63     # . . push args
+ 64     68/push "F - test-factorial"/imm32
+ 65     68/push 0x78/imm32/expected-120
+ 66     50/push-eax
+ 67     # . . call
+ 68     e8/call check-ints-equal/disp32
+ 69     # . . discard args
+ 70     81 0/subop/add %esp 0xc/imm32
+ 71     # end
+ 72     c3/return
+ 73 
+ 74 Entry:  # run tests if necessary, compute `factorial(5)` if not
+ 75     # . prologue
+ 76     89/<- %ebp 4/r32/esp
+ 77 
+ 78     # initialize heap (needed by tests elsewhere)
+ 79     # . Heap = new-segment(Heap-size)
+ 80     # . . push args
+ 81     68/push Heap/imm32
+ 82     ff 6/subop/push *Heap-size
+ 83     # . . call
+ 84     e8/call new-segment/disp32
+ 85     # . . discard args
+ 86     81 0/subop/add %esp 8/imm32
+ 87 
+ 88     # if (argc <= 1) return factorial(5)
+ 89     81 7/subop/compare *ebp 1/imm32
+ 90     7f/jump-if-> $main:run-tests/disp8
+ 91     # . . push args
+ 92     68/push 5/imm32
+ 93     # . . call
+ 94     e8/call factorial/disp32
+ 95     # . . discard args
+ 96     81 0/subop/add %esp 4/imm32
+ 97     # .
+ 98     89/<- %ebx 0/r32/eax
+ 99     eb/jump $main:end/disp8
+100 $main:run-tests:
+101     # otherwise if first arg is "test", then return run_tests()
+102     # if (!kernel-string-equal?(argv[1], "test")) goto do-nothing
+103     # . eax = kernel-string-equal?(argv[1], "test")
+104     # . . push args
+105     68/push "test"/imm32
+106     ff 6/subop/push *(ebp+8)
+107     # . . call
+108     e8/call kernel-string-equal?/disp32
+109     # . . discard args
+110     81 0/subop/add %esp 8/imm32
+111     # . if (eax == false) goto do-nothing
+112     3d/compare-eax-and 0/imm32/false
+113     74/jump-if-= $main:do-nothing/disp8
+114     # run-tests()
+115     e8/call run-tests/disp32
+116     # exit(*Num-test-failures)
+117     8b/-> *Num-test-failures 3/r32/ebx
+118     eb/jump $main:end/disp8
+119 $main:do-nothing:
+120     bb/copy-to-ebx 0/imm32
+121 $main:end:
+122     e8/call  syscall_exit/disp32
+
+ + + diff --git a/html/linux/apps/factorial3.subx.html b/html/linux/apps/factorial3.subx.html new file mode 100644 index 00000000..93cf4e55 --- /dev/null +++ b/html/linux/apps/factorial3.subx.html @@ -0,0 +1,142 @@ + + + + +Mu - linux/apps/factorial3.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/factorial3.subx +
+ 1 ## compute the factorial of 5, and return the result in the exit code
+ 2 #
+ 3 # Uses syntax sugar for:
+ 4 #   rm32 operands
+ 5 #   function calls
+ 6 #
+ 7 # To run:
+ 8 #   $ ./translate_subx init.linux [01]*.subx apps/factorial3.subx -o factorial
+ 9 #   $ bootstrap/bootstrap run factorial
+10 # Expected result:
+11 #   $ echo $?
+12 #   120
+13 #
+14 # You can also run the automated test suite:
+15 #   $ bootstrap/bootstrap run factorial test
+16 # Expected output:
+17 #   ........
+18 # Every '.' indicates a passing test. Failing tests get a 'F'.
+19 #
+20 # Compare factorial2.subx
+21 
+22 == code
+23 
+24 factorial:  # n: int -> _/eax: int
+25     # . prologue
+26     55/push-ebp
+27     89/<- %ebp 4/r32/esp
+28     # save registers
+29     51/push-ecx
+30     # if (n <= 1) return 1
+31     b8/copy-to-eax 1/imm32
+32     81 7/subop/compare *(ebp+8) 1/imm32
+33     7e/jump-if-<= $factorial:end/disp8
+34     # n > 1; return n * factorial(n-1)
+35     8b/-> *(ebp+8) 1/r32/ecx
+36     49/decrement-ecx
+37     (factorial %ecx)  # => eax
+38     f7 4/subop/multiply-into-eax *(ebp+8)
+39     # TODO: check for overflow
+40 $factorial:end:
+41     # restore registers
+42     59/pop-to-ecx
+43     # . epilogue
+44     89/<- %esp 5/r32/ebp
+45     5d/pop-to-ebp
+46     c3/return
+47 
+48 test-factorial:
+49     (factorial 5)
+50     (check-ints-equal %eax 0x78 "F - test-factorial")
+51     c3/return
+52 
+53 Entry:  # run tests if necessary, compute `factorial(5)` if not
+54     # . prologue
+55     89/<- %ebp 4/r32/esp
+56 
+57     # initialize heap (needed by tests elsewhere)
+58     (new-segment *Heap-size Heap)
+59 
+60     # if (argc <= 1) return factorial(5)
+61     81 7/subop/compare *ebp 1/imm32
+62     7f/jump-if-> $main:run-tests/disp8
+63     (factorial 5)  # => eax
+64     89/<- %ebx 0/r32/eax
+65     eb/jump $main:end/disp8
+66 $main:run-tests:
+67     # otherwise if first arg is "test", then return run_tests()
+68     # if (!kernel-string-equal?(argv[1], "test")) goto do-nothing
+69     (kernel-string-equal? *(ebp+8) "test")  # => eax
+70     3d/compare-eax-and 0/imm32/false
+71     74/jump-if-= $main:do-nothing/disp8
+72     #
+73     (run-tests)
+74     # exit(*Num-test-failures)
+75     8b/-> *Num-test-failures 3/r32/ebx
+76     eb/jump $main:end/disp8
+77 $main:do-nothing:
+78     bb/copy-to-ebx 0/imm32
+79 $main:end:
+80     e8/call  syscall_exit/disp32
+
+ + + diff --git a/html/linux/apps/factorial4.subx.html b/html/linux/apps/factorial4.subx.html new file mode 100644 index 00000000..879a7a44 --- /dev/null +++ b/html/linux/apps/factorial4.subx.html @@ -0,0 +1,150 @@ + + + + +Mu - linux/apps/factorial4.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/factorial4.subx +
+ 1 ## compute the factorial of 5, and return the result in the exit code
+ 2 #
+ 3 # Uses syntax sugar for:
+ 4 #   rm32 operands
+ 5 #   function calls
+ 6 #   control flow
+ 7 #
+ 8 # To run:
+ 9 #   $ ./translate_subx init.linux [01]*.subx apps/factorial4.subx -o factorial
+10 #   $ bootstrap/bootstrap run factorial
+11 # Expected result:
+12 #   $ echo $?
+13 #   120
+14 #
+15 # You can also run the automated test suite:
+16 #   $ bootstrap/bootstrap run factorial test
+17 # Expected output:
+18 #   ........
+19 # Every '.' indicates a passing test. Failing tests get a 'F'.
+20 #
+21 # Compare factorial3.subx
+22 
+23 == code
+24 
+25 factorial:  # n: int -> _/eax: int
+26     # . prologue
+27     55/push-ebp
+28     89/<- %ebp 4/r32/esp
+29     # save registers
+30     51/push-ecx
+31     # if (n <= 1) return 1
+32     81 7/subop/compare *(ebp+8) 1/imm32
+33     {
+34       7f/jump-if-> break/disp8
+35       b8/copy-to-eax 1/imm32
+36       eb/jump $factorial:end/disp8
+37     }
+38     # n > 1; return n * factorial(n-1)
+39     8b/-> *(ebp+8) 1/r32/ecx
+40     49/decrement-ecx
+41     (factorial %ecx)  # => eax
+42     f7 4/subop/multiply-into-eax *(ebp+8)
+43     # TODO: check for overflow
+44 $factorial:end:
+45     # restore registers
+46     59/pop-to-ecx
+47     # . epilogue
+48     89/<- %esp 5/r32/ebp
+49     5d/pop-to-ebp
+50     c3/return
+51 
+52 test-factorial:
+53     (factorial 5)
+54     (check-ints-equal %eax 0x78 "F - test-factorial")
+55     c3/return
+56 
+57 Entry:  # run tests if necessary, compute `factorial(5)` if not
+58     # . prologue
+59     89/<- %ebp 4/r32/esp
+60 
+61     # initialize heap (needed by tests elsewhere)
+62     (new-segment *Heap-size Heap)
+63 
+64     # if (argc <= 1) return factorial(5)
+65     {
+66       # if (argc > 1) break
+67       81 7/subop/compare *ebp 1/imm32
+68       7f/jump-if-> break/disp8
+69       # ebx = factorial(5)
+70       (factorial 5)  # => eax
+71       89/<- %ebx 0/r32/eax
+72       eb/jump $main:end/disp8
+73     }
+74     # otherwise if first arg is "test", then return run_tests()
+75     {
+76       # if (!kernel-string-equal?(argv[1], "test")) break
+77       (kernel-string-equal? *(ebp+8) "test")  # => eax
+78       3d/compare-eax-and 0/imm32/false
+79       74/jump-if-= break/disp8
+80       #
+81       (run-tests)
+82       # exit(*Num-test-failures)
+83       8b/-> *Num-test-failures 3/r32/ebx
+84       eb/jump $main:end/disp8
+85     }
+86     bb/copy-to-ebx 0/imm32
+87 $main:end:
+88     e8/call  syscall_exit/disp32
+
+ + + diff --git a/html/linux/apps/hello.mu.html b/html/linux/apps/hello.mu.html new file mode 100644 index 00000000..b7033551 --- /dev/null +++ b/html/linux/apps/hello.mu.html @@ -0,0 +1,72 @@ + + + + +Mu - linux/apps/hello.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/hello.mu +
+ 1 # Meaningless conventional example.
+ 2 #
+ 3 # To run:
+ 4 #   $ ./translate apps/hello.mu
+ 5 #   $ ./a.elf
+ 6 
+ 7 fn main -> _/ebx: int {
+ 8   print-string 0/screen, "Hello world!\n"
+ 9   return 0
+10 }
+
+ + + diff --git a/html/linux/apps/parse-int.mu.html b/html/linux/apps/parse-int.mu.html new file mode 100644 index 00000000..0ba861a7 --- /dev/null +++ b/html/linux/apps/parse-int.mu.html @@ -0,0 +1,114 @@ + + + + +Mu - linux/apps/parse-int.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/parse-int.mu +
+ 1 # parse a decimal int at the commandline
+ 2 #
+ 3 # To run:
+ 4 #   $ ./translate apps/parse-int.mu
+ 5 #   $ ./a.elf 123
+ 6 #   $ echo $?
+ 7 #   123
+ 8 
+ 9 fn main _args: (addr array addr array byte) -> _/ebx: int {
+10   # if no args, print a message and exit
+11   var args/esi: (addr array addr array byte) <- copy _args
+12   var n/ecx: int <- length args
+13   compare n, 1
+14   {
+15     break-if->
+16     print-string 0/screen, "usage: parse-int <integer>\n"
+17     return 1
+18   }
+19   # otherwise parse the first arg as an integer
+20   var in/ecx: (addr addr array byte) <- index args, 1
+21   var out/eax: int <- parse-int *in
+22   return out
+23 }
+24 
+25 fn parse-int _in: (addr array byte) -> _/eax: int {
+26   var in/esi: (addr array byte) <- copy _in
+27   var len/edx: int <- length in
+28   var i/ecx: int <- copy 0
+29   var result/edi: int <- copy 0
+30   {
+31     compare i, len
+32     break-if->=
+33     # result *= 10
+34     var ten/eax: int <- copy 0xa
+35     result <- multiply ten
+36     # c = in[i]
+37     var tmp/ebx: (addr byte) <- index in, i
+38     var c/eax: byte <- copy-byte *tmp
+39     #
+40     var g/eax: grapheme <- copy c
+41     var digit/eax: int <- to-decimal-digit g
+42     result <- add digit
+43     i <- increment
+44     loop
+45   }
+46   return result
+47 }
+
+ + + diff --git a/html/linux/apps/print-file.mu.html b/html/linux/apps/print-file.mu.html new file mode 100644 index 00000000..21dfc9d2 --- /dev/null +++ b/html/linux/apps/print-file.mu.html @@ -0,0 +1,104 @@ + + + + +Mu - linux/apps/print-file.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/print-file.mu +
+ 1 # accept a filename on the commandline, read it and print it out to screen
+ 2 # only ascii right now, just like the rest of Mu
+ 3 #
+ 4 # To run:
+ 5 #   $ ./translate apps/print-file.mu
+ 6 #   $ echo abc > x
+ 7 #   $ ./a.elf x
+ 8 #   abc
+ 9 
+10 fn main _args: (addr array addr array byte) -> _/ebx: int {
+11   var args/eax: (addr array addr array byte) <- copy _args
+12   var n/ecx: int <- length args
+13   compare n, 1
+14   {
+15     break-if->
+16     print-string 0/screen, "usage: cat <filename>\n"
+17     return 0
+18   }
+19   {
+20     break-if-<=
+21     var filename/edx: (addr addr array byte) <- index args 1
+22     var in: (handle buffered-file)
+23     {
+24       var addr-in/eax: (addr handle buffered-file) <- address in
+25       open *filename, 0/read-only, addr-in
+26     }
+27     var _in-addr/eax: (addr buffered-file) <- lookup in
+28     var in-addr/ecx: (addr buffered-file) <- copy _in-addr
+29     {
+30       var c/eax: byte <- read-byte-buffered in-addr
+31       compare c, 0xffffffff/end-of-file
+32       break-if-=
+33       var g/eax: grapheme <- copy c
+34       print-grapheme 0/screen, g
+35       loop
+36     }
+37   }
+38   return 0
+39 }
+
+ + + diff --git a/html/linux/apps/raytracing/1.mu.html b/html/linux/apps/raytracing/1.mu.html new file mode 100644 index 00000000..f7464218 --- /dev/null +++ b/html/linux/apps/raytracing/1.mu.html @@ -0,0 +1,95 @@ + + + + +Mu - linux/apps/raytracing/1.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/raytracing/1.mu +
+ 1 # Listing 1 of https://raytracing.github.io/books/RayTracingInOneWeekend.html
+ 2 # (simplified)
+ 3 #
+ 4 # To run (on Linux):
+ 5 #   $ git clone https://github.com/akkartik/mu
+ 6 #   $ cd mu/linux
+ 7 #   $ ./translate apps/raytracing/1.mu
+ 8 #   $ ./a.elf > 1.ppm
+ 9 
+10 fn main -> _/ebx: int {
+11   print-string 0, "P3\n256 256\n255\n"
+12   var j/ecx: int <- copy 0xff
+13   {
+14     compare j, 0
+15     break-if-<
+16     var i/eax: int <- copy 0
+17     {
+18       compare i, 0xff
+19       break-if->
+20       print-int32-decimal 0, i
+21       print-string 0, " "
+22       print-int32-decimal 0, j
+23       print-string 0, " 64\n"
+24       i <- increment
+25       loop
+26     }
+27     j <- decrement
+28     loop
+29   }
+30   return 0
+31 }
+
+ + + diff --git a/html/linux/apps/raytracing/2.mu.html b/html/linux/apps/raytracing/2.mu.html new file mode 100644 index 00000000..6ae05c81 --- /dev/null +++ b/html/linux/apps/raytracing/2.mu.html @@ -0,0 +1,153 @@ + + + + +Mu - linux/apps/raytracing/2.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/raytracing/2.mu +
+ 1 # Listing 7 of https://raytracing.github.io/books/RayTracingInOneWeekend.html
+ 2 #
+ 3 # To run (on Linux):
+ 4 #   $ git clone https://github.com/akkartik/mu
+ 5 #   $ cd mu/linux
+ 6 #   $ ./translate apps/raytracing/2.mu
+ 7 #   $ ./a.elf > 2.ppm
+ 8 
+ 9 fn main -> _/ebx: int {
+10   print-string 0, "P3\n256 256\n255\n"
+11   var _four/edx: int <- copy 4
+12   var four/xmm1: float <- convert _four
+13   var one-fourth/xmm1: float <- reciprocal four
+14   var max/edx: int <- copy 0xff
+15   var image-size/xmm2: float <- convert max
+16   var j/ecx: int <- copy 0xff
+17   {
+18     compare j, 0
+19     break-if-<
+20     var i/eax: int <- copy 0
+21     {
+22       compare i, 0xff
+23       break-if->
+24       var c: rgb
+25       # compute r
+26       var tmp/xmm0: float <- convert i
+27       tmp <- divide image-size
+28       var r-addr/edx: (addr float) <- get c, r
+29       copy-to *r-addr, tmp
+30 #?       var tmp2/ebx: int <- reinterpret *r-addr
+31 #?       print-int32-hex 0, tmp2
+32 #?       print-string 0, "\n"
+33       # compute g
+34       tmp <- convert j
+35       tmp <- divide image-size
+36       var g-addr/edx: (addr float) <- get c, g
+37       copy-to *g-addr, tmp
+38       # compute b
+39       var b-addr/edx: (addr float) <- get c, b
+40       copy-to *b-addr, one-fourth
+41       # emit
+42       var c-addr/edx: (addr rgb) <- address c
+43       print-rgb 0, c-addr
+44       i <- increment
+45       loop
+46     }
+47     j <- decrement
+48     loop
+49   }
+50   return 0
+51 }
+52 
+53 type rgb {
+54   # components normalized to within [0.0, 1.0]
+55   r: float
+56   g: float
+57   b: float
+58 }
+59 
+60 # print translating to [0, 256)
+61 fn print-rgb screen: (addr screen), _c: (addr rgb) {
+62   var c/esi: (addr rgb) <- copy _c
+63   var n/ecx: int <- copy 0xff  # turns out 255 works just as well as 255.999, which is lucky because we don't have floating-point literals
+64   var xn/xmm1: float <- convert n
+65   # print 255 * c->r
+66   var result/xmm0: float <- copy xn
+67   var src-addr/eax: (addr float) <- get c, r
+68   result <- multiply *src-addr
+69   var result-int/edx: int <- convert result
+70   print-int32-decimal screen, result-int
+71   print-string screen, " "
+72   # print 255 * c->g
+73   src-addr <- get c, g
+74   result <- copy xn
+75   result <- multiply *src-addr
+76   result-int <- convert result
+77   print-int32-decimal screen, result-int
+78   print-string screen, " "
+79   # print 255 * c->b
+80   src-addr <- get c, b
+81   result <- copy xn
+82   result <- multiply *src-addr
+83   result-int <- convert result
+84   print-int32-decimal screen, result-int
+85   print-string screen, "\n"
+86 }
+
+ + + diff --git a/html/linux/apps/raytracing/3.mu.html b/html/linux/apps/raytracing/3.mu.html new file mode 100644 index 00000000..c43df3a4 --- /dev/null +++ b/html/linux/apps/raytracing/3.mu.html @@ -0,0 +1,554 @@ + + + + +Mu - linux/apps/raytracing/3.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/raytracing/3.mu +
+  1 # Listing 9 of https://raytracing.github.io/books/RayTracingInOneWeekend.html
+  2 #
+  3 # To run (on Linux):
+  4 #   $ git clone https://github.com/akkartik/mu
+  5 #   $ cd mu/linux
+  6 #   $ ./translate apps/raytracing/3.mu
+  7 #   $ ./a.elf > 3.ppm
+  8 
+  9 fn ray-color _in: (addr ray), _out: (addr rgb) {
+ 10   var in/esi: (addr ray) <- copy _in
+ 11   var out/edi: (addr rgb) <- copy _out
+ 12   var dir/eax: (addr vec3) <- get in, dir
+ 13 #?   print-string 0, "r.dir: "
+ 14 #?   print-vec3 0, dir
+ 15 #?   print-string 0, "\n"
+ 16   var unit-storage: vec3
+ 17   var unit/ecx: (addr vec3) <- address unit-storage
+ 18   vec3-unit dir, unit
+ 19 #?   print-string 0, "r.dir normalized: "
+ 20 #?   print-vec3 0, unit
+ 21 #?   print-string 0, "\n"
+ 22   var y-addr/eax: (addr float) <- get unit, y
+ 23   # t = (dir.y + 1.0) / 2.0
+ 24   var t/xmm0: float <- copy *y-addr
+ 25   var one/eax: int <- copy 1
+ 26   var one-f/xmm1: float <- convert one
+ 27   t <- add one-f
+ 28   var two/eax: int <- copy 2
+ 29   var two-f/xmm2: float <- convert two
+ 30   t <- divide two-f
+ 31 #?   print-string 0, "t: "
+ 32 #?   print-float-hex 0, t
+ 33 #?   print-string 0, "\n"
+ 34   # whitening = (1.0 - t) * white
+ 35   var whitening-storage: rgb
+ 36   var whitening/ecx: (addr rgb) <- address whitening-storage
+ 37   rgb-white whitening
+ 38   var one-minus-t/xmm3: float <- copy one-f
+ 39   one-minus-t <- subtract t
+ 40   rgb-scale-up whitening, one-minus-t
+ 41 #?   print-string 0, "whitening: "
+ 42 #?   print-rgb-raw 0, whitening
+ 43 #?   print-string 0, "\n"
+ 44   # out = t * (0.5, 0.7, 1.0)
+ 45   var dest/eax: (addr float) <- get out, r
+ 46   fill-in-rational dest, 5, 0xa
+ 47   dest <- get out, g
+ 48   fill-in-rational dest, 7, 0xa
+ 49   dest <- get out, b
+ 50   copy-to *dest, one-f
+ 51   rgb-scale-up out, t
+ 52 #?   print-string 0, "base: "
+ 53 #?   print-rgb-raw 0, out
+ 54 #?   print-string 0, "\n"
+ 55   # blend with whitening
+ 56   rgb-add-to out, whitening
+ 57 #?   print-string 0, "result: "
+ 58 #?   print-rgb-raw 0, out
+ 59 #?   print-string 0, "\n"
+ 60 }
+ 61 
+ 62 fn main -> _/ebx: int {
+ 63 
+ 64   # image
+ 65   #   width = 400
+ 66   #   height = 400 * 9/16 = 225
+ 67   var aspect: float
+ 68   var aspect-addr/eax: (addr float) <- address aspect
+ 69   fill-in-rational aspect-addr, 0x10, 9  # 16/9
+ 70 #?   print-string 0, "aspect ratio: "
+ 71 #?   print-float-hex 0, aspect
+ 72 #?   print-string 0, " "
+ 73 #?   {
+ 74 #?     var foo2/ebx: int <- reinterpret aspect
+ 75 #?     print-int32-hex 0, foo2
+ 76 #?   }
+ 77 #?   print-string 0, "\n"
+ 78 
+ 79   # camera
+ 80 
+ 81   # viewport-height = 2.0
+ 82   var tmp/eax: int <- copy 2
+ 83   var two-f/xmm4: float <- convert tmp
+ 84   var viewport-height/xmm7: float <- copy two-f
+ 85 #?   print-string 0, "viewport height: "
+ 86 #?   print-float-hex 0, viewport-height
+ 87 #?   print-string 0, " "
+ 88 #?   {
+ 89 #?     var foo: float
+ 90 #?     copy-to foo, viewport-height
+ 91 #?     var foo2/ebx: int <- reinterpret foo
+ 92 #?     print-int32-hex 0, foo2
+ 93 #?   }
+ 94 #?   print-string 0, "\n"
+ 95   # viewport-width = aspect * viewport-height
+ 96   var viewport-width/xmm6: float <- convert tmp
+ 97   viewport-width <- multiply aspect
+ 98 #?   print-string 0, "viewport width: "
+ 99 #?   print-float-hex 0, viewport-width
+100 #?   print-string 0, " "
+101 #?   {
+102 #?     var foo: float
+103 #?     copy-to foo, viewport-width
+104 #?     var foo2/ebx: int <- reinterpret foo
+105 #?     print-int32-hex 0, foo2
+106 #?   }
+107 #?   print-string 0, "\n"
+108   # focal-length = 1.0
+109   tmp <- copy 1
+110   var focal-length/xmm5: float <- convert tmp
+111 
+112   # origin = point3(0, 0, 0)
+113   var origin-storage: vec3
+114   var origin/edi: (addr vec3) <- address origin-storage
+115   # horizontal = vec3(viewport-width, 0, 0)
+116   var horizontal-storage: vec3
+117   var dest/eax: (addr float) <- get horizontal-storage, x
+118   copy-to *dest, viewport-width
+119   var horizontal/ebx: (addr vec3) <- address horizontal-storage
+120   # vertical = vec3(0, viewport-height, 0)
+121   var vertical-storage: vec3
+122   dest <- get vertical-storage, y
+123   copy-to *dest, viewport-height
+124   var vertical/edx: (addr vec3) <- address vertical-storage
+125   # lower-left-corner = origin - horizontal/2 - vertical/2 - vec3(0, 0, focal-length)
+126   # . lower-left-corner = origin
+127   var lower-left-corner-storage: vec3
+128   var lower-left-corner/esi: (addr vec3) <- address lower-left-corner-storage
+129   copy-object origin, lower-left-corner
+130   # . lower-left-corner -= horizontal/2
+131   var tmp2: vec3
+132   var tmp2-addr/eax: (addr vec3) <- address tmp2
+133   copy-object horizontal, tmp2-addr
+134   vec3-scale-down tmp2-addr, two-f
+135   vec3-subtract-from lower-left-corner, tmp2-addr
+136   # . lower-left-corner -= vertical/2
+137   copy-object vertical, tmp2-addr
+138   vec3-scale-down tmp2-addr, two-f
+139   vec3-subtract-from lower-left-corner, tmp2-addr
+140   # . lower-left-corner -= vec3(0, 0, focal-length)
+141   var dest2/ecx: (addr float) <- get lower-left-corner, z
+142   var tmp3/xmm0: float <- copy *dest2
+143   tmp3 <- subtract focal-length
+144   copy-to *dest2, tmp3
+145   # phew!
+146 
+147   # render
+148 
+149   # live variables at this point:
+150   #   origin (edi)
+151   #   lower-left-corner (esi)
+152   #   horizontal (ebx)
+153   #   vertical (edx)
+154   # floating-point registers are all free
+155   print-string 0, "P3\n400 225\n255\n"  # 225 = image height
+156   var tmp/eax: int <- copy 0x18f # image width - 1
+157   var image-width-1/xmm7: float <- convert tmp
+158   tmp <- copy 0xe0  # image height - 1
+159   var image-height-1/xmm6: float <- convert tmp
+160   #
+161   var j/ecx: int <- copy 0xe0  # 224
+162   {
+163     compare j, 0
+164     break-if-<
+165     var i/eax: int <- copy 0
+166     {
+167       compare i, 0x190  # 400 = image width
+168       break-if->=
+169       # u = i / (image-width - 1)
+170       var u/xmm0: float <- convert i
+171       u <- divide image-width-1
+172 #?       print-string 0, "u: "
+173 #?       print-float-hex 0, u
+174 #?       print-string 0, "\n"
+175       # v = j / (image-height - 1)
+176       var v/xmm1: float <- convert j
+177       v <- divide image-height-1
+178       # r = ray(origin, lower-left-corner + u*horizontal + v*vertical - origin)
+179       var r-storage: ray
+180       # . . we're running out of int registers now,
+181       # . . but luckily we don't need i and j in the rest of this loop iteration,
+182       # . . so we'll just spill them in a block
+183       {
+184         # . r.orig = origin
+185         var r/eax: (addr ray) <- address r-storage
+186         var dest/ecx: (addr vec3) <- get r, orig
+187         copy-object origin, dest
+188         # . r.dir = lower-left-corner
+189         dest <- get r, dir
+190         copy-object lower-left-corner, dest
+191         # . r.dir += horizontal*u
+192         var tmp-vec3: vec3
+193         var tmp/eax: (addr vec3) <- address tmp-vec3
+194         copy-object horizontal, tmp
+195         vec3-scale-up tmp, u
+196         vec3-add-to dest, tmp
+197         # . r.dir += vertical*v
+198         copy-object vertical, tmp
+199         vec3-scale-up tmp, v
+200         vec3-add-to dest, tmp
+201         # . r.dir -= origin
+202         vec3-subtract-from dest, origin
+203 #?         print-string 0, "ray direction: "
+204 #?         print-vec3 0, dest
+205 #?         print-string 0, "\n"
+206       }
+207       # pixel-color = ray-color(r)
+208       var c-storage: rgb
+209       var c/ecx: (addr rgb) <- address c-storage
+210       {
+211         var r/eax: (addr ray) <- address r-storage
+212         ray-color r, c
+213         # write color
+214         print-rgb 0, c
+215 #?         print-rgb-raw 0, c
+216 #?         print-string 0, "\n"
+217       }
+218       i <- increment
+219       loop
+220     }
+221     j <- decrement
+222     loop
+223   }
+224   return 0
+225 }
+226 
+227 type ray {
+228   orig: vec3  # point
+229   dir: vec3
+230 }
+231 
+232 # A little different from the constructor at https://raytracing.github.io/books/RayTracingInOneWeekend.html
+233 # We immediately normalize the direction vector so we don't have to keep doing
+234 # so.
+235 fn initialize-ray _self: (addr ray), o: (addr vec3), d: (addr vec3) {
+236   var self/esi: (addr ray) <- copy _self
+237   var dest/eax: (addr vec3) <- get self, orig
+238   copy-object o, dest
+239   dest <- get self, dir
+240   vec3-unit d, dest
+241 }
+242 
+243 fn ray-at _self: (addr ray), t: float, out: (addr vec3) {
+244   var self/esi: (addr ray) <- copy _self
+245   var src/eax: (addr vec3) <- get self, dir
+246   copy-object src, out
+247   vec3-scale-up out, t
+248   src <- get self, orig
+249   vec3-add-to out, src
+250 }
+251 
+252 type rgb {
+253   # components normalized to within [0.0, 1.0]
+254   r: float
+255   g: float
+256   b: float
+257 }
+258 
+259 # print translating to [0, 256)
+260 fn print-rgb screen: (addr screen), _c: (addr rgb) {
+261   var c/esi: (addr rgb) <- copy _c
+262   var xn: float
+263   var xn-addr/ecx: (addr float) <- address xn
+264   fill-in-rational xn-addr, 0x3e7ff, 0x3e8  # 255999 / 1000
+265   # print 255.999 * c->r
+266   var result/xmm0: float <- copy xn
+267   var src-addr/eax: (addr float) <- get c, r
+268   result <- multiply *src-addr
+269   var result-int/edx: int <- truncate result
+270   print-int32-decimal screen, result-int
+271   print-string screen, " "
+272   # print 255.999 * c->g
+273   src-addr <- get c, g
+274   result <- copy xn
+275   result <- multiply *src-addr
+276   result-int <- truncate result
+277   print-int32-decimal screen, result-int
+278   print-string screen, " "
+279   # print 255.999 * c->b
+280   src-addr <- get c, b
+281   result <- copy xn
+282   result <- multiply *src-addr
+283   result-int <- truncate result
+284   print-int32-decimal screen, result-int
+285   print-string screen, "\n"
+286 }
+287 
+288 fn print-rgb-raw screen: (addr screen), _v: (addr rgb) {
+289   var v/esi: (addr rgb) <- copy _v
+290   print-string screen, "("
+291   var tmp/eax: (addr float) <- get v, r
+292   print-float-hex screen, *tmp
+293   print-string screen, ", "
+294   tmp <- get v, g
+295   print-float-hex screen, *tmp
+296   print-string screen, ", "
+297   tmp <- get v, b
+298   print-float-hex screen, *tmp
+299   print-string screen, ")"
+300 }
+301 
+302 fn rgb-white _c: (addr rgb) {
+303   var c/esi: (addr rgb) <- copy _c
+304   var one/eax: int <- copy 1
+305   var one-f/xmm0: float <- convert one
+306   var dest/edi: (addr float) <- get c, r
+307   copy-to *dest, one-f
+308   dest <- get c, g
+309   copy-to *dest, one-f
+310   dest <- get c, b
+311   copy-to *dest, one-f
+312 }
+313 
+314 fn rgb-add-to _c1: (addr rgb), _c2: (addr rgb) {
+315   var c1/edi: (addr rgb) <- copy _c1
+316   var c2/esi: (addr rgb) <- copy _c2
+317   # c1.r += c2.r
+318   var arg1/eax: (addr float) <- get c1, r
+319   var arg2/ecx: (addr float) <- get c2, r
+320   var result/xmm0: float <- copy *arg1
+321   result <- add *arg2
+322   copy-to *arg1, result
+323   # c1.g += c2.g
+324   arg1 <- get c1, g
+325   arg2 <- get c2, g
+326   result <- copy *arg1
+327   result <- add *arg2
+328   copy-to *arg1, result
+329   # c1.b += c2.b
+330   arg1 <- get c1, b
+331   arg2 <- get c2, b
+332   result <- copy *arg1
+333   result <- add *arg2
+334   copy-to *arg1, result
+335 }
+336 
+337 fn rgb-scale-up _c1: (addr rgb), f: float {
+338   var c1/edi: (addr rgb) <- copy _c1
+339   # c1.r *= f
+340   var dest/eax: (addr float) <- get c1, r
+341   var result/xmm0: float <- copy *dest
+342   result <- multiply f
+343   copy-to *dest, result
+344   # c1.g *= f
+345   dest <- get c1, g
+346   result <- copy *dest
+347   result <- multiply f
+348   copy-to *dest, result
+349   # c1.b *= f
+350   dest <- get c1, b
+351   result <- copy *dest
+352   result <- multiply f
+353   copy-to *dest, result
+354 }
+355 
+356 type vec3 {
+357   x: float
+358   y: float
+359   z: float
+360 }
+361 
+362 fn print-vec3 screen: (addr screen), _v: (addr vec3) {
+363   var v/esi: (addr vec3) <- copy _v
+364   print-string screen, "("
+365   var tmp/eax: (addr float) <- get v, x
+366   print-float-hex screen, *tmp
+367   print-string screen, ", "
+368   tmp <- get v, y
+369   print-float-hex screen, *tmp
+370   print-string screen, ", "
+371   tmp <- get v, z
+372   print-float-hex screen, *tmp
+373   print-string screen, ")"
+374 }
+375 
+376 fn vec3-add-to _v1: (addr vec3), _v2: (addr vec3) {
+377   var v1/edi: (addr vec3) <- copy _v1
+378   var v2/esi: (addr vec3) <- copy _v2
+379   # v1.x += v2.x
+380   var arg1/eax: (addr float) <- get v1, x
+381   var arg2/ecx: (addr float) <- get v2, x
+382   var result/xmm0: float <- copy *arg1
+383   result <- add *arg2
+384   copy-to *arg1, result
+385   # v1.y += v2.y
+386   arg1 <- get v1, y
+387   arg2 <- get v2, y
+388   result <- copy *arg1
+389   result <- add *arg2
+390   copy-to *arg1, result
+391   # v1.z += v2.z
+392   arg1 <- get v1, z
+393   arg2 <- get v2, z
+394   result <- copy *arg1
+395   result <- add *arg2
+396   copy-to *arg1, result
+397 }
+398 
+399 fn vec3-subtract-from v1: (addr vec3), v2: (addr vec3) {
+400   var tmp-storage: vec3
+401   var tmp/eax: (addr vec3) <- address tmp-storage
+402   copy-object v2, tmp
+403   vec3-negate tmp
+404   vec3-add-to v1, tmp
+405 }
+406 
+407 fn vec3-negate v: (addr vec3) {
+408   var negative-one/eax: int <- copy -1
+409   var negative-one-f/xmm0: float <- convert negative-one
+410   vec3-scale-up v, negative-one-f
+411 }
+412 
+413 fn vec3-scale-up _v: (addr vec3), f: float {
+414   var v/edi: (addr vec3) <- copy _v
+415   # v.x *= f
+416   var dest/eax: (addr float) <- get v, x
+417   var result/xmm0: float <- copy *dest
+418   result <- multiply f
+419   copy-to *dest, result
+420   # v.y *= f
+421   dest <- get v, y
+422   result <- copy *dest
+423   result <- multiply f
+424   copy-to *dest, result
+425   # v.z *= f
+426   dest <- get v, z
+427   result <- copy *dest
+428   result <- multiply f
+429   copy-to *dest, result
+430 }
+431 
+432 fn vec3-scale-down _v: (addr vec3), f: float {
+433   var v/edi: (addr vec3) <- copy _v
+434   # v.x /= f
+435   var dest/eax: (addr float) <- get v, x
+436   var result/xmm0: float <- copy *dest
+437   result <- divide f
+438   copy-to *dest, result
+439   # v.y /= f
+440   dest <- get v, y
+441   result <- copy *dest
+442   result <- divide f
+443   copy-to *dest, result
+444   # v.z /= f
+445   dest <- get v, z
+446   result <- copy *dest
+447   result <- divide f
+448   copy-to *dest, result
+449 }
+450 
+451 fn vec3-unit in: (addr vec3), out: (addr vec3) {
+452   var len/xmm0: float <- vec3-length in
+453 #?   print-string 0, "len: "
+454 #?   print-float-hex 0, len
+455 #?   print-string 0, "\n"
+456   copy-object in, out
+457   vec3-scale-down out, len
+458 }
+459 
+460 fn vec3-length v: (addr vec3) -> _/xmm0: float {
+461   var result/xmm0: float <- vec3-length-squared v
+462   result <- square-root result
+463   return result
+464 }
+465 
+466 fn vec3-length-squared _v: (addr vec3) -> _/xmm0: float {
+467   var v/esi: (addr vec3) <- copy _v
+468   # result = v.x * v.x
+469   var src/eax: (addr float) <- get v, x
+470   var tmp/xmm1: float <- copy *src
+471   tmp <- multiply tmp
+472   var result/xmm0: float <- copy tmp
+473   # result += v.y * v.y
+474   src <- get v, y
+475   tmp <- copy *src
+476   tmp <- multiply tmp
+477   result <- add tmp
+478   # result += v.z * v.z
+479   src <- get v, z
+480   tmp <- copy *src
+481   tmp <- multiply tmp
+482   result <- add tmp
+483   return result
+484 }
+
+ + + diff --git a/html/linux/apps/raytracing/color.mu.html b/html/linux/apps/raytracing/color.mu.html new file mode 100644 index 00000000..dc60a456 --- /dev/null +++ b/html/linux/apps/raytracing/color.mu.html @@ -0,0 +1,100 @@ + + + + +Mu - linux/apps/raytracing/color.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/raytracing/color.mu +
+ 1 type rgb {
+ 2   # components normalized to within [0.0, 1.0]
+ 3   r: float
+ 4   g: float
+ 5   b: float
+ 6 }
+ 7 
+ 8 # print translating to [0, 256)
+ 9 fn print-rgb screen: (addr screen), _c: (addr rgb) {
+10   var c/esi: (addr rgb) <- copy _c
+11   var xn: float
+12   var xn-addr/ecx: (addr float) <- address xn
+13   fill-in-rational xn-addr, 0x3e7ff, 0x3e8  # 255999 / 1000
+14   # print 255.999 * c->r
+15   var result/xmm0: float <- copy xn
+16   var src-addr/eax: (addr float) <- get c, r
+17   result <- multiply *src-addr
+18   var result-int/edx: int <- truncate result
+19   print-int32-decimal screen, result-int
+20   print-string screen, " "
+21   # print 255.999 * c->g
+22   src-addr <- get c, g
+23   result <- copy xn
+24   result <- multiply *src-addr
+25   result-int <- truncate result
+26   print-int32-decimal screen, result-int
+27   print-string screen, " "
+28   # print 255.999 * c->b
+29   src-addr <- get c, b
+30   result <- copy xn
+31   result <- multiply *src-addr
+32   result-int <- truncate result
+33   print-int32-decimal screen, result-int
+34   print-string screen, "\n"
+35 }
+
+ + + diff --git a/html/linux/apps/raytracing/ray.mu.html b/html/linux/apps/raytracing/ray.mu.html new file mode 100644 index 00000000..5400c1f2 --- /dev/null +++ b/html/linux/apps/raytracing/ray.mu.html @@ -0,0 +1,86 @@ + + + + +Mu - linux/apps/raytracing/ray.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/raytracing/ray.mu +
+ 1 type ray {
+ 2   orig: vec3  # point
+ 3   dir: vec3
+ 4 }
+ 5 
+ 6 # A little different from the constructor at https://raytracing.github.io/books/RayTracingInOneWeekend.html
+ 7 # We immediately normalize the direction vector so we don't have to keep doing
+ 8 # so.
+ 9 fn initialize-ray _self: (addr ray), o: (addr vec3), d: (addr vec3) {
+10   var self/esi: (addr ray) <- copy _self
+11   var dest/eax: (addr vec3) <- get self, orig
+12   copy-object o, dest
+13   dest <- get self, dir
+14   vec3-unit d, dest
+15 }
+16 
+17 fn ray-at _self: (addr ray), t: float, out: (addr vec3) {
+18   var self/esi: (addr ray) <- copy _self
+19   var src/eax: (addr vec3) <- get self, dir
+20   copy-object src, out
+21   vec3-scale-up out, t
+22   src <- get self, orig
+23   vec3-add-to out, src
+24 }
+
+ + + diff --git a/html/linux/apps/raytracing/vec.mu.html b/html/linux/apps/raytracing/vec.mu.html new file mode 100644 index 00000000..9fe5b990 --- /dev/null +++ b/html/linux/apps/raytracing/vec.mu.html @@ -0,0 +1,201 @@ + + + + +Mu - linux/apps/raytracing/vec.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/raytracing/vec.mu +
+  1 type vec3 {
+  2   x: float
+  3   y: float
+  4   z: float
+  5 }
+  6 
+  7 fn print-vec3 screen: (addr screen), _v: (addr vec3) {
+  8   var v/esi: (addr vec3) <- copy _v
+  9   print-string screen, "("
+ 10   var tmp/eax: (addr float) <- get v, x
+ 11   print-float-hex screen, *tmp
+ 12   print-string screen, ", "
+ 13   tmp <- get v, y
+ 14   print-float-hex screen, *tmp
+ 15   print-string screen, ", "
+ 16   tmp <- get v, z
+ 17   print-float-hex screen, *tmp
+ 18   print-string screen, ")"
+ 19 }
+ 20 
+ 21 fn vec3-add-to _v1: (addr vec3), _v2: (addr vec3) {
+ 22   var v1/edi: (addr vec3) <- copy _v1
+ 23   var v2/esi: (addr vec3) <- copy _v2
+ 24   # v1.x += v2.x
+ 25   var arg1/eax: (addr float) <- get v1, x
+ 26   var arg2/ecx: (addr float) <- get v2, x
+ 27   var result/xmm0: float <- copy *arg1
+ 28   result <- add *arg2
+ 29   copy-to *arg1, result
+ 30   # v1.y += v2.y
+ 31   arg1 <- get v1, y
+ 32   arg2 <- get v2, y
+ 33   result <- copy *arg1
+ 34   result <- add *arg2
+ 35   copy-to *arg1, result
+ 36   # v1.z += v2.z
+ 37   arg1 <- get v1, z
+ 38   arg2 <- get v2, z
+ 39   result <- copy *arg1
+ 40   result <- add *arg2
+ 41   copy-to *arg1, result
+ 42 }
+ 43 
+ 44 fn vec3-subtract-from v1: (addr vec3), v2: (addr vec3) {
+ 45   var tmp-storage: vec3
+ 46   var tmp/eax: (addr vec3) <- address tmp-storage
+ 47   copy-object v2, tmp
+ 48   vec3-negate tmp
+ 49   vec3-add-to v1, tmp
+ 50 }
+ 51 
+ 52 fn vec3-negate v: (addr vec3) {
+ 53   var negative-one/eax: int <- copy -1
+ 54   var negative-one-f/xmm0: float <- convert negative-one
+ 55   vec3-scale-up v, negative-one-f
+ 56 }
+ 57 
+ 58 fn vec3-scale-up _v: (addr vec3), f: float {
+ 59   var v/edi: (addr vec3) <- copy _v
+ 60   # v.x *= f
+ 61   var dest/eax: (addr float) <- get v, x
+ 62   var result/xmm0: float <- copy *dest
+ 63   result <- multiply f
+ 64   copy-to *dest, result
+ 65   # v.y *= f
+ 66   dest <- get v, y
+ 67   result <- copy *dest
+ 68   result <- multiply f
+ 69   copy-to *dest, result
+ 70   # v.z *= f
+ 71   dest <- get v, z
+ 72   result <- copy *dest
+ 73   result <- multiply f
+ 74   copy-to *dest, result
+ 75 }
+ 76 
+ 77 fn vec3-scale-down _v: (addr vec3), f: float {
+ 78   var v/edi: (addr vec3) <- copy _v
+ 79   # v.x /= f
+ 80   var dest/eax: (addr float) <- get v, x
+ 81   var result/xmm0: float <- copy *dest
+ 82   result <- divide f
+ 83   copy-to *dest, result
+ 84   # v.y /= f
+ 85   dest <- get v, y
+ 86   result <- copy *dest
+ 87   result <- divide f
+ 88   copy-to *dest, result
+ 89   # v.z /= f
+ 90   dest <- get v, z
+ 91   result <- copy *dest
+ 92   result <- divide f
+ 93   copy-to *dest, result
+ 94 }
+ 95 
+ 96 fn vec3-unit in: (addr vec3), out: (addr vec3) {
+ 97   var len/xmm0: float <- vec3-length in
+ 98 #?   print-string 0, "len: "
+ 99 #?   print-float-hex 0, len
+100 #?   print-string 0, "\n"
+101   copy-object in, out
+102   vec3-scale-down out, len
+103 }
+104 
+105 fn vec3-length v: (addr vec3) -> _/xmm0: float {
+106   var result/xmm0: float <- vec3-length-squared v
+107   result <- square-root result
+108   return result
+109 }
+110 
+111 fn vec3-length-squared _v: (addr vec3) -> _/xmm0: float {
+112   var v/esi: (addr vec3) <- copy _v
+113   # result = v.x * v.x
+114   var src/eax: (addr float) <- get v, x
+115   var tmp/xmm1: float <- copy *src
+116   tmp <- multiply tmp
+117   var result/xmm0: float <- copy tmp
+118   # result += v.y * v.y
+119   src <- get v, y
+120   tmp <- copy *src
+121   tmp <- multiply tmp
+122   result <- add tmp
+123   # result += v.z * v.z
+124   src <- get v, z
+125   tmp <- copy *src
+126   tmp <- multiply tmp
+127   result <- add tmp
+128   return result
+129 }
+130 
+131 fn vec3-dot _v1: (addr vec3), _v2: (addr vec3) -> _/xmm0: float {
+132 }
+133 
+134 fn vec3-cross _v1: (addr vec3), _v2: (addr vec3), out: (addr vec3) {
+135 }
+
+ + + diff --git a/html/linux/apps/rpn.mu.html b/html/linux/apps/rpn.mu.html new file mode 100644 index 00000000..b5aba508 --- /dev/null +++ b/html/linux/apps/rpn.mu.html @@ -0,0 +1,215 @@ + + + + +Mu - linux/apps/rpn.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/rpn.mu +
+  1 # Integer arithmetic using postfix notation
+  2 #
+  3 # Limitations:
+  4 #   No division yet.
+  5 #
+  6 # To build:
+  7 #   $ ./translate apps/rpn.mu
+  8 #
+  9 # Example session:
+ 10 #   $ ./a.elf
+ 11 #   press ctrl-c or ctrl-d to exit
+ 12 #   > 1
+ 13 #   1
+ 14 #   > 1 1 +
+ 15 #   2
+ 16 #   > 1 2 3 + +
+ 17 #   6
+ 18 #   > 1 2 3 * +
+ 19 #   7
+ 20 #   > 1 2 + 3 *
+ 21 #   9
+ 22 #   > 1 3 4 * +
+ 23 #   13
+ 24 #   > ^D
+ 25 #   $
+ 26 #
+ 27 # Error handling is non-existent. This is just a prototype.
+ 28 
+ 29 fn main -> _/ebx: int {
+ 30   var in-storage: (stream byte 0x100)
+ 31   var in/esi: (addr stream byte) <- address in-storage
+ 32   print-string 0/screen, "press ctrl-c or ctrl-d to exit\n"
+ 33   # read-eval-print loop
+ 34   {
+ 35     # print prompt
+ 36     print-string 0/screen, "> "
+ 37     # read line
+ 38     clear-stream in
+ 39     read-line-from-real-keyboard in
+ 40     var done?/eax: boolean <- stream-empty? in
+ 41     compare done?, 0
+ 42     break-if-!=
+ 43     # parse and eval
+ 44     var out/eax: int <- simplify in
+ 45     # print
+ 46     print-int32-decimal 0/screen, out
+ 47     print-string 0/screen, "\n"
+ 48     #
+ 49     loop
+ 50   }
+ 51   return 0
+ 52 }
+ 53 
+ 54 type int-stack {
+ 55   data: (handle array int)
+ 56   top: int
+ 57 }
+ 58 
+ 59 fn simplify in: (addr stream byte) -> _/eax: int {
+ 60   var word-storage: slice
+ 61   var word/ecx: (addr slice) <- address word-storage
+ 62   var stack-storage: int-stack
+ 63   var stack/esi: (addr int-stack) <- address stack-storage
+ 64   initialize-int-stack stack, 0x10
+ 65   $simplify:word-loop: {
+ 66     next-word in, word
+ 67     var done?/eax: boolean <- slice-empty? word
+ 68     compare done?, 0
+ 69     break-if-!=
+ 70     # if word is an operator, perform it
+ 71     {
+ 72       var add?/eax: boolean <- slice-equal? word, "+"
+ 73       compare add?, 0
+ 74       break-if-=
+ 75       var _b/eax: int <- pop-int-stack stack
+ 76       var b/edx: int <- copy _b
+ 77       var a/eax: int <- pop-int-stack stack
+ 78       a <- add b
+ 79       push-int-stack stack, a
+ 80       loop $simplify:word-loop
+ 81     }
+ 82     {
+ 83       var sub?/eax: boolean <- slice-equal? word, "-"
+ 84       compare sub?, 0
+ 85       break-if-=
+ 86       var _b/eax: int <- pop-int-stack stack
+ 87       var b/edx: int <- copy _b
+ 88       var a/eax: int <- pop-int-stack stack
+ 89       a <- subtract b
+ 90       push-int-stack stack, a
+ 91       loop $simplify:word-loop
+ 92     }
+ 93     {
+ 94       var mul?/eax: boolean <- slice-equal? word, "*"
+ 95       compare mul?, 0
+ 96       break-if-=
+ 97       var _b/eax: int <- pop-int-stack stack
+ 98       var b/edx: int <- copy _b
+ 99       var a/eax: int <- pop-int-stack stack
+100       a <- multiply b
+101       push-int-stack stack, a
+102       loop $simplify:word-loop
+103     }
+104     # otherwise it's an int
+105     var n/eax: int <- parse-decimal-int-from-slice word
+106     push-int-stack stack, n
+107     loop
+108   }
+109   var result/eax: int <- pop-int-stack stack
+110   return result
+111 }
+112 
+113 fn initialize-int-stack _self: (addr int-stack), n: int {
+114   var self/esi: (addr int-stack) <- copy _self
+115   var d/edi: (addr handle array int) <- get self, data
+116   populate d, n
+117   var top/eax: (addr int) <- get self, top
+118   copy-to *top, 0
+119 }
+120 
+121 fn push-int-stack _self: (addr int-stack), _val: int {
+122   var self/esi: (addr int-stack) <- copy _self
+123   var top-addr/ecx: (addr int) <- get self, top
+124   var data-ah/edx: (addr handle array int) <- get self, data
+125   var data/eax: (addr array int) <- lookup *data-ah
+126   var top/edx: int <- copy *top-addr
+127   var dest-addr/edx: (addr int) <- index data, top
+128   var val/eax: int <- copy _val
+129   copy-to *dest-addr, val
+130   add-to *top-addr, 1
+131 }
+132 
+133 fn pop-int-stack _self: (addr int-stack) -> _/eax: int {
+134   var self/esi: (addr int-stack) <- copy _self
+135   var top-addr/ecx: (addr int) <- get self, top
+136   {
+137     compare *top-addr, 0
+138     break-if->
+139     return 0
+140   }
+141   subtract-from *top-addr, 1
+142   var data-ah/edx: (addr handle array int) <- get self, data
+143   var data/eax: (addr array int) <- lookup *data-ah
+144   var top/edx: int <- copy *top-addr
+145   var result-addr/eax: (addr int) <- index data, top
+146   var val/eax: int <- copy *result-addr
+147   return val
+148 }
+
+ + + diff --git a/html/linux/apps/texture.mu.html b/html/linux/apps/texture.mu.html new file mode 100644 index 00000000..c3f44607 --- /dev/null +++ b/html/linux/apps/texture.mu.html @@ -0,0 +1,126 @@ + + + + +Mu - linux/apps/texture.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/texture.mu +
+ 1 # Playing with emitting cool textures.
+ 2 #
+ 3 # To run (on Linux):
+ 4 #   $ git clone https://github.com/akkartik/mu
+ 5 #   $ cd mu
+ 6 #   $ ./translate apps/texture.mu
+ 7 #   $ ./a.elf > a.ppm
+ 8 
+ 9 fn main -> _/ebx: int {
+10 #?   var width/esi: int <- copy 0x190  # 400
+11 #?   var height/edi: int <- copy 0xe1  # 225; aspect ratio 16:9
+12   var width/esi: int <- copy 0xff
+13   var height/edi: int <- copy 0xff
+14   print-string 0/screen, "P3\n"
+15   print-int32-decimal 0/screen, width
+16   print-string 0/screen, " "
+17   print-int32-decimal 0/screen, height
+18   print-string 0/screen, "\n"
+19   print-string 0/screen, "255\n"  # color depth
+20   var row/ecx: int <- copy 0
+21   {
+22     compare row, height
+23     break-if->=
+24     var col/edx: int <- copy 0
+25     {
+26       compare col, width
+27       break-if->=
+28       # r
+29       var tmp/eax: int <- copy col
+30       tmp <- multiply row
+31       tmp <- and 0x7f
+32       tmp <- add 0x80
+33       tmp <- copy 0xff
+34       print-int32-decimal 0/screen, tmp
+35       print-string 0/screen, " "
+36       # g
+37       tmp <- copy row
+38       tmp <- multiply col
+39       tmp <- and 0x7f
+40       tmp <- add 0x80
+41 #?       tmp <- copy 0xcf
+42       print-int32-decimal 0/screen, tmp
+43       print-string 0/screen, " "
+44       # b
+45       tmp <- copy row
+46       tmp <- multiply col
+47       tmp <- and 0x7f
+48       tmp <- add 0x80
+49       print-int32-decimal 0/screen, tmp
+50       print-string 0/screen, "\n"
+51       col <- increment
+52       loop
+53     }
+54     row <- increment
+55     loop
+56   }
+57   return 0
+58 }
+
+ + + diff --git a/html/linux/apps/tui.mu.html b/html/linux/apps/tui.mu.html new file mode 100644 index 00000000..82681e6a --- /dev/null +++ b/html/linux/apps/tui.mu.html @@ -0,0 +1,98 @@ + + + + +Mu - linux/apps/tui.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/apps/tui.mu +
+ 1 # Test some primitives for text-mode.
+ 2 #
+ 3 # To run:
+ 4 #   $ ./translate apps/tui.mu
+ 5 #   $ ./a.elf
+ 6 
+ 7 fn main -> _/ebx: int {
+ 8   var nrows/eax: int <- copy 0
+ 9   var ncols/ecx: int <- copy 0
+10   nrows, ncols <- screen-size 0
+11   enable-screen-grid-mode
+12   move-cursor 0/screen, 5/row, 0x22/col
+13   start-color 0/screen, 1/fg, 0x7a/bg
+14   start-blinking 0/screen
+15   print-string 0/screen, "Hello world!"
+16   reset-formatting 0/screen
+17   move-cursor 0/screen, 6/row, 0x22/col
+18   print-string 0/screen, "tty dimensions: "
+19   print-int32-hex 0/screen, nrows
+20   print-string 0/screen, " rows, "
+21   print-int32-hex 0/screen, ncols
+22   print-string 0/screen, " rows\n"
+23 
+24   print-string 0/screen, "press a key to see its code: "
+25   enable-keyboard-immediate-mode
+26   var x/eax: grapheme <- read-key-from-real-keyboard
+27   enable-keyboard-type-mode
+28   enable-screen-type-mode
+29   print-string 0/screen, "You pressed "
+30   var x-int/eax: int <- copy x
+31   print-int32-hex 0/screen, x-int
+32   print-string 0/screen, "\n"
+33   return 0
+34 }
+
+ + + -- cgit 1.4.1-2-gfad0