From 3350c34a74844e21ea69077e01efff3bae64bdcd Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Tue, 23 Mar 2021 17:31:08 -0700 Subject: . --- html/linux/crenshaw2-1.subx.html | 621 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 621 insertions(+) create mode 100644 html/linux/crenshaw2-1.subx.html (limited to 'html/linux/crenshaw2-1.subx.html') diff --git a/html/linux/crenshaw2-1.subx.html b/html/linux/crenshaw2-1.subx.html new file mode 100644 index 00000000..0973ab35 --- /dev/null +++ b/html/linux/crenshaw2-1.subx.html @@ -0,0 +1,621 @@ + + + + +Mu - linux/crenshaw2-1.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/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 apps/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
+
+ + + -- cgit 1.4.1-2-gfad0