From d1c9392a5461e0d33e226375a8f7986a97d2d66b Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Mon, 26 Nov 2018 01:19:47 -0800 Subject: 4782 --- html/subx/apps/crenshaw2-1b.subx.html | 899 ++++++++++++++++++++++++++++++++++ 1 file changed, 899 insertions(+) create mode 100644 html/subx/apps/crenshaw2-1b.subx.html (limited to 'html/subx/apps/crenshaw2-1b.subx.html') diff --git a/html/subx/apps/crenshaw2-1b.subx.html b/html/subx/apps/crenshaw2-1b.subx.html new file mode 100644 index 00000000..21c9ab2f --- /dev/null +++ b/html/subx/apps/crenshaw2-1b.subx.html @@ -0,0 +1,899 @@ + + + + +Mu - subx/apps/crenshaw2-1b.subx + + + + + + + + + + +
+  1 ## Port of https://github.com/akkartik/crenshaw/blob/master/tutor2.1.pas
+  2 # Corresponds to the section "single digits" in https://compilers.iecc.com/crenshaw/tutor2.txt
+  3 # except that we support numbers of multiple digits.
+  4 #
+  5 # To run (from the subx directory):
+  6 #   $ ./subx translate *.subx apps/crenshaw2-1.subx -o crenshaw2-1
+  7 #   $ echo '1a'  |./subx run apps/crenshaw2-1
+  8 # Expected output (not working yet):
+  9 #   # syscall(exit, 1a)
+ 10 #   bb/copy-to-EBX  3/imm32
+ 11 #   b8/copy-to-EAX  1/imm32/exit
+ 12 #   cd/syscall  0x80/imm8
+ 13 #
+ 14 # To run the generated output:
+ 15 #   $ echo '1a'  |./subx run apps/crenshaw2-1 > z1.subx
+ 16 #   $ ./subx translate z1.subx -o z1
+ 17 #   $ ./subx run z1
+ 18 #   $ echo $?
+ 19 #   26  # 0x1a in decimal
+ 20 #
+ 21 # Stdin must contain just a single hex digit. Other input will print an error:
+ 22 #   $ echo 'xyz'  |./subx run apps/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                                                   operand     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 # main: run tests if necessary, call 'compile' if not
+ 34   # prolog
+ 35   89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 36   # if (argc > 1)
+ 37   81          7/subop/compare     1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0/disp8         1/imm32           # compare *EBP
+ 38   7e/jump-if-lesser-or-equal  $run-main/disp8
+ 39   # and if (argv[1] == "test")
+ 40     # push args
+ 41   68/push  "test"/imm32
+ 42   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0x8/disp8       .                 # push *(EBP+8)
+ 43     # call
+ 44   e8/call  kernel-string-equal/disp32
+ 45     # discard args
+ 46   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 47     # check result
+ 48   3d/compare-EAX  1/imm32
+ 49   75/jump-if-not-equal  $run-main/disp8
+ 50   # then return run-tests()
+ 51   e8/call  run-tests/disp32
+ 52 #?   e8/call test-get-num-reads-multiple-digits/disp32
+ 53   8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/EBX   Num-test-failures/disp32          # copy *Num-test-failures to EBX
+ 54   eb/jump  $main:end/disp8
+ 55 $run-main:
+ 56   # allocate space for an exit-descriptor
+ 57     # var ed/EAX : (address exit-descriptor)
+ 58   81          5/subop/subtract    3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # subtract from ESP
+ 59   8d/copy-address                 0/mod/indirect  4/rm32/sib    4/base/ESP  4/index/none  .           0/r32/EAX   .               .                 # copy ESP to EAX
+ 60     # clear ed->target (so we really exit)
+ 61   c7/copy                         0/mod/direct    0/rm32/EAX    .           .             .           .           .               0/imm32           # copy to *EAX
+ 62   # compile(Stdin, 1/stdout, 2/stderr, ed)
+ 63     # push args
+ 64   50/push-EAX/ed
+ 65   68/push  2/imm32/stderr
+ 66   68/push  1/imm32/stdout
+ 67   68/push  Stdin/imm32
+ 68     # call
+ 69   e8/call  compile/disp32
+ 70     # discard args
+ 71   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
+ 72   # syscall(exit, 0)
+ 73   bb/copy-to-EBX  0/imm32
+ 74 $main:end:
+ 75   b8/copy-to-EAX  1/imm32/exit
+ 76   cd/syscall  0x80/imm8
+ 77 
+ 78 # the main entry point
+ 79 compile:  # in : fd or (address stream), out : fd or (address stream), err : fd or (address stream), ed : (address exit-descriptor) -> <void>
+ 80   # prolog
+ 81   55/push-EBP
+ 82   89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 83   # save registers
+ 84   50/push-EAX
+ 85   51/push-ECX
+ 86   # Look = get-char(in)
+ 87     # push args
+ 88   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           8/disp8      .                    # push *(EBP+8)
+ 89     # call
+ 90   e8/call  get-char/disp32
+ 91     # discard args
+ 92   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 93   # var num/ECX : (address stream) on the stack
+ 94   # Numbers can be 32 bits or 8 hex bytes long. One of them will be in 'Look', so we need space for 7 bytes.
+ 95   # We won't add more, so that we can get overflow-handling for free.
+ 96   # Add 12 bytes for 'read', 'write' and 'length' fields, for a total of 19 bytes, or 0x13 in hex.
+ 97   81          5/subop/subtract    3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x13/imm32        # subtract from ESP
+ 98   8d/copy-address                 0/mod/indirect  4/rm32/sib    4/base/ESP  4/index/none  .           1/r32/ECX   .               .                 # copy ESP to ECX
+ 99   # num->length = 7
+100   c7/copy                         1/mod/*+disp8   1/rm32/ECX    .           .             .           .           8/disp8         7/imm32           # copy to *(ECX+8)
+101   # clear-stream(num)
+102     # push args
+103   51/push-ECX
+104     # call
+105   e8/call  clear-stream/disp32
+106     # discard args
+107   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+108   # get-num(in, num, err, ed)
+109     # push args
+110   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0x14/disp8      .                 # push *(EBP+20)
+111   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0x10/disp8      .                 # push *(EBP+16)
+112   51/push-ECX/num
+113   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           8/disp8      .                    # push *(EBP+8)
+114     # call
+115   e8/call  get-num/disp32
+116     # discard args
+117   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
+118   # EAX = write(_test-stream, "Ab")
+119     # push args
+120   68/push  "Ab"/imm32
+121   68/push  _test-stream/imm32
+122     # call
+123   e8/call  write/disp32
+124     # discard args
+125   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+126   # EAX = write(out, "bb/copy-to-EBX  ")
+127     # push args
+128   68/push  "bb/copy-to-EBX  "/imm32
+129   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0xc/disp8       .                 # push *(EBP+12)
+130     # call
+131   e8/call  write/disp32
+132     # discard args
+133   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+134   # write-stream(out, num)
+135     # push args
+136   51/push-ECX/num
+137   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0xc/disp8       .                 # push *(EBP+12)
+138     # call
+139   e8/call  write-stream/disp32
+140     # discard args
+141   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+142   # write(out, Newline)
+143     # push args
+144   68/push  Newline/imm32
+145   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0xc/disp8       .                 # push *(EBP+12)
+146     # call
+147   e8/call  write/disp32
+148     # discard args
+149   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+150   # EAX = write(out, "b8/copy-to-EAX  1/imm32/exit")
+151     # push args
+152   68/push  "b8/copy-to-EAX  1/imm32/exit"/imm32
+153   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           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   # EAX = write(out, Newline)
+159     # push args
+160   68/push  Newline/imm32
+161   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           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   # EAX = write(out, "cd/syscall  0x80/imm8")
+167     # push args
+168   68/push  "cd/syscall  0x80/imm8"/imm32
+169   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           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   # EAX = write(out, Newline)
+175     # push args
+176   68/push  Newline/imm32
+177   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0xc/disp8       .                 # push *(EBP+12)
+178     # call
+179   e8/call  write/disp32
+180     # discard args
+181   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+182   # restore registers
+183   59/pop-to-ECX
+184   58/pop-to-EAX
+185   # epilog
+186   89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+187   5d/pop-to-EBP
+188   c3/return
+189 
+190 # Read a sequence of digits into 'out'. Abort if there are none, or if there is
+191 # no space in 'out'.
+192 # Input comes from the global variable 'Look' (first byte) and the argument
+193 # 'in' (rest). We leave the next byte from 'in' into 'Look' on exit.
+194 get-num:  # in : (address buffered-file), out : (address stream), err : fd or (address stream), ed : (address exit-descriptor) -> <void>
+195   # pseudocode:
+196   #   if !is-digit?(Look) expected(ed, err, "integer")
+197   #   do
+198   #     if out.write >= out.length
+199   #       write(err, "Error: too many digits in number\n")
+200   #       stop(ed, 1)
+201   #     out.data[out.write] = LSB(Look)
+202   #     ++out.write
+203   #     Look = get-char(in)
+204   #   while is-digit?(Look)
+205   # This is complicated because I don't want to hard-code the error strategy in
+206   # a general helper like write-byte. Maybe I should just create a local helper.
+207   #
+208   # within the loop we'll try to keep things in registers:
+209   #   ESI : in
+210   #   EDI : out
+211   #   EAX : temp
+212   #   ECX : out->write
+213   #   EDX : out->length
+214   #   EBX : temp2
+215   # We can't allocate Look to a register because it gets written implicitly in
+216   # get-char in each iteration of the loop. (Thereby demonstrating that it's
+217   # not the right interface for us. But we'll keep it just to follow Crenshaw.)
+218   #
+219   # prolog
+220   55/push-EBP
+221   89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+222   # EAX = is-digit?(Look)
+223     # push args
+224   ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Look/disp32     .                 # push *Look
+225     # call
+226   e8/call  is-digit?/disp32
+227     # discard args
+228   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+229   # if EAX == 0 error
+230   3d/compare-EAX  0/imm32
+231   75/jump-if-not-equal  $get-num:main/disp8
+232     # expected(ed, err, "integer")
+233       # push args
+234   68/push  "integer"/imm32
+235   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0x10/disp8      .                 # push *(EBP+16)
+236   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0x14/disp8      .                 # push *(EBP+20)
+237       # call
+238   e8/call  expected/disp32  # never returns
+239       # discard args
+240   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+241 $get-num:main:
+242   # save registers
+243   50/push-EAX
+244   51/push-ECX
+245   52/push-EDX
+246   53/push-EBX
+247   56/push-ESI
+248   57/push-EDI
+249   # read necessary variables to registers
+250     # ESI = in
+251   8b/copy                         1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
+252     # EDI = out
+253   8b/copy                         1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           7/r32/EDI   0xc/disp8       .                 # copy *(EBP+12) to EDI
+254     # ECX = out->write
+255   8b/copy                         0/mod/indirect  7/rm32/EDI    .           .             .           1/r32/ECX   .               .                 # copy *EDI to ECX
+256     # EDX = out->length
+257   8b/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           2/r32/EDX   8/disp8         .                 # copy *(EDI+8) to EDX
+258 $get-num:loop:
+259   # if out->write >= out->length error
+260   3b/compare                      3/mod/direct    1/rm32/ECX    .           .             .           2/r32/EDX   .               .                 # compare EDX with ECX
+261   7d/jump-if-lesser  $get-num:loop-stage2/disp8
+262     # error(ed, err, "get-num: too many digits in number")  # TODO: show full number
+263       # push args
+264   68/push  "get-num: too many digits in number"/imm32
+265   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0x10/disp8      .                 # push *(EBP+16)
+266   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0x14/disp8      .                 # push *(EBP+20)
+267       # call
+268   e8/call  error/disp32  # never returns
+269       # discard args
+270   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+271 $get-num:loop-stage2:
+272   # out->data[out->write] = LSB(Look)
+273   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
+274   8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/EAX   Look/disp32     .                 # copy *Look to EAX
+275   88/copy-byte                    0/mod/indirect  3/rm32/EBX    .           .             .           0/r32/AL    .               .                 # copy byte at AL to *EBX
+276   # ++out->write
+277   41/increment-ECX
+278   # Look = get-char(in)
+279     # push args
+280   56/push-ESI
+281     # call
+282   e8/call  get-char/disp32
+283     # discard args
+284   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+285   # EAX = is-digit?(Look)
+286     # push args
+287   ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Look/disp32     .                 # push *Look
+288     # call
+289   e8/call  is-digit?/disp32
+290     # discard args
+291   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+292   # if EAX loop
+293   3d/compare-EAX  0/imm32
+294   0f 85/jump-if-not-equal  $get-num:loop/disp32
+295 $get-num:loop-end:
+296   # persist necessary variables from registers
+297   89/copy                         0/mod/indirect  7/rm32/EDI    .           .             .           1/r32/ECX   .               .                 # copy ECX to *EDI
+298   # restore registers
+299   5f/pop-to-EDI
+300   5e/pop-to-ESI
+301   5b/pop-to-EBX
+302   5a/pop-to-EDX
+303   59/pop-to-ECX
+304   58/pop-to-EAX
+305   # epilog
+306   89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+307   5d/pop-to-EBP
+308   c3/return
+309 
+310 test-get-num-reads-single-digit:
+311   ## check that get-num returns first character if it's a digit
+312   # This test uses exit-descriptors. Use EBP for setting up local variables.
+313   55/push-EBP
+314   89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+315   ## clear all streams
+316   # clear-stream(_test-stream)
+317     # push args
+318   68/push  _test-stream/imm32
+319     # call
+320   e8/call  clear-stream/disp32
+321     # discard args
+322   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+323   # clear-stream(_test-buffered-file+4)
+324     # push args
+325   b8/copy-to-EAX  _test-buffered-file/imm32
+326   05/add-to-EAX  4/imm32
+327   50/push-EAX
+328     # call
+329   e8/call  clear-stream/disp32
+330     # discard args
+331   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+332   # clear-stream(_test-output-stream)
+333     # push args
+334   68/push  _test-output-stream/imm32
+335     # call
+336   e8/call  clear-stream/disp32
+337     # discard args
+338   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+339   # clear-stream(_test-error-stream)
+340     # push args
+341   68/push  _test-error-stream/imm32
+342     # call
+343   e8/call  clear-stream/disp32
+344     # discard args
+345   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+346   ## initialize 'in'
+347   # write(_test-stream, "3")
+348     # push args
+349   68/push  "3"/imm32
+350   68/push  _test-stream/imm32
+351     # call
+352   e8/call  write/disp32
+353     # discard args
+354   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+355   ## initialize exit-descriptor 'ed'
+356   # allocate on stack
+357   # var ed/EAX : (address exit-descriptor)
+358   81          5/subop/subtract    3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # subtract from ESP
+359   8d/copy-address                 0/mod/indirect  4/rm32/sib    4/base/ESP  4/index/none  .           0/r32/EAX   .               .                 # copy ESP to EAX
+360   # size the exit-descriptor for the call to get-num below
+361   # tailor-exit-descriptor(ed, 16)
+362     # push args
+363   68/push  0x10/imm32/nbytes-of-args-for-get-num
+364   50/push-EAX/ed
+365     # call
+366   e8/call  tailor-exit-descriptor/disp32
+367     # discard args
+368   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+369   ## prime the pump
+370   # get-char(_test-buffered-file)
+371     # push args
+372   68/push  _test-buffered-file/imm32
+373     # call
+374   e8/call  get-char/disp32
+375     # discard args
+376   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+377   ## get-num(in, out, err, ed)
+378     # push args
+379   50/push-EAX/ed
+380   68/push  _test-error-stream/imm32
+381   68/push  _test-output-stream/imm32
+382   68/push  _test-buffered-file/imm32
+383     # call
+384   e8/call  get-num/disp32
+385   ## registers except ESP may be clobbered at this point
+386     # discard args
+387   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
+388   # check-ints-equal(*_test-output-stream.data, '3')
+389     # push args
+390   68/push  "F - test-get-num-reads-single-digit"/imm32
+391   68/push  0x33/imm32
+392   b8/copy-to-EAX  _test-output-stream/imm32
+393   ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           0xc/disp8       .                 # push *(EAX+12)
+394     # call
+395   e8/call  check-ints-equal/disp32
+396     # discard args
+397   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+398   # reclaim locals
+399   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+400   5d/pop-to-EBP
+401   c3/return
+402 
+403 test-get-num-aborts-on-non-digit-in-Look:
+404   ## check that get-num returns first character if it's a digit
+405   # This test uses exit-descriptors. Use EBP for setting up local variables.
+406   55/push-EBP
+407   89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+408   ## clear all streams
+409   # clear-stream(_test-stream)
+410     # push args
+411   68/push  _test-stream/imm32
+412     # call
+413   e8/call  clear-stream/disp32
+414     # discard args
+415   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+416   # clear-stream(_test-buffered-file+4)
+417     # push args
+418   b8/copy-to-EAX  _test-buffered-file/imm32
+419   05/add-to-EAX  4/imm32
+420   50/push-EAX
+421     # call
+422   e8/call  clear-stream/disp32
+423     # discard args
+424   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+425   # clear-stream(_test-output-stream)
+426     # push args
+427   68/push  _test-output-stream/imm32
+428     # call
+429   e8/call  clear-stream/disp32
+430     # discard args
+431   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+432   # clear-stream(_test-error-stream)
+433     # push args
+434   68/push  _test-error-stream/imm32
+435     # call
+436   e8/call  clear-stream/disp32
+437     # discard args
+438   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+439   ## initialize 'in'
+440   # write(_test-stream, "3")
+441     # push args
+442   68/push  "3"/imm32
+443   68/push  _test-stream/imm32
+444     # call
+445   e8/call  write/disp32
+446     # discard args
+447   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+448   ## initialize exit-descriptor 'ed'
+449   # allocate on stack
+450   # var ed/EAX : (address exit-descriptor)
+451   81          5/subop/subtract    3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # subtract from ESP
+452   8d/copy-address                 0/mod/indirect  4/rm32/sib    4/base/ESP  4/index/none  .           0/r32/EAX   .               .                 # copy ESP to EAX
+453   # size the exit-descriptor for the call to get-num below
+454   # tailor-exit-descriptor(ed, 16)
+455     # push args
+456   68/push  0x10/imm32/nbytes-of-args-for-get-num
+457   50/push-EAX/ed
+458     # call
+459   e8/call  tailor-exit-descriptor/disp32
+460     # discard args
+461   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+462   ## don't initialize Look
+463   ## get-num(in, out, err, ed)
+464     # push args
+465   50/push-EAX/ed
+466   68/push  _test-error-stream/imm32
+467   68/push  _test-output-stream/imm32
+468   68/push  _test-buffered-file/imm32
+469     # call
+470   e8/call  get-num/disp32
+471   ## registers except ESP may be clobbered at this point
+472     # discard args
+473   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
+474   ## check that get-num tried to call exit(1)
+475   # check-ints-equal(ed->value, 2, msg)  # i.e. stop was called with value 1
+476     # push args
+477   68/push  "F - test-get-num-aborts-on-non-digit-in-Look"/imm32
+478   68/push  2/imm32
+479     # push ed->value
+480   ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
+481     # call
+482   e8/call  check-ints-equal/disp32
+483     # discard args
+484   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+485   # reclaim locals
+486   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+487   5d/pop-to-EBP
+488   c3/return
+489 
+490 test-get-num-reads-multiple-digits:
+491   ## check that get-num returns all initial digits until it encounters a non-digit
+492   # This test uses exit-descriptors. Use EBP for setting up local variables.
+493   55/push-EBP
+494   89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+495   ## clear all streams
+496   # clear-stream(_test-stream)
+497     # push args
+498   68/push  _test-stream/imm32
+499     # call
+500   e8/call  clear-stream/disp32
+501     # discard args
+502   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+503   # clear-stream(_test-buffered-file+4)
+504     # push args
+505   b8/copy-to-EAX  _test-buffered-file/imm32
+506   05/add-to-EAX  4/imm32
+507   50/push-EAX
+508     # call
+509   e8/call  clear-stream/disp32
+510     # discard args
+511   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+512   # clear-stream(_test-output-stream)
+513     # push args
+514   68/push  _test-output-stream/imm32
+515     # call
+516   e8/call  clear-stream/disp32
+517     # discard args
+518   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+519   # clear-stream(_test-error-stream)
+520     # push args
+521   68/push  _test-error-stream/imm32
+522     # call
+523   e8/call  clear-stream/disp32
+524     # discard args
+525   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+526   ## initialize 'in'
+527   # write(_test-stream, "3456 x")
+528     # push args
+529   68/push  "3456"/imm32
+530   68/push  _test-stream/imm32
+531     # call
+532   e8/call  write/disp32
+533     # discard args
+534   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+535   ## initialize exit-descriptor 'ed'
+536   # allocate on stack
+537   # var ed/EAX : (address exit-descriptor)
+538   81          5/subop/subtract    3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # subtract from ESP
+539   8d/copy-address                 0/mod/indirect  4/rm32/sib    4/base/ESP  4/index/none  .           0/r32/EAX   .               .                 # copy ESP to EAX
+540   # size the exit-descriptor for the call to get-num below
+541   # tailor-exit-descriptor(ed, 16)
+542     # push args
+543   68/push  0x10/imm32/nbytes-of-args-for-get-num
+544   50/push-EAX/ed
+545     # call
+546   e8/call  tailor-exit-descriptor/disp32
+547     # discard args
+548   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+549   ## prime the pump
+550   # get-char(_test-buffered-file)
+551     # push args
+552   68/push  _test-buffered-file/imm32
+553     # call
+554   e8/call  get-char/disp32
+555     # discard args
+556   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+557   ## get-num(in, out, err, ed)
+558     # push args
+559   50/push-EAX/ed
+560   68/push  _test-error-stream/imm32
+561   68/push  _test-output-stream/imm32
+562   68/push  _test-buffered-file/imm32
+563     # call
+564   e8/call  get-num/disp32
+565   ## registers except ESP may be clobbered at this point
+566     # discard args
+567   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
+568   # check-ints-equal(*_test-output-stream.data, '3456')
+569     # push args
+570   68/push  "F - test-get-num-reads-multiple-digits"/imm32
+571   68/push  0x36353433/imm32
+572   b8/copy-to-EAX  _test-output-stream/imm32
+573   ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           0xc/disp8       .                 # push *(EAX+12)
+574     # call
+575   e8/call  check-ints-equal/disp32
+576     # discard args
+577   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+578   # reclaim locals
+579   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+580   5d/pop-to-EBP
+581   c3/return
+582 
+583 test-get-num-reads-multiple-digits-followed-by-nondigit:
+584   ## check that get-num returns all initial digits until it encounters a non-digit
+585   # This test uses exit-descriptors. Use EBP for setting up local variables.
+586   55/push-EBP
+587   89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+588   ## clear all streams
+589   # clear-stream(_test-stream)
+590     # push args
+591   68/push  _test-stream/imm32
+592     # call
+593   e8/call  clear-stream/disp32
+594     # discard args
+595   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+596   # clear-stream(_test-buffered-file+4)
+597     # push args
+598   b8/copy-to-EAX  _test-buffered-file/imm32
+599   05/add-to-EAX  4/imm32
+600   50/push-EAX
+601     # call
+602   e8/call  clear-stream/disp32
+603     # discard args
+604   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+605   # clear-stream(_test-output-stream)
+606     # push args
+607   68/push  _test-output-stream/imm32
+608     # call
+609   e8/call  clear-stream/disp32
+610     # discard args
+611   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+612   # clear-stream(_test-error-stream)
+613     # push args
+614   68/push  _test-error-stream/imm32
+615     # call
+616   e8/call  clear-stream/disp32
+617     # discard args
+618   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+619   ## initialize 'in'
+620   # write(_test-stream, "3456 x")
+621     # push args
+622   68/push  "3456 x"/imm32
+623   68/push  _test-stream/imm32
+624     # call
+625   e8/call  write/disp32
+626     # discard args
+627   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+628   ## initialize exit-descriptor 'ed'
+629   # allocate on stack
+630   # var ed/EAX : (address exit-descriptor)
+631   81          5/subop/subtract    3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # subtract from ESP
+632   8d/copy-address                 0/mod/indirect  4/rm32/sib    4/base/ESP  4/index/none  .           0/r32/EAX   .               .                 # copy ESP to EAX
+633   # size the exit-descriptor for the call to get-num below
+634   # tailor-exit-descriptor(ed, 16)
+635     # push args
+636   68/push  0x10/imm32/nbytes-of-args-for-get-num
+637   50/push-EAX/ed
+638     # call
+639   e8/call  tailor-exit-descriptor/disp32
+640     # discard args
+641   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+642   ## prime the pump
+643   # get-char(_test-buffered-file)
+644     # push args
+645   68/push  _test-buffered-file/imm32
+646     # call
+647   e8/call  get-char/disp32
+648     # discard args
+649   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+650   ## get-num(in, out, err, ed)
+651     # push args
+652   50/push-EAX/ed
+653   68/push  _test-error-stream/imm32
+654   68/push  _test-output-stream/imm32
+655   68/push  _test-buffered-file/imm32
+656     # call
+657   e8/call  get-num/disp32
+658   ## registers except ESP may be clobbered at this point
+659     # discard args
+660   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
+661   # check-ints-equal(*_test-output-stream.data, '3456')
+662     # push args
+663   68/push  "F - test-get-num-reads-multiple-digits-followed-by-nondigit"/imm32
+664   68/push  0x36353433/imm32
+665   b8/copy-to-EAX  _test-output-stream/imm32
+666   ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           0xc/disp8       .                 # push *(EAX+12)
+667     # call
+668   e8/call  check-ints-equal/disp32
+669     # discard args
+670   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+671   # reclaim locals
+672   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+673   5d/pop-to-EBP
+674   c3/return
+675 
+676 ## helpers
+677 
+678 # write(f, "Error: "+s+" expected\n") then stop(ed, 1)
+679 expected:  # ed : (address exit-descriptor), f : fd or (address stream), s : (address array byte) -> <void>
+680   # prolog
+681   55/push-EBP
+682   89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+683   # write(f, "Error: ")
+684     # push args
+685   68/push  "Error: "/imm32
+686   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0xc/disp8       .                 # push *(EBP+12)
+687     # call
+688   e8/call  write/disp32
+689     # discard args
+690   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+691   # write(f, s)
+692     # push args
+693   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0x10/disp8      .                 # push *(EBP+16)
+694   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0xc/disp8       .                 # push *(EBP+12)
+695     # call
+696   e8/call  write/disp32
+697     # discard args
+698   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+699   # write(f, " expected")
+700     # push args
+701   68/push  " expected"/imm32
+702   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0xc/disp8       .                 # push *(EBP+12)
+703     # call
+704   e8/call  write/disp32
+705     # discard args
+706   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+707   # write(f, Newline)
+708     # push args
+709   68/push  Newline/imm32
+710   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0xc/disp8       .                 # push *(EBP+12)
+711     # call
+712   e8/call  write/disp32
+713     # discard args
+714   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+715   # stop(ed, 1)
+716     # push args
+717   68/push  1/imm32
+718   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           8/disp8         .                 # push *(EBP+8)
+719     # call
+720   e8/call  stop/disp32
+721   ## should never get past this point
+722   # epilog
+723   89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+724   5d/pop-to-EBP
+725   c3/return
+726 
+727 # write(f, "Error: "+s+"\n") then stop(ed, 1)
+728 error:  # ed : (address exit-descriptor), f : fd or (address stream), s : (address array byte) -> <void>
+729   # prolog
+730   55/push-EBP
+731   89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+732   # write(f, "Error: ")
+733     # push args
+734   68/push  "Error: "/imm32
+735   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0xc/disp8       .                 # push *(EBP+12)
+736     # call
+737   e8/call  write/disp32
+738     # discard args
+739   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+740   # write(f, s)
+741     # push args
+742   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0x10/disp8      .                 # push *(EBP+16)
+743   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0xc/disp8       .                 # push *(EBP+12)
+744     # call
+745   e8/call  write/disp32
+746     # discard args
+747   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+748   # write(f, Newline)
+749     # push args
+750   68/push  Newline/imm32
+751   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0xc/disp8       .                 # push *(EBP+12)
+752     # call
+753   e8/call  write/disp32
+754     # discard args
+755   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+756   # stop(ed, 1)
+757     # push args
+758   68/push  1/imm32
+759   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           8/disp8         .                 # push *(EBP+8)
+760     # call
+761   e8/call  stop/disp32
+762   ## should never get past this point
+763   # epilog
+764   89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+765   5d/pop-to-EBP
+766   c3/return
+767 
+768 # read a byte from 'f', and store it in 'Look'
+769 get-char:  # f : (address buffered-file) -> <void>
+770   # prolog
+771   55/push-EBP
+772   89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+773   # save registers
+774   50/push-EAX
+775   # read-byte(f)
+776     # push args
+777   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0x8/disp8       .                 # push *(EBP+8)
+778     # call
+779   e8/call  read-byte/disp32
+780     # discard args
+781   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+782   # save EAX to Look
+783   89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/EAX   Look/disp32     .                 # copy EAX to *Look
+784   # restore registers
+785   58/pop-to-EAX
+786   # epilog
+787   89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+788   5d/pop-to-EBP
+789   c3/return
+790 
+791 is-digit?:  # c : int -> bool/EAX
+792   # prolog
+793   55/push-EBP
+794   89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+795   # EAX = false
+796   b8/copy-to-EAX  0/imm32
+797   # if c < '0' return false
+798   81          7/subop/compare     1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0x8/disp8       0x30/imm32        # compare *(EBP+8)
+799   7c/jump-if-lesser  $is-digit?:end/disp8
+800   # if c > '9' return false
+801   81          7/subop/compare     1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0x8/disp8       0x39/imm32        # compare *(EBP+8)
+802   7f/jump-if-greater  $is-digit?:end/disp8
+803   # otherwise return true
+804   b8/copy-to-EAX  1/imm32
+805 $is-digit?:end:
+806   # epilog
+807   89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+808   5d/pop-to-EBP
+809   c3/return
+810 
+811 == data
+812 
+813 Look:
+814   00 00 00 00
+815 
+816 _test-output-stream:
+817   # current write index
+818   00 00 00 00
+819   # current read index
+820   00 00 00 00
+821   # length (= 8)
+822   08 00 00 00
+823   # data
+824   00 00 00 00 00 00 00 00  # 8 bytes
+825 
+826 _test-error-stream:
+827   # current write index
+828   00 00 00 00
+829   # current read index
+830   00 00 00 00
+831   # length (= 8)
+832   08 00 00 00
+833   # data
+834   00 00 00 00 00 00 00 00  # 8 bytes
+835 
+836 # vim:nowrap:textwidth=0
+
+ + + -- cgit 1.4.1-2-gfad0