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:
  5 #   $ subx translate apps/crenshaw2.1.subx crenshaw 2.1
  6 #   $ echo '3'  |subx run apps/crenshaw2.1  |xxd -
  7 # Expected output:
  8 #   TODO
  9 #
 10 # The output is the code a function would need to include, returning the
 11 # result in EAX.
 12 #
 13 # Major note: byte strings are not null-terminated. Instead they're prefixed
 14 # with a 32-bit length.
 15 
 16 == code
 17 # instruction                     effective address                                                   operand     displacement    immediate
 18 # op          subop               mod             rm32          base        index         scale       r32
 19 # 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
 20 
 21 # main:
 22   # abort(Error_integer)
 23     # push args
 24   68/push  Error_integer/imm32
 25     # call
 26   e8/call  abort/disp32
 27     # discard arg
 28   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add 4 to ESP
 29   # exit(0)
 30   bb/copy                         .               .             .           .             .           .           .               0/imm32           # copy 0 to EBX
 31   b8/copy                         .               .             .           .             .           .           .               1/imm32/exit      # copy 1 to EAX
 32   cd/syscall  0x80/imm8
 33 
 34 # print error message and exit
 35 # really maps to the 'Expected' function in Crenshaw
 36 abort:  # s : (address array byte) -> <void>
 37   # error(s)
 38     # push args
 39   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           .           4/disp8         .                 # push *(ESP+4)
 40     # call
 41   e8/call  error/disp32
 42     # discard arg
 43   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add 4 to ESP
 44   # exit(1)
 45   bb/copy                         .               .             .           .             .           .           .               1/imm32           # copy 1 to EBX
 46   b8/copy                         .               .             .           .             .           .           .               1/imm32/exit      # copy 1 to EAX
 47   cd/syscall  0x80/imm8
 48 
 49 # print out "Error: #{s} expected\n" to stderr
 50 error:  # s : (address array byte) -> <void>
 51   # write_stderr("Error: ")
 52     # push args
 53   68/push  Error/imm32
 54     # call
 55   e8/call  write_stderr/disp32
 56     # discard arg
 57   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add 4 to ESP
 58   # write_stderr(s)
 59     # push args
 60   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           .           4/disp8         .                 # push *(ESP+4)
 61     # call
 62   e8/call  write_stderr/disp32
 63     # discard arg
 64   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add 4 to ESP
 65   # write_stderr(" expected")
 66     # push args
 67   68/push  Expected_suffix/imm32
 68     # call
 69   e8/call  write_stderr/disp32
 70     # discard arg
 71   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add 4 to ESP
 72   # write_stderr("\n")
 73     # push args
 74   68/push  Newline/imm32
 75     # call
 76   e8/call  write_stderr/disp32
 77     # discard arg
 78   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add 4 to ESP
 79   # end
 80   c3/return
 81 
 82 write_stderr:  # s : (address array byte) -> <void>
 83   # write(2/stderr, (data) s+4, (size) *s)
 84     # fd = 2 (stderr)
 85   bb/copy                         .               .             .           .             .           .           .               2/imm32           # copy 2 to EBX
 86     # x = s+4
 87   8b/copy                         1/mod/*+disp8   4/rm32/SIB    4/base/ESP  4/index/none  .           1/r32/ECX   4/disp8         .                 # copy *(ESP+4) to ECX
 88   81          0/subop/add         3/mod/direct    1/rm32/ECX    .           .             .           .           .               4/imm32           # add 4 to ECX
 89     # size = *s
 90   8b/copy                         1/mod/*+disp8   4/rm32/SIB    4/base/ESP  4/index/none  .           2/r32/EDX   4/disp8         .                 # copy *(ESP+4) to EDX
 91   8b/copy                         0/mod/indirect  2/rm32/EDX    .           .             .           2/r32/EDX   .               .                 # copy *EDX to EDX
 92     # call write()
 93   b8/copy                         .               .             .           .             .           .           .               4/imm32/write     # copy 1 to EAX
 94   cd/syscall  0x80/imm8
 95   # end
 96   c3/return
 97 
 98 write_stdout:  # s : (address array byte) -> <void>
 99   # write(1/stdout, (data) s+4, (size) *s)
100     # fd = 1 (stdout)
101   bb/copy                         .               .             .           .             .           .           .               1/imm32           # copy 1 to EBX
102     # x = s+4
103   8b/copy                         1/mod/*+disp8   4/rm32/SIB    4/base/ESP  4/index/none  .           1/r32/ECX   4/disp8         .                 # copy *(ESP+4) to ECX
104   81          0/subop/add         3/mod/direct    1/rm32/ECX    .           .             .           .           .               4/imm32           # add 4 to ECX
105     # size = *s
106   8b/copy                         1/mod/*+disp8   4/rm32/SIB    4/base/ESP  4/index/none  .           2/r32/EDX   4/disp8         .                 # copy *(ESP+4) to EDX
107   8b/copy                         0/mod/indirect  2/rm32/EDX    .           .             .           2/r32/EDX   .               .                 # copy *EDX to EDX
108     # call write()
109   b8/copy                         .               .             .           .             .           .           .               4/imm32/write     # copy 1 to EAX
110   cd/syscall  0x80/imm8
111   # end
112   c3/return
113 
114 == data
115 Newline:
116   # size
117   01 00 00 00
118   # data
119   0a/newline
120 Error:  # "Error: " : (array byte)
121   # size
122   07 00 00 00
123   # data
124   45/E 72/r 72/r 6f/o 72/r 3a/: 20/space
125 Expected_suffix:  # " expected" : (array byte)
126   # size
127   09 00 00 00
128   # data
129   20/space 65/e 78/x 70/p 65/e 63/c 74/t 65/e 64/d
130 Error_integer:  # "Integer" : (array byte)
131   # size
132   07 00 00 00
133   # data
134   49/I 6e/n 74/t 65/e 67/g 65/e 72/r