OSSP CVS Repository

ossp - Check-in [1427]
Not logged in
[Honeypot]  [Browse]  [Home]  [Login]  [Reports
[Search]  [Ticket]  [Timeline
  [Patchset]  [Tagging/Branching

Check-in Number: 1427
Date: 2001-Dec-14 13:42:07 (local)
2001-Dec-14 12:42:07 (UTC)
User:rse
Branch:
Comment: Whoohooo! Add support for location tracking. This way the reported errors contain line, column, context and found/expected information. Now the specification parser is full featured...
Tickets:
Inspections:
Files:
ossp-pkg/l2/l2_spec.c      1.4 -> 1.5     58 inserted, 0 deleted
ossp-pkg/l2/l2_spec.h      1.2 -> 1.3     17 inserted, 0 deleted
ossp-pkg/l2/l2_spec_parse.y      1.4 -> 1.5     13 inserted, 14 deleted
ossp-pkg/l2/l2_spec_scan.l      1.5 -> 1.6     14 inserted, 6 deleted

ossp-pkg/l2/l2_spec.c 1.4 -> 1.5

--- 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;
+}
+


ossp-pkg/l2/l2_spec.h 1.2 -> 1.3

--- 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__ */


ossp-pkg/l2/l2_spec_parse.y 1.4 -> 1.5

--- 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;
           }
       }


ossp-pkg/l2/l2_spec_scan.l 1.5 -> 1.6

--- 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;
 }
 <SS_PARAM_Q>\" {
     BEGIN(SS_PARAM);
 }
 <SS_PARAM_Q>\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;
 }   
 <SS_PARAM_Q>\\[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

CVSTrac 2.0.1