about summary refs log blame commit diff stats
path: root/html/314divide.subx.html
blob: b1351c1c102bf15d955bd7d08bc89b4a3dbc92a5 (plain) (tree)
1
2
3
4
5
6
7
8
9








                                                                                                               
                                                

                       

                                                                                                 


                                     
                                  
           


































                                                                                 
                                                                                                                             





















                                                                                                                                                                                       
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Mu - 314divide.subx</title>
<meta name="Generator" content="Vim/8.1">
<meta name="plugin-version" content="vim8.1_v1">
<meta name="syntax" content="none">
<meta name="settings" content="number_lines,use_css,pre_wrap,no_foldcolumn,expand_tabs,line_ids,prevent_copy=">
<meta name="colorscheme" content="minimal-dark">
<style type="text/css">
<!--
pre { white-space: pre-wrap; font-family: monospace; color: #000000; background-color: #a8a8a8; }
body { font-size:12pt; font-family: monospace; color: #000000; background-color: #a8a8a8; }
a { color:inherit; }
* { font-size:12pt; font-size: 1em; }
.subxComment { color: #005faf; }
.subxS1Comment { color: #0000af; }
.LineNr { }
.subxFunction { color: #af5f00; text-decoration: underline; }
.Constant { color: #008787; }
-->
</style>

<script type='text/javascript'>
<!--

/* 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/314divide.subx'>https://github.com/akkartik/mu/blob/main/314divide.subx</a>
<pre id='vimCodeElement'>
<span id="L1" class="LineNr"> 1 </span>== code
<span id="L2" class="LineNr"> 2 </span>
<span id="L3" class="LineNr"> 3 </span><span class="subxFunction">integer-divide</span>:  <span class="subxComment"># a: int, b: int -&gt; quotient/eax: int, remainder/edx: int</span>
<span id="L4" class="LineNr"> 4 </span>    <span class="subxS1Comment"># . prologue</span>
<span id="L5" class="LineNr"> 5 </span>    55/push-ebp
<span id="L6" class="LineNr"> 6 </span>    89/&lt;- %ebp 4/r32/esp
<span id="L7" class="LineNr"> 7 </span>    <span class="subxComment"># eax = a</span>
<span id="L8" class="LineNr"> 8 </span>    8b/-&gt; *(ebp+8) 0/r32/eax
<span id="L9" class="LineNr"> 9 </span>    <span class="subxComment"># edx = all 0s or all 1s</span>
<span id="L10" class="LineNr">10 </span>    99/sign-extend-eax-into-edx
<span id="L11" class="LineNr">11 </span>    <span class="subxComment"># quotient, remainder = divide eax by b</span>
<span id="L12" class="LineNr">12 </span>    f7 7/subop/divide-eax-edx-by *(ebp+0xc)
<span id="L13" class="LineNr">13 </span><span class="Constant">$integer-divide:end</span>:
<span id="L14" class="LineNr">14 </span>    <span class="subxS1Comment"># . epilogue</span>
<span id="L15" class="LineNr">15 </span>    89/&lt;- %esp 5/r32/ebp
<span id="L16" class="LineNr">16 </span>    5d/pop-to-ebp
<span id="L17" class="LineNr">17 </span>    c3/return
</pre>
</body>
</html>
<!-- vim: set foldmethod=manual : -->
boolean) } ; trim trailing newline in result (easier history management below) { begin (l:character <- last result:buffer-address) (trailing-newline?:boolean <- equal l:character ((#\newline literal))) (break-unless trailing-newline?:boolean) (len:integer-address <- get-address result:buffer-address/deref length:offset) (len:integer-address/deref <- subtract len:integer-address/deref 1:literal) } ; test: 3<enter> => size of s is 2 (s:string-address <- to-array result:buffer-address) (reply s:string-address) ]) (function process-key [ ; return t to signal end of expression (default-space:space-address <- new space:literal 60:literal) (0:space-address/names:read-expression <- next-input) (k:keyboard-address <- next-input) (screen:terminal-address <- next-input) (c:character <- wait-for-key k:keyboard-address silent:literal/terminal) (len:integer-address <- get-address result:buffer-address/space:1/deref length:offset) (maybe-cancel-this-expression c:character abort:continuation/space:1) ; check for ctrl-d and exit { begin (eof?:boolean <- equal c:character ((ctrl-d literal))) (break-unless eof?:boolean) ; return empty expression (s:string-address-address <- get-address result:buffer-address/space:1/deref data:offset) (s:string-address-address/deref <- copy nil:literal) (reply t:literal) } ; check for backspace ; test: 3<backspace>4<enter> ; todo: backspace past newline { begin (backspace?:boolean <- equal c:character ((#\backspace literal))) (break-unless backspace?:boolean) (print-character screen:terminal-address c:character/backspace) { begin ; delete last character if any (zero?:boolean <- lesser-or-equal len:integer-address/deref 0:literal) (break-if zero?:boolean) (len:integer-address/deref <- subtract len:integer-address/deref 1:literal) ; switch colors ; test: "a"<backspace>bc" ; test: "a\"<backspace>bc" { begin (backspaced-over-close-quote?:boolean <- backspaced-over-unescaped? result:buffer-address/space:1 ((#\" literal)) escapes:buffer-address/space:1) ; " (break-unless backspaced-over-close-quote?:boolean) (slurp-string result:buffer-address/space:1 escapes:buffer-address/space:1 abort:continuation/space:1 k:keyboard-address screen:terminal-address) (reply nil:literal) } ; test: (+ 1 (<backspace>2) ; test: (+ 1 #\(<backspace><backspace><backspace>2) { begin (backspaced-over-open-paren?:boolean <- backspaced-over-unescaped? result:buffer-address/space:1 ((#\( literal)) escapes:buffer-address/space:1) (break-unless backspaced-over-open-paren?:boolean) (open-parens:integer/space:1 <- subtract open-parens:integer/space:1 1:literal) (reply nil:literal) } ; test: (+ 1 2)<backspace> 3) ; test: (+ 1 2#\)<backspace><backspace><backspace> 3) { begin (backspaced-over-close-paren?:boolean <- backspaced-over-unescaped? result:buffer-address/space:1 ((#\) literal)) escapes:buffer-address/space:1) (break-unless backspaced-over-close-paren?:boolean) (open-parens:integer/space:1 <- add open-parens:integer/space:1 1:literal) (reply nil:literal) } } (reply nil:literal) } ; up arrow; switch to previous item in history { begin (up-arrow?:boolean <- equal c:character ((up literal))) (break-unless up-arrow?:boolean) ; if history exists ; test: <up><enter> up without history has no effect { begin (empty-history?:boolean <- lesser-or-equal history-length:integer/space:1 0:literal) (break-unless empty-history?:boolean) (reply nil:literal) } ; if pointer not already at start of history ; test: 34<enter><up><up><enter> up past history has no effect { begin (at-history-start?:boolean <- lesser-or-equal current-history-index:integer/space:1 0:literal) (break-unless at-history-start?:boolean) (reply nil:literal) } ; then update history index, copy into current buffer ; test: 34<enter><up><enter> up restores previous command ; test todo: 34<enter>23<up>34<down><enter> up doesn't mess up typing on current line ; test todo: 34<enter><up>5<enter><up><up> commands don't modify history ; test todo: multi-line expressions ; identify the history item (current-history-index:integer/space:1 <- subtract current-history-index:integer/space:1 1:literal) (switch-to-history 0:space-address screen:terminal-address) ; <enter> is trimmed in the history expression, so wait for the human to ; hit <enter> again or backspace to make edits (reply nil:literal) } ; down arrow; switch to next item in history { begin (down-arrow?:boolean <- equal c:character ((down literal))) (break-unless down-arrow?:boolean) ; if history exists ; test: <down><enter> down without history has no effect { begin (empty-history?:boolean <- lesser-or-equal history-length:integer/space:1 0:literal) (break-unless empty-history?:boolean) (reply nil:literal) } ; if pointer not already at end of history ; test: 34<enter><down><down><enter> up past history has no effect { begin (x:integer <- subtract history-length:integer/space:1 1:literal) (before-history-end?:boolean <- greater-or-equal current-history-index:integer/space:1 x:integer) (break-unless before-history-end?:boolean) (reply nil:literal) } ; then update history index, copy into current buffer ; test: 34<enter><up><enter> up restores previous command ; test todo: 34<enter>23<up>34<down><enter> up doesn't mess up typing on current line ; test todo: 34<enter><up>5<enter><up><up> commands don't modify history ; test todo: multi-line expressions ; identify the history item (current-history-index:integer/space:1 <- add current-history-index:integer/space:1 1:literal) (switch-to-history 0:space-address screen:terminal-address) ; <enter> is trimmed in the history expression, so wait for the human to ; hit <enter> again or backspace to make edits (reply nil:literal) } ; if it's a newline, decide whether to return ; test: <enter>34<enter> { begin (newline?:boolean <- equal c:character ((#\newline literal))) (break-unless newline?:boolean) (print-character screen:terminal-address c:character/newline) (at-top-level?:boolean <- lesser-or-equal open-parens:integer/space:1 0:literal) (end-expression?:boolean <- and at-top-level?:boolean not-empty?:boolean/space:1) (reply end-expression?:boolean) } ; printable character; save ;? ($print (("append\n" literal))) ;? 2 (result:buffer-address/space:1 <- append result:buffer-address/space:1 c:character) ;? ($print (("done\n" literal))) ;? 2 ; if it's backslash, read, save and print one additional character ; test: (prn #\() { begin (backslash?:boolean <- equal c:character ((#\\ literal))) (break-unless backslash?:boolean) (print-character screen:terminal-address c:character/backslash 7:literal/white) (result:buffer-address/space:1 escapes:buffer-address/space:1 <- slurp-escaped-character result:buffer-address/space:1 7:literal/white escapes:buffer-address/space:1 abort:continuation/space:1 k:keyboard-address screen:terminal-address) (reply nil:literal) } ; if it's a semi-colon, parse a comment { begin (comment?:boolean <- equal c:character ((#\; literal))) (break-unless comment?:boolean) (print-character screen:terminal-address c:character/semi-colon 4:literal/fg/blue) (comment-read?:boolean <- slurp-comment result:buffer-address/space:1 escapes:buffer-address/space:1 abort:continuation/space:1 k:keyboard-address screen:terminal-address) ; return if comment was read (i.e. consumed a newline) ; test: ;a<backspace><backspace> (shouldn't end command until <enter>) { begin (break-if comment-read?:boolean) (reply nil:literal) } ; and we're not within parens ; test: (+ 1 2) ; comment<enter> ; test: (+ 1<enter>; abc<enter>2)<enter> ; test: ; comment<enter>(+ 1 2)<enter> ; too expensive to build: 3<backspace>; comment<enter>(+ 1 2)<enter> (at-top-level?:boolean <- lesser-or-equal open-parens:integer/space:1 0:literal) (end-expression?:boolean <- and at-top-level?:boolean not-empty?:boolean/space:1) (reply end-expression?:boolean) } ; if it's not whitespace, set not-empty? and continue { begin (space?:boolean <- equal c:character ((#\space literal))) (break-if space?:boolean) (newline?:boolean <- equal c:character ((#\newline literal))) (break-if newline?:boolean) (tab?:boolean <- equal c:character ((tab literal))) (break-if tab?:boolean) (not-empty?:boolean/space:1 <- copy t:literal) ; fall through } ; if it's a quote, parse a string { begin (string-started?:boolean <- equal c:character ((#\" literal))) ; for vim: " (break-unless string-started?:boolean) (print-character screen:terminal-address c:character/open-quote 6:literal/fg/cyan) (slurp-string result:buffer-address/space:1 escapes:buffer-address/space:1 abort:continuation/space:1 k:keyboard-address screen:terminal-address) (reply nil:literal) } ; color parens by depth, so they're easy to balance ; test: (+ 1 1)<enter> ; test: (def foo () (+ 1 (* 2 3)))<enter> { begin (open-paren?:boolean <- equal c:character ((#\( literal))) (break-unless open-paren?:boolean) (_ color-code:integer <- divide-with-remainder open-parens:integer/space:1 3:literal) ; 3 distinct colors for parens (color-code:integer <- add color-code:integer 1:literal) (print-character screen:terminal-address c:character/open-paren color-code:integer) (open-parens:integer/space:1 <- add open-parens:integer/space:1 1:literal) ;? ($print open-parens:integer/space:1) ;? 2 (reply nil:literal) } { begin (close-paren?:boolean <- equal c:character ((#\) literal))) (break-unless close-paren?:boolean) (open-parens:integer/space:1 <- subtract open-parens:integer/space:1 1:literal) (_ color-code:integer <- divide-with-remainder open-parens:integer/space:1 3:literal) ; 3 distinct colors for parens (color-code:integer <- add color-code:integer 1:literal) (print-character screen:terminal-address c:character/close-paren color-code:integer) ;? ($print open-parens:integer/space:1) ;? 2 (reply nil:literal) } ; if all else fails, print the character without color (print-character screen:terminal-address c:character/regular) ; todo: error on space outside parens, like python ; todo: [] ; todo: history on up/down (reply nil:literal) ]) (function switch-to-history [ (default-space:space-address <- new space:literal 30:literal) (0:space-address/names:read-expression <- next-input) (screen:terminal-address <- next-input) (clear-repl-state 0:space-address) (curr-history:string-address <- buffer-index history:buffer-address/space:1 current-history-index:integer/space:1) (curr-history-len:integer <- length curr-history:string-address/deref) ; and retype it into the current expression (hist:keyboard-address <- init-keyboard curr-history:string-address) (hist-index:integer-address <- get-address hist:keyboard-address/deref index:offset) { begin (done?:boolean <- greater-or-equal hist-index:integer-address/deref curr-history-len:integer) (break-if done?:boolean) (sub-return:boolean <- process-key 0:space-address hist:keyboard-address screen:terminal-address) (assert-false sub-return:boolean (("recursive call to process keys thought it was done" literal))) (loop) } ]) (function clear-repl-state [ (default-space:space-address/names:read-expression <- next-input) ; clear result (len:integer-address <- get-address result:buffer-address/deref length:offset) (backspace-over len:integer-address/deref screen:terminal-address) (len:integer-address/deref <- copy 0:literal) ; clear other state accumulated for the existing expression (open-parens:integer <- copy 0:literal) (escapes:buffer-address <- init-buffer 5:literal) (not-empty?:boolean <- copy nil:literal) ]) (function backspace-over [ (default-space:space-address <- new space:literal 30:literal) (len:integer <- next-input) (screen:terminal-address <- next-input) { begin (done?:boolean <- lesser-or-equal len:integer 0:literal) (break-if done?:boolean) (print-character screen:terminal-address ((#\backspace literal))) (len:integer <- subtract len:integer 1:literal) (loop) } ]) ; list of characters, list of indices of escaped characters, abort continuation ; -> whether a comment was consumed (can also return by backspacing past comment leader ';') (function slurp-comment [ (default-space:space-address <- new space:literal 30:literal) (in:buffer-address <- next-input) (escapes:buffer-address <- next-input) (abort:continuation <- next-input) (k:keyboard-address <- next-input) (screen:terminal-address <- next-input) ; test: ; abc<enter> { begin next-key-in-comment (c:character <- wait-for-key k:keyboard-address silent:literal/terminal) (maybe-cancel-this-expression c:character abort:continuation screen:terminal-address) ; test: check needs to come before print (print-character screen:terminal-address c:character 4:literal/fg/blue) ; handle backspace ; test: ; abc<backspace><backspace>def<enter> ; todo: how to exit comment? { begin (backspace?:boolean <- equal c:character ((#\backspace literal))) (break-unless backspace?:boolean) (len:integer-address <- get-address in:buffer-address/deref length:offset) ; buffer has to have at least the semi-colon so can't be empty (len:integer-address/deref <- subtract len:integer-address/deref 1:literal) ; if we erase start of comment, return (comment-deleted?:boolean <- backspaced-over-unescaped? in:buffer-address ((#\; literal)) escapes:buffer-address) ; " (jump-unless comment-deleted?:boolean next-key-in-comment:offset) ; loop (reply nil:literal/read-comment?) } (in:buffer-address <- append in:buffer-address c:character) (newline?:boolean <- equal c:character ((#\newline literal))) (loop-unless newline?:boolean) } (reply t:literal/read-comment?) ]) (function slurp-string [ (default-space:space-address <- new space:literal 30:literal) (in:buffer-address <- next-input) (escapes:buffer-address <- next-input) (abort:continuation <- next-input) (k:keyboard-address <- next-input) (screen:terminal-address <- next-input) ; test: "abc" { begin next-key-in-string (c:character <- wait-for-key k:keyboard-address silent:literal/terminal) (maybe-cancel-this-expression c:character abort:continuation screen:terminal-address) ; test: check needs to come before print (print-character screen:terminal-address c:character 6:literal/fg/cyan) ; handle backspace ; test: "abc<backspace>d" ; todo: how to exit string? { begin (backspace?:boolean <- equal c:character ((#\backspace literal))) (break-unless backspace?:boolean) (len:integer-address <- get-address in:buffer-address/deref length:offset) ; typed a quote before calling slurp-string, so can't be empty (len:integer-address/deref <- subtract len:integer-address/deref 1:literal) ; if we erase start of string, return ; test: "<backspace>34 (string-deleted?:boolean <- backspaced-over-unescaped? in:buffer-address ((#\" literal)) escapes:buffer-address) ; " ;? ($print string-deleted?:boolean) ;? 1 (jump-if string-deleted?:boolean end:offset) ; break (jump next-key-in-string:offset) ; loop } (in:buffer-address <- append in:buffer-address c:character) ; break on quote -- unless escaped by backslash ; test: "abc\"ef" { begin (backslash?:boolean <- equal c:character ((#\\ literal))) (break-unless backslash?:boolean) (in:buffer-address escapes:buffer-address <- slurp-escaped-character in:buffer-address 6:literal/cyan escapes:buffer-address abort:continuation k:keyboard-address screen:terminal-address) (jump next-key-in-string:offset) ; loop } ; if not backslash (end-quote?:boolean <- equal c:character ((#\" literal))) ; for vim: " (loop-unless end-quote?:boolean) } end ]) ; buffer to add character to, color to print it in to the screen, abort continuation (function slurp-escaped-character [ (default-space:space-address <- new space:literal 30:literal) (in:buffer-address <- next-input) (color-code:integer <- next-input) (escapes:buffer-address <- next-input) (abort:continuation <- next-input) (k:keyboard-address <- next-input) (screen:terminal-address <- next-input) (c:character <- wait-for-key k:keyboard-address silent:literal/terminal) (maybe-cancel-this-expression c:character abort:continuation screen:terminal-address) ; test: check needs to come before print (print-character screen:terminal-address c:character color-code:integer) (len:integer-address <- get-address in:buffer-address/deref length:offset) (escapes:buffer-address <- append escapes:buffer-address len:integer-address/deref) ;? ($print (("+" literal))) ;? 1 ; handle backspace ; test: "abc\<backspace>def" ; test: #\<backspace> { begin (backspace?:boolean <- equal c:character ((#\backspace literal))) (break-unless backspace?:boolean) ; just typed a backslash, so buffer can't be empty (len:integer-address/deref <- subtract len:integer-address/deref 1:literal) (elen:integer-address <- get-address escapes:buffer-address/deref length:offset) (elen:integer-address/deref <- subtract elen:integer-address/deref 1:literal) ;? ($print (("-" literal))) ;? 1 (reply in:buffer-address/same-as-arg:0 escapes:buffer-address/same-as-arg:2) } ; if not backspace, save and return (in:buffer-address <- append in:buffer-address c:character) (reply in:buffer-address/same-as-arg:0 escapes:buffer-address/same-as-arg:2) ]) (function backspaced-over-unescaped? [ (default-space:space-address <- new space:literal 30:literal) (in:buffer-address <- next-input) (expected:character <- next-input) (escapes:buffer-address <- next-input) ; char just backspaced over matches { begin (c:character <- past-last in:buffer-address) (char-match?:boolean <- equal c:character expected:character) (break-if char-match?:boolean) (reply nil:literal) } ; and char before cursor is not an escape { begin (most-recent-escape:integer <- last escapes:buffer-address) (last-idx:integer <- get in:buffer-address/deref length:offset) ;? ($print most-recent-escape:integer) ;? 1 ;? ($print last-idx:integer) ;? 1 (was-unescaped?:boolean <- not-equal last-idx:integer most-recent-escape:integer) (break-if was-unescaped?:boolean) (reply nil:literal) } (reply t:literal) ]) ; return the character past the end of the buffer, if there's room (function past-last [ (default-space:space-address <- new space:literal 30:literal) (in:buffer-address <- next-input) (n:integer <- get in:buffer-address/deref length:offset) (s:string-address <- get in:buffer-address/deref data:offset) (capacity:integer <- length s:string-address/deref) { begin (no-space?:boolean <- greater-or-equal n:integer capacity:integer) (break-unless no-space?:boolean) (reply ((#\null literal))) } (result:character <- index s:string-address/deref n:integer) (reply result:character) ]) (function maybe-cancel-this-expression [ ; check for ctrl-g and abort (default-space:space-address <- new space:literal 30:literal) (c:character <- next-input) (abort:continuation <- next-input) (screen:terminal-address <- next-input) { begin (interrupt?:boolean <- equal c:character ((ctrl-g literal))) (break-unless interrupt?:boolean) (print-character screen:terminal-address ((#\^ literal))) (print-character screen:terminal-address ((#\G literal))) (print-character screen:terminal-address ((#\newline literal))) (continue-from abort:continuation) } ]) (function main [ (default-space:space-address <- new space:literal 30:literal) (cursor-mode) ($print (("connected to anarki! type in an expression, then hit enter. ctrl-d exits. ctrl-g clears the current expression." literal))) (print-character nil:literal/terminal ((#\newline literal))) ; todo: ctrl-g shouldn't clear history (abort:continuation <- current-continuation) (history:buffer-address <- init-buffer 5:literal) ; buffer of buffers of strings, one per expression typed in { begin (s:string-address <- read-expression nil:literal/keyboard nil:literal/terminal abort:continuation history:buffer-address) (break-unless s:string-address) ;? (x:integer <- length s:string-address/deref) ;? 1 ;? ($print x:integer) ;? 1 ;? ($print ((#\newline literal))) ;? 1 (history:buffer-address <- append history:buffer-address s:string-address) ;? (len:integer <- get history:buffer-address/deref length:offset) ;? 1 ;? ($print len:integer) ;? 1 ;? ($print ((#\newline literal))) ;? 1 (retro-mode) ; print errors cleanly ;? (print-string nil:literal/terminal s:string-address) ;? 1 (t:string-address <- $eval s:string-address) (cursor-mode) ($print (("=> " literal))) (print-string nil:literal/terminal t:string-address) (print-character nil:literal/terminal ((#\newline literal))) (print-character nil:literal/terminal ((#\newline literal))) ; empty line separates each expression and result (loop) } ])