|
|
@ -217,6 +217,136 @@ static enum fh_error w_dot_quote(struct fh_thread_s *fh, const struct fh_word_s |
|
|
|
return FH_OK; |
|
|
|
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[] = { |
|
|
|
const struct name_and_handler fh_builtins_text[] = { |
|
|
|
{"s\"", w_s_quote, 1, 0}, |
|
|
|
{"s\"", w_s_quote, 1, 0}, |
|
|
|
{"s\\\"", w_s_quote, 1, 1}, // escaped
|
|
|
|
{"s\\\"", w_s_quote, 1, 1}, // escaped
|
|
|
@ -232,5 +362,12 @@ const struct name_and_handler fh_builtins_text[] = { |
|
|
|
{"??", w_debug_dump, 0, 0}, |
|
|
|
{"??", w_debug_dump, 0, 0}, |
|
|
|
{"emit", w_emit, 0, 0}, |
|
|
|
{"emit", w_emit, 0, 0}, |
|
|
|
{"see", w_see, 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 */ } |
|
|
|
{ /* end marker */ } |
|
|
|
}; |
|
|
|
}; |
|
|
|