From 440771ca0056eb20396e24f03d349a75ee1c9d22 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Sun, 26 Jun 2011 15:18:29 +0300 Subject: 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) : New member. (grecs_node) : 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. --- src/Make.am | 2 +- src/bind-gram.y | 68 +++++++++++---------- src/bind-lex.l | 58 +++++++++++------- src/diag.c | 18 ++++-- src/format.c | 59 ++++++++++++++----- src/git-parser.c | 93 +++++++++++++++++++++-------- src/grecs-gram.y | 43 +++++++------- src/grecs-lex.l | 102 ++++++++++++++++++++------------ src/grecs-locus.h | 56 ++++++++++++++++++ src/grecs.h | 45 ++++++++++---- src/join.c | 27 +++++---- src/lookup.c | 54 ++++++++++++----- src/meta1-gram.y | 37 ++++++------ src/meta1-lex.l | 27 ++++++--- src/parser.c | 5 +- src/path-parser.c | 172 +++++++++++++++++++++++++++++++++++------------------- src/preproc.c | 22 ++++--- src/tree.c | 45 +++++++++----- 18 files changed, 629 insertions(+), 304 deletions(-) create mode 100644 src/grecs-locus.h (limited to 'src') diff --git a/src/Make.am b/src/Make.am index bc70edc..286bf4c 100644 --- a/src/Make.am +++ b/src/Make.am @@ -59,7 +59,7 @@ GRECS_SRC = \ $(GRECS_PARSER_GIT)\ $(GRECS_PARSER_META1) -noinst_HEADERS = +noinst_HEADERS = grecs-locus.h EXTRA_DIST=\ grecs-gram.h\ 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 @@ -19,7 +19,8 @@ # include #endif #include -#include +#include +#include #include #include #include @@ -30,17 +31,16 @@ 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; @@ -49,8 +49,7 @@ static struct grecs_value *stmtlist_to_value(struct grecs_node *node); struct { struct grecs_node *head, *tail; } node_list; } -%token BIND_IDENT BIND_CONTROLS -%token BIND_STRING +%token BIND_STRING BIND_IDENT BIND_CONTROLS %type string %type value ctlsub %type vallist tag @@ -62,8 +61,7 @@ static struct grecs_value *stmtlist_to_value(struct grecs_node *node); 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); } @@ -102,38 +100,44 @@ stmt : simple 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); } @@ -151,8 +155,10 @@ block : BIND_IDENT tag '{' maybe_stmtlist '}' ';' (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); } ; @@ -176,6 +182,7 @@ vallist : vlist $$ = 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])); @@ -201,20 +208,19 @@ 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; } ; @@ -240,7 +246,7 @@ ctllist : value int yyerror(char *s) { - grecs_error(&grecs_current_locus, 0, "%s", s); + grecs_error(&yylloc, 0, "%s", s); return 0; } @@ -249,7 +255,7 @@ 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; 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 @@ -22,6 +22,7 @@ with Grecs. If not, see . */ #include +#include #include #include #include @@ -32,6 +33,14 @@ #include +#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 @@ -45,26 +54,27 @@ P [1-9][0-9]* "/*" BEGIN(COMMENT); [^*\n]* /* eat anything that's not a '*' */ "*"+[^*/\n]* /* eat up '*'s not followed by '/'s */ -\n ++grecs_current_locus.line; +\n grecs_locus_point_advance_line(grecs_current_locus_point); "*"+"/" 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 */ @@ -97,19 +107,20 @@ P [1-9][0-9]* 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; @@ -135,7 +146,7 @@ cmp_context(const void *a, const void *b) } 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; @@ -148,7 +159,7 @@ _push_context(const char *name, ino_t i_node, dev_t 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")); @@ -158,7 +169,11 @@ _push_context(const char *name, ino_t i_node, dev_t i_dev) 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); @@ -184,7 +199,7 @@ _pop_context() } 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); @@ -199,10 +214,8 @@ yywrap() } 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; @@ -245,15 +258,16 @@ grecs_bind_new_source(const char *name) 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; } diff --git a/src/diag.c b/src/diag.c index 89b38f4..e8b6940 100644 --- a/src/diag.c +++ b/src/diag.c @@ -18,17 +18,22 @@ # include #endif #include +#include #include #include #include #include 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); @@ -37,11 +42,12 @@ default_print_diag(grecs_locus_t *locus, int err, int errcode, const char *msg) 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; @@ -56,7 +62,7 @@ grecs_warning(grecs_locus_t *locus, int errcode, const char *fmt, ...) } 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; diff --git a/src/format.c b/src/format.c index d65f712..f1a876f 100644 --- a/src/format.c +++ b/src/format.c @@ -31,7 +31,7 @@ grecs_data_type_string(enum grecs_data_type type) switch (type) { case grecs_type_void: return "void"; - + case grecs_type_string: return "string"; @@ -47,13 +47,13 @@ grecs_data_type_string(enum grecs_data_type type) case grecs_type_time: return "time"; - + case grecs_type_bool: return "boolean"; - + case grecs_type_ipv4: return "IPv4"; - + case grecs_type_cidr: return "CIDR"; @@ -125,7 +125,7 @@ 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); @@ -192,7 +192,33 @@ 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); } @@ -203,7 +229,7 @@ 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) @@ -277,7 +303,7 @@ 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; @@ -297,7 +323,18 @@ grecs_format_node(struct grecs_node *node, int flags, 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) { @@ -367,7 +404,3 @@ 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 @@ -40,6 +40,8 @@ struct token { 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) @@ -52,10 +54,13 @@ 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; } @@ -75,8 +80,12 @@ 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); } @@ -113,7 +122,7 @@ 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; } @@ -133,21 +142,39 @@ collect_substring() } } +#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; } @@ -171,7 +198,8 @@ gettoken(void) } 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; @@ -179,7 +207,8 @@ gettoken(void) 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; @@ -197,7 +226,8 @@ gettoken(void) 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; @@ -207,10 +237,10 @@ gettoken(void) 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; } @@ -227,6 +257,7 @@ gettoken(void) unput(); grecs_txtacc_grow_char(acc, 0); tok.buf = grecs_txtacc_finish(acc, 0); + endpoint(tok, 0); return; } @@ -234,6 +265,7 @@ gettoken(void) tok.chbuf[1] = 0; tok.buf = tok.chbuf; tok.type = input_char; + endpoint(tok, 0); } static void @@ -270,10 +302,18 @@ getvalue() { int len; struct grecs_value *val = grecs_malloc(sizeof(*val)); + while (input() && ISSPACE(input_char) && input_char != '\n') ; + + val->locus.beg = grecs_current_locus_point; + if (input_char != '\n') collect_value(); + val->locus.end = grecs_current_locus_point; + val->locus.end.line--; + val->locus.end.col = tok.prev_col; + grecs_txtacc_grow_char(acc, 0); tok.type = TOK_VALUE; tok.buf = grecs_txtacc_finish(acc, 1); @@ -296,28 +336,30 @@ read_statement(struct grecs_node *parent) return 0; } if (tok.type != TOK_KEYWORD) { - grecs_error(&grecs_current_locus, 0, "syntax error"); + grecs_error(&tok.loc, 0, "syntax error"); error_recovery(); return 1; } - node = grecs_node_create(grecs_node_stmt, &grecs_current_locus); + node = grecs_node_create(grecs_node_stmt, &tok.loc); node->ident = grecs_strdup(tok.buf); - + node->idloc = tok.loc; + gettoken(); if (tok.type == TOK_EOF) { - grecs_error(&grecs_current_locus, 0, "unexpected EOF"); + grecs_error(&tok.loc, 0, "unexpected EOF"); grecs_node_free(node); return 0; } if (tok.type != TOK_EQ) { - grecs_error(&grecs_current_locus, 0, + grecs_error(&tok.loc, 0, "expected `=', but found `%s'", tok.buf); error_recovery(); grecs_node_free(node); return 1; } node->v.value = getvalue(); + node->locus.end = node->v.value->locus.end; grecs_node_bind(parent, node, 1); return 1; } @@ -339,8 +381,7 @@ create_subsection_node(struct grecs_node *root) char *ident = ep->data; p = grecs_find_node(root, ident); if (!p) { - p = grecs_node_create(grecs_node_block, - &grecs_current_locus); + p = grecs_node_create(grecs_node_block, &tok.loc); p->ident = grecs_strdup(ident); grecs_node_bind(root, p, 1); } @@ -361,7 +402,7 @@ read_section(struct grecs_node *parent) } else if (tok.type == TOK_KEYWORD) { read_statement(parent); } else { - grecs_error(&grecs_current_locus, 0, "syntax error"); + grecs_error(&tok.loc, 0, "syntax error"); error_recovery(); } return 1; @@ -378,15 +419,17 @@ grecs_git_parser(const char *name, int traceflags) grecs_error(NULL, errno, _("cannot open `%s'"), name); return NULL; } - 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; acc = grecs_txtacc_create(); tok.path = grecs_list_create(); - root = grecs_node_create(grecs_node_root, &grecs_current_locus); + root = grecs_node_create(grecs_node_root, &tok.loc); while (read_section(root)) ; + root->locus.end = grecs_current_locus_point; fclose(infile); grecs_txtacc_free(acc); grecs_list_free(tok.path); diff --git a/src/grecs-gram.y b/src/grecs-gram.y index bbe3d5e..92de6b2 100644 --- a/src/grecs-gram.y +++ b/src/grecs-gram.y @@ -19,6 +19,7 @@ # include #endif #include +#include #include #include #include @@ -31,11 +32,10 @@ int yyerror(char *s); static struct grecs_node *parse_tree; %} +%error-verbose +%locations + %union { - struct { - grecs_locus_t locus; - char *string; - } ident; char *string; grecs_value_t svalue, *pvalue; struct grecs_list *list; @@ -44,8 +44,7 @@ static struct grecs_node *parse_tree; struct { struct grecs_node *head, *tail; } node_list; } -%token IDENT -%token STRING QSTRING MSTRING +%token STRING QSTRING MSTRING IDENT %type string slist %type slist0 %type value @@ -58,8 +57,7 @@ static struct grecs_node *parse_tree; 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); } @@ -92,25 +90,27 @@ stmt : simple simple : IDENT vallist ';' { - $$ = 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; } | IDENT ';' { - $$ = grecs_node_create(grecs_node_stmt, - &$1.locus); - $$->ident = $1.string; + $$ = grecs_node_create(grecs_node_stmt, &@1); + $$->ident = $1; + $$->idloc = @1; $$->v.value = NULL; } ; block : IDENT tag '{' stmtlist '}' opt_sc { - $$ = 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.head, 1); } @@ -135,6 +135,7 @@ vallist : vlist $$ = 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])); @@ -160,25 +161,25 @@ vlist : value value : string { $$.type = GRECS_TYPE_STRING; + $$.locus = @1; $$.v.string = $1; } | list { $$.type = GRECS_TYPE_LIST; + $$.locus = @1; $$.v.list = $1; } | MSTRING { $$.type = GRECS_TYPE_STRING; + $$.locus = @1; $$.v.string = $1; } ; string : STRING | IDENT - { - $$ = $1.string; - } | slist ; @@ -244,7 +245,7 @@ opt_sc : /* empty */ int yyerror(char *s) { - grecs_error(&grecs_current_locus, 0, "%s", s); + grecs_error(&yylloc, 0, "%s", s); return 0; } diff --git a/src/grecs-lex.l b/src/grecs-lex.l index 5ca4e31..ba7a386 100644 --- a/src/grecs-lex.l +++ b/src/grecs-lex.l @@ -2,7 +2,7 @@ %top { #ifdef HAVE_CONFIG_H # include -#endif +#endif } %{ /* grecs - Gray's Extensible Configuration System @@ -22,6 +22,7 @@ with Grecs. If not, see . */ #include +#include #include #include #include @@ -37,7 +38,7 @@ static int multiline_unescape; /* Unescape here-document contents */ static int (*char_to_strip)(char); /* Strip matching characters of each here-document line */ -grecs_locus_t grecs_current_locus; /* Input file location */ +struct grecs_locus_point grecs_current_locus_point; /* Input file location */ /* Line correction. Equals to the number of #line directives inserted into the input by the preprocessor instance. The external preprocessor, if any, counts these as input lines and therefore the line numbers in *its* @@ -54,16 +55,23 @@ static int ident(void); static int isemptystr(int off); #undef YY_INPUT -#define YY_INPUT(buf,result,max_size) \ - do \ - { \ - if (grecs_preprocessor) \ - result = fread(buf, 1, max_size, yyin); \ - else \ - result = grecs_preproc_fill_buffer(buf, max_size); \ - } \ - while(0) - +#define YY_INPUT(buf,result,max_size) \ + do { \ + if (grecs_preprocessor) \ + result = fread(buf, 1, max_size, yyin); \ + else \ + result = grecs_preproc_fill_buffer(buf, max_size); \ + } while(0) + +#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); + %} @@ -78,18 +86,21 @@ P [1-9][0-9]* "/*" BEGIN(COMMENT); [^*\n]* /* eat anything that's not a '*' */ "*"+[^*/\n]* /* eat up '*'s not followed by '/'s */ -\n ++grecs_current_locus.line; +\n grecs_locus_point_advance_line(grecs_current_locus_point); "*"+"/" BEGIN(INITIAL); /* Line directive */ ^[ \t]*#[ \t]*{P}[ \t]+\".*\".*\n { grecs_parse_line_directive_cpp(yytext, - &grecs_current_locus, + &yylloc, + &grecs_current_locus_point, &xlines); } -^[ \t]*#[ \t]*line[ \t].*\n { grecs_parse_line_directive(yytext, &grecs_current_locus, - &xlines); } +^[ \t]*#[ \t]*line[ \t].*\n { grecs_parse_line_directive(yytext, + &yylloc, + &grecs_current_locus_point, + &xlines); } /* 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} return ident(); @@ -123,11 +134,12 @@ P [1-9][0-9]* "<<"(-" "?)?\"{ID}\"[ \t]*#.*\n | "<<"(-" "?)?\"{ID}\"[ \t]*"//".*\n | "<<"(-" "?)?\"{ID}\"[ \t]*\n { - BEGIN(ML); - multiline_begin(yytext+2); - grecs_current_locus.line++; } + BEGIN(ML); + multiline_begin(yytext+2); } /* Ignore m4 line statements */ -^"#line ".*\n { grecs_current_locus.line++; } +^"#line ".*\n { + grecs_locus_point_advance_line(grecs_current_locus_point); +} .*\n { char *p = multiline_strip_tabs(yytext); if (!strncmp(p, multiline_delimiter, multiline_delimiter_len) @@ -136,20 +148,30 @@ P [1-9][0-9]* multiline_delimiter = NULL; BEGIN(INITIAL); yylval.string = grecs_line_finish(); + + /* Update end pos */ + yylloc.end.line--; + for (yylloc.end.col = 0, + p = yylval.string + strlen(yylval.string) - 1; + p > yylval.string && p[-1] != '\n'; + yylloc.end.col++, p--); + if (yylloc.end.col == 0) + yylloc.end.col = 1; return MSTRING; } - grecs_current_locus.line++; + grecs_locus_point_advance_line(grecs_current_locus_point); multiline_add(p); } {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]); } %% pid_t grecs_preproc_pid; @@ -161,7 +183,7 @@ yywrap() grecs_preproc_extrn_shutdown(grecs_preproc_pid); else grecs_preproc_done(); - grecs_current_locus.file = NULL; + grecs_current_locus_point.file = NULL; return 1; } @@ -285,6 +307,11 @@ multiline_begin(char *p) memcpy(multiline_delimiter, p, multiline_delimiter_len); multiline_delimiter[multiline_delimiter_len] = 0; grecs_line_begin(); + + /* Update locus */ + grecs_locus_point_advance_line(grecs_current_locus_point); + yylloc.beg = grecs_current_locus_point; + yylloc.beg.col++; } static int @@ -300,8 +327,7 @@ ident() len = strlen(p); str = grecs_malloc(len + 1); strcpy(str, p); - yylval.ident.locus = grecs_current_locus; - yylval.ident.string = str; + yylval.string = str; return IDENT; } @@ -315,7 +341,8 @@ grecs_value_ptr_from_static(grecs_value_t *input) static int -assign_locus(grecs_locus_t *ploc, char *name, char *line, size_t *pxlines) +assign_locus(struct grecs_locus_point *ploc, + char *name, char *line, size_t *pxlines) { char *p; @@ -325,11 +352,13 @@ assign_locus(grecs_locus_t *ploc, char *name, char *line, size_t *pxlines) ploc->file = grecs_install_text(name); } ploc->line = strtoul(line, &p, 10) - (pxlines ? *pxlines : 0); + ploc->col = 0; return *p != 0; } void -grecs_parse_line_directive(char *text, grecs_locus_t *ploc, size_t *pxlines) +grecs_parse_line_directive(char *text, grecs_locus_t *ploc, + struct grecs_locus_point *ppoint, size_t *pxlines) { int rc = 1; struct wordsplit ws; @@ -338,13 +367,13 @@ grecs_parse_line_directive(char *text, grecs_locus_t *ploc, size_t *pxlines) grecs_error(ploc, 0, _("cannot parse #line line")); else { if (ws.ws_wordc == 2) - rc = assign_locus(ploc, NULL, + rc = assign_locus(ppoint, NULL, ws.ws_wordv[1], pxlines); else if (ws.ws_wordc == 3) - rc = assign_locus(ploc, ws.ws_wordv[2], + rc = assign_locus(ppoint, ws.ws_wordv[2], ws.ws_wordv[1], pxlines); else if (ws.ws_wordc == 4) { - rc = assign_locus(ploc, ws.ws_wordv[2], + rc = assign_locus(ppoint, ws.ws_wordv[2], ws.ws_wordv[1], 0); if (pxlines && rc == 0) { char *p; @@ -365,6 +394,7 @@ grecs_parse_line_directive(char *text, grecs_locus_t *ploc, size_t *pxlines) void grecs_parse_line_directive_cpp(char *text, grecs_locus_t *ploc, + struct grecs_locus_point *ppoint, size_t *pxlines) { struct wordsplit ws; @@ -375,7 +405,7 @@ grecs_parse_line_directive_cpp(char *text, grecs_locus_t *ploc, } else if (ws.ws_wordc < 3) grecs_error(ploc, 0, _("invalid #line statement")); else { - if (assign_locus(ploc, ws.ws_wordv[2], + if (assign_locus(ppoint, ws.ws_wordv[2], ws.ws_wordv[1], pxlines)) grecs_error(ploc, 0, _("malformed #line statement")); } diff --git a/src/grecs-locus.h b/src/grecs-locus.h new file mode 100644 index 0000000..e23add2 --- /dev/null +++ b/src/grecs-locus.h @@ -0,0 +1,56 @@ +/* grecs - Gray's Extensible Configuration System + Copyright (C) 2007-2011 Sergey Poznyakoff + + Grecs is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + Grecs is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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 . */ + +#define YYLTYPE grecs_locus_t + +#define YYLLOC_DEFAULT(Current, Rhs, N) \ + do { \ + if (N) { \ + (Current).beg = YYRHSLOC(Rhs, 1).beg; \ + (Current).end = YYRHSLOC(Rhs, N).end; \ + } else { \ + (Current).beg = YYRHSLOC(Rhs, 0).end; \ + (Current).end = (Current).beg; \ + } \ + } while (0) + +#define YY_LOCATION_PRINT(File, Loc) do { \ + if ((Loc).beg.col == 0) \ + fprintf(File, "%s:%u", \ + (Loc).beg.file, \ + (Loc).beg.line); \ + else if (strcmp((Loc).beg.file, (Loc).end.file)) \ + fprintf(File, "%s:%u.%u-%s:%u.%u", \ + (Loc).beg.file, \ + (Loc).beg.line, (Loc).beg.col, \ + (Loc).end.file, \ + (Loc).end.line, (Loc).end.col); \ + else if ((Loc).beg.line != (Loc).end.line) \ + fprintf(File, "%s:%u.%u-%u.%u", \ + (Loc).beg.file, \ + (Loc).beg.line, (Loc).beg.col, \ + (Loc).end.line, (Loc).end.col); \ + else if ((Loc).beg.col != (Loc).end.col) \ + fprintf(File, "%s:%u.%u-%u", \ + (Loc).beg.file, \ + (Loc).beg.line, (Loc).beg.col, \ + (Loc).end.col); \ + else \ + fprintf(File, "%s:%u.%u", \ + (Loc).beg.file, \ + (Loc).beg.line); \ + } while (0) + diff --git a/src/grecs.h b/src/grecs.h index 8bd70d1..1581791 100644 --- a/src/grecs.h +++ b/src/grecs.h @@ -51,9 +51,23 @@ struct grecs_version_info { char *buffer; }; -typedef struct { +struct grecs_locus_point { char *file; - int line; + unsigned line; + unsigned col; +}; + +#define grecs_locus_point_advance_line(loc) do { \ + (loc).line++; \ + (loc).col = 0; \ + } while (0) + +#define GRECS_LOCUS_POINT_EQ(a,b) \ + ((strcmp((a)->file, (b)->file) == 0) && ((a)->line == (b)->line)) + +typedef struct grecs_locus { + struct grecs_locus_point beg; + struct grecs_locus_point end; } grecs_locus_t; extern grecs_locus_t grecs_locus; @@ -109,6 +123,7 @@ struct grecs_list { typedef struct grecs_value { int type; + grecs_locus_t locus; union { struct grecs_list *list; char *string; @@ -137,6 +152,7 @@ typedef struct grecs_node { struct grecs_node *next; struct grecs_node *prev; char *ident; + grecs_locus_t idloc; union { struct grecs_value *value; struct grecs_symtab *texttab; @@ -192,12 +208,14 @@ void grecs_free(void *ptr); grecs_value_t *grecs_value_ptr_from_static(grecs_value_t *input); -extern void (*grecs_print_diag_fun)(grecs_locus_t *, int, int, const char*); +extern void (*grecs_print_diag_fun)(grecs_locus_t const *, int, int, const char*); -void grecs_warning(grecs_locus_t *locus, int errcode, const char *fmt, ...) - __attribute__ ((__format__ (__printf__, 3, 4))); -void grecs_error(grecs_locus_t *locus, int errcode, const char *fmt, ...) - __attribute__ ((__format__ (__printf__, 3, 4))); +void grecs_warning(grecs_locus_t const *locus, + int errcode, const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 3, 4))); +void grecs_error(grecs_locus_t const *locus, int errcode, + const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 3, 4))); extern int grecs_trace_flags; @@ -208,8 +226,10 @@ void grecs_gram_trace(int n); void grecs_lex_trace(int n); void grecs_parse_line_directive(char *text, grecs_locus_t *ploc, + struct grecs_locus_point *ppoint, size_t *pxlines); void grecs_parse_line_directive_cpp(char *text, grecs_locus_t *ploc, + struct grecs_locus_point *ppoint, size_t *pxlines); @@ -251,7 +271,8 @@ void grecs_line_begin(void); char *grecs_line_finish(void); extern int grecs_string_convert(void *target, enum grecs_data_type type, - const char *string, grecs_locus_t *locus); + const char *string, + grecs_locus_t const *locus); extern void grecs_process_ident(struct grecs_keyword *kwp, grecs_value_t *value, void *base, @@ -259,12 +280,15 @@ extern void grecs_process_ident(struct grecs_keyword *kwp, struct grecs_node *grecs_node_create(enum grecs_node_type type, grecs_locus_t *loc); +struct grecs_node *grecs_node_create_points(enum grecs_node_type type, + struct grecs_locus_point beg, + struct grecs_locus_point end); void grecs_node_bind(struct grecs_node *master, struct grecs_node *node, int dn); int grecs_node_eq(struct grecs_node *a, struct grecs_node *b); -extern grecs_locus_t grecs_current_locus; +extern struct grecs_locus_point grecs_current_locus_point; extern int grecs_error_count; extern int grecs_default_port; @@ -450,7 +474,8 @@ struct grecs_node *grecs_find_node(struct grecs_node *node, const char *path); struct grecs_node *grecs_node_from_path(const char *path, const char *value); struct grecs_node *grecs_node_from_path_locus(const char *path, const char *value, - grecs_locus_t *locus); + grecs_locus_t *locus, + grecs_locus_t *vallocus); int grecs_tree_reduce(struct grecs_node *node, struct grecs_keyword *kwd, int flags); diff --git a/src/join.c b/src/join.c index fd7c3ad..29db5bf 100644 --- a/src/join.c +++ b/src/join.c @@ -21,6 +21,21 @@ #include #include "grecs.h" +static void +reset_point(struct grecs_locus_point *point, struct grecs_symtab *st) +{ + struct grecs_syment *ent, key; + int install = 1; + + if (!point->file) + return; + key.name = (char*) point->file; + ent = grecs_symtab_lookup_or_install(st, &key, &install); + if (!ent) + grecs_alloc_die(); + point->file = ent->name; +} + static enum grecs_tree_recurse_res reset_locus(enum grecs_tree_recurse_op op, struct grecs_node *node, void *data) { @@ -28,16 +43,8 @@ reset_locus(enum grecs_tree_recurse_op op, struct grecs_node *node, void *data) switch (op) { case grecs_tree_recurse_set: case grecs_tree_recurse_pre: - if (node->locus.file) { - struct grecs_syment *ent, key; - int install = 1; - key.name = (char*) node->locus.file; - ent = grecs_symtab_lookup_or_install(st, &key, - &install); - if (!ent) - grecs_alloc_die(); - node->locus.file = ent->name; - } + reset_point(&node->locus.beg, st); + reset_point(&node->locus.end, st); break; default: break; diff --git a/src/lookup.c b/src/lookup.c index f16e94b..2e737aa 100644 --- a/src/lookup.c +++ b/src/lookup.c @@ -199,7 +199,7 @@ parse_label(const char *str) lst = grecs_value_list_create(); for (i = 0; i < ws.ws_wordc; i++) { - struct grecs_value *p = grecs_malloc(sizeof(*p)); + struct grecs_value *p = grecs_zalloc(sizeof(*p)); p->type = GRECS_TYPE_STRING; p->v.string = ws.ws_wordv[i]; grecs_list_append(lst, p); @@ -210,7 +210,7 @@ parse_label(const char *str) } else { if (wordsplit(str, &ws, WRDSF_DEFFLAGS)) return NULL; - val = grecs_malloc(sizeof(*val)); + val = grecs_zalloc(sizeof(*val)); if (ws.ws_wordc == 1) { val->type = GRECS_TYPE_STRING; val->v.string = ws.ws_wordv[0]; @@ -221,14 +221,14 @@ parse_label(const char *str) sizeof(val->v.arg.v[0])); for (i = 0; i < ws.ws_wordc; i++) { val->v.arg.v[i] = - grecs_malloc(sizeof(val->v.arg.v[0])); + grecs_zalloc(sizeof(*val->v.arg.v[0])); val->v.arg.v[i]->type = GRECS_TYPE_STRING; val->v.arg.v[i]->v.string = ws.ws_wordv[i]; } } - ws.ws_wordc = 0; - wordsplit_free(&ws); } + ws.ws_wordc = 0; + wordsplit_free(&ws); return val; } @@ -244,15 +244,16 @@ split_cfg_path(const char *path, int *pargc, char ***pargv, if (path[0] == '\\') { argv = calloc(2, sizeof (*argv)); if (!argv) - return ENOMEM; + return WRDSE_NOSPACE; argv[0] = strdup(path + 1); if (!argv[0]) { free(argv); - return ENOMEM; + return WRDSE_NOSPACE; } argv[1] = NULL; argc = 1; } else { + int rc; struct wordsplit ws; if (strchr("./:;,^~", path[0])) { @@ -262,8 +263,10 @@ split_cfg_path(const char *path, int *pargc, char ***pargv, } ws.ws_delim = delim; - if (wordsplit(path, &ws, WRDSF_DEFFLAGS|WRDSF_DELIM)) - return errno; + rc = wordsplit(path, &ws, + WRDSF_DELIM | WRDSF_DEFFLAGS); + if (rc) + return rc; argc = ws.ws_wordc; argv = ws.ws_wordv; ws.ws_wordc = 0; @@ -333,9 +336,25 @@ grecs_find_node(struct grecs_node *node, const char *path) } +static void +fixup_loci(struct grecs_node *node, + grecs_locus_t const *plocus, + struct grecs_locus_point const *endp) +{ + grecs_locus_t loc = *plocus; + + for (; node; node = node->down) { + node->idloc = loc; + + node->locus = loc; + if (endp) + node->locus.end = *endp; + } +} + struct grecs_node * grecs_node_from_path_locus(const char *path, const char *value, - grecs_locus_t *locus) + grecs_locus_t *plocus, grecs_locus_t *vallocus) { int rc; int i; @@ -346,10 +365,13 @@ grecs_node_from_path_locus(const char *path, const char *value, rc = split_cfg_path(path, &argc, &argv, NULL); if (rc) return NULL; - dn = grecs_node_create(grecs_node_stmt, locus); + + dn = grecs_node_create(grecs_node_stmt, NULL); dn->ident = argv[argc - 1]; if (value) { struct grecs_value *gval = parse_label(value); + if (vallocus) + gval->locus = *vallocus; dn->v.value = gval; } else dn->v.value = NULL; @@ -371,7 +393,7 @@ grecs_node_from_path_locus(const char *path, const char *value, break; } while (*q); - node = grecs_node_create(grecs_node_block, locus); + node = grecs_node_create(grecs_node_block, plocus); node->ident = argv[i]; if (label) node->v.value = label; @@ -381,7 +403,11 @@ grecs_node_from_path_locus(const char *path, const char *value, dn->up = node; dn = node; } - + + if (plocus) + fixup_loci(dn, + plocus, vallocus ? &vallocus->end : NULL); + free(argv); return dn; } @@ -389,7 +415,7 @@ grecs_node_from_path_locus(const char *path, const char *value, struct grecs_node * grecs_node_from_path(const char *path, const char *value) { - return grecs_node_from_path_locus(path, value, NULL); + return grecs_node_from_path_locus(path, value, NULL, NULL); } diff --git a/src/meta1-gram.y b/src/meta1-gram.y index 455c362..0fb6727 100644 --- a/src/meta1-gram.y +++ b/src/meta1-gram.y @@ -21,6 +21,7 @@ #include #include #include "grecs.h" +#include "grecs-locus.h" int yylex(void); int yyerror(char *s); @@ -29,11 +30,10 @@ static struct grecs_node *parse_tree; extern int yy_flex_debug; %} +%error-verbose +%locations + %union { - struct { - grecs_locus_t locus; - char *string; - } ident; char *string; grecs_value_t svalue, *pvalue; struct grecs_list *list; @@ -41,8 +41,7 @@ extern int yy_flex_debug; struct grecs_node *node; } -%token META1_IDENT -%token META1_STRING +%token META1_STRING META1_IDENT %type stmt simple block maybe_stmtlist %type stmtlist %type tag value @@ -53,8 +52,7 @@ extern int yy_flex_debug; 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); } @@ -87,18 +85,20 @@ stmt : simple simple : META1_IDENT '=' value opt_sc { - $$ = grecs_node_create(grecs_node_stmt, - &$1.locus); - $$->ident = $1.string; + $$ = grecs_node_create_points(grecs_node_stmt, + @1.beg, @3.end); + $$->ident = $1; + $$->idloc = @1; $$->v.value = $3; } ; block : META1_IDENT tag '{' stmtlist '}' opt_sc { - $$ = 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.head, 1); } @@ -112,7 +112,7 @@ tag : /* empty */ { $$ = grecs_malloc(sizeof($$[0])); $$->type = GRECS_TYPE_STRING; - $$->v.string = $1.string; + $$->v.string = $1; } ; @@ -120,20 +120,19 @@ value : string { $$ = grecs_malloc(sizeof($$[0])); $$->type = GRECS_TYPE_STRING; + $$->locus = @1; $$->v.string = $1; } | list { $$ = grecs_malloc(sizeof($$[0])); $$->type = GRECS_TYPE_LIST; + $$->locus = @1; $$->v.list = $1; } ; string : META1_IDENT - { - $$ = $1.string; - } | slist ; @@ -193,7 +192,7 @@ opt_sc : /* empty */ int yyerror(char *s) { - grecs_error(&grecs_current_locus, 0, "%s", s); + grecs_error(&yylloc, 0, "%s", s); return 0; } diff --git a/src/meta1-lex.l b/src/meta1-lex.l index cb2931d..04eddb5 100644 --- a/src/meta1-lex.l +++ b/src/meta1-lex.l @@ -23,6 +23,7 @@ # include #endif #include "grecs.h" +#include "grecs-locus.h" #include "meta1-gram.h" #include } @@ -30,6 +31,15 @@ %{ static int yywrap(void); static void meta1_line_add_unescape_hex(const char *text, size_t len); + +#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 @@ -39,10 +49,10 @@ X [0-9a-fA-F] "/*" BEGIN (COMMENT); [^*\n]* /* eat anything that's not a '*' */ "*"+[^*/\n]* /* eat up '*'s not followed by '/'s */ -\n ++grecs_current_locus.line; +\n grecs_locus_point_advance_line(grecs_current_locus_point); "*"+"/" BEGIN (INITIAL); /* End-of-line comments */ -#.*\n { grecs_current_locus.line++; } +#.*\n { grecs_locus_point_advance_line(grecs_current_locus_point); } #.* /* end-of-file comment */; /* Number */ 0[xX]{X}+ | @@ -54,8 +64,7 @@ X [0-9a-fA-F] /* Identifiers (unquoted strings) */ [a-zA-Z0-9_\./:\*-]+ { grecs_line_begin(); grecs_line_add(yytext, yyleng); - yylval.ident.locus = grecs_current_locus; - yylval.ident.string = grecs_line_finish(); + yylval.string = grecs_line_finish(); return META1_IDENT; } /* Quoted strings */ \"[^\\"\n]*\" { grecs_line_begin(); @@ -78,16 +87,16 @@ X [0-9a-fA-F] yylval.string = grecs_line_finish(); return META1_STRING; } [^\\"\n]*\n { BEGIN(INITIAL); - grecs_error(&grecs_current_locus, 0, + grecs_error(&yylloc, 0, _("newline in a string")); - grecs_line_add (yytext, yyleng - 1); - yylval.string = grecs_line_finish (); + grecs_line_add(yytext, yyleng - 1); + yylval.string = grecs_line_finish(); return META1_STRING; } /* Other tokens */ [ \t\f][ \t\f]* ; -\n { grecs_current_locus.line++; } +\n { grecs_locus_point_advance_line(grecs_current_locus_point); } [,;{}=] return yytext[0]; -. { grecs_error(&grecs_current_locus, 0, +. { grecs_error(&yylloc, 0, (isascii(yytext[0]) && isprint(yytext[0])) ? _("stray character %c") : _("stray character \\%03o"), diff --git a/src/parser.c b/src/parser.c index 5d8bdf3..4e315e5 100644 --- a/src/parser.c +++ b/src/parser.c @@ -56,7 +56,8 @@ struct grecs_node * grecs_parse(const char *name) { grecs_error_count = 0; - grecs_current_locus.file = grecs_install_text(name); - grecs_current_locus.line = 0; + grecs_current_locus_point.file = grecs_install_text(name); + grecs_current_locus_point.line = 1; + grecs_current_locus_point.col = 0; return grecs_parser_fun(name, grecs_trace_flags); } diff --git a/src/path-parser.c b/src/path-parser.c index c66f8ca..f42ac60 100644 --- a/src/path-parser.c +++ b/src/path-parser.c @@ -23,17 +23,25 @@ #include #include -static size_t -trimnl(char *buf) +static int +next_char(FILE *infile) { - size_t len = strlen(buf); - - if (len && buf[len-1] == '\n') { - buf[--len] = 0; - if (len && buf[len-1] == '\r') - buf[--len] = 0; + int c = fgetc(infile); + if (c == '\n') + grecs_locus_point_advance_line(grecs_current_locus_point); + else { + grecs_current_locus_point.col++; + if (c == '\\') { + int nc = fgetc(infile); + if (nc == '\n') { + grecs_locus_point_advance_line(grecs_current_locus_point); + c = fgetc(infile); + grecs_current_locus_point.col++; + } else + ungetc(nc, infile); + } } - return len; + return c; } struct grecs_node * @@ -41,84 +49,126 @@ grecs_path_parser(const char *name, int traceflags) { struct grecs_node *root, *subtree = NULL, *node; FILE *infile; - char *buf = NULL; - size_t size = 0; struct grecs_txtacc *acc = NULL; - char *prevptr = NULL; - char *ptr, *p; - int inquote, cont = 0; + char *kw, *val; + grecs_locus_t kwloc, valloc, rootloc; + int inquote; + int lookahead; + int err = 0; + unsigned prev_col; infile = fopen(name, "r"); if (!infile) { grecs_error(NULL, errno, _("cannot open `%s'"), name); return NULL; } - grecs_current_locus.file = grecs_install_text(name); - grecs_current_locus.line = 0; + grecs_current_locus_point.file = grecs_install_text(name); + grecs_current_locus_point.line = 1; + grecs_current_locus_point.col = 0; + rootloc.beg = grecs_current_locus_point; + rootloc.beg.col++; + + acc = grecs_txtacc_create(); - while (grecs_getline(&buf, &size, infile) >= 0) { - size_t len; - - ++grecs_current_locus.line; - len = trimnl(buf); - if (len && buf[len-1] == '\\') { - if (!acc) - acc = grecs_txtacc_create(); - else if (prevptr) { - grecs_txtacc_free_string(acc, prevptr); - prevptr = NULL; + while ((lookahead = next_char(infile)) > 0) { + while (1) { + while (lookahead == ' ' || lookahead == '\t') + lookahead = next_char(infile); + + if (lookahead == '#') { + while ((lookahead = next_char(infile)) && + lookahead != '\n') + ; + continue; } - grecs_txtacc_grow(acc, buf, len - 1); - cont = 1; - continue; - } else { - if (cont) - ptr = prevptr = grecs_txtacc_finish(acc, 0); - else - ptr = buf; - cont = 0; + break; } + + if (lookahead <= 0) + break; + + kwloc.beg = grecs_current_locus_point; - while (*ptr && (*ptr == ' ' || *ptr == '\t')) - ptr++; - if (!*ptr || *ptr == '#') - continue; inquote = 0; - for (p = ptr; *p && *p != ':'; p++) { + for (; lookahead > 0 && lookahead != ':'; + lookahead = next_char(infile)) { if (inquote) { - if (inquote == '"' && *p == '\\') - p++; - else if (*p == inquote) + if (inquote == '"' && lookahead == '\\') { + lookahead = next_char(infile); + if (lookahead <= 0) + break; + } else if (lookahead == inquote) inquote = 0; - } else if (*p == '\'' || *p == '"') - inquote = *p; + } else if (lookahead == '\'' || lookahead == '"') + inquote = lookahead; + grecs_txtacc_grow_char(acc, lookahead); } - if (!*p) { - grecs_error(&grecs_current_locus, 0, - _("syntax error")); - continue; + + if (lookahead <= 0) { + grecs_error(&kwloc, 0, _("unexpected end of file")); + err = 1; + break; } - *p++ = 0; - while (*p && (*p == ' ' || *p == '\t')) - p++; + + grecs_txtacc_grow_char(acc, 0); + kw = grecs_txtacc_finish(acc, 0); + + kwloc.end = grecs_current_locus_point; + kwloc.end.col--; + + while ((lookahead = next_char(infile)) > 0 && + (lookahead == ' ' || lookahead == '\t')); + + if (lookahead <= 0) { + grecs_error(&kwloc, 0, _("unexpected end of file")); + err = 1; + break; + } + + valloc.beg = grecs_current_locus_point; + do { + grecs_txtacc_grow_char(acc, lookahead); + prev_col = grecs_current_locus_point.col; + } while ((lookahead = next_char(infile)) > 0 && + lookahead != '\n'); + valloc.end = grecs_current_locus_point; + valloc.end.line--; + valloc.end.col = prev_col; + + grecs_txtacc_grow_char(acc, 0); + val = grecs_txtacc_finish(acc, 0); + + node = grecs_node_from_path_locus(kw, val, &kwloc, &valloc); + if (!node) { + grecs_error(&kwloc, 0, _("parse error")); + err = 1; + break; + } + node->locus.end = valloc.end; + node->idloc = kwloc; - node = grecs_node_from_path_locus(ptr, p, - &grecs_current_locus); if (!subtree) subtree = node; else grecs_node_bind(subtree, node, 0); + grecs_txtacc_free_string(acc, kw); + grecs_txtacc_free_string(acc, val); } fclose(infile); - free(buf); grecs_txtacc_free(acc); - root = grecs_node_create(grecs_node_root, &grecs_current_locus); - root->v.texttab = grecs_text_table(); - grecs_node_bind(root, subtree, 1); - grecs_tree_reduce(root, NULL, 0); - + if (err) { + grecs_tree_free(subtree); + root = NULL; + } else { + rootloc.end = grecs_current_locus_point; + root = grecs_node_create(grecs_node_root, &rootloc); + root->v.texttab = grecs_text_table(); + grecs_node_bind(root, subtree, 1); + grecs_tree_reduce(root, NULL, 0); + } + return root; } diff --git a/src/preproc.c b/src/preproc.c index 1eeddd0..a5dda52 100644 --- a/src/preproc.c +++ b/src/preproc.c @@ -55,6 +55,7 @@ static size_t linebufsize = 0; #define INFILE context_stack->infile #define LOCUS context_stack->locus +#define POINT context_stack->locus.beg static char *linebuf; static size_t bufsize; @@ -123,8 +124,8 @@ pp_line_stmt() if (grecs_asprintf(&linebufbase, &linebufsize, "#line %lu \"%s\" %lu\n", - (unsigned long) LOCUS.line, - LOCUS.file, (unsigned long) context_stack->xlines)) + (unsigned long) POINT.line, + POINT.file, (unsigned long) context_stack->xlines)) grecs_alloc_die(); ls_size = strlen(linebufbase); @@ -211,7 +212,7 @@ grecs_preproc_fill_buffer(char *buf, size_t size) } if (!is_line && len > 0 && linebuf[len - 1] == '\n') - LOCUS.line++; + POINT.line++; } return bufsize - size; } @@ -397,7 +398,7 @@ push_source(const char *name, int once) return 1; } - if (LOCUS.file && STAT_ID_EQ(st, context_stack->id)) { + if (POINT.file && STAT_ID_EQ(st, context_stack->id)) { grecs_error(&LOCUS, 0, _("Recursive inclusion")); return 1; } @@ -431,10 +432,13 @@ push_source(const char *name, int once) /* Push current context */ ctx = grecs_malloc(sizeof(*ctx)); - ctx->locus.file = grecs_install_text(name); - ctx->locus.line = 1; + ctx->locus.beg.file = grecs_install_text(name); + ctx->locus.beg.line = 1; + ctx->locus.beg.col = 0; + ctx->locus.end.file = NULL; + ctx->locus.end.line = ctx->locus.end.col = 0; ctx->xlines = 0; - ctx->namelen = strlen(ctx->locus.file); + ctx->namelen = strlen(ctx->locus.beg.file); ctx->id.i_node = st.st_ino; ctx->id.device = st.st_dev; ctx->infile = fp; @@ -470,11 +474,11 @@ pop_source() return 1; } - LOCUS.line++; + POINT.line++; if (grecs_grecs__flex_debug) fprintf(stderr, "Resuming file `%s' at line %lu\n", - LOCUS.file, (unsigned long) LOCUS.line); + POINT.file, (unsigned long) POINT.line); pp_line_stmt(); diff --git a/src/tree.c b/src/tree.c index 58b34a5..6fdbb85 100644 --- a/src/tree.c +++ b/src/tree.c @@ -62,6 +62,18 @@ grecs_node_create(enum grecs_node_type type, grecs_locus_t *loc) return np; } +struct grecs_node * +grecs_node_create_points(enum grecs_node_type type, + struct grecs_locus_point beg, + struct grecs_locus_point end) +{ + grecs_locus_t loc; + + loc.beg = beg; + loc.end = end; + return grecs_node_create(type, &loc); +} + void grecs_node_bind(struct grecs_node *master, struct grecs_node *node, int dn) { @@ -281,7 +293,7 @@ target_ptr(struct grecs_keyword *kwp, char *base) } static int -string_to_bool(const char *string, int *pval, grecs_locus_t *locus) +string_to_bool(const char *string, int *pval, grecs_locus_t const *locus) { if (strcmp(string, "yes") == 0 || strcmp(string, "true") == 0 @@ -303,7 +315,8 @@ string_to_bool(const char *string, int *pval, grecs_locus_t *locus) } static int -string_to_host(struct in_addr *in, const char *string, grecs_locus_t *locus) +string_to_host(struct in_addr *in, const char *string, + grecs_locus_t const *locus) { if (inet_aton(string, in) == 0) { struct hostent *hp; @@ -318,7 +331,7 @@ string_to_host(struct in_addr *in, const char *string, grecs_locus_t *locus) static int string_to_sockaddr(struct grecs_sockaddr *sp, const char *string, - grecs_locus_t *locus) + grecs_locus_t const *locus) { if (string[0] == '/') { struct sockaddr_un s_un; @@ -434,7 +447,7 @@ string_to_sockaddr(struct grecs_sockaddr *sp, const char *string, break; \ if (x <= sum) \ { \ - grecs_error(loc, 0, _("numeric overflow")); \ + grecs_error(loc, 0, _("numeric overflow")); \ return 1; \ } \ else if (limit && x > limit) \ @@ -513,7 +526,7 @@ string_to_sockaddr(struct grecs_sockaddr *sp, const char *string, int grecs_string_convert(void *target, enum grecs_data_type type, - const char *string, grecs_locus_t *locus) + const char *string, grecs_locus_t const *locus) { switch (type) { case grecs_type_void: @@ -568,7 +581,7 @@ grecs_string_convert(void *target, enum grecs_data_type type, grecs_error(locus, 0, _("%s: not a valid IP address"), string); return 1; - } + } break; case grecs_type_host: @@ -707,7 +720,7 @@ grecs_process_ident(struct grecs_keyword *kwp, grecs_value_t *value, const grecs_value_t *vp = ep->data; if (vp->type != GRECS_TYPE_STRING) - grecs_error(locus, 0, + grecs_error(&vp->locus, 0, _("%s: incompatible data type in list item #%d"), kwp->ident, num); else if (type == grecs_type_string) @@ -716,9 +729,10 @@ grecs_process_ident(struct grecs_keyword *kwp, grecs_value_t *value, else { void *ptr = grecs_malloc(size); if (grecs_string_convert(ptr, - type, - vp->v.string, - locus) == 0) + type, + vp->v.string, + &vp->locus) + == 0) grecs_list_append(list, ptr); else grecs_free(ptr); @@ -753,7 +767,8 @@ grecs_process_ident(struct grecs_keyword *kwp, grecs_value_t *value, else { ptr = grecs_malloc(size); if (grecs_string_convert(ptr, type, - value->v.string, locus)) { + value->v.string, + &value->locus)) { grecs_free(ptr); grecs_list_free(list); return; @@ -763,8 +778,8 @@ grecs_process_ident(struct grecs_keyword *kwp, grecs_value_t *value, *(struct grecs_list**)target = list; } else grecs_string_convert(target, GRECS_TYPE(kwp->type), - value->v.string, - locus); + value->v.string, + &value->locus); } @@ -835,11 +850,11 @@ nodeproc(enum grecs_tree_recurse_op op, struct grecs_node *node, void *data) case grecs_tree_recurse_set: kwp = find_keyword(clos->cursect, node->ident); if (!kwp) { - grecs_error(&node->locus, 0, _("Unknown keyword")); + grecs_error(&node->idloc, 0, _("Unknown keyword")); return grecs_tree_recurse_skip; } grecs_process_ident(kwp, node->v.value, CURRENT_BASE(clos), - &node->locus); + &node->idloc); break; case grecs_tree_recurse_pre: -- cgit v1.2.1