From 332cbba31f60c3915ba109a14105d4e8f7369a7a Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Sun, 20 Jan 2019 22:50:44 -0800 Subject: 4937 --- html/subx/071next-token.subx.html | 1293 ++++++++++++++++++++++++------------- subx/071next-token.subx | 416 +++++++++++- subx/apps/crenshaw2-1 | Bin 14148 -> 15313 bytes subx/apps/crenshaw2-1b | Bin 14707 -> 15872 bytes subx/apps/factorial | Bin 13066 -> 14231 bytes subx/apps/handle | Bin 13859 -> 15024 bytes subx/apps/hex | Bin 17127 -> 18292 bytes subx/apps/pack.subx | 25 +- 8 files changed, 1282 insertions(+), 452 deletions(-) diff --git a/html/subx/071next-token.subx.html b/html/subx/071next-token.subx.html index 814a4672..005a425a 100644 --- a/html/subx/071next-token.subx.html +++ b/html/subx/071next-token.subx.html @@ -18,11 +18,12 @@ a { color:inherit; } .subxS2Comment { color: #8a8a8a; } .LineNr { } .subxS1Comment { color: #0000af; } -.SpecialChar { color: #d70000; } +.CommentedCode { color: #8a8a8a; } .subxFunction { color: #af5f00; text-decoration: underline; } .subxTest { color: #5f8700; } .Constant { color: #008787; } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } +.SpecialChar { color: #d70000; } --> @@ -64,448 +65,854 @@ if ('onhashchange' in window) { 4 # . 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 5 6 # main: - 7 e8/call run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'. - 8 # syscall(exit, Num-test-failures) - 9 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX - 10 b8/copy-to-EAX 1/imm32/exit - 11 cd/syscall 0x80/imm8 - 12 - 13 # extract the next run of characters that are different from a given 'delimiter' - 14 # on eof return an empty interval - 15 next-token: # in : (address stream), delimiter : byte, out : (address slice) - 16 # . prolog - 17 55/push-EBP - 18 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 19 # . save registers - 20 50/push-EAX - 21 51/push-ECX - 22 56/push-ESI - 23 57/push-EDI - 24 # ESI = in - 25 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI - 26 # EDI = out - 27 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 0x10/disp8 . # copy *(EBP+16) to EDI - 28 # skip-chars-matching(in, delimiter) - 29 # . . push args - 30 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 31 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - 32 # . . call - 33 e8/call skip-chars-matching/disp32 - 34 # . . discard args - 35 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 36 # out->start = &in->data[in->read] - 37 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX - 38 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/EAX 0xc/disp8 . # copy ESI+ECX+12 to EAX - 39 89/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy EAX to *EDI - 40 # skip-chars-not-matching(in, delimiter) - 41 # . . push args - 42 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 43 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - 44 # . . call - 45 e8/call skip-chars-not-matching/disp32 - 46 # . . discard args - 47 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 48 # out->end = &in->data[in->read] - 49 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX - 50 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/EAX 0xc/disp8 . # copy ESI+ECX+12 to EAX - 51 89/copy 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDI+4) - 52 # . restore registers - 53 5f/pop-to-EDI - 54 5e/pop-to-ESI - 55 59/pop-to-ECX - 56 58/pop-to-EAX - 57 # . epilog - 58 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 59 5d/pop-to-EBP - 60 c3/return - 61 - 62 test-next-token: - 63 # . prolog - 64 55/push-EBP - 65 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 66 # setup - 67 # . clear-stream(_test-stream) - 68 # . . push args - 69 68/push _test-stream/imm32 - 70 # . . call - 71 e8/call clear-stream/disp32 - 72 # . . discard args - 73 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 74 # var slice/ECX = {0, 0} - 75 68/push 0/imm32/end - 76 68/push 0/imm32/start - 77 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - 78 # write(_test-stream, " ab") - 79 # . . push args - 80 68/push " ab"/imm32 - 81 68/push _test-stream/imm32 - 82 # . . call - 83 e8/call write/disp32 - 84 # . . discard args - 85 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 86 # next-token(_test-stream, 0x20/space, slice) - 87 # . . push args - 88 51/push-ECX - 89 68/push 0x20/imm32 - 90 68/push _test-stream/imm32 - 91 # . . call - 92 e8/call next-token/disp32 - 93 # . . discard args - 94 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - 95 # check-ints-equal(slice->start - _test-stream->data, 2, msg) - 96 # . check-ints-equal(slice->start - _test-stream, 14, msg) - 97 # . . push args - 98 68/push "F - test-next-token: start"/imm32 - 99 68/push 0xe/imm32 -100 # . . push slice->start - _test-stream -101 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX -102 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-stream/imm32 # subtract from EAX -103 50/push-EAX -104 # . . call -105 e8/call check-ints-equal/disp32 -106 # . . discard args -107 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -108 # check-ints-equal(slice->end - _test-stream->data, 4, msg) -109 # . check-ints-equal(slice->end - _test-stream, 16, msg) -110 # . . push args -111 68/push "F - test-next-token: end"/imm32 -112 68/push 0x10/imm32 -113 # . . push slice->end - _test-stream -114 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX -115 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-stream/imm32 # subtract from EAX -116 50/push-EAX -117 # . . call -118 e8/call check-ints-equal/disp32 -119 # . . discard args -120 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -121 # . epilog -122 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -123 5d/pop-to-EBP -124 c3/return -125 -126 test-next-token-eof: -127 # . prolog -128 55/push-EBP -129 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -130 # setup -131 # . clear-stream(_test-stream) -132 # . . push args -133 68/push _test-stream/imm32 -134 # . . call -135 e8/call clear-stream/disp32 -136 # . . discard args -137 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -138 # var slice/ECX = {0, 0} -139 68/push 0/imm32/end -140 68/push 0/imm32/start -141 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -142 # write nothing to _test-stream -143 # next-token(_test-stream, 0x20/space, slice) -144 # . . push args -145 51/push-ECX -146 68/push 0x20/imm32 -147 68/push _test-stream/imm32 -148 # . . call -149 e8/call next-token/disp32 -150 # . . discard args -151 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -152 # check-ints-equal(slice->end, slice->start, msg) -153 # . . push args -154 68/push "F - test-next-token-eof"/imm32 -155 ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+4) -156 ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX -157 # . . call -158 e8/call check-ints-equal/disp32 -159 # . . discard args -160 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -161 # . epilog -162 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -163 5d/pop-to-EBP -164 c3/return -165 -166 skip-chars-matching: # in : (address stream), delimiter : byte -167 # . prolog -168 55/push-EBP -169 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -170 # . save registers -171 50/push-EAX -172 51/push-ECX -173 52/push-EDX -174 56/push-ESI -175 # ESI = in -176 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI -177 # ECX = in->read -178 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX -179 # EBX = in->write -180 8b/copy 0/mod/indirect 6/rm32/ESI . . . 3/r32/EBX . . # copy *ESI to EBX -181 # EDX = delimiter -182 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 2/r32/EDX 0xc/disp8 . # copy *(EBP+12) to EDX -183 $skip-chars-matching:loop: -184 # if (in->read >= in->write) break -185 3b/compare 3/mod/direct 3/rm32/EBX . . . 1/r32/ECX . . # compare ECX with *EBX -186 7d/jump-if-greater-or-equal $skip-chars-matching:end/disp8 -187 # EAX = in->data[in->read] -188 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX -189 8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/AL 0xc/disp8 . # copy byte at *(ESI+ECX+12) to AL -190 # if (EAX != delimiter) break -191 39/compare 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # compare EAX and EDX -192 75/jump-if-not-equal $skip-chars-matching:end/disp8 -193 # ++in->read -194 41/inc-ECX -195 eb/jump $skip-chars-matching:loop/disp8 -196 $skip-chars-matching:end: -197 # persist in->read -198 89/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy ECX to *(ESI+4) -199 # . restore registers -200 5e/pop-to-ESI -201 5a/pop-to-EDX -202 59/pop-to-ECX -203 58/pop-to-EAX -204 # . epilog -205 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -206 5d/pop-to-EBP -207 c3/return -208 -209 test-skip-chars-matching: -210 # setup -211 # . clear-stream(_test-stream) -212 # . . push args -213 68/push _test-stream/imm32 -214 # . . call -215 e8/call clear-stream/disp32 -216 # . . discard args -217 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -218 # write(_test-stream, " ab") -219 # . . push args -220 68/push " ab"/imm32 -221 68/push _test-stream/imm32 -222 # . . call -223 e8/call write/disp32 -224 # . . discard args -225 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -226 # skip-chars-matching(_test-stream, 0x20/space) -227 # . . push args -228 68/push 0x20/imm32 -229 68/push _test-stream/imm32 -230 # . . call -231 e8/call skip-chars-matching/disp32 -232 # . . discard args -233 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -234 # check-ints-equal(_test-stream->read, 2, msg) -235 # . . push args -236 68/push "F - test-skip-chars-matching"/imm32 -237 68/push 2/imm32 -238 # . . push *_test-stream->read -239 b8/copy-to-EAX _test-stream/imm32 -240 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) -241 # . . call -242 e8/call check-ints-equal/disp32 -243 # . . discard args -244 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -245 # end -246 c3/return -247 -248 test-skip-chars-matching-none: -249 # setup -250 # . clear-stream(_test-stream) -251 # . . push args -252 68/push _test-stream/imm32 -253 # . . call -254 e8/call clear-stream/disp32 -255 # . . discard args -256 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -257 # write(_test-stream, "ab") -258 # . . push args -259 68/push "ab"/imm32 -260 68/push _test-stream/imm32 -261 # . . call -262 e8/call write/disp32 -263 # . . discard args -264 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -265 # skip-chars-matching(_test-stream, 0x20/space) -266 # . . push args -267 68/push 0x20/imm32 -268 68/push _test-stream/imm32 -269 # . . call -270 e8/call skip-chars-matching/disp32 -271 # . . discard args -272 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -273 # check-ints-equal(_test-stream->read, 0, msg) -274 # . . push args -275 68/push "F - test-skip-chars-matching-none"/imm32 -276 68/push 0/imm32 -277 # . . push *_test-stream->read -278 b8/copy-to-EAX _test-stream/imm32 -279 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) -280 # . . call -281 e8/call check-ints-equal/disp32 -282 # . . discard args -283 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -284 # end -285 c3/return -286 -287 # minor fork of 'skip-chars-matching' -288 skip-chars-not-matching: # in : (address stream), delimiter : byte -289 # . prolog -290 55/push-EBP -291 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -292 # . save registers -293 50/push-EAX -294 51/push-ECX -295 52/push-EDX -296 56/push-ESI -297 # ESI = in -298 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI -299 # ECX = in->read -300 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX -301 # EBX = in->write -302 8b/copy 0/mod/indirect 6/rm32/ESI . . . 3/r32/EBX . . # copy *ESI to EBX -303 # EDX = delimiter -304 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 2/r32/EDX 0xc/disp8 . # copy *(EBP+12) to EDX -305 $skip-chars-not-matching:loop: -306 # if (in->read >= in->write) break -307 3b/compare 3/mod/direct 3/rm32/EBX . . . 1/r32/ECX . . # compare ECX with *EBX -308 7d/jump-if-greater-or-equal $skip-chars-not-matching:end/disp8 -309 # EAX = in->data[in->read] -310 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX -311 8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/AL 0xc/disp8 . # copy byte at *(ESI+ECX+12) to AL -312 # if (EAX == delimiter) break -313 39/compare 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # compare EAX and EDX -314 74/jump-if-equal $skip-chars-not-matching:end/disp8 -315 # ++in->read -316 41/inc-ECX -317 eb/jump $skip-chars-not-matching:loop/disp8 -318 $skip-chars-not-matching:end: -319 # persist in->read -320 89/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy ECX to *(ESI+4) -321 # . restore registers -322 5e/pop-to-ESI -323 5a/pop-to-EDX -324 59/pop-to-ECX -325 58/pop-to-EAX -326 # . epilog -327 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP -328 5d/pop-to-EBP -329 c3/return -330 -331 test-skip-chars-not-matching: -332 # setup -333 # . clear-stream(_test-stream) -334 # . . push args -335 68/push _test-stream/imm32 -336 # . . call -337 e8/call clear-stream/disp32 -338 # . . discard args -339 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -340 # write(_test-stream, "ab ") -341 # . . push args -342 68/push "ab "/imm32 -343 68/push _test-stream/imm32 -344 # . . call -345 e8/call write/disp32 -346 # . . discard args -347 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -348 # skip-chars-not-matching(_test-stream, 0x20/space) -349 # . . push args -350 68/push 0x20/imm32 -351 68/push _test-stream/imm32 -352 # . . call -353 e8/call skip-chars-not-matching/disp32 -354 # . . discard args -355 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -356 # check-ints-equal(_test-stream->read, 2, msg) -357 # . . push args -358 68/push "F - test-skip-chars-not-matching"/imm32 -359 68/push 2/imm32 -360 # . . push *_test-stream->read -361 b8/copy-to-EAX _test-stream/imm32 -362 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) -363 # . . call -364 e8/call check-ints-equal/disp32 -365 # . . discard args -366 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -367 # end -368 c3/return -369 -370 test-skip-chars-not-matching-none: -371 # setup -372 # . clear-stream(_test-stream) -373 # . . push args -374 68/push _test-stream/imm32 -375 # . . call -376 e8/call clear-stream/disp32 -377 # . . discard args -378 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -379 # write(_test-stream, " ab") -380 # . . push args -381 68/push " ab"/imm32 -382 68/push _test-stream/imm32 -383 # . . call -384 e8/call write/disp32 -385 # . . discard args -386 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -387 # skip-chars-not-matching(_test-stream, 0x20/space) -388 # . . push args -389 68/push 0x20/imm32 -390 68/push _test-stream/imm32 -391 # . . call -392 e8/call skip-chars-not-matching/disp32 -393 # . . discard args -394 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -395 # check-ints-equal(_test-stream->read, 0, msg) -396 # . . push args -397 68/push "F - test-skip-chars-not-matching-none"/imm32 -398 68/push 0/imm32 -399 # . . push *_test-stream->read -400 b8/copy-to-EAX _test-stream/imm32 -401 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) -402 # . . call -403 e8/call check-ints-equal/disp32 -404 # . . discard args -405 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -406 # end -407 c3/return -408 -409 test-skip-chars-not-matching-all: -410 # setup -411 # . clear-stream(_test-stream) -412 # . . push args -413 68/push _test-stream/imm32 -414 # . . call -415 e8/call clear-stream/disp32 -416 # . . discard args -417 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -418 # write(_test-stream, "ab") -419 # . . push args -420 68/push "ab"/imm32 -421 68/push _test-stream/imm32 -422 # . . call -423 e8/call write/disp32 -424 # . . discard args -425 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -426 # skip-chars-not-matching(_test-stream, 0x20/space) -427 # . . push args -428 68/push 0x20/imm32 -429 68/push _test-stream/imm32 -430 # . . call -431 e8/call skip-chars-not-matching/disp32 -432 # . . discard args -433 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -434 # check-ints-equal(_test-stream->read, 2, msg) -435 # . . push args -436 68/push "F - test-skip-chars-not-matching-all"/imm32 -437 68/push 2/imm32 -438 # . . push *_test-stream->read -439 b8/copy-to-EAX _test-stream/imm32 -440 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) -441 # . . call -442 e8/call check-ints-equal/disp32 -443 # . . discard args -444 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -445 # end -446 c3/return -447 -448 # . . vim:nowrap:textwidth=0 + 7 #? e8/call test-skip-chars-matching-in-slice/disp32 + 8 e8/call run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'. + 9 # syscall(exit, Num-test-failures) + 10 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX + 11 b8/copy-to-EAX 1/imm32/exit + 12 cd/syscall 0x80/imm8 + 13 + 14 # extract the next run of characters that are different from a given 'delimiter' (skipping multiple delimiters if necessary) + 15 # on eof return an empty interval + 16 next-token: # in : (address stream), delimiter : byte, out : (address slice) + 17 # . prolog + 18 55/push-EBP + 19 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 20 # . save registers + 21 50/push-EAX + 22 51/push-ECX + 23 56/push-ESI + 24 57/push-EDI + 25 # ESI = in + 26 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI + 27 # EDI = out + 28 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 0x10/disp8 . # copy *(EBP+16) to EDI + 29 # skip-chars-matching(in, delimiter) + 30 # . . push args + 31 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) + 32 56/push-ESI + 33 # . . call + 34 e8/call skip-chars-matching/disp32 + 35 # . . discard args + 36 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 37 # out->start = &in->data[in->read] + 38 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX + 39 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/EAX 0xc/disp8 . # copy ESI+ECX+12 to EAX + 40 89/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy EAX to *EDI + 41 # skip-chars-not-matching(in, delimiter) + 42 # . . push args + 43 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) + 44 56/push-ESI + 45 # . . call + 46 e8/call skip-chars-not-matching/disp32 + 47 # . . discard args + 48 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 49 # out->end = &in->data[in->read] + 50 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX + 51 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/EAX 0xc/disp8 . # copy ESI+ECX+12 to EAX + 52 89/copy 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDI+4) + 53 # . restore registers + 54 5f/pop-to-EDI + 55 5e/pop-to-ESI + 56 59/pop-to-ECX + 57 58/pop-to-EAX + 58 # . epilog + 59 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 60 5d/pop-to-EBP + 61 c3/return + 62 + 63 test-next-token: + 64 # . prolog + 65 55/push-EBP + 66 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 67 # setup + 68 # . clear-stream(_test-stream) + 69 # . . push args + 70 68/push _test-stream/imm32 + 71 # . . call + 72 e8/call clear-stream/disp32 + 73 # . . discard args + 74 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 75 # var slice/ECX = {0, 0} + 76 68/push 0/imm32/end + 77 68/push 0/imm32/start + 78 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX + 79 # write(_test-stream, " ab") + 80 # . . push args + 81 68/push " ab"/imm32 + 82 68/push _test-stream/imm32 + 83 # . . call + 84 e8/call write/disp32 + 85 # . . discard args + 86 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 87 # next-token(_test-stream, 0x20/space, slice) + 88 # . . push args + 89 51/push-ECX + 90 68/push 0x20/imm32 + 91 68/push _test-stream/imm32 + 92 # . . call + 93 e8/call next-token/disp32 + 94 # . . discard args + 95 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + 96 # check-ints-equal(slice->start - _test-stream->data, 2, msg) + 97 # . check-ints-equal(slice->start - _test-stream, 14, msg) + 98 # . . push args + 99 68/push "F - test-next-token: start"/imm32 +100 68/push 0xe/imm32 +101 # . . push slice->start - _test-stream +102 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX +103 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-stream/imm32 # subtract from EAX +104 50/push-EAX +105 # . . call +106 e8/call check-ints-equal/disp32 +107 # . . discard args +108 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +109 # check-ints-equal(slice->end - _test-stream->data, 4, msg) +110 # . check-ints-equal(slice->end - _test-stream, 16, msg) +111 # . . push args +112 68/push "F - test-next-token: end"/imm32 +113 68/push 0x10/imm32 +114 # . . push slice->end - _test-stream +115 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX +116 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-stream/imm32 # subtract from EAX +117 50/push-EAX +118 # . . call +119 e8/call check-ints-equal/disp32 +120 # . . discard args +121 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +122 # . epilog +123 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +124 5d/pop-to-EBP +125 c3/return +126 +127 test-next-token-eof: +128 # . prolog +129 55/push-EBP +130 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +131 # setup +132 # . clear-stream(_test-stream) +133 # . . push args +134 68/push _test-stream/imm32 +135 # . . call +136 e8/call clear-stream/disp32 +137 # . . discard args +138 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +139 # var slice/ECX = {0, 0} +140 68/push 0/imm32/end +141 68/push 0/imm32/start +142 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX +143 # write nothing to _test-stream +144 # next-token(_test-stream, 0x20/space, slice) +145 # . . push args +146 51/push-ECX +147 68/push 0x20/imm32 +148 68/push _test-stream/imm32 +149 # . . call +150 e8/call next-token/disp32 +151 # . . discard args +152 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +153 # check-ints-equal(slice->end, slice->start, msg) +154 # . . push args +155 68/push "F - test-next-token-eof"/imm32 +156 ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+4) +157 ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX +158 # . . call +159 e8/call check-ints-equal/disp32 +160 # . . discard args +161 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +162 # . epilog +163 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +164 5d/pop-to-EBP +165 c3/return +166 +167 # extract the next run of characters that are different from a given 'delimiter' (skipping multiple delimiters if necessary) +168 # on eof return an empty interval +169 next-token-from-slice: # in : (address slice), delimiter : byte, out : (address slice) +170 # . prolog +171 55/push-EBP +172 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +173 # . save registers +174 50/push-EAX +175 56/push-ESI +176 57/push-EDI +177 # ESI = in +178 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI +179 # EDI = out +180 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 0x10/disp8 . # copy *(EBP+16) to EDI +181 # EAX = skip-chars-matching-in-slice(in->start, in->end, delimiter) +182 # . . push args +183 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +184 ff 6/subop/push 1/mod/*+disp8 6/rm32/ESI . . . . 4/disp8 . # push *(ESI+4) +185 ff 6/subop/push 0/mod/indirect 6/rm32/ESI . . . . . . # push *ESI +186 # . . call +187 e8/call skip-chars-matching-in-slice/disp32 +188 # . . discard args +189 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +190 # out->start = EAX +191 89/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy EAX to *EDI +192 # EAX = skip-chars-not-matching-in-slice(EAX, in->end, delimiter) +193 # . . push args +194 ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) +195 ff 6/subop/push 1/mod/*+disp8 6/rm32/ESI . . . . 4/disp8 . # push *(ESI+4) +196 50/push-EAX +197 # . . call +198 e8/call skip-chars-not-matching-in-slice/disp32 +199 # . . discard args +200 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +201 # out->end = EAX +202 89/copy 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDI+4) +203 # . restore registers +204 5f/pop-to-EDI +205 5e/pop-to-ESI +206 58/pop-to-EAX +207 # . epilog +208 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +209 5d/pop-to-EBP +210 c3/return +211 +212 test-next-token-from-slice: +213 # . prolog +214 55/push-EBP +215 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +216 # (EAX..ECX) = " ab" +217 b8/copy-to-EAX " ab"/imm32 +218 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +219 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +220 05/add-to-EAX 4/imm32 +221 # var in/ESI : (address slice) = {EAX, ECX} +222 51/push-ECX +223 50/push-EAX +224 89/copy 3/mod/direct 6/rm32/ESI . . . 4/r32/ESP . . # copy ESP to ESI +225 # var out/EDI : (address slice) = {0, 0} +226 68/push 0/imm32/end +227 68/push 0/imm32/start +228 89/copy 3/mod/direct 7/rm32/EDI . . . 4/r32/ESP . . # copy ESP to EDI +229 # next-token-from-slice(in, 0x20/space, out) +230 # . . push args +231 57/push-EDI +232 68/push 0x20/imm32 +233 56/push-ESI +234 # . . call +235 e8/call next-token-from-slice/disp32 +236 # . . discard args +237 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +238 # out->start should be at the 'a' +239 # . check-ints-equal(out->start - in->start, 2, msg) +240 # . . push args +241 68/push "F - test-next-token-from-slice: start"/imm32 +242 68/push 2/imm32 +243 # . . push out->start - in->start +244 8b/copy 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # copy *EDI to ECX +245 2b/subtract 0/mod/indirect 6/rm32/ESI . . . 1/r32/ECX . . # subtract *ESI from ECX +246 51/push-ECX +247 # . . call +248 e8/call check-ints-equal/disp32 +249 # . . discard args +250 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +251 # out->end should be after the 'b' +252 # check-ints-equal(out->end - in->start, 4, msg) +253 # . . push args +254 68/push "F - test-next-token-from-slice: end"/imm32 +255 68/push 4/imm32 +256 # . . push out->end - in->start +257 8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 1/r32/ECX 4/disp8 . # copy *(EDI+4) to ECX +258 2b/subtract 0/mod/indirect 6/rm32/ESI . . . 1/r32/ECX . . # subtract *ESI from ECX +259 51/push-ECX +260 # . . call +261 e8/call check-ints-equal/disp32 +262 # . . discard args +263 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +264 # . epilog +265 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +266 5d/pop-to-EBP +267 c3/return +268 +269 test-next-token-from-slice-eof: +270 # . prolog +271 55/push-EBP +272 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +273 # var in/ESI : (address slice) = {0, 0} +274 51/push-ECX +275 50/push-EAX +276 89/copy 3/mod/direct 6/rm32/ESI . . . 4/r32/ESP . . # copy ESP to ESI +277 # var out/EDI : (address slice) = {0, 0} +278 68/push 0/imm32/end +279 68/push 0/imm32/start +280 89/copy 3/mod/direct 7/rm32/EDI . . . 4/r32/ESP . . # copy ESP to EDI +281 # next-token-from-slice(in, 0x20/space, out) +282 # . . push args +283 57/push-EDI +284 68/push 0x20/imm32 +285 56/push-ESI +286 # . . call +287 e8/call next-token-from-slice/disp32 +288 # . . discard args +289 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +290 # out should be empty +291 # . check-ints-equal(out->end - out->start, 0, msg) +292 # . . push args +293 68/push "F - test-next-token-from-slice-eof"/imm32 +294 68/push 0/imm32 +295 # . . push out->start - in->start +296 8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 1/r32/ECX 4/disp8 . # copy *(EDI+4) to ECX +297 2b/subtract 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # subtract *EDI from ECX +298 51/push-ECX +299 # . . call +300 e8/call check-ints-equal/disp32 +301 # . . discard args +302 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +303 # . epilog +304 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +305 5d/pop-to-EBP +306 c3/return +307 +308 test-next-token-from-slice-nothing: +309 # . prolog +310 55/push-EBP +311 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +312 # (EAX..ECX) = " " +313 b8/copy-to-EAX " "/imm32 +314 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +315 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +316 05/add-to-EAX 4/imm32 +317 # var in/ESI : (address slice) = {EAX, ECX} +318 51/push-ECX +319 50/push-EAX +320 89/copy 3/mod/direct 6/rm32/ESI . . . 4/r32/ESP . . # copy ESP to ESI +321 # var out/EDI : (address slice) = {0, 0} +322 68/push 0/imm32/end +323 68/push 0/imm32/start +324 89/copy 3/mod/direct 7/rm32/EDI . . . 4/r32/ESP . . # copy ESP to EDI +325 # next-token-from-slice(in, 0x20/space, out) +326 # . . push args +327 57/push-EDI +328 68/push 0x20/imm32 +329 56/push-ESI +330 # . . call +331 e8/call next-token-from-slice/disp32 +332 # . . discard args +333 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +334 # out should be empty +335 # . check-ints-equal(out->end - out->start, 0, msg) +336 # . . push args +337 68/push "F - test-next-token-from-slice-eof"/imm32 +338 68/push 0/imm32 +339 # . . push out->start - in->start +340 8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 1/r32/ECX 4/disp8 . # copy *(EDI+4) to ECX +341 2b/subtract 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # subtract *EDI from ECX +342 51/push-ECX +343 # . . call +344 e8/call check-ints-equal/disp32 +345 # . . discard args +346 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +347 # . epilog +348 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +349 5d/pop-to-EBP +350 c3/return +351 +352 skip-chars-matching: # in : (address stream), delimiter : byte +353 # . prolog +354 55/push-EBP +355 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +356 # . save registers +357 50/push-EAX +358 51/push-ECX +359 52/push-EDX +360 56/push-ESI +361 # ESI = in +362 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI +363 # ECX = in->read +364 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX +365 # EBX = in->write +366 8b/copy 0/mod/indirect 6/rm32/ESI . . . 3/r32/EBX . . # copy *ESI to EBX +367 # EDX = delimiter +368 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 2/r32/EDX 0xc/disp8 . # copy *(EBP+12) to EDX +369 $skip-chars-matching:loop: +370 # if (in->read >= in->write) break +371 39/compare 3/mod/direct 1/rm32/ECX . . . 3/r32/EBX . . # compare ECX with EBX +372 7d/jump-if-greater-or-equal $skip-chars-matching:end/disp8 +373 # EAX = in->data[in->read] +374 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX +375 8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/AL 0xc/disp8 . # copy byte at *(ESI+ECX+12) to AL +376 # if (EAX != delimiter) break +377 39/compare 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # compare EAX and EDX +378 75/jump-if-not-equal $skip-chars-matching:end/disp8 +379 # ++in->read +380 41/inc-ECX +381 eb/jump $skip-chars-matching:loop/disp8 +382 $skip-chars-matching:end: +383 # persist in->read +384 89/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy ECX to *(ESI+4) +385 # . restore registers +386 5e/pop-to-ESI +387 5a/pop-to-EDX +388 59/pop-to-ECX +389 58/pop-to-EAX +390 # . epilog +391 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +392 5d/pop-to-EBP +393 c3/return +394 +395 test-skip-chars-matching: +396 # setup +397 # . clear-stream(_test-stream) +398 # . . push args +399 68/push _test-stream/imm32 +400 # . . call +401 e8/call clear-stream/disp32 +402 # . . discard args +403 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +404 # write(_test-stream, " ab") +405 # . . push args +406 68/push " ab"/imm32 +407 68/push _test-stream/imm32 +408 # . . call +409 e8/call write/disp32 +410 # . . discard args +411 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +412 # skip-chars-matching(_test-stream, 0x20/space) +413 # . . push args +414 68/push 0x20/imm32 +415 68/push _test-stream/imm32 +416 # . . call +417 e8/call skip-chars-matching/disp32 +418 # . . discard args +419 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +420 # check-ints-equal(_test-stream->read, 2, msg) +421 # . . push args +422 68/push "F - test-skip-chars-matching"/imm32 +423 68/push 2/imm32 +424 # . . push *_test-stream->read +425 b8/copy-to-EAX _test-stream/imm32 +426 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) +427 # . . call +428 e8/call check-ints-equal/disp32 +429 # . . discard args +430 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +431 # end +432 c3/return +433 +434 test-skip-chars-matching-none: +435 # setup +436 # . clear-stream(_test-stream) +437 # . . push args +438 68/push _test-stream/imm32 +439 # . . call +440 e8/call clear-stream/disp32 +441 # . . discard args +442 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +443 # write(_test-stream, "ab") +444 # . . push args +445 68/push "ab"/imm32 +446 68/push _test-stream/imm32 +447 # . . call +448 e8/call write/disp32 +449 # . . discard args +450 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +451 # skip-chars-matching(_test-stream, 0x20/space) +452 # . . push args +453 68/push 0x20/imm32 +454 68/push _test-stream/imm32 +455 # . . call +456 e8/call skip-chars-matching/disp32 +457 # . . discard args +458 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +459 # check-ints-equal(_test-stream->read, 0, msg) +460 # . . push args +461 68/push "F - test-skip-chars-matching-none"/imm32 +462 68/push 0/imm32 +463 # . . push *_test-stream->read +464 b8/copy-to-EAX _test-stream/imm32 +465 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) +466 # . . call +467 e8/call check-ints-equal/disp32 +468 # . . discard args +469 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +470 # end +471 c3/return +472 +473 # minor fork of 'skip-chars-matching' +474 skip-chars-not-matching: # in : (address stream), delimiter : byte +475 # . prolog +476 55/push-EBP +477 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +478 # . save registers +479 50/push-EAX +480 51/push-ECX +481 52/push-EDX +482 56/push-ESI +483 # ESI = in +484 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI +485 # ECX = in->read +486 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX +487 # EBX = in->write +488 8b/copy 0/mod/indirect 6/rm32/ESI . . . 3/r32/EBX . . # copy *ESI to EBX +489 # EDX = delimiter +490 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 2/r32/EDX 0xc/disp8 . # copy *(EBP+12) to EDX +491 $skip-chars-not-matching:loop: +492 # if (in->read >= in->write) break +493 39/compare 3/mod/direct 1/rm32/ECX . . . 3/r32/EBX . . # compare ECX with EBX +494 7d/jump-if-greater-or-equal $skip-chars-not-matching:end/disp8 +495 # EAX = in->data[in->read] +496 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX +497 8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/AL 0xc/disp8 . # copy byte at *(ESI+ECX+12) to AL +498 # if (EAX == delimiter) break +499 39/compare 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # compare EAX and EDX +500 74/jump-if-equal $skip-chars-not-matching:end/disp8 +501 # ++in->read +502 41/inc-ECX +503 eb/jump $skip-chars-not-matching:loop/disp8 +504 $skip-chars-not-matching:end: +505 # persist in->read +506 89/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy ECX to *(ESI+4) +507 # . restore registers +508 5e/pop-to-ESI +509 5a/pop-to-EDX +510 59/pop-to-ECX +511 58/pop-to-EAX +512 # . epilog +513 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +514 5d/pop-to-EBP +515 c3/return +516 +517 test-skip-chars-not-matching: +518 # setup +519 # . clear-stream(_test-stream) +520 # . . push args +521 68/push _test-stream/imm32 +522 # . . call +523 e8/call clear-stream/disp32 +524 # . . discard args +525 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +526 # write(_test-stream, "ab ") +527 # . . push args +528 68/push "ab "/imm32 +529 68/push _test-stream/imm32 +530 # . . call +531 e8/call write/disp32 +532 # . . discard args +533 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +534 # skip-chars-not-matching(_test-stream, 0x20/space) +535 # . . push args +536 68/push 0x20/imm32 +537 68/push _test-stream/imm32 +538 # . . call +539 e8/call skip-chars-not-matching/disp32 +540 # . . discard args +541 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +542 # check-ints-equal(_test-stream->read, 2, msg) +543 # . . push args +544 68/push "F - test-skip-chars-not-matching"/imm32 +545 68/push 2/imm32 +546 # . . push *_test-stream->read +547 b8/copy-to-EAX _test-stream/imm32 +548 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) +549 # . . call +550 e8/call check-ints-equal/disp32 +551 # . . discard args +552 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +553 # end +554 c3/return +555 +556 test-skip-chars-not-matching-none: +557 # setup +558 # . clear-stream(_test-stream) +559 # . . push args +560 68/push _test-stream/imm32 +561 # . . call +562 e8/call clear-stream/disp32 +563 # . . discard args +564 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +565 # write(_test-stream, " ab") +566 # . . push args +567 68/push " ab"/imm32 +568 68/push _test-stream/imm32 +569 # . . call +570 e8/call write/disp32 +571 # . . discard args +572 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +573 # skip-chars-not-matching(_test-stream, 0x20/space) +574 # . . push args +575 68/push 0x20/imm32 +576 68/push _test-stream/imm32 +577 # . . call +578 e8/call skip-chars-not-matching/disp32 +579 # . . discard args +580 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +581 # check-ints-equal(_test-stream->read, 0, msg) +582 # . . push args +583 68/push "F - test-skip-chars-not-matching-none"/imm32 +584 68/push 0/imm32 +585 # . . push *_test-stream->read +586 b8/copy-to-EAX _test-stream/imm32 +587 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) +588 # . . call +589 e8/call check-ints-equal/disp32 +590 # . . discard args +591 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +592 # end +593 c3/return +594 +595 test-skip-chars-not-matching-all: +596 # setup +597 # . clear-stream(_test-stream) +598 # . . push args +599 68/push _test-stream/imm32 +600 # . . call +601 e8/call clear-stream/disp32 +602 # . . discard args +603 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +604 # write(_test-stream, "ab") +605 # . . push args +606 68/push "ab"/imm32 +607 68/push _test-stream/imm32 +608 # . . call +609 e8/call write/disp32 +610 # . . discard args +611 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +612 # skip-chars-not-matching(_test-stream, 0x20/space) +613 # . . push args +614 68/push 0x20/imm32 +615 68/push _test-stream/imm32 +616 # . . call +617 e8/call skip-chars-not-matching/disp32 +618 # . . discard args +619 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +620 # check-ints-equal(_test-stream->read, 2, msg) +621 # . . push args +622 68/push "F - test-skip-chars-not-matching-all"/imm32 +623 68/push 2/imm32 +624 # . . push *_test-stream->read +625 b8/copy-to-EAX _test-stream/imm32 +626 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) +627 # . . call +628 e8/call check-ints-equal/disp32 +629 # . . discard args +630 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +631 # end +632 c3/return +633 +634 skip-chars-matching-in-slice: # curr : (address byte), end : (address byte), delimiter : byte -> curr/EAX +635 # . prolog +636 55/push-EBP +637 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +638 # . save registers +639 51/push-ECX +640 52/push-EDX +641 53/push-EBX +642 # EAX = curr +643 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 8/disp8 . # copy *(EBP+8) to EAX +644 # ECX = end +645 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 0xc/disp8 . # copy *(EBP+12) to ECX +646 # EDX = delimiter +647 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 2/r32/EDX 0x10/disp8 . # copy *(EBP+16) to EDX +648 # EBX = 0 +649 31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX +650 $skip-chars-matching-in-slice:loop: +651 # if (curr >= end) break +652 39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX with ECX +653 7d/jump-if-greater-or-equal $skip-chars-matching-in-slice:end/disp8 +654 # if (*curr != delimiter) break +655 8a/copy-byte 0/mod/indirect 0/rm32/EAX . . . 3/r32/BL . . # copy byte at *EAX to BL +656 39/compare 3/mod/direct 3/rm32/EBX . . . 2/r32/EDX . . # compare EBX and EDX +657 75/jump-if-not-equal $skip-chars-matching-in-slice:end/disp8 +658 # ++in->read +659 40/inc-EAX +660 eb/jump $skip-chars-matching-in-slice:loop/disp8 +661 $skip-chars-matching-in-slice:end: +662 # . restore registers +663 5b/pop-to-EBX +664 5a/pop-to-EDX +665 59/pop-to-ECX +666 # . epilog +667 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +668 5d/pop-to-EBP +669 c3/return +670 +671 test-skip-chars-matching-in-slice: +672 # (EAX..ECX) = " ab" +673 b8/copy-to-EAX " ab"/imm32 +674 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +675 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +676 05/add-to-EAX 4/imm32 +677 # EAX = skip-chars-matching-in-slice(EAX, ECX, 0x20/space) +678 # . . push args +679 68/push 0x20/imm32 +680 51/push-ECX +681 50/push-EAX +682 # . . call +683 e8/call skip-chars-matching-in-slice/disp32 +684 # . . discard args +685 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +686 # check-ints-equal(ECX-EAX, 2, msg) +687 # . . push args +688 68/push "F - test-skip-chars-matching-in-slice"/imm32 +689 68/push 2/imm32 +690 # . . push ECX-EAX +691 29/subtract 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # subtract EAX from ECX +692 51/push-ECX +693 # . . call +694 e8/call check-ints-equal/disp32 +695 # . . discard args +696 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +697 # end +698 c3/return +699 +700 test-skip-chars-matching-in-slice-none: +701 # (EAX..ECX) = "ab" +702 b8/copy-to-EAX "ab"/imm32 +703 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +704 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +705 05/add-to-EAX 4/imm32 +706 # EAX = skip-chars-matching-in-slice(EAX, ECX, 0x20/space) +707 # . . push args +708 68/push 0x20/imm32 +709 51/push-ECX +710 50/push-EAX +711 # . . call +712 e8/call skip-chars-matching-in-slice/disp32 +713 # . . discard args +714 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +715 # check-ints-equal(ECX-EAX, 2, msg) +716 # . . push args +717 68/push "F - test-skip-chars-matching-in-slice-none"/imm32 +718 68/push 2/imm32 +719 # . . push ECX-EAX +720 29/subtract 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # subtract EAX from ECX +721 51/push-ECX +722 # . . call +723 e8/call check-ints-equal/disp32 +724 # . . discard args +725 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +726 # end +727 c3/return +728 +729 # minor fork of 'skip-chars-matching-in-slice' +730 skip-chars-not-matching-in-slice: # curr : (address byte), end : (address byte), delimiter : byte -> curr/EAX +731 # . prolog +732 55/push-EBP +733 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP +734 # . save registers +735 51/push-ECX +736 52/push-EDX +737 53/push-EBX +738 # EAX = curr +739 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 8/disp8 . # copy *(EBP+8) to EAX +740 # ECX = end +741 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 0xc/disp8 . # copy *(EBP+12) to ECX +742 # EDX = delimiter +743 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 2/r32/EDX 0x10/disp8 . # copy *(EBP+16) to EDX +744 # EBX = 0 +745 31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX +746 $skip-chars-not-matching-in-slice:loop: +747 # if (curr >= end) break +748 39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX with ECX +749 7d/jump-if-greater-or-equal $skip-chars-not-matching-in-slice:end/disp8 +750 # if (*curr == delimiter) break +751 8a/copy-byte 0/mod/indirect 0/rm32/EAX . . . 3/r32/BL . . # copy byte at *EAX to BL +752 39/compare 3/mod/direct 3/rm32/EBX . . . 2/r32/EDX . . # compare EBX and EDX +753 74/jump-if-equal $skip-chars-not-matching-in-slice:end/disp8 +754 # ++in->read +755 40/inc-EAX +756 eb/jump $skip-chars-not-matching-in-slice:loop/disp8 +757 $skip-chars-not-matching-in-slice:end: +758 # . restore registers +759 5b/pop-to-EBX +760 5a/pop-to-EDX +761 59/pop-to-ECX +762 # . epilog +763 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP +764 5d/pop-to-EBP +765 c3/return +766 +767 test-skip-chars-not-matching-in-slice: +768 # (EAX..ECX) = "ab " +769 b8/copy-to-EAX "ab "/imm32 +770 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +771 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +772 05/add-to-EAX 4/imm32 +773 # EAX = skip-chars-not-matching-in-slice(EAX, ECX, 0x20/space) +774 # . . push args +775 68/push 0x20/imm32 +776 51/push-ECX +777 50/push-EAX +778 # . . call +779 e8/call skip-chars-not-matching-in-slice/disp32 +780 # . . discard args +781 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +782 # check-ints-equal(ECX-EAX, 1, msg) +783 # . . push args +784 68/push "F - test-skip-chars-not-matching-in-slice"/imm32 +785 68/push 1/imm32 +786 # . . push ECX-EAX +787 29/subtract 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # subtract EAX from ECX +788 51/push-ECX +789 # . . call +790 e8/call check-ints-equal/disp32 +791 # . . discard args +792 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +793 # end +794 c3/return +795 +796 test-skip-chars-not-matching-in-slice-none: +797 # (EAX..ECX) = " ab" +798 b8/copy-to-EAX " ab"/imm32 +799 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +800 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +801 05/add-to-EAX 4/imm32 +802 # EAX = skip-chars-not-matching-in-slice(EAX, ECX, 0x20/space) +803 # . . push args +804 68/push 0x20/imm32 +805 51/push-ECX +806 50/push-EAX +807 # . . call +808 e8/call skip-chars-not-matching-in-slice/disp32 +809 # . . discard args +810 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +811 # check-ints-equal(ECX-EAX, 3, msg) +812 # . . push args +813 68/push "F - test-skip-chars-not-matching-in-slice-none"/imm32 +814 68/push 3/imm32 +815 # . . push ECX-EAX +816 29/subtract 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # subtract EAX from ECX +817 51/push-ECX +818 # . . call +819 e8/call check-ints-equal/disp32 +820 # . . discard args +821 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +822 # end +823 c3/return +824 +825 test-skip-chars-not-matching-in-slice-all: +826 # (EAX..ECX) = "ab" +827 b8/copy-to-EAX "ab"/imm32 +828 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX +829 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX +830 05/add-to-EAX 4/imm32 +831 # EAX = skip-chars-not-matching-in-slice(EAX, ECX, 0x20/space) +832 # . . push args +833 68/push 0x20/imm32 +834 51/push-ECX +835 50/push-EAX +836 # . . call +837 e8/call skip-chars-not-matching-in-slice/disp32 +838 # . . discard args +839 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +840 # check-ints-equal(ECX-EAX, 0, msg) +841 # . . push args +842 68/push "F - test-skip-chars-not-matching-in-slice-all"/imm32 +843 68/push 0/imm32 +844 # . . push ECX-EAX +845 29/subtract 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # subtract EAX from ECX +846 51/push-ECX +847 # . . call +848 e8/call check-ints-equal/disp32 +849 # . . discard args +850 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +851 # end +852 c3/return +853 +854 # . . vim:nowrap:textwidth=0 diff --git a/subx/071next-token.subx b/subx/071next-token.subx index 539caf95..a3cd6035 100644 --- a/subx/071next-token.subx +++ b/subx/071next-token.subx @@ -4,13 +4,14 @@ # . 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: +#? e8/call test-skip-chars-matching-in-slice/disp32 e8/call run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'. # syscall(exit, Num-test-failures) 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX b8/copy-to-EAX 1/imm32/exit cd/syscall 0x80/imm8 -# extract the next run of characters that are different from a given 'delimiter' +# extract the next run of characters that are different from a given 'delimiter' (skipping multiple delimiters if necessary) # on eof return an empty interval next-token: # in : (address stream), delimiter : byte, out : (address slice) # . prolog @@ -28,7 +29,7 @@ next-token: # in : (address stream), delimiter : byte, out : (address slice) # skip-chars-matching(in, delimiter) # . . push args ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + 56/push-ESI # . . call e8/call skip-chars-matching/disp32 # . . discard args @@ -40,7 +41,7 @@ next-token: # in : (address stream), delimiter : byte, out : (address slice) # skip-chars-not-matching(in, delimiter) # . . push args ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + 56/push-ESI # . . call e8/call skip-chars-not-matching/disp32 # . . discard args @@ -163,6 +164,191 @@ test-next-token-eof: 5d/pop-to-EBP c3/return +# extract the next run of characters that are different from a given 'delimiter' (skipping multiple delimiters if necessary) +# on eof return an empty interval +next-token-from-slice: # in : (address slice), delimiter : byte, out : (address slice) + # . prolog + 55/push-EBP + 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + # . save registers + 50/push-EAX + 56/push-ESI + 57/push-EDI + # ESI = in + 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI + # EDI = out + 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 0x10/disp8 . # copy *(EBP+16) to EDI + # EAX = skip-chars-matching-in-slice(in->start, in->end, delimiter) + # . . push args + ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) + ff 6/subop/push 1/mod/*+disp8 6/rm32/ESI . . . . 4/disp8 . # push *(ESI+4) + ff 6/subop/push 0/mod/indirect 6/rm32/ESI . . . . . . # push *ESI + # . . call + e8/call skip-chars-matching-in-slice/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + # out->start = EAX + 89/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy EAX to *EDI + # EAX = skip-chars-not-matching-in-slice(EAX, in->end, delimiter) + # . . push args + ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) + ff 6/subop/push 1/mod/*+disp8 6/rm32/ESI . . . . 4/disp8 . # push *(ESI+4) + 50/push-EAX + # . . call + e8/call skip-chars-not-matching-in-slice/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + # out->end = EAX + 89/copy 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDI+4) + # . restore registers + 5f/pop-to-EDI + 5e/pop-to-ESI + 58/pop-to-EAX + # . epilog + 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 5d/pop-to-EBP + c3/return + +test-next-token-from-slice: + # . prolog + 55/push-EBP + 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + # (EAX..ECX) = " ab" + b8/copy-to-EAX " ab"/imm32 + 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX + 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX + 05/add-to-EAX 4/imm32 + # var in/ESI : (address slice) = {EAX, ECX} + 51/push-ECX + 50/push-EAX + 89/copy 3/mod/direct 6/rm32/ESI . . . 4/r32/ESP . . # copy ESP to ESI + # var out/EDI : (address slice) = {0, 0} + 68/push 0/imm32/end + 68/push 0/imm32/start + 89/copy 3/mod/direct 7/rm32/EDI . . . 4/r32/ESP . . # copy ESP to EDI + # next-token-from-slice(in, 0x20/space, out) + # . . push args + 57/push-EDI + 68/push 0x20/imm32 + 56/push-ESI + # . . call + e8/call next-token-from-slice/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + # out->start should be at the 'a' + # . check-ints-equal(out->start - in->start, 2, msg) + # . . push args + 68/push "F - test-next-token-from-slice: start"/imm32 + 68/push 2/imm32 + # . . push out->start - in->start + 8b/copy 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # copy *EDI to ECX + 2b/subtract 0/mod/indirect 6/rm32/ESI . . . 1/r32/ECX . . # subtract *ESI from ECX + 51/push-ECX + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + # out->end should be after the 'b' + # check-ints-equal(out->end - in->start, 4, msg) + # . . push args + 68/push "F - test-next-token-from-slice: end"/imm32 + 68/push 4/imm32 + # . . push out->end - in->start + 8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 1/r32/ECX 4/disp8 . # copy *(EDI+4) to ECX + 2b/subtract 0/mod/indirect 6/rm32/ESI . . . 1/r32/ECX . . # subtract *ESI from ECX + 51/push-ECX + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + # . epilog + 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 5d/pop-to-EBP + c3/return + +test-next-token-from-slice-eof: + # . prolog + 55/push-EBP + 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + # var in/ESI : (address slice) = {0, 0} + 51/push-ECX + 50/push-EAX + 89/copy 3/mod/direct 6/rm32/ESI . . . 4/r32/ESP . . # copy ESP to ESI + # var out/EDI : (address slice) = {0, 0} + 68/push 0/imm32/end + 68/push 0/imm32/start + 89/copy 3/mod/direct 7/rm32/EDI . . . 4/r32/ESP . . # copy ESP to EDI + # next-token-from-slice(in, 0x20/space, out) + # . . push args + 57/push-EDI + 68/push 0x20/imm32 + 56/push-ESI + # . . call + e8/call next-token-from-slice/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + # out should be empty + # . check-ints-equal(out->end - out->start, 0, msg) + # . . push args + 68/push "F - test-next-token-from-slice-eof"/imm32 + 68/push 0/imm32 + # . . push out->start - in->start + 8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 1/r32/ECX 4/disp8 . # copy *(EDI+4) to ECX + 2b/subtract 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # subtract *EDI from ECX + 51/push-ECX + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + # . epilog + 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 5d/pop-to-EBP + c3/return + +test-next-token-from-slice-nothing: + # . prolog + 55/push-EBP + 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + # (EAX..ECX) = " " + b8/copy-to-EAX " "/imm32 + 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX + 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX + 05/add-to-EAX 4/imm32 + # var in/ESI : (address slice) = {EAX, ECX} + 51/push-ECX + 50/push-EAX + 89/copy 3/mod/direct 6/rm32/ESI . . . 4/r32/ESP . . # copy ESP to ESI + # var out/EDI : (address slice) = {0, 0} + 68/push 0/imm32/end + 68/push 0/imm32/start + 89/copy 3/mod/direct 7/rm32/EDI . . . 4/r32/ESP . . # copy ESP to EDI + # next-token-from-slice(in, 0x20/space, out) + # . . push args + 57/push-EDI + 68/push 0x20/imm32 + 56/push-ESI + # . . call + e8/call next-token-from-slice/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + # out should be empty + # . check-ints-equal(out->end - out->start, 0, msg) + # . . push args + 68/push "F - test-next-token-from-slice-eof"/imm32 + 68/push 0/imm32 + # . . push out->start - in->start + 8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 1/r32/ECX 4/disp8 . # copy *(EDI+4) to ECX + 2b/subtract 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # subtract *EDI from ECX + 51/push-ECX + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + # . epilog + 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 5d/pop-to-EBP + c3/return + skip-chars-matching: # in : (address stream), delimiter : byte # . prolog 55/push-EBP @@ -182,7 +368,7 @@ skip-chars-matching: # in : (address stream), delimiter : byte 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 2/r32/EDX 0xc/disp8 . # copy *(EBP+12) to EDX $skip-chars-matching:loop: # if (in->read >= in->write) break - 3b/compare 3/mod/direct 3/rm32/EBX . . . 1/r32/ECX . . # compare ECX with *EBX + 39/compare 3/mod/direct 1/rm32/ECX . . . 3/r32/EBX . . # compare ECX with EBX 7d/jump-if-greater-or-equal $skip-chars-matching:end/disp8 # EAX = in->data[in->read] 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX @@ -304,7 +490,7 @@ skip-chars-not-matching: # in : (address stream), delimiter : byte 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 2/r32/EDX 0xc/disp8 . # copy *(EBP+12) to EDX $skip-chars-not-matching:loop: # if (in->read >= in->write) break - 3b/compare 3/mod/direct 3/rm32/EBX . . . 1/r32/ECX . . # compare ECX with *EBX + 39/compare 3/mod/direct 1/rm32/ECX . . . 3/r32/EBX . . # compare ECX with EBX 7d/jump-if-greater-or-equal $skip-chars-not-matching:end/disp8 # EAX = in->data[in->read] 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX @@ -445,4 +631,224 @@ test-skip-chars-not-matching-all: # end c3/return +skip-chars-matching-in-slice: # curr : (address byte), end : (address byte), delimiter : byte -> curr/EAX + # . prolog + 55/push-EBP + 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + # . save registers + 51/push-ECX + 52/push-EDX + 53/push-EBX + # EAX = curr + 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 8/disp8 . # copy *(EBP+8) to EAX + # ECX = end + 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 0xc/disp8 . # copy *(EBP+12) to ECX + # EDX = delimiter + 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 2/r32/EDX 0x10/disp8 . # copy *(EBP+16) to EDX + # EBX = 0 + 31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX +$skip-chars-matching-in-slice:loop: + # if (curr >= end) break + 39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX with ECX + 7d/jump-if-greater-or-equal $skip-chars-matching-in-slice:end/disp8 + # if (*curr != delimiter) break + 8a/copy-byte 0/mod/indirect 0/rm32/EAX . . . 3/r32/BL . . # copy byte at *EAX to BL + 39/compare 3/mod/direct 3/rm32/EBX . . . 2/r32/EDX . . # compare EBX and EDX + 75/jump-if-not-equal $skip-chars-matching-in-slice:end/disp8 + # ++in->read + 40/inc-EAX + eb/jump $skip-chars-matching-in-slice:loop/disp8 +$skip-chars-matching-in-slice:end: + # . restore registers + 5b/pop-to-EBX + 5a/pop-to-EDX + 59/pop-to-ECX + # . epilog + 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 5d/pop-to-EBP + c3/return + +test-skip-chars-matching-in-slice: + # (EAX..ECX) = " ab" + b8/copy-to-EAX " ab"/imm32 + 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX + 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX + 05/add-to-EAX 4/imm32 + # EAX = skip-chars-matching-in-slice(EAX, ECX, 0x20/space) + # . . push args + 68/push 0x20/imm32 + 51/push-ECX + 50/push-EAX + # . . call + e8/call skip-chars-matching-in-slice/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + # check-ints-equal(ECX-EAX, 2, msg) + # . . push args + 68/push "F - test-skip-chars-matching-in-slice"/imm32 + 68/push 2/imm32 + # . . push ECX-EAX + 29/subtract 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # subtract EAX from ECX + 51/push-ECX + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + # end + c3/return + +test-skip-chars-matching-in-slice-none: + # (EAX..ECX) = "ab" + b8/copy-to-EAX "ab"/imm32 + 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX + 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX + 05/add-to-EAX 4/imm32 + # EAX = skip-chars-matching-in-slice(EAX, ECX, 0x20/space) + # . . push args + 68/push 0x20/imm32 + 51/push-ECX + 50/push-EAX + # . . call + e8/call skip-chars-matching-in-slice/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + # check-ints-equal(ECX-EAX, 2, msg) + # . . push args + 68/push "F - test-skip-chars-matching-in-slice-none"/imm32 + 68/push 2/imm32 + # . . push ECX-EAX + 29/subtract 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # subtract EAX from ECX + 51/push-ECX + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + # end + c3/return + +# minor fork of 'skip-chars-matching-in-slice' +skip-chars-not-matching-in-slice: # curr : (address byte), end : (address byte), delimiter : byte -> curr/EAX + # . prolog + 55/push-EBP + 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + # . save registers + 51/push-ECX + 52/push-EDX + 53/push-EBX + # EAX = curr + 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 8/disp8 . # copy *(EBP+8) to EAX + # ECX = end + 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 0xc/disp8 . # copy *(EBP+12) to ECX + # EDX = delimiter + 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 2/r32/EDX 0x10/disp8 . # copy *(EBP+16) to EDX + # EBX = 0 + 31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX +$skip-chars-not-matching-in-slice:loop: + # if (curr >= end) break + 39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX with ECX + 7d/jump-if-greater-or-equal $skip-chars-not-matching-in-slice:end/disp8 + # if (*curr == delimiter) break + 8a/copy-byte 0/mod/indirect 0/rm32/EAX . . . 3/r32/BL . . # copy byte at *EAX to BL + 39/compare 3/mod/direct 3/rm32/EBX . . . 2/r32/EDX . . # compare EBX and EDX + 74/jump-if-equal $skip-chars-not-matching-in-slice:end/disp8 + # ++in->read + 40/inc-EAX + eb/jump $skip-chars-not-matching-in-slice:loop/disp8 +$skip-chars-not-matching-in-slice:end: + # . restore registers + 5b/pop-to-EBX + 5a/pop-to-EDX + 59/pop-to-ECX + # . epilog + 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 5d/pop-to-EBP + c3/return + +test-skip-chars-not-matching-in-slice: + # (EAX..ECX) = "ab " + b8/copy-to-EAX "ab "/imm32 + 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX + 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX + 05/add-to-EAX 4/imm32 + # EAX = skip-chars-not-matching-in-slice(EAX, ECX, 0x20/space) + # . . push args + 68/push 0x20/imm32 + 51/push-ECX + 50/push-EAX + # . . call + e8/call skip-chars-not-matching-in-slice/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + # check-ints-equal(ECX-EAX, 1, msg) + # . . push args + 68/push "F - test-skip-chars-not-matching-in-slice"/imm32 + 68/push 1/imm32 + # . . push ECX-EAX + 29/subtract 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # subtract EAX from ECX + 51/push-ECX + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + # end + c3/return + +test-skip-chars-not-matching-in-slice-none: + # (EAX..ECX) = " ab" + b8/copy-to-EAX " ab"/imm32 + 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX + 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX + 05/add-to-EAX 4/imm32 + # EAX = skip-chars-not-matching-in-slice(EAX, ECX, 0x20/space) + # . . push args + 68/push 0x20/imm32 + 51/push-ECX + 50/push-EAX + # . . call + e8/call skip-chars-not-matching-in-slice/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + # check-ints-equal(ECX-EAX, 3, msg) + # . . push args + 68/push "F - test-skip-chars-not-matching-in-slice-none"/imm32 + 68/push 3/imm32 + # . . push ECX-EAX + 29/subtract 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # subtract EAX from ECX + 51/push-ECX + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + # end + c3/return + +test-skip-chars-not-matching-in-slice-all: + # (EAX..ECX) = "ab" + b8/copy-to-EAX "ab"/imm32 + 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX + 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX + 05/add-to-EAX 4/imm32 + # EAX = skip-chars-not-matching-in-slice(EAX, ECX, 0x20/space) + # . . push args + 68/push 0x20/imm32 + 51/push-ECX + 50/push-EAX + # . . call + e8/call skip-chars-not-matching-in-slice/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + # check-ints-equal(ECX-EAX, 0, msg) + # . . push args + 68/push "F - test-skip-chars-not-matching-in-slice-all"/imm32 + 68/push 0/imm32 + # . . push ECX-EAX + 29/subtract 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # subtract EAX from ECX + 51/push-ECX + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + # end + c3/return + # . . vim:nowrap:textwidth=0 diff --git a/subx/apps/crenshaw2-1 b/subx/apps/crenshaw2-1 index bcf1415c..448cc762 100755 Binary files a/subx/apps/crenshaw2-1 and b/subx/apps/crenshaw2-1 differ diff --git a/subx/apps/crenshaw2-1b b/subx/apps/crenshaw2-1b index 29fcdc94..b31edcd3 100755 Binary files a/subx/apps/crenshaw2-1b and b/subx/apps/crenshaw2-1b differ diff --git a/subx/apps/factorial b/subx/apps/factorial index 5062a5a0..2f10831f 100755 Binary files a/subx/apps/factorial and b/subx/apps/factorial differ diff --git a/subx/apps/handle b/subx/apps/handle index 929e5c5a..5069d19d 100755 Binary files a/subx/apps/handle and b/subx/apps/handle differ diff --git a/subx/apps/hex b/subx/apps/hex index d854606e..10c02bf6 100755 Binary files a/subx/apps/hex and b/subx/apps/hex differ diff --git a/subx/apps/pack.subx b/subx/apps/pack.subx index d7052b0b..f09a6b2f 100644 --- a/subx/apps/pack.subx +++ b/subx/apps/pack.subx @@ -86,27 +86,43 @@ $main:end: # read first word as opcode and write-slice # if 0f or f2 or f3 read second opcode and write-slice # if 'f2 0f' or 'f3 0f' read third opcode and write-slice -# scan words +# while true: +# word-slice = next-word +# if empty(word-slice) break # if has metadata 'mod', parse into mod # if has metadata 'rm32', parse into rm32 # if has metadata 'r32', parse into r32 # if has metadata 'subop', parse into r32 # if at least one of the 3 was present, print-byte -# scan words +# while true: +# word-slice = next-word +# if empty(word-slice) break # if has metadata 'base', parse into base # if has metadata 'index', parse into index # if has metadata 'scale', parse into scale # if at least one of the 3 was present, print-byte # parse errors => -# scan words +# while true: +# word-slice = next-word +# if empty(word-slice) break # if has metadata 'disp8', emit as 1 byte # if has metadata 'disp16', emit as 2 bytes # if has metadata 'disp32', emit as 4 bytes -# scan words +# while true: +# word-slice = next-word +# if empty(word-slice) break # if has metadata 'imm8', emit # if has metadata 'imm32', emit as 4 bytes # finally, emit line prefixed with a ' # ' +# has-metadata?(word-slice, m): +# next-token2(word-slice, '/') # skip +# while true: +# slice = next-token2(word-slice, '/') +# if empty?(slice) break +# if equal(slice, m) return true +# return false + # simplifications since we perform zero error handling (continuing to rely on the C++ version for that): # missing fields are always 0-filled # bytes never mentioned are silently dropped; if you don't provide /mod, /rm32 or /r32 you don't get a 0 modrm byte. You get *no* modrm byte. @@ -123,6 +139,7 @@ $main:end: # # we won't bother saving the internal structure of lines; reparsing should be cheap using two primitives: # next-token(stream, delim char) -> slice (start, end pointers) +# next-token(stream, slice, delim char) -> slice' # slice-equal?(slice, string) # helpers: -- cgit 1.4.1-2-gfad0