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

Reply via email to