https://github.com/akkartik/mu/blob/main/linux/128subx-words.subx

      1 # Helpers for parsing SubX words, with their rules for hex, labels and metadata.
      2
      3 == code
      4 #   instruction                     effective address                                                   register    displacement    immediate
      5 # . op          subop               mod             rm32          base        index         scale       r32
      6 # . 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
      7
      8 has-metadata?:  # word: (addr slice), s: (addr string) -> result/eax: boolean
      9     # pseudocode:
     10     #   var twig: &slice = next-token-from-slice(word->start, word->end, '/')  # skip name
     11     #   curr = twig->end
     12     #   while true
     13     #     twig = next-token-from-slice(curr, word->end, '/')
     14     #     if (twig.empty()) break
     15     #     if (slice-equal?(twig, s)) return true
     16     #     curr = twig->end
     17     #   return false
     18     # . prologue
     19     55/push-ebp
     20     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
     21     # . save registers
     22     51/push-ecx
     23     52/push-edx
     24     56/push-esi
     25     57/push-edi
     26     # esi = word
     27     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
     28     # var edx: (addr byte) = word->end
     29     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           2/r32/edx   4/disp8         .                 # copy *(esi+4) to edx
     30     # var twig/edi: slice
     31     68/push  0/imm32/end
     32     68/push  0/imm32/start
     33     89/copy                         3/mod/direct    7/rm32/edi    .           .             .           4/r32/esp   .               .                 # copy esp to edi
     34     # next-token-from-slice(word->start, word->end, '/', twig)
     35     # . . push args
     36     57/push-edi
     37     68/push  0x2f/imm32/slash
     38     52/push-edx
     39     ff          6/subop/push        0/mod/indirect  6/rm32/esi    .           .             .           .           .               .                 # push *esi
     40     # . . call
     41     e8/call  next-token-from-slice/disp32
     42     # . . discard args
     43     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
     44 $has-metadata?:loop:
     45     # next-token-from-slice(curr, word->end, '/', twig)
     46     # . . push args
     47     57/push-edi
     48     68/push  0x2f/imm32/slash
     49     52/push-edx
     50     ff          6/subop/push        1/mod/*+disp8   7/rm32/edi    .           .             .           .           4/disp8         .                 # push *(edi+4)
     51     # . . call
     52     e8/call  next-token-from-slice/disp32
     53     # . . discard args
     54     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
     55     # if (slice-empty?(twig)) return false
     56     # . eax = slice-empty?(twig)
     57     # . . push args
     58     57/push-edi
     59     # . . call
     60     e8/call  slice-empty?/disp32
     61     # . . discard args
     62     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
     63     # . if (eax != false) return false
     64     3d/compare-eax-and  0/imm32/false
     65     75/jump-if-!=  $has-metadata?:false/disp8
     66     # if (slice-equal?(twig, s)) return true
     67     # . eax = slice-equal?(twig, s)
     68     # . . push args
     69     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
     70     57/push-edi
     71     # . . call
     72     e8/call  slice-equal?/disp32
     73     # . . discard args
     74     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     75     # . if (eax != false) return true
     76     3d/compare-eax-and  0/imm32/false
     77     # eax already contains true
     78     75/jump-if-!=  $has-metadata?:end/disp8
     79     eb/jump  $has-metadata?:loop/disp8
     80 $has-metadata?:false:
     81     b8/copy-to-eax  0/imm32/false
     82 $has-metadata?:end:
     83     # . reclaim locals
     84     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     85     # . restore registers
     86     5f/pop-to-edi
     87     5e/pop-to-esi
     88     5a/pop-to-edx
     89     59/pop-to-ecx
     90     # . epilogue
     91     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
     92     5d/pop-to-ebp
     93     c3/return
     94
     95 test-has-metadata-true:
     96     # . prologue
     97     55/push-ebp
     98     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
     99     # (eax..ecx) = "ab/imm32"
    100     b8/copy-to-eax  "ab/imm32"/imm32
    101     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    102     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    103     05/add-to-eax  4/imm32
    104     # var in/esi: slice = {eax, ecx}
    105     51/push-ecx
    106     50/push-eax
    107     89/copy                         3/mod/direct    6/rm32/esi    .           .             .           4/r32/esp   .               .                 # copy esp to esi
    108     # eax = has-metadata?(esi, "imm32")
    109     # . . push args
    110     68/push  "imm32"/imm32
    111     56/push-esi
    112     # . . call
    113     e8/call  has-metadata?/disp32
    114     # . . discard args
    115     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    116     # check-ints-equal(eax, 1, msg)
    117     # . . push args
    118     68/push  "F - test-has-metadata-true"/imm32
    119     68/push  1/imm32/true
    120     50/push-eax
    121     # . . call
    122     e8/call  check-ints-equal/disp32
    123     # . . discard args
    124     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    125     # . epilogue
    126     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    127     5d/pop-to-ebp
    128     c3/return
    129
    130 test-has-metadata-false:
    131     # . prologue
    132     55/push-ebp
    133     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    134     # (eax..ecx) = "ab/c"
    135     b8/copy-to-eax  "ab/c"/imm32
    136     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    137     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    138     05/add-to-eax  4/imm32
    139     # var in/esi: slice = {eax, ecx}
    140     51/push-ecx
    141     50/push-eax
    142     89/copy                         3/mod/direct    6/rm32/esi    .           .             .           4/r32/esp   .               .                 # copy esp to esi
    143     # eax = has-metadata?(esi, "d")
    144     # . . push args
    145     68/push  "d"/imm32
    146     56/push-esi
    147     # . . call
    148     e8/call  has-metadata?/disp32
    149     # . . discard args
    150     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    151     # check-ints-equal(eax, 0, msg)
    152     # . . push args
    153     68/push  "F - test-has-metadata-false"/imm32
    154     68/push  0/imm32/false
    155     50/push-eax
    156     # . . call
    157     e8/call  check-ints-equal/disp32
    158     # . . discard args
    159     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    160     # . epilogue
    161     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    162     5d/pop-to-ebp
    163     c3/return
    164
    165 test-has-metadata-ignore-name:
    166     # . prologue
    167     55/push-ebp
    168     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    169     # (eax..ecx) = "a/b"
    170     b8/copy-to-eax  "a/b"/imm32
    171     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    172     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    173     05/add-to-eax  4/imm32
    174     # var in/esi: slice = {eax, ecx}
    175     51/push-ecx
    176     50/push-eax
    177     89/copy                         3/mod/direct    6/rm32/esi    .           .             .           4/r32/esp   .               .                 # copy esp to esi
    178     # eax = has-metadata?(esi, "a")
    179     # . . push args
    180     68/push  "a"/imm32
    181     56/push-esi
    182     # . . call
    183     e8/call  has-metadata?/disp32
    184     # . . discard args
    185     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    186     # check-ints-equal(eax, 0, msg)
    187     # . . push args
    188     68/push  "F - test-has-metadata-ignore-name"/imm32
    189     68/push  0/imm32/false
    190     50/push-eax
    191     # . . call
    192     e8/call  check-ints-equal/disp32
    193     # . . discard args
    194     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    195     # . epilogue
    196     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    197     5d/pop-to-ebp
    198     c3/return
    199
    200 test-has-metadata-multiple-true:
    201     # . prologue
    202     55/push-ebp
    203     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    204     # (eax..ecx) = "a/b/c"
    205     b8/copy-to-eax  "a/b/c"/imm32
    206     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    207     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    208     05/add-to-eax  4/imm32
    209     # var in/esi: slice = {eax, ecx}
    210     51/push-ecx
    211     50/push-eax
    212     89/copy                         3/mod/direct    6/rm32/esi    .           .             .           4/r32/esp   .               .                 # copy esp to esi
    213     # eax = has-metadata?(esi, "c")
    214     # . . push args
    215     68/push  "c"/imm32
    216     56/push-esi
    217     # . . call
    218     e8/call  has-metadata?/disp32
    219     # . . discard args
    220     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    221     # check-ints-equal(eax, 1, msg)
    222     # . . push args
    223     68/push  "F - test-has-metadata-multiple-true"/imm32
    224     68/push  1/imm32/true
    225     50/push-eax
    226     # . . call
    227     e8/call  check-ints-equal/disp32
    228     # . . discard args
    229     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    230     # . epilogue
    231     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    232     5d/pop-to-ebp
    233     c3/return
    234
    235 test-has-metadata-multiple-false:
    236     # . prologue
    237     55/push-ebp
    238     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    239     # (eax..ecx) = "a/b/c"
    240     b8/copy-to-eax  "a/b/c"/imm32
    241     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    242     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    243     05/add-to-eax  4/imm32
    244     # var in/esi: slice = {eax, ecx}
    245     51/push-ecx
    246     50/push-eax
    247     89/copy                         3/mod/direct    6/rm32/esi    .           .             .           4/r32/esp   .               .                 # copy esp to esi
    248     # eax = has-metadata?(esi, "d")
    249     # . . push args
    250     68/push  "d"/imm32
    251     56/push-esi
    252     # . . call
    253     e8/call  has-metadata?/disp32
    254     # . . discard args
    255     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    256     # check-ints-equal(eax, 0, msg)
    257     # . . push args
    258     68/push  "F - test-has-metadata-multiple-false"/imm32
    259     68/push  0/imm32/false
    260     50/push-eax
    261     # . . call
    262     e8/call  check-ints-equal/disp32
    263     # . . discard args
    264     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    265     # . epilogue
    266     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    267     5d/pop-to-ebp
    268     c3/return
    269
    270 # conditions for 'valid' names that are not at risk of looking like hex numbers
    271 # keep in sync with the rules in labels.cc
    272 #: - if it starts with a digit, it's treated as a number. If it can't be
    273 #:   parsed as hex it will raise an error.
    274 #: - if it starts with '-' it's treated as a number.
    275 #: - if it starts with '0x' it's treated as a number. (redundant)
    276 #: - if it's two characters long, it can't be a name. Either it's a hex
    277 #:   byte, or it raises an error.
    278 valid-name?:  # in: (addr slice) -> result/eax: boolean
    279     # . prologue
    280     55/push-ebp
    281     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    282     # . save registers
    283     51/push-ecx
    284     56/push-esi
    285     # esi = in
    286     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
    287     # var start/ecx: (addr byte) = in->start
    288     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # copy *esi to ecx
    289 $valid-name?:check0:
    290     # if (start >= in->end) return false
    291     3b/compare                      1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # compare ecx with *(esi+4)
    292     73/jump-if-addr>=  $valid-name?:false/disp8
    293 $valid-name?:check1:
    294     # var len/eax: int = in->end - start
    295     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           0/r32/eax   4/disp8         .                 # copy *(esi+4) to eax
    296     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
    297     # if (eax == 2) return false
    298     3d/compare-eax-and  2/imm32
    299     74/jump-if-=  $valid-name?:false/disp8
    300 $valid-name?:check2:
    301     # var c/eax: (addr byte) = *start
    302     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
    303     8a/copy-byte                    0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/AL    .               .                 # copy byte at *ecx to AL
    304     # if (c == "-") return false
    305     3d/compare-eax-and  2d/imm32/-
    306     74/jump-if-=  $valid-name?:false/disp8
    307 $valid-name?:check3a:
    308     # if (c < "0") return true
    309     3d/compare-eax-with  30/imm32/0
    310     7c/jump-if-<  $valid-name?:true/disp8
    311 $valid-name?:check3b:
    312     # if (c > "9") return true
    313     3d/compare-eax-with  39/imm32/9
    314     7f/jump-if->  $valid-name?:true/disp8
    315 $valid-name?:false:
    316     # return false
    317     b8/copy-to-eax  0/imm32/false
    318     eb/jump  $valid-name?:end/disp8
    319 $valid-name?:true:
    320     # return true
    321     b8/copy-to-eax  1/imm32/true
    322 $valid-name?:end:
    323     # . restore registers
    324     5e/pop-to-esi
    325     59/pop-to-ecx
    326     # . epilogue
    327     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    328     5d/pop-to-ebp
    329     c3/return
    330
    331 test-valid-name-digit-prefix:
    332     # . prologue
    333     55/push-ebp
    334     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    335     # (eax..ecx) = "34"
    336     b8/copy-to-eax  "34"/imm32
    337     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    338     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    339     05/add-to-eax  4/imm32
    340     # var slice/ecx: slice = {eax, ecx}
    341     51/push-ecx
    342     50/push-eax
    343     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    344     # eax = valid-name?(slice)
    345     # . . push args
    346     51/push-ecx
    347     # . . call
    348     e8/call  valid-name?/disp32
    349     # . . discard args
    350     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    351     # check-ints-equal(eax, 0, msg)
    352     # . . push args
    353     68/push  "F - test-valid-name-digit-prefix"/imm32
    354     68/push  0/imm32/false
    355     50/push-eax
    356     # . . call
    357     e8/call  check-ints-equal/disp32
    358     # . . discard args
    359     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    360     # . epilogue
    361     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    362     5d/pop-to-ebp
    363     c3/return
    364
    365 test-valid-name-negative-prefix:
    366     # . prologue
    367     55/push-ebp
    368     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    369     # (eax..ecx) = "-0x34"
    370     b8/copy-to-eax  "-0x34"/imm32
    371     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    372     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    373     05/add-to-eax  4/imm32
    374     # var slice/ecx: slice = {eax, ecx}
    375     51/push-ecx
    376     50/push-eax
    377     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    378     # eax = valid-name?(slice)
    379     # . . push args
    380     51/push-ecx
    381     # . . call
    382     e8/call  valid-name?/disp32
    383     # . . discard args
    384     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    385     # check-ints-equal(eax, 0, msg)
    386     # . . push args
    387     68/push  "F - test-valid-name-negative-prefix"/imm32
    388     68/push  0/imm32/false
    389     50/push-eax
    390     # . . call
    391     e8/call  check-ints-equal/disp32
    392     # . . discard args
    393     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    394     # . epilogue
    395     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    396     5d/pop-to-ebp
    397     c3/return
    398
    399 test-valid-name-0x-prefix:
    400     # . prologue
    401     55/push-ebp
    402     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    403     # (eax..ecx) = "0x34"
    404     b8/copy-to-eax  "0x34"/imm32
    405     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    406     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    407     05/add-to-eax  4/imm32
    408     # var slice/ecx: slice = {eax, ecx}
    409     51/push-ecx
    410     50/push-eax
    411     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    412     # eax = valid-name?(slice)
    413     # . . push args
    414     51/push-ecx
    415     # . . call
    416     e8/call  valid-name?/disp32
    417     # . . discard args
    418     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    419     # check-ints-equal(eax, 0, msg)
    420     # . . push args
    421     68/push  "F - test-valid-name-0x-prefix"/imm32
    422     68/push  0/imm32/false
    423     50/push-eax
    424     # . . call
    425     e8/call  check-ints-equal/disp32
    426     # . . discard args
    427     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    428     # . epilogue
    429     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    430     5d/pop-to-ebp
    431     c3/return
    432
    433 test-valid-name-starts-with-pre-digit:
    434     # . prologue
    435     55/push-ebp
    436     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    437     # (eax..ecx) = "/03"
    438     b8/copy-to-eax  "/03"/imm32
    439     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    440     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    441     05/add-to-eax  4/imm32
    442     # var slice/ecx: slice = {eax, ecx}
    443     51/push-ecx
    444     50/push-eax
    445     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    446     # eax = valid-name?(slice)
    447     # . . push args
    448     51/push-ecx
    449     # . . call
    450     e8/call  valid-name?/disp32
    451     # . . discard args
    452     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    453     # check-ints-equal(eax, 1, msg)
    454     # . . push args
    455     68/push  "F - test-valid-name-starts-with-pre-digit"/imm32
    456     68/push  1/imm32/true
    457     50/push-eax
    458     # . . call
    459     e8/call  check-ints-equal/disp32
    460     # . . discard args
    461     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    462     # . epilogue
    463     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    464     5d/pop-to-ebp
    465     c3/return
    466
    467 test-valid-name-starts-with-post-digit:
    468     # . prologue
    469     55/push-ebp
    470     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    471     # (eax..ecx) = "q34"
    472     b8/copy-to-eax  "q34"/imm32
    473     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    474     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    475     05/add-to-eax  4/imm32
    476     # var slice/ecx: slice = {eax, ecx}
    477     51/push-ecx
    478     50/push-eax
    479     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    480     # eax = valid-name?(slice)
    481     # . . push args
    482     51/push-ecx
    483     # . . call
    484     e8/call  valid-name?/disp32
    485     # . . discard args
    486     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    487     # check-ints-equal(eax, 1, msg)
    488     # . . push args
    489     68/push  "F - test-valid-name-starts-with-post-digit"/imm32
    490     68/push  1/imm32/true
    491     50/push-eax
    492     # . . call
    493     e8/call  check-ints-equal/disp32
    494     # . . discard args
    495     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    496     # . epilogue
    497     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    498     5d/pop-to-ebp
    499     c3/return
    500
    501 test-valid-name-starts-with-digit:
    502     # . prologue
    503     55/push-ebp
    504     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    505     # (eax..ecx) = "0x34"
    506     b8/copy-to-eax  "0x34"/imm32
    507     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    508     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    509     05/add-to-eax  4/imm32
    510     # var slice/ecx: slice = {eax, ecx}
    511     51/push-ecx
    512     50/push-eax
    513     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    514     # eax = valid-name?(slice)
    515     # . . push args
    516     51/push-ecx
    517     # . . call
    518     e8/call  valid-name?/disp32
    519     # . . discard args
    520     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    521     # check-ints-equal(eax, 0, msg)
    522     # . . push args
    523     68/push  "F - test-valid-name-starts-with-digit"/imm32
    524     68/push  0/imm32/false
    525     50/push-eax
    526     # . . call
    527     e8/call  check-ints-equal/disp32
    528     # . . discard args
    529     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    530     # . epilogue
    531     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    532     5d/pop-to-ebp
    533     c3/return
    534
    535 label?:  # word: (addr slice) -> result/eax: boolean
    536     # . prologue
    537     55/push-ebp
    538     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    539     # . save registers
    540     51/push-ecx
    541     # ecx = word
    542     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
    543     # var end/ecx: (addr byte) = word->end
    544     8b/copy                         1/mod/*+disp8   1/rm32/ecx    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(ecx+4) to ecx
    545     # return *(end - 1) == ':'
    546     # . eax = *(end-1)
    547     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
    548     8a/copy-byte                    1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/AL    -1/disp8         .                 # copy byte at *(ecx-1) to AL
    549     # . return (eax == ':')
    550     3d/compare-eax-and  0x3a/imm32/colon
    551     b8/copy-to-eax  1/imm32/true
    552     74/jump-if-=  $label?:end/disp8
    553     b8/copy-to-eax  0/imm32/false
    554 $label?:end:
    555     # . restore registers
    556     59/pop-to-ecx
    557     # . epilogue
    558     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    559     5d/pop-to-ebp
    560     c3/return
    561
    562 test-label?:
    563     # . prologue
    564     55/push-ebp
    565     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    566 $test-label?:true:
    567     # (eax..ecx) = "AAA:"
    568     b8/copy-to-eax  "AAA:"/imm32
    569     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    570     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    571     05/add-to-eax  4/imm32
    572     # var slice/ecx: slice = {eax, ecx}
    573     51/push-ecx
    574     50/push-eax
    575     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    576     # label?(slice/ecx)
    577     # . . push args
    578     51/push-ecx
    579     # . . call
    580     e8/call  label?/disp32
    581     # . . discard args
    582     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    583     # check-ints-equal(eax, 1, msg)
    584     # . . push args
    585     68/push  "F - test-label?:true"/imm32
    586     68/push  1/imm32
    587     50/push-eax
    588     # . . call
    589     e8/call  check-ints-equal/disp32
    590     # . . discard args
    591     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    592 $test-label?:false:
    593     # (eax..ecx) = "AAA"
    594     b8/copy-to-eax  "AAA"/imm32
    595     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    596     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    597     05/add-to-eax  4/imm32
    598     # var slice/ecx: slice = {eax, ecx}
    599     51/push-ecx
    600     50/push-eax
    601     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    602     # label?(slice/ecx)
    603     # . . push args
    604     51/push-ecx
    605     # . . call
    606     e8/call  label?/disp32
    607     # . . discard args
    608     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    609     # check-ints-equal(eax, 0, msg)
    610     # . . push args
    611     68/push  "F - test-label?:false"/imm32
    612     68/push  0/imm32
    613     50/push-eax
    614     # . . call
    615     e8/call  check-ints-equal/disp32
    616     # . . discard args
    617     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    618     # . epilogue
    619     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    620     5d/pop-to-ebp
    621     c3/return
    622
    623 # . . vim:nowrap:textwidth=0