This seems awkward but works. Maybe there's a better way. lemon
documentation is silent about handling this kind of errors, and
the results found when googing for lemon and YYABORT aren't
encouraging.
---
src/compiler/parser.y | 28 +++++++++++++++++++++-------
src/compiler/parser_helper.c | 10 +++++++---
src/compiler/parser_itf.h | 5 +++--
src/compiler/ptest/ptest.c | 22 +++++++++++++++++++---
src/compiler/test/error | 9 +++++++++
5 files changed, 59 insertions(+), 15 deletions(-)
diff --git a/src/compiler/parser.y b/src/compiler/parser.y
index 9ba3d89..2875fd5 100644
--- a/src/compiler/parser.y
+++ b/src/compiler/parser.y
@@ -28,6 +28,9 @@
#include "parser.h"
+ struct yyParser;
+ static void yy_parse_failed(struct yyParser *yypParser);
+
const enum ast_op tok2op[] = {
[TOK_IDENT] = op_ident,
[TOK_CONSTANT] = op_constant,
@@ -58,8 +61,8 @@
[TOK_INT] = op_int,
};
- struct ast_node *node(int token, const char *id, struct ast_node *a,
- struct ast_node *b, struct ast_node *c)
+ static struct ast_node *node(int token, const char *id,
+ struct ast_node *a, struct ast_node *b, struct ast_node *c)
{
struct ast_node *n;
@@ -71,6 +74,14 @@
n->contents.branches.c = c;
return n;
}
+
+ static void syntax_error(struct parser_state *state)
+ {
+ if(!state->error_label) {
+ state->error_label = state->id->label;
+ state->error_lineno = state->id->lineno;
+ }
+ }
}
%start_symbol start
@@ -85,10 +96,7 @@
%type node {struct ast_node *}
%destructor node { free($$); }
%syntax_error {
- if(!state->error_label) {
- state->error_label = state->id->label;
- state->error_lineno = state->id->lineno;
- }
+ syntax_error(state);
yy_parse_failed(yypParser);
}
@@ -106,7 +114,13 @@ assignments ::= assignments assignment.
assignments ::= .
assignment ::= ident(I) TOK_ASSIGN node(N) opt_semi. {
- fpvm_do_assign(state->comm->fragment, I->label, N);
+ if(!fpvm_do_assign(state->comm->fragment, I->label, N)) {
+ state->error =
+ strdup(fpvm_get_last_error(state->comm->fragment));
+ syntax_error(state);
+ yy_parse_failed(yypParser);
+ return;
+ }
fpvm_parse_free(N);
}
diff --git a/src/compiler/parser_helper.c b/src/compiler/parser_helper.c
index 4758d9f..4976e85 100644
--- a/src/compiler/parser_helper.c
+++ b/src/compiler/parser_helper.c
@@ -70,6 +70,7 @@ const char *fpvm_parse(const char *expr, int start_token,
struct parser_state state = {
.comm = comm,
.success = 0,
+ .error = NULL,
.error_label = NULL,
.id = NULL,
};
@@ -108,11 +109,14 @@ const char *fpvm_parse(const char *expr, int start_token,
ParseFree(p, free);
delete_scanner(s);
- if(!state.success)
+ if(!state.success) {
error = alloc_printf(
- "FPVM, line %d, near \"%.*s\": parse error",
+ "FPVM, line %d, near \"%.*s\": %s",
state.error_lineno, printable_label(state.error_label),
- state.error_label);
+ state.error_label,
+ state.error ? state.error : "parse error");
+ free((void *) state.error);
+ }
return error;
}
diff --git a/src/compiler/parser_itf.h b/src/compiler/parser_itf.h
index 2de69ee..57c84c1 100644
--- a/src/compiler/parser_itf.h
+++ b/src/compiler/parser_itf.h
@@ -35,9 +35,10 @@ struct id {
struct parser_state {
int success;
union parser_comm *comm;
- const char *error_label;
+ const char *error; /* malloc'ed error message or NULL */
+ const char *error_label;/* details about the failing token */
int error_lineno;
- const struct id *id; /* for error handling */
+ const struct id *id; /* input, for error handling */
};
void *ParseAlloc(void *(*mallocProc)(size_t));
diff --git a/src/compiler/ptest/ptest.c b/src/compiler/ptest/ptest.c
index 7db901b..c89fc68 100644
--- a/src/compiler/ptest/ptest.c
+++ b/src/compiler/ptest/ptest.c
@@ -12,6 +12,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
+#include <string.h>
#include "../fpvm.h"
#include "../parser_helper.h"
@@ -19,6 +20,7 @@
static int quiet = 0;
+static const char *fail = NULL;
static void dump_ast(const struct ast_node *ast);
@@ -133,9 +135,19 @@ static void dump_ast(const struct ast_node *ast)
}
+const char *fpvm_get_last_error(struct fpvm_fragment *fragment)
+{
+ return fragment->last_error;
+}
+
+
int fpvm_do_assign(struct fpvm_fragment *fragment, const char *dest,
struct ast_node *ast)
{
+ if (fail) {
+ snprintf(fragment->last_error, FPVM_MAXERRLEN, "%s", fail);
+ return 0;
+ }
if (!quiet) {
printf("%s = ", dest);
dump_ast(ast);
@@ -177,7 +189,7 @@ static const char *read_stdin(void)
static void usage(const char *name)
{
- fprintf(stderr, "usage: %s [-q] [expr]\n", name);
+ fprintf(stderr, "usage: %s [-f error] [-q] [expr]\n", name);
exit(1);
}
@@ -186,11 +198,15 @@ int main(int argc, char **argv)
{
int c;
const char *buf;
- union parser_comm comm;
+ struct fpvm_fragment fragment;
+ union parser_comm comm = { .fragment = &fragment };
const char *error;
- while ((c = getopt(argc, argv, "q")) != EOF)
+ while ((c = getopt(argc, argv, "f:q")) != EOF)
switch (c) {
+ case 'f':
+ fail = optarg;
+ break;
case 'q':
quiet = 1;
break;
diff --git a/src/compiler/test/error b/src/compiler/test/error
index e44af1d..1beadc4 100755
--- a/src/compiler/test/error
+++ b/src/compiler/test/error
@@ -29,4 +29,13 @@ expect <<EOF
FPVM, line 1, near "+": parse error
EOF
+#------------------------------------------------------------------------------
+
+ptest_fail "code generation error" -f "codegen" <<EOF
+x = a + b
+EOF
+expect <<EOF
+FPVM, line 1, near "b": codegen
+EOF
+
###############################################################################
--
1.7.1
_______________________________________________
http://lists.milkymist.org/listinfo.cgi/devel-milkymist.org
IRC: #milkymist@Freenode