We'll need this when the compiler parses the entire patch, not just
an expression.
---
 src/compiler/parser.y        |    8 ++-
 src/compiler/parser_helper.c |   34 ++++++++--
 src/compiler/parser_itf.h    |    4 +
 src/compiler/scanner.h       |    1 +
 src/compiler/scanner.re      |   21 +++++-
 src/compiler/test/comment    |    6 +-
 src/compiler/test/error      |    6 +-
 src/compiler/test/location   |  158 ++++++++++++++++++++++++++++++++++++++++++
 src/compiler/test/number     |    3 +-
 src/compiler/test/wrap       |    4 +-
 10 files changed, 226 insertions(+), 19 deletions(-)
 create mode 100755 src/compiler/test/location

diff --git a/src/compiler/parser.y b/src/compiler/parser.y
index 53695ed..acc6af7 100644
--- a/src/compiler/parser.y
+++ b/src/compiler/parser.y
@@ -85,7 +85,13 @@
 
 %type node {struct ast_node *}
 %destructor node { free($$); }
-%syntax_error { yy_parse_failed(yypParser); }
+%syntax_error {
+       if(!state->error_label) {
+               state->error_label = state->id->label;
+               state->error_lineno = state->id->lineno; 
+       }
+       yy_parse_failed(yypParser);
+}
 
 start ::= TOK_START_EXPR node(N). {
        state->comm->parseout = N;
diff --git a/src/compiler/parser_helper.c b/src/compiler/parser_helper.c
index c959282..f75a1ec 100644
--- a/src/compiler/parser_helper.c
+++ b/src/compiler/parser_helper.c
@@ -24,12 +24,33 @@
 #include "parser_itf.h"
 #include "parser_helper.h"
 
+static char printable_char(unsigned char c)
+{
+       return c < ' ' || c > '~' ? '?' : c;
+}
+
+/*
+ * Since operators don't set "label" properly in unique(), we can't just print
+ * the whole string, but need to cut it at the first non-printable character.
+ */
+
+static int printable_label(const char *s)
+{
+       const char *p;
+
+       for(p = s; *p > ' '; p++);
+       return p-s;
+}
+
+
 int fpvm_parse(const char *expr, int start_token, union parser_comm *comm)
 {
        struct scanner *s;
        struct parser_state state = {
                .comm = comm,
                .success = 0,
+               .error_label = NULL,
+               .id = NULL,
        };
        int tok;
        struct id *identifier;
@@ -42,14 +63,17 @@ int fpvm_parse(const char *expr, int start_token, union 
parser_comm *comm)
        while(tok != TOK_EOF) {
                identifier = malloc(sizeof(struct id));
                identifier->token = tok;
+               identifier->lineno = s->lineno;
                if(tok == TOK_CONSTANT) {
                        identifier->constant = get_constant(s);
                        identifier->label = "";
                } else {
                        identifier->label = get_token(s);
                }
+               state.id = identifier;
                if(tok == TOK_ERROR) {
-                       printf("FPVM: scan error\n");
+                       printf("FPVM, line %d, near \"%c\": scan error\n",
+                           s->lineno, printable_char(s->cursor[-1]));
                        ParseFree(p, free);
                        delete_scanner(s);
                        return 0;
@@ -61,10 +85,10 @@ int fpvm_parse(const char *expr, int start_token, union 
parser_comm *comm)
        ParseFree(p, free);
        delete_scanner(s);
 
-       if(!state.success) {
-               printf("FPVM: parse error\n");
-               return 0;
-       }
+       if(!state.success)
+               printf("FPVM, line %d, near \"%.*s\": parse error\n",
+                   state.error_lineno, printable_label(state.error_label),
+                   state.error_label);
 
        return state.success;
 }
diff --git a/src/compiler/parser_itf.h b/src/compiler/parser_itf.h
index f36aab8..2de69ee 100644
--- a/src/compiler/parser_itf.h
+++ b/src/compiler/parser_itf.h
@@ -29,11 +29,15 @@ struct id {
        int token;
        const char *label;
        float constant;
+       int lineno;
 };
 
 struct parser_state {
        int success;
        union parser_comm *comm;
+       const char *error_label;
+       int error_lineno;
+       const struct id *id; /* for error handling */
 };
 
 void *ParseAlloc(void *(*mallocProc)(size_t));
diff --git a/src/compiler/scanner.h b/src/compiler/scanner.h
index 627364a..d41b0c1 100644
--- a/src/compiler/scanner.h
+++ b/src/compiler/scanner.h
@@ -28,6 +28,7 @@ struct scanner {
        unsigned char *old_cursor;
        unsigned char *cursor;
        unsigned char *limit;
+       int lineno;
 };
 
 struct scanner *new_scanner(unsigned char *input);
diff --git a/src/compiler/scanner.re b/src/compiler/scanner.re
index df59d3f..5d06096 100644
--- a/src/compiler/scanner.re
+++ b/src/compiler/scanner.re
@@ -41,7 +41,8 @@ struct scanner *new_scanner(unsigned char *input)
        s->old_cursor = input;
        s->cursor = input;
        s->limit = input + strlen((char *)input);
-       
+       s->lineno = 1;
+
        return s;
 }
 
@@ -50,6 +51,16 @@ void delete_scanner(struct scanner *s)
        free(s);
 }
 
+static int nls(const unsigned char *s, const unsigned char *end)
+{
+       int n = 0;
+
+       while(s != end)
+               if(*s++ == '\n')
+                       n++;
+       return n;
+}
+
 int scan(struct scanner *s)
 {
        std:
@@ -57,11 +68,15 @@ int scan(struct scanner *s)
        s->old_cursor = s->cursor;
        
        /*!re2c
-               [\x20\n\r\t]            { goto std; }
+               [\x20\r\t]              { goto std; }
+               "\n"                    { s->lineno++;
+                                         goto std; }
 
                "//"[^\n\x00]*          { goto std; }
                "/*"("*"*[^/\x00]|[^*\x00])*"*"+"/"
-                                       { goto std; }
+                                       { s->lineno += nls(s->old_cursor,
+                                             s->cursor);
+                                         goto std; }
 
                [0-9]+                  { return TOK_CONSTANT; }
                [0-9]+ "." [0-9]*       { return TOK_CONSTANT; }
diff --git a/src/compiler/test/comment b/src/compiler/test/comment
index 1bec66c..3aeadc0 100755
--- a/src/compiler/test/comment
+++ b/src/compiler/test/comment
@@ -113,7 +113,7 @@ a = 9 /*/
 b = a
 EOF
 expect <<EOF
-FPVM: parse error
+FPVM, line 1, near "*/": parse error
 EOF
 
 #------------------------------------------------------------------------------
@@ -123,14 +123,14 @@ a = b + c /* comment
 d = e + f
 EOF
 expect <<EOF
-FPVM: parse error
+FPVM, line 1, near "*": parse error
 EOF
 
 #------------------------------------------------------------------------------
 
 ptest_fail "comment: unterminated /* ... without newline" "a = b+c /* comment"
 expect <<EOF
-FPVM: parse error
+FPVM, line 1, near "*": parse error
 EOF
 
 ###############################################################################
diff --git a/src/compiler/test/error b/src/compiler/test/error
index c8d8749..e44af1d 100755
--- a/src/compiler/test/error
+++ b/src/compiler/test/error
@@ -7,7 +7,7 @@ ptest_fail "syntax error: x = backtick" <<EOF
 x = \`
 EOF
 expect <<EOF
-FPVM: scan error
+FPVM, line 1, near "\`": scan error
 EOF
 
 #------------------------------------------------------------------------------
@@ -17,7 +17,7 @@ x = a b
 EOF
 expect <<EOF
 x = a
-FPVM: parse error
+FPVM, line 1, near "b": parse error
 EOF
 
 #------------------------------------------------------------------------------
@@ -26,7 +26,7 @@ ptest_fail "syntax error: x = a + + b" <<EOF
 x = a + + b
 EOF
 expect <<EOF
-FPVM: parse error
+FPVM, line 1, near "+": parse error
 EOF
 
 ###############################################################################
diff --git a/src/compiler/test/location b/src/compiler/test/location
new file mode 100755
index 0000000..aabee2d
--- /dev/null
+++ b/src/compiler/test/location
@@ -0,0 +1,158 @@
+#!/bin/sh
+. ./Common
+
+###############################################################################
+
+ptest_fail "location: scanner, inside line" <<EOF
+a = b
+x = \` y
+c = d
+EOF
+expect <<EOF
+a = b
+FPVM, line 2, near "\`": scan error
+EOF
+
+#------------------------------------------------------------------------------
+
+ptest_fail "location: scanner, beginning of line" <<EOF
+a = b
+\`x = y
+c = d
+EOF
+expect <<EOF
+FPVM, line 2, near "\`": scan error
+EOF
+
+#------------------------------------------------------------------------------
+
+ptest_fail "location: scanner, end of line" <<EOF
+a = b
+x = y\`
+c = d
+EOF
+expect <<EOF
+a = b
+FPVM, line 2, near "\`": scan error
+EOF
+
+#------------------------------------------------------------------------------
+
+ptest_fail "location: parser, inside line" <<EOF
+a = b
+x = * y
+c = d
+EOF
+expect <<EOF
+a = b
+FPVM, line 2, near "*": parse error
+EOF
+
+#------------------------------------------------------------------------------
+
+ptest_fail "location: parser, beginning of line" <<EOF
+a = b
+)x = y
+c = d
+EOF
+expect <<EOF
+a = b
+FPVM, line 2, near ")x": parse error
+EOF
+
+#------------------------------------------------------------------------------
+
+ptest_fail "location: parser, end of line (1)" <<EOF
+a = b
+x = y(
+c = d
+EOF
+expect <<EOF
+a = b
+x = y
+FPVM, line 2, near "(": parse error
+EOF
+
+#------------------------------------------------------------------------------
+
+ptest_fail "location: parser, end of line (2)" <<EOF
+a = b
+x = )
+c = d
+EOF
+expect <<EOF
+a = b
+FPVM, line 2, near ")": parse error
+EOF
+
+#------------------------------------------------------------------------------
+
+ptest_fail "location: error is end of line" <<EOF
+a = b
+x =
+EOF
+expect <<EOF
+a = b
+FPVM, line 2, near "=": parse error
+EOF
+
+#------------------------------------------------------------------------------
+
+ptest_fail "location: error is EOF" "x="
+expect <<EOF
+FPVM, line 1, near "=": parse error
+EOF
+
+#------------------------------------------------------------------------------
+
+ptest_fail "location: error is identifier" <<EOF
+foo = this is an error
+EOF
+expect <<EOF
+foo = this
+FPVM, line 1, near "an": parse error
+EOF
+
+#------------------------------------------------------------------------------
+
+ptest_fail "location: 3rd line" <<EOF
+a = b
+c = d
+)
+EOF
+expect <<EOF
+a = b
+c = d
+FPVM, line 3, near ")": parse error
+EOF
+
+#------------------------------------------------------------------------------
+
+ptest_fail "location: 5th line, with // comments" <<EOF
+// assign a
+a = b
+// assign c
+c = d
+)
+EOF
+expect <<EOF
+a = b
+c = d
+FPVM, line 5, near ")": parse error
+EOF
+
+#------------------------------------------------------------------------------
+
+ptest_fail "location: 4th line, with /*...*/ comments" <<EOF
+a = b /* some
+comment */
+c = d
+)
+EOF
+expect <<EOF
+a = b
+c = d
+FPVM, line 4, near ")": parse error
+EOF
+
+###############################################################################
diff --git a/src/compiler/test/number b/src/compiler/test/number
index db7fb10..2162eaf 100755
--- a/src/compiler/test/number
+++ b/src/compiler/test/number
@@ -20,7 +20,6 @@ b = 1.2
 EOF
 
 #------------------------------------------------------------------------------
-#------------------------------------------------------------------------------
 
 ptest "number: c = .3" <<EOF
 c = .3
@@ -53,7 +52,7 @@ ptest_fail "number: f = ." <<EOF
 f = .
 EOF
 expect <<EOF
-FPVM: scan error
+FPVM, line 1, near ".": scan error
 EOF
 
 ###############################################################################
diff --git a/src/compiler/test/wrap b/src/compiler/test/wrap
index 1e978ee..e3ed6c4 100755
--- a/src/compiler/test/wrap
+++ b/src/compiler/test/wrap
@@ -75,7 +75,7 @@ ptest_fail "wrap: one assignment containing semicolon (1)" 
<<EOF
 a = b +; c
 EOF
 expect <<EOF
-FPVM: parse error
+FPVM, line 1, near ";": parse error
 EOF
 
 #------------------------------------------------------------------------------
@@ -85,7 +85,7 @@ a = b; + c
 EOF
 expect <<EOF
 a = b
-FPVM: parse error
+FPVM, line 1, near "+": parse error
 EOF
 
 ###############################################################################
-- 
1.7.1

_______________________________________________
http://lists.milkymist.org/listinfo.cgi/devel-milkymist.org
IRC: #milkymist@Freenode

Reply via email to