many fixes using prelimtest
This commit is contained in:
@@ -18,6 +18,7 @@ add_executable(forth
|
||||
src/fh_mem.c
|
||||
src/fh_error.c
|
||||
src/fh_see.c
|
||||
src/fh_parse.c
|
||||
)
|
||||
|
||||
target_include_directories(forth PRIVATE include)
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@
|
||||
#define HEAP_SIZE (1024*1024)
|
||||
#define MAXLINE 65535
|
||||
#define PAD_OFFSET 340 // why? copied from somewhere
|
||||
#define WORDBUF_SIZE 128
|
||||
#define WORDBUF_SIZE 256
|
||||
#define INPUT_BUFFER_SIZE 256
|
||||
|
||||
#define CELL 4
|
||||
|
||||
@@ -27,6 +27,7 @@ enum fh_error {
|
||||
FH_ERR_ILLEGAL_STORE,
|
||||
FH_ERR_DIV_BY_ZERO,
|
||||
FH_ERR_SYNTAX,
|
||||
FH_ERR_NOT_APPLICABLE,
|
||||
FH_ERR_MAX,
|
||||
};
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@ struct fh_global_s {
|
||||
bool verbose;
|
||||
/** Interactive mode (i.e. not started with a file argument) */
|
||||
bool interactive;
|
||||
/** Echo read lines in non-interactive mode */
|
||||
bool echo;
|
||||
};
|
||||
|
||||
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);
|
||||
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_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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
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_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_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 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(
|
||||
struct fh_thread_s *fh,
|
||||
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 */
|
||||
|
||||
// SFR and magic addresses are "negative"
|
||||
#define MAGICADDR_INTERACTIVE 0xFFFFFFFFULL
|
||||
#define MAGICADDR_EXEC_INTERACTIVE 0xFFFFFFFFULL
|
||||
|
||||
#define MAGICADDR_BASE 0xFFFFBA5EULL
|
||||
#define MAGICADDR_HERE 0xFFFF4E7EULL
|
||||
#define MAGICADDR_INPTR 0xFFFFF111ULL
|
||||
#define MAGICADDR_UNRESOLVED 0xFFFFFBADULL
|
||||
|
||||
/** 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;
|
||||
uint32_t a = 0;
|
||||
TRY(ds_pop(fh, &a));
|
||||
TRY(ds_push(fh, TOBOOL(a < 0)));
|
||||
TRY(ds_push(fh, TOBOOL((int32_t)a < 0)));
|
||||
return FH_OK;
|
||||
}
|
||||
|
||||
|
||||
+17
-17
@@ -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;
|
||||
TRY(fh_fetch(fh, addr, &val));
|
||||
uint32_t val2 = 0;
|
||||
TRY(ds_pop(fh, &val));
|
||||
TRY(ds_pop(fh, &val2));
|
||||
|
||||
TRY(fh_store(fh, addr, val2 + val));
|
||||
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));
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
@@ -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[] = {
|
||||
{"chars", wp_mul, 0, 1},
|
||||
{"char+", wp_add, 0, 1},
|
||||
{"cells", wp_mul, 0, CELL},
|
||||
{"cell+", wp_add, 0, CELL},
|
||||
{"@", w_fetch, 0, 0},
|
||||
{"!", w_store, 0, 0},
|
||||
{"+!", w_plus_store, 0, 0},
|
||||
{"2!", w_two_store, 0, 0},
|
||||
{"2@", w_two_fetch, 0, 0},
|
||||
{"aligned", w_aligned, 0, 0},
|
||||
{"allot", w_allot, 0, 0},
|
||||
{"align", w_align, 0, 0},
|
||||
{",", w_comma, 0, 0},
|
||||
{"here", w_here, 0, 0},
|
||||
{"pad", w_pad, 0, 0},
|
||||
{"chars", wp_mul, 0, 1},
|
||||
{"char+", wp_add, 0, 1},
|
||||
{"cells", wp_mul, 0, CELL},
|
||||
{"cell+", wp_add, 0, CELL},
|
||||
{"@", w_fetch, 0, 0},
|
||||
{"!", w_store, 0, 0},
|
||||
{"+!", w_plus_store, 0, 0},
|
||||
{"2!", w_two_store, 0, 0},
|
||||
{"2@", w_two_fetch, 0, 0},
|
||||
{"aligned", w_aligned, 0, 0},
|
||||
{"allot", w_allot, 0, 0},
|
||||
{"align", w_align, 0, 0},
|
||||
{",", w_comma, 0, 0},
|
||||
{"here", w_here, 0, 0},
|
||||
{"pad", w_pad, 0, 0},
|
||||
|
||||
{ /* end marker */ }
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "fh_stack.h"
|
||||
#include "fh_print.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)
|
||||
{
|
||||
@@ -179,6 +180,17 @@ static enum fh_error w_rightbracket(struct fh_thread_s *fh, const struct fh_word
|
||||
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)
|
||||
{
|
||||
(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;
|
||||
}
|
||||
|
||||
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[] = {
|
||||
{"depth", w_depth, 0, 0},
|
||||
{"unused", w_unused, 0, 0},
|
||||
{">in", w_to_in, 0, 0},
|
||||
{":", w_colon, 0, 0},
|
||||
{";", w_semicolon, 1, 0},
|
||||
{"forget", w_forget, 1, 0},
|
||||
@@ -261,6 +349,7 @@ const struct name_and_handler fh_builtins_meta[] = {
|
||||
{"postpone", w_postpone, 1, 0},
|
||||
{"[", w_leftbracket, 1, 0},
|
||||
{"]", w_rightbracket, 1, 0},
|
||||
{"source", w_source, 0, 0},
|
||||
{"literal", w_literal, 1, 0},
|
||||
{"char", w_char, 0, 0},
|
||||
{"[char]", w_char, 1, 0},
|
||||
@@ -268,6 +357,8 @@ const struct name_and_handler fh_builtins_meta[] = {
|
||||
{"variable", wp_variable, 1, 0},
|
||||
{"value", wp_variable, 1, 1},
|
||||
{"constant", wp_variable, 1, 2},
|
||||
{"word", w_word, 0, 0},
|
||||
{"count", w_count, 0, 0},
|
||||
|
||||
{ /* end marker */ }
|
||||
};
|
||||
|
||||
@@ -6,22 +6,6 @@
|
||||
#include "fh_print.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
|
||||
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[] = {
|
||||
{"depth", w_depth, 0, 0},
|
||||
{"unused", w_unused, 0, 0},
|
||||
{"reset", w_reset, 1, 0},
|
||||
{"bye", w_bye, 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_DIV_BY_ZERO] = "DIV_BY_ZERO",
|
||||
[FH_ERR_SYNTAX] = "SYNTAX_ERROR",
|
||||
[FH_ERR_NOT_APPLICABLE] = "NOT_APPLICABLE",
|
||||
};
|
||||
|
||||
/** 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;
|
||||
break;
|
||||
|
||||
case MAGICADDR_INPTR:
|
||||
*dst = fh->inputptr;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (addr & 3) {
|
||||
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!");
|
||||
return FH_ERR_ILLEGAL_STORE;
|
||||
|
||||
case MAGICADDR_INPTR:
|
||||
fh->inputptr = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (addr & 3) {
|
||||
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);
|
||||
}
|
||||
|
||||
/** 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) {
|
||||
if (addr >= HEAP_SIZE) {
|
||||
|
||||
+143
@@ -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;
|
||||
}
|
||||
+4
-120
@@ -28,122 +28,6 @@ static const char *substatenames[FH_SUBSTATE_MAX] = {
|
||||
[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. */
|
||||
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);
|
||||
LOG("Exec: early return");
|
||||
TRY(rs_pop(fh, &fh->execptr));
|
||||
if (fh->execptr == MAGICADDR_INTERACTIVE) {
|
||||
if (fh->execptr == MAGICADDR_EXEC_INTERACTIVE) {
|
||||
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:
|
||||
LOG("Exec: word-end (RETURN)");
|
||||
TRY(rs_pop(fh, &fh->execptr));
|
||||
if (fh->execptr == MAGICADDR_INTERACTIVE) {
|
||||
if (fh->execptr == MAGICADDR_EXEC_INTERACTIVE) {
|
||||
goto end;
|
||||
}
|
||||
goto instr;
|
||||
@@ -395,7 +279,7 @@ enum fh_error fh_init(struct fh_thread_s *fh)
|
||||
fh->dict_last = MAGICADDR_DICTFIRST;
|
||||
TRY(register_builtin_words(fh));
|
||||
|
||||
fh->execptr = MAGICADDR_INTERACTIVE;
|
||||
fh->execptr = MAGICADDR_EXEC_INTERACTIVE;
|
||||
fh->base = 10;
|
||||
return FH_OK;
|
||||
}
|
||||
@@ -545,7 +429,7 @@ enum fh_error fh_process_line(struct fh_thread_s *fh, const char *linebuf, size_
|
||||
|
||||
char c;
|
||||
|
||||
if (!fh_globals.interactive) {
|
||||
if (fh_globals.echo && !fh_globals.interactive) {
|
||||
LOGI("%s", linebuf);
|
||||
}
|
||||
|
||||
|
||||
+10
-2
@@ -12,6 +12,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
fh_globals.verbose = false;
|
||||
fh_globals.interactive = isatty(STDIN_FILENO);
|
||||
fh_globals.echo = 0;
|
||||
|
||||
FILE *infile = stdin;
|
||||
|
||||
@@ -26,6 +27,9 @@ int main(int argc, char *argv[])
|
||||
case 'v':
|
||||
fh_globals.verbose = 1;
|
||||
break;
|
||||
case 'e':
|
||||
fh_globals.echo = 1;
|
||||
break;
|
||||
default:
|
||||
LOGE("Unknown flag: %c", c);
|
||||
return 1;
|
||||
@@ -70,7 +74,9 @@ int main(int argc, char *argv[])
|
||||
|
||||
rv = fh_process_line(&fh, linebuf, strlen(linebuf));
|
||||
if (rv == FH_OK) {
|
||||
FHPRINT_SVC(" ok\n");
|
||||
if (fh_globals.interactive || fh_globals.echo) {
|
||||
FHPRINT_SVC(" ok\n");
|
||||
}
|
||||
} else {
|
||||
LOGE("ERROR %s on line %d", fherr_name(rv), linecnt);
|
||||
if (!fh_globals.interactive) {
|
||||
@@ -83,7 +89,9 @@ int main(int argc, char *argv[])
|
||||
fh.return_stack_top = 0;
|
||||
}
|
||||
|
||||
FHPRINT("%s", prompt);
|
||||
if (fh_globals.interactive) {
|
||||
FHPRINT("%s", prompt);
|
||||
}
|
||||
}
|
||||
|
||||
// Show resource usage
|
||||
|
||||
Reference in New Issue
Block a user