diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2011-06-26 15:18:29 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2011-06-26 21:23:42 +0300 |
commit | 440771ca0056eb20396e24f03d349a75ee1c9d22 (patch) | |
tree | 3ec58a85e96d21a855ad3dcefaa8adc51039fc38 | |
parent | 4c1959a4848c30206de3be4b16bdf04b650daae8 (diff) | |
download | grecs-440771ca0056eb20396e24f03d349a75ee1c9d22.tar.gz grecs-440771ca0056eb20396e24f03d349a75ee1c9d22.tar.bz2 |
Keep track of columns in the node and value locations. Improve error diagnostics.
* src/grecs.h (grecs_locus_point): New struct.
(grecs_locus_point_advance_line): New macro.
(grecs_locus_t): Redesign.
(grecs_value) <locus>: New member.
(grecs_node) <idloc>: New member.
(grecs_print_diag_fun): Change signature.
(grecs_warning,grecs_error): Change signature.
(grecs_parse_line_directive)
(grecs_parse_line_directive_cpp)
(grecs_string_convert): Change signature.
(grecs_current_locus): Remove.
(grecs_current_locus_point): New extern.
* src/grecs-locus.h: New file.
* src/Make.am (noinst_HEADERS): Add grecs-locus.h.
* src/join.c (reset_locus): Rewrite.
* src/lookup.c: Initialize new members of grecs_value and grecs_node.
(split_cfg_path): Return wrdse error code.
(grecs_node_from_path_locus): Take two grecs_locus_t arguments.
Make sure all created nodes have their locus members
properly initialized.
* src/parser.c (grecs_parse): Initialize grecs_current_locus_point.
* src/tree.c (grecs_node_create_points): New function.
(string_to_bool,string_to_host,string_to_sockaddr)
(grecs_string_convert): Change signatures. Be more precise in
what locus to report.
* src/diag.c (default_print_diag): Use YY_LOCATION_PRINT to
output locus.
(grecs_print_diag_fun): Change signature.
(grecs_warning,grecs_error): Change signature.
* src/format.c (grecs_format_locus): Rewrite.
(grecs_format_node): Be more precise in what locus is being
output.
* src/bind-gram.y: Keep track of locations. Turn on error-verbose mode.
* src/grecs-gram.y: Likewise.
* src/meta1-gram.y: Likewise.
* src/bind-lex.l: Keep track of locations.
* src/git-parser.c: Likewise.
* src/grecs-lex.l: Likewise.
* src/meta1-lex.l: Likewise.
* src/path-parser.c: Likewise.
* src/preproc.c: Likewise.
* tests/gcf1.conf: Untabify.
* tests/format01.at: Reflect changes in the output.
* tests/join.at: Likewise.
* tests/set.at: Likewise.
* tests/locus-bind.at: New testcase.
* tests/locus-git.at: New testcase.
* tests/locus-meta1.at: New testcase.
* tests/locus00.at: New testcase.
* tests/locus01.at: New testcase.
* tests/locus02.at: New testcase.
* tests/path-locus.at: New testcase.
-rw-r--r-- | src/Make.am | 2 | ||||
-rw-r--r-- | src/bind-gram.y | 68 | ||||
-rw-r--r-- | src/bind-lex.l | 58 | ||||
-rw-r--r-- | src/diag.c | 18 | ||||
-rw-r--r-- | src/format.c | 59 | ||||
-rw-r--r-- | src/git-parser.c | 93 | ||||
-rw-r--r-- | src/grecs-gram.y | 43 | ||||
-rw-r--r-- | src/grecs-lex.l | 102 | ||||
-rw-r--r-- | src/grecs-locus.h | 56 | ||||
-rw-r--r-- | src/grecs.h | 45 | ||||
-rw-r--r-- | src/join.c | 27 | ||||
-rw-r--r-- | src/lookup.c | 54 | ||||
-rw-r--r-- | src/meta1-gram.y | 37 | ||||
-rw-r--r-- | src/meta1-lex.l | 27 | ||||
-rw-r--r-- | src/parser.c | 5 | ||||
-rw-r--r-- | src/path-parser.c | 172 | ||||
-rw-r--r-- | src/preproc.c | 22 | ||||
-rw-r--r-- | src/tree.c | 45 | ||||
-rw-r--r-- | tests/Makefile.am | 9 | ||||
-rw-r--r-- | tests/format01.at | 28 | ||||
-rw-r--r-- | tests/gcf1.conf | 12 | ||||
-rw-r--r-- | tests/gcffmt.c | 14 | ||||
-rw-r--r-- | tests/gcfpeek.c | 20 | ||||
-rw-r--r-- | tests/join.at | 16 | ||||
-rw-r--r-- | tests/locus-bind.at | 40 | ||||
-rw-r--r-- | tests/locus-git.at | 61 | ||||
-rw-r--r-- | tests/locus-meta1.at | 37 | ||||
-rw-r--r-- | tests/locus00.at | 30 | ||||
-rw-r--r-- | tests/locus01.at | 34 | ||||
-rw-r--r-- | tests/locus02.at | 32 | ||||
-rw-r--r-- | tests/path-locus.at | 92 | ||||
-rw-r--r-- | tests/set.at | 2 | ||||
-rw-r--r-- | tests/testsuite.at | 22 |
33 files changed, 1034 insertions, 348 deletions
diff --git a/src/Make.am b/src/Make.am index bc70edc..286bf4c 100644 --- a/src/Make.am +++ b/src/Make.am @@ -56,13 +56,13 @@ GRECS_SRC = \ version.c\ wordsplit.c\ $(GRECS_PARSER_BIND)\ $(GRECS_PARSER_GIT)\ $(GRECS_PARSER_META1) -noinst_HEADERS = +noinst_HEADERS = grecs-locus.h EXTRA_DIST=\ grecs-gram.h\ $(GRECS_EXTRA_BIND)\ $(GRECS_EXTRA_META1)\ $(PP_SETUP_FILE)\ diff --git a/src/bind-gram.y b/src/bind-gram.y index c751ae1..e353a54 100644 --- a/src/bind-gram.y +++ b/src/bind-gram.y @@ -16,57 +16,55 @@ with Grecs. If not, see <http://www.gnu.org/licenses/>. */ #ifdef HAVE_CONFIG_H # include <config.h> #endif #include <grecs.h> -#include <grecs-gram.h> +#include <grecs-locus.h> +#include <bind-gram.h> #include <stdlib.h> #include <stdarg.h> #include <string.h> #include <errno.h> int yylex(void); int yyerror(char *s); static struct grecs_node *parse_tree; extern int yy_flex_debug; -extern int grecs_bind_new_source(const char *name); +extern int grecs_bind_new_source(const char *name, grecs_locus_t *loc); extern void grecs_bind_close_sources(void); static struct grecs_value *stmtlist_to_value(struct grecs_node *node); %} +%error-verbose +%locations + %union { - struct { - grecs_locus_t locus; - char *string; - } ident; char *string; grecs_value_t svalue, *pvalue; struct grecs_list *list; struct grecs_node *node; grecs_locus_t locus; struct { struct grecs_node *head, *tail; } node_list; } -%token <ident> BIND_IDENT BIND_CONTROLS -%token <string> BIND_STRING +%token <string> BIND_STRING BIND_IDENT BIND_CONTROLS %type <string> string %type <svalue> value ctlsub %type <pvalue> vallist tag %type <list> vlist ctllist %type <node> stmt simple block maybe_stmtlist %type <node_list> stmtlist %% input : maybe_stmtlist { - parse_tree = grecs_node_create(grecs_node_root, - &grecs_current_locus); + parse_tree = grecs_node_create(grecs_node_root, &@1); parse_tree->v.texttab = grecs_text_table(); grecs_node_bind(parse_tree, $1, 1); } ; maybe_stmtlist: @@ -99,44 +97,50 @@ stmtlist: stmt stmt : simple | block ; simple : BIND_IDENT vallist ';' { - if (strcmp($1.string, "include") == 0 && + if (strcmp($1, "include") == 0 && $2->type == GRECS_TYPE_STRING) { - grecs_bind_new_source($2->v.string); + grecs_bind_new_source($2->v.string, &@1); $$ = NULL; } else { - $$ = grecs_node_create(grecs_node_stmt, &$1.locus); - $$->ident = $1.string; + $$ = grecs_node_create_points(grecs_node_stmt, + @1.beg, @2.end); + $$->ident = $1; + $$->idloc = @1; $$->v.value = $2; } } | string ';' { - $$ = grecs_node_create(grecs_node_stmt, - &grecs_current_locus); + $$ = grecs_node_create(grecs_node_stmt, &@1); $$->ident = $1; + $$->idloc = @1; $$->v.value = NULL; } | '!' string ';' { - $$ = grecs_node_create(grecs_node_stmt, - &grecs_current_locus); - $$->ident = grecs_strdup("!"); - $$->v.value = grecs_malloc(sizeof($$->v.value[0])); - $$->v.value->type = GRECS_TYPE_STRING; - $$->v.value->v.string = $2; + $$ = grecs_node_create_points(grecs_node_stmt, + @1.beg, @2.end); + $$->ident = grecs_strdup("!"); + $$->idloc = @1; + $$->v.value = grecs_malloc(sizeof($$->v.value[0])); + $$->v.value->type = GRECS_TYPE_STRING; + $$->v.value->locus = @2; + $$->v.value->v.string = $2; } ; block : BIND_IDENT tag '{' maybe_stmtlist '}' ';' { - $$ = grecs_node_create(grecs_node_block, &$1.locus); - $$->ident = $1.string; + $$ = grecs_node_create_points(grecs_node_block, + @1.beg, @5.end); + $$->ident = $1; + $$->idloc = @1; $$->v.value = $2; grecs_node_bind($$, $4, 1); } | BIND_CONTROLS '{' ctlsub '}' ';' /* Special case: @@ -148,14 +152,16 @@ block : BIND_IDENT tag '{' maybe_stmtlist '}' ';' This produces: .controls: (inet, 127.0.0.1, port, 953, allow, \ (127.0.0.1, 127.0.0.2), keys, (rndc-key)) */ { - $$ = grecs_node_create(grecs_node_stmt, &$1.locus); - $$->ident = $1.string; + $$ = grecs_node_create_points(grecs_node_stmt, + @1.beg, @4.end); + $$->ident = $1; + $$->idloc = @1; $$->v.value = grecs_value_ptr_from_static(&$3); } ; tag : /* empty */ { @@ -173,12 +179,13 @@ vallist : vlist } else { size_t i; struct grecs_list_entry *ep; $$ = grecs_malloc(sizeof($$[0])); $$->type = GRECS_TYPE_ARRAY; + $$->locus = @1; $$->v.arg.c = n; $$->v.arg.v = grecs_calloc(n, sizeof($$->v.arg.v[0])); for (i = 0, ep = $1->head; ep; i++, ep = ep->next) $$->v.arg.v[i] = ep->data; } @@ -198,26 +205,25 @@ vlist : value } ; value : string { $$.type = GRECS_TYPE_STRING; + $$.locus = @1; $$.v.string = $1; } ; string : BIND_STRING | BIND_IDENT - { - $$ = $1.string; - } ; ctlsub : ctllist ';' { $$.type = GRECS_TYPE_LIST; + $$.locus = @1; $$.v.list = $1; } ; ctllist : value { @@ -237,22 +243,22 @@ ctllist : value %% int yyerror(char *s) { - grecs_error(&grecs_current_locus, 0, "%s", s); + grecs_error(&yylloc, 0, "%s", s); return 0; } struct grecs_node * grecs_bind_parser(const char *name, int traceflags) { int rc; - if (grecs_bind_new_source(name)) + if (grecs_bind_new_source(name, NULL)) return NULL; yy_flex_debug = traceflags & GRECS_TRACE_LEX; yydebug = traceflags & GRECS_TRACE_GRAM; parse_tree = NULL; grecs_line_acc_create(); rc = yyparse(); diff --git a/src/bind-lex.l b/src/bind-lex.l index 10df618..ef1598c 100644 --- a/src/bind-lex.l +++ b/src/bind-lex.l @@ -19,22 +19,31 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grecs. If not, see <http://www.gnu.org/licenses/>. */ #include <grecs.h> +#include <grecs-locus.h> #include <bind-gram.h> #include <unistd.h> #include <fcntl.h> #include <ctype.h> #include <stdlib.h> #include <errno.h> #include <sys/stat.h> #include <wordsplit.h> +#define YY_USER_ACTION do { \ + if (YYSTATE == 0) { \ + yylloc.beg = grecs_current_locus_point; \ + yylloc.beg.col++; \ + } \ + grecs_current_locus_point.col += yyleng; \ + yylloc.end = grecs_current_locus_point; \ + } while (0); %} %x COMMENT STR WS [ \t\f][ \t\f]* ID [a-zA-Z_][a-zA-Z_0-9-]* @@ -42,32 +51,33 @@ P [1-9][0-9]* %% /* C-style comments */ "/*" BEGIN(COMMENT); <COMMENT>[^*\n]* /* eat anything that's not a '*' */ <COMMENT>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */ -<COMMENT>\n ++grecs_current_locus.line; +<COMMENT>\n grecs_locus_point_advance_line(grecs_current_locus_point); <COMMENT>"*"+"/" BEGIN(INITIAL); /* Line directive */ ^[ \t]*#[ \t]*{P}[ \t]+\".*\".*\n { grecs_parse_line_directive_cpp(yytext, - &grecs_current_locus, + &yylloc, + &grecs_current_locus_point, NULL); } ^[ \t]*#[ \t]*line[ \t].*\n { grecs_parse_line_directive(yytext, - &grecs_current_locus, + &yylloc, + &grecs_current_locus_point, NULL); } /* End-of-line comments */ -#.*\n { grecs_current_locus.line++; } +#.*\n { grecs_locus_point_advance_line(grecs_current_locus_point); } #.* /* end-of-file comment */; -"//".*\n { grecs_current_locus.line++; } +"//".*\n { grecs_locus_point_advance_line(grecs_current_locus_point); } "//".* /* end-of-file comment */; /* Identifiers */ {ID} { grecs_line_begin(); grecs_line_add(yytext, yyleng); - yylval.ident.string = grecs_line_finish(); - yylval.ident.locus = grecs_current_locus; - return strcmp(yylval.ident.string, "controls") == 0 ? + yylval.string = grecs_line_finish(); + return strcmp(yylval.string, "controls") == 0 ? BIND_CONTROLS : BIND_IDENT; } /* Strings */ [a-zA-Z0-9_\.\*/:@-]([a-zA-Z0-9_\./:@-][a-zA-Z0-9_\.\*/:@-]*)? { grecs_line_begin(); grecs_line_add(yytext, yyleng); @@ -94,25 +104,26 @@ P [1-9][0-9]* if (yyleng > 1) grecs_line_add(yytext, yyleng - 1); yylval.string = grecs_line_finish(); return BIND_STRING; } {WS} ; /* Other tokens */ -\n { grecs_current_locus.line++; } +\n { grecs_locus_point_advance_line(grecs_current_locus_point); } [,;{}()!] return yytext[0]; . { if (isascii(yytext[0]) && isprint(yytext[0])) - grecs_error(&grecs_current_locus, 0, + grecs_error(&yylloc, 0, _("stray character %c"), yytext[0]); else - grecs_error(&grecs_current_locus, 0, _("stray character \\%03o"), - (unsigned char) yytext[0]); } + grecs_error(&yylloc, 0, _("stray character \\%03o"), + (unsigned char) yytext[0]); } %% struct bind_input_context { ino_t i_node; dev_t i_dev; + struct grecs_locus_point point; grecs_locus_t locus; /* Current input location */ YY_BUFFER_STATE state; FILE *input; }; static struct grecs_list *input_stack; @@ -132,36 +143,40 @@ cmp_context(const void *a, const void *b) struct bind_input_context const *bc = b; return !(ac->i_node == bc->i_node && ac->i_dev == bc->i_dev); } static int -_push_context(const char *name, ino_t i_node, dev_t i_dev) +_push_context(const char *name, ino_t i_node, dev_t i_dev, grecs_locus_t *loc) { struct bind_input_context ctx, *pctx; if (!input_stack) { input_stack = grecs_list_create(); input_stack->free_entry = free_context; input_stack->cmp = cmp_context; } else { ctx.i_dev = i_dev; ctx.i_node = i_node; pctx = grecs_list_locate(input_stack, &ctx); if (pctx) { - grecs_error(&grecs_current_locus, 0, + grecs_error(&yylloc, 0, _("%s has already been included"), name); grecs_error(&pctx->locus, 0, _("this is where the previous inclusion occurred")); return 1; } pctx = grecs_malloc(sizeof(*pctx)); pctx->i_node = i_node; pctx->i_dev = i_dev; - pctx->locus = grecs_current_locus; + if (loc) + pctx->locus = *loc; + else + memset(&pctx->locus, 0, sizeof(pctx->locus)); /* FIXME */ + pctx->point = grecs_current_locus_point; pctx->state = YY_CURRENT_BUFFER; pctx->input = yyin; grecs_list_push(input_stack, pctx); } return 0; } @@ -181,13 +196,13 @@ _pop_context() if (!pctx) { yyin = NULL; return 1; } i_node = pctx->i_node; i_dev = pctx->i_dev; - grecs_current_locus = pctx->locus; + grecs_current_locus_point = pctx->point; yyin = pctx->input; yy_delete_buffer(YY_CURRENT_BUFFER); yy_switch_to_buffer(pctx->state); grecs_free(pctx); return 0; } @@ -196,16 +211,14 @@ int yywrap() { return _pop_context(); } int -grecs_bind_new_source(const char *name) +grecs_bind_new_source(const char *name, grecs_locus_t *loc) { - grecs_locus_t *loc = grecs_current_locus.file ? - &grecs_current_locus : NULL; struct stat st; FILE *fp; if (access(name, F_OK)) { int ec = errno; char *tmp = grecs_find_include_file(name, 0); @@ -242,21 +255,22 @@ grecs_bind_new_source(const char *name) grecs_free(cmd); return 1; } grecs_free(cmd); } - if (_push_context(name, st.st_ino, st.st_dev)) { + if (_push_context(name, st.st_ino, st.st_dev, loc)) { return 1; } i_node = st.st_ino; i_dev = st.st_dev; yyin = fp; yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); - grecs_current_locus.file = grecs_install_text(name); - grecs_current_locus.line = 1; + grecs_current_locus_point.file = grecs_install_text(name); + grecs_current_locus_point.line = 1; + grecs_current_locus_point.col = 0; return 0; } void grecs_bind_close_sources() { @@ -15,36 +15,42 @@ with Grecs. If not, see <http://www.gnu.org/licenses/>. */ #ifdef HAVE_CONFIG_H # include <config.h> #endif #include <grecs.h> +#include <grecs-locus.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <errno.h> static void -default_print_diag(grecs_locus_t *locus, int err, int errcode, const char *msg) +default_print_diag(grecs_locus_t const *locus, int err, int errcode, + const char *msg) { fflush(stdout); - if (locus) - fprintf(stderr, "%s:%d: ", locus->file, locus->line); + if (locus) { + YY_LOCATION_PRINT(stderr, *locus); + fputc(':', stderr); + fputc(' ', stderr); + } if (!err) fprintf(stderr, "warning: "); fprintf(stderr, "%s", msg); if (errcode) fprintf(stderr, ": %s", strerror(errno)); fputc('\n', stderr); } -void (*grecs_print_diag_fun)(grecs_locus_t *, int, int, const char *msg) = +void (*grecs_print_diag_fun)(grecs_locus_t const *, int, int, + const char *msg) = default_print_diag; void -grecs_warning(grecs_locus_t *locus, int errcode, const char *fmt, ...) +grecs_warning(grecs_locus_t const *locus, int errcode, const char *fmt, ...) { va_list ap; char *buf = NULL; size_t size = 0; va_start(ap, fmt); @@ -53,13 +59,13 @@ grecs_warning(grecs_locus_t *locus, int errcode, const char *fmt, ...) va_end(ap); grecs_print_diag_fun(locus, 0, errcode, buf); free(buf); } void -grecs_error(grecs_locus_t *locus, int errcode, const char *fmt, ...) +grecs_error(grecs_locus_t const *locus, int errcode, const char *fmt, ...) { va_list ap; char *buf = NULL; size_t size = 0; va_start(ap, fmt); diff --git a/src/format.c b/src/format.c index d65f712..f1a876f 100644 --- a/src/format.c +++ b/src/format.c @@ -28,13 +28,13 @@ const char * grecs_data_type_string(enum grecs_data_type type) { switch (type) { case grecs_type_void: return "void"; - + case grecs_type_string: return "string"; case grecs_type_short: case grecs_type_ushort: case grecs_type_int: @@ -44,19 +44,19 @@ grecs_data_type_string(enum grecs_data_type type) case grecs_type_size: /*FIXME case grecs_type_off:*/ return "number"; case grecs_type_time: return "time"; - + case grecs_type_bool: return "boolean"; - + case grecs_type_ipv4: return "IPv4"; - + case grecs_type_cidr: return "CIDR"; case grecs_type_host: return "hostname"; @@ -122,13 +122,13 @@ grecs_print_docstring(const char *docstring, unsigned level, FILE *stream) void grecs_print_simple_statement(struct grecs_keyword *kwp, unsigned level, FILE *stream) { const char *argstr; - + if (kwp->docstring) grecs_print_docstring(kwp->docstring, level, stream); format_level(level, stream); if (kwp->argname) argstr = kwp->argname; @@ -189,24 +189,50 @@ grecs_print_statement_array(struct grecs_keyword *kwp, void grecs_format_locus(grecs_locus_t *locus, struct grecs_format_closure *clos) { if (locus) { char *str = NULL; size_t size = 0; - grecs_asprintf(&str, &size, "%s:%d", locus->file, locus->line); + + if (locus->beg.col == 0) + grecs_asprintf(&str, &size, "%s:%u", + locus->beg.file, + locus->beg.line); + else if (strcmp(locus->beg.file, locus->end.file)) + grecs_asprintf(&str, &size, "%s:%u.%u-%s:%u.%u", + locus->beg.file, + locus->beg.line, locus->beg.col, + locus->end.file, + locus->end.line, locus->end.col); + else if (locus->beg.line != locus->end.line) + grecs_asprintf(&str, &size, "%s:%u.%u-%u.%u", + locus->beg.file, + locus->beg.line, locus->beg.col, + locus->end.line, locus->end.col); + else if (locus->beg.col != locus->end.col) + grecs_asprintf(&str, &size, "%s:%u.%u-%u", + locus->beg.file, + locus->beg.line, locus->beg.col, + locus->end.col); + else + grecs_asprintf(&str, &size, "%s:%u.%u", + locus->beg.file, + locus->beg.line, + locus->beg.col); + clos->fmtfun(str, clos->data); free(str); } } void grecs_format_node_path(struct grecs_node *node, int flags, struct grecs_format_closure *clos) { char delim[2] = "."; - + if (node->up) grecs_format_node_path(node->up, flags, clos); if (node->type == grecs_node_root) return; if (flags & _GRECS_NODE_MASK_DELIM) delim[0] = flags & _GRECS_NODE_MASK_DELIM; @@ -274,13 +300,13 @@ grecs_format_value(struct grecs_value *val, int flags, int grecs_format_node(struct grecs_node *node, int flags, struct grecs_format_closure *clos) { const char *delim_str = NULL; - + if (!(flags & _GRECS_NODE_MASK_OUTPUT)) { errno = EINVAL; return 1; } switch (node->type) { @@ -294,13 +320,24 @@ grecs_format_node(struct grecs_node *node, int flags, } break; } case grecs_node_stmt: if (flags & GRECS_NODE_FLAG_LOCUS) { - grecs_format_locus(&node->locus, clos); + grecs_locus_t *locus; + + if (flags & GRECS_NODE_FLAG_PATH) { + if (flags & GRECS_NODE_FLAG_VALUE) + locus = &node->locus; + else + locus = &node->idloc; + } else if (flags & GRECS_NODE_FLAG_VALUE) + locus = &node->v.value->locus; + else + locus = &node->locus; + grecs_format_locus(locus, clos); delim_str = ": "; } if (flags & GRECS_NODE_FLAG_PATH) { if (delim_str) clos->fmtfun(delim_str, clos->data); grecs_format_node_path(node, flags, clos); @@ -364,10 +401,6 @@ grecs_print_value(struct grecs_value *val, int flags, FILE *fp) int grecs_print_node(struct grecs_node *node, int flags, FILE *fp) { struct grecs_format_closure clos = { file_fmt, fp }; return grecs_format_node(node, flags, &clos); } - - - - diff --git a/src/git-parser.c b/src/git-parser.c index 4ab64be..e332704 100644 --- a/src/git-parser.c +++ b/src/git-parser.c @@ -37,28 +37,33 @@ static struct grecs_txtacc *acc; struct token { int type; char *buf; char chbuf[2]; int putback; struct grecs_list *path; + grecs_locus_t loc; + unsigned prev_col; } tok; #define ISSPACE(c) (strchr(" \t\r\f\n", c) != NULL) #define ISIDENT(c) ((isascii(c) && isalnum(c)) || (c) == '_') #define ISINITIAL(c) ((isascii(c) && isalpha(c)) || (c) == '_') static int rawinput() { if (!infile || feof(infile)) return input_char = 0; input_char = fgetc(infile); - if (input_char == '\n') - grecs_current_locus.line++; - else if (input_char < 0) + if (input_char == '\n') { + tok.prev_col = grecs_current_locus_point.col; + grecs_locus_point_advance_line(grecs_current_locus_point); + } else if (input_char < 0) input_char == 0; + else + grecs_current_locus_point.col++; return input_char; } static int input() { @@ -72,14 +77,18 @@ input() static void unput() { if (!input_char) return; - if (input_char == '\n') - grecs_current_locus.line--; + if (input_char == '\n') { + grecs_current_locus_point.line--; + grecs_current_locus_point.col = tok.prev_col; + } else + grecs_current_locus_point.col--; + ungetc(input_char, infile); } static void error_recovery() { @@ -110,13 +119,13 @@ collect_subsection_name() static void collect_substring() { while (rawinput()) { if (input_char == '\\') { if (!input()) { - grecs_error(&grecs_current_locus, 0, + grecs_error(&tok.loc, 0, "unexpected EOF in string"); break; } switch (input_char) { case 'n': input_char = '\n'; @@ -130,27 +139,45 @@ collect_substring() } else if (input_char == '"') break; grecs_txtacc_grow_char(acc, input_char); } } +#define endpoint(t,adj) do { \ + (t).loc.end = grecs_current_locus_point; \ + if (adj) { \ + if (input_char == '\n') \ + (t).loc.end.col = (t).prev_col; \ + else \ + (t).loc.end.col -= (adj); \ + } \ + } while (0) + static void gettoken(void) { int putback = tok.putback; tok.putback = 0; - if (putback) + if (putback) { + if (putback == '\n') + grecs_locus_point_advance_line(grecs_current_locus_point); + else + grecs_current_locus_point.col++; return; - + } + tok.buf = NULL; /* Skip whitespace */ while (input() && ISSPACE(input_char)) ; + tok.loc.beg = grecs_current_locus_point; + if (input_char <= 0) { tok.type = TOK_EOF; + endpoint(tok, 0); return; } if (input_char == '[') { int dot_delimited = -1; @@ -168,21 +195,23 @@ gettoken(void) break; if (dot_delimited == 1) input(); } if (input_char == TOK_EOF) { - grecs_error(&grecs_current_locus, 0, + endpoint(tok, 0); + grecs_error(&tok.loc, 0, "unexpected EOF in section header"); tok.type = TOK_ERR; return; } if (input_char == ']') break; if (input_char == '\n') { - grecs_error(&grecs_current_locus, 0, + endpoint(tok, 1); + grecs_error(&tok.loc, 0, "unexpect newline in in section header"); tok.type = TOK_ERR; return; } if (dot_delimited != 1 && input_char == '"') { @@ -194,26 +223,27 @@ gettoken(void) else collect_unquoted(); if (dot_delimited == -1) dot_delimited = input_char == '.'; else if (dot_delimited == 1) { if (input_char != '.' && input_char != ']') { - grecs_error(&grecs_current_locus, 0, + endpoint(tok, 1); + grecs_error(&tok.loc, 0, "unexpected character in section header"); tok.type = TOK_ERR; return; } } grecs_txtacc_grow_char(acc, 0); p = grecs_txtacc_finish(acc, 0); grecs_list_append(tok.path, p); } - + + endpoint(tok, 1); if (grecs_list_size(tok.path) == 0) { - grecs_error(&grecs_current_locus, 0, - "empty section header"); + grecs_error(&tok.loc, 0, "empty section header"); tok.type = TOK_ERR; return; } tok.type = TOK_SECTION; return; @@ -224,19 +254,21 @@ gettoken(void) do grecs_txtacc_grow_char(acc, input_char); while (input() && ISIDENT(input_char)); unput(); grecs_txtacc_grow_char(acc, 0); tok.buf = grecs_txtacc_finish(acc, 0); + endpoint(tok, 0); return; } tok.chbuf[0] = input_char; tok.chbuf[1] = 0; tok.buf = tok.chbuf; tok.type = input_char; + endpoint(tok, 0); } static void collect_value() { do { @@ -267,16 +299,24 @@ collect_value() static struct grecs_value * getvalue() |