1 == code 2 # instruction effective address register displacement immediate 3 # . op subop mod rm32 base index scale r32 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 # If datum of 'word' is not a valid name, it must be a hex int. Parse and print 7 # it in 'width' bytes of hex, least significant first. 8 # Otherwise just print the entire word including metadata. 9 # Always print a trailing space. 10 emit: # out: (addr buffered-file), word: (addr slice), width: int 11 # . prologue 12 55/push-ebp 13 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 14 # . save registers 15 50/push-eax 16 56/push-esi 17 57/push-edi 18 # esi = word 19 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 0xc/disp8 . # copy *(ebp+12) to esi 20 # var datum/edi: slice 21 68/push 0/imm32/end 22 68/push 0/imm32/start 23 89/copy 3/mod/direct 7/rm32/edi . . . 4/r32/esp . . # copy esp to edi 24 # datum = next-token-from-slice(word->start, word->end, '/') 25 # . . push args 26 57/push-edi 27 68/push 0x2f/imm32/slash 28 ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4) 29 ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi 30 # . . call 31 e8/call next-token-from-slice/disp32 32 # . . discard args 33 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 34 # if (valid-name?(datum)) write-slice-buffered(out, word) and return 35 # . eax = valid-name?(name) 36 # . . push args 37 57/push-edi 38 # . . call 39 e8/call valid-name?/disp32 40 # . . discard args 41 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 42 # . if (eax != false) 43 3d/compare-eax-and 0/imm32/false 44 74/jump-if-= $emit:hex-int/disp8 45 $emit:name: 46 # . write-slice-buffered(out, word) 47 # . . push args 48 56/push-esi 49 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 50 # . . call 51 e8/call write-slice-buffered/disp32 52 # . . discard args 53 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 54 # . write-buffered(out, " ") 55 # . . push args 56 68/push Space/imm32 57 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 58 # . . call 59 e8/call write-buffered/disp32 60 # . . discard args 61 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 62 # . return 63 eb/jump $emit:end/disp8 64 # otherwise emit-hex(out, parse-hex-int-from-slice(datum), width) 65 # (Weird shit can happen here if the datum of 'word' isn't either a valid 66 # name or a hex number. `emit` is mostly used by translate_subx, which 67 # is currently designed to only receive legal SubX programs. We just 68 # want to make sure that valid names aren't treated as (valid) hex 69 # numbers.) 70 $emit:hex-int: 71 # . var value/eax: int = parse-hex-int-from-slice(datum) 72 # . . push args 73 57/push-edi 74 # . . call 75 e8/call parse-hex-int-from-slice/disp32 76 # . . discard args 77 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 78 # . emit-hex(out, value, width) 79 # . . push args 80 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) 81 50/push-eax 82 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 83 # . . call 84 e8/call emit-hex/disp32 85 # . . discard args 86 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 87 $emit:end: 88 # . reclaim locals 89 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 90 # . restore registers 91 5f/pop-to-edi 92 5e/pop-to-esi 93 58/pop-to-eax 94 # . epilogue 95 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 96 5d/pop-to-ebp 97 c3/return 98 99 test-emit-number: 100 # . prologue 101 55/push-ebp 102 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 103 # setup 104 # . clear-stream(_test-output-stream) 105 # . . push args 106 68/push _test-output-stream/imm32 107 # . . call 108 e8/call clear-stream/disp32 109 # . . discard args 110 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 111 # . clear-stream($_test-output-buffered-file->buffer) 112 # . . push args 113 68/push $_test-output-buffered-file->buffer/imm32 114 # . . call 115 e8/call clear-stream/disp32 116 # . . discard args 117 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 118 # (eax..ecx) = "30" 119 b8/copy-to-eax "30"/imm32 120 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 121 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 122 05/add-to-eax 4/imm32 123 # var slice/ecx: slice = {eax, ecx} 124 51/push-ecx 125 50/push-eax 126 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 127 # emit(_test-output-buffered-file, slice, 1) 128 # . . push args 129 68/push 1/imm32 130 51/push-ecx 131 68/push _test-output-buffered-file/imm32 132 # . . call 133 e8/call emit/disp32 134 # . . discard args 135 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 136 # flush(_test-output-buffered-file) 137 # . . push args 138 68/push _test-output-buffered-file/imm32 139 # . . call 140 e8/call flush/disp32 141 # . . discard args 142 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 143 # check-stream-equal(_test-output-stream, "30 ", msg) 144 # . . push args 145 68/push "F - test-emit-number/1"/imm32 146 68/push "30 "/imm32 147 68/push _test-output-stream/imm32 148 # . . call 149 e8/call check-stream-equal/disp32 150 # . . discard args 151 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 152 # . epilogue 153 89/copy 3/mod/direct 4/rm32/esp . . . <<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Mu - 513grapheme-stack.mu</title> <meta name="Generator" content="Vim/8.2"> <meta name="plugin-version" content="vim8.1_v2"> <meta name="syntax" content="none"> <meta name="settings" content="number_lines,use_css,pre_wrap,no_foldcolumn,expand_tabs,line_ids,prevent_copy=,use_input_for_pc=fallback"> <meta name="colorscheme" content="minimal-light"> <style> <!-- pre { white-space: pre-wrap; font-family: monospace; color: #000000; background-color: #ffffd7; } body { font-size:12pt; font-family: monospace; color: #000000; background-color: #ffffd7; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } .PreProc { color: #c000c0; } .muRegEdx { color: #af5f00; } .Special { color: #ff6060; } .LineNr { } .Constant { color: #008787; } .muRegEbx { color: #5f00ff; } .muRegEsi { color: #005faf; } .muRegEdi { color: #00af00; } .muRegEcx { color: #870000; } .Delimiter { color: #c000c0; } .muFunction { color: #af5f00; text-decoration: underline; } .muTest { color: #5f8700; } .muComment { color: #005faf; } --> </style> <script> <!-- /* function to open any folds containing a jumped-to line before jumping to it */ function JumpToLine() { var lineNum; lineNum = window.location.hash; lineNum = lineNum.substr(1); /* strip off '#' */ if (lineNum.indexOf('L') == -1) { lineNum = 'L'+lineNum; } var lineElem = document.getElementById(lineNum); /* Always jump to new location even if the line was hidden inside a fold, or * we corrected the raw number to a line ID. */ if (lineElem) { lineElem.scrollIntoView(true); } return true; } if ('onhashchange' in window) { window.onhashchange = JumpToLine; } --> </script> </head> <body onload='JumpToLine();'> <a href='https://github.com/akkartik/mu/blob/main/513grapheme-stack.mu'>https://github.com/akkartik/mu/blob/main/513grapheme-stack.mu</a> <pre id='vimCodeElement'> <span id="L1" class="LineNr"> 1 </span><span class="muComment"># grapheme stacks are the smallest unit of editable text</span> <span id="L2" class="LineNr"> 2 </span> <span id="L3" class="LineNr"> 3 </span><span class="PreProc">type</span> <a href='513grapheme-stack.mu.html#L3'>grapheme-stack</a> <span class="Delimiter">{</span> <span id="L4" class="LineNr"> 4 </span> data: (handle array grapheme) <span id="L5" class="LineNr"> 5 </span> top: int <span id="L6" class="LineNr"> 6 </span><span class="Delimiter">}</span> <span id="L7" class="LineNr"> 7 </span> <span id="L8" class="LineNr"> 8 </span><span class="PreProc">fn</span> <span class="muFunction"><a href='513grapheme-stack.mu.html#L8'>initialize-grapheme-stack</a></span> _self: (addr <a href='513grapheme-stack.mu.html#L3'>grapheme-stack</a>), n: int <span class="Delimiter">{</span> <span id="L9" class="LineNr"> 9 </span> <span class="PreProc">var</span> self/<span class="muRegEsi">esi</span>: (addr <a href='513grapheme-stack.mu.html#L3'>grapheme-stack</a>) <span class="Special"><-</span> copy _self <span id="L10" class="LineNr"> 10 </span> <span class="PreProc">var</span> d/<span class="muRegEdi">edi</span>: (addr handle array grapheme) <span class="Special"><-</span> get self, data <span id="L11" class="LineNr"> 11 </span> populate d, n <span id="L12" class="LineNr"> 12 </span> <span class="PreProc">var</span> top/eax: (addr int) <span class="Special"><-</span> get self, top <span id="L13" class="LineNr"> 13 </span> copy-to *top, <span class="Constant">0</span> <span id="L14" class="LineNr"> 14 </span><span class="Delimiter">}</span> <span id="L15" class="LineNr"> 15 </span> <span id="L16" class="LineNr"> 16 </span><span class="PreProc">fn</span> <span class="muFunction"><a href='513grapheme-stack.mu.html#L16'>clear-grapheme-stack</a></span> _self: (addr <a href='513grapheme-stack.mu.html#L3'>grapheme-stack</a>) <span class="Delimiter">{</span> <span id="L17" class="LineNr"> 17 </span> <span class="PreProc">var</span> self/<span class="muRegEsi">esi</span>: (addr <a href='513grapheme-stack.mu.html#L3'>grapheme-stack</a>) <span class="Special"><-</span> copy _self <span id="L18" class="LineNr"> 18 </span> <span class="PreProc">var</span> top/eax: (addr int) <span class="Special"><-</span> get self, top <span id="L19" class="LineNr"> 19 </span> copy-to *top, <span class="Constant">0</span> <span id="L20" class="LineNr"> 20 </span><span class="Delimiter">}</span> <span id="L21" class="LineNr"> 21 </span> <span id="L22" class="LineNr"> 22 </span><span class="PreProc">fn</span> <span class="muFunction"><a href='513grapheme-stack.mu.html#L22'>grapheme-stack-empty?</a></span> _self: (addr <a href='513grapheme-stack.mu.html#L3'>grapheme-stack</a>)<span class="PreProc"> -> </span>_/eax: boolean <span class="Delimiter">{</span> <span id="L23" class="LineNr"> 23 </span> <span class="PreProc">var</span> self/<span class="muRegEsi">esi</span>: (addr <a href='513grapheme-stack.mu.html#L3'>grapheme-stack</a>) <span class="Special"><-</span> copy _self <span id="L24" class="LineNr"> 24 </span> <span class="PreProc">var</span> top/eax: (addr int) <span class="Special"><-</span> get self, top <span id="L25" class="LineNr"> 25 </span> compare *top, <span class="Constant">0</span> <span id="L26" class="LineNr"> 26 </span> <span class="Delimiter">{</span> <span id="L27" class="LineNr"> 27 </span> <span class="PreProc">break-if-!=</span> <span id="L28" class="LineNr"> 28 </span> <span class="PreProc">return</span> <span class="Constant">1</span>/true <span id="L29" class="LineNr"> 29 </span> <span class="Delimiter">}</span> <span