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