Index: ossp-pkg/l2/l2_spec.c RCS File: /v/ossp/cvs/ossp-pkg/l2/l2_spec.c,v rcsdiff -q -kk '-r1.4' '-r1.5' -u '/v/ossp/cvs/ossp-pkg/l2/l2_spec.c,v' 2>/dev/null --- l2_spec.c 2001/11/30 09:44:47 1.4 +++ l2_spec.c 2001/12/14 12:42:07 1.5 @@ -95,3 +95,61 @@ return ctx.rv; } +/* remember a specification parsing error (used internally) */ +void l2_spec_error(l2_spec_ctx_t *ctx, l2_result_t rv, YYLTYPE *loc, const char *fmt, ...) +{ + const char *cpF, *cpL; + const char *cpP, *cpE; + int line, column; + char *cpBuf; + char *cp; + int n; + + /* determine first and last positions of token */ + cpF = ctx->inputbuf+loc->first; + cpL = ctx->inputbuf+loc->last; + + /* determine epilog and prolog of token */ + cpP = cpF-4; + if (cpP < ctx->inputbuf) + cpP = ctx->inputbuf; + cpE = cpL+4; + if (cpE > ctx->inputbuf+ctx->inputlen) + cpE = ctx->inputbuf+ctx->inputlen; + + /* calculate line and column of token */ + line = 1; + column = 1; + for (cp = ctx->inputbuf; cp < (ctx->inputbuf+ctx->inputlen) && cp != cpF; cp++) { + column++; + if (*cp == '\n') { + column = 1; + line++; + } + } + + /* extract token context with mark token borders */ + if ((cpBuf = malloc((cpE-cpP)+2+1)) == NULL) + return; + cp = cpBuf; + n = cpF-cpP; + memcpy(cp, cpP, n); cp += n; + *cp++ = '<'; + n = cpL-cpF; + memcpy(cp, cpF, n); cp += n; + *cp++ = '>'; + n = cpE-cpL; + memcpy(cp, cpL, n); cp += n; + *cp++ = '\0'; + + /* remember error */ + l2_env_errorinfo(ctx->env, rv, "line %d, column %d: `%s'; %s", + line, column, cpBuf, fmt); + ctx->rv = rv; + + /* cleanup */ + free(cpBuf); + + return; +} + Index: ossp-pkg/l2/l2_spec.h RCS File: /v/ossp/cvs/ossp-pkg/l2/l2_spec.h,v rcsdiff -q -kk '-r1.2' '-r1.3' -u '/v/ossp/cvs/ossp-pkg/l2/l2_spec.h,v' 2>/dev/null --- l2_spec.h 2001/11/07 16:30:51 1.2 +++ l2_spec.h 2001/12/14 12:42:07 1.3 @@ -3,6 +3,7 @@ #include "l2.h" +/* internal specification scanner/parser context */ typedef struct { const char *inputptr; /* input buffer: current reading pointer */ const char *inputbuf; /* input buffer: begin of buffer */ @@ -14,4 +15,20 @@ void *yyscan; /* Flex scanner context */ } l2_spec_ctx_t; +/* internal scanner/parser token location */ +typedef struct { + int first; + int last; +} l2_spec_loc_t; +#define YYLTYPE l2_spec_loc_t + +/* support for automatic location tracking by Bison */ +#define first_line first +#define first_column first +#define last_line last +#define last_column last + +/* error reporting function */ +extern void l2_spec_error(l2_spec_ctx_t *ctx, l2_result_t rv, YYLTYPE *loc, const char *fmt, ...); + #endif /* __L2_SPEC_H__ */ Index: ossp-pkg/l2/l2_spec_parse.y RCS File: /v/ossp/cvs/ossp-pkg/l2/l2_spec_parse.y,v rcsdiff -q -kk '-r1.4' '-r1.5' -u '/v/ossp/cvs/ossp-pkg/l2/l2_spec_parse.y,v' 2>/dev/null --- l2_spec_parse.y 2001/11/08 21:58:00 1.4 +++ l2_spec_parse.y 2001/12/14 12:42:07 1.5 @@ -48,8 +48,7 @@ /* generate verbose error messages and remember them inside the context */ #undef yyerror #define yyerror(msg) \ - do { l2_env_errorinfo(CTX->env, L2_ERR_ARG, "%s", msg); \ - CTX->rv = L2_ERR_ARG; } while (0) + l2_spec_error(CTX, L2_ERR_SYN, &yylloc, msg) #define YYERROR_VERBOSE /* scanner state transition */ @@ -107,14 +106,14 @@ | channel T_OP_ARROW stream { $$ = $1; if ((CTX->rv = l2_channel_link($1, L2_LINK_CHILD, $3, NULL)) != L2_OK) { - l2_env_errorinfo(CTX->env, CTX->rv, "unable to link parent with child"); + l2_spec_error(CTX, CTX->rv, &yylloc, "unable to link parent with child"); YYERROR; } } | channel T_OP_ARROW '{' streams '}' { $$ = $1; if ((CTX->rv = l2_channel_link($1, L2_LINK_CHILD, $4, NULL)) != L2_OK) { - l2_env_errorinfo(CTX->env, CTX->rv, "unable to link parent with child list"); + l2_spec_error(CTX, CTX->rv, &yylloc, "unable to link parent with child list"); YYERROR; } } @@ -128,7 +127,7 @@ | stream ';' streams { $$ = $1; if ((CTX->rv = l2_channel_link($1, L2_LINK_SIBLING, $3, NULL)) != L2_OK) { - l2_env_errorinfo(CTX->env, CTX->rv, "unable to link childs together"); + l2_spec_error(CTX, CTX->rv, &yylloc, "unable to link childs together"); YYERROR; } } @@ -139,14 +138,14 @@ : channel_level '/' channel_level ':' channel_cons { $$ = $5; if ((CTX->rv = l2_channel_levels($5, $1, $3)) != L2_OK) { - l2_env_errorinfo(CTX->env, CTX->rv, "failed to set channel write and flush levels"); + l2_spec_error(CTX, CTX->rv, &yylloc, "failed to set channel write and flush levels"); YYERROR; } } | channel_level ':' channel_cons { $$ = $3; if ((CTX->rv = l2_channel_levels($3, $1, L2_LEVEL_NONE)) != L2_OK) { - l2_env_errorinfo(CTX->env, CTX->rv, "failed to set channel write levels"); + l2_spec_error(CTX, CTX->rv, &yylloc, "failed to set channel write levels"); YYERROR; } } @@ -160,7 +159,7 @@ : T_ID { unsigned int levelmask; if ((CTX->rv = l2_util_s2l($1, strlen($1), ',', &levelmask)) != L2_OK) { - l2_env_errorinfo(CTX->env, CTX->rv, "invalid level '%s'", $1); + l2_spec_error(CTX, CTX->rv, &yylloc, "invalid level '%s'", $1); YYERROR; } $$ = L2_LEVEL_UPTO(levelmask); @@ -175,7 +174,7 @@ : T_ID { unsigned int levelmask; if ((CTX->rv = l2_util_s2l($1, strlen($1), ',', &levelmask)) != L2_OK) { - l2_env_errorinfo(CTX->env, CTX->rv, "invalid level '%s'", $1); + l2_spec_error(CTX, CTX->rv, &yylloc, "invalid level '%s'", $1); YYERROR; } $$ = levelmask; @@ -183,7 +182,7 @@ | T_ID '|' channel_level_mask { unsigned int levelmask; if ((CTX->rv = l2_util_s2l($1, strlen($1), ',', &levelmask)) != L2_OK) { - l2_env_errorinfo(CTX->env, CTX->rv, "invalid level '%s'", $1); + l2_spec_error(CTX, CTX->rv, &yylloc, "invalid level '%s'", $1); YYERROR; } $$ = levelmask | $3; @@ -195,7 +194,7 @@ : T_ID { l2_channel_t *ch; if ((CTX->rv = l2_channel_create(&ch, CTX->env, $1)) != L2_OK) { - l2_env_errorinfo(CTX->env, CTX->rv, "failed to create channel '%s'", $1); + l2_spec_error(CTX, CTX->rv, &yylloc, "failed to create channel '%s'", $1); YYERROR; } $$ = ch; @@ -214,13 +213,13 @@ /* channel parameters */ channel_params : /* empty */ + | '(' ')' | '(' channel_param_list ')' ; /* channel parameter list */ channel_param_list - : /* empty */ - | channel_param + : channel_param | channel_param ',' channel_param_list ; @@ -228,7 +227,7 @@ channel_param : T_ID '=' { l2_spec_scan_push(CTX, "SS_PARAM"); } T_PARAM { l2_spec_scan_pop(CTX); } { if ((CTX->rv = l2_channel_configure(CTX->chTmp, "%s=\"%s\"", $1, $4)) != L2_OK) { - l2_env_errorinfo(CTX->env, CTX->rv, "failed to configure channel with '%s=\"%s\"'", $1, $4); + l2_spec_error(CTX, CTX->rv, &yylloc, "failed to configure channel with '%s=\"%s\"'", $1, $4); YYERROR; } } Index: ossp-pkg/l2/l2_spec_scan.l RCS File: /v/ossp/cvs/ossp-pkg/l2/l2_spec_scan.l,v rcsdiff -q -kk '-r1.5' '-r1.6' -u '/v/ossp/cvs/ossp-pkg/l2/l2_spec_scan.l,v' 2>/dev/null --- l2_spec_scan.l 2001/11/08 21:58:00 1.5 +++ l2_spec_scan.l 2001/12/14 12:42:07 1.6 @@ -42,6 +42,16 @@ #undef YY_INPUT #define YY_INPUT(buf,result,max_size) (result = yyinput(CTX, buf, max_size)) static int yyinput(l2_spec_ctx_t *ctx, char *buf, int max_size); + +/* location tracking */ +#define YY_USER_INIT \ + yylloc->first = 0; \ + yylloc->last = 0; +#define YY_USER_ACTION \ + yylloc->first = yylloc->last; \ + yylloc->last += yyleng; +#define YY_USER_ACTION_ROLLBACK \ + yylloc->last = yylloc->first %} /* scanner options */ @@ -86,22 +96,21 @@ yylval->cpValue = strdup(caParam); cpParam = NULL; yyless(0); + YY_USER_ACTION_ROLLBACK; return T_PARAM; } \" { BEGIN(SS_PARAM); } \n { - l2_env_errorinfo(CTX->env, L2_ERR_ARG, "%s", "Unterminated string"); - CTX->rv = L2_ERR_ARG; + l2_spec_error(CTX, L2_ERR_SYN, yylloc, "Unterminated string"); return 0; } \\[0-7]{1,3} { unsigned int result; (void)sscanf(yytext+1, "%o", &result); if (result > 0xff) { - l2_env_errorinfo(CTX->env, L2_ERR_ARG, "%s", "Escape sequence out of bound"); - CTX->rv = L2_ERR_ARG; + l2_spec_error(CTX, L2_ERR_SYN, yylloc, "Escape sequence out of bound"); return 0; } else @@ -111,8 +120,7 @@ unsigned int result; (void)sscanf(yytext+1, "%x", &result); if (result > 0xff) { - l2_env_errorinfo(CTX->env, L2_ERR_ARG, "%s", "Escape sequence out of bound"); - CTX->rv = L2_ERR_ARG; + l2_spec_error(CTX, L2_ERR_SYN, yylloc, "Escape sequence out of bound"); return 0; } else