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 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("Integer")
23     # push args
24   68/push  "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 to ESP
29   # syscall(exit, 0)
30   bb/copy-to-EBX  0/imm32
31   b8/copy-to-EAX  1/imm32/exit
32   cd/syscall  0x80/imm8
33 
34 ## helpers
35 
36 # print error message and exit
37 # really maps to the 'Expected' function in Crenshaw
38 abort:  # s : (address array byte) -> <void>
39   # error(s)
40     # push args
41   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           .           4/disp8         .                 # push *(ESP+4)
42     # call
43   e8/call  error/disp32
44     # discard arg
45   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
46   # syscall(exit, 1)
47   bb/copy-to-EBX  1/imm32
48   b8/copy-to-EAX  1/imm32/exit
49   cd/syscall  0x80/imm8
50 
51 # print out "Error: #{s} expected\n" to stderr
52 error:  # s : (address array byte) -> <void>
53   # write(2/stderr, "Error: ")
54     # push args
55   68/push  "Error: "/imm32
56   68/push  2/imm32/stderr
57     # call
58   e8/call  write/disp32
59     # discard arg
60   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
61   # write(2/stderr, s)
62     # push args
63   ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           .           4/disp8         .                 # push *(ESP+4)
64   68/push  2/imm32/stderr
65     # call
66   e8/call  write/disp32
67     # discard arg
68   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
69   # write(2/stderr, " expected")
70     # push args
71   68/push  " expected"/imm32
72   68/push  2/imm32/stderr
73     # call
74   e8/call  write/disp32
75     # discard arg
76   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
77   # write(2/stderr, "\n")
78     # push args
79   68/push  Newline/imm32
80   68/push  2/imm32/stderr
81     # call
82   e8/call  write/disp32
83     # discard arg
84   81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
85   # end
86   c3/return
87 
88 # vim:nowrap:textwidth=0