parent
883cc7faf1
commit
5da44313c5
@ -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
|
@ -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; |
||||||
|
} |
Loading…
Reference in new issue