https://github.com/akkartik/mu/blob/main/linux/crenshaw2-1b.subx
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 == code
29
30
31
32
33 Entry:
34
35 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . .
36
37
38
39
40 68/push Heap/imm32
41 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Heap-size/disp32
42
43 e8/call new-segment/disp32
44
45 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32
46
47
48
49 81 7/subop/compare 1/mod/*+disp8 5/rm32/ebp . . . . 0/disp8 1/imm32
50 7e/jump-if-<= $run-main/disp8
51
52
53
54 68/push "test"/imm32
55 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 .
56
57 e8/call kernel-string-equal?/disp32
58
59 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32
60
61 3d/compare-eax-and 0/imm32/false
62 74/jump-if-= $run-main/disp8
63
64 e8/call run-tests/disp32
65
66 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/ebx Num-test-failures/disp32
67 eb/jump $main:end/disp8
68 $run-main:
69
70
71
72 68/push 0/imm32/exit-descriptor
73 68/push 2/imm32/stderr
74 68/push 1/imm32/stdout
75 68/push Stdin/imm32
76
77 e8/call compile/disp32
78
79 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32
80
81 bb/copy-to-ebx 0/imm32
82 $main:end:
83 e8/call syscall_exit/disp32
84
85
86 compile:
87
88 55/push-ebp
89 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . .
90
91 50/push-eax
92 51/push-ecx
93
94
95
96 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 .
97
98 e8/call get-char/disp32
99
100 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32
101
102
103
104
105
106 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x13/imm32
107 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . .
108
109
110 c7 0/subop/copy 1/mod/*+disp8 1/rm32/ecx . . . . 8/disp8 7/imm32
111
112
113 51/push-ecx
114
115 e8/call clear-stream/disp32
116
117 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32
118
119
120
121 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x14/disp8 .
122 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 .
123 51/push-ecx/num
124 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 .
125
126 e8/call get-num/disp32
127
128 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32
129
130
131
132
133
134
135
136 68/push "bb/copy-to-ebx "/imm32
137 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 .
138
139 e8/call write/disp32
140
141 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32
142
143
144 51/push-ecx/num
145 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 .
146
147 e8/call write-stream/disp32
148
149 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32
150
151
152 68/push Newline/imm32
153 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 .
154
155 e8/call write/disp32
156
157 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32
158
159
160 68/push "b8/copy-to-eax 1/imm32/exit\n"/imm32
161 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 .
162
163 e8/call write/disp32
164
165 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32
166
167
168 68/push "cd/syscall 0x80/imm8\n"/imm32
169 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 .
170
171 e8/call write/disp32
172
173 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32
174 $compile:end:
175
176 59/pop-to-ecx
177 58/pop-to-eax
178
179 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . .
180 5d/pop-to-ebp
181 c3/return
182
183
184
185
186
187 get-num:
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213 55/push-ebp
214 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . .
215
216
217
218 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Look/disp32 .
219
220 e8/call digit?/disp32
221
222 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32
223
224 3d/compare-eax-and 0/imm32/false
225 75/jump-if-!= $get-num:main/disp8
226
227
228 68/push "integer"/imm32
229 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 .
230 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x14/disp8 .
231
232 e8/call expected/disp32
233
234 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32
235 $get-num:main:
236
237
238 50/push-eax
239 51/push-ecx
240 52/push-edx
241 53/push-ebx
242 56/push-esi
243 57/push-edi
244
245
246 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 .
247
248 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 0xc/disp8 .
249
250 8b/copy 0/mod/indirect 7/rm32/edi . . . 1/r32/ecx . .
251
252 8b/copy 1/mod/*+disp8 7/rm32/edi . . . 2/r32/edx 8/disp8 .
253 $get-num:loop:
254
255 39/compare 3/mod/direct 2/rm32/edx . . . 1/r32/ecx . .
256 7d/jump-if-< $get-num:loop-stage2/disp8
257
258
259 68/push "get-num: too many digits in number"/imm32
260 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 .
261 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x14/disp8 .
262
263 e8/call error/disp32
264
265 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32
266 $get-num:loop-stage2:
267
268 8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/edi 1/index/ecx . 3/r32/ebx 0xc/disp8 .
269 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/eax Look/disp32 .
270 88/copy-byte 0/mod/indirect 3/rm32/ebx . . . 0/r32/AL . .
271
272 41/increment-ecx
273
274
275 56/push-esi
276
277 e8/call get-char/disp32
278
279 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32
280
281
282
283 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Look/disp32 .
284
285 e8/call digit?/disp32
286
287 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32
288
289 3d/compare-eax-and 0/imm32/false
290 0f 85/jump-if-!= $get-num:loop/disp32
291 $get-num:loop-end:
292
293 89/copy 0/mod/indirect 7/rm32/edi . . . 1/r32/ecx . .
294 $get-num:end:
295
296 5f/pop-to-edi
297 5e/pop-to-esi
298 5b/pop-to-ebx
299 5a/pop-to-edx
300 59/pop-to-ecx
301 58/pop-to-eax
302
303 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . .
304 5d/pop-to-ebp
305 c3/return
306
307 test-get-num-reads-single-digit:
308
309
310 55/push-ebp
311 89/copy 3/mod/direct 5/rm32/ebp . . ="p">}
void
parse_cmd_three_args(void** state)
{
char* inp = "/cmd arg1 arg2 arg3";
gboolean result = FALSE;
gchar** args = parse_args(inp, 3, 3, &result);
assert_true(result);
assert_int_equal(3, g_strv_length(args));
assert_string_equal("arg1", args[0]);
assert_string_equal("arg2", args[1]);
assert_string_equal("arg3", args[2]);
g_strfreev(args);
}
void
parse_cmd_three_args_with_spaces(void** state)
{
char* inp = " /cmd arg1 arg2 arg3 ";
gboolean result = FALSE;
gchar** args = parse_args(inp, 3, 3, &result);
assert_true(result);
assert_int_equal(3, g_strv_length(args));
assert_string_equal("arg1", args[0]);
assert_string_equal("arg2", args[1]);
assert_string_equal("arg3", args[2]);
g_strfreev(args);
}
void
parse_cmd_with_freetext(void** state)
{
char* inp = "/cmd this is some free text";
gboolean result = FALSE;
gchar** args = parse_args_with_freetext(inp, 1, 1, &result);
assert_true(result);
assert_int_equal(1, g_strv_length(args));
assert_string_equal("this is some free text", args[0]);
g_strfreev(args);
}
void
parse_cmd_one_arg_with_freetext(void** state)
{
char* inp = "/cmd arg1 this is some free text";
gboolean result = FALSE;
gchar** args = parse_args_with_freetext(inp, 1, 2, &result);
assert_true(result);
assert_int_equal(2, g_strv_length(args));
assert_string_equal("arg1", args[0]);
assert_string_equal("this is some free text", args[1]);
g_strfreev(args);
}
void
parse_cmd_two_args_with_freetext(void** state)
{
char* inp = "/cmd arg1 arg2 this is some free text";
gboolean result = FALSE;
gchar** args = parse_args_with_freetext(inp, 1, 3, &result);
assert_true(result);
assert_int_equal(3, g_strv_length(args));
assert_string_equal("arg1", args[0]);
assert_string_equal("arg2", args[1]);
assert_string_equal("this is some free text", args[2]);
g_strfreev(args);
}
void
parse_cmd_min_zero(void** state)
{
char* inp = "/cmd";
gboolean result = FALSE;
gchar** args = parse_args(inp, 0, 2, &result);
assert_true(result);
assert_int_equal(0, g_strv_length(args));
assert_null(args[0]);
g_strfreev(args);
}
void
parse_cmd_min_zero_with_freetext(void** state)
{
char* inp = "/cmd";
gboolean result = FALSE;
gchar** args = parse_args_with_freetext(inp, 0, 2, &result);
assert_true(result);
assert_int_equal(0, g_strv_length(args));
assert_null(args[0]);
g_strfreev(args);
}
void
parse_cmd_with_quoted(void** state)
{
char* inp = "/cmd \"arg1\" arg2";
gboolean result = FALSE;
gchar** args = parse_args(inp, 2, 2, &result);
assert_true(result);
assert_int_equal(2, g_strv_length(args));
assert_string_equal("arg1", args[0]);
assert_string_equal("arg2", args[1]);
g_strfreev(args);
}
void
parse_cmd_with_quoted_and_space(void** state)
{
char* inp = "/cmd \"the arg1\" arg2";
gboolean result = FALSE;
gchar** args = parse_args(inp, 2, 2, &result);
assert_true(result);
assert_int_equal(2, g_strv_length(args));
assert_string_equal("the arg1", args[0]);
assert_string_equal("arg2", args[1]);
g_strfreev(args);
}
void
parse_cmd_with_quoted_and_many_spaces(void** state)
{
char* inp = "/cmd \"the arg1 is here\" arg2";
gboolean result = FALSE;
gchar** args = parse_args(inp, 2, 2, &result);
assert_true(result);
assert_int_equal(2, g_strv_length(args));
assert_string_equal("the arg1 is here", args[0]);
assert_string_equal("arg2", args[1]);
g_strfreev(args);
}
void
parse_cmd_with_many_quoted_and_many_spaces(void** state)
{
char* inp = "/cmd \"the arg1 is here\" \"and arg2 is right here\"";
gboolean result = FALSE;
gchar** args = parse_args(inp, 2, 2, &result);
assert_true(result);
assert_int_equal(2, g_strv_length(args));
assert_string_equal("the arg1 is here", args[0]);
assert_string_equal("and arg2 is right here", args[1]);
g_strfreev(args);
}
void
parse_cmd_freetext_with_quoted(void** state)
{
char* inp = "/cmd \"arg1\" arg2 hello there what's up";
gboolean result = FALSE;
gchar** args = parse_args_with_freetext(inp, 3, 3, &result);
assert_true(result);
assert_int_equal(3, g_strv_length(args));
assert_string_equal("arg1", args[0]);
assert_string_equal("arg2", args[1]);
assert_string_equal("hello there what's up", args[2]);
g_strfreev(args);
}
void
parse_cmd_freetext_with_quoted_and_space(void** state)
{
char* inp = "/cmd \"the arg1\" arg2 another bit of freetext";
gboolean result = FALSE;
gchar** args = parse_args_with_freetext(inp, 3, 3, &result);
assert_true(result);
assert_int_equal(3, g_strv_length(args));
assert_string_equal("the arg1", args[0]);
assert_string_equal("arg2", args[1]);
assert_string_equal("another bit of freetext", args[2]);
g_strfreev(args);
}
void
parse_cmd_freetext_with_quoted_and_many_spaces(void** state)
{
char* inp = "/cmd \"the arg1 is here\" arg2 some more freetext";
gboolean result = FALSE;
gchar** args = parse_args_with_freetext(inp, 3, 3, &result);
assert_true(result);
assert_int_equal(3, g_strv_length(args));
assert_string_equal("the arg1 is here", args[0]);
assert_string_equal("arg2", args[1]);
assert_string_equal("some more freetext", args[2]);
g_strfreev(args);
}
void
parse_cmd_freetext_with_many_quoted_and_many_spaces(void** state)
{
char* inp = "/cmd \"the arg1 is here\" \"and arg2 is right here\" and heres the free text";
gboolean result = FALSE;
gchar** args = parse_args_with_freetext(inp, 3, 3, &result);
assert_true(result);
assert_int_equal(3, g_strv_length(args));
assert_string_equal("the arg1 is here", args[0]);
assert_string_equal("and arg2 is right here", args[1]);
assert_string_equal("and heres the free text", args[2]);
g_strfreev(args);
}
void
parse_cmd_with_quoted_freetext(void** state)
{
char* inp = "/cmd arg1 here is \"some\" quoted freetext";
gboolean result = FALSE;
gchar** args = parse_args_with_freetext(inp, 1, 2, &result);
assert_true(result);
assert_int_equal(2, g_strv_length(args));
assert_string_equal("arg1", args[0]);
assert_string_equal("here is \"some\" quoted freetext", args[1]);
g_strfreev(args);
}
void
parse_cmd_with_third_arg_quoted_0_min_3_max(void** state)
{
char* inp = "/group add friends \"The User\"";
gboolean result = FALSE;
gchar** args = parse_args_with_freetext(inp, 0, 3, &result);
assert_true(result);
assert_int_equal(3, g_strv_length(args));
assert_string_equal("add", args[0]);
assert_string_equal("friends", args[1]);
assert_string_equal("The User", args[2]);
g_strfreev(args);
}
void
parse_cmd_with_second_arg_quoted_0_min_3_max(void** state)
{
char* inp = "/group add \"The Group\" friend";
gboolean result = FALSE;
gchar** args = parse_args_with_freetext(inp, 0, 3, &result);
assert_true(result);
assert_int_equal(3, g_strv_length(args));
assert_string_equal("add", args[0]);
assert_string_equal("The Group", args[1]);
assert_string_equal("friend", args[2]);
g_strfreev(args);
}
void
parse_cmd_with_second_and_third_arg_quoted_0_min_3_max(void** state)
{
char* inp = "/group add \"The Group\" \"The User\"";
gboolean result = FALSE;
gchar** args = parse_args_with_freetext(inp, 0, 3, &result);
assert_true(result);
assert_int_equal(3, g_strv_length(args));
assert_string_equal("add", args[0]);
assert_string_equal("The Group", args[1]);
assert_string_equal("The User", args[2]);
g_strfreev(args);
}
void
count_one_token(void** state)
{
char* inp = "one";
int result = count_tokens(inp);
assert_int_equal(1, result);
}
void
count_one_token_quoted_no_whitespace(void** state)
{
char* inp = "\"one\"";
int result = count_tokens(inp);
assert_int_equal(1, result);
}
void
count_one_token_quoted_with_whitespace(void** state)
{
char* inp = "\"one two\"";
int result = count_tokens(inp);
assert_int_equal(1, result);
}
void
count_two_tokens(void** state)
{
char* inp = "one two";
int result = count_tokens(inp);
assert_int_equal(2, result);
}
void
count_two_tokens_first_quoted(void** state)
{
char* inp = "\"one and\" two";
int result = count_tokens(inp);
assert_int_equal(2, result);
}
void
count_two_tokens_second_quoted(void** state)
{
char* inp = "one \"two and\"";
int result = count_tokens(inp);
assert_int_equal(2, result);
}
void
count_two_tokens_both_quoted(void** state)
{
char* inp = "\"one and then\" \"two and\"";
int result = count_tokens(inp);
assert_int_equal(2, result);
}
void
get_first_of_one(void** state)
{
char* inp = "one";
char* result = get_start(inp, 2);
assert_string_equal("one", result);
free(result);
}
void
get_first_of_two(void** state)
{
char* inp = "one two";
char* result = get_start(inp, 2);
assert_string_equal("one ", result);
free(result);
}
void
get_first_two_of_three(void** state)
{
char* inp = "one two three";
char* result = get_start(inp, 3);
assert_string_equal("one two ", result);
free(result);
}
void
get_first_two_of_three_first_quoted(void** state)
{
char* inp = "\"one\" two three";
char* result = get_start(inp, 3);
assert_string_equal("\"one\" two ", result);
free(result);
}
void
get_first_two_of_three_s