diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c50092..31214a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/include/fh_config.h b/include/fh_config.h index 4c8bf3d..84458cb 100644 --- a/include/fh_config.h +++ b/include/fh_config.h @@ -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 diff --git a/include/fh_error.h b/include/fh_error.h index 0350295..e5436d6 100644 --- a/include/fh_error.h +++ b/include/fh_error.h @@ -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, }; diff --git a/include/fh_globals.h b/include/fh_globals.h index 8f21dfc..e14300f 100644 --- a/include/fh_globals.h +++ b/include/fh_globals.h @@ -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; diff --git a/include/fh_mem.h b/include/fh_mem.h index 1344bb9..22bbf1e 100644 --- a/include/fh_mem.h +++ b/include/fh_mem.h @@ -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); diff --git a/include/fh_parse.h b/include/fh_parse.h new file mode 100644 index 0000000..b9205f9 --- /dev/null +++ b/include/fh_parse.h @@ -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 diff --git a/include/fh_runtime.h b/include/fh_runtime.h index 18b4527..68c9f9e 100644 --- a/include/fh_runtime.h +++ b/include/fh_runtime.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 */ diff --git a/src/fh_builtins_arith.c b/src/fh_builtins_arith.c index 4391b90..02add6e 100644 --- a/src/fh_builtins_arith.c +++ b/src/fh_builtins_arith.c @@ -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; } diff --git a/src/fh_builtins_mem.c b/src/fh_builtins_mem.c index 5efda50..b4d24a1 100644 --- a/src/fh_builtins_mem.c +++ b/src/fh_builtins_mem.c @@ -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 */ } }; diff --git a/src/fh_builtins_meta.c b/src/fh_builtins_meta.c index d04c05e..0d5d77c 100644 --- a/src/fh_builtins_meta.c +++ b/src/fh_builtins_meta.c @@ -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 */ } }; diff --git a/src/fh_builtins_system.c b/src/fh_builtins_system.c index c11ae0c..00cb5c3 100644 --- a/src/fh_builtins_system.c +++ b/src/fh_builtins_system.c @@ -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}, diff --git a/src/fh_error.c b/src/fh_error.c index d501a31..7cbd3b2 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_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 */ diff --git a/src/fh_mem.c b/src/fh_mem.c index 0fab924..b9a198f 100644 --- a/src/fh_mem.c +++ b/src/fh_mem.c @@ -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) { diff --git a/src/fh_parse.c b/src/fh_parse.c new file mode 100644 index 0000000..fb59b3d --- /dev/null +++ b/src/fh_parse.c @@ -0,0 +1,143 @@ +#include +#include +#include +#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; +} diff --git a/src/fh_runtime.c b/src/fh_runtime.c index 4248abf..4c7bf4b 100644 --- a/src/fh_runtime.c +++ b/src/fh_runtime.c @@ -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); } diff --git a/src/main.c b/src/main.c index 8bf2d23..4526530 100644 --- a/src/main.c +++ b/src/main.c @@ -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