diff --git a/include/fh_runtime.h b/include/fh_runtime.h index 9fbc980..85a9473 100644 --- a/include/fh_runtime.h +++ b/include/fh_runtime.h @@ -35,6 +35,11 @@ enum fh_instruction_kind { /** This is the `s"` instruction, the length (u32) and string data immediately follow */ FH_INSTR_ALLOCSTR, + /** This is the `c"` instruction, the length (u32) and string data immediately follow. + * The string data already contains the length prefix. + */ + FH_INSTR_ALLOCSTR_C, + /** This is the `."` instruction, same format as above. */ FH_INSTR_TYPESTR, diff --git a/src/fh_builtins_text.c b/src/fh_builtins_text.c index e436882..be2c58b 100644 --- a/src/fh_builtins_text.c +++ b/src/fh_builtins_text.c @@ -209,6 +209,39 @@ static enum fh_error w_s_quote(struct fh_thread_s *fh, const struct fh_word_s *w return FH_OK; } +static enum fh_error w_c_quote(struct fh_thread_s *fh, const struct fh_word_s *w) +{ + (void) w; + enum fh_error rv; + size_t len; + uint32_t addr = fh->here + (fh->state == FH_STATE_INTERPRET ? 0 : INSTR_SIZE); + + /* read the string straight into HEAP */ + + fh_input_consume_spaces(fh); + char *start = ((char *) &fh->heap[addr]) + 1; // space for the counter + uint32_t maxlen = HEAP_END - addr; + if (maxlen > 255) { + maxlen = 255; + } + TRY(fh_input_read_quotedstring(fh, w->param == 1, start, maxlen, &len)); + fh->here = WORDALIGNED(addr + len + 1); + fh->heap[addr] = (uint8_t) len; // char count + + struct fh_instruction_s instr; + if (fh->state == FH_STATE_INTERPRET) { + LOG("Interpret a c-string alloc: \"%.*s\"", len, start); + TRY(ds_push(fh, addr)); + } else { + LOG("Compile a c-string: \"%.*s\"", len, start); + instr.kind = FH_INSTR_ALLOCSTR_C; + instr.data = WORDALIGNED(len + 1); + fh_heap_write(fh, addr - INSTR_SIZE, &instr, INSTR_SIZE); + } + + return FH_OK; +} + static bool chartest_equals_or_end(char c, void *param) { char cc = *(char*)param; @@ -443,6 +476,7 @@ static enum fh_error w_to_number(struct fh_thread_s *fh, const struct fh_word_s const struct name_and_handler fh_builtins_text[] = { {"s\"", w_s_quote, 1, 0}, + {"c\"", w_c_quote, 1, 0}, {"s\\\"", w_s_quote, 1, 1}, // escaped {".\"", w_dot_quote, 1, '"'}, {".(", w_dot_quote, 1, ')'}, diff --git a/src/fh_runtime.c b/src/fh_runtime.c index f9e0774..bacddac 100644 --- a/src/fh_runtime.c +++ b/src/fh_runtime.c @@ -344,18 +344,24 @@ enum fh_error w_user_word(struct fh_thread_s *fh, const struct fh_word_s *w0) TRY(ds_pop(fh, &val)); // discard the tested value goto instr; - /* special case for strings stored in compile memory */ case FH_INSTR_ALLOCSTR: + strl = instr->data; + LOG("\x1b[35mExec: alloc-str\x1b[m \"%.*s\"", strl, fh_str_at(fh, fh->execptr)); + TRY(ds_push(fh, fh->execptr)); // give pointer directly into the definition + TRY(ds_push(fh, strl)); + fh->execptr += strl; + goto instr; + + case FH_INSTR_ALLOCSTR_C: + LOG("\x1b[35mExec: alloc-str-c\x1b[m \"%.*s\"", fh->heap[fh->execptr], fh_str_at(fh, fh->execptr+1)); + TRY(ds_push(fh, fh->execptr)); + fh->execptr += instr->data; + goto instr; + case FH_INSTR_TYPESTR: strl = instr->data; - if (instr->kind == FH_INSTR_ALLOCSTR) { - LOG("\x1b[35mExec: alloc-str\x1b[m \"%.*s\"", strl, fh_str_at(fh, fh->execptr)); - TRY(ds_push(fh, fh->execptr)); // give pointer directly into the definition - TRY(ds_push(fh, strl)); - } else { - LOG("\x1b[35mExec: type-str\x1b[m \"%.*s\"", strl, fh_str_at(fh, fh->execptr)); - FHPRINT("%.*s", (int) strl, fh_str_at(fh, fh->execptr)); - } + LOG("\x1b[35mExec: type-str\x1b[m \"%.*s\"", strl, fh_str_at(fh, fh->execptr)); + FHPRINT("%.*s", (int) strl, fh_str_at(fh, fh->execptr)); fh->execptr += strl; goto instr; diff --git a/src/fh_see.c b/src/fh_see.c index e336583..25a2814 100644 --- a/src/fh_see.c +++ b/src/fh_see.c @@ -100,15 +100,21 @@ static void show_word(struct fh_thread_s *fh, const struct fh_word_s *w) /* special case for strings stored in compile memory */ case FH_INSTR_ALLOCSTR: + strl = instr->data; + FHPRINT("AllocStr(\"%.*s\")\n", strl, fh_str_at(fh, execptr)); + execptr += strl; + break; + case FH_INSTR_TYPESTR: strl = instr->data; - if (instr->kind == FH_INSTR_ALLOCSTR) { - FHPRINT("AllocStr(\"%.*s\")\n", strl, fh_str_at(fh, execptr)); - execptr += strl; - } else { - FHPRINT("PrintStr(\"%.*s\")\n", strl, fh_str_at(fh, execptr)); - execptr += strl; - } + FHPRINT("PrintStr(\"%.*s\")\n", strl, fh_str_at(fh, execptr)); + execptr += strl; + break; + + case FH_INSTR_ALLOCSTR_C: + strl = instr->data; + FHPRINT("AllocStrC(%d, \"%.*s\")\n", fh->heap[execptr], fh->heap[execptr], fh_str_at(fh, execptr + 1)); + execptr += strl; break; case FH_INSTR_ENDWORD: