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 #
  4 # To run (from the subx directory):
  5 #   $ ./subx translate *.subx apps/crenshaw2-1.subx -o crenshaw2-1
  6 #   $ echo '3'  |./subx run apps/crenshaw2-1
  7 # Expected output (not working yet):
  8 #   # syscall(exit, 3)
  9 #   bb/copy-to-EBX  3/imm32
 10 #   b8/copy-to-EAX  1/imm32/exit
 11 #   cd/syscall  0x80/imm8
 12 #
 13 # To run the generated output:
 14 #   $ echo '3'  |./subx run apps/crenshaw2-1 > z1.subx
 15 #   $ ./subx translate z1.subx -o z1
 16 #   $ ./subx run z1
 17 #   $ echo $?
 18 #   3
 19 #
 20 # Stdin must contain just a single hex number. Other input will print an error:
 21 #   $ echo 'xyz'  |./subx run apps/crenshaw2-1
 22 #   Error: integer expected
 23 
 24 == code
 25 # instruction                     effective address                                                   operand     displacement    immediate
 26 # op          subop               mod             rm32          base        index         scale       r32
 27 # 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
 28 
 29 # main:
 30   # allocate space for an exit-descriptor
 31   # var ed/EAX : (address exit-descriptor)
 32   81          5/subop/subtract    3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # subtract from ESP
 33   8d/copy-address                 0/mod/indirect  4/rm32/sib    4/base/ESP  4/index/none  .           0/r32/EAX   .               .                 # copy ESP to EAX
 34   # clear ed->target (so we really exit)
 35   c7/copy                         0/mod/direct    0/rm32/EAX    .           .             .           .           .               0/imm32           # copy to *EAX
 36   # expected(ed, 2/stderr, "integer")
 37     # push args
 38   68/push  "integer"/imm32
 39   68/push  2/imm32/stderr
 40   50/push-EAX
 41     # call
 42   e8/call  expected/disp32
 43     # discard args
 44   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
 45   # syscall(exit, 0)
 46   bb/copy-to-EBX  0/imm32
 47   b8/copy-to-EAX  1/imm32/exit
 48   cd/syscall  0x80/imm8
 49 
 50 ## helpers
 51 
 52 expected:  # ed : (address exit-descriptor), f : fd or (address stream), s : (address array byte)
 53   # prolog
 54   55/push-EBP
 55   89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
 56   # write(f, "Error: ")
 57     # push args
 58   68/push  "Error: "/imm32
 59   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0xc/disp8       .                 # push *(EBP+12)
 60     # call
 61   e8/call  write/disp32
 62     # discard args
 63   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
 64   # write(f, s)
 65     # push args
 66   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0x10/disp8      .                 # push *(EBP+16)
 67   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0xc/disp8       .                 # push *(EBP+12)
 68     # call
 69   e8/call  write/disp32
 70     # discard args
 71   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
 72   # write(f, " expected")
 73     # push args
 74   68/push  " expected"/imm32
 75   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0xc/disp8       .                 # push *(EBP+12)
 76     # call
 77   e8/call  write/disp32
 78     # discard args
 79   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
 80   # write(f, Newline)
 81     # push args
 82   68/push  Newline/imm32
 83   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           0xc/disp8       .                 # push *(EBP+12)
 84     # call
 85   e8/call  write/disp32
 86     # discard args
 87   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
 88   # stop(ed, 1)
 89     # push args
 90   68/push  1/imm32
 91   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    5/base/EBP  4/index/none  .           .           8/disp8         .                 # push *(EBP+8)
 92     # call
 93   e8/call  stop/disp32
 94   ## should never get past this point
 95   # epilog
 96   89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
 97   5d/pop-to-EBP
 98   c3/return
 99 
100 # vim:nowrap:textwidth=0