forth-riscv

My forth
git clone git://git.electrosoup.com/forth-riscv
Log | Files | Refs

commit 51ea8748a32244c57113c6bedef511397cfe76dd
parent 31ebc4bf49bc204657605429ea5a6523482fa3f4
Author: Christian Ermann <christianermann@gmail.com>
Date:   Thu, 28 Nov 2024 12:26:08 -0800

Add prefix-based parsing to interpreter

Diffstat:
Msrc/forth.s | 138+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 118 insertions(+), 20 deletions(-)

diff --git a/src/forth.s b/src/forth.s @@ -1,5 +1,3 @@ -.option norelax - .extern uart_put_char .extern uart_get_char .extern uart_put_string @@ -178,6 +176,38 @@ defcode "bye", bye, 0x71F39F63 next # ----------------------------------------------------------------------------- +# built-in prefixes +# ----------------------------------------------------------------------------- + +defvar "#", prefix_decimal, 0x260C9112 + .int 0x23 + .int 0 + .int string_to_decimal + +defvar "$", prefix_hex, 0x210C8933 + .int 0x24 + .int _prefix_decimal + .int string_to_hex + +defvar "%", prefix_binary, 0x200C87A0 + .int 0x25 + .int _prefix_hex + .int string_to_binary + +defvar "'", prefix_address, 0x220C8AC6 + .int 0x27 + .int _prefix_binary + .int string_to_address + +defvar "*", prefix_execute, 0x2F0C9F3D + .int 0x2A + .int _prefix_address + .int string_to_execute + +defvar "latest-prefix", latest_prefix, 0x86C823C5 + .int _prefix_execute + +# ----------------------------------------------------------------------------- # constants and variables # ----------------------------------------------------------------------------- @@ -479,6 +509,53 @@ _to_number_done: mv w, x next +defword "string>#", string_to_decimal, 0x75831783 + la x, _base + li y, 10 + sw y, 0(x) + jal to_number + bnez w, _string_to_number_fail + not w, w + exit + +defword "string>$", string_to_hex, 0x7A831F62 + la x, _base + li y, 16 + sw y, 0(x) + jal to_number + bnez w, _string_to_number_fail + not w, w + exit + +defword "string>%", string_to_binary, 0x7B8320F5 + la x, _base + li y, 2 + sw y, 0(x) + jal to_number + bnez w, _string_to_number_fail + not w, w + exit + +_string_to_number_fail: + mv w, zero + exit + +defword "string>address", string_to_address, 0xFDC3CE9A + jal find + addi x, w, code_offset + push x + exit + +defword "string>execute" string_to_execute, 0xC1A5C011 + jal string_to_address + beqz w, _string_to_execute_done + pop w + jal execute + push w + li w, 1 +_string_to_execute_done: + exit + defcode "word>hash", word_to_hash, 0x50E0A245 load_cell w, hash_offset(w) next @@ -525,15 +602,45 @@ defcode "execute", execute, 0xA01E3D98 jr x # 'next' should be called by the executed word +defcode "match-prefix", match_prefix, 0x2C1AB495 + lw x, 0(psp) + lb x, 0(x) + la y, _latest_prefix + lw y, 0(y) + push w +_match_prefix_loop: + lb w, 0(y) + beq w, x, _match_prefix_done + addi y, y, cell + lw y, 0(y) + bnez y, _match_prefix_loop +_match_prefix_fail: + mv w, zero + next +_match_prefix_done: + # decrement string length + lw x, 0(psp) + addi x, x, -1 + sw x, 0(psp) + # increment string address + lw x, cell(psp) + addi x, x, 1 + sw x, cell(psp) + # code address + addi w, y, 2*cell + next + defword "interpret", interpret, 0x1F98C57A _interpret_start: jal parse_word beqz w, _interpret_parse_area_empty - jal two_dup + jal match_prefix + bnez w, _interpret_execute_prefix +_interpret_find_word: + jal drop jal find - beqz w, _interpret_word_not_found + beqz w, _interpret_retry _interpret_word_found: - addi psp, psp, 2 * cell # nip, nip addi w, w, code_offset # compiling? la x, _state @@ -554,24 +661,15 @@ _interpret_execute_word: pop w jalr x j _interpret_start -_interpret_word_not_found: - pop w - jal to_number - bnez w, _interpret_retry +_interpret_execute_prefix: + load_cell x, 0(w) pop w - # compiling? - la x, _state - load_cell x, 0(x) - beqz x, _interpret_start -_interpret_compile_number: - push w - la w, lit - jal jal_to - jal comma - jal comma + jalr x + pop x + beqz w, _interpret_retry + mv w, x j _interpret_start _interpret_retry: - addi psp, psp, cell pop w j _interpret_start _interpret_parse_area_empty: