diff --git a/include/fh_config.h b/include/fh_config.h index e9a9262..52fd421 100644 --- a/include/fh_config.h +++ b/include/fh_config.h @@ -21,6 +21,7 @@ #define HEAP_END (HEAP_SIZE - WORDBUF_SIZE - INPUT_BUFFER_SIZE) #define WORDBUF_ADDR HEAP_END +#define WORDBUF_LASTCHAR_ADDR (WORDBUF_ADDR + WORDBUF_SIZE - 1) #define INPUTBUF_ADDR (HEAP_END + WORDBUF_SIZE) // SFR and magic addresses are "negative" diff --git a/include/fh_error.h b/include/fh_error.h index 6591c6d..e4f8263 100644 --- a/include/fh_error.h +++ b/include/fh_error.h @@ -28,6 +28,7 @@ enum fh_error { FH_ERR_ARITH, FH_ERR_SYNTAX, FH_ERR_NOT_APPLICABLE, + FH_ERR_PICTNUM_FULL, FH_ERR_MAX, }; diff --git a/include/fh_runtime.h b/include/fh_runtime.h index de5810d..4a214cf 100644 --- a/include/fh_runtime.h +++ b/include/fh_runtime.h @@ -176,6 +176,9 @@ struct fh_thread_s { /** Address of the last dict word */ uint32_t dict_last; + /** Pictured numeric output buffer write cursor (used for prepend) */ + uint32_t pictnumptr; + /** Input buffer parse position */ uint32_t inputptr; /** Input buffer total content size */ diff --git a/src/fh_builtins_text.c b/src/fh_builtins_text.c index b0d2e66..c08d0a8 100644 --- a/src/fh_builtins_text.c +++ b/src/fh_builtins_text.c @@ -217,6 +217,136 @@ static enum fh_error w_dot_quote(struct fh_thread_s *fh, const struct fh_word_s return FH_OK; } +static enum fh_error w_less_hash(struct fh_thread_s *fh, const struct fh_word_s *w) +{ + (void) w; + enum fh_error rv; + fh->pictnumptr = WORDBUF_LASTCHAR_ADDR; + return FH_OK; +} + +static enum fh_error w_hash_greater(struct fh_thread_s *fh, const struct fh_word_s *w) +{ + (void) w; + enum fh_error rv; + + + uint64_t dummy; + TRY(ds_pop_dw(fh, &dummy)); + + uint32_t len = WORDBUF_LASTCHAR_ADDR - fh->pictnumptr; + uint32_t addr; + TRY(fh_heap_reserve(fh, len, &addr)); + fh_heap_copy(fh, addr, fh->pictnumptr+1, len); + LOG("#> output: \"%.*s\"", len, &fh->heap[fh->pictnumptr+1]); + TRY(ds_push(fh, addr)); + TRY(ds_push(fh, len)); + return FH_OK; +} + +static enum fh_error pictnum_prepend_char(struct fh_thread_s *fh, char c) { + enum fh_error rv; + if (fh->pictnumptr < WORDBUF_ADDR) { + return FH_ERR_PICTNUM_FULL; + } + LOG("Prepend: %c", c); + TRY(fh_store_char(fh, fh->pictnumptr, c)); + fh->pictnumptr--; + return FH_OK; +} + +static char dig2char(uint64_t digit) { + char repr; + if (digit < 10) { + repr = '0' + digit; + } else if (digit < 36) { + repr = 'A' + (digit - 10); + } else { + repr = '?'; // XXX bad base? + } + return repr; +} + +static enum fh_error w_hash(struct fh_thread_s *fh, const struct fh_word_s *w) +{ + (void) w; + enum fh_error rv; + uint64_t num; + TRY(ds_pop_dw(fh, &num)); + uint64_t digit = num % fh->base; + TRY(pictnum_prepend_char(fh, dig2char(digit))); + TRY(ds_push_dw(fh, num / (uint64_t)fh->base)); + return FH_OK; +} + +static enum fh_error w_hash_s(struct fh_thread_s *fh, const struct fh_word_s *w) +{ + (void) w; + enum fh_error rv; + uint64_t num; + TRY(ds_pop_dw(fh, &num)); + + do { + uint64_t digit = num % fh->base; + num = num / (uint64_t)fh->base; + TRY(pictnum_prepend_char(fh, dig2char(digit))); + } while (num > 0); + + TRY(ds_push_dw(fh, num)); // this is zero now + return FH_OK; +} + +static enum fh_error w_sign(struct fh_thread_s *fh, const struct fh_word_s *w) +{ + (void) w; + enum fh_error rv; + uint32_t num; + TRY(ds_pop(fh, &num)); + if ((int32_t)num < 0) { + TRY(pictnum_prepend_char(fh, '-')); + } + return FH_OK; +} + +static enum fh_error w_hold(struct fh_thread_s *fh, const struct fh_word_s *w) +{ + (void) w; + enum fh_error rv; + uint32_t ch; + TRY(ds_pop(fh, &ch)); + + char buf[5]; + int num = utf8_encode(buf, ch); + for(int i=num-1;i>=0;i--) { + TRY(pictnum_prepend_char(fh, buf[i])); + } + return FH_OK; +} + +static enum fh_error w_holds(struct fh_thread_s *fh, const struct fh_word_s *w) +{ + (void) w; + enum fh_error rv; + uint32_t ch; + + uint32_t count = 0, addr = 0; + LOG("Get count,addr"); + TRY(ds_pop(fh, &count)); + TRY(ds_pop(fh, &addr)); + + const char *str = fh_str_at(fh, addr); + if (!str) { + LOGE("HOLDS addr out of bounds!"); + return FH_ERR_NOT_APPLICABLE; + } + + for(int i=count-1;i>=0;i--) { + TRY(pictnum_prepend_char(fh, str[i])); + } + + return FH_OK; +} + const struct name_and_handler fh_builtins_text[] = { {"s\"", w_s_quote, 1, 0}, {"s\\\"", w_s_quote, 1, 1}, // escaped @@ -232,5 +362,12 @@ const struct name_and_handler fh_builtins_text[] = { {"??", w_debug_dump, 0, 0}, {"emit", w_emit, 0, 0}, {"see", w_see, 0, 0}, + {"<#", w_less_hash, 0, 0}, + {"#>", w_hash_greater, 0, 0}, + {"#", w_hash, 0, 0}, + {"#s", w_hash_s, 0, 0}, + {"sign", w_sign, 0, 0}, + {"hold", w_hold, 0, 0}, + {"holds", w_holds, 0, 0}, { /* end marker */ } }; diff --git a/src/fh_error.c b/src/fh_error.c index db67bf8..942620c 100644 --- a/src/fh_error.c +++ b/src/fh_error.c @@ -20,6 +20,7 @@ static const char *errornames[FH_ERR_MAX] = { [FH_ERR_ILLEGAL_STORE] = "ILLEGAL_STORE", [FH_ERR_ARITH] = "ARITHMETIC_ERROR", [FH_ERR_SYNTAX] = "SYNTAX_ERROR", + [FH_ERR_PICTNUM_FULL] = "PICTNUM_FULL", [FH_ERR_NOT_APPLICABLE] = "NOT_APPLICABLE", }; diff --git a/testfiles/combinedtest.f b/testfiles/combinedtest.f index f74f1f5..6686fe1 100644 --- a/testfiles/combinedtest.f +++ b/testfiles/combinedtest.f @@ -838,6 +838,7 @@ T{ ' W1 >BODY -> HERE }T T{ W1 -> HERE 1 + }T T{ W1 -> HERE 2 + }T +0 [if] \ TODO \ ------------------------------------------------------------------------ TESTING EVALUATE @@ -882,6 +883,7 @@ DROP -> 0 }T \ BLANK LINE RETURN ZERO-LENGTH STRING : GS4 SOURCE >IN ! DROP ; T{ GS4 123 456 -> }T +[then] \ ------------------------------------------------------------------------ TESTING <# # #S #> HOLD SIGN BASE >NUMBER HEX DECIMAL