about summary refs log tree commit diff stats
path: root/127next-word.subx
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2020-12-04 21:57:51 -0800
committerKartik Agaram <vc@akkartik.com>2020-12-04 23:02:53 -0800
commit18d5bab2b66406ee1e329ef099b375d98f0c2dd8 (patch)
tree00c29a0b83fc049a9362bd5cb1337926257329e1 /127next-word.subx
parent8a8db34f259f12b06f7b87e4f4c1b5530425ff29 (diff)
downloadmu-18d5bab2b66406ee1e329ef099b375d98f0c2dd8.tar.gz
7329 - snapshot: advent day 4 part 2
I've found two bugs in SubX libraries:

1. next-word had an out-of-bounds read
2. next-word was skipping comments, because that's what I need during bootstrapping.
I've created a new variant called next-raw-word that doesn't skip comments.
These really need better names.

We're now at the point where 4b.mu has the right structure and returns
identical result to 4a.mu.
Diffstat (limited to '127next-word.subx')
-rw-r--r--127next-word.subx64
1 files changed, 63 insertions, 1 deletions
diff --git a/127next-word.subx b/127next-word.subx
index 6705437f..5af326d4 100644
--- a/127next-word.subx
+++ b/127next-word.subx
@@ -5,7 +5,8 @@
 # . op          subop               mod             rm32          base        index         scale       r32
 # . 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
 
-# (re)compute the bounds of the next word in the line
+# (re)compute the bounds of the next word in the line (surrounded by whitespace,
+# treating '#' comments as a single word)
 # return empty string on reaching end of file
 next-word:  # line: (addr stream byte), out: (addr slice)
     # . prologue
@@ -56,6 +57,7 @@ $next-word:comment:
     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/esi  0/index/eax   .           0/r32/eax   0xc/disp8       .                 # copy esi+eax+12 to eax
     89/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           0/r32/eax   4/disp8         .                 # copy eax to *(edi+4)
     # . line->read = line->write
+    8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           0/r32/eax   .               .                 # copy *esi to eax
     89/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           0/r32/eax   4/disp8         .                 # copy eax to *(esi+4)
     # . return
     eb/jump  $next-word:end/disp8
@@ -298,3 +300,63 @@ test-next-word-returns-empty-string-on-newline:
     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
     5d/pop-to-ebp
     c3/return
+
+# (re)compute the bounds of the next word in the line (separated by whitespace)
+# return empty string on reaching end of file
+next-raw-word:  # line: (addr stream byte), out: (addr slice)
+    # . prologue
+    55/push-ebp
+    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+    # . save registers
+    50/push-eax
+    51/push-ecx
+    56/push-esi
+    57/push-edi
+    # esi = line
+    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
+    # edi = out
+    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   0xc/disp8       .                 # copy *(ebp+12) to edi
+    # skip-chars-matching-whitespace(line)
+    # . . push args
+    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+    # . . call
+    e8/call  skip-chars-matching-whitespace/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+$next-raw-word:check0:
+    # if (line->read >= line->write) clear out and return
+    # . eax = line->read
+    8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           0/r32/eax   4/disp8         .                 # copy *(esi+4) to eax
+    # . if (eax < line->write) goto next check
+    3b/compare                      0/mod/indirect  6/rm32/esi    .           .             .           0/r32/eax   .               .                 # compare eax with *esi
+    7c/jump-if-<  $next-raw-word:word-exists/disp8
+    # . return out
+    c7          0/subop/copy        0/mod/direct    7/rm32/edi    .           .             .           .           .               0/imm32           # copy to *edi
+    c7          0/subop/copy        1/mod/*+disp8   7/rm32/edi    .           .             .           .           4/disp8         0/imm32           # copy to *(edi+4)
+    eb/jump  $next-raw-word:end/disp8
+$next-raw-word:word-exists:
+    # out->start = &line->data[line->read]
+    8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(esi+4) to ecx
+    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx   .           0/r32/eax   0xc/disp8       .                 # copy esi+ecx+12 to eax
+    89/copy                         0/mod/indirect  7/rm32/edi    .           .             .           0/r32/eax   .               .                 # copy eax to *edi
+    # skip-chars-not-matching-whitespace(line)  # including trailing newline
+    # . . push args
+    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+    # . . call
+    e8/call  skip-chars-not-matching-whitespace/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+    # out->end = &line->data[line->read]
+    8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(esi+4) to ecx
+    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx   .           0/r32/eax   0xc/disp8       .                 # copy esi+ecx+12 to eax
+    89/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           0/r32/eax   4/disp8         .                 # copy eax to *(edi+4)
+$next-raw-word:end:
+    # . restore registers
+    5f/pop-to-edi
+    5e/pop-to-esi
+    59/pop-to-ecx
+    58/pop-to-eax
+    # . epilogue
+    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+    5d/pop-to-ebp
+    c3/return