https://github.com/akkartik/mu/blob/main/linux/assort.subx

       1 # Read a series of segments from stdin and concatenate segments with the same
       2 # name on stdout.
       3 #
       4 # Segments are emitted in order of first encounter.
       5 #
       6 # Drop lines that are all comments. They could get misleading after assortment
       7 # because we don't know if they refer to the line above or the line below.
       8 #
       9 # To run:
      10 #   $ bootstrap/bootstrap translate [01]*.subx subx-params.subx assort.subx  -o assort
      11 #   $ cat x
      12 #   == code
      13 #   abc
      14 #   == code
      15 #   def
      16 #   $ cat x  |bootstrap/bootstrap run assort
      17 #   == code
      18 #   abc
      19 #   def
      20
      21 == code
      22 #   instruction                     effective address                                                   register    displacement    immediate
      23 # . op          subop               mod             rm32          base        index         scale       r32
      24 # . 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
      25
      26 Entry:  # run tests if necessary, convert stdin if not
      27     # . prologue
      28     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
      29
      30     # initialize heap
      31     # . Heap = new-segment(Heap-size)
      32     # . . push args
      33     68/push  Heap/imm32
      34     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Heap-size/disp32                  # push *Heap-size
      35     # . . call
      36     e8/call  new-segment/disp32
      37     # . . discard args
      38     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
      39
      40     # - if argc > 1 and argv[1] == "test", then return run_tests()
      41     # if (argc <= 1) goto interactive
      42     81          7/subop/compare     1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0/disp8         1/imm32           # compare *ebp
      43     7e/jump-if-<=  $subx-assort-main:interactive/disp8
      44     # if (!kernel-string-equal?(argv[1], "test")) goto interactive
      45     # . eax = kernel-string-equal?(argv[1], "test")
      46     # . . push args
      47     68/push  "test"/imm32
      48     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
      49     # . . call
      50     e8/call  kernel-string-equal?/disp32
      51     # . . discard args
      52     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
      53     # . if (eax == false) goto interactive
      54     3d/compare-eax-and  0/imm32/false
      55     74/jump-if-=  $subx-assort-main:interactive/disp8
      56     # run-tests()
      57     e8/call  run-tests/disp32
      58     # syscall(exit, *Num-test-failures)
      59     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/ebx   Num-test-failures/disp32          # copy *Num-test-failures to ebx
      60     eb/jump  $subx-assort-main:end/disp8
      61 $subx-assort-main:interactive:
      62     # - otherwise convert stdin
      63     # var ed/eax: exit-descriptor
      64     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # subtract from esp
      65     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           4/r32/esp   .               .                 # copy esp to eax
      66     # configure ed to really exit()
      67     # . ed->target = 0
      68     c7          0/subop/copy        0/mod/direct    0/rm32/eax    .           .             .           .           .               0/imm32           # copy to *eax
      69     # subx-assort(Stdin, Stdout, Stderr, ed)
      70     # . . push args
      71     50/push-eax/ed
      72     68/push  Stderr/imm32
      73     68/push  Stdout/imm32
      74     68/push  Stdin/imm32
      75     # . . call
      76     e8/call  subx-assort/disp32
      77     # . . discard args
      78     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
      79     # syscall(exit, 0)
      80     bb/copy-to-ebx  0/imm32
      81 $subx-assort-main:end:
      82     e8/call  syscall_exit/disp32
      83
      84 # data structure:
      85 #   table: (addr stream {(handle array byte), (handle stream byte)})     (16 bytes/row)
      86 # inefficient; uses sequential search for looking up segments by name
      87
      88 subx-assort:  # in: (addr buffered-file), out: (addr buffered-file)
      89     # pseudocode:
      90     #   var table: (addr stream {(handle array byte), (handle stream byte)} 10 rows)
      91     #   read-segments(in, table)
      92     #   write-segments(out, table)
      93     #
      94     # . prologue
      95     55/push-ebp
      96     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
      97     # . save registers
      98     51/push-ecx
      99     # var table/ecx: (stream {string, (handle stream byte)} 160)  # 10 rows * 16 bytes/row
     100     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0xa0/imm32        # subtract from esp
     101     68/push  0xa0/imm32/length
     102     68/push  0/imm32/read
     103     68/push  0/imm32/write
     104     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
     105     # clear-stream(table)
     106     # . . push args
     107     51/push-ecx
     108     # . . call
     109     e8/call  clear-stream/disp32
     110     # . . discard args
     111     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
     112 $subx-assort:read:
     113 +--  9 lines: #?     # print("read\n") -------------------------------------------------------------------------------------------------------------------------------------
     122     # read-segments(in, table)
     123     # . . push args
     124     51/push-ecx
     125     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
     126     # . . call
     127     e8/call  read-segments/disp32
     128     # . . discard args
     129     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     130 $subx-assort:write:
     131 +--  9 lines: #?     # print("write\n") ------------------------------------------------------------------------------------------------------------------------------------
     140     # write-segments(out, table)
     141     # . . push args
     142     51/push-ecx
     143     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
     144     # . . call
     145     e8/call  write-segments/disp32
     146     # . . discard args
     147     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     148 $subx-assort:end:
     149     # . reclaim locals
     150     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xac/imm32        # add to esp
     151     # . restore registers
     152     59/pop-to-ecx
     153     # . epilogue
     154     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
     155     5d/pop-to-ebp
     156     c3/return
     157
     158 test-subx-assort:
     159     # . prologue
     160     55/push-ebp
     161     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
     162     # setup
     163     # . clear-stream(_test-input-stream)
     164     # . . push args
     165     68/push  _test-input-stream/imm32
     166     # . . call
     167     e8/call  clear-stream/disp32
     168     # . . discard args
     169     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
     170     # . clear-stream($_test-input-buffered-file->buffer)
     171     # . . push args
     172     68/push  $_test-input-buffered-file->buffer/imm32
     173     # . . call
     174     e8/call  clear-stream/disp32
     175     # . . discard args
     176     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
     177     # . clear-stream(_test-output-stream)
     178     # . . push args
     179     68/push  _test-output-stream/imm32
     180     # . . call
     181     e8/call  clear-stream/disp32
     182     # . . discard args
     183     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
     184     # . clear-stream($_test-output-buffered-file->buffer)
     185     # . . push args
     186     68/push  $_test-output-buffered-file->buffer/imm32
     187     # . . call
     188     e8/call  clear-stream/disp32
     189     # . . discard args
     190     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
     191     # initialize input (meta comments in parens)
     192     #   # comment 1
     193     #     # comment 2 indented
     194     #   == code 0x09000000  (new segment)
     195     #   # comment 3 inside a segment
     196     #   1
     197     #                         (empty line)
     198     #   2 3 # comment 4 inline with other contents
     199     #   == data 0x0a000000  (new segment)
     200     #   4 5/imm32
     201     #   == code  (existing segment but non-contiguous with previous iteration)
     202     #   6 7
     203     #   8 9  (multiple lines)
     204     #   == code  (existing segment contiguous with previous iteration)
     205     #   10 11
     206     # . write(_test-input-stream, "# comment 1\n")
     207     # . . push args
     208     68/push  "# comment 1\n"/imm32
     209     68/push  _test-input-stream/imm32
     210     # . . call
     211     e8/call  write/disp32
     212     # . . discard args
     213     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     214     # . write(_test-input-stream, "  # comment 2 indented\n")
     215     # . . push args
     216     68/push  "  # comment 2 indented\n"/imm32
     217     68/push  _test-input-stream/imm32
     218     # . . call
     219     e8/call  write/disp32
     220     # . . discard args
     221     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     222     # . write(_test-input-stream, "== code 0x09000000\n")
     223     # . . push args
     224     68/push  "== code 0x09000000\n"/imm32
     225     68/push  _test-input-stream/imm32
     226     # . . call
     227     e8/call  write/disp32
     228     # . . discard args
     229     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     230     # . write(_test-input-stream, "# comment 3 inside a segment\n")
     231     # . . push args
     232     68/push  "# comment 3 inside a segment\n"/imm32
     233     68/push  _test-input-stream/imm32
     234     # . . call
     235     e8/call  write/disp32
     236     # . . discard args
     237     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     238     # . write(_test-input-stream, "1\n")
     239     # . . push args
     240     68/push  "1\n"/imm32
     241     68/push  _test-input-stream/imm32
     242     # . . call
     243     e8/call  write/disp32
     244     # . . discard args
     245     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     246     # . write(_test-input-stream, "\n")  # empty line
     247     # . . push args
     248     68/push  Newline/imm32
     249     68/push  _test-input-stream/imm32
     250     # . . call
     251     e8/call  write/disp32
     252     # . . discard args
     253     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     254     # . write(_test-input-stream, "2 3 # comment 4 inline with other contents\n")
     255     # . . push args
     256     68/push  "2 3 # comment 4 inline with other contents\n"/imm32
     257     68/push  _test-input-stream/imm32
     258     # . . call
     259     e8/call  write/disp32
     260     # . . discard args
     261     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     262     # . write(_test-input-stream, "== data 0x0a000000\n")
     263     # . . push args
     264     68/push  "== data 0x0a000000\n"/imm32
     265     68/push  _test-input-stream/imm32
     266     # . . call
     267     e8/call  write/disp32
     268     # . . discard args
     269     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     270     # . write(_test-input-stream, "4 5/imm32\n")
     271     # . . push args
     272     68/push  "4 5/imm32\n"/imm32
     273     68/push  _test-input-stream/imm32
     274     # . . call
     275     e8/call  write/disp32
     276     # . . discard args
     277     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     278     # . write(_test-input-stream, "== code\n")
     279     # . . push args
     280     68/push  "== code\n"/imm32
     281     68/push  _test-input-stream/imm32
     282     # . . call
     283     e8/call  write/disp32
     284     # . . discard args
     285     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     286     # . write(_test-input-stream, "6 7\n")
     287     # . . push args
     288     68/push  "6 7\n"/imm32
     289     68/push  _test-input-stream/imm32
     290     # . . call
     291     e8/call  write/disp32
     292     # . . discard args
     293     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     294     # . write(_test-input-stream, "8 9\n")
     295     # . . push args
     296     68/push  "8 9\n"/imm32
     297     68/push  _test-input-stream/imm32
     298     # . . call
     299     e8/call  write/disp32
     300     # . . discard args
     301     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     302     # . write(_test-input-stream, "== code\n")
     303     # . . push args
     304     68/push  "== code\n"/imm32
     305     68/push  _test-input-stream/imm32
     306     # . . call
     307     e8/call  write/disp32
     308     # . . discard args
     309     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     310     # . write(_test-input-stream, "10 11\n")
     311     # . . push args
     312     68/push  "10 11\n"/imm32
     313     68/push  _test-input-stream/imm32
     314     # . . call
     315     e8/call  write/disp32
     316     # . . discard args
     317     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     318     # subx-assort(_test-input-buffered-file, _test-output-buffered-file)
     319     # . . push args
     320     68/push  _test-output-buffered-file/imm32
     321     68/push  _test-input-buffered-file/imm32
     322     # . . call
     323     e8/call  subx-assort/disp32
     324     # . . discard args
     325     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     326     # . flush(_test-output-buffered-file)
     327     # . . push args
     328     68/push  _test-output-buffered-file/imm32
     329     # . . call
     330     e8/call  flush/disp32
     331     # . . discard args
     332     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
     333     # check output
     334     #   == code 0x09000000
     335     #   1
     336     #   2 3 # comment 4 inline with other contents
     337     #   6 7
     338     #   8 9
     339     #   10 11
     340     #   == data 0x0a000000
     341     #   4 5/imm32
     342 +-- 33 lines: #?     # dump output -----------------------------------------------------------------------------------------------------------------------------------------
     375     # . check-next-stream-line-equal(_test-output-stream, "== code 0x09000000", msg)
     376     # . . push args
     377     68/push  "F - test-subx-assort/0"/imm32
     378     68/push  "== code 0x09000000"/imm32
     379     68/push  _test-output-stream/imm32
     380     # . . call
     381     e8/call  check-next-stream-line-equal/disp32
     382     # . . discard args
     383     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
     384     # . check-next-stream-line-equal(_test-output-stream, "1", msg)
     385     # . . push args
     386     68/push  "F - test-subx-assort/1"/imm32
     387     68/push  "1"/imm32
     388     68/push  _test-output-stream/imm32
     389     # . . call
     390     e8/call  check-next-stream-line-equal/disp32
     391     # . . discard args
     392     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
     393     # . check-next-stream-line-equal(_test-output-stream, "2 3 # comment 4 inline with other contents", msg)
     394     # . . push args
     395     68/push  "F - test-subx-assort/2"/imm32
     396     68/push  "2 3 # comment 4 inline with other contents"/imm32
     397     68/push  _test-output-stream/imm32
     398     # . . call
     399     e8/call  check-next-stream-line-equal/disp32
     400     # . . discard args
     401     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
     402     # . check-next-stream-line-equal(_test-output-stream, "6 7", msg)
     403     # . . push args
     404     68/push  "F - test-subx-assort/3"/imm32
     405     68/push  "6 7"/imm32
     406     68/push  _test-output-stream/imm32
     407     # . . call
     408     e8/call  check-next-stream-line-equal/disp32
     409     # . . discard args
     410     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
     411     # . check-next-stream-line-equal(_test-output-stream, "8 9", msg)
     412     # . . push args
     413     68/push  "F - test-subx-assort/4"/imm32
     414     68/push  "8 9"/imm32
     415     68/push  _test-output-stream/imm32
     416     # . . call
     417     e8/call  check-next-stream-line-equal/disp32
     418     # . . discard args
     419     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
     420     # . check-next-stream-line-equal(_test-output-stream, "10 11", msg)
     421     # . . push args
     422     68/push  "F - test-subx-assort/5"/imm32
     423     68/push  "10 11"/imm32
     424     68/push  _test-output-stream/imm32
     425     # . . call
     426     e8/call  check-next-stream-line-equal/disp32
     427     # . . discard args
     428     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
     429     # . check-next-stream-line-equal(_test-output-stream, "== data 0x0a000000", msg)
     430     # . . push args
     431     68/push  "F - test-subx-assort/6"/imm32
     432     68/push  "== data 0x0a000000"/imm32
     433     68/push  _test-output-stream/imm32
     434     # . . call
     435     e8/call  check-next-stream-line-equal/disp32
     436     # . . discard args
     437     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
     438     # . check-next-stream-line-equal(_test-output-stream, "4 5/imm32", msg)
     439     # . . push args
     440     68/push  "F - test-subx-assort/7"/imm32
     441     68/push  "4 5/imm32"/imm32
     442     68/push  _test-output-stream/imm32
     443     # . . call
     444     e8/call  check-next-stream-line-equal/disp32
     445     # . . discard args
     446     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
     447     # . epilogue
     448     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
     449     5d/pop-to-ebp
     450     c3/return
     451
     452 read-segments:  # in: (addr buffered-file), table: (addr stream {(handle array byte), (handle stream byte)})
     453     # pseudocode:
     454     #   var curr-segment: (addr stream byte) = 0
     455     #   var line: (stream byte 512)
     456     #   while true
     457     #     clear-stream(line)
     458     #     read-line-buffered(in, line)
     459     #     if (line->write == 0) break             # end of file
     460     #     var word-slice = next-word-or-string(line)
     461     #     if slice-empty?(word-slice)             # whitespace
     462     #       continue
     463     #     if slice-starts-with?(word-slice, "#")  # comment
     464     #       continue
     465     #     if slice-equal?(word-slice, "==")
     466     #       var segment-name = next-word-or-string(line)
     467     #       var segment-slot: (addr handle stream byte) = get-or-insert-slice(table, segment-name, row-size=16)
     468     #       if *segment-slot != 0
     469     #         curr-segment = lookup(*segment-slot)
     470     #         continue
     471     #       new-stream(Heap, Segment-size, 1, segment-slot)
     472     #       curr-segment = lookup(*segment-slot)
     473     #     rewind-stream(line)
     474     #     write-stream(curr-segment, line)  # abort if curr-segment overflows
     475     #
     476     # word-slice and segment-name are both slices with disjoint lifetimes, so
     477     # we'll use the same address for them.
     478     #
     479     # registers:
     480     #   line: ecx
     481     #   word-slice and segment-name: edx
     482     #   segment-name and curr-segment: ebx
     483     #   word-slice->start: esi
     484     #   temporary: eax
     485     #
     486     # . prologue
     487     55/push-ebp
     488     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
     489     # . save registers
     490     50/push-eax
     491     51/push-ecx
     492     52/push-edx
     493     53/push-ebx
     494     56/push-esi
     495     57/push-edi
     496     # var line/ecx: (stream byte 512)
     497     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x200/imm32       # subtract from esp
     498     68/push  0x200/imm32/length
     499     68/push  0/imm32/read
     500     68/push  0/imm32/write
     501     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
     502     # var word-slice/edx: slice
     503     68/push  0/imm32/end
     504     68/push  0/imm32/start
     505     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
     506 $read-segments:loop:
     507     # clear-stream(line)
     508     # . . push args
     509     51/push-ecx
     510     # . . call
     511     e8/call  clear-stream/disp32
     512     # . . discard args
     513     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
     514     # read-line-buffered(in, line)
     515     # . . push args
     516     51/push-ecx
     517     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
     518     # . . call
     519     e8/call  read-line-buffered/disp32
     520     # . . discard args
     521     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     522 $read-segments:check0:
     523     # if (line->write == 0) break
     524     81          7/subop/compare     0/mod/indirect  1/rm32/ecx    .           .             .           .           .               0/imm32           # compare *ecx
     525     0f 84/jump-if-=  $read-segments:break/disp32
     526 +-- 33 lines: #?     # dump line -------------------------------------------------------------------------------------------------------------------------------------------
     559     # next-word-or-string(line, word-slice)
     560     # . . push args
     561     52/push-edx
     562     51/push-ecx
     563     # . . call
     564     e8/call  next-word-or-string/disp32
     565     # . . discard args
     566     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     567 $read-segments:check1:
     568 +--  9 lines: #?     # print("check1\n") -----------------------------------------------------------------------------------------------------------------------------------
     577     # if (slice-empty?(word-slice)) continue
     578     # . eax = slice-empty?(word-slice)
     579     # . . push args
     580     52/push-edx
     581     # . . call
     582     e8/call  slice-empty?/disp32
     583     # . . discard args
     584     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
     585     # . if (eax != false) continue
     586     3d/compare-eax-and  0/imm32/false
     587     0f 85/jump-if-!=  $read-segments:loop/disp32
     588 $read-segments:check-for-comment:
     589 +--  9 lines: #?     # print("check for comment\n") ------------------------------------------------------------------------------------------------------------------------
     598     # if (slice-starts-with?(word-slice, "#")) continue
     599     # . var start/esi: (addr byte) = word-slice->start
     600     8b/copy                         0/mod/indirect  2/rm32/edx    .           .             .           6/r32/esi   .               .                 # copy *ecx to esi
     601     # . var c/eax: byte = *start
     602     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
     603     8a/copy-byte                    0/mod/indirect  6/rm32/esi    .           .             .           0/r32/AL    .               .                 # copy byte at *esi to AL
     604     # . if (c == '#') continue
     605     3d/compare-eax-and  0x23/imm32/hash
     606     0f 84/jump-if-=  $read-segments:loop/disp32
     607 $read-segments:check-for-segment-header:
     608 +--  9 lines: #?     # print("check for segment header\n") -----------------------------------------------------------------------------------------------------------------
     617 +-- 40 lines: #?     # dump word-slice -------------------------------------------------------------------------------------------------------------------------------------
     657     # if !slice-equal?(word-slice, "==") goto next check
     658     # . eax = slice-equal?(word-slice, "==")
     659     # . . push args
     660     68/push  "=="/imm32
     661     52/push-edx
     662     # . . call
     663     e8/call  slice-equal?/disp32
     664     # . . discard args
     665     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     666     # . if (eax == false) goto next check
     667     3d/compare-eax-and  0/imm32/false
     668     0f 84/jump-if-=  $read-segments:regular-line/disp32
     669     # segment-name = next-word-or-string(line)
     670     # . . push args
     671     52/push-edx
     672     51/push-ecx
     673     # . . call
     674     e8/call  next-word-or-string/disp32
     675     # . . discard args
     676     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     677 +-- 40 lines: #?     # dump segment name -----------------------------------------------------------------------------------------------------------------------------------
     717     # var segment-slot/edi: (addr handle stream byte) = get-or-insert-slice(table, segment-name, row-size=16, Heap)
     718     # . eax = get-or-insert-slice(table, segment-name, row-size=16, Heap)
     719     # . . push args
     720     68/push  Heap/imm32
     721     68/push  0x10/imm32/row-size
     722     52/push-edx
     723     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
     724     # . . call
     725     e8/call  get-or-insert-slice/disp32
     726     # . . discard args
     727     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
     728     # . edi = eax
     729     89/copy                         3/mod/direct    7/rm32/edi    .           .             .           0/r32/eax   .               .                 # copy eax to edi
     730 +-- 33 lines: #?     # print("slot: " segment-slot "\n") -------------------------------------------------------------------------------------------------------------------
     763     # if (*segment-slot != 0) update curr-segment and continue
     764     81          7/subop/compare     0/mod/indirect  7/rm32/edi    .           .             .           .           .               0/imm32           # compare edi
     765     0f 84/jump-if-=  $read-segments:create-segment/disp32
     766     # var curr-segment/ebx: (addr stream byte) = lookup(*segment-slot)
     767     # . eax = lookup(*segment-slot)
     768     # . . push args
     769     ff          6/subop/push        1/mod/*+disp8   7/rm32/edi    .           .             .           .           4/disp8         .                 # push *(edi+4)
     770     ff          6/subop/push        0/mod/indirect  7/rm32/edi    .           .             .           .           .               .                 # push *edi
     771     # . . call
     772     e8/call  lookup/disp32
     773     # . . discard args
     774     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     775     # . ebx = eax
     776     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to ebx
     777     # continue
     778     e9/jump  $read-segments:loop/disp32
     779 $read-segments:create-segment:
     780     # new-stream(Heap, Segment-size, 1, segment-slot)
     781     # . . push args
     782     57/push-edi
     783     68/push  1/imm32
     784     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Segment-size/disp32               # push *Segment-size
     785     68/push  Heap/imm32
     786     # . . call
     787     e8/call  new-stream/disp32
     788     # . . discard args
     789     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
     790     # var curr-segment/ebx: (addr stream byte) = lookup(*segment-slot)
     791     # . eax = lookup(*segment-slot)
     792     # . . push args
     793     ff          6/subop/push        1/mod/*+disp8   7/rm32/edi    .           .             .           .           4/disp8         .                 # push *(edi+4)
     794     ff          6/subop/push        0/mod/indirect  7/rm32/edi    .           .             .           .           .               .                 # push *edi
     795     # . . call
     796     e8/call  lookup/disp32
     797     # . . discard args
     798     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     799     # . ebx = eax
     800     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to ebx
     801     # fall through
     802 $read-segments:regular-line:
     803 +--  9 lines: #?     # print("regular line\n") -----------------------------------------------------------------------------------------------------------------------------
     812 +-- 33 lines: #?     # dump line -------------------------------------------------------------------------------------------------------------------------------------------
     845 +-- 33 lines: #?     # print("addr: " curr-segment->write "\n") ------------------------------------------------------------------------------------------------------------
     878 +-- 33 lines: #?     # print("write: " curr-segment->write "\n") -----------------------------------------------------------------------------------------------------------
     911 +-- 33 lines: #?     # print("size: " curr-segment->size "\n") -------------------------------------------------------------------------------------------------------------
     944     # rewind-stream(line)
     945     # . . push args
     946     51/push-ecx
     947     # . . call
     948     e8/call  rewind-stream/disp32
     949     # . . discard args
     950     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
     951 +--  9 lines: #?     # print("write stream\n") -----------------------------------------------------------------------------------------------------------------------------
     960     # write-stream(curr-segment, line)
     961     # . . push args
     962     51/push-ecx
     963     53/push-ebx
     964     # . . call
     965     e8/call  write-stream/disp32
     966     # . . discard args
     967     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     968     # loop
     969 +--  9 lines: #?     # print("loop\n") -------------------------------------------------------------------------------------------------------------------------------------
     978     e9/jump  $read-segments:loop/disp32
     979 $read-segments:break:
     980 $read-segments:end:
     981     # . reclaim locals
     982     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x214/imm32       # add to esp
     983     # . restore registers
     984     5f/pop-to-edi
     985     5e/pop-to-esi
     986     5b/pop-to-ebx
     987     5a/pop-to-edx
     988     59/pop-to-ecx
     989     58/pop-to-eax
     990     # . epilogue
     991     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
     992     5d/pop-to-ebp
     993     c3/return
     994
     995 write-segments:  # out: (addr buffered-file), table: (addr stream {(handle array byte), (handle stream byte)})
     996     # pseudocode:
     997     #   var curr = table->data
     998     #   var max = &table->data[table->write]
     999     #   while curr < max
    1000     #     var stream: (addr stream byte) = lookup(table[i].stream)
    1001     #     write-stream-data(out, stream)
    1002     #     curr += 16
    1003     #   flush(out)
    1004     #
    1005     # . prologue
    1006     55/push-ebp
    1007     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    1008     # . save registers
    1009     50/push-eax
    1010     52/push-edx
    1011     56/push-esi
    1012     # esi = table
    1013     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   0xc/disp8       .                 # copy *(ebp+12) to esi
    1014     # var write/edx: int = table->write
    1015     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           2/r32/edx   .               .                 # copy *esi to edx
    1016     # var curr/esi: (addr byte) = table->data
    1017     81          0/subop/add         3/mod/direct    6/rm32/esi    .           .             .           .           .               0xc/imm32         # add to eax
    1018     # var max/edx: (addr byte) = curr + write
    1019     01/add                          3/mod/direct    2/rm32/edx    .           .             .           6/r32/esi   .               .                 # add esi to edx
    1020 $write-segments:loop:
    1021     # if (curr >= max) break
    1022     39/compare                      3/mod/direct    6/rm32/esi    .           .             .           2/r32/edx   .               .                 # compare esi with edx
    1023     73/jump-if-addr>=  $write-segments:break/disp8
    1024     # var stream/eax: (addr stream byte) = lookup(table[i].stream)
    1025     # . . push args
    1026     ff          6/subop/push        1/mod/*+disp8   6/rm32/esi    .           .             .           .           0xc/disp8       .                 # push *(esi+12)
    1027     ff          6/subop/push        1/mod/*+disp8   6/rm32/esi    .           .             .           .           8/disp8         .                 # push *(esi+8)
    1028     # . . call
    1029     e8/call  lookup/disp32
    1030     # . . discard args
    1031     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    1032     # write-stream-data(out, stream)
    1033     # . . push args
    1034     50/push-eax
    1035     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    1036     # . . call
    1037     e8/call  write-stream-data/disp32
    1038     # . . discard args
    1039     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    1040 $write-segments:continue:
    1041     # curr += 16
    1042     81          0/subop/add         3/mod/direct    6/rm32/esi    .           .             .           .           .               0x10/imm32        # add to esi
    1043     eb/jump  $write-segments:loop/disp8
    1044 $write-segments:break:
    1045     # flush(out)
    1046     # . . push args
    1047     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    1048     # . . call
    1049     e8/call  flush/disp32
    1050     # . . discard args
    1051     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    1052 $write-segments:end:
    1053     # . restore registers
    1054     5e/pop-to-esi
    1055     5a/pop-to-edx
    1056     58/pop-to-eax
    1057     # . epilogue
    1058     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    1059     5d/pop-to-ebp
    1060     c3/return
    1061
    1062 # . . vim:nowrap:textwidth=0