# Mu - subx/apps/crenshaw2-1.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 #
      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