From e290683f0c88d88b90aab587bee87d548fdb594f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C5=99emysl=20Janouch?=
Date: Wed, 17 May 2017 21:29:07 +0200
Subject: [PATCH] Get rid of the "script" parser
Since it is largely incompatible with what we're doing.
---
ell.c | 297 ++++++++--------------------------------------------------
1 file changed, 38 insertions(+), 259 deletions(-)
diff --git a/ell.c b/ell.c
index 9d786e4..f26a2aa 100755
--- a/ell.c
+++ b/ell.c
@@ -44,7 +44,7 @@
static char *format (const char *format, ...) ATTRIBUTE_PRINTF (1, 2);
static char *
-strdup_vprintf (const char *format, va_list ap) {
+vformat (const char *format, va_list ap) {
va_list aq;
va_copy (aq, ap);
int size = vsnprintf (NULL, 0, format, aq);
@@ -64,7 +64,7 @@ static char *
format (const char *format, ...) {
va_list ap;
va_start (ap, format);
- char *result = strdup_vprintf (format, ap);
+ char *result = vformat (format, ap);
va_end (ap);
return result;
}
@@ -135,7 +135,7 @@ static struct item *new_clone_list (const struct item *);
static void
item_free (struct item *item) {
if (item->type == ITEM_LIST)
- item_free_list (get_list (item));
+ item_free_list (item->head);
free (item);
}
@@ -257,7 +257,7 @@ struct lexer {
unsigned column; ///< Current column
int64_t integer; ///< Parsed boolean or integer value
- struct str string; ///< Parsed string value
+ struct buffer string; ///< Parsed string value
};
/// Input has to be null-terminated anyway
@@ -266,12 +266,11 @@ lexer_init (struct lexer *self, const char *p, size_t len) {
memset (self, 0, sizeof *self);
self->p = p;
self->len = len;
- str_init (&self->string);
}
static void
lexer_free (struct lexer *self) {
- str_free (&self->string);
+ free (self->string.s);
}
static bool lexer_is_word_char (int c) { return !strchr ("()[]{}\n@#'", c); }
@@ -289,33 +288,25 @@ lexer_advance (struct lexer *self) {
return c;
}
-static void lexer_error (struct lexer *self,
- struct error **e, const char *format, ...) ATTRIBUTE_PRINTF (3, 4);
+static void lexer_error (struct lexer *self, char **e, const char *fmt, ...)
+ ATTRIBUTE_PRINTF (3, 4);
+// TODO: see "script", we can just use error constants to avoid allocation
static void
-lexer_error (struct lexer *self, struct error **e, const char *format, ...) {
- struct str description;
- str_init (&description);
-
+lexer_error (struct lexer *self, char **e, const char *fmt, ...) {
va_list ap;
- va_start (ap, format);
- str_append_vprintf (&description, format, ap);
+ va_start (ap, fmt);
+ char *description = vformat (fmt, ap);
va_end (ap);
- if (self->report_line)
- error_set (e, "near line %u, column %u: %s",
- self->line + 1, self->column + 1, description.str);
- else if (self->len)
- error_set (e, "near character %u: %s",
- self->column + 1, description.str);
- else
- error_set (e, "near end: %s", description.str);
+ *e = format ("near line %u, column %u: %s",
+ self->line + 1, self->column + 1, description);
- str_free (&description);
+ free (description);
}
static bool
-lexer_hexa_escape (struct lexer *self, struct str *output) {
+lexer_hexa_escape (struct lexer *self, struct buffer *output) {
int i;
unsigned char code = 0;
@@ -334,20 +325,19 @@ lexer_hexa_escape (struct lexer *self, struct str *output) {
if (!i)
return false;
- str_append_c (output, code);
+ buffer_append_c (output, code);
return true;
}
static bool
-lexer_escape_sequence
- (struct lexer *self, struct str *output, struct error **e) {
+lexer_escape_sequence (struct lexer *self, struct buffer *output, char **e) {
if (!self->len) {
lexer_error (self, e, "premature end of escape sequence");
return false;
}
- unsigned char c;
- switch ((c = *self->p)) {
+ unsigned char c = *self->p;
+ switch (c) {
case '"': break;
case '\\': break;
case 'a': c = '\a'; break;
@@ -372,19 +362,19 @@ lexer_escape_sequence
return false;
}
- str_append_c (output, c);
+ buffer_append_c (output, c);
lexer_advance (self);
return true;
}
static bool
-lexer_string (struct lexer *self, struct str *output, struct error **e) {
+lexer_string (struct lexer *self, struct buffer *output, char **e) {
unsigned char c;
while (self->len) {
if ((c = lexer_advance (self)) == '\'')
return true;
if (c != '\\')
- str_append_c (output, c);
+ buffer_append_c (output, c);
else if (!lexer_escape_sequence (self, output, e))
return false;
}
@@ -393,13 +383,16 @@ lexer_string (struct lexer *self, struct str *output, struct error **e) {
}
static enum token
-lexer_next (struct lexer *self, struct error **e) {
+lexer_next (struct lexer *self, char **e) {
// Skip over any whitespace between tokens
- while (self->len && isspace_ascii (*self->p) && *self->p != '\n')
+ while (self->len && isspace (*self->p) && *self->p != '\n')
lexer_advance (self);
if (!self->len)
return T_ABORT;
+ free (self->string.s);
+ self->string = (struct buffer) BUFFER_INITIALIZER;
+
switch (*self->p) {
case '(': lexer_advance (self); return T_LPAREN;
case ')': lexer_advance (self); return T_RPAREN;
@@ -419,232 +412,24 @@ lexer_next (struct lexer *self, struct error **e) {
case '\'':
lexer_advance (self);
- str_reset (&self->string);
if (!lexer_string (self, &self->string, e))
return T_ABORT;
return T_STRING;
}
assert (lexer_is_word_char (*self->p));
- str_reset (&self->string);
do
- str_append_c (&self->string, lexer_advance (self));
+ buffer_append_c (&self->string, lexer_advance (self));
while (lexer_is_word_char (*self->p));
return T_STRING;
}
// --- Parsing -----------------------------------------------------------------
-#define PARSE_ERROR_TABLE(XX) \
- XX( OK, NULL ) \
- XX( EOF, "unexpected end of input" ) \
- XX( INVALID_HEXA_ESCAPE, "invalid hexadecimal escape sequence" ) \
- XX( INVALID_ESCAPE, "unrecognized escape sequence" ) \
- XX( MEMORY, "memory allocation failure" ) \
- XX( FLOAT_RANGE, "floating point value out of range" ) \
- XX( INTEGER_RANGE, "integer out of range" ) \
- XX( INVALID_INPUT, "invalid input" ) \
- XX( UNEXPECTED_INPUT, "unexpected input" )
-
-enum tokenizer_error {
-#define XX(x, y) PARSE_ERROR_ ## x,
- PARSE_ERROR_TABLE (XX)
-#undef XX
- PARSE_ERROR_COUNT
-};
-
-struct tokenizer {
- const char *cursor;
- enum tokenizer_error error;
-};
-
-static bool
-decode_hexa_escape (struct tokenizer *self, struct buffer *buf) {
- int i;
- char c, code = 0;
-
- for (i = 0; i < 2; i++) {
- c = tolower (*self->cursor);
- if (c >= '0' && c <= '9')
- code = (code << 4) | (c - '0');
- else if (c >= 'a' && c <= 'f')
- code = (code << 4) | (c - 'a' + 10);
- else
- break;
-
- self->cursor++;
- }
-
- if (!i)
- return false;
-
- buffer_append_c (buf, code);
- return true;
-}
-
-static bool
-decode_escape_sequence (struct tokenizer *self, struct buffer *buf) {
- // Support some basic escape sequences from the C language
- char c;
- switch ((c = *self->cursor)) {
- case '\0':
- self->error = PARSE_ERROR_EOF;
- return false;
- case 'x':
- case 'X':
- self->cursor++;
- if (decode_hexa_escape (self, buf))
- return true;
-
- self->error = PARSE_ERROR_INVALID_HEXA_ESCAPE;
- return false;
- default:
- self->cursor++;
- const char *from = "abfnrtv\"\\", *to = "\a\b\f\n\r\t\v\"\\", *x;
- if ((x = strchr (from, c))) {
- buffer_append_c (buf, to[x - from]);
- return true;
- }
- self->error = PARSE_ERROR_INVALID_ESCAPE;
- return false;
- }
-}
-
-static struct item *
-parse_string (struct tokenizer *self) {
- struct buffer buf = BUFFER_INITIALIZER;
- struct item *item = NULL;
- char c;
-
- while (true)
- switch ((c = *self->cursor++)) {
- case '\0':
- self->cursor--;
- self->error = PARSE_ERROR_EOF;
- goto end;
- case '"':
- if (buf.memory_failure
- || !(item = new_string (buf.s, buf.len)))
- self->error = PARSE_ERROR_MEMORY;
- goto end;
- case '\\':
- if (decode_escape_sequence (self, &buf))
- break;
- goto end;
- default:
- buffer_append_c (&buf, c);
- }
-
-end:
- free (buf.s);
- return item;
-}
-
-static struct item *
-parse_word (struct tokenizer *self) {
- struct buffer buf = BUFFER_INITIALIZER;
- struct item *item = NULL;
- char c;
-
- // Here we accept almost anything that doesn't break the grammar
- while (!strchr (" []\"", (c = *self->cursor++)) && (unsigned char) c > ' ')
- buffer_append_c (&buf, c);
- self->cursor--;
-
- if (buf.memory_failure)
- self->error = PARSE_ERROR_MEMORY;
- else if (!buf.len)
- self->error = PARSE_ERROR_INVALID_INPUT;
- else if (!(item = new_word (buf.s, buf.len)))
- self->error = PARSE_ERROR_MEMORY;
-
- free (buf.s);
- return item;
-}
-
-static struct item *parse_item_list (struct tokenizer *);
-
-static struct item *
-parse_list (struct tokenizer *self) {
- struct item *list = parse_item_list (self);
- if (self->error) {
- assert (list == NULL);
- return NULL;
- }
- if (!*self->cursor) {
- self->error = PARSE_ERROR_EOF;
- item_free_list (list);
- return NULL;
- }
- assert (*self->cursor == ']');
- self->cursor++;
- return new_list (list);
-}
-
-static struct item *
-parse_item (struct tokenizer *self) {
- char c;
- switch ((c = *self->cursor++)) {
- case '[': return parse_list (self);
- case '"': return parse_string (self);
- default:;
- }
-
- self->cursor--;
- return parse_word (self);
-}
-
-static struct item *
-parse_item_list (struct tokenizer *self) {
- struct item *head = NULL;
- struct item **tail = &head;
-
- char c;
- bool expected = true;
- while ((c = *self->cursor) && c != ']') {
- if (isspace (c)) {
- self->cursor++;
- expected = true;
- continue;
- } else if (!expected) {
- self->error = PARSE_ERROR_UNEXPECTED_INPUT;
- goto fail;
- }
-
- if (!(*tail = parse_item (self)))
- goto fail;
- tail = &(*tail)->next;
- expected = false;
- }
- return head;
-
-fail:
- item_free_list (head);
- return NULL;
-}
-
static struct item *
parse (const char *s, const char **error) {
- struct tokenizer self = { .cursor = s, .error = PARSE_ERROR_OK };
- struct item *list = parse_item_list (&self);
- if (!self.error && *self.cursor != '\0') {
- self.error = PARSE_ERROR_UNEXPECTED_INPUT;
- item_free_list (list);
- list = NULL;
- }
-
-#define XX(x, y) y,
- static const char *strings[PARSE_ERROR_COUNT] =
- { PARSE_ERROR_TABLE (XX) };
-#undef XX
-
- static char error_buf[128];
- if (self.error && error) {
- snprintf (error_buf, sizeof error_buf, "at character %d: %s",
- (int) (self.cursor - s) + 1, strings[self.error]);
- *error = error_buf;
- }
- return list;
+ // TODO
+ return NULL;
}
// --- Runtime -----------------------------------------------------------------
@@ -700,7 +485,7 @@ set_error (struct context *ctx, const char *format, ...) {
va_list ap;
va_start (ap, format);
- ctx->error = strdup_vprintf (format, ap);
+ ctx->error = vformat (format, ap);
va_end (ap);
if (!ctx->error)
@@ -807,7 +592,7 @@ execute (struct context *ctx, struct item *script) {
if (!push (ctx, new_clone (script)))
return false;
}
- else if (!call_function (ctx, get_word (script)))
+ else if (!call_function (ctx, script->value))
return false;
}
return true;
@@ -827,7 +612,7 @@ init_runtime_library_scripts (void) {
const char *name; ///< Name of the function
const char *definition; ///< The defining script
} scripts[] = {
- { "greet", "print (.. 'hello ' (.. @1))" },
+ { "greet", "arg _name \n print (.. 'hello ' (.. @_name))" },
};
for (size_t i = 0; i < N_ELEMENTS (scripts); i++) {
@@ -870,8 +655,8 @@ defn (fn_concatenate) {
static bool
init_runtime_library (void)
{
- return register_handler ("..", fn_concatenate);
- && register_handler ("print", fn_print);
+ return register_handler ("..", fn_concatenate)
+ && register_handler ("print", fn_print)
&& init_runtime_library_scripts ();
}
@@ -893,12 +678,12 @@ process_message (const char *msg) {
struct item *script = parse (msg, &error);
if (error) {
printf ("%s: %s\r\n", "parse error", error);
- goto end;
+ return;
}
struct context ctx;
context_init (&ctx);
- ctx.user_data = &info;
+ ctx.user_data = NULL;
execute (&ctx, script);
item_free_list (script);
@@ -910,17 +695,11 @@ process_message (const char *msg) {
if (failure)
printf ("%s: %s\r\n", "runtime error", failure);
context_free (&ctx);
-end:
- free (msg_ctx_quote);
}
int
main (int argc, char *argv[]) {
- freopen (NULL, "rb", stdin); setvbuf (stdin, NULL, _IOLBF, BUFSIZ);
- freopen (NULL, "wb", stdout); setvbuf (stdout, NULL, _IOLBF, BUFSIZ);
-
- if (!init_runtime_library ()
- || !register_handler (".", fn_dot))
+ if (!init_runtime_library ())
printf ("%s\n", "runtime library initialization failed");
// TODO: load the entirety of stdin and execute it