https://github.com/akkartik/mu/blob/master/apps/tile/rpn.mu
  1 fn evaluate functions: (addr handle function), bindings: (addr table), scratch: (addr line), end: (addr word), out: (addr value-stack) {
  2   var line/eax: (addr line) <- copy scratch
  3   var word-ah/eax: (addr handle word) <- get line, data
  4   var curr/eax: (addr word) <- lookup *word-ah
  5   var curr-stream-storage: (stream byte 0x10)
  6   var curr-stream/edi: (addr stream byte) <- address curr-stream-storage
  7   clear-value-stack out
  8   $evaluate:loop: {
  9     # precondition (should never hit)
 10     compare curr, 0
 11     break-if-=
 12     # update curr-stream
 13     emit-word curr, curr-stream
 14 #?     print-stream-to-real-screen curr-stream
 15 #?     print-string-to-real-screen "\n"
 16     $evaluate:process-word: {
 17       # if curr-stream is an operator, perform it
 18       {
 19         var is-add?/eax: boolean <- stream-data-equal? curr-stream, "+"
 20         compare is-add?, 0
 21         break-if-=
 22         var _b/eax: int <- pop-int-from-value-stack out
 23         var b/edx: int <- copy _b
 24         var a/eax: int <- pop-int-from-value-stack out
 25         a <- add b
 26         push-int-to-value-stack out, a
 27         break $evaluate:process-word
 28       }
 29       {
 30         var is-sub?/eax: boolean <- stream-data-equal? curr-stream, "-"
 31         compare is-sub?, 0
 32         break-if-=
 33         var _b/eax: int <- pop-int-from-value-stack out
 34         var b/edx: int <- copy _b
 35         var a/eax: int <- pop-int-from-value-stack out
 36         a <- subtract b
 37         push-int-to-value-stack out, a
 38         break $evaluate:process-word
 39       }
 40       {
 41         var is-mul?/eax: boolean <- stream-data-equal? curr-stream, "*"
 42         compare is-mul?, 0
 43         break-if-=
 44         var _b/eax: int <- pop-int-from-value-stack out
 45         var b/edx: int <- copy _b
 46         var a/eax: int <- pop-int-from-value-stack out
 47         a <- multiply b
 48         push-int-to-value-stack out, a
 49         break $evaluate:process-word
 50       }
 51       {
 52         var is-len?/eax: boolean <- stream-data-equal? curr-stream, "len"
 53         compare is-len?, 0
 54         break-if-=
 55 #?         print-string 0, "is len\n"
 56         # pop target-val from out
 57         var out2/esi: (addr value-stack) <- copy out
 58         var top-addr/ecx: (addr int) <- get out2, top
 59         compare *top-addr, 0
 60         break-if-<=
 61 #?         print-string 0, "stack has stuff\n"
 62         var data-ah/eax: (addr handle array value) <- get out2, data
 63         var data/eax: (addr array value) <- lookup *data-ah
 64         var top/edx: int <- copy *top-addr
 65         top <- decrement
 66         var dest-offset/edx: (offset value) <- compute-offset data, top
 67         var target-val/edx: (addr value) <- index data, dest-offset
 68         # check target-val is a string or array
 69         var target-type-addr/eax: (addr int) <- get target-val, type
 70         compare *target-type-addr, 1  # string
 71         {
 72           break-if-!=
 73           # compute length
 74           var src-ah/eax: (addr handle array byte) <- get target-val, text-data
 75           var src/eax: (addr array byte) <- lookup *src-ah
 76           var result/ebx: int <- length src
 77           # save result into target-val
 78           var type-addr/eax: (addr int) <- get target-val, type
 79           copy-to *type-addr, 0  # int
 80           var target-string-ah/eax: (addr handle array byte) <- get target-val, text-data
 81           var empty: (handle array byte)
 82           copy-handle empty, target-string-ah
 83           var target/eax: (addr int) <- get target-val, int-data
 84           copy-to *target, result
 85           break $evaluate:process-word
 86         }
 87         compare *target-type-addr, 2  # array of ints
 88         {
 89           break-if-!=
 90           # compute length
 91           var src-ah/eax: (addr handle array value) <- get target-val, array-data
 92           var src/eax: (addr array value) <- lookup *src-ah
 93           var result/ebx: int <- length src
 94           # save result into target-val
 95           var type-addr/eax: (addr int) <- get target-val, type
 96           copy-to *type-addr, 0  # int
 97           var target-array-ah/eax: (addr handle array value) <- get target-val, array-data
 98           var empty: (handle array value)
 99           copy-handle empty, target-array-ah
100           var target/eax: (addr int) <- get target-val, int-data
101           copy-to *target, result
102           break $evaluate:process-word
103         }
104       }
105       {
106         var is-open?/eax: boolean <- stream-data-equal? curr-stream, "open"
107         compare is-open?, 0
108         break-if-=
109         # pop target-val from out
110         var out2/esi: (addr value-stack) <- copy out
111         var top-addr/ecx: (addr int) <- get out2, top
112         compare *top-addr, 0
113         break-if-<=
114         var data-ah/eax: (addr handle array value) <- get out2, data
115         var data/eax: (addr array value) <- lookup *data-ah
116         var top/edx: int <- copy *top-addr
117         top <- decrement
118         var dest-offset/edx: (offset value) <- compute-offset data, top
119         var target-val/edx: (addr value) <- index data, dest-offset
120         # check target-val is a string
121         var target-type-addr/eax: (addr int) <- get target-val, type
122         compare *target-type-addr, 1  # string
123         break-if-!=
124         # open target-val as a filename and save the handle in target-val
125         var src-ah/eax: (addr handle array byte) <- get target-val, text-data
126         var src/eax: (addr array byte) <- lookup *src-ah
127         var result-ah/ecx: (addr handle buffered-file) <- get target-val, file-data
128         open src, 0, result-ah  # write? = false
129         # save result into target-val
130         var type-addr/eax: (addr int) <- get target-val, type
131         copy-to *type-addr, 3  # file
132         var target-string-ah/eax: (addr handle array byte) <- get target-val, text-data
133         var empty: (handle array byte)
134         copy-handle empty, target-string-ah
135         break $evaluate:process-word
136       }
137       {
138         var is-read?/eax: boolean <- stream-data-equal? curr-stream, "read"
139         compare is-read?, 0
140         break-if-=
141         # pop target-val from out
142         var out2/esi: (addr value-stack) <- copy out
143         var top-addr/ecx: (addr int) <- get out2, top
144         compare *top-addr, 0
145         break-if-<=
146         var data-ah/eax: (addr handle array value) <- get out2, data
147         var data/eax: (addr array value) <- lookup *data-ah
148         var top/edx: int <- copy *top-addr
149         top <- decrement
150         var dest-offset/edx: (offset value) <- compute-offset data, top
151         var target-val/edx: (addr value) <- index data, dest-offset
152         # check target-val is a file
153         var target-type-addr/eax: (addr int) <- get target-val, type
154         compare *target-type-addr, 3  # file
155         break-if-!=
156         # read a line from the file and save in target-val
157         # read target-val as a filename and save the handle in target-val
158         var file-ah/eax: (addr handle buffered-file) <- get target-val, file-data
159         var file/eax: (addr buffered-file) <- lookup *file-ah
160         var s: (stream byte 0x100)
161         var s-addr/ecx: (addr stream byte) <- address s
162         read-line-buffered file, s-addr
163         var target/eax: (addr handle array byte) <- get target-val, text-data
164         stream-to-array s-addr, target
165         # save result into target-val
166         var type-addr/eax: (addr int) <- get target-val, type
167         copy-to *type-addr, 1  # string
168         var target-file-ah/eax: (addr handle buffered-file) <- get target-val, file-data
169         var empty: (handle buffered-file)
170         copy-handle empty, target-file-ah
171         break $evaluate:process-word
172       }
173       {
174         var is-slurp?/eax: boolean <- stream-data-equal? curr-stream, "slurp"
175         compare is-slurp?, 0
176         break-if-=
177         # pop target-val from out
178         var out2/esi: (addr value-stack) <- copy out
179         var top-addr/ecx: (addr int) <- get out2, top
180         compare *top-addr, 0
181         break-if-<=
182         var data-ah/eax: (addr handle array value) <- get out2, data
183         var data/eax: (addr array value) <- lookup *data-ah
184         var top/edx: int <- copy *top-addr
185         top <- decrement
186         var dest-offset/edx: (offset value) <- compute-offset data, top
187         var target-val/edx: (addr value) <- index data, dest-offset
188         # check target-val is a file
189         var target-type-addr/eax: (addr int) <- get target-val, type
190         compare *target-type-addr, 3  # file
191         break-if-!=
192         # slurp all contents from file and save in target-val
193         # read target-val as a filename and save the handle in target-val
194         var file-ah/eax: (addr handle buffered-file) <- get target-val, file-data
195         var file/eax: (addr buffered-file) <- lookup *file-ah
196         var s: (stream byte 0x100)
197         var s-addr/ecx: (addr stream byte) <- address s
198         slurp file, s-addr
199         var target/eax: (addr handle array byte) <- get target-val, text-data
200         stream-to-array s-addr, target
201         # save result into target-val
202         var type-addr/eax: (addr int) <- get target-val, type
203         copy-to *type-addr, 1  # string
204         var target-file-ah/eax: (addr handle buffered-file) <- get target-val, file-data
205         var empty: (handle buffered-file)
206         copy-handle empty, target-file-ah
207         break $evaluate:process-word
208       }
209       {
210         var is-lines?/eax: boolean <- stream-data-equal? curr-stream, "lines"
211         compare is-lines?, 0
212         break-if-=
213         # pop target-val from out
214         var out2/esi: (addr value-stack) <- copy out
215         var top-addr/ecx: (addr int) <- get out2, top
216         compare *top-addr, 0
217         break-if-<=
218         var data-ah/eax: (addr handle array value) <- get out2, data
219         var data/eax: (addr array value) <- lookup *data-ah
220         var top/edx: int <- copy *top-addr
221         top <- decrement
222         var dest-offset/edx: (offset value) <- compute-offset data, top
223         var target-val/edx: (addr value) <- index data, dest-offset
224         # check target-val is a file
225         var target-type-addr/eax: (addr int) <- get target-val, type
226         compare *target-type-addr, 3  # file
227         break-if-!=
228         # read all lines from file and save as an array of strings in target-val
229         # read target-val as a filename and save the handle in target-val
230         var file-ah/eax: (addr handle buffered-file) <- get target-val, file-data
231         var file/eax: (addr buffered-file) <- lookup *file-ah
232         var s: (stream byte 0x100)
233         var s-addr/ecx: (addr stream byte) <- address s
234         slurp file, s-addr
235         var tmp-ah/eax: (addr handle array byte) <- get target-val, text-data
236         stream-to-array s-addr, tmp-ah
237         var tmp/eax: (addr array byte) <- lookup *tmp-ah
238 #?         enable-screen-type-mode
239 #?         print-string 0, tmp
240         var h: (handle array (handle array byte))
241         {
242           var ah/edx: (addr handle array (handle array byte)) <- address h
243           split-string tmp, 0xa, ah
244         }
245         var target/eax: (addr handle array value) <- get target-val, array-data
246         save-lines h, target
247         # save result into target-val
248         var type-addr/eax: (addr int) <- get target-val, type
249         copy-to *type-addr, 2  # array
250         var target-file-ah/eax: (addr handle buffered-file) <- get target-val, file-data
251         var empty-file: (handle buffered-file)
252         copy-handle empty-file, target-file-ah
253         var target-text-ah/eax: (addr handle array byte) <- get target-val, text-data
254         var empty-text: (handle array byte)
255         copy-handle empty-text, target-text-ah
256         break $evaluate:process-word
257       }
258       # if curr-stream defines a binding, save top of stack to bindings
259       {
260         var done?/eax: boolean <- stream-empty? curr-stream
261         compare done?, 0  # false
262         break-if-!=
263         var new-byte/eax: byte <- read-byte curr-stream
264         compare new-byte, 0x3d  # '='
265         break-if-!=
266         # pop target-val from out
267         var out2/esi: (addr value-stack) <- copy out
268         var top-addr/ecx: (addr int) <- get out2, top
269         compare *top-addr, 0
270         break-if-<=
271         var data-ah/eax: (addr handle array value) <- get out2, data
272         var data/eax: (addr array value) <- lookup *data-ah
273         var top/edx: int <- copy *top-addr
274         top <- decrement
275         var dest-offset/edx: (offset value) <- compute-offset data, top
276         var target-val/edx: (addr value) <- index data, dest-offset
277         # create binding from curr-stream to target-val
278         var key-h: (handle array byte)
279         var key/ecx: (addr handle array byte) <- address key-h
280         stream-to-array curr-stream, key
281         bind-in-table bindings, key, target-val
282         break $evaluate:process-word
283       }
284       rewind-stream curr-stream
285       # if curr-stream is a known function name, call it appropriately
286       {
287         var callee-h: (handle function)
288         var callee-ah/eax: (addr handle function) <- address callee-h
289         find-function functions, curr-stream, callee-ah
290         var callee/eax: (addr function) <- lookup *callee-ah
291         compare callee, 0
292         break-if-=
293         perform-call callee, out, functions
294         break $evaluate:process-word
295       }
296       # HACKS: we're trying to avoid turning this into Forth
297       {
298         var is-dup?/eax: boolean <- stream-data-equal? curr-stream, "dup"
299         compare is-dup?, 0
300         break-if-=
301         # read src-val from out
302         var out2/esi: (addr value-stack) <- copy out
303         var top-addr/ecx: (addr int) <- get out2, top
304         compare *top-addr, 0
305         break-if-<=
306         var data-ah/eax: (addr handle array value) <- get out2, data
307         var data/eax: (addr array value) <- lookup *data-ah
308         var top/ecx: int <- copy *top-addr
309         top <- decrement
310         var offset/edx: (offset value) <- compute-offset data, top
311         var src-val/edx: (addr value) <- index data, offset
312         # push a copy of it
313         top <- increment
314         var offset/ebx: (offset value) <- compute-offset data, top
315         var target-val/ebx: (addr value) <- index data, offset
316         copy-object src-val, target-val
317         # commit
318         var top-addr/ecx: (addr int) <- get out2, top
319         increment *top-addr
320         break $evaluate:process-word
321       }
322       {
323         var is-swap?/eax: boolean <- stream-data-equal? curr-stream, "swap"
324         compare is-swap?, 0
325         break-if-=
326         # read top-val from out
327         var out2/esi: (addr value-stack) <- copy out
328         var top-addr/ecx: (addr int) <- get out2, top
329         compare *top-addr, 0
330         break-if-<=
331         var data-ah/eax: (addr handle array value) <- get out2, data
332         var data/eax: (addr array value) <- lookup *data-ah
333         var top/ecx: int <- copy *top-addr
334         top <- decrement
335         var offset/edx: (offset value) <- compute-offset data, top
336         var top-val/edx: (addr value) <- index data, offset
337         # read next val from out
338         top <- decrement
339         var offset/ebx: (offset value) <- compute-offset data, top
340         var pen-top-val/ebx: (addr value) <- index data, offset
341         # swap
342         var tmp: value
343         var tmp-a/eax: (addr value) <- address tmp
344         copy-object top-val, tmp-a
345         copy-object pen-top-val, top-val
346         copy-object tmp-a, pen-top-val
347         break $evaluate:process-word
348       }
349       # END HACKS
350       # if it's a name, push its value
351       {
352         compare bindings, 0
353         break-if-=
354         var tmp: (handle array byte)
355         var curr-string-ah/edx: (addr handle array byte) <- address tmp
356         stream-to-array curr-stream, curr-string-ah  # unfortunate leak
357         var curr-string/eax: (addr array byte) <- lookup *curr-string-ah
358         var val-storage: (handle value)
359         var val-ah/edi: (addr handle value) <- address val-storage
360         lookup-binding bindings, curr-string, val-ah
361         var val/eax: (addr value) <- lookup *val-ah
362         compare val, 0
363         break-if-=
364         push-value-stack out, val
365         break $evaluate:process-word
366       }
367       # if the word starts with a quote and ends with a quote, turn it into a string
368       {
369         var start/eax: byte <- stream-first curr-stream
370         compare start, 0x22  # double-quote
371         break-if-!=
372         var end/eax: byte <- stream-final curr-stream
373         compare end, 0x22  # double-quote
374         break-if-!=
375         var h: (handle array byte)
376         var s/eax: (addr handle array byte) <- address h
377         unquote-stream-to-array curr-stream, s  # leak
378         push-string-to-value-stack out, *s
379         break $evaluate:process-word
380       }
381       # if the word starts with a '[' and ends with a ']', turn it into an array
382       {
383         var start/eax: byte <- stream-first curr-stream
384         compare start, 0x5b  # '['
385         break-if-!=
386         var end/eax: byte <- stream-final curr-stream
387         compare end, 0x5d  # ']'
388         break-if-!=
389         # wastefully create a new input string to strip quotes
390         var h: (handle array value)
391         var input-ah/eax: (addr handle array byte) <- address h
392         unquote-stream-to-array curr-stream, input-ah  # leak
393         # wastefully parse input into int-array
394         # TODO: support parsing arrays of other types
395         var input/eax: (addr array byte) <- lookup *input-ah
396         var h2: (handle array int)
397         var int-array-ah/esi: (addr handle array int) <- address h2
398         parse-array-of-decimal-ints input, int-array-ah  # leak
399         var _int-array/eax: (addr array int) <- lookup *int-array-ah
400         var int-array/esi: (addr array int) <- copy _int-array
401         var len/ebx: int <- length int-array
402         # push value-array of same size as int-array
403         var h3: (handle array value)
404         var value-array-ah/eax: (addr handle array value) <- address h3
405         populate value-array-ah, len
406         push-array-to-value-stack out, *value-array-ah
407         # copy int-array into value-array
408         var _value-array/eax: (addr array value) <- lookup *value-array-ah
409         var value-array/edi: (addr array value) <- copy _value-array
410         var i/eax: int <- copy 0
411         {
412           compare i, len
413           break-if->=
414           var src-addr/ecx: (addr int) <- index int-array, i
415           var src/ecx: int <- copy *src-addr
416           var dest-offset/edx: (offset value) <- compute-offset value-array, i
417           var dest-val/edx: (addr value) <- index value-array, dest-offset
418           var dest/edx: (addr int) <- get dest-val, int-data
419           copy-to *dest, src
420           i <- increment
421           loop
422         }
423         break $evaluate:process-word
424       }
425       # otherwise assume it's a literal int and push it
426       {
427         var n/eax: int <- parse-decimal-int-from-stream curr-stream
428         push-int-to-value-stack out, n
429       }
430     }
431     # termination check
432     compare curr, end
433     break-if-=
434     # update
435     var next-word-ah/edx: (addr handle word) <- get curr, next
436     curr <- lookup *next-word-ah
437     #
438     loop
439   }
440   # process next line if necessary
441   var line/eax: (addr line) <- copy scratch
442   var next-line-ah/eax: (addr handle line) <- get line, next
443   var next-line/eax: (addr line) <- lookup *next-line-ah
444   compare next-line, 0
445   break-if-=
446   evaluate functions, bindings, next-line, end, out
447 }
448 
449 fn test-evaluate {
450   var line-storage: line
451   var line/esi: (addr line) <- address line-storage
452   var first-word-ah/eax: (addr handle word) <- get line-storage, data
453   allocate-word-with first-word-ah, "3"
454   append-word-with *first-word-ah, "=a"
455   var next-line-ah/eax: (addr handle line) <- get line-storage, next
456   allocate next-line-ah
457   var next-line/eax: (addr line) <- lookup *next-line-ah
458   var first-word-ah/eax: (addr handle word) <- get next-line, data
459   allocate-word-with first-word-ah, "a"
460   var functions-storage: (handle function)
461   var functions/ecx: (addr handle function) <- address functions-storage
462   var table-storage: table
463   var table/ebx: (addr table) <- address table-storage
464   initialize-table table, 0x10
465   var stack-storage: value-stack
466   var stack/edi: (addr value-stack) <- address stack-storage
467   initialize-value-stack stack, 0x10
468   evaluate functions, table, line, 0, stack
469   var x/eax: int <- pop-int-from-value-stack stack
470   check-ints-equal x, 3, "F - test-evaluate"
471 }
472 
473 fn find-function first: (addr handle function), name: (addr stream byte), out: (addr handle function) {
474   var curr/esi: (addr handle function) <- copy first
475   $find-function:loop: {
476     var _f/eax: (addr function) <- lookup *curr
477     var f/ecx: (addr function) <- copy _f
478     compare f, 0
479     break-if-=
480     var curr-name-ah/eax: (addr handle array byte) <- get f, name
481     var curr-name/eax: (addr array byte) <- lookup *curr-name-ah
482     var done?/eax: boolean <- stream-data-equal? name, curr-name
483     compare done?, 0  # false
484     {
485       break-if-=
486       copy-handle *curr, out
487       break $find-function:loop
488     }
489     curr <- get f, next
490     loop
491   }
492 }
493 
494 fn perform-call _callee: (addr function), caller-stack: (addr value-stack), functions: (addr handle function) {
495   var callee/ecx: (addr function) <- copy _callee
496   # create bindings for args
497   var table-storage: table
498   var table/esi: (addr table) <- address table-storage
499   initialize-table table, 0x10
500   bind-args callee, caller-stack, table
501   # obtain body
502   var body-ah/eax: (addr handle line) <- get callee, body
503   var body/eax: (addr line) <- lookup *body-ah
504   # perform call
505   var stack-storage: value-stack
506   var stack/edi: (addr value-stack) <- address stack-storage
507   initialize-value-stack stack, 0x10
508 #?   print-string-to-real-screen "about to enter recursive eval\n"
509   evaluate functions, table, body, 0, stack
510 #?   print-string-to-real-screen "exited recursive eval\n"
511   # pop target-val from out
512   var top-addr/ecx: (addr int) <- get stack, top
513   compare *top-addr, 0
514   break-if-<=
515   var data-ah/eax: (addr handle array value) <- get stack, data
516   var data/eax: (addr array value) <- lookup *data-ah
517   var top/edx: int <- copy *top-addr
518   top <- decrement
519   var dest-offset/edx: (offset value) <- compute-offset data, top
520   var target-val/edx: (addr value) <- index data, dest-offset
521   # stitch target-val into caller-stack
522   push-value-stack caller-stack, target-val
523 }
524 
525 # pop args from the caller-stack and bind them to successive args
526 # implies: function args are stored in reverse order
527 fn bind-args _callee: (addr function), _caller-stack: (addr value-stack), table: (addr table) {
528   var callee/ecx: (addr function) <- copy _callee
529   var curr-arg-ah/eax: (addr handle word) <- get callee, args
530   var curr-arg/eax: (addr word) <- lookup *curr-arg-ah
531   #
532   var curr-key-storage: (handle array byte)
533   var curr-key/edx: (addr handle array byte) <- address curr-key-storage
534   {
535     compare curr-arg, 0
536     break-if-=
537     # create binding
538     word-to-string curr-arg, curr-key
539     {
540       # pop target-val from caller-stack
541       var caller-stack/esi: (addr value-stack) <- copy _caller-stack
542       var top-addr/ecx: (addr int) <- get caller-stack, top
543       compare *top-addr, 0
544       break-if-<=
545       decrement *top-addr
546       var data-ah/eax: (addr handle array value) <- get caller-stack, data
547       var data/eax: (addr array value) <- lookup *data-ah
548       var top/ebx: int <- copy *top-addr
549       var dest-offset/ebx: (offset value) <- compute-offset data, top
550       var target-val/ebx: (addr value) <- index data, dest-offset
551       # create binding from curr-key to target-val
552       bind-in-table table, curr-key, target-val
553     }
554     #
555     var next-arg-ah/edx: (addr handle word) <- get curr-arg, next
556     curr-arg <- lookup *next-arg-ah
557     loop
558   }
559 }
560 
561 # Copy of 'simplify' that just tracks the maximum stack depth needed
562 # Doesn't actually need to simulate the stack, since every word has a predictable effect.
563 fn max-stack-depth first-word: (addr word), final-word: (addr word) -> _/edi: int {
564   var curr-word/eax: (addr word) <- copy first-word
565   var curr-depth/ecx: int <- copy 0
566   var result/edi: int <- copy 0
567   $max-stack-depth:loop: {
568     $max-stack-depth:process-word: {
569       # handle operators
570       {
571         var is-add?/eax: boolean <- word-equal? curr-word, "+"
572         compare is-add?, 0
573         break-if-=
574         curr-depth <- decrement
575         break $max-stack-depth:process-word
576       }
577       {
578         var is-sub?/eax: boolean <- word-equal? curr-word, "-"
579         compare is-sub?, 0
580         break-if-=
581         curr-depth <- decrement
582         break $max-stack-depth:process-word
583       }
584       {
585         var is-mul?/eax: boolean <- word-equal? curr-word, "*"
586         compare is-mul?, 0
587         break-if-=
588         curr-depth <- decrement
589         break $max-stack-depth:process-word
590       }
591       # otherwise it's an int (do we need error-checking?)
592       curr-depth <- increment
593       # update max depth if necessary
594       {
595         compare curr-depth, result
596         break-if-<=
597         result <- copy curr-depth
598       }
599     }
600     # if curr-word == final-word break
601     compare curr-word, final-word
602     break-if-=
603     # curr-word = curr-word->next
604     var next-word-ah/edx: (addr handle word) <- get curr-word, next
605     curr-word <- lookup *next-word-ah
606     #
607     loop
608   }
609   return result
610 }