many fixes using prelimtest

master
Ondřej Hruška 3 years ago
parent 883cc7faf1
commit 5da44313c5
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 1
      CMakeLists.txt
  2. 2
      include/fh_config.h
  3. 1
      include/fh_error.h
  4. 2
      include/fh_globals.h
  5. 1
      include/fh_mem.h
  6. 21
      include/fh_parse.h
  7. 10
      include/fh_runtime.h
  8. 2
      src/fh_builtins_arith.c
  9. 34
      src/fh_builtins_mem.c
  10. 91
      src/fh_builtins_meta.c
  11. 18
      src/fh_builtins_system.c
  12. 1
      src/fh_error.c
  13. 14
      src/fh_mem.c
  14. 143
      src/fh_parse.c
  15. 124
      src/fh_runtime.c
  16. 12
      src/main.c

@ -18,6 +18,7 @@ add_executable(forth
src/fh_mem.c src/fh_mem.c
src/fh_error.c src/fh_error.c
src/fh_see.c src/fh_see.c
src/fh_parse.c
) )
target_include_directories(forth PRIVATE include) target_include_directories(forth PRIVATE include)

@ -13,7 +13,7 @@
#define HEAP_SIZE (1024*1024) #define HEAP_SIZE (1024*1024)
#define MAXLINE 65535 #define MAXLINE 65535
#define PAD_OFFSET 340 // why? copied from somewhere #define PAD_OFFSET 340 // why? copied from somewhere
#define WORDBUF_SIZE 128 #define WORDBUF_SIZE 256
#define INPUT_BUFFER_SIZE 256 #define INPUT_BUFFER_SIZE 256
#define CELL 4 #define CELL 4

@ -27,6 +27,7 @@ enum fh_error {
FH_ERR_ILLEGAL_STORE, FH_ERR_ILLEGAL_STORE,
FH_ERR_DIV_BY_ZERO, FH_ERR_DIV_BY_ZERO,
FH_ERR_SYNTAX, FH_ERR_SYNTAX,
FH_ERR_NOT_APPLICABLE,
FH_ERR_MAX, FH_ERR_MAX,
}; };

@ -15,6 +15,8 @@ struct fh_global_s {
bool verbose; bool verbose;
/** Interactive mode (i.e. not started with a file argument) */ /** Interactive mode (i.e. not started with a file argument) */
bool interactive; bool interactive;
/** Echo read lines in non-interactive mode */
bool echo;
}; };
extern struct fh_global_s fh_globals; extern struct fh_global_s fh_globals;

@ -29,6 +29,7 @@ enum fh_error fh_heap_reserve(
void fh_heap_write(struct fh_thread_s *fh, uint32_t addr, const void *src, uint32_t len); void fh_heap_write(struct fh_thread_s *fh, uint32_t addr, const void *src, uint32_t len);
enum fh_error fh_heap_put(struct fh_thread_s *fh, const void *src, uint32_t len); enum fh_error fh_heap_put(struct fh_thread_s *fh, const void *src, uint32_t len);
void fh_heap_copy(struct fh_thread_s *fh, uint32_t addr, uint32_t srcaddr, uint32_t len); void fh_heap_copy(struct fh_thread_s *fh, uint32_t addr, uint32_t srcaddr, uint32_t len);
void fh_heap_copyptr(struct fh_thread_s *fh, uint32_t addr, char * source, uint32_t len);
enum fh_error fh_put_instr(struct fh_thread_s *fh, enum fb_instruction_kind kind, uint32_t data); enum fh_error fh_put_instr(struct fh_thread_s *fh, enum fb_instruction_kind kind, uint32_t data);

@ -0,0 +1,21 @@
/**
* Parsing
*
* Created on 2021/11/17.
*/
#ifndef FORTH_FH_PARSE_H
#define FORTH_FH_PARSE_H
typedef bool (*chartest_t)(char c, void* param);
void fh_input_consume_matching(struct fh_thread_s *fh, chartest_t test, void* param);
void fh_input_consume_spaces(struct fh_thread_s *fh);
enum fh_error fh_input_read_delimited(struct fh_thread_s *fh, char **out, size_t *len, chartest_t test, void* param);
enum fh_error fh_input_read_word(struct fh_thread_s *fh, char **out, size_t *len);
enum fh_error fh_input_read_quotedstring(struct fh_thread_s *fh, bool escaped, char *outbuf, size_t capacity, size_t *out_len);
#endif //FORTH_FH_PARSE_H

@ -197,19 +197,17 @@ struct fh_thread_s {
#define INPUTBUF_ADDR (HEAP_END + WORDBUF_SIZE) #define INPUTBUF_ADDR (HEAP_END + WORDBUF_SIZE)
enum fh_error fh_loop_nest(struct fh_thread_s *fh, uint32_t indexvalue); enum fh_error fh_loop_nest(struct fh_thread_s *fh, uint32_t indexvalue);
enum fh_error fh_loop_unnest(struct fh_thread_s *fh); enum fh_error fh_loop_unnest(struct fh_thread_s *fh);
enum fh_error fh_add_word(const struct fh_word_s *w, struct fh_thread_s *fh); enum fh_error fh_add_word(const struct fh_word_s *w, struct fh_thread_s *fh);
void fh_setstate(struct fh_thread_s *fh, enum fh_state state, enum fh_substate substate); void fh_setstate(struct fh_thread_s *fh, enum fh_state state, enum fh_substate substate);
void fh_setsubstate(struct fh_thread_s *fh, enum fh_substate substate); void fh_setsubstate(struct fh_thread_s *fh, enum fh_substate substate);
enum fh_error w_user_word(struct fh_thread_s *fh, const struct fh_word_s *w); enum fh_error w_user_word(struct fh_thread_s *fh, const struct fh_word_s *w);
enum fh_error fh_input_read_quotedstring(struct fh_thread_s *fh, bool escaped, char *outbuf, size_t capacity, size_t *out_len);
enum fh_error fh_input_read_word(struct fh_thread_s *fh, char **out, size_t *len);
void fh_input_consume_spaces(struct fh_thread_s *fh);
enum fh_error fh_postpone_word( enum fh_error fh_postpone_word(
struct fh_thread_s *fh, struct fh_thread_s *fh,
const char *name, const char *name,
@ -226,9 +224,11 @@ enum fh_error fh_see_word(
/* if the return address is this, we should drop back to interactive mode */ /* if the return address is this, we should drop back to interactive mode */
// SFR and magic addresses are "negative" // SFR and magic addresses are "negative"
#define MAGICADDR_INTERACTIVE 0xFFFFFFFFULL #define MAGICADDR_EXEC_INTERACTIVE 0xFFFFFFFFULL
#define MAGICADDR_BASE 0xFFFFBA5EULL #define MAGICADDR_BASE 0xFFFFBA5EULL
#define MAGICADDR_HERE 0xFFFF4E7EULL #define MAGICADDR_HERE 0xFFFF4E7EULL
#define MAGICADDR_INPTR 0xFFFFF111ULL
#define MAGICADDR_UNRESOLVED 0xFFFFFBADULL #define MAGICADDR_UNRESOLVED 0xFFFFFBADULL
/** Get a value rounded up to multiple of word size */ /** Get a value rounded up to multiple of word size */

@ -90,7 +90,7 @@ static enum fh_error w_zero_less(struct fh_thread_s *fh, const struct fh_word_s
enum fh_error rv; enum fh_error rv;
uint32_t a = 0; uint32_t a = 0;
TRY(ds_pop(fh, &a)); TRY(ds_pop(fh, &a));
TRY(ds_push(fh, TOBOOL(a < 0))); TRY(ds_push(fh, TOBOOL((int32_t)a < 0)));
return FH_OK; return FH_OK;
} }

@ -39,7 +39,7 @@ static enum fh_error w_plus_store(struct fh_thread_s *fh, const struct fh_word_s
uint32_t val = 0; uint32_t val = 0;
TRY(fh_fetch(fh, addr, &val)); TRY(fh_fetch(fh, addr, &val));
uint32_t val2 = 0; uint32_t val2 = 0;
TRY(ds_pop(fh, &val)); TRY(ds_pop(fh, &val2));
TRY(fh_store(fh, addr, val2 + val)); TRY(fh_store(fh, addr, val2 + val));
return FH_OK; return FH_OK;
@ -96,7 +96,7 @@ static enum fh_error w_allot(struct fh_thread_s *fh, const struct fh_word_s *w)
TRY(fh_heap_reserve(fh, ci, NULL)); TRY(fh_heap_reserve(fh, ci, NULL));
} else { } else {
LOG("Deallot %d", count); LOG("Deallot %d", count);
fh->here = WORDALIGNED((uint32_t) (int32_t)fh->here + count); fh->here = WORDALIGNED((uint32_t) (int32_t) fh->here + count);
} }
return FH_OK; return FH_OK;
} }
@ -148,21 +148,21 @@ static enum fh_error w_here(struct fh_thread_s *fh, const struct fh_word_s *w)
} }
const struct name_and_handler fh_builtins_mem[] = { const struct name_and_handler fh_builtins_mem[] = {
{"chars", wp_mul, 0, 1}, {"chars", wp_mul, 0, 1},
{"char+", wp_add, 0, 1}, {"char+", wp_add, 0, 1},
{"cells", wp_mul, 0, CELL}, {"cells", wp_mul, 0, CELL},
{"cell+", wp_add, 0, CELL}, {"cell+", wp_add, 0, CELL},
{"@", w_fetch, 0, 0}, {"@", w_fetch, 0, 0},
{"!", w_store, 0, 0}, {"!", w_store, 0, 0},
{"+!", w_plus_store, 0, 0}, {"+!", w_plus_store, 0, 0},
{"2!", w_two_store, 0, 0}, {"2!", w_two_store, 0, 0},
{"2@", w_two_fetch, 0, 0}, {"2@", w_two_fetch, 0, 0},
{"aligned", w_aligned, 0, 0}, {"aligned", w_aligned, 0, 0},
{"allot", w_allot, 0, 0}, {"allot", w_allot, 0, 0},
{"align", w_align, 0, 0}, {"align", w_align, 0, 0},
{",", w_comma, 0, 0}, {",", w_comma, 0, 0},
{"here", w_here, 0, 0}, {"here", w_here, 0, 0},
{"pad", w_pad, 0, 0}, {"pad", w_pad, 0, 0},
{ /* end marker */ } { /* end marker */ }
}; };

@ -5,6 +5,7 @@
#include "fh_stack.h" #include "fh_stack.h"
#include "fh_print.h" #include "fh_print.h"
#include "fh_builtins.h" #include "fh_builtins.h"
#include "fh_parse.h"
static enum fh_error w_colon(struct fh_thread_s *fh, const struct fh_word_s *w) static enum fh_error w_colon(struct fh_thread_s *fh, const struct fh_word_s *w)
{ {
@ -179,6 +180,17 @@ static enum fh_error w_rightbracket(struct fh_thread_s *fh, const struct fh_word
return FH_OK; return FH_OK;
} }
static enum fh_error w_source(struct fh_thread_s *fh, const struct fh_word_s *w)
{
(void) w;
enum fh_error rv;
TRY(ds_push(fh, INPUTBUF_ADDR));
TRY(ds_push(fh, fh->inputlen));
// TRY(ds_push(fh, INPUTBUF_ADDR + fh->inputptr));
// TRY(ds_push(fh, fh->inputlen - fh->inputptr));
return FH_OK;
}
static enum fh_error w_literal(struct fh_thread_s *fh, const struct fh_word_s *w) static enum fh_error w_literal(struct fh_thread_s *fh, const struct fh_word_s *w)
{ {
(void) w; (void) w;
@ -251,7 +263,83 @@ static enum fh_error w_char(struct fh_thread_s *fh, const struct fh_word_s *w)
return FH_OK; return FH_OK;
} }
static enum fh_error w_depth(struct fh_thread_s *fh, const struct fh_word_s *w)
{
(void) w;
enum fh_error rv;
TRY(ds_push(fh, fh->data_stack_top));
return FH_OK;
}
static enum fh_error w_unused(struct fh_thread_s *fh, const struct fh_word_s *w)
{
(void) w;
enum fh_error rv;
TRY(ds_push(fh, HEAP_SIZE - fh->here));
return FH_OK;
}
static enum fh_error w_to_in(struct fh_thread_s *fh, const struct fh_word_s *w)
{
(void) w;
enum fh_error rv;
TRY(ds_push(fh, MAGICADDR_INPTR));
return FH_OK;
}
static bool chartest_equals_or_end(char c, void *param)
{
char cc = (char) *(uint32_t *) param;
return c == cc || c == 0;
}
static enum fh_error w_word(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));
if (ch > 0xFF) {
LOGE("Char out of ASCII bounds!");
return FH_ERR_NOT_APPLICABLE;
}
fh_input_consume_matching(fh, chartest_equals_or_end, &ch);
char *out;
size_t len;
fh_input_read_delimited(fh, &out, &len, chartest_equals_or_end, &ch);
if (len >= WORDBUF_SIZE) {
LOGE("WORD parsed string too long");
return FH_ERR_NAME_TOO_LONG;
}
fh_store_char(fh, WORDBUF_ADDR, (char) len);
fh_heap_copyptr(fh, WORDBUF_ADDR + 1, out, len);
TRY(ds_push(fh, WORDBUF_ADDR));
return FH_OK;
}
static enum fh_error w_count(struct fh_thread_s *fh, const struct fh_word_s *w)
{
(void) w;
enum fh_error rv;
uint32_t caddr;
TRY(ds_pop(fh, &caddr));
uint8_t len;
TRY(fh_fetch_char(fh, caddr, (char*)&len));
TRY(ds_push(fh, caddr + 1));
TRY(ds_push(fh, len));
return FH_OK;
}
const struct name_and_handler fh_builtins_meta[] = { const struct name_and_handler fh_builtins_meta[] = {
{"depth", w_depth, 0, 0},
{"unused", w_unused, 0, 0},
{">in", w_to_in, 0, 0},
{":", w_colon, 0, 0}, {":", w_colon, 0, 0},
{";", w_semicolon, 1, 0}, {";", w_semicolon, 1, 0},
{"forget", w_forget, 1, 0}, {"forget", w_forget, 1, 0},
@ -261,6 +349,7 @@ const struct name_and_handler fh_builtins_meta[] = {
{"postpone", w_postpone, 1, 0}, {"postpone", w_postpone, 1, 0},
{"[", w_leftbracket, 1, 0}, {"[", w_leftbracket, 1, 0},
{"]", w_rightbracket, 1, 0}, {"]", w_rightbracket, 1, 0},
{"source", w_source, 0, 0},
{"literal", w_literal, 1, 0}, {"literal", w_literal, 1, 0},
{"char", w_char, 0, 0}, {"char", w_char, 0, 0},
{"[char]", w_char, 1, 0}, {"[char]", w_char, 1, 0},
@ -268,6 +357,8 @@ const struct name_and_handler fh_builtins_meta[] = {
{"variable", wp_variable, 1, 0}, {"variable", wp_variable, 1, 0},
{"value", wp_variable, 1, 1}, {"value", wp_variable, 1, 1},
{"constant", wp_variable, 1, 2}, {"constant", wp_variable, 1, 2},
{"word", w_word, 0, 0},
{"count", w_count, 0, 0},
{ /* end marker */ } { /* end marker */ }
}; };

@ -6,22 +6,6 @@
#include "fh_print.h" #include "fh_print.h"
#include "fh_builtins.h" #include "fh_builtins.h"
static enum fh_error w_depth(struct fh_thread_s *fh, const struct fh_word_s *w)
{
(void) w;
enum fh_error rv;
TRY(ds_push(fh, fh->data_stack_top));
return FH_OK;
}
static enum fh_error w_unused(struct fh_thread_s *fh, const struct fh_word_s *w)
{
(void) w;
enum fh_error rv;
TRY(ds_push(fh, HEAP_SIZE - fh->here));
return FH_OK;
}
// extension // extension
static enum fh_error w_reset(struct fh_thread_s *fh, const struct fh_word_s *w) static enum fh_error w_reset(struct fh_thread_s *fh, const struct fh_word_s *w)
{ {
@ -52,8 +36,6 @@ static enum fh_error w_debug(struct fh_thread_s *fh, const struct fh_word_s *w)
} }
const struct name_and_handler fh_builtins_system[] = { const struct name_and_handler fh_builtins_system[] = {
{"depth", w_depth, 0, 0},
{"unused", w_unused, 0, 0},
{"reset", w_reset, 1, 0}, {"reset", w_reset, 1, 0},
{"bye", w_bye, 0, 0}, {"bye", w_bye, 0, 0},
{"debug", w_debug, 0, 0}, {"debug", w_debug, 0, 0},

@ -20,6 +20,7 @@ static const char *errornames[FH_ERR_MAX] = {
[FH_ERR_ILLEGAL_STORE] = "ILLEGAL_STORE", [FH_ERR_ILLEGAL_STORE] = "ILLEGAL_STORE",
[FH_ERR_DIV_BY_ZERO] = "DIV_BY_ZERO", [FH_ERR_DIV_BY_ZERO] = "DIV_BY_ZERO",
[FH_ERR_SYNTAX] = "SYNTAX_ERROR", [FH_ERR_SYNTAX] = "SYNTAX_ERROR",
[FH_ERR_NOT_APPLICABLE] = "NOT_APPLICABLE",
}; };
/** Get error name from code, returns Unknown if not defined */ /** Get error name from code, returns Unknown if not defined */

@ -39,6 +39,10 @@ enum fh_error fh_fetch(struct fh_thread_s *fh, uint32_t addr, uint32_t *dst)
*dst = fh->here; *dst = fh->here;
break; break;
case MAGICADDR_INPTR:
*dst = fh->inputptr;
break;
default: default:
if (addr & 3) { if (addr & 3) {
LOGE("Address 0x%08x is not aligned!", addr); LOGE("Address 0x%08x is not aligned!", addr);
@ -78,6 +82,10 @@ enum fh_error fh_store(struct fh_thread_s *fh, uint32_t addr, uint32_t val)
LOGE("HERE is read-only!"); LOGE("HERE is read-only!");
return FH_ERR_ILLEGAL_STORE; return FH_ERR_ILLEGAL_STORE;
case MAGICADDR_INPTR:
fh->inputptr = val;
break;
default: default:
if (addr & 3) { if (addr & 3) {
LOGE("Address 0x%08x is not aligned!", addr); LOGE("Address 0x%08x is not aligned!", addr);
@ -166,6 +174,12 @@ void fh_heap_copy(struct fh_thread_s *fh, uint32_t addr, uint32_t srcaddr, uint3
memcpy(&fh->heap[addr], &fh->heap[srcaddr], len); memcpy(&fh->heap[addr], &fh->heap[srcaddr], len);
} }
/** Copy bytes from anywhere to heap. The region must have been previously allocated! */
void fh_heap_copyptr(struct fh_thread_s *fh, uint32_t addr, char * source, uint32_t len)
{
memcpy(&fh->heap[addr], source, len);
}
char *fh_str_at(struct fh_thread_s *fh, uint32_t addr) { char *fh_str_at(struct fh_thread_s *fh, uint32_t addr) {
if (addr >= HEAP_SIZE) { if (addr >= HEAP_SIZE) {

@ -0,0 +1,143 @@
#include <ctype.h>
#include <stdint.h>
#include <stddef.h>
#include "fh_print.h"
#include "fh_runtime.h"
#include "fh_error.h"
#include "fh_parse.h"
void fh_input_consume_matching(struct fh_thread_s *fh, chartest_t test, void* param) {
char *rp = (char *) &fh->heap[INPUTBUF_ADDR + fh->inputptr];
while (test(*rp, param)) {
rp++;
fh->inputptr++;
}
}
void fh_input_consume_spaces(struct fh_thread_s *fh) {
char *rp = (char *) &fh->heap[INPUTBUF_ADDR + fh->inputptr];
while (isspace(*rp)) {
rp++;
fh->inputptr++;
}
}
enum fh_error fh_input_read_delimited(struct fh_thread_s *fh, char **out, size_t *len, chartest_t test, void* param)
{
char *rp = (char *) &fh->heap[INPUTBUF_ADDR + fh->inputptr];
char *start = rp;
while (1) {
char c = *rp;
if (test(c, param)) {
if (rp == start) {
LOGE("Expected a word!");
return FH_ERR_SYNTAX;
}
*out = start;
*len = rp - start;
fh->inputptr++; // advance past the delimiter
return FH_OK;
}
rp++;
fh->inputptr++;
}
}
static bool chartest_space_or_end(char c, void *param)
{
(void)param;
return isspace(c) || c == 0;
}
enum fh_error fh_input_read_word(struct fh_thread_s *fh, char **out, size_t *len) {
return fh_input_read_delimited(fh, out, len, chartest_space_or_end, NULL);
}
enum fh_error fh_input_read_quotedstring(struct fh_thread_s *fh, bool escaped, char *outbuf, size_t capacity, size_t *out_len) {
char *rp = (char *) &fh->heap[INPUTBUF_ADDR + fh->inputptr];
bool next_escaped = false;
size_t remains = capacity;
size_t len = 0;
int hexdigits = 0;
uint32_t hex = 0;
while (len < capacity) {
char c = *rp;
if (c == 0) {
LOGE("Unterminated quoted string!");
return FH_ERR_SYNTAX;
}
if (hexdigits) {
hex <<= 4;
if (isdigit(c)) {
hex |= c - '0';
} else if (c>='a' && c<='f') {
hex |= c - 'a';
} else if (c>='A' && c<='F') {
hex |= c - 'A';
} else {
LOGE("Bad hex escape");
return FH_ERR_SYNTAX;
}
hexdigits--;
if (hexdigits == 0) {
c = (char) hex;
goto append;
}
}
if (!escaped || !next_escaped) {
if (c == '\"') {
*outbuf = 0;
*out_len = len;
// advance past the quote
fh->inputptr++;
return FH_OK;
}
if (c == '\\') {
next_escaped = true;
goto skip;
}
} else {
next_escaped = false;
switch (c) {
case 'a': c = 7; break;
case 'b': c = 8; break;
case 'e': c = 27; break;
case 'f': c = 12; break;
case 'l': c = 10; break;
case 'm':
case 'n':
if (remains < 2) goto full;
*outbuf++ = '\r';
*outbuf++ = '\n';
remains -= 2;
len += 2;
goto skip;
case 'q': c = '"'; break;
case 'r': c = '\r'; break;
case 't': c = '\t'; break;
case 'v': c = '\v'; break;
case 'z': c = 0; break; // XXX this will cause problems!
case 'x':
hex = 0;
hexdigits = 2;
goto skip;
default:;
// just append normally
}
}
append:
*outbuf++ = c;
len++;
skip:
rp++;
fh->inputptr++;
}
full:
LOGE("String too long!");
return FH_ERR_SYNTAX;
}

@ -28,122 +28,6 @@ static const char *substatenames[FH_SUBSTATE_MAX] = {
[FH_SUBSTATE_EXIT] = "EXIT", [FH_SUBSTATE_EXIT] = "EXIT",
}; };
void fh_input_consume_spaces(struct fh_thread_s *fh) {
char *rp = (char *) &fh->heap[INPUTBUF_ADDR + fh->inputptr];
while (isspace(*rp)) {
rp++;
fh->inputptr++;
}
}
enum fh_error fh_input_read_word(struct fh_thread_s *fh, char **out, size_t *len) {
char *rp = (char *) &fh->heap[INPUTBUF_ADDR + fh->inputptr];
char *start = rp;
while (1) {
char c = *rp;
if (isspace(c) || c == 0) {
if (rp == start) {
LOGE("Expected a word!");
return FH_ERR_SYNTAX;
}
*out = start;
*len = rp - start;
return FH_OK;
}
rp++;
fh->inputptr++;
}
}
enum fh_error fh_input_read_quotedstring(struct fh_thread_s *fh, bool escaped, char *outbuf, size_t capacity, size_t *out_len) {
char *rp = (char *) &fh->heap[INPUTBUF_ADDR + fh->inputptr];
bool next_escaped = false;
size_t remains = capacity;
size_t len = 0;
int hexdigits = 0;
uint32_t hex = 0;
while (len < capacity) {
char c = *rp;
if (c == 0) {
LOGE("Unterminated quoted string!");
return FH_ERR_SYNTAX;
}
if (hexdigits) {
hex <<= 4;
if (isdigit(c)) {
hex |= c - '0';
} else if (c>='a' && c<='f') {
hex |= c - 'a';
} else if (c>='A' && c<='F') {
hex |= c - 'A';
} else {
LOGE("Bad hex escape");
return FH_ERR_SYNTAX;
}
hexdigits--;
if (hexdigits == 0) {
c = (char) hex;
goto append;
}
}
if (!escaped || !next_escaped) {
if (c == '\"') {
*outbuf = 0;
*out_len = len;
// advance past the quote
fh->inputptr++;
return FH_OK;
}
if (c == '\\') {
next_escaped = true;
goto skip;
}
} else {
next_escaped = false;
switch (c) {
case 'a': c = 7; break;
case 'b': c = 8; break;
case 'e': c = 27; break;
case 'f': c = 12; break;
case 'l': c = 10; break;
case 'm':
case 'n':
if (remains < 2) goto full;
*outbuf++ = '\r';
*outbuf++ = '\n';
remains -= 2;
len += 2;
goto skip;
case 'q': c = '"'; break;
case 'r': c = '\r'; break;
case 't': c = '\t'; break;
case 'v': c = '\v'; break;
case 'z': c = 0; break; // XXX this will cause problems!
case 'x':
hex = 0;
hexdigits = 2;
goto skip;
default:;
// just append normally
}
}
append:
*outbuf++ = c;
len++;
skip:
rp++;
fh->inputptr++;
}
full:
LOGE("String too long!");
return FH_ERR_SYNTAX;
}
/** Add a word to the dictionary. */ /** Add a word to the dictionary. */
enum fh_error fh_add_word(const struct fh_word_s *w, struct fh_thread_s *fh) enum fh_error fh_add_word(const struct fh_word_s *w, struct fh_thread_s *fh)
{ {
@ -250,7 +134,7 @@ enum fh_error w_user_word(struct fh_thread_s *fh, const struct fh_word_s *w0)
fh_setsubstate(fh, 0); fh_setsubstate(fh, 0);
LOG("Exec: early return"); LOG("Exec: early return");
TRY(rs_pop(fh, &fh->execptr)); TRY(rs_pop(fh, &fh->execptr));
if (fh->execptr == MAGICADDR_INTERACTIVE) { if (fh->execptr == MAGICADDR_EXEC_INTERACTIVE) {
goto end; goto end;
} }
} }
@ -373,7 +257,7 @@ enum fh_error w_user_word(struct fh_thread_s *fh, const struct fh_word_s *w0)
case FH_INSTR_ENDWORD: case FH_INSTR_ENDWORD:
LOG("Exec: word-end (RETURN)"); LOG("Exec: word-end (RETURN)");
TRY(rs_pop(fh, &fh->execptr)); TRY(rs_pop(fh, &fh->execptr));
if (fh->execptr == MAGICADDR_INTERACTIVE) { if (fh->execptr == MAGICADDR_EXEC_INTERACTIVE) {
goto end; goto end;
} }
goto instr; goto instr;
@ -395,7 +279,7 @@ enum fh_error fh_init(struct fh_thread_s *fh)
fh->dict_last = MAGICADDR_DICTFIRST; fh->dict_last = MAGICADDR_DICTFIRST;
TRY(register_builtin_words(fh)); TRY(register_builtin_words(fh));
fh->execptr = MAGICADDR_INTERACTIVE; fh->execptr = MAGICADDR_EXEC_INTERACTIVE;
fh->base = 10; fh->base = 10;
return FH_OK; return FH_OK;
} }
@ -545,7 +429,7 @@ enum fh_error fh_process_line(struct fh_thread_s *fh, const char *linebuf, size_
char c; char c;
if (!fh_globals.interactive) { if (fh_globals.echo && !fh_globals.interactive) {
LOGI("%s", linebuf); LOGI("%s", linebuf);
} }

@ -12,6 +12,7 @@ int main(int argc, char *argv[])
{ {
fh_globals.verbose = false; fh_globals.verbose = false;
fh_globals.interactive = isatty(STDIN_FILENO); fh_globals.interactive = isatty(STDIN_FILENO);
fh_globals.echo = 0;
FILE *infile = stdin; FILE *infile = stdin;
@ -26,6 +27,9 @@ int main(int argc, char *argv[])
case 'v': case 'v':
fh_globals.verbose = 1; fh_globals.verbose = 1;
break; break;
case 'e':
fh_globals.echo = 1;
break;
default: default:
LOGE("Unknown flag: %c", c); LOGE("Unknown flag: %c", c);
return 1; return 1;
@ -70,7 +74,9 @@ int main(int argc, char *argv[])
rv = fh_process_line(&fh, linebuf, strlen(linebuf)); rv = fh_process_line(&fh, linebuf, strlen(linebuf));
if (rv == FH_OK) { if (rv == FH_OK) {
FHPRINT_SVC(" ok\n"); if (fh_globals.interactive || fh_globals.echo) {
FHPRINT_SVC(" ok\n");
}
} else { } else {
LOGE("ERROR %s on line %d", fherr_name(rv), linecnt); LOGE("ERROR %s on line %d", fherr_name(rv), linecnt);
if (!fh_globals.interactive) { if (!fh_globals.interactive) {
@ -83,7 +89,9 @@ int main(int argc, char *argv[])
fh.return_stack_top = 0; fh.return_stack_top = 0;
} }
FHPRINT("%s", prompt); if (fh_globals.interactive) {
FHPRINT("%s", prompt);
}
} }
// Show resource usage // Show resource usage

Loading…
Cancel
Save