Trying to build a forth runtime in C
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
forth/src/fh_parse.c

143 lines
3.3 KiB

#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;
}