about summary refs log tree commit diff stats
path: root/subx/apps/crenshaw2-1.subx
blob: 32436bad44d93a85316224182e624219d091bc1e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
## port of https://github.com/akkartik/crenshaw/blob/master/tutor2.1.pas
# corresponds to the section "single digits" in https://compilers.iecc.com/crenshaw/tutor2.txt
#
# To run:
#   $ subx translate apps/crenshaw2.1.subx crenshaw 2.1
#   $ echo '3'  |subx run apps/crenshaw2.1  |xxd -
# Expected output:
#   TODO
#
# Major note: byte strings are not null-terminated. Instead they're prefixed
# with a 32-bit length.

== code
# instruction                     effective address                                                   operand     displacement    immediate
# op          subop               mod             rm32          base        index         scale       r32
# 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

# main:
  # abort(Error_integer)
    # push args
  68/push                         .               .             .           .             .           .           .               Error_integer/imm32
    # call
  e8/call                         .               .             .           .             .           .           abort/disp32
    # discard arg
  81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add 4 to ESP
  # exit(0)
  bb/copy                         .               .             .           .             .           .           .               0/imm32           # copy 0 to EBX
  b8/copy                         .               .             .           .             .           .           .               1/imm32/exit      # copy 1 to EAX
  cd/syscall                      .               .             .           .             .           .           .               0x80/imm8         # int 80h

# print error message and exit
# really maps to the 'Expected' function in Crenshaw
abort:  # s : (address array byte) -> <void>
  # error(s)
    # push args
  ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           .           4/disp8         .                 # push *(ESP+4)
    # call
  e8/call                         .               .             .           .             .           .           error/disp32
    # discard arg
  81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add 4 to ESP
  # exit(1)
  bb/copy                         .               .             .           .             .           .           .               1/imm32           # copy 1 to EBX
  b8/copy                         .               .             .           .             .           .           .               1/imm32/exit      # copy 1 to EAX
  cd/syscall                      .               .             .           .             .           .           .               0x80/imm8         # int 80h

# print out "Error: #{s} expected\n" to stderr
error:  # s : (address array byte) -> <void>
  # write_stderr("Error: ")
    # push args
  68/push                         .               .             .           .             .           .           .               Error/imm32
    # call
  e8/call                         .               .             .           .             .           .           write_stderr/disp32
    # discard arg
  81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add 4 to ESP
  # write_stderr(s)
    # push args
  ff          6/subop/push        1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           .           4/disp8         .                 # push *(ESP+4)
    # call
  e8/call                         .               .             .           .             .           .           write_stderr/disp32
    # discard arg
  81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add 4 to ESP
  # write_stderr(" expected")
    # push args
  68/push                         .               .             .           .             .           .           .               Expected_suffix/imm32
    # call
  e8/call                         .               .             .           .             .           .           write_stderr/disp32
    # discard arg
  81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add 4 to ESP
  # write_stderr("\n")
    # push args
  68/push                         .               .             .           .             .           .           .               Newline/imm32
    # call
  e8/call                         .               .             .           .             .           .           write_stderr/disp32
    # discard arg
  81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add 4 to ESP
  # end
  c3/return

write_stderr:  # s : (address array byte) -> <void>
  # write(2/stderr, (data) s+4, (size) *s)
    # fd = 2 (stderr)
  bb/copy                         .               .             .           .             .           .           .               2/imm32           # copy 2 to EBX
    # x = s+4
  8b/copy                         1/mod/*+disp8   4/rm32/SIB    4/base/ESP  4/index/none  .           1/r32/ECX   4/disp8         .                 # copy *(ESP+4) to ECX
  81          0/subop/add         3/mod/direct    1/rm32/ECX    .           .             .           .           .               4/imm32           # add 4 to ECX
    # size = *s
  8b/copy                         1/mod/*+disp8   4/rm32/SIB    4/base/ESP  4/index/none  .           2/r32/EDX   4/disp8         .                 # copy *(ESP+4) to EDX
  8b/copy                         0/mod/indirect  2/rm32/EDX    .           .             .           2/r32/EDX   .               .                 # copy *EDX to EDX
    # call write()
  b8/copy                         .               .             .           .             .           .           .               4/imm32/write     # copy 1 to EAX
  cd/syscall                      .               .             .           .             .           .           .               0x80/imm8         # int 80h
  # end
  c3/return

write_stdout:  # s : (address array byte) -> <void>
  # write(1/stdout, (data) s+4, (size) *s)
    # fd = 1 (stdout)
  bb/copy                         .               .             .           .             .           .           .               1/imm32           # copy 1 to EBX
    # x = s+4
  8b/copy                         1/mod/*+disp8   4/rm32/SIB    4/base/ESP  4/index/none  .           1/r32/ECX   4/disp8         .                 # copy *(ESP+4) to ECX
  81          0/subop/add         3/mod/direct    1/rm32/ECX    .           .             .           .           .               4/imm32           # add 4 to ECX
    # size = *s
  8b/copy                         1/mod/*+disp8   4/rm32/SIB    4/base/ESP  4/index/none  .           2/r32/EDX   4/disp8         .                 # copy *(ESP+4) to EDX
  8b/copy                         0/mod/indirect  2/rm32/EDX    .           .             .           2/r32/EDX   .               .                 # copy *EDX to EDX
    # call write()
  b8/copy                         .               .             .           .             .           .           .               4/imm32/write     # copy 1 to EAX
  cd/syscall                      .               .             .           .             .           .           .               0x80/imm8         # int 80h
  # end
  c3/return

== data
Newline:
  # size
  01 00 00 00
  # data
  0a/newline
Error:  # "Error: " : (array byte)
  # size
  07 00 00 00
  # data
  45/E 72/r 72/r 6f/o 72/r 3a/: 20/space
Expected_suffix:  # " expected" : (array byte)
  # size
  09 00 00 00
  # data
  20/space 65/e 78/x 70/p 65/e 63/c 74/t 65/e 64/d
Error_integer:  # "Integer" : (array byte)
  # size
  07 00 00 00
  # data
  49/I 6e/n 74/t 65/e 67/g 65/e 72/r