diff options
-rw-r--r-- | 311parse-decimal-int.subx | 54 | ||||
-rw-r--r-- | 400.mu | 2 | ||||
-rw-r--r-- | 403unicode.mu | 21 | ||||
-rw-r--r-- | apps/tile/environment.mu | 50 | ||||
-rw-r--r-- | apps/tile/gap-buffer.mu | 54 | ||||
-rw-r--r-- | apps/tile/int-stack.mu | 20 | ||||
-rw-r--r-- | apps/tile/rpn.mu | 122 | ||||
-rw-r--r-- | apps/tile/word.mu | 6 |
8 files changed, 267 insertions, 62 deletions
diff --git a/311parse-decimal-int.subx b/311parse-decimal-int.subx index 538f3e87..fe08b932 100644 --- a/311parse-decimal-int.subx +++ b/311parse-decimal-int.subx @@ -1,6 +1,7 @@ # Helpers for parsing decimal ints. -parse-decimal-int-from-slice: # in: (addr slice) -> out/eax: int # . prologue +parse-decimal-int-from-slice: # in: (addr slice) -> out/eax: int + # . prologue 55/push-ebp 89/<- %ebp 4/r32/esp # . save registers @@ -17,6 +18,57 @@ $parse-decimal-int-from-slice:end: 5d/pop-to-ebp c3/return +parse-decimal-int: # in: (addr array byte) -> result/eax: int + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + 52/push-edx + # eax = in + 8b/-> *(ebp+8) 0/r32/eax + # var start/ecx: (addr byte) = &in->data + 8d/copy-address *(eax+4) 1/r32/ecx + # var end/edx: (addr byte) = &in->data[in->size] + 8b/-> *eax 2/r32/edx + 8d/copy-address *(eax+edx+4) 2/r32/edx + # + (parse-decimal-int-helper %ecx %edx) # => eax +$parse-decimal-int:end: + # . restore registers + 5a/pop-to-edx + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +parse-decimal-int-from-stream: # in: (addr stream byte) -> result/eax: int + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + 52/push-edx + # eax = in + 8b/-> *(ebp+8) 0/r32/eax + # var start/ecx: (addr byte) = &in->data[in->read] + 8b/-> *(eax+4) 1/r32/ecx + 8d/copy-address *(eax+ecx+0xc) 1/r32/ecx + # var end/edx: (addr byte) = &in->data[in->write] + 8b/-> *eax 2/r32/edx + 8d/copy-address *(eax+edx+0xc) 2/r32/edx + # + (parse-decimal-int-helper %ecx %edx) # => eax +$parse-decimal-int-from-stream:end: + # . restore registers + 5a/pop-to-edx + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + parse-decimal-int-helper: # start: (addr byte), end: (addr byte) -> result/eax: int # . prologue 55/push-ebp diff --git a/400.mu b/400.mu index d3f4c0f0..db32cdc9 100644 --- a/400.mu +++ b/400.mu @@ -69,7 +69,9 @@ sig parse-hex-int-from-slice in: (addr slice) -> result/eax: int #sig parse-hex-int-helper start: (addr byte), end: (addr byte) -> result/eax: int sig is-hex-digit? c: byte -> result/eax: boolean #sig from-hex-char in/eax: byte -> out/eax: nibble +sig parse-decimal-int in: (addr array byte) -> result/eax: int sig parse-decimal-int-from-slice in: (addr slice) -> result/eax: int +sig parse-decimal-int-from-stream in: (addr stream byte) -> result/eax: int #sig parse-decimal-int-helper start: (addr byte), end: (addr byte) -> result/eax: int sig error-byte ed: (addr exit-descriptor), out: (addr buffered-file), msg: (addr array byte), n: byte #sig allocate ad: (addr allocation-descriptor), n: int, out: (addr handle _) diff --git a/403unicode.mu b/403unicode.mu index 23f14d8f..dcb1e658 100644 --- a/403unicode.mu +++ b/403unicode.mu @@ -373,3 +373,24 @@ fn test-shift-left-bytes-5 { #? run-tests #? r <- copy 0 #? } + +# write a grapheme to a stream of bytes +# this is like write-to-stream, except we skip leading 0 bytes +fn write-grapheme out: (addr stream byte), g: grapheme { +$write-grapheme:body: { + var c/eax: int <- copy g + append-byte out, c # first byte is always written + c <- shift-right 8 + compare c, 0 + break-if-= $write-grapheme:body + append-byte out, c + c <- shift-right 8 + compare c, 0 + break-if-= $write-grapheme:body + append-byte out, c + c <- shift-right 8 + compare c, 0 + break-if-= $write-grapheme:body + append-byte out, c +} +} diff --git a/apps/tile/environment.mu b/apps/tile/environment.mu index 8c5f1b2a..929e4d6f 100644 --- a/apps/tile/environment.mu +++ b/apps/tile/environment.mu @@ -94,6 +94,8 @@ fn render _env: (addr environment), max-depth: int { var screen/edi: (addr screen) <- copy _screen # prepare screen clear-screen screen + move-cursor screen, 5, 1 # input-row+stack-margin-top + print-string screen, "stack:" move-cursor screen, 3, 3 # input-row, input-col # cursor-word var cursor-word-ah/esi: (addr handle word) <- get env, cursor-word @@ -115,7 +117,7 @@ fn render _env: (addr environment), max-depth: int { compare curr-word, 0 break-if-= move-cursor screen, 3, curr-col # input-row - curr-col <- render-stack screen, first-word, curr-word, max-depth, curr-col, cursor-word, cursor-col-a + curr-col <- render-column screen, first-word, curr-word, max-depth, curr-col, cursor-word, cursor-col-a var next-word-ah/edx: (addr handle word) <- get curr-word, next curr-word <- lookup *next-word-ah loop @@ -123,27 +125,49 @@ fn render _env: (addr environment), max-depth: int { move-cursor screen, 3, *cursor-col-a # input-row } -# Render the stack result from interpreting first-world to final-word (inclusive) -# with the bottom-left corner at botleft-row, botleft-col. +# Render: +# - final-word +# - the stack result from interpreting first-world to final-word (inclusive) +# with the bottom-left corner at botleft-row, botleft-col. # # Outputs: # - Return the farthest column written. # - If final-word is same as cursor-word, do some additional computation to set # cursor-col-a. -fn render-stack screen: (addr screen), first-word: (addr word), final-word: (addr word), botleft-depth: int, botleft-col: int, cursor-word: (addr word), cursor-col-a: (addr int) -> right-col/ecx: int { +fn render-column screen: (addr screen), first-word: (addr word), final-word: (addr word), botleft-depth: int, botleft-col: int, cursor-word: (addr word), cursor-col-a: (addr int) -> right-col/ecx: int { + # compute stack + var stack: int-stack + var stack-addr/edi: (addr int-stack) <- address stack + initialize-int-stack stack-addr, 0x10 # max-words + evaluate first-word, final-word, stack-addr + # render stack + var curr-row/ecx: int <- copy botleft-depth + curr-row <- add 6 # input-row 3 + stack-margin-top 3 + var i/eax: int <- int-stack-length stack-addr + curr-row <- subtract i + { + compare i, 0 + break-if-<= + move-cursor screen, curr-row, botleft-col + { + var val/eax: int <- pop-int-stack stack-addr + print-int32-decimal screen, val + } + curr-row <- increment + i <- decrement + loop + } + right-col <- copy 8 # TODO: adaptive + # render word, initialize result move-cursor screen, 3, botleft-col # input-row print-word screen, final-word - right-col <- copy botleft-col - var len/eax: int <- word-length final-word - right-col <- add len - right-col <- add 3 # margin-right +#? var len/eax: int <- word-length final-word +#? right-col <- copy len - # render stack - var botleft-row/eax: int <- copy botleft-depth - botleft-row <- add 4 # input-row 3 + 1 stack-margin-top - move-cursor screen, botleft-row, botleft-col - print-string screen "-" + # post-process right-col + right-col <- add botleft-col + right-col <- add 3 # margin-right } # We could be a little faster by not using 'first-word' (since max is commutative), diff --git a/apps/tile/gap-buffer.mu b/apps/tile/gap-buffer.mu index 1503690b..75f88122 100644 --- a/apps/tile/gap-buffer.mu +++ b/apps/tile/gap-buffer.mu @@ -6,15 +6,15 @@ type gap-buffer { fn initialize-gap-buffer _self: (addr gap-buffer) { var self/esi: (addr gap-buffer) <- copy _self var left/eax: (addr grapheme-stack) <- get self, left - initialize-grapheme-stack left, 0x10 + initialize-grapheme-stack left, 0x10 # max-word-size var right/eax: (addr grapheme-stack) <- get self, right - initialize-grapheme-stack right, 0x10 + initialize-grapheme-stack right, 0x10 # max-word-size } # just for tests fn initialize-gap-buffer-with self: (addr gap-buffer), s: (addr array byte) { initialize-gap-buffer self - var stream-storage: (stream byte 0x10) + var stream-storage: (stream byte 0x10) # max-word-size var stream/ecx: (addr stream byte) <- address stream-storage write stream, s { @@ -27,6 +27,52 @@ fn initialize-gap-buffer-with self: (addr gap-buffer), s: (addr array byte) { } } +fn emit-gap-buffer _self: (addr gap-buffer), out: (addr stream byte) { + var self/esi: (addr gap-buffer) <- copy _self + clear-stream out + var left/eax: (addr grapheme-stack) <- get self, left + emit-stack-from-bottom left, out + var right/eax: (addr grapheme-stack) <- get self, right + emit-stack-from-top right, out +} + +# dump stack from bottom to top +fn emit-stack-from-bottom _self: (addr grapheme-stack), out: (addr stream byte) { + var self/esi: (addr grapheme-stack) <- copy _self + var data-ah/edi: (addr handle array grapheme) <- get self, data + var _data/eax: (addr array grapheme) <- lookup *data-ah + var data/edi: (addr array grapheme) <- copy _data + var top-addr/ecx: (addr int) <- get self, top + var i/eax: int <- copy 0 + { + compare i, *top-addr + break-if->= + var g/edx: (addr grapheme) <- index data, i + write-grapheme out, *g + i <- increment + loop + } +} + +# dump stack from top to bottom +fn emit-stack-from-top _self: (addr grapheme-stack), out: (addr stream byte) { + var self/esi: (addr grapheme-stack) <- copy _self + var data-ah/edi: (addr handle array grapheme) <- get self, data + var _data/eax: (addr array grapheme) <- lookup *data-ah + var data/edi: (addr array grapheme) <- copy _data + var top-addr/ecx: (addr int) <- get self, top + var i/eax: int <- copy *top-addr + i <- decrement + { + compare i, 0 + break-if-< + var g/edx: (addr grapheme) <- index data, i + write-grapheme out, *g + i <- decrement + loop + } +} + fn render-gap-buffer screen: (addr screen), _gap: (addr gap-buffer) { var gap/esi: (addr gap-buffer) <- copy _gap var left/eax: (addr grapheme-stack) <- get gap, left @@ -111,7 +157,7 @@ $gap-buffer-equal?:body: { # complication: graphemes may be multiple bytes # so don't rely on length # instead turn the expected result into a stream and arrange to read from it in order - var stream-storage: (stream byte 0x10) + var stream-storage: (stream byte 0x10) # max-word-size var expected-stream/ecx: (addr stream byte) <- address stream-storage write expected-stream, s # compare left diff --git a/apps/tile/int-stack.mu b/apps/tile/int-stack.mu index 5e7a2223..3bb9336f 100644 --- a/apps/tile/int-stack.mu +++ b/apps/tile/int-stack.mu @@ -47,3 +47,23 @@ $pop-int-stack:body: { val <- copy *result-addr } } + +fn int-stack-empty? _self: (addr int-stack) -> result/eax: boolean { +$int-stack-empty?:body: { + var self/esi: (addr int-stack) <- copy _self + var top-addr/eax: (addr int) <- get self, top + compare *top-addr, 0 + { + break-if-!= + result <- copy 1 # true + break $int-stack-empty?:body + } + result <- copy 0 # false +} +} + +fn int-stack-length _self: (addr int-stack) -> result/eax: int { + var self/esi: (addr int-stack) <- copy _self + var top-addr/eax: (addr int) <- get self, top + result <- copy *top-addr +} diff --git a/apps/tile/rpn.mu b/apps/tile/rpn.mu index 696912fd..3ca8a38f 100644 --- a/apps/tile/rpn.mu +++ b/apps/tile/rpn.mu @@ -1,53 +1,87 @@ -fn simplify in: (addr stream byte), out: (addr int-stack) { - var word-storage: slice - var word/ecx: (addr slice) <- address word-storage +fn evaluate start: (addr word), end: (addr word), out: (addr int-stack) { + var curr/eax: (addr word) <- copy start + var curr-text-storage: (stream byte 0x10) + var curr-text/edi: (addr stream byte) <- address curr-text-storage clear-int-stack out - $simplify:word-loop: { - next-word in, word - var done?/eax: boolean <- slice-empty? word - compare done?, 0 - break-if-!= - # if word is an operator, perform it - { - var is-add?/eax: boolean <- slice-equal? word, "+" - compare is-add?, 0 - break-if-= - var _b/eax: int <- pop-int-stack out - var b/edx: int <- copy _b - var a/eax: int <- pop-int-stack out - a <- add b - push-int-stack out, a - loop $simplify:word-loop - } - { - var is-sub?/eax: boolean <- slice-equal? word, "-" - compare is-sub?, 0 - break-if-= - var _b/eax: int <- pop-int-stack out - var b/edx: int <- copy _b - var a/eax: int <- pop-int-stack out - a <- subtract b - push-int-stack out, a - loop $simplify:word-loop - } - { - var is-mul?/eax: boolean <- slice-equal? word, "*" - compare is-mul?, 0 - break-if-= - var _b/eax: int <- pop-int-stack out - var b/edx: int <- copy _b - var a/eax: int <- pop-int-stack out - a <- multiply b - push-int-stack out, a - loop $simplify:word-loop + $evaluate:loop: { + # precondition (should never hit) + compare curr, 0 + break-if-= + # update curr-text + emit-word curr, curr-text + $evaluate:process-word: { + # if curr-text is an operator, perform it + { + var is-add?/eax: boolean <- stream-data-equal? curr-text, "+" + compare is-add?, 0 + break-if-= + var _b/eax: int <- pop-int-stack out + var b/edx: int <- copy _b + var a/eax: int <- pop-int-stack out + a <- add b + push-int-stack out, a + break $evaluate:process-word + } + { + var is-sub?/eax: boolean <- stream-data-equal? curr-text, "-" + compare is-sub?, 0 + break-if-= + var _b/eax: int <- pop-int-stack out + var b/edx: int <- copy _b + var a/eax: int <- pop-int-stack out + a <- subtract b + push-int-stack out, a + break $evaluate:process-word + } + { + var is-mul?/eax: boolean <- stream-data-equal? curr-text, "*" + compare is-mul?, 0 + break-if-= + var _b/eax: int <- pop-int-stack out + var b/edx: int <- copy _b + var a/eax: int <- pop-int-stack out + a <- multiply b + push-int-stack out, a + break $evaluate:process-word + } + # otherwise it's an int + { + var n/eax: int <- parse-decimal-int-from-stream curr-text + push-int-stack out, n + } } - # otherwise it's an int - var n/eax: int <- parse-decimal-int-from-slice word - push-int-stack out, n + # termination check + compare curr, end + break-if-= + # update + var next-word-ah/edx: (addr handle word) <- get curr, next + curr <- lookup *next-word-ah + # loop } } +fn test-evaluate { + # input = [1, 2, +] + var w: (handle word) + var wah/eax: (addr handle word) <- address w + allocate wah + var wa/eax: (addr word) <- lookup w + initialize-word-with wa, "1" + append-word-with w, "2" + var next/ecx: (addr handle word) <- get wa, next + append-word-with *next, "+" + # initialize output + var stack-storage: int-stack + var stack/edx: (addr int-stack) <- address stack-storage + initialize-int-stack stack, 0x10 + # + evaluate wa, 0, stack + # check output + var x/eax: int <- pop-int-stack stack + check-ints-equal x, 3, "F - test-evaluate" +} + # Copy of 'simplify' that just tracks the maximum stack depth needed # Doesn't actually need to simulate the stack, since every word has a predictable effect. fn max-stack-depth first-word: (addr word), final-word: (addr word) -> result/edi: int { diff --git a/apps/tile/word.mu b/apps/tile/word.mu index e1c5e22d..9e683985 100644 --- a/apps/tile/word.mu +++ b/apps/tile/word.mu @@ -116,3 +116,9 @@ fn append-word _self-ah: (addr handle word) { var prev-ah/eax: (addr handle word) <- get next, prev copy-handle *self-ah, prev-ah } + +fn emit-word _self: (addr word), out: (addr stream byte) { + var self/esi: (addr word) <- copy _self + var data/eax: (addr gap-buffer) <- get self, data + emit-gap-buffer data, out +} |