6807 - tile: render intermediate stack state
This commit is contained in:
parent
72e8240a23
commit
8e4b4f2013
|
@ -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
|
||||
|
|
2
400.mu
2
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 _)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
122
apps/tile/rpn.mu
122
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
|
||||
$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
|
||||
}
|
||||
}
|
||||
{
|
||||
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
|
||||
}
|
||||
# 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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue