]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
ap_expr: open string expressions to the <word>.
authorYann Ylavic <ylavic@apache.org>
Mon, 2 Oct 2017 21:57:26 +0000 (21:57 +0000)
committerYann Ylavic <ylavic@apache.org>
Mon, 2 Oct 2017 21:57:26 +0000 (21:57 +0000)
Introduces the syntax "%{:<word>:}", borrowed from the <var>'s one, and which
likewise can be embedded anywhere in a string expression (the same reserved
character ':' gets reused in an unambiguous manner).

This allows the two types of expressions (boolean and string) to now share
fully the same language set, namely: strings, lists, vars, regexes, backrefs,
functions with multiple or complex arguments, and especially combinations
thereof.

Most of them were reserved to boolean expressions only, while complex string
constructions can also benefit to, well, strings. The <word> construct allows
that (say the syntax "%{:<word>:}" looks like a temporary variable constructed
in a string).

Since string expressions may now have to deal with lists (arrays), they also
need a way to produce/extract strings from list and vice versa. This can be
done with the new "join" and "split" operators, while the new substitution
regexes (like "s/<pattern>/<substitute>/<flags>") may be used to manipulate
strings in place. All this of course available for both string and boolean
expressions.

Tests and doc updates upcoming..

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1810605 13f79535-47bb-0310-9956-ffa450edef68

include/ap_regex.h
server/util_expr_eval.c
server/util_expr_parse.c
server/util_expr_parse.h
server/util_expr_parse.y
server/util_expr_private.h
server/util_expr_scan.c
server/util_expr_scan.l
server/util_pcre.c

index dbe9b2469045d1d9d439aaf78227ad0959d87733..8f891fae98694c7f0e940a16f9b3e8fa8c241349 100644 (file)
@@ -76,6 +76,9 @@ extern "C" {
 #define AP_REG_MULTI    0x10 /**< perl's /g (needs fixing) */
 #define AP_REG_NOMEM    0x20 /**< nomem in our code */
 #define AP_REG_DOTALL   0x40 /**< perl's /s flag */
+#define AP_REG_NOTEMPTY 0x080 /**< Empty match not valid */
+#define AP_REG_ANCHORED 0x100 /**< Match at the first position */
 
 #define AP_REG_MATCH "MATCH_" /**< suggested prefix for ap_regname */
 
index 697bc4dcc0ff39923d2942dfa95963e655b6cad0..8500fa26d9eda8c8fdfc58306f4a20627df8bc99 100644 (file)
@@ -27,6 +27,7 @@
 #include "util_varbuf.h"
 #include "util_expr_private.h"
 #include "util_md5.h"
+#include "util_varbuf.h"
 
 #include "apr_lib.h"
 #include "apr_fnmatch.h"
@@ -54,6 +55,8 @@ AP_IMPLEMENT_HOOK_RUN_FIRST(int, expr_lookup, (ap_expr_lookup_parms *parms),
 
 #define  LOG_MARK(info)  __FILE__, __LINE__, (info)->module_index
 
+static int ap_expr_eval_cond(ap_expr_eval_ctx_t *ctx, const ap_expr_t *node);
+
 static const char *ap_expr_eval_string_func(ap_expr_eval_ctx_t *ctx,
                                             const ap_expr_t *info,
                                             const ap_expr_t *args);
@@ -63,6 +66,19 @@ static const char *ap_expr_eval_var(ap_expr_eval_ctx_t *ctx,
                                     ap_expr_var_func_t *func,
                                     const void *data);
 
+typedef struct {
+    int type, flags;
+    const ap_expr_t *subst;
+} ap_expr_regctx_t;
+
+static const char *ap_expr_regexec(const char *subject,
+                                   const ap_expr_t *reg,
+                                   apr_array_header_t *list,
+                                   ap_expr_eval_ctx_t *ctx);
+
+static apr_array_header_t *ap_expr_list_make(ap_expr_eval_ctx_t *ctx,
+                                             const ap_expr_t *node);
+
 /* define AP_EXPR_DEBUG to log the parse tree when parsing an expression */
 #ifdef AP_EXPR_DEBUG
 static void expr_dump_tree(const ap_expr_t *e, const server_rec *s,
@@ -71,7 +87,7 @@ static void expr_dump_tree(const ap_expr_t *e, const server_rec *s,
 
 /*
  * To reduce counting overhead, we only count calls to
- * ap_expr_eval_word() and ap_expr_eval(). The max number of
+ * ap_expr_eval_word() and ap_expr_eval_cond(). The max number of
  * stack frames is larger by some factor.
  */
 #define AP_EXPR_MAX_RECURSION   20
@@ -87,6 +103,37 @@ static int inc_rec(ap_expr_eval_ctx_t *ctx)
     return 1;
 }
 
+static const char *ap_expr_list_pstrcat(apr_pool_t *p,
+                                        const apr_array_header_t *list,
+                                        const char *sep)
+{
+    if (list->nelts <= 0) {
+        return NULL;
+    }
+    else if (list->nelts == 1) {
+        return APR_ARRAY_IDX(list, 0, const char*);
+    }
+    else {
+        struct ap_varbuf vb;
+        int n = list->nelts - 1, i;
+        apr_size_t slen = strlen(sep), vlen;
+        const char *val;
+
+        ap_varbuf_init(p, &vb, 0);
+        for (i = 0; i < n; ++i) {
+            val = APR_ARRAY_IDX(list, i, const char*);
+            vlen = strlen(val);
+            ap_varbuf_grow(&vb, vlen + slen + 1);
+            ap_varbuf_strmemcat(&vb, val, vlen);
+            ap_varbuf_strmemcat(&vb, sep, slen);
+        }
+        val = APR_ARRAY_IDX(list, n, const char*);
+        ap_varbuf_strmemcat(&vb, val, strlen(val));
+
+        return vb.buf;
+    }
+}
+
 static const char *ap_expr_eval_word(ap_expr_eval_ctx_t *ctx,
                                      const ap_expr_t *node)
 {
@@ -98,6 +145,12 @@ static const char *ap_expr_eval_word(ap_expr_eval_ctx_t *ctx,
     case op_String:
         result = node->node_arg1;
         break;
+    case op_Word:
+        result = ap_expr_eval_word(ctx, node->node_arg1);
+        break;
+    case op_Bool:
+        result = ap_expr_eval_cond(ctx, node->node_arg1) ? "true" : "false";
+        break;
     case op_Var:
         result = ap_expr_eval_var(ctx, (ap_expr_var_func_t *)node->node_arg1,
                                   node->node_arg2);
@@ -168,7 +221,20 @@ static const char *ap_expr_eval_word(ap_expr_eval_ctx_t *ctx,
         result = ap_expr_eval_string_func(ctx, info, args);
         break;
     }
-    case op_RegexBackref: {
+    case op_Join: {
+        const char *sep;
+        apr_array_header_t *list = ap_expr_list_make(ctx, node->node_arg1);
+        sep = node->node_arg2 ? ap_expr_eval_word(ctx, node->node_arg2) : "";
+        result = ap_expr_list_pstrcat(ctx->p, list, sep);
+        break;
+    }
+    case op_Regsub: {
+        const ap_expr_t *reg = node->node_arg2;
+        const char *subject = ap_expr_eval_word(ctx, node->node_arg1);
+        result = ap_expr_regexec(subject, reg, NULL, ctx);
+        break;
+    }
+    case op_Regref: {
         const unsigned int *np = node->node_arg1;
         result = ap_expr_eval_re_backref(ctx, *np);
         break;
@@ -219,15 +285,7 @@ static const char *ap_expr_eval_string_func(ap_expr_eval_ctx_t *ctx,
     if (arg->node_op == op_ListElement) {
         /* Evaluate the list elements and store them in apr_array_header. */
         ap_expr_string_list_func_t *func = (ap_expr_string_list_func_t *)info->node_arg1;
-        apr_array_header_t *args = apr_array_make(ctx->p, 2, sizeof(char *));
-        do {
-            const ap_expr_t *val = arg->node_arg1;
-            const char **new = apr_array_push(args);
-            *new = ap_expr_eval_word(ctx, val);
-
-            arg = arg->node_arg2;
-        } while (arg != NULL);
-
+        apr_array_header_t *args = ap_expr_list_make(ctx, arg->node_arg1);
         return (*func)(ctx, data, args);
     }
     else {
@@ -249,6 +307,170 @@ static int intstrcmp(const char *s1, const char *s2)
         return 1;
 }
 
+static const char *ap_expr_regexec(const char *subject,
+                                   const ap_expr_t *reg,
+                                   apr_array_header_t *list,
+                                   ap_expr_eval_ctx_t *ctx)
+{
+    struct ap_varbuf vb;
+    const char *val = subject;
+    const ap_regex_t *regex = reg->node_arg1;
+    const ap_expr_regctx_t *regctx = reg->node_arg2;
+    ap_regmatch_t *pmatch = NULL, match0;
+    apr_size_t nmatch = 0;
+    const char *str = "";
+    apr_size_t len = 0;
+    int empty = 0, rv;
+
+    ap_varbuf_init(ctx->p, &vb, 0);
+    if (ctx->re_nmatch > 0) {
+        nmatch = ctx->re_nmatch;
+        pmatch = ctx->re_pmatch;
+    }
+    else if (regctx->type != 'm') {
+        nmatch = 1;
+        pmatch = &match0;
+    }
+    do {
+        /* If previous match was empty, we can't issue the exact same one or
+         * we'd loop indefinitively.  So let's instead ask for an anchored and
+         * non-empty match (i.e. something not empty at the start of the value)
+         * and if nothing is found advance by one character below.
+         */
+        rv = ap_regexec(regex, val, nmatch, pmatch, 
+                        empty ? AP_REG_ANCHORED | AP_REG_NOTEMPTY : 0);
+        if (regctx->type == 'm') {
+            /* Simple match "m//", just return whether it matched (subject)
+             * or not (NULL) 
+             */
+            return (rv == 0) ? subject : NULL;
+        }
+        if (rv == 0) {
+            /* Substitution "s//" or split "S//" matched.
+             * s// => replace $0 with evaluated regctx->subst
+             * S// => split at $0 (keeping evaluated regctx->subst if any)
+             */
+            int pos = pmatch[0].rm_so,
+                end = pmatch[0].rm_eo;
+            AP_DEBUG_ASSERT(pos >= 0 && pos <= end);
+
+            if (regctx->subst) {
+                *ctx->re_source = val;
+                str = ap_expr_eval_word(ctx, regctx->subst);
+                len = strlen(str);
+            }
+            /* Splitting makes sense into a given list only, if NULL we fall
+             * back into returning a s// string...
+             */
+            if (list) {
+                char *tmp = apr_palloc(ctx->p, pos + len + 1);
+                memcpy(tmp, val, pos);
+                memcpy(tmp + pos, str, len);
+                tmp[pos + len] = '\0';
+                APR_ARRAY_PUSH(list, const char*) = tmp;
+            }
+            else { /* regctx->type == 's' */
+                ap_varbuf_grow(&vb, pos + len + 1);
+                ap_varbuf_strmemcat(&vb, val, pos);
+                ap_varbuf_strmemcat(&vb, str, len);
+                if (!(regctx->flags & AP_REG_MULTI)) {
+                    /* Single substitution, preserve remaining data */
+                    ap_varbuf_strmemcat(&vb, val + end, strlen(val) - end);
+                    break;
+                }
+            }
+            /* Note an empty match */
+            empty = (end == 0);
+            val += end;
+        }
+        else if (empty) {
+            /* Skip this non-matching character (or CRLF) and restart
+             * another "normal" match (possibly empty) from there.
+             */
+            if (val[0] == APR_ASCII_CR && val[1] == APR_ASCII_LF) {
+                val += 2;
+            }
+            else {
+                val++;
+            }
+            empty = 0;
+        }
+        else {
+            if (list) {
+                APR_ARRAY_PUSH(list, const char*) = val;
+            }
+            else if (vb.avail) {
+                ap_varbuf_strmemcat(&vb, val, strlen(val));
+            }
+            else {
+                return val;
+            }
+            break;
+        }
+    } while (*val);
+
+    return vb.buf;
+}
+
+static apr_array_header_t *ap_expr_list_make(ap_expr_eval_ctx_t *ctx,
+                                             const ap_expr_t *node)
+{
+    apr_array_header_t *list = NULL;
+
+    if (node->node_op == op_ListRegex) {
+        const ap_expr_t *arg = node->node_arg1;
+        const ap_expr_t *reg = node->node_arg2;
+        const ap_expr_regctx_t *regctx = reg->node_arg2;
+        const apr_array_header_t *source = ap_expr_list_make(ctx, arg);
+        int i;
+
+        list = apr_array_make(ctx->p, source->nelts, sizeof(const char*));
+        for (i = 0; i < source->nelts; ++i) {
+            const char *val = APR_ARRAY_IDX(source, i, const char*);
+            if (regctx->type == 'S') {
+                (void)ap_expr_regexec(val, reg, list, ctx);
+            }
+            else {
+                val = ap_expr_regexec(val, reg, NULL, ctx);
+                if (val) {
+                    APR_ARRAY_PUSH(list, const char*) = val;
+                }
+            }
+        }
+    }
+    else if (node->node_op == op_ListElement) {
+        int n = 0;
+        const ap_expr_t *elem;
+        for (elem = node; elem; elem = elem->node_arg2) {
+            AP_DEBUG_ASSERT(elem->node_op == op_ListElement);
+            n++;
+        }
+
+        list = apr_array_make(ctx->p, n, sizeof(const char*));
+        for (elem = node; elem; elem = elem->node_arg2) {
+            APR_ARRAY_PUSH(list, const char*) =
+                ap_expr_eval_word(ctx, elem->node_arg1);
+        }
+    }
+    else if (node->node_op == op_ListFuncCall) {
+        const ap_expr_t *info = node->node_arg1;
+        ap_expr_list_func_t *func = info->node_arg1;
+
+        AP_DEBUG_ASSERT(func != NULL);
+        AP_DEBUG_ASSERT(info->node_op == op_ListFuncInfo);
+        list = (*func)(ctx, info->node_arg2,
+                       ap_expr_eval_word(ctx, node->node_arg2));
+    }
+    else {
+        const char *subject = ap_expr_eval_word(ctx, node);
+
+        list = apr_array_make(ctx->p, 8, sizeof(const char*));
+        (void)ap_expr_regexec(subject, node->node_arg2, list, ctx);
+    }
+
+    return list;
+}
+
 static int ap_expr_eval_comp(ap_expr_eval_ctx_t *ctx, const ap_expr_t *node)
 {
     const ap_expr_t *e1 = node->node_arg1;
@@ -279,30 +501,17 @@ static int ap_expr_eval_comp(ap_expr_eval_ctx_t *ctx, const ap_expr_t *node)
     case op_STR_GE:
         return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >= 0);
     case op_IN: {
-            const char *needle = ap_expr_eval_word(ctx, e1);
-            if (e2->node_op == op_ListElement) {
-                do {
-                    const ap_expr_t *val = e2->node_arg1;
-                    AP_DEBUG_ASSERT(e2->node_op == op_ListElement);
-                    if (strcmp(needle, ap_expr_eval_word(ctx, val)) == 0)
+            int n;
+            const char *needle, *subject;
+            apr_array_header_t *haystack;
+            haystack = ap_expr_list_make(ctx, e2);
+            if (haystack) {
+                needle = ap_expr_eval_word(ctx, e1);
+                for (n = 0; n < haystack->nelts; ++n) {
+                    subject = APR_ARRAY_IDX(haystack, n, const char*);
+                    if (strcmp(needle, subject) == 0) {
                         return 1;
-                    e2 = e2->node_arg2;
-                } while (e2 != NULL);
-            }
-            else if (e2->node_op == op_ListFuncCall) {
-                const ap_expr_t *info = e2->node_arg1;
-                const ap_expr_t *arg = e2->node_arg2;
-                ap_expr_list_func_t *func = (ap_expr_list_func_t *)info->node_arg1;
-                apr_array_header_t *haystack;
-
-                AP_DEBUG_ASSERT(func != NULL);
-                AP_DEBUG_ASSERT(info->node_op == op_ListFuncInfo);
-                haystack = (*func)(ctx, info->node_arg2, ap_expr_eval_word(ctx, arg));
-                if (haystack == NULL) {
-                    return 0;
-                }
-                if (ap_array_str_contains(haystack, needle)) {
-                    return 1;
+                    }
                 }
             }
             return 0;
@@ -326,10 +535,7 @@ static int ap_expr_eval_comp(ap_expr_eval_ctx_t *ctx, const ap_expr_t *node)
                 result = (0 == ap_regexec(regex, word, 0, NULL, 0));
             }
 
-            if (node->node_op == op_REG)
-                return result;
-            else
-                return !result;
+            return result ^ (node->node_op == op_NRE);
         }
     default:
         *ctx->err = "Internal evaluation error: Unknown comp expression node";
@@ -401,18 +607,13 @@ AP_DECLARE(const char *) ap_expr_parse(apr_pool_t *pool, apr_pool_t *ptemp,
     ap_expr_parse_ctx_t ctx;
     int rc;
 
+    memset(&ctx, 0, sizeof ctx);
     ctx.pool     = pool;
     ctx.ptemp    = ptemp;
     ctx.inputbuf = expr;
     ctx.inputlen = strlen(expr);
     ctx.inputptr = ctx.inputbuf;
-    ctx.expr     = NULL;
-    ctx.error    = NULL;        /* generic bison error message (XXX: usually not very useful, should be axed) */
-    ctx.error2   = NULL;        /* additional error message */
     ctx.flags    = info->flags;
-    ctx.scan_del    = '\0';
-    ctx.scan_buf[0] = '\0';
-    ctx.scan_ptr    = ctx.scan_buf;
     ctx.lookup_fn   = lookup_fn ? lookup_fn : ap_expr_lookup_default;
     ctx.at_start    = 1;
 
@@ -420,6 +621,11 @@ AP_DECLARE(const char *) ap_expr_parse(apr_pool_t *pool, apr_pool_t *ptemp,
     ap_expr_yyset_extra(&ctx, ctx.scanner);
     rc = ap_expr_yyparse(&ctx);
     ap_expr_yylex_destroy(ctx.scanner);
+
+    /* ctx.error: the generic bison error message
+     *            (XXX: usually not very useful, should be axed)
+     * ctx.error2: an additional error message
+     */
     if (ctx.error) {
         if (ctx.error2)
             return apr_psprintf(pool, "%s: %s", ctx.error, ctx.error2);
@@ -464,7 +670,7 @@ AP_DECLARE(ap_expr_info_t*) ap_expr_parse_cmd_mi(const cmd_parms *cmd,
 }
 
 ap_expr_t *ap_expr_make(ap_expr_node_op_e op, const void *a1, const void *a2,
-                      ap_expr_parse_ctx_t *ctx)
+                        ap_expr_parse_ctx_t *ctx)
 {
     ap_expr_t *node = apr_palloc(ctx->pool, sizeof(ap_expr_t));
     node->node_op   = op;
@@ -473,6 +679,100 @@ ap_expr_t *ap_expr_make(ap_expr_node_op_e op, const void *a1, const void *a2,
     return node;
 }
 
+ap_expr_t *ap_expr_concat_make(const void *a1, const void *a2,
+                               ap_expr_parse_ctx_t *ctx)
+{
+    const ap_expr_t *node;
+
+    /* Optimize out empty string(s) concatenation */
+    if ((node = a1)
+            && node->node_op == op_String
+            && !*(const char *)node->node_arg1) {
+        return (ap_expr_t *)a2;
+    }
+    if ((node = a2)
+            && node->node_op == op_String
+            && !*(const char *)node->node_arg1) {
+        return (ap_expr_t *)a1;
+    }
+
+    return ap_expr_make(op_Concat, a1, a2, ctx);
+}
+
+ap_expr_t *ap_expr_str_word_make(const ap_expr_t *arg,
+                                 ap_expr_parse_ctx_t *ctx)
+{
+    ap_expr_t *node = apr_palloc(ctx->pool, sizeof(ap_expr_t));
+    node->node_op   = op_Word;
+    node->node_arg1 = arg;
+    node->node_arg2 = NULL;
+    return node;
+}
+
+ap_expr_t *ap_expr_str_bool_make(const ap_expr_t *arg,
+                                 ap_expr_parse_ctx_t *ctx)
+{
+    ap_expr_t *node = apr_palloc(ctx->pool, sizeof(ap_expr_t));
+    node->node_op   = op_Bool;
+    node->node_arg1 = arg;
+    node->node_arg2 = NULL;
+    return node;
+}
+
+ap_expr_t *ap_expr_regex_make(const char *pattern, const char *flags,
+                              const ap_expr_t *subst, int split,
+                              ap_expr_parse_ctx_t *ctx)
+{
+    ap_expr_t *node = NULL;
+    ap_expr_regctx_t *regctx;
+    ap_regex_t *regex;
+
+    regctx = apr_palloc(ctx->pool, sizeof *regctx);
+    regctx->subst = subst;
+    regctx->flags = 0;
+    if (flags) {
+        for (; *flags; ++flags) {
+            switch (*flags) {
+            case 'i':
+                regctx->flags |= AP_REG_ICASE;
+                break;
+            case 'm':
+                regctx->flags |= AP_REG_NEWLINE;
+                break;
+            case 's':
+                regctx->flags |= AP_REG_DOTALL;
+                break;
+            case 'g':
+                regctx->flags |= AP_REG_MULTI;
+                break;
+            }
+        }
+    }
+    if (subst) {
+        if (split) {
+            regctx->type = 'S';
+            regctx->flags |= AP_REG_MULTI;
+        }
+        else {
+            regctx->type = 's';
+        }
+    }
+    else {
+        regctx->type = 'm';
+    }
+
+    regex = ap_pregcomp(ctx->pool, pattern, regctx->flags);
+    if (!regex) {
+        return NULL;
+    }
+
+    node = apr_palloc(ctx->pool, sizeof(ap_expr_t));
+    node->node_op   = op_Regex;
+    node->node_arg1 = regex;
+    node->node_arg2 = regctx;
+    return node;
+}
+
 static ap_expr_t *ap_expr_info_make(int type, const char *name,
                                   ap_expr_parse_ctx_t *ctx,
                                   const ap_expr_t *arg)
@@ -533,6 +833,16 @@ ap_expr_t *ap_expr_list_func_make(const char *name, const ap_expr_t *arg,
     return ap_expr_make(op_ListFuncCall, info, arg, ctx);
 }
 
+ap_expr_t *ap_expr_list_regex_make(const ap_expr_t *arg, const ap_expr_t *reg,
+                                   ap_expr_parse_ctx_t *ctx)
+{
+    ap_expr_t *node = apr_palloc(ctx->pool, sizeof(ap_expr_t));
+    node->node_op   = op_ListRegex;
+    node->node_arg1 = arg;
+    node->node_arg2 = reg;
+    return node;
+}
+
 ap_expr_t *ap_expr_unary_op_make(const char *name, const ap_expr_t *arg,
                                ap_expr_parse_ctx_t *ctx)
 {
@@ -654,10 +964,15 @@ static void expr_dump_tree(const ap_expr_t *e, const server_rec *s,
     case op_IN:
     case op_REG:
     case op_NRE:
+    case op_Word:
+    case op_Bool:
+    case op_Join:
+    case op_Regsub:
     case op_Concat:
     case op_StringFuncCall:
     case op_ListFuncCall:
     case op_ListElement:
+    case op_ListRegex:
         {
             char *name;
             switch (e->node_op) {
@@ -680,10 +995,15 @@ static void expr_dump_tree(const ap_expr_t *e, const server_rec *s,
             CASE_OP(op_IN);
             CASE_OP(op_REG);
             CASE_OP(op_NRE);
+            CASE_OP(op_Word);
+            CASE_OP(op_Bool);
+            CASE_OP(op_Join);
+            CASE_OP(op_Regsub);
             CASE_OP(op_Concat);
             CASE_OP(op_StringFuncCall);
             CASE_OP(op_ListFuncCall);
             CASE_OP(op_ListElement);
+            CASE_OP(op_ListRegex);
             default:
                 ap_assert(0);
             }
@@ -729,8 +1049,8 @@ static void expr_dump_tree(const ap_expr_t *e, const server_rec *s,
         DUMP_P("op_Regex", e->node_arg1);
         break;
     /* arg1: pointer to int */
-    case op_RegexBackref:
-        DUMP_IP("op_RegexBackref", e->node_arg1);
+    case op_Regref:
+        DUMP_IP("op_Regref", e->node_arg1);
         break;
     default:
         ap_log_error(MARK, "%*sERROR: INVALID OP %d", indent, " ", e->node_op);
@@ -769,7 +1089,7 @@ static int ap_expr_eval_binary_op(ap_expr_eval_ctx_t *ctx,
 }
 
 
-static int ap_expr_eval(ap_expr_eval_ctx_t *ctx, const ap_expr_t *node)
+static int ap_expr_eval_cond(ap_expr_eval_ctx_t *ctx, const ap_expr_t *node)
 {
     const ap_expr_t *e1 = node->node_arg1;
     const ap_expr_t *e2 = node->node_arg2;
@@ -791,13 +1111,13 @@ static int ap_expr_eval(ap_expr_eval_ctx_t *ctx, const ap_expr_t *node)
         case op_Or:
             do {
                 if (e1->node_op == op_Not) {
-                    if (!ap_expr_eval(ctx, e1->node_arg1)) {
+                    if (!ap_expr_eval_cond(ctx, e1->node_arg1)) {
                         result ^= TRUE;
                         goto out;
                     }
                 }
                 else {
-                    if (ap_expr_eval(ctx, e1)) {
+                    if (ap_expr_eval_cond(ctx, e1)) {
                         result ^= TRUE;
                         goto out;
                     }
@@ -809,13 +1129,13 @@ static int ap_expr_eval(ap_expr_eval_ctx_t *ctx, const ap_expr_t *node)
         case op_And:
             do {
                 if (e1->node_op == op_Not) {
-                    if (ap_expr_eval(ctx, e1->node_arg1)) {
+                    if (ap_expr_eval_cond(ctx, e1->node_arg1)) {
                         result ^= FALSE;
                         goto out;
                     }
                 }
                 else {
-                    if (!ap_expr_eval(ctx, e1)) {
+                    if (!ap_expr_eval_cond(ctx, e1)) {
                         result ^= FALSE;
                         goto out;
                     }
@@ -889,7 +1209,7 @@ AP_DECLARE(int) ap_expr_exec_ctx(ap_expr_eval_ctx_t *ctx)
         }
     }
     else {
-        rc = ap_expr_eval(ctx, ctx->info->root_node);
+        rc = ap_expr_eval_cond(ctx, ctx->info->root_node);
         if (*ctx->err != NULL) {
             ap_log_rerror(LOG_MARK(ctx->info), APLOG_ERR, 0, ctx->r,
                           APLOGNO(03299)
index d5891c6f616f3bf173a2cf74729064d474722458..27b45dc33634c6fefa9331d904dcecdf43600883 100644 (file)
@@ -1,4 +1,4 @@
-/* A Bison parser, made by GNU Bison 2.7.12-4996.  */
+/* A Bison parser, made by GNU Bison 2.7.1.  */
 
 /* Bison implementation for Yacc-like parsers in C
    
@@ -44,7 +44,7 @@
 #define YYBISON 1
 
 /* Bison version.  */
-#define YYBISON_VERSION "2.7.12-4996"
+#define YYBISON_VERSION "2.7.1"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -120,33 +120,40 @@ extern int ap_expr_yydebug;
      T_ID = 264,
      T_STRING = 265,
      T_REGEX = 266,
-     T_REGEX_I = 267,
-     T_REGEX_BACKREF = 268,
-     T_OP_UNARY = 269,
-     T_OP_BINARY = 270,
-     T_STR_BEGIN = 271,
-     T_STR_END = 272,
-     T_VAR_BEGIN = 273,
-     T_VAR_END = 274,
-     T_OP_EQ = 275,
-     T_OP_NE = 276,
-     T_OP_LT = 277,
-     T_OP_LE = 278,
-     T_OP_GT = 279,
-     T_OP_GE = 280,
-     T_OP_REG = 281,
-     T_OP_NRE = 282,
-     T_OP_IN = 283,
-     T_OP_STR_EQ = 284,
-     T_OP_STR_NE = 285,
-     T_OP_STR_LT = 286,
-     T_OP_STR_LE = 287,
-     T_OP_STR_GT = 288,
-     T_OP_STR_GE = 289,
-     T_OP_CONCAT = 290,
-     T_OP_OR = 291,
-     T_OP_AND = 292,
-     T_OP_NOT = 293
+     T_REGSUB = 267,
+     T_REG_MATCH = 268,
+     T_REG_SUBST = 269,
+     T_REG_FLAGS = 270,
+     T_REG_REF = 271,
+     T_OP_UNARY = 272,
+     T_OP_BINARY = 273,
+     T_STR_BEGIN = 274,
+     T_STR_END = 275,
+     T_VAR_BEGIN = 276,
+     T_VAR_END = 277,
+     T_VAREXP_BEGIN = 278,
+     T_VAREXP_END = 279,
+     T_OP_EQ = 280,
+     T_OP_NE = 281,
+     T_OP_LT = 282,
+     T_OP_LE = 283,
+     T_OP_GT = 284,
+     T_OP_GE = 285,
+     T_OP_REG = 286,
+     T_OP_NRE = 287,
+     T_OP_IN = 288,
+     T_OP_STR_EQ = 289,
+     T_OP_STR_NE = 290,
+     T_OP_STR_LT = 291,
+     T_OP_STR_LE = 292,
+     T_OP_STR_GT = 293,
+     T_OP_STR_GE = 294,
+     T_OP_CONCAT = 295,
+     T_OP_SPLIT = 296,
+     T_OP_JOIN = 297,
+     T_OP_OR = 298,
+     T_OP_AND = 299,
+     T_OP_NOT = 300
    };
 #endif
 
@@ -163,7 +170,7 @@ typedef union YYSTYPE
 
 
 /* Line 387 of yacc.c  */
-#line 167 "util_expr_parse.c"
+#line 174 "util_expr_parse.c"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
@@ -189,7 +196,7 @@ int ap_expr_yyparse ();
 
 /* Copy the second part of user declarations.  */
 /* Line 390 of yacc.c  */
-#line 102 "util_expr_parse.y"
+#line 116 "util_expr_parse.y"
 
 #include "util_expr_private.h"
 #define yyscanner ctx->scanner
@@ -197,7 +204,7 @@ int ap_expr_yyparse ();
 int ap_expr_yylex(YYSTYPE *lvalp, void *scanner);
 
 /* Line 390 of yacc.c  */
-#line 201 "util_expr_parse.c"
+#line 208 "util_expr_parse.c"
 
 #ifdef short
 # undef short
@@ -424,22 +431,22 @@ union yyalloc
 #endif /* !YYCOPY_NEEDED */
 
 /* YYFINAL -- State number of the termination state.  */
-#define YYFINAL  28
+#define YYFINAL  30
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   134
+#define YYLAST   300
 
 /* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  50
+#define YYNTOKENS  66
 /* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  14
+#define YYNNTS  17
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  54
+#define YYNRULES  68
 /* YYNRULES -- Number of states.  */
-#define YYNSTATES  98
+#define YYNSTATES  139
 
 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
 #define YYUNDEFTOK  2
-#define YYMAXUTOK   298
+#define YYMAXUTOK   314
 
 #define YYTRANSLATE(YYX)                                               \
   ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
@@ -451,15 +458,15 @@ static const yytype_uint8 yytranslate[] =
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-      44,    45,     2,     2,    48,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,    49,     2,
+      60,    61,     2,     2,    64,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,    65,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,    46,     2,    47,     2,     2,     2,     2,
+       2,     2,     2,    62,     2,    63,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -476,7 +483,9 @@ static const yytype_uint8 yytranslate[] =
        5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
       15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
       25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
-      35,    36,    37,    38,    39,    40,    41,    42,    43
+      35,    36,    37,    38,    39,    40,    41,    42,    43,    44,
+      45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
+      55,    56,    57,    58,    59
 };
 
 #if YYDEBUG
@@ -487,43 +496,51 @@ static const yytype_uint8 yyprhs[] =
        0,     0,     3,     6,     9,    11,    13,    15,    18,    22,
       26,    28,    31,    35,    39,    41,    45,    49,    53,    57,
       61,    65,    69,    73,    77,    81,    85,    89,    93,    97,
-     101,   103,   107,   109,   113,   116,   118,   120,   122,   124,
-     126,   130,   136,   138,   142,   144,   146,   148,   152,   155,
-     157,   159,   161,   166,   171
+     101,   103,   107,   111,   115,   119,   121,   125,   127,   130,
+     132,   134,   136,   138,   142,   148,   152,   156,   158,   161,
+     165,   169,   173,   175,   177,   179,   182,   187,   194,   198,
+     202,   207,   212,   214,   216,   218,   220,   225,   230
 };
 
 /* YYRHS -- A `-1'-separated list of the rules' RHS.  */
 static const yytype_int8 yyrhs[] =
 {
-      51,     0,    -1,     5,    52,    -1,     6,    56,    -1,     7,
-      -1,     3,    -1,     4,    -1,    38,    52,    -1,    52,    36,
-      52,    -1,    52,    37,    52,    -1,    53,    -1,    14,    59,
-      -1,    59,    15,    59,    -1,    44,    52,    45,    -1,     7,
-      -1,    59,    20,    59,    -1,    59,    21,    59,    -1,    59,
-      22,    59,    -1,    59,    23,    59,    -1,    59,    24,    59,
-      -1,    59,    25,    59,    -1,    59,    29,    59,    -1,    59,
-      30,    59,    -1,    59,    31,    59,    -1,    59,    32,    59,
-      -1,    59,    33,    59,    -1,    59,    34,    59,    -1,    59,
-      28,    54,    -1,    59,    26,    60,    -1,    59,    27,    60,
-      -1,    62,    -1,    46,    55,    47,    -1,    59,    -1,    55,
-      48,    59,    -1,    56,    57,    -1,    57,    -1,     7,    -1,
-      10,    -1,    58,    -1,    61,    -1,    18,     9,    19,    -1,
-      18,     9,    49,    56,    19,    -1,     8,    -1,    59,    35,
-      59,    -1,    58,    -1,    61,    -1,    63,    -1,    16,    56,
-      17,    -1,    16,    17,    -1,    11,    -1,    12,    -1,    13,
-      -1,     9,    44,    59,    45,    -1,     9,    44,    59,    45,
-      -1,     9,    44,    55,    45,    -1
+      67,     0,    -1,     5,    68,    -1,     6,    72,    -1,     7,
+      -1,     3,    -1,     4,    -1,    45,    68,    -1,    68,    43,
+      68,    -1,    68,    44,    68,    -1,    69,    -1,    17,    75,
+      -1,    75,    18,    75,    -1,    60,    68,    61,    -1,     7,
+      -1,    75,    25,    75,    -1,    75,    26,    75,    -1,    75,
+      27,    75,    -1,    75,    28,    75,    -1,    75,    29,    75,
+      -1,    75,    30,    75,    -1,    75,    34,    75,    -1,    75,
+      35,    75,    -1,    75,    36,    75,    -1,    75,    37,    75,
+      -1,    75,    38,    75,    -1,    75,    39,    75,    -1,    75,
+      33,    70,    -1,    75,    31,    76,    -1,    75,    32,    76,
+      -1,    81,    -1,    75,    31,    78,    -1,    70,    31,    79,
+      -1,    62,    71,    63,    -1,    60,    70,    61,    -1,    75,
+      -1,    75,    64,    71,    -1,    73,    -1,    72,    73,    -1,
+       7,    -1,    10,    -1,    74,    -1,    80,    -1,    21,     9,
+      22,    -1,    21,     9,    65,    72,    22,    -1,    23,    75,
+      24,    -1,    23,    68,    24,    -1,     8,    -1,    19,    20,
+      -1,    19,    72,    20,    -1,    75,    40,    75,    -1,    75,
+      31,    77,    -1,    74,    -1,    80,    -1,    82,    -1,    42,
+      70,    -1,    42,    70,    64,    75,    -1,    42,    60,    70,
+      64,    75,    61,    -1,    60,    75,    61,    -1,    11,    13,
+      15,    -1,    12,    13,    72,    15,    -1,    41,    13,    72,
+      15,    -1,    76,    -1,    77,    -1,    78,    -1,    16,    -1,
+       9,    60,    75,    61,    -1,     9,    60,    75,    61,    -1,
+       9,    60,    71,    61,    -1
 };
 
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
-static const yytype_uint8 yyrline[] =
+static const yytype_uint16 yyrline[] =
 {
-       0,   112,   112,   113,   114,   117,   118,   119,   120,   121,
-     122,   123,   124,   125,   126,   129,   130,   131,   132,   133,
-     134,   135,   136,   137,   138,   139,   140,   141,   142,   143,
-     146,   147,   150,   151,   154,   155,   156,   159,   160,   161,
-     164,   165,   168,   169,   170,   171,   172,   173,   174,   177,
-     186,   197,   204,   207,   208
+       0,   126,   126,   127,   128,   131,   132,   133,   134,   135,
+     136,   137,   138,   139,   140,   143,   144,   145,   146,   147,
+     148,   149,   150,   151,   152,   153,   154,   155,   156,   157,
+     160,   161,   162,   163,   164,   167,   168,   171,   172,   173,
+     176,   177,   178,   181,   182,   183,   184,   187,   188,   189,
+     190,   191,   192,   193,   194,   195,   198,   201,   204,   207,
+     216,   225,   242,   243,   244,   247,   254,   258,   259
 };
 #endif
 
@@ -534,22 +551,30 @@ static const char *const yytname[] =
 {
   "$end", "error", "$undefined", "\"true\"", "\"false\"",
   "\"boolean expression\"", "\"string expression\"", "\"error token\"",
-  "\"number\"", "\"identifier\"", "\"cstring\"", "\"regex\"",
-  "\"case-indendent regex\"", "\"regex back reference\"",
-  "\"unary operator\"", "\"binary operator\"", "\"start of string\"",
-  "\"end of string\"", "\"start of variable name\"",
-  "\"end of variable name\"", "\"integer equal\"", "\"integer not equal\"",
-  "\"integer less than\"", "\"integer less or equal\"",
-  "\"integer greater than\"", "\"integer greater or equal\"",
-  "\"regex match\"", "\"regex non-match\"", "\"contained in\"",
-  "\"string equal\"", "\"string not equal\"", "\"string less than\"",
-  "\"string less or equal\"", "\"string greater than\"",
-  "\"string greater or equal\"", "\"string concatenation\"",
-  "\"logical or\"", "\"logical and\"", "\"logical not\"", "\"function\"",
-  "\"listfunction\"", "\"stringpart\"", "\"variable\"", "\"rebackref\"",
-  "'('", "')'", "'{'", "'}'", "','", "':'", "$accept", "root", "expr",
-  "comparison", "wordlist", "words", "string", "strpart", "var", "word",
-  "regex", "backref", "lstfunccall", "strfunccall", YY_NULL
+  "\"number\"", "\"identifier\"", "\"string\"", "\"match regex\"",
+  "\"substitution regex\"", "\"match pattern of the regex\"",
+  "\"substitution pattern of the regex\"", "\"flags of the regex\"",
+  "\"regex back reference\"", "\"unary operator\"", "\"binary operator\"",
+  "\"start of string\"", "\"end of string\"", "\"start of variable name\"",
+  "\"end of variable name\"", "\"start of variable expression\"",
+  "\"end of variable expression\"", "\"integer equal\"",
+  "\"integer not equal\"", "\"integer less than\"",
+  "\"integer less or equal\"", "\"integer greater than\"",
+  "\"integer greater or equal\"", "\"regex match\"", "\"regex non-match\"",
+  "\"contained in\"", "\"string equal\"", "\"string not equal\"",
+  "\"string less than\"", "\"string less or equal\"",
+  "\"string greater than\"", "\"string greater or equal\"",
+  "\"string concatenation\"", "\"split operator\"", "\"join operator\"",
+  "\"logical or\"", "\"logical and\"", "\"logical not\"", "\"condition\"",
+  "\"comparison\"", "\"string function\"", "\"list function\"",
+  "\"list of words\"", "\"tuple of words\"", "\"word expression\"",
+  "\"any string expression\"", "\"variable expression\"",
+  "\"regular expression match\"", "\"regular expression substitution\"",
+  "\"regular expression split\"", "\"any regular expression\"",
+  "\"regular expression back reference\"", "'('", "')'", "'{'", "'}'",
+  "','", "':'", "$accept", "root", "cond", "comp", "wordlist", "words",
+  "string", "strany", "var", "word", "regex", "regsub", "regsplit",
+  "regany", "regref", "lstfunc", "strfunc", YY_NULL
 };
 #endif
 
@@ -562,19 +587,22 @@ static const yytype_uint16 yytoknum[] =
      265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
      275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
      285,   286,   287,   288,   289,   290,   291,   292,   293,   294,
-     295,   296,   297,   298,    40,    41,   123,   125,    44,    58
+     295,   296,   297,   298,   299,   300,   301,   302,   303,   304,
+     305,   306,   307,   308,   309,   310,   311,   312,   313,   314,
+      40,    41,   123,   125,    44,    58
 };
 # endif
 
 /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
 static const yytype_uint8 yyr1[] =
 {
-       0,    50,    51,    51,    51,    52,    52,    52,    52,    52,
-      52,    52,    52,    52,    52,    53,    53,    53,    53,    53,
-      53,    53,    53,    53,    53,    53,    53,    53,    53,    53,
-      54,    54,    55,    55,    56,    56,    56,    57,    57,    57,
-      58,    58,    59,    59,    59,    59,    59,    59,    59,    60,
-      60,    61,    62,    63,    63
+       0,    66,    67,    67,    67,    68,    68,    68,    68,    68,
+      68,    68,    68,    68,    68,    69,    69,    69,    69,    69,
+      69,    69,    69,    69,    69,    69,    69,    69,    69,    69,
+      70,    70,    70,    70,    70,    71,    71,    72,    72,    72,
+      73,    73,    73,    74,    74,    74,    74,    75,    75,    75,
+      75,    75,    75,    75,    75,    75,    75,    75,    75,    76,
+      77,    78,    79,    79,    79,    80,    81,    82,    82
 };
 
 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
@@ -583,9 +611,10 @@ static const yytype_uint8 yyr2[] =
        0,     2,     2,     2,     1,     1,     1,     2,     3,     3,
        1,     2,     3,     3,     1,     3,     3,     3,     3,     3,
        3,     3,     3,     3,     3,     3,     3,     3,     3,     3,
-       1,     3,     1,     3,     2,     1,     1,     1,     1,     1,
-       3,     5,     1,     3,     1,     1,     1,     3,     2,     1,
-       1,     1,     4,     4,     4
+       1,     3,     3,     3,     3,     1,     3,     1,     2,     1,
+       1,     1,     1,     3,     5,     3,     3,     1,     2,     3,
+       3,     3,     1,     1,     1,     2,     4,     6,     3,     3,
+       4,     4,     1,     1,     1,     1,     4,     4,     4
 };
 
 /* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
@@ -593,47 +622,55 @@ static const yytype_uint8 yyr2[] =
    means the default is an error.  */
 static const yytype_uint8 yydefact[] =
 {
-       0,     0,     0,     4,     0,     5,     6,    14,    42,     0,
-      51,     0,     0,     0,     0,     0,     2,    10,    44,     0,
-      45,    46,    36,    37,     3,    35,    38,    39,     1,     0,
-      11,    48,     0,     0,     7,     0,     0,     0,     0,     0,
+       0,     0,     0,     4,     0,     5,     6,    14,    47,     0,
+      65,     0,     0,     0,     0,     0,     0,     0,     2,    10,
+      52,     0,    53,    54,    39,    40,     3,    37,    41,    42,
+       1,     0,     0,    11,    48,     0,     0,     0,     0,     0,
+       0,     0,    55,     0,    30,     7,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,    34,     0,    32,    47,    40,
-       0,    13,     8,     9,    12,    15,    16,    17,    18,    19,
-      20,    49,    50,    28,    29,     0,     0,    27,    30,    21,
-      22,    23,    24,    25,    26,    43,    54,     0,    53,     0,
-       0,     0,    32,    33,    41,     0,    31,    52
+       0,     0,     0,     0,     0,     0,     0,    38,     0,     0,
+       0,     0,    49,    43,     0,    46,    45,     0,     0,     0,
+       0,     0,    35,     0,     0,     0,    13,    58,     8,     9,
+      12,    15,    16,    17,    18,    19,    20,     0,     0,    28,
+      51,    29,    27,    21,    22,    23,    24,    25,    26,    50,
+      68,    67,     0,     0,     0,     0,    34,     0,    33,     0,
+      62,    63,    64,    32,    56,    31,     0,     0,    36,    44,
+      66,     0,     0,    59,     0,    57,     0,    60,    61
 };
 
 /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int8 yydefgoto[] =
 {
-      -1,     4,    16,    17,    77,    56,    24,    25,    18,    19,
-      73,    20,    78,    21
+      -1,     4,    18,    19,    42,    68,    26,    27,    20,    21,
+      99,   100,   122,   123,    22,    44,    23
 };
 
 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
    STATE-NUM.  */
-#define YYPACT_NINF -41
-static const yytype_int8 yypact[] =
+#define YYPACT_NINF -46
+static const yytype_int16 yypact[] =
 {
-      22,    48,    60,   -41,    16,   -41,   -41,   -41,   -41,   -24,
-     -41,   102,     8,    32,    48,    48,   -23,   -41,   -41,    74,
-     -41,   -41,   -41,   -41,    50,   -41,   -41,   -41,   -41,   102,
-      -3,   -41,   116,    23,   -41,    87,    48,    48,   102,   102,
-     102,   102,   102,   102,   102,    68,    68,    -6,   102,   102,
-     102,   102,   102,   102,   102,   -41,   -40,   -28,   -41,   -41,
-      60,   -41,   -23,    28,    -3,    -3,    -3,    -3,    -3,    -3,
-      -3,   -41,   -41,   -41,   -41,    30,   102,   -41,   -41,    -3,
-      -3,    -3,    -3,    -3,    -3,    -3,   -41,   102,   -41,   103,
-     102,    36,    -3,    -3,   -41,   -26,   -41,   -41
+     257,   136,   277,   -46,    29,   -46,   -46,   -46,   -46,   -29,
+     -46,   164,   216,    39,   136,     7,   136,   136,    27,   -46,
+     -46,   243,   -46,   -46,   -46,   -46,   276,   -46,   -46,   -46,
+     -46,   164,   164,   -22,   -46,   100,   -18,    75,   220,     8,
+     142,   164,    -9,    19,   -46,   -46,     0,   182,   136,   136,
+     164,   164,   164,   164,   164,   164,   164,    83,    47,   142,
+     164,   164,   164,   164,   164,   164,   164,   -46,    21,   107,
+       1,    48,   -46,   -46,   277,   -46,   -46,   164,   142,    32,
+      66,    37,   -19,    42,   164,    -6,   -46,   -46,    27,    57,
+     -22,   -22,   -22,   -22,   -22,   -22,   -22,    91,    92,   -46,
+     -46,   -46,    77,   -22,   -22,   -22,   -22,   -22,   -22,   -22,
+     -46,   -46,   164,   154,   129,   -24,   -46,   164,   -46,   101,
+     -46,   -46,   -46,   -46,   -22,   -46,   109,   277,   -46,   -46,
+     -46,    67,   277,   -46,   176,   -46,   219,   -46,   -46
 };
 
 /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int8 yypgoto[] =
 {
-     -41,   -41,    39,   -41,   -41,     1,   -10,   -20,    -2,    -5,
-      35,    -1,   -41,   -41
+     -46,   -46,     3,   -46,   -32,   -38,   -10,   -21,    -2,    25,
+     -45,    46,    51,   -46,    -1,   -46,   -46
 };
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
@@ -642,60 +679,98 @@ static const yytype_int8 yypgoto[] =
 #define YYTABLE_NINF -1
 static const yytype_uint8 yytable[] =
 {
-      26,    27,    32,    75,    55,    86,    30,    54,    87,    54,
-      26,    27,    55,    36,    37,    22,    28,    88,    23,    97,
-      29,    10,    26,    27,    57,    31,    13,     1,     2,     3,
-      26,    27,    54,    64,    65,    66,    67,    68,    69,    70,
-      76,    33,    59,    79,    80,    81,    82,    83,    84,    85,
-      89,     5,     6,    34,    35,     7,     8,     9,    26,    27,
-      23,    10,    11,    10,    12,    37,    13,    22,    13,    55,
-      23,    92,    60,    10,    90,    62,    63,    91,    13,    71,
-      72,    74,    93,    96,    87,    95,    14,    26,    27,    38,
-       0,     0,    15,     0,    39,    40,    41,    42,    43,    44,
-      45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
-       8,     9,     0,    23,     0,    10,    10,     0,    12,     0,
-      13,    13,    94,    36,    37,     0,    23,     0,     0,    10,
-       0,     0,    61,    58,    13
+      28,    29,    35,    81,    73,    67,    98,    83,    79,    71,
+      28,    29,    71,   101,    67,     8,    39,    37,    66,    45,
+      46,    66,    83,    10,    28,    29,    12,   102,    13,    30,
+      14,    31,    71,    28,    29,   119,    33,   116,   120,    38,
+      43,    66,    47,    48,    49,   112,   115,    74,    36,    15,
+      85,    88,    89,    97,    98,    84,    69,    70,    97,    66,
+      98,    86,    87,    83,   113,    80,    82,    40,    77,    41,
+      48,    49,    28,    29,   128,    90,    91,    92,    93,    94,
+      95,    96,   110,   119,    43,   103,   104,   105,   106,   107,
+     108,   109,    67,   116,    97,    98,   117,    85,    71,    75,
+     118,    49,   114,    80,   126,   127,    66,    66,    83,   124,
+      25,    28,    29,    67,   132,    67,    10,   134,    48,    49,
+      72,    13,   136,    14,   133,    28,    29,    87,   135,   121,
+      28,    29,    28,    29,    28,    29,   125,    82,    71,     5,
+       6,     0,   131,     7,     8,     9,     0,    66,     0,     0,
+       8,    39,    10,    11,     0,    12,     0,    13,    10,    14,
+      71,    12,     0,    13,    25,    14,     0,     0,   111,    66,
+      10,   112,     8,     9,     0,    13,   129,    14,    15,     0,
+      10,    16,     0,    12,    15,    13,    25,    14,     0,     0,
+     130,   137,    10,   112,     0,     0,    17,    13,     0,    14,
+      50,     0,    78,     0,    41,     0,    15,    51,    52,    53,
+      54,    55,    56,    57,    58,    59,    60,    61,    62,    63,
+      64,    65,    66,    24,    32,     0,    25,     0,     0,    25,
+       0,     0,    10,     0,   138,    10,    34,    13,    50,    14,
+      13,     0,    14,    87,    76,    51,    52,    53,    54,    55,
+      56,    57,    58,    59,    60,    61,    62,    63,    64,    65,
+      66,    50,     1,     2,     3,     0,     0,     0,    51,    52,
+      53,    54,    55,    56,    57,    58,    59,    60,    61,    62,
+      63,    64,    65,    66,    24,     0,    25,    25,     0,     0,
+       0,     0,    10,    10,     0,     0,     0,    13,    13,    14,
+      14
 };
 
 #define yypact_value_is_default(Yystate) \
-  (!!((Yystate) == (-41)))
+  (!!((Yystate) == (-46)))
 
 #define yytable_value_is_error(Yytable_value) \
   YYID (0)
 
-static const yytype_int8 yycheck[] =
+static const yytype_int16 yycheck[] =
 {
-       2,     2,    12,     9,    24,    45,    11,    35,    48,    35,
-      12,    12,    32,    36,    37,     7,     0,    45,    10,    45,
-      44,    13,    24,    24,    29,    17,    18,     5,     6,     7,
-      32,    32,    35,    38,    39,    40,    41,    42,    43,    44,
-      46,     9,    19,    48,    49,    50,    51,    52,    53,    54,
-      60,     3,     4,    14,    15,     7,     8,     9,    60,    60,
-      10,    13,    14,    13,    16,    37,    18,     7,    18,    89,
-      10,    76,    49,    13,    44,    36,    37,    76,    18,    11,
-      12,    46,    87,    47,    48,    90,    38,    89,    89,    15,
-      -1,    -1,    44,    -1,    20,    21,    22,    23,    24,    25,
-      26,    27,    28,    29,    30,    31,    32,    33,    34,    35,
-       8,     9,    -1,    10,    -1,    13,    13,    -1,    16,    -1,
-      18,    18,    19,    36,    37,    -1,    10,    -1,    -1,    13,
-      -1,    -1,    45,    17,    18
+       2,     2,    12,    41,    22,    26,    12,    31,    40,    31,
+      12,    12,    31,    58,    35,     8,     9,    14,    40,    16,
+      17,    40,    31,    16,    26,    26,    19,    59,    21,     0,
+      23,    60,    31,    35,    35,    41,    11,    61,    83,    14,
+      15,    40,    17,    43,    44,    64,    78,    65,     9,    42,
+      31,    48,    49,    11,    12,    64,    31,    32,    11,    40,
+      12,    61,    61,    31,    74,    40,    41,    60,    60,    62,
+      43,    44,    74,    74,   112,    50,    51,    52,    53,    54,
+      55,    56,    61,    41,    59,    60,    61,    62,    63,    64,
+      65,    66,   113,    61,    11,    12,    64,    31,    31,    24,
+      63,    44,    77,    78,    13,    13,    40,    40,    31,    84,
+      10,   113,   113,   134,    13,   136,    16,   127,    43,    44,
+      20,    21,   132,    23,    15,   127,   127,    61,    61,    83,
+     132,   132,   134,   134,   136,   136,    85,   112,    31,     3,
+       4,    -1,   117,     7,     8,     9,    -1,    40,    -1,    -1,
+       8,     9,    16,    17,    -1,    19,    -1,    21,    16,    23,
+      31,    19,    -1,    21,    10,    23,    -1,    -1,    61,    40,
+      16,    64,     8,     9,    -1,    21,    22,    23,    42,    -1,
+      16,    45,    -1,    19,    42,    21,    10,    23,    -1,    -1,
+      61,    15,    16,    64,    -1,    -1,    60,    21,    -1,    23,
+      18,    -1,    60,    -1,    62,    -1,    42,    25,    26,    27,
+      28,    29,    30,    31,    32,    33,    34,    35,    36,    37,
+      38,    39,    40,     7,    60,    -1,    10,    -1,    -1,    10,
+      -1,    -1,    16,    -1,    15,    16,    20,    21,    18,    23,
+      21,    -1,    23,    61,    24,    25,    26,    27,    28,    29,
+      30,    31,    32,    33,    34,    35,    36,    37,    38,    39,
+      40,    18,     5,     6,     7,    -1,    -1,    -1,    25,    26,
+      27,    28,    29,    30,    31,    32,    33,    34,    35,    36,
+      37,    38,    39,    40,     7,    -1,    10,    10,    -1,    -1,
+      -1,    -1,    16,    16,    -1,    -1,    -1,    21,    21,    23,
+      23
 };
 
 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
    symbol of state STATE-NUM.  */
 static const yytype_uint8 yystos[] =
 {
-       0,     5,     6,     7,    51,     3,     4,     7,     8,     9,
-      13,    14,    16,    18,    38,    44,    52,    53,    58,    59,
-      61,    63,     7,    10,    56,    57,    58,    61,     0,    44,
-      59,    17,    56,     9,    52,    52,    36,    37,    15,    20,
-      21,    22,    23,    24,    25,    26,    27,    28,    29,    30,
-      31,    32,    33,    34,    35,    57,    55,    59,    17,    19,
-      49,    45,    52,    52,    59,    59,    59,    59,    59,    59,
-      59,    11,    12,    60,    60,     9,    46,    54,    62,    59,
-      59,    59,    59,    59,    59,    59,    45,    48,    45,    56,
-      44,    55,    59,    59,    19,    59,    47,    45
+       0,     5,     6,     7,    67,     3,     4,     7,     8,     9,
+      16,    17,    19,    21,    23,    42,    45,    60,    68,    69,
+      74,    75,    80,    82,     7,    10,    72,    73,    74,    80,
+       0,    60,    60,    75,    20,    72,     9,    68,    75,     9,
+      60,    62,    70,    75,    81,    68,    68,    75,    43,    44,
+      18,    25,    26,    27,    28,    29,    30,    31,    32,    33,
+      34,    35,    36,    37,    38,    39,    40,    73,    71,    75,
+      75,    31,    20,    22,    65,    24,    24,    60,    60,    70,
+      75,    71,    75,    31,    64,    31,    61,    61,    68,    68,
+      75,    75,    75,    75,    75,    75,    75,    11,    12,    76,
+      77,    76,    70,    75,    75,    75,    75,    75,    75,    75,
+      61,    61,    64,    72,    75,    70,    61,    64,    63,    41,
+      76,    77,    78,    79,    75,    78,    13,    13,    71,    22,
+      61,    75,    13,    15,    72,    61,    72,    15,    15
 };
 
 #define yyerrok                (yyerrstatus = 0)
@@ -1507,345 +1582,448 @@ yyreduce:
     {
         case 2:
 /* Line 1787 of yacc.c  */
-#line 112 "util_expr_parse.y"
+#line 126 "util_expr_parse.y"
     { ctx->expr = (yyvsp[(2) - (2)].exVal); }
     break;
 
   case 3:
 /* Line 1787 of yacc.c  */
-#line 113 "util_expr_parse.y"
+#line 127 "util_expr_parse.y"
     { ctx->expr = (yyvsp[(2) - (2)].exVal); }
     break;
 
   case 4:
 /* Line 1787 of yacc.c  */
-#line 114 "util_expr_parse.y"
+#line 128 "util_expr_parse.y"
     { YYABORT; }
     break;
 
   case 5:
 /* Line 1787 of yacc.c  */
-#line 117 "util_expr_parse.y"
+#line 131 "util_expr_parse.y"
     { (yyval.exVal) = ap_expr_make(op_True,        NULL, NULL, ctx); }
     break;
 
   case 6:
 /* Line 1787 of yacc.c  */
-#line 118 "util_expr_parse.y"
+#line 132 "util_expr_parse.y"
     { (yyval.exVal) = ap_expr_make(op_False,       NULL, NULL, ctx); }
     break;
 
   case 7:
 /* Line 1787 of yacc.c  */
-#line 119 "util_expr_parse.y"
+#line 133 "util_expr_parse.y"
     { (yyval.exVal) = ap_expr_make(op_Not,         (yyvsp[(2) - (2)].exVal),   NULL, ctx); }
     break;
 
   case 8:
 /* Line 1787 of yacc.c  */
-#line 120 "util_expr_parse.y"
+#line 134 "util_expr_parse.y"
     { (yyval.exVal) = ap_expr_make(op_Or,          (yyvsp[(1) - (3)].exVal),   (yyvsp[(3) - (3)].exVal),   ctx); }
     break;
 
   case 9:
 /* Line 1787 of yacc.c  */
-#line 121 "util_expr_parse.y"
+#line 135 "util_expr_parse.y"
     { (yyval.exVal) = ap_expr_make(op_And,         (yyvsp[(1) - (3)].exVal),   (yyvsp[(3) - (3)].exVal),   ctx); }
     break;
 
   case 10:
 /* Line 1787 of yacc.c  */
-#line 122 "util_expr_parse.y"
+#line 136 "util_expr_parse.y"
     { (yyval.exVal) = ap_expr_make(op_Comp,        (yyvsp[(1) - (1)].exVal),   NULL, ctx); }
     break;
 
   case 11:
 /* Line 1787 of yacc.c  */
-#line 123 "util_expr_parse.y"
+#line 137 "util_expr_parse.y"
     { (yyval.exVal) = ap_expr_unary_op_make(       (yyvsp[(1) - (2)].cpVal),   (yyvsp[(2) - (2)].exVal),   ctx); }
     break;
 
   case 12:
 /* Line 1787 of yacc.c  */
-#line 124 "util_expr_parse.y"
+#line 138 "util_expr_parse.y"
     { (yyval.exVal) = ap_expr_binary_op_make((yyvsp[(2) - (3)].cpVal),   (yyvsp[(1) - (3)].exVal),   (yyvsp[(3) - (3)].exVal),   ctx); }
     break;
 
   case 13:
 /* Line 1787 of yacc.c  */
-#line 125 "util_expr_parse.y"
+#line 139 "util_expr_parse.y"
     { (yyval.exVal) = (yyvsp[(2) - (3)].exVal); }
     break;
 
   case 14:
 /* Line 1787 of yacc.c  */
-#line 126 "util_expr_parse.y"
+#line 140 "util_expr_parse.y"
     { YYABORT; }
     break;
 
   case 15:
 /* Line 1787 of yacc.c  */
-#line 129 "util_expr_parse.y"
+#line 143 "util_expr_parse.y"
     { (yyval.exVal) = ap_expr_make(op_EQ,      (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); }
     break;
 
   case 16:
 /* Line 1787 of yacc.c  */
-#line 130 "util_expr_parse.y"
+#line 144 "util_expr_parse.y"
     { (yyval.exVal) = ap_expr_make(op_NE,      (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); }
     break;
 
   case 17:
 /* Line 1787 of yacc.c  */
-#line 131 "util_expr_parse.y"
+#line 145 "util_expr_parse.y"
     { (yyval.exVal) = ap_expr_make(op_LT,      (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); }
     break;
 
   case 18:
 /* Line 1787 of yacc.c  */
-#line 132 "util_expr_parse.y"
+#line 146 "util_expr_parse.y"
     { (yyval.exVal) = ap_expr_make(op_LE,      (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); }
     break;
 
   case 19:
 /* Line 1787 of yacc.c  */
-#line 133 "util_expr_parse.y"
+#line 147 "util_expr_parse.y"
     { (yyval.exVal) = ap_expr_make(op_GT,      (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); }
     break;
 
   case 20:
 /* Line 1787 of yacc.c  */
-#line 134 "util_expr_parse.y"
+#line 148 "util_expr_parse.y"
     { (yyval.exVal) = ap_expr_make(op_GE,      (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); }
     break;
 
   case 21:
 /* Line 1787 of yacc.c  */
-#line 135 "util_expr_parse.y"
+#line 149 "util_expr_parse.y"
     { (yyval.exVal) = ap_expr_make(op_STR_EQ,  (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); }
     break;
 
   case 22:
 /* Line 1787 of yacc.c  */
-#line 136 "util_expr_parse.y"
+#line 150 "util_expr_parse.y"
     { (yyval.exVal) = ap_expr_make(op_STR_NE,  (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); }
     break;
 
   case 23:
 /* Line 1787 of yacc.c  */
-#line 137 "util_expr_parse.y"
+#line 151 "util_expr_parse.y"
     { (yyval.exVal) = ap_expr_make(op_STR_LT,  (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); }
     break;
 
   case 24:
 /* Line 1787 of yacc.c  */
-#line 138 "util_expr_parse.y"
+#line 152 "util_expr_parse.y"
     { (yyval.exVal) = ap_expr_make(op_STR_LE,  (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); }
     break;
 
   case 25:
 /* Line 1787 of yacc.c  */
-#line 139 "util_expr_parse.y"
+#line 153 "util_expr_parse.y"
     { (yyval.exVal) = ap_expr_make(op_STR_GT,  (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); }
     break;
 
   case 26:
 /* Line 1787 of yacc.c  */
-#line 140 "util_expr_parse.y"
+#line 154 "util_expr_parse.y"
     { (yyval.exVal) = ap_expr_make(op_STR_GE,  (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); }
     break;
 
   case 27:
 /* Line 1787 of yacc.c  */
-#line 141 "util_expr_parse.y"
+#line 155 "util_expr_parse.y"
     { (yyval.exVal) = ap_expr_make(op_IN,      (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); }
     break;
 
   case 28:
 /* Line 1787 of yacc.c  */
-#line 142 "util_expr_parse.y"
+#line 156 "util_expr_parse.y"
     { (yyval.exVal) = ap_expr_make(op_REG,     (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); }
     break;
 
   case 29:
 /* Line 1787 of yacc.c  */
-#line 143 "util_expr_parse.y"
+#line 157 "util_expr_parse.y"
     { (yyval.exVal) = ap_expr_make(op_NRE,     (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); }
     break;
 
   case 30:
 /* Line 1787 of yacc.c  */
-#line 146 "util_expr_parse.y"
+#line 160 "util_expr_parse.y"
     { (yyval.exVal) = (yyvsp[(1) - (1)].exVal); }
     break;
 
   case 31:
 /* Line 1787 of yacc.c  */
-#line 147 "util_expr_parse.y"
-    { (yyval.exVal) = (yyvsp[(2) - (3)].exVal); }
+#line 161 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_list_regex_make((yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); }
     break;
 
   case 32:
 /* Line 1787 of yacc.c  */
-#line 150 "util_expr_parse.y"
-    { (yyval.exVal) = ap_expr_make(op_ListElement, (yyvsp[(1) - (1)].exVal), NULL, ctx); }
+#line 162 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_list_regex_make((yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); }
     break;
 
   case 33:
 /* Line 1787 of yacc.c  */
-#line 151 "util_expr_parse.y"
-    { (yyval.exVal) = ap_expr_make(op_ListElement, (yyvsp[(3) - (3)].exVal), (yyvsp[(1) - (3)].exVal),   ctx); }
+#line 163 "util_expr_parse.y"
+    { (yyval.exVal) = (yyvsp[(2) - (3)].exVal); }
     break;
 
   case 34:
 /* Line 1787 of yacc.c  */
-#line 154 "util_expr_parse.y"
-    { (yyval.exVal) = ap_expr_make(op_Concat, (yyvsp[(1) - (2)].exVal), (yyvsp[(2) - (2)].exVal), ctx); }
+#line 164 "util_expr_parse.y"
+    { (yyval.exVal) = (yyvsp[(2) - (3)].exVal); }
     break;
 
   case 35:
 /* Line 1787 of yacc.c  */
-#line 155 "util_expr_parse.y"
-    { (yyval.exVal) = (yyvsp[(1) - (1)].exVal); }
+#line 167 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_ListElement, (yyvsp[(1) - (1)].exVal), NULL, ctx); }
     break;
 
   case 36:
 /* Line 1787 of yacc.c  */
-#line 156 "util_expr_parse.y"
-    { YYABORT; }
+#line 168 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_ListElement, (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal),   ctx); }
     break;
 
   case 37:
 /* Line 1787 of yacc.c  */
-#line 159 "util_expr_parse.y"
-    { (yyval.exVal) = ap_expr_make(op_String, (yyvsp[(1) - (1)].cpVal), NULL, ctx); }
+#line 171 "util_expr_parse.y"
+    { (yyval.exVal) = (yyvsp[(1) - (1)].exVal); }
     break;
 
   case 38:
 /* Line 1787 of yacc.c  */
-#line 160 "util_expr_parse.y"
-    { (yyval.exVal) = (yyvsp[(1) - (1)].exVal); }
+#line 172 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_concat_make((yyvsp[(1) - (2)].exVal), (yyvsp[(2) - (2)].exVal), ctx); }
     break;
 
   case 39:
 /* Line 1787 of yacc.c  */
-#line 161 "util_expr_parse.y"
-    { (yyval.exVal) = (yyvsp[(1) - (1)].exVal); }
+#line 173 "util_expr_parse.y"
+    { YYABORT; }
     break;
 
   case 40:
 /* Line 1787 of yacc.c  */
-#line 164 "util_expr_parse.y"
-    { (yyval.exVal) = ap_expr_var_make((yyvsp[(2) - (3)].cpVal), ctx); }
+#line 176 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_String, (yyvsp[(1) - (1)].cpVal), NULL, ctx); }
     break;
 
   case 41:
 /* Line 1787 of yacc.c  */
-#line 165 "util_expr_parse.y"
-    { (yyval.exVal) = ap_expr_str_func_make((yyvsp[(2) - (5)].cpVal), (yyvsp[(4) - (5)].exVal), ctx); }
+#line 177 "util_expr_parse.y"
+    { (yyval.exVal) = (yyvsp[(1) - (1)].exVal); }
     break;
 
   case 42:
 /* Line 1787 of yacc.c  */
-#line 168 "util_expr_parse.y"
-    { (yyval.exVal) = ap_expr_make(op_Digit,  (yyvsp[(1) - (1)].cpVal), NULL, ctx); }
+#line 178 "util_expr_parse.y"
+    { (yyval.exVal) = (yyvsp[(1) - (1)].exVal); }
     break;
 
   case 43:
 /* Line 1787 of yacc.c  */
-#line 169 "util_expr_parse.y"
-    { (yyval.exVal) = ap_expr_make(op_Concat, (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal),   ctx); }
+#line 181 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_var_make((yyvsp[(2) - (3)].cpVal), ctx); }
     break;
 
   case 44:
 /* Line 1787 of yacc.c  */
-#line 170 "util_expr_parse.y"
-    { (yyval.exVal) = (yyvsp[(1) - (1)].exVal); }
+#line 182 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_str_func_make((yyvsp[(2) - (5)].cpVal), (yyvsp[(4) - (5)].exVal), ctx); }
     break;
 
   case 45:
 /* Line 1787 of yacc.c  */
-#line 171 "util_expr_parse.y"
-    { (yyval.exVal) = (yyvsp[(1) - (1)].exVal); }
+#line 183 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_str_word_make((yyvsp[(2) - (3)].exVal), ctx); }
     break;
 
   case 46:
 /* Line 1787 of yacc.c  */
-#line 172 "util_expr_parse.y"
-    { (yyval.exVal) = (yyvsp[(1) - (1)].exVal); }
+#line 184 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_str_bool_make((yyvsp[(2) - (3)].exVal), ctx); }
     break;
 
   case 47:
 /* Line 1787 of yacc.c  */
-#line 173 "util_expr_parse.y"
-    { (yyval.exVal) = (yyvsp[(2) - (3)].exVal); }
+#line 187 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_Digit,  (yyvsp[(1) - (1)].cpVal), NULL, ctx); }
     break;
 
   case 48:
 /* Line 1787 of yacc.c  */
-#line 174 "util_expr_parse.y"
+#line 188 "util_expr_parse.y"
     { (yyval.exVal) = ap_expr_make(op_String, "", NULL, ctx); }
     break;
 
   case 49:
 /* Line 1787 of yacc.c  */
-#line 177 "util_expr_parse.y"
+#line 189 "util_expr_parse.y"
+    { (yyval.exVal) = (yyvsp[(2) - (3)].exVal); }
+    break;
+
+  case 50:
+/* Line 1787 of yacc.c  */
+#line 190 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_Concat, (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal),   ctx); }
+    break;
+
+  case 51:
+/* Line 1787 of yacc.c  */
+#line 191 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_Regsub, (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal),   ctx); }
+    break;
+
+  case 52:
+/* Line 1787 of yacc.c  */
+#line 192 "util_expr_parse.y"
+    { (yyval.exVal) = (yyvsp[(1) - (1)].exVal); }
+    break;
+
+  case 53:
+/* Line 1787 of yacc.c  */
+#line 193 "util_expr_parse.y"
+    { (yyval.exVal) = (yyvsp[(1) - (1)].exVal); }
+    break;
+
+  case 54:
+/* Line 1787 of yacc.c  */
+#line 194 "util_expr_parse.y"
+    { (yyval.exVal) = (yyvsp[(1) - (1)].exVal); }
+    break;
+
+  case 55:
+/* Line 1787 of yacc.c  */
+#line 195 "util_expr_parse.y"
+    {
+                                           (yyval.exVal) = ap_expr_make(op_Join,   (yyvsp[(2) - (2)].exVal), NULL, ctx);
+            }
+    break;
+
+  case 56:
+/* Line 1787 of yacc.c  */
+#line 198 "util_expr_parse.y"
     {
-                ap_regex_t *regex;
-                if ((regex = ap_pregcomp(ctx->pool, (yyvsp[(1) - (1)].cpVal),
-                                         AP_REG_EXTENDED|AP_REG_NOSUB)) == NULL) {
+                                           (yyval.exVal) = ap_expr_make(op_Join,   (yyvsp[(2) - (4)].exVal), (yyvsp[(4) - (4)].exVal),   ctx);
+            }
+    break;
+
+  case 57:
+/* Line 1787 of yacc.c  */
+#line 201 "util_expr_parse.y"
+    {
+                                           (yyval.exVal) = ap_expr_make(op_Join,   (yyvsp[(3) - (6)].exVal), (yyvsp[(5) - (6)].exVal),   ctx);
+            }
+    break;
+
+  case 58:
+/* Line 1787 of yacc.c  */
+#line 204 "util_expr_parse.y"
+    { (yyval.exVal) = (yyvsp[(2) - (3)].exVal); }
+    break;
+
+  case 59:
+/* Line 1787 of yacc.c  */
+#line 207 "util_expr_parse.y"
+    {
+                ap_expr_t *e = ap_expr_regex_make((yyvsp[(2) - (3)].cpVal), (yyvsp[(3) - (3)].cpVal), NULL, 0, ctx);
+                if (!e) {
                     ctx->error = "Failed to compile regular expression";
                     YYERROR;
                 }
-                (yyval.exVal) = ap_expr_make(op_Regex, regex, NULL, ctx);
+                (yyval.exVal) = e;
             }
     break;
 
-  case 50:
+  case 60:
 /* Line 1787 of yacc.c  */
-#line 186 "util_expr_parse.y"
+#line 216 "util_expr_parse.y"
     {
-                ap_regex_t *regex;
-                if ((regex = ap_pregcomp(ctx->pool, (yyvsp[(1) - (1)].cpVal),
-                                         AP_REG_EXTENDED|AP_REG_NOSUB|AP_REG_ICASE)) == NULL) {
+                ap_expr_t *e = ap_expr_regex_make((yyvsp[(2) - (4)].cpVal), (yyvsp[(4) - (4)].cpVal), (yyvsp[(3) - (4)].exVal), 0, ctx);
+                if (!e) {
                     ctx->error = "Failed to compile regular expression";
                     YYERROR;
                 }
-                (yyval.exVal) = ap_expr_make(op_Regex, regex, NULL, ctx);
+                (yyval.exVal) = e;
             }
     break;
 
-  case 51:
+  case 61:
 /* Line 1787 of yacc.c  */
-#line 197 "util_expr_parse.y"
+#line 225 "util_expr_parse.y"
+    {
+                /* Returns a list:
+                 * <word> ~= split/://
+                 *  => split around ':', replace it with empty
+                 * <word> ~= split/:/\n/
+                 *  => split around ':', replace it with '\n'
+                 * <list> ~= split/.*?Ip Address:([^,]+)/$1/
+                 *  => split around the whole match, replace it with $1
+                 */
+                ap_expr_t *e = ap_expr_regex_make((yyvsp[(2) - (4)].cpVal), (yyvsp[(4) - (4)].cpVal), (yyvsp[(3) - (4)].exVal), 1, ctx);
+                if (!e) {
+                    ctx->error = "Failed to compile regular expression";
+                    YYERROR;
+                }
+                (yyval.exVal) = e;
+            }
+    break;
+
+  case 62:
+/* Line 1787 of yacc.c  */
+#line 242 "util_expr_parse.y"
+    { (yyval.exVal) = (yyvsp[(1) - (1)].exVal); }
+    break;
+
+  case 63:
+/* Line 1787 of yacc.c  */
+#line 243 "util_expr_parse.y"
+    { (yyval.exVal) = (yyvsp[(1) - (1)].exVal); }
+    break;
+
+  case 64:
+/* Line 1787 of yacc.c  */
+#line 244 "util_expr_parse.y"
+    { (yyval.exVal) = (yyvsp[(1) - (1)].exVal); }
+    break;
+
+  case 65:
+/* Line 1787 of yacc.c  */
+#line 247 "util_expr_parse.y"
     {
                 int *n = apr_palloc(ctx->pool, sizeof(int));
                 *n = (yyvsp[(1) - (1)].num);
-                (yyval.exVal) = ap_expr_make(op_RegexBackref, n, NULL, ctx);
+                (yyval.exVal) = ap_expr_make(op_Regref, n, NULL, ctx);
             }
     break;
 
-  case 52:
+  case 66:
 /* Line 1787 of yacc.c  */
-#line 204 "util_expr_parse.y"
+#line 254 "util_expr_parse.y"
     { (yyval.exVal) = ap_expr_list_func_make((yyvsp[(1) - (4)].cpVal), (yyvsp[(3) - (4)].exVal), ctx); }
     break;
 
-  case 53:
+  case 67:
 /* Line 1787 of yacc.c  */
-#line 207 "util_expr_parse.y"
+#line 258 "util_expr_parse.y"
     { (yyval.exVal) = ap_expr_str_func_make((yyvsp[(1) - (4)].cpVal), (yyvsp[(3) - (4)].exVal), ctx); }
     break;
 
-  case 54:
+  case 68:
 /* Line 1787 of yacc.c  */
-#line 208 "util_expr_parse.y"
+#line 259 "util_expr_parse.y"
     { (yyval.exVal) = ap_expr_str_func_make((yyvsp[(1) - (4)].cpVal), (yyvsp[(3) - (4)].exVal), ctx); }
     break;
 
 
 /* Line 1787 of yacc.c  */
-#line 1849 "util_expr_parse.c"
+#line 2027 "util_expr_parse.c"
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
@@ -2077,7 +2255,7 @@ yyreturn:
 
 
 /* Line 2050 of yacc.c  */
-#line 211 "util_expr_parse.y"
+#line 262 "util_expr_parse.y"
 
 
 void yyerror(ap_expr_parse_ctx_t *ctx, const char *s)
index 21b0ffba56fe49109014f687e768fbd842281ac7..3f9ee26377868a9848133117c3854b97cb45b386 100644 (file)
@@ -1,4 +1,4 @@
-/* A Bison parser, made by GNU Bison 2.7.12-4996.  */
+/* A Bison parser, made by GNU Bison 2.7.1.  */
 
 /* Bison interface for Yacc-like parsers in C
    
@@ -55,33 +55,40 @@ extern int ap_expr_yydebug;
      T_ID = 264,
      T_STRING = 265,
      T_REGEX = 266,
-     T_REGEX_I = 267,
-     T_REGEX_BACKREF = 268,
-     T_OP_UNARY = 269,
-     T_OP_BINARY = 270,
-     T_STR_BEGIN = 271,
-     T_STR_END = 272,
-     T_VAR_BEGIN = 273,
-     T_VAR_END = 274,
-     T_OP_EQ = 275,
-     T_OP_NE = 276,
-     T_OP_LT = 277,
-     T_OP_LE = 278,
-     T_OP_GT = 279,
-     T_OP_GE = 280,
-     T_OP_REG = 281,
-     T_OP_NRE = 282,
-     T_OP_IN = 283,
-     T_OP_STR_EQ = 284,
-     T_OP_STR_NE = 285,
-     T_OP_STR_LT = 286,
-     T_OP_STR_LE = 287,
-     T_OP_STR_GT = 288,
-     T_OP_STR_GE = 289,
-     T_OP_CONCAT = 290,
-     T_OP_OR = 291,
-     T_OP_AND = 292,
-     T_OP_NOT = 293
+     T_REGSUB = 267,
+     T_REG_MATCH = 268,
+     T_REG_SUBST = 269,
+     T_REG_FLAGS = 270,
+     T_REG_REF = 271,
+     T_OP_UNARY = 272,
+     T_OP_BINARY = 273,
+     T_STR_BEGIN = 274,
+     T_STR_END = 275,
+     T_VAR_BEGIN = 276,
+     T_VAR_END = 277,
+     T_VAREXP_BEGIN = 278,
+     T_VAREXP_END = 279,
+     T_OP_EQ = 280,
+     T_OP_NE = 281,
+     T_OP_LT = 282,
+     T_OP_LE = 283,
+     T_OP_GT = 284,
+     T_OP_GE = 285,
+     T_OP_REG = 286,
+     T_OP_NRE = 287,
+     T_OP_IN = 288,
+     T_OP_STR_EQ = 289,
+     T_OP_STR_NE = 290,
+     T_OP_STR_LT = 291,
+     T_OP_STR_LE = 292,
+     T_OP_STR_GT = 293,
+     T_OP_STR_GE = 294,
+     T_OP_CONCAT = 295,
+     T_OP_SPLIT = 296,
+     T_OP_JOIN = 297,
+     T_OP_OR = 298,
+     T_OP_AND = 299,
+     T_OP_NOT = 300
    };
 #endif
 
@@ -98,7 +105,7 @@ typedef union YYSTYPE
 
 
 /* Line 2053 of yacc.c  */
-#line 102 "util_expr_parse.h"
+#line 109 "util_expr_parse.h"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
index 9e02602139ecbe8af6b9be4e28d62097b0bd62ab..ce1d6188dff205000d6c07a6767d9136943735b1 100644 (file)
 
 %token  <cpVal> T_DIGIT             "number"
 %token  <cpVal> T_ID                "identifier"
-%token  <cpVal> T_STRING            "cstring"
-%token  <cpVal> T_REGEX             "regex"
-%token  <cpVal> T_REGEX_I           "case-indendent regex"
-%token  <num>   T_REGEX_BACKREF     "regex back reference"
+%token  <cpVal> T_STRING            "string"
+
+%token          T_REGEX             "match regex"
+%token          T_REGSUB            "substitution regex"
+%token  <cpVal> T_REG_MATCH         "match pattern of the regex"
+%token  <cpVal> T_REG_SUBST         "substitution pattern of the regex"
+%token  <cpVal> T_REG_FLAGS         "flags of the regex"
+%token  <num>   T_REG_REF           "regex back reference"
+
 %token  <cpVal> T_OP_UNARY          "unary operator"
 %token  <cpVal> T_OP_BINARY         "binary operator"
 
@@ -59,6 +64,8 @@
 %token  T_STR_END                   "end of string"
 %token  T_VAR_BEGIN                 "start of variable name"
 %token  T_VAR_END                   "end of variable name"
+%token  T_VAREXP_BEGIN              "start of variable expression"
+%token  T_VAREXP_END                "end of variable expression"
 
 %token  T_OP_EQ                     "integer equal"
 %token  T_OP_NE                     "integer not equal"
 %token  T_OP_STR_LE                 "string less or equal"
 %token  T_OP_STR_GT                 "string greater than"
 %token  T_OP_STR_GE                 "string greater or equal"
+
 %token  T_OP_CONCAT                 "string concatenation"
 
+%token  T_OP_SPLIT                  "split operator"
+%token  T_OP_JOIN                   "join operator"
+
 %token  T_OP_OR                     "logical or"
 %token  T_OP_AND                    "logical and"
 %token  T_OP_NOT                    "logical not"
 %right  T_OP_NOT
 %right  T_OP_CONCAT
 
-%type   <exVal>   expr
-%type   <exVal>   comparison
-%type   <exVal>   strfunccall   "function"
-%type   <exVal>   lstfunccall   "listfunction"
-%type   <exVal>   regex
-%type   <exVal>   words
-%type   <exVal>   wordlist
-%type   <exVal>   word
-%type   <exVal>   string
-%type   <exVal>   strpart       "stringpart"
-%type   <exVal>   var           "variable"
-%type   <exVal>   backref       "rebackref"
+%type   <exVal>   cond              "condition"
+%type   <exVal>   comp              "comparison"
+%type   <exVal>   strfunc           "string function"
+%type   <exVal>   lstfunc           "list function"
+%type   <exVal>   wordlist          "list of words"
+%type   <exVal>   words             "tuple of words"
+%type   <exVal>   word              "word expression"
+%type   <exVal>   string            "string expression"
+%type   <exVal>   strany            "any string expression"
+%type   <exVal>   var               "variable expression"
+%type   <exVal>   regex             "regular expression match"
+%type   <exVal>   regsub            "regular expression substitution"
+%type   <exVal>   regsplit          "regular expression split"
+%type   <exVal>   regany            "any regular expression"
+%type   <exVal>   regref            "regular expression back reference"
 
 %{
 #include "util_expr_private.h"
@@ -109,24 +123,24 @@ int ap_expr_yylex(YYSTYPE *lvalp, void *scanner);
 
 %%
 
-root      : T_EXPR_BOOL   expr           { ctx->expr = $2; }
+root      : T_EXPR_BOOL   cond           { ctx->expr = $2; }
           | T_EXPR_STRING string         { ctx->expr = $2; }
           | T_ERROR                      { YYABORT; }
           ;
 
-expr      : T_TRUE                       { $$ = ap_expr_make(op_True,        NULL, NULL, ctx); }
+cond      : T_TRUE                       { $$ = ap_expr_make(op_True,        NULL, NULL, ctx); }
           | T_FALSE                      { $$ = ap_expr_make(op_False,       NULL, NULL, ctx); }
-          | T_OP_NOT expr                { $$ = ap_expr_make(op_Not,         $2,   NULL, ctx); }
-          | expr T_OP_OR expr            { $$ = ap_expr_make(op_Or,          $1,   $3,   ctx); }
-          | expr T_OP_AND expr           { $$ = ap_expr_make(op_And,         $1,   $3,   ctx); }
-          | comparison                   { $$ = ap_expr_make(op_Comp,        $1,   NULL, ctx); }
+          | T_OP_NOT cond                { $$ = ap_expr_make(op_Not,         $2,   NULL, ctx); }
+          | cond T_OP_OR cond            { $$ = ap_expr_make(op_Or,          $1,   $3,   ctx); }
+          | cond T_OP_AND cond           { $$ = ap_expr_make(op_And,         $1,   $3,   ctx); }
+          | comp                         { $$ = ap_expr_make(op_Comp,        $1,   NULL, ctx); }
           | T_OP_UNARY word              { $$ = ap_expr_unary_op_make(       $1,   $2,   ctx); }
           | word T_OP_BINARY word        { $$ = ap_expr_binary_op_make($2,   $1,   $3,   ctx); }
-          | '(' expr ')'                 { $$ = $2; }
+          | '(' cond ')'                 { $$ = $2; }
           | T_ERROR                      { YYABORT; }
           ;
 
-comparison: word T_OP_EQ word            { $$ = ap_expr_make(op_EQ,      $1, $3, ctx); }
+comp      : word T_OP_EQ word            { $$ = ap_expr_make(op_EQ,      $1, $3, ctx); }
           | word T_OP_NE word            { $$ = ap_expr_make(op_NE,      $1, $3, ctx); }
           | word T_OP_LT word            { $$ = ap_expr_make(op_LT,      $1, $3, ctx); }
           | word T_OP_LE word            { $$ = ap_expr_make(op_LE,      $1, $3, ctx); }
@@ -143,70 +157,107 @@ comparison: word T_OP_EQ word            { $$ = ap_expr_make(op_EQ,      $1, $3,
           | word T_OP_NRE regex          { $$ = ap_expr_make(op_NRE,     $1, $3, ctx); }
           ;
 
-wordlist  : lstfunccall                  { $$ = $1; }
+wordlist  : lstfunc                      { $$ = $1; }
+          | word     T_OP_REG regsplit   { $$ = ap_expr_list_regex_make($1, $3, ctx); }
+          | wordlist T_OP_REG regany     { $$ = ap_expr_list_regex_make($1, $3, ctx); }
           | '{' words '}'                { $$ = $2; }
+          | '(' wordlist ')'             { $$ = $2; }
           ;
 
 words     : word                         { $$ = ap_expr_make(op_ListElement, $1, NULL, ctx); }
-          | words ',' word               { $$ = ap_expr_make(op_ListElement, $3, $1,   ctx); }
+          | word ',' words               { $$ = ap_expr_make(op_ListElement, $1, $3,   ctx); }
           ;
 
-string    : string strpart               { $$ = ap_expr_make(op_Concat, $1, $2, ctx); }
-          | strpart                      { $$ = $1; }
+string    : strany                       { $$ = $1; }
+          | string strany                { $$ = ap_expr_concat_make($1, $2, ctx); }
           | T_ERROR                      { YYABORT; }
           ;
 
-strpart   : T_STRING                     { $$ = ap_expr_make(op_String, $1, NULL, ctx); }
+strany    : T_STRING                     { $$ = ap_expr_make(op_String, $1, NULL, ctx); }
           | var                          { $$ = $1; }
-          | backref                      { $$ = $1; }
+          | regref                       { $$ = $1; }
           ;
 
 var       : T_VAR_BEGIN T_ID T_VAR_END            { $$ = ap_expr_var_make($2, ctx); }
           | T_VAR_BEGIN T_ID ':' string T_VAR_END { $$ = ap_expr_str_func_make($2, $4, ctx); }
+          | T_VAREXP_BEGIN word T_VAREXP_END      { $$ = ap_expr_str_word_make($2, ctx); }
+          | T_VAREXP_BEGIN cond T_VAREXP_END      { $$ = ap_expr_str_bool_make($2, ctx); }
           ;
 
 word      : T_DIGIT                      { $$ = ap_expr_make(op_Digit,  $1, NULL, ctx); }
+          | T_STR_BEGIN T_STR_END        { $$ = ap_expr_make(op_String, "", NULL, ctx); }
+          | T_STR_BEGIN string T_STR_END { $$ = $2; }
           | word T_OP_CONCAT word        { $$ = ap_expr_make(op_Concat, $1, $3,   ctx); }
+          | word T_OP_REG regsub         { $$ = ap_expr_make(op_Regsub, $1, $3,   ctx); }
           | var                          { $$ = $1; }
-          | backref                      { $$ = $1; }
-          | strfunccall                  { $$ = $1; }
-          | T_STR_BEGIN string T_STR_END { $$ = $2; }
-          | T_STR_BEGIN T_STR_END        { $$ = ap_expr_make(op_String, "", NULL, ctx); }
+          | regref                       { $$ = $1; }
+          | strfunc                      { $$ = $1; }
+          | T_OP_JOIN     wordlist              {
+                                           $$ = ap_expr_make(op_Join,   $2, NULL, ctx);
+            }
+          | T_OP_JOIN     wordlist ',' word     {
+                                           $$ = ap_expr_make(op_Join,   $2, $4,   ctx);
+            }
+          | T_OP_JOIN '(' wordlist ',' word ')' {
+                                           $$ = ap_expr_make(op_Join,   $3, $5,   ctx);
+            }
+          | '(' word ')'                 { $$ = $2; }
           ;
 
-regex     : T_REGEX {
-                ap_regex_t *regex;
-                if ((regex = ap_pregcomp(ctx->pool, $1,
-                                         AP_REG_EXTENDED|AP_REG_NOSUB)) == NULL) {
+regex     : T_REGEX T_REG_MATCH T_REG_FLAGS {
+                ap_expr_t *e = ap_expr_regex_make($2, $3, NULL, 0, ctx);
+                if (!e) {
                     ctx->error = "Failed to compile regular expression";
                     YYERROR;
                 }
-                $$ = ap_expr_make(op_Regex, regex, NULL, ctx);
+                $$ = e;
             }
-          | T_REGEX_I {
-                ap_regex_t *regex;
-                if ((regex = ap_pregcomp(ctx->pool, $1,
-                                         AP_REG_EXTENDED|AP_REG_NOSUB|AP_REG_ICASE)) == NULL) {
+          ;
+regsub    : T_REGSUB T_REG_MATCH string T_REG_FLAGS {
+                ap_expr_t *e = ap_expr_regex_make($2, $4, $3, 0, ctx);
+                if (!e) {
+                    ctx->error = "Failed to compile regular expression";
+                    YYERROR;
+                }
+                $$ = e;
+            }
+          ;
+regsplit  : T_OP_SPLIT T_REG_MATCH string T_REG_FLAGS {
+                /* Returns a list:
+                 * <word> ~= split/://
+                 *  => split around ':', replace it with empty
+                 * <word> ~= split/:/\n/
+                 *  => split around ':', replace it with '\n'
+                 * <list> ~= split/.*?Ip Address:([^,]+)/$1/
+                 *  => split around the whole match, replace it with $1
+                 */
+                ap_expr_t *e = ap_expr_regex_make($2, $4, $3, 1, ctx);
+                if (!e) {
                     ctx->error = "Failed to compile regular expression";
                     YYERROR;
                 }
-                $$ = ap_expr_make(op_Regex, regex, NULL, ctx);
+                $$ = e;
             }
           ;
+regany    : regex     { $$ = $1; }
+          | regsub    { $$ = $1; }
+          | regsplit  { $$ = $1; }
+          ;
 
-backref     : T_REGEX_BACKREF   {
+regref    : T_REG_REF {
                 int *n = apr_palloc(ctx->pool, sizeof(int));
                 *n = $1;
-                $$ = ap_expr_make(op_RegexBackref, n, NULL, ctx);
+                $$ = ap_expr_make(op_Regref, n, NULL, ctx);
             }
-            ;
+          ;
 
-lstfunccall : T_ID '(' word ')' { $$ = ap_expr_list_func_make($1, $3, ctx); }
-            ;
+lstfunc   : T_ID '(' word ')'  { $$ = ap_expr_list_func_make($1, $3, ctx); }
+       /* | T_ID '(' words ')' { $$ = ap_expr_list_func_make($1, $3, ctx); } */
+          ;
 
-strfunccall : T_ID '(' word ')' { $$ = ap_expr_str_func_make($1, $3, ctx); }
-            | T_ID '(' words ')' { $$ = ap_expr_str_func_make($1, $3, ctx); }
-            ;
+strfunc   : T_ID '(' word ')'  { $$ = ap_expr_str_func_make($1, $3, ctx); }
+          | T_ID '(' words ')' { $$ = ap_expr_str_func_make($1, $3, ctx); }
+          ;
 
 %%
 
index 14cc4e3ccce759f3b7472d8a13e390ce5f4ce893..b0fcacefef9da4c4d48ff35a2602a712cc9dbbaf 100644 (file)
@@ -54,9 +54,10 @@ typedef enum {
     op_REG, op_NRE,
     op_STR_EQ, op_STR_NE, op_STR_LT, op_STR_LE, op_STR_GT, op_STR_GE,
     op_Concat,
-    op_Digit, op_String, op_Regex, op_RegexBackref,
-    op_Var,
-    op_ListElement,
+    op_Digit, op_String,
+    op_Var, op_Word, op_Bool, op_Join,
+    op_Regex, op_Regsub, op_Regref,
+    op_ListElement, op_ListRegex,
     /*
      * call external functions/operators.
      * The info node contains the function pointer and some function specific
@@ -79,6 +80,15 @@ struct ap_expr_node {
     const void *node_arg2;
 };
 
+/** The stack used by scanner and parser */
+typedef struct ap_expr_parser_stack {
+    char *scan_ptr;
+    char  scan_buf[MAX_STRING_LEN];
+    int   scan_stop;
+    int   scan_flag;
+    struct ap_expr_parser_stack *next;
+} ap_expr_parser_stack_t;
+
 /** The context used by scanner and parser */
 typedef struct {
     /* internal state of the scanner */
@@ -86,9 +96,8 @@ typedef struct {
     int                inputlen;
     const char        *inputptr;
     void              *scanner;
-    char              *scan_ptr;
-    char               scan_buf[MAX_STRING_LEN];
-    char               scan_del;
+    ap_expr_parser_stack_t *current,
+                           *spares;
     int                at_start;
 
     /* pools for result and temporary usage */
@@ -119,12 +128,23 @@ void ap_expr_yyset_extra(ap_expr_parse_ctx_t *context, void *scanner);
 /* create a parse tree node */
 ap_expr_t *ap_expr_make(ap_expr_node_op_e op, const void *arg1,
                         const void *arg2, ap_expr_parse_ctx_t *ctx);
+ap_expr_t *ap_expr_concat_make(const void *a1, const void *a2,
+                               ap_expr_parse_ctx_t *ctx);
+ap_expr_t *ap_expr_str_word_make(const ap_expr_t *arg,
+                                 ap_expr_parse_ctx_t *ctx);
+ap_expr_t *ap_expr_str_bool_make(const ap_expr_t *arg,
+                                 ap_expr_parse_ctx_t *ctx);
+ap_expr_t *ap_expr_regex_make(const char *pattern, const char *flags,
+                              const ap_expr_t *subst, int split,
+                              ap_expr_parse_ctx_t *ctx);
 /* create parse tree node for the string-returning function 'name' */
 ap_expr_t *ap_expr_str_func_make(const char *name, const ap_expr_t *arg,
                                ap_expr_parse_ctx_t *ctx);
 /* create parse tree node for the list-returning function 'name' */
 ap_expr_t *ap_expr_list_func_make(const char *name, const ap_expr_t *arg,
                                 ap_expr_parse_ctx_t *ctx);
+ap_expr_t *ap_expr_list_regex_make(const ap_expr_t *lst, const ap_expr_t *re,
+                                   ap_expr_parse_ctx_t *ctx);
 /* create parse tree node for the variable 'name' */
 ap_expr_t *ap_expr_var_make(const char *name, ap_expr_parse_ctx_t *ctx);
 /* create parse tree node for the unary operator 'name' */
index 2f014e5ba1aa565901c466cfa8562e110e339bd2..fdb9da7aa2c9e973a1d3d0ab588b9be593d6a4b8 100644 (file)
@@ -8,8 +8,8 @@
 
 #define FLEX_SCANNER
 #define YY_FLEX_MAJOR_VERSION 2
-#define YY_FLEX_MINOR_VERSION 5
-#define YY_FLEX_SUBMINOR_VERSION 35
+#define YY_FLEX_MINOR_VERSION 6
+#define YY_FLEX_SUBMINOR_VERSION 1
 #if YY_FLEX_SUBMINOR_VERSION > 0
 #define FLEX_BETA
 #endif
@@ -88,25 +88,13 @@ typedef unsigned int flex_uint32_t;
 
 #endif /* ! FLEXINT_H */
 
-#ifdef __cplusplus
-
-/* The "const" storage-class-modifier is valid. */
-#define YY_USE_CONST
-
-#else  /* ! __cplusplus */
-
-/* C99 requires __STDC__ to be defined as 1. */
-#if defined (__STDC__)
-
-#define YY_USE_CONST
-
-#endif /* defined (__STDC__) */
-#endif /* ! __cplusplus */
-
-#ifdef YY_USE_CONST
+/* TODO: this is always defined, so inline it */
 #define yyconst const
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define yynoreturn __attribute__((__noreturn__))
 #else
-#define yyconst
+#define yynoreturn
 #endif
 
 /* Returned upon end-of-file. */
@@ -179,11 +167,17 @@ typedef void* yyscan_t;
 typedef struct yy_buffer_state *YY_BUFFER_STATE;
 #endif
 
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
 #define EOB_ACT_CONTINUE_SCAN 0
 #define EOB_ACT_END_OF_FILE 1
 #define EOB_ACT_LAST_MATCH 2
 
     #define YY_LESS_LINENO(n)
+    #define YY_LINENO_REWIND_TO(ptr)
     
 /* Return all but the first "n" matched characters back to the input stream. */
 #define yyless(n) \
@@ -201,11 +195,6 @@ typedef struct yy_buffer_state *YY_BUFFER_STATE;
 
 #define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
 
-#ifndef YY_TYPEDEF_YY_SIZE_T
-#define YY_TYPEDEF_YY_SIZE_T
-typedef size_t yy_size_t;
-#endif
-
 #ifndef YY_STRUCT_YY_BUFFER_STATE
 #define YY_STRUCT_YY_BUFFER_STATE
 struct yy_buffer_state
@@ -218,7 +207,7 @@ struct yy_buffer_state
        /* Size of input buffer in bytes, not including room for EOB
         * characters.
         */
-       yy_size_t yy_buf_size;
+       int yy_buf_size;
 
        /* Number of characters read into yy_ch_buf, not including EOB
         * characters.
@@ -246,7 +235,7 @@ struct yy_buffer_state
 
     int yy_bs_lineno; /**< The line count. */
     int yy_bs_column; /**< The column count. */
-    
+
        /* Whether to try to fill the input buffer when we reach the
         * end of it.
         */
@@ -334,7 +323,7 @@ void ap_expr_yyfree (void * ,yyscan_t yyscanner );
 
 /* Begin user sect3 */
 
-#define ap_expr_yywrap(n) 1
+#define ap_expr_yywrap(yyscanner) (/*CONSTCOND*/1)
 #define YY_SKIP_YYWRAP
 
 typedef unsigned char YY_CHAR;
@@ -346,20 +335,20 @@ typedef int yy_state_type;
 static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
 static yy_state_type yy_try_NUL_trans (yy_state_type current_state  ,yyscan_t yyscanner);
 static int yy_get_next_buffer (yyscan_t yyscanner );
-static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
+static void yynoreturn yy_fatal_error (yyconst char* msg ,yyscan_t yyscanner );
 
 /* Done after the current pattern has been matched and before the
  * corresponding action - sets up yytext.
  */
 #define YY_DO_BEFORE_ACTION \
        yyg->yytext_ptr = yy_bp; \
-       yyleng = (size_t) (yy_cp - yy_bp); \
+       yyleng = (int) (yy_cp - yy_bp); \
        yyg->yy_hold_char = *yy_cp; \
        *yy_cp = '\0'; \
        yyg->yy_c_buf_p = yy_cp;
 
-#define YY_NUM_RULES 67
-#define YY_END_OF_BUFFER 68
+#define YY_NUM_RULES 74
+#define YY_END_OF_BUFFER 75
 /* This struct is not used in this scanner,
    but its presence is necessary. */
 struct yy_trans_info
@@ -367,40 +356,43 @@ struct yy_trans_info
        flex_int32_t yy_verify;
        flex_int32_t yy_nxt;
        };
-static yyconst flex_int16_t yy_accept[124] =
+static yyconst flex_int16_t yy_accept[157] =
     {   0,
         0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-        0,    0,   68,   66,    1,   43,    2,   66,   66,   66,
-       65,   66,   44,   26,   63,   32,   30,   34,   64,   64,
-       64,   64,   64,   64,   64,   64,   64,   64,   64,   66,
-       14,    4,    3,   17,   17,   67,   17,   23,    4,   22,
-       20,   21,   67,   16,   16,   24,   27,   29,   28,    1,
-       31,   37,   19,   18,   39,   63,   59,   59,   59,   59,
-       59,   59,   33,   30,   36,   35,   64,   64,   57,   64,
-       55,   54,   58,   53,   52,   25,   25,   56,   64,   40,
-       64,   41,   14,   13,   15,   12,    5,    6,   10,   11,
-
-        7,    8,    9,   20,   60,   46,   48,   50,   45,   49,
-       51,   47,   38,   64,   42,   64,    5,    6,   64,   61,
-        5,   62,    0
+        0,    0,    0,    0,    0,    0,    0,    0,   75,   73,
+       15,   14,    1,   15,   15,   15,   16,   46,   17,   73,
+       73,   73,   72,   73,   47,   27,   70,   73,   35,   33,
+       37,   71,   71,   71,   71,   71,   71,   71,   71,   71,
+       71,   71,   71,   71,   73,   26,   22,   21,   25,   24,
+       14,   24,   24,   24,   23,   66,   65,   29,   30,   14,
+       30,   30,   30,   31,    2,    3,   13,    6,    6,    5,
+       11,   12,    8,    9,   10,   13,   16,   34,   40,   32,
+       20,   42,   70,   63,   63,   63,   63,   63,   63,   19,
+
+       36,   33,   39,   38,   71,   71,   60,   71,   58,   57,
+       61,   71,   56,   55,   28,   28,   59,   71,   43,   71,
+       71,   44,   21,    4,    6,    6,    0,    5,    7,   18,
+       62,   49,   51,   53,   48,   52,   54,   50,   41,   71,
+       71,   45,   71,   71,    6,    5,    5,    5,    7,   71,
+       67,   71,   68,   69,   64,    0
     } ;
 
-static yyconst flex_int32_t yy_ec[256] =
+static yyconst YY_CHAR yy_ec[256] =
     {   0,
         1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    2,    4,    5,    6,    7,    8,    9,    5,   10,
        10,    1,    1,   11,   12,   13,   14,   15,   15,   15,
-       15,   15,   15,   15,   15,   16,   16,   17,    6,   18,
-       19,   20,    6,    1,   21,   21,   21,   21,   21,   21,
-       21,   21,   21,   21,   21,   21,   21,   21,   21,   21,
-       21,   21,   21,   21,   21,   21,   21,   21,   21,   21,
-        1,   22,    1,    6,   23,    1,   24,   25,   21,   26,
-
-       27,   28,   29,   21,   30,   21,   21,   31,   32,   33,
-       34,   21,   35,   36,   37,   38,   39,   21,   21,   21,
-       21,   21,   40,   41,   42,   43,    1,    1,    1,    1,
+       15,   16,   16,   16,   16,   17,   17,   18,    6,   19,
+       20,   21,    6,    1,   22,   22,   22,   22,   22,   22,
+       23,   23,   23,   23,   23,   23,   23,   23,   23,   23,
+       23,   23,   23,   23,   23,   23,   23,   23,   23,   23,
+        1,   24,    1,    6,   25,    1,   26,   27,   22,   28,
+
+       29,   30,   31,   23,   32,   33,   23,   34,   35,   36,
+       37,   38,   39,   40,   41,   42,   43,   23,   23,   44,
+       23,   23,   45,   46,   47,   48,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
@@ -417,129 +409,177 @@ static yyconst flex_int32_t yy_ec[256] =
         1,    1,    1,    1,    1
     } ;
 
-static yyconst flex_int32_t yy_meta[44] =
+static yyconst YY_CHAR yy_meta[49] =
     {   0,
-        1,    1,    2,    1,    2,    1,    2,    2,    1,    1,
-        1,    1,    1,    1,    3,    3,    1,    1,    1,    1,
-        3,    2,    3,    3,    3,    3,    3,    3,    3,    3,
-        3,    3,    3,    3,    3,    3,    3,    3,    3,    1,
-        1,    2,    1
+        1,    1,    2,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    3,    3,    3,    1,    1,    1,
+        1,    3,    4,    1,    4,    3,    3,    3,    3,    3,
+        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,
+        4,    4,    4,    4,    1,    1,    1,    1
     } ;
 
-static yyconst flex_int16_t yy_base[133] =
+static yyconst flex_uint16_t yy_base[171] =
     {   0,
-        0,    0,   41,   47,   89,    0,  130,  136,    0,    0,
-      147,  146,  175,  275,   54,   28,  275,   43,  134,  164,
-      275,  164,  275,  275,   45,  152,   32,  151,    0,  136,
-      133,  143,   26,  133,   35,  194,   38,  129,  128,  122,
-        0,  275,  275,   51,  122,  221,  275,  275,  275,  275,
-        0,  275,  275,   61,  121,  275,  275,  275,  275,   76,
-      275,  275,  275,  275,  275,   65,    0,  125,   47,  126,
-      107,  130,  275,  275,  275,  275,    0,  130,    0,  124,
-        0,    0,    0,    0,    0,  275,    0,    0,  104,    0,
-      101,  275,    0,  275,  275,  275,   71,  131,  275,  275,
-
-      275,  275,  275,    0,    0,    0,    0,    0,    0,    0,
-        0,    0,    0,   99,    0,   61,  133,  135,   57,    0,
-      138,    0,  275,  259,  262,  265,   79,   67,  268,  271,
-       65,   42
+        0,    0,    0,    6,   30,    0,   78,    0,  124,  126,
+      170,  213,    0,    0,  132,  134,    0,    0,  244,  455,
+      455,  455,  455,    0,  198,  245,   16,  116,  455,    5,
+      197,  232,  455,  275,  455,  455,   10,  193,  219,  118,
+      217,    0,  200,  196,  208,  101,  197,  195,  115,  308,
+      116,  190,  191,  188,  177,  455,  455,    0,  455,  455,
+      455,  144,  177,  340,  455,  455,  455,  455,  455,  455,
+      152,  170,  370,  455,  455,  196,  455,   13,  170,  174,
+      455,  455,  455,  455,  455,    0,  144,  455,  455,  455,
+      195,  455,  177,    0,  173,  120,  175,  123,  181,  455,
+
+      455,  455,  455,  455,    0,  181,    0,  174,    0,    0,
+        0,  175,    0,    0,  455,    0,    0,  164,    0,  171,
+      137,  455,    0,  455,  139,  181,  184,  187,    0,  455,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,  138,
+      136,    0,  138,  134,  455,  455,  455,  455,  455,  122,
+        0,   86,    0,    0,    0,  455,  414,  418,  422,  426,
+      430,  434,  438,  442,  444,  446,  448,    3,  450,    1
     } ;
 
-static yyconst flex_int16_t yy_def[133] =
+static yyconst flex_int16_t yy_def[171] =
     {   0,
-      123,    1,  124,  124,  123,    5,  124,  124,  125,  125,
-      126,  126,  123,  123,  123,  123,  123,  123,  123,  123,
-      123,  127,  123,  123,  123,  123,  123,  123,  128,  128,
-      128,  128,  128,  128,  128,  128,  128,  128,  128,  123,
-      129,  123,  123,  123,  123,  130,  123,  123,  123,  123,
-      131,  123,  123,  123,  123,  123,  123,  123,  123,  123,
-      123,  123,  123,  123,  123,  123,  132,  132,  132,  132,
-      132,  132,  123,  123,  123,  123,  128,  128,  128,  128,
-      128,  128,  128,  128,  128,  123,  128,  128,  128,  128,
-      128,  123,  129,  123,  123,  123,  123,  123,  123,  123,
-
-      123,  123,  123,  131,  132,  132,  132,  132,  132,  132,
-      132,  132,  128,  128,  128,  128,  123,  123,  128,  128,
-      123,  128,    0,  123,  123,  123,  123,  123,  123,  123,
-      123,  123
+      157,  157,  158,  158,  156,    5,  156,    7,  159,  159,
+      160,  160,  161,  161,  162,  162,  163,  163,  156,  156,
+      156,  156,  156,  156,  156,  164,  156,  156,  156,  156,
+      156,  156,  156,  165,  156,  156,  156,  156,  156,  156,
+      156,  166,  166,  166,  166,  166,  166,  166,  166,  166,
+      166,  166,   50,  166,  156,  156,  156,  167,  156,  156,
+      156,  156,  156,  164,  156,  156,  156,  156,  156,  156,
+      156,  156,  164,  156,  156,  156,  156,  156,  156,  156,
+      156,  156,  156,  156,  156,  168,  156,  156,  156,  156,
+      156,  156,  156,  169,  169,  169,  169,  169,  169,  156,
+
+      156,  156,  156,  156,  166,  166,  166,  166,  166,  166,
+      166,  166,  166,  166,  156,  166,  166,  166,  166,  166,
+      166,  156,  167,  156,  156,  156,  156,  156,  170,  156,
+      169,  169,  169,  169,  169,  169,  169,  169,  166,  166,
+      166,  166,  166,  166,  156,  156,  156,  156,  156,  166,
+      166,  166,  166,  166,  166,    0,  156,  156,  156,  156,
+      156,  156,  156,  156,  156,  156,  156,  156,  156,  156
     } ;
 
-static yyconst flex_int16_t yy_nxt[319] =
+static yyconst flex_uint16_t yy_nxt[504] =
     {   0,
-       14,   15,   15,   16,   17,   14,   18,   19,   20,   21,
-       21,   22,   23,   24,   25,   25,   21,   26,   27,   28,
-       29,   14,   14,   30,   29,   29,   31,   32,   33,   34,
-       35,   36,   37,   38,   29,   29,   29,   39,   29,   21,
-       40,   21,   14,   42,  105,   43,   61,   44,   45,   42,
-       74,   43,   81,   44,   45,   60,   60,   63,   63,   66,
-       66,   84,   46,   82,   88,   94,   94,  104,   46,   77,
-       62,   89,   85,  107,   75,   94,   94,   60,   60,   66,
-       66,   67,   47,  122,  108,  117,  118,  120,   47,   48,
-       48,   49,   48,   48,   48,   48,   48,   48,   48,   48,
-
-       48,   48,   48,   48,   48,   50,   48,   48,   48,   51,
-       48,   48,   51,   51,   51,   51,   51,   51,   51,   51,
-       51,   51,   51,   51,   51,   51,   51,   51,   48,   48,
-       52,   48,   42,  110,   53,  119,   54,   55,   42,  116,
-       53,  115,   54,   55,  111,  118,  118,  121,  118,  118,
-      118,   46,  118,  118,  114,  113,  112,   46,  109,  106,
-       95,   95,   92,   91,   90,   83,   80,   79,   78,   76,
-       73,   56,   65,   64,  123,   59,   59,   56,   66,   66,
-      123,  123,  123,  123,  123,  123,  123,  123,  123,  123,
-       68,  123,   69,   70,   71,  123,   72,   86,   86,   86,
-
-       86,   86,  123,  123,   86,   86,   86,   86,  123,  123,
-       86,  123,  123,  123,  123,  123,   87,  123,  123,  123,
-      123,  123,  123,  123,  123,  123,  123,  123,  123,  123,
-      123,  123,  123,  123,   86,   97,   98,  123,  123,  123,
-      123,  123,  123,  123,  123,   99,  123,  123,  100,  123,
-      123,  123,  123,  101,  123,  123,  102,  123,  103,   41,
-       41,   41,   57,   57,   57,   58,   58,   58,   93,  123,
-       93,   96,   96,   96,   13,  123,  123,  123,  123,  123,
-      123,  123,  123,  123,  123,  123,  123,  123,  123,  123,
-      123,  123,  123,  123,  123,  123,  123,  123,  123,  123,
-
-      123,  123,  123,  123,  123,  123,  123,  123,  123,  123,
-      123,  123,  123,  123,  123,  123,  123,  123
+      156,  156,   22,  149,   23,  129,   24,   25,   22,  156,
+       23,  156,   24,   25,   75,   75,   75,   87,   87,   90,
+       90,   90,  156,   26,   93,   93,   93,  125,  125,   26,
+       20,   27,   27,   28,   29,   20,   30,   31,   32,   33,
+       33,   34,   35,   36,   37,   37,   37,   38,   39,   40,
+       41,   42,   42,   20,   20,   43,   42,   42,   44,   45,
+       46,   47,   48,   49,   50,   51,   52,   42,   42,   42,
+       53,   54,   42,   42,   33,   55,   33,   20,   56,   56,
+       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,   56,   57,   56,   56,   56,   58,
+
+       58,   56,   56,   58,   58,   58,   58,   58,   58,   58,
+       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
+       58,   58,   56,   56,   59,   56,   61,  155,   61,  109,
+       62,   63,   62,   63,   70,   88,   70,  102,   71,   72,
+       71,   72,  110,  113,  117,   87,   87,   64,  133,   64,
+      154,  136,  118,  145,  145,   73,  114,   73,   75,   75,
+       75,  134,  153,   89,  137,  103,   75,   75,   75,  152,
+       65,  151,   65,   67,   67,   67,   67,   67,  150,  144,
+       67,   67,   67,   67,  126,  126,  127,   67,  128,  128,
+      128,   93,   93,   93,   67,  146,  146,  147,  147,  147,
+
+      147,  148,  148,  148,  143,  142,  141,  140,  139,  138,
+      135,  132,  130,  124,   76,   67,   67,   67,   67,   67,
+       67,   76,  122,   67,   67,   67,   67,  121,  120,  119,
+       67,  112,  111,  108,  107,  106,  104,   67,  101,  100,
+       92,   91,   76,  156,  156,  156,  156,  156,  156,  156,
+      156,  156,  156,  156,  156,  156,  156,  156,   67,   78,
+       79,   80,  156,  156,  156,  156,  156,  156,  156,  156,
+      156,   81,  156,  156,   82,  156,  156,  156,  156,  156,
+       83,  156,  156,  156,   84,  156,   85,  156,   86,   93,
+       93,   93,  156,  156,  156,  156,  156,  156,  156,  156,
+
+      156,  156,  156,   95,  156,   96,   97,  156,   98,  156,
+       99,  115,  115,  115,  115,  115,  156,  156,  115,  115,
+      115,  115,  156,  156,  156,  115,  156,  156,  156,  156,
+      156,  156,  116,  156,  156,  156,  156,  156,  156,  156,
+      156,  156,  156,  156,  156,  156,  156,  156,  156,  156,
+      156,  156,  156,  115,   78,   79,   80,  156,  156,  156,
+      156,  156,  156,  156,  156,  156,   81,  156,  156,   82,
+      156,  156,  156,  156,  156,   83,  156,  156,  156,   84,
+      156,   85,  156,   86,   78,   79,   80,  156,  156,  156,
+      156,  156,  156,  156,  156,  156,   81,  156,  156,   82,
+
+      156,  156,  156,  156,  156,   83,  156,  156,  156,   84,
+      156,   85,  156,   86,   20,   20,   20,   20,   21,   21,
+       21,   21,   60,   60,   60,   60,   66,   66,   66,   66,
+       68,   68,   68,   68,   69,   69,   69,   69,   74,   74,
+       74,   74,   77,  156,   77,   77,   94,   94,  105,  105,
+      123,  123,  131,  131,   19,  156,  156,  156,  156,  156,
+      156,  156,  156,  156,  156,  156,  156,  156,  156,  156,
+      156,  156,  156,  156,  156,  156,  156,  156,  156,  156,
+      156,  156,  156,  156,  156,  156,  156,  156,  156,  156,
+      156,  156,  156,  156,  156,  156,  156,  156,  156,  156,
+
+      156,  156,  156
     } ;
 
-static yyconst flex_int16_t yy_chk[319] =
+static yyconst flex_int16_t yy_chk[504] =
     {   0,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    3,  132,    3,   16,    3,    3,    4,
-       27,    4,   33,    4,    4,   15,   15,   18,   18,   25,
-       25,   35,    3,   33,   37,   44,   44,  131,    4,  128,
-       16,   37,   35,   69,   27,   54,   54,   60,   60,   66,
-       66,  127,    3,  119,   69,   97,   97,  116,    4,    5,
+        0,    0,    3,  170,    3,  168,    3,    3,    4,    0,
+        4,    0,    4,    4,   24,   24,   24,   27,   27,   30,
+       30,   30,    0,    3,   37,   37,   37,   78,   78,    4,
         5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
-
         5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
         5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
         5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
-        5,    5,    7,   71,    7,  114,    7,    7,    8,   91,
-        8,   89,    8,    8,   71,   98,   98,  117,  117,  118,
-      118,    7,  121,  121,   80,   78,   72,    8,   70,   68,
-       55,   45,   40,   39,   38,   34,   32,   31,   30,   28,
-       26,    7,   20,   19,   13,   12,   11,    8,   22,   22,
+        5,    5,    5,    5,    5,    5,    5,    5,    7,    7,
+        7,    7,    7,    7,    7,    7,    7,    7,    7,    7,
+        7,    7,    7,    7,    7,    7,    7,    7,    7,    7,
+
+        7,    7,    7,    7,    7,    7,    7,    7,    7,    7,
+        7,    7,    7,    7,    7,    7,    7,    7,    7,    7,
+        7,    7,    7,    7,    7,    7,    9,  152,   10,   46,
+        9,    9,   10,   10,   15,   28,   16,   40,   15,   15,
+       16,   16,   46,   49,   51,   87,   87,    9,   96,   10,
+      150,   98,   51,  125,  125,   15,   49,   16,   62,   62,
+       62,   96,  144,   28,   98,   40,   71,   71,   71,  143,
+        9,  141,   10,   11,   11,   11,   11,   11,  140,  121,
+       11,   11,   11,   11,   79,   79,   79,   11,   80,   80,
+       80,   93,   93,   93,   11,  126,  126,  126,  127,  127,
+
+      127,  128,  128,  128,  120,  118,  112,  108,  106,   99,
+       97,   95,   91,   76,   72,   11,   12,   12,   12,   12,
+       12,   63,   55,   12,   12,   12,   12,   54,   53,   52,
+       12,   48,   47,   45,   44,   43,   41,   12,   39,   38,
+       32,   31,   25,   19,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,   12,   26,
+       26,   26,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,   26,    0,    0,   26,    0,    0,    0,    0,    0,
+       26,    0,    0,    0,   26,    0,   26,    0,   26,   34,
+       34,   34,    0,    0,    0,    0,    0,    0,    0,    0,
+
+        0,    0,    0,   34,    0,   34,   34,    0,   34,    0,
+       34,   50,   50,   50,   50,   50,    0,    0,   50,   50,
+       50,   50,    0,    0,    0,   50,    0,    0,    0,    0,
+        0,    0,   50,    0,    0,    0,    0,    0,    0,    0,
         0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-       22,    0,   22,   22,   22,    0,   22,   36,   36,   36,
-
-       36,   36,    0,    0,   36,   36,   36,   36,    0,    0,
-       36,    0,    0,    0,    0,    0,   36,    0,    0,    0,
-        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-        0,    0,    0,    0,   36,   46,   46,    0,    0,    0,
-        0,    0,    0,    0,    0,   46,    0,    0,   46,    0,
-        0,    0,    0,   46,    0,    0,   46,    0,   46,  124,
-      124,  124,  125,  125,  125,  126,  126,  126,  129,    0,
-      129,  130,  130,  130,  123,  123,  123,  123,  123,  123,
-      123,  123,  123,  123,  123,  123,  123,  123,  123,  123,
-      123,  123,  123,  123,  123,  123,  123,  123,  123,  123,
-
-      123,  123,  123,  123,  123,  123,  123,  123,  123,  123,
-      123,  123,  123,  123,  123,  123,  123,  123
+        0,    0,    0,   50,   64,   64,   64,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,   64,    0,    0,   64,
+        0,    0,    0,    0,    0,   64,    0,    0,    0,   64,
+        0,   64,    0,   64,   73,   73,   73,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,   73,    0,    0,   73,
+
+        0,    0,    0,    0,    0,   73,    0,    0,    0,   73,
+        0,   73,    0,   73,  157,  157,  157,  157,  158,  158,
+      158,  158,  159,  159,  159,  159,  160,  160,  160,  160,
+      161,  161,  161,  161,  162,  162,  162,  162,  163,  163,
+      163,  163,  164,    0,  164,  164,  165,  165,  166,  166,
+      167,  167,  169,  169,  156,  156,  156,  156,  156,  156,
+      156,  156,  156,  156,  156,  156,  156,  156,  156,  156,
+      156,  156,  156,  156,  156,  156,  156,  156,  156,  156,
+      156,  156,  156,  156,  156,  156,  156,  156,  156,  156,
+      156,  156,  156,  156,  156,  156,  156,  156,  156,  156,
+
+      156,  156,  156
     } ;
 
 /* The intent behind this definition is that it'll catch
@@ -577,12 +617,12 @@ static yyconst flex_int16_t yy_chk[319] =
 
 
 
-
 #line 43 "util_expr_scan.l"
 #include "util_expr_private.h"
 #include "util_expr_parse.h"
 #include "http_main.h"
 #include "http_log.h"
+#include "apr_lib.h"
 
 #undef  YY_INPUT
 #define YY_INPUT(buf,result,max_size)                       \
@@ -604,37 +644,113 @@ static yyconst flex_int16_t yy_chk[319] =
  * XXX: longjmp. It is not clear if the scanner is in any state
  * XXX: to be cleaned up, though.
  */
+static int unreachable = 0;
 #define YY_FATAL_ERROR(msg)                                     \
     do {                                                        \
         ap_log_error(APLOG_MARK, APLOG_CRIT, 0, ap_server_conf, \
                      APLOGNO(03296)                             \
                      "expr parser fatal error (BUG?): "         \
                      "%s, exiting", msg);                       \
-         abort();                                               \
+        if (unreachable) {                                      \
+            /* Not reached, silence [-Wunused-function] */      \
+            yy_fatal_error(msg, yyscanner);                     \
+        }                                                       \
+        else {                                                  \
+            abort();                                            \
+        }                                                       \
     } while (0)
 
 #define YY_EXTRA_TYPE ap_expr_parse_ctx_t*
 
-#define PERROR(msg) do { yyextra->error2 = msg ; return T_ERROR; } while (0)
+#define PERROR(msg) do {    \
+    yyextra->error2 = msg;  \
+    return T_ERROR;         \
+} while (0)
+
+#define PERROR_CHAR(prefix, chr) do {                                       \
+    char *msg;                                                              \
+    if (apr_isprint((chr))) {                                               \
+        msg = apr_psprintf(yyextra->pool, prefix "'%c'", (char)(chr));      \
+    }                                                                       \
+    else {                                                                  \
+        msg = apr_psprintf(yyextra->pool, prefix "'\\x%.2X'", (int)(chr));  \
+    }                                                                       \
+    PERROR(msg);                                                            \
+} while (0)
+
+#define STACK_PUSH() do {                               \
+    ap_expr_parser_stack_t *sk;                         \
+    if (yyextra->spares) {                              \
+        sk = yyextra->spares;                           \
+        yyextra->spares = sk->next;                     \
+    }                                                   \
+    else {                                              \
+        sk = apr_palloc(yyextra->ptemp, sizeof(*sk));   \
+    }                                                   \
+    sk->scan_ptr  = sk->scan_buf;                       \
+    sk->scan_stop = sk->scan_buf[0] = '\0';             \
+    sk->scan_flag = 0;                                  \
+    sk->next = yyextra->current;                        \
+    yyextra->current = sk;                              \
+} while (0)
+
+#define STACK_POP() do {            \
+    ap_expr_parser_stack_t *sk;     \
+    sk = yyextra->current;          \
+    yyextra->current = sk->next;    \
+    sk->next = yyextra->spares;     \
+    yyextra->spares = sk;           \
+} while (0)
+
+#define STATE_PUSH(st, sk) do {     \
+    yy_push_state((st), yyscanner); \
+    if ((sk)) {                     \
+        STACK_PUSH();               \
+    }                               \
+} while (0)
+
+#define STATE_POP(sk) do {          \
+    if ((sk)) {                     \
+        STACK_POP();                \
+    }                               \
+    yy_pop_state(yyscanner);        \
+} while (0)
+
+#define str_ptr  (yyextra->current->scan_ptr)
+#define str_buf  (yyextra->current->scan_buf)
+#define str_stop (yyextra->current->scan_stop)
+#define str_flag (yyextra->current->scan_flag)
+
+#define STR_APPEND_CHECK(chr, chk) do {                     \
+    if ((chk) && apr_iscntrl((chr))) {                      \
+        PERROR_CHAR("Invalid string character ", (chr));    \
+    }                                                       \
+    if (str_ptr >= str_buf + sizeof(str_buf) - 1) {         \
+        PERROR("String too long");                          \
+    }                                                       \
+    *str_ptr++ = (char)(chr);                               \
+} while (0)
 
-#define str_ptr     (yyextra->scan_ptr)
-#define str_buf     (yyextra->scan_buf)
-#define str_del     (yyextra->scan_del)
+#define STR_APPEND_NOCHECK(chr) \
+    STR_APPEND_CHECK((chr), 0)
 
-#define STR_APPEND(c) do {                          \
-        *str_ptr++ = (c);                           \
-        if (str_ptr >= str_buf + sizeof(str_buf))   \
-            PERROR("String too long");              \
-    } while (0)
+#define STR_EMPTY() \
+    (str_ptr == str_buf)
 
-#line 630 "util_expr_scan.c"
+#define STR_RETURN() \
+    (apr_pstrdup(yyextra->pool, (*str_ptr = '\0', str_ptr = str_buf)))
+
+#line 744 "util_expr_scan.c"
 
 #define INITIAL 0
 #define str 1
-#define var 2
-#define vararg 3
-#define regex 4
-#define regex_flags 5
+#define expr 2
+#define var 3
+#define vararg 4
+#define split 5
+#define regex 6
+#define regsub 7
+#define regflags 8
 
 #ifndef YY_NO_UNISTD_H
 /* Special case for "unistd.h", since it is non-ANSI. We include it way
@@ -709,19 +825,23 @@ void ap_expr_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
 
 FILE *ap_expr_yyget_in (yyscan_t yyscanner );
 
-void ap_expr_yyset_in  (FILE * in_str ,yyscan_t yyscanner );
+void ap_expr_yyset_in  (FILE * _in_str ,yyscan_t yyscanner );
 
 FILE *ap_expr_yyget_out (yyscan_t yyscanner );
 
-void ap_expr_yyset_out  (FILE * out_str ,yyscan_t yyscanner );
+void ap_expr_yyset_out  (FILE * _out_str ,yyscan_t yyscanner );
 
-int ap_expr_yyget_leng (yyscan_t yyscanner );
+                       int ap_expr_yyget_leng (yyscan_t yyscanner );
 
 char *ap_expr_yyget_text (yyscan_t yyscanner );
 
 int ap_expr_yyget_lineno (yyscan_t yyscanner );
 
-void ap_expr_yyset_lineno (int line_number ,yyscan_t yyscanner );
+void ap_expr_yyset_lineno (int _line_number ,yyscan_t yyscanner );
+
+int ap_expr_yyget_column  (yyscan_t yyscanner );
+
+void ap_expr_yyset_column (int _column_no ,yyscan_t yyscanner );
 
 YYSTYPE * ap_expr_yyget_lval (yyscan_t yyscanner );
 
@@ -739,6 +859,10 @@ extern int ap_expr_yywrap (yyscan_t yyscanner );
 #endif
 #endif
 
+#ifndef YY_NO_UNPUT
+    
+#endif
+
 #ifndef yytext_ptr
 static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
 #endif
@@ -757,7 +881,7 @@ static int input (yyscan_t yyscanner );
 
 #endif
 
-    static void yy_push_state (int new_state ,yyscan_t yyscanner);
+    static void yy_push_state (int _new_state ,yyscan_t yyscanner);
     
     static void yy_pop_state (yyscan_t yyscanner );
     
@@ -776,7 +900,7 @@ static int input (yyscan_t yyscanner );
 /* This used to be an fputs(), but since the string might contain NUL's,
  * we now use fwrite().
  */
-#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
+#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0)
 #endif
 
 /* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
@@ -800,7 +924,7 @@ static int input (yyscan_t yyscanner );
        else \
                { \
                errno=0; \
-               while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+               while ( (result = (int) fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
                        { \
                        if( errno != EINTR) \
                                { \
@@ -857,7 +981,7 @@ extern int ap_expr_yylex \
 
 /* Code executed at the end of each rule. */
 #ifndef YY_BREAK
-#define YY_BREAK break;
+#define YY_BREAK /*LINTED*/break;
 #endif
 
 #define YY_RULE_SETUP \
@@ -867,39 +991,11 @@ extern int ap_expr_yylex \
  */
 YY_DECL
 {
-       register yy_state_type yy_current_state;
-       register char *yy_cp, *yy_bp;
-       register int yy_act;
+       yy_state_type yy_current_state;
+       char *yy_cp, *yy_bp;
+       int yy_act;
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
-#line 93 "util_expr_scan.l"
-
-
-  char  regex_buf[MAX_STRING_LEN];
-  char *regex_ptr = NULL;
-  char  regex_del = '\0';
-
-
- /*
-  * Set initial state for string expressions
-  */
-  if (yyextra->at_start) {
-    yyextra->at_start = 0;
-    if (yyextra->flags & AP_EXPR_FLAG_STRING_RESULT) {
-        BEGIN(str);
-        return T_EXPR_STRING;
-    }
-    else {
-        return T_EXPR_BOOL;
-    }
-  }
-
-
- /*
-  * Whitespaces
-  */
-#line 901 "util_expr_scan.c"
-
     yylval = yylval_param;
 
        if ( !yyg->yy_init )
@@ -928,7 +1024,33 @@ YY_DECL
                ap_expr_yy_load_buffer_state(yyscanner );
                }
 
-       while ( 1 )             /* loops until end-of-file is reached */
+       {
+#line 179 "util_expr_scan.l"
+
+
+
+ /*
+  * Set initial state for string expressions
+  */
+  if (yyextra->at_start) {
+    yyextra->at_start = 0;
+    if (yyextra->flags & AP_EXPR_FLAG_STRING_RESULT) {
+        STATE_PUSH(str, 1);
+        return T_EXPR_STRING;
+    }
+    else {
+        STATE_PUSH(expr, 1);
+        return T_EXPR_BOOL;
+    }
+  }
+
+
+ /*
+  * Back off INITIAL pushes
+  */
+#line 1052 "util_expr_scan.c"
+
+       while ( /*CONSTCOND*/1 )                /* loops until end-of-file is reached */
                {
                yy_cp = yyg->yy_c_buf_p;
 
@@ -944,7 +1066,7 @@ YY_DECL
 yy_match:
                do
                        {
-                       register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+                       YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
                        if ( yy_accept[yy_current_state] )
                                {
                                yyg->yy_last_accepting_state = yy_current_state;
@@ -953,13 +1075,13 @@ yy_match:
                        while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
                                {
                                yy_current_state = (int) yy_def[yy_current_state];
-                               if ( yy_current_state >= 124 )
+                               if ( yy_current_state >= 157 )
                                        yy_c = yy_meta[(unsigned int) yy_c];
                                }
-                       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+                       yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c];
                        ++yy_cp;
                        }
-               while ( yy_current_state != 123 );
+               while ( yy_current_state != 156 );
                yy_cp = yyg->yy_last_accepting_cpos;
                yy_current_state = yyg->yy_last_accepting_state;
 
@@ -979,519 +1101,577 @@ do_action:     /* This label is used only to access EOF actions. */
                        yy_current_state = yyg->yy_last_accepting_state;
                        goto yy_find_action;
 
-case 1:
-/* rule 1 can match eol */
-YY_RULE_SETUP
-#line 118 "util_expr_scan.l"
-{ 
-    /* NOP */
+case YY_STATE_EOF(str):
+#line 201 "util_expr_scan.l"
+{
+    STATE_POP(0); /* <str> */
+    if (YY_START != INITIAL) {
+        PERROR("Unterminated string");
+    }
+    yylval->cpVal = STR_RETURN();
+    STACK_POP(); /* ^ after this */
+    return T_STRING;
 }
        YY_BREAK
-/*
-  * strings ("..." and '...')
-  */
-case 2:
-YY_RULE_SETUP
-#line 125 "util_expr_scan.l"
+case YY_STATE_EOF(expr):
+#line 210 "util_expr_scan.l"
 {
-    str_ptr = str_buf;
-    str_del = yytext[0];
-    BEGIN(str);
-    return T_STR_BEGIN;
+    STATE_POP(1); /* <expr> */
+    if (YY_START != INITIAL) {
+        PERROR("Unterminated expression");
+    }
 }
        YY_BREAK
-case 3:
+case 1:
 YY_RULE_SETUP
-#line 131 "util_expr_scan.l"
+#line 217 "util_expr_scan.l"
 {
-    if (yytext[0] == str_del) {
-        if (YY_START == var) {
-            PERROR("Unterminated variable in string");
-        }
-        else if (str_ptr == str_buf) {
-            BEGIN(INITIAL);
-            return T_STR_END;
-        }
-        else {
-            /* return what we have so far and scan delimiter again */
-            *str_ptr = '\0';
-            yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
-            yyless(0);
-            str_ptr = str_buf;
+    if (yytext[0] == str_stop) {
+        if (!STR_EMPTY()) {
+            yyless(0); /* come back below */
+            yylval->cpVal = STR_RETURN();
             return T_STRING;
         }
+        STATE_POP(1); /* <str> */
+        return T_STR_END;
     }
-    else {
-        STR_APPEND(yytext[0]);
-    }
+    STR_APPEND_NOCHECK(yytext[0]);
 }
        YY_BREAK
-case 4:
-/* rule 4 can match eol */
+/* regexp backref inside string/arg */
+case 2:
 YY_RULE_SETUP
-#line 153 "util_expr_scan.l"
+#line 231 "util_expr_scan.l"
 {
-    PERROR("Unterminated string or variable");
+    if (!STR_EMPTY()) {
+        yyless(0); /* come back below */
+        yylval->cpVal = STR_RETURN();
+        return T_STRING;
+    }
+    yylval->num = yytext[1] - '0';
+    return T_REG_REF;
 }
        YY_BREAK
-case YY_STATE_EOF(var):
-case YY_STATE_EOF(vararg):
-#line 156 "util_expr_scan.l"
+/* variable inside string/arg */
+case 3:
+YY_RULE_SETUP
+#line 242 "util_expr_scan.l"
 {
-    PERROR("Unterminated string or variable");
+    if (!STR_EMPTY()) {
+        yyless(0); /* come back below */
+        yylval->cpVal = STR_RETURN();
+        return T_STRING;
+    }
+    STATE_PUSH(var, 1);
+    return T_VAR_BEGIN;
 }
        YY_BREAK
-case YY_STATE_EOF(str):
-#line 159 "util_expr_scan.l"
+case 4:
+YY_RULE_SETUP
+#line 252 "util_expr_scan.l"
 {
-    if (!(yyextra->flags & AP_EXPR_FLAG_STRING_RESULT)) {
-        PERROR("Unterminated string or variable");
-    }
-    else {
-        *str_ptr = '\0';
-        yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
-        str_ptr = str_buf;
-        BEGIN(INITIAL);
+    if (!STR_EMPTY()) {
+        yyless(0); /* come back below */
+        yylval->cpVal = STR_RETURN();
         return T_STRING;
     }
+    STATE_PUSH(expr, 1);
+    return T_VAREXP_BEGIN;
 }
        YY_BREAK
+/* Any non-octal or octal higher than 377 (decimal 255) is invalid */
 case 5:
 YY_RULE_SETUP
-#line 172 "util_expr_scan.l"
+#line 263 "util_expr_scan.l"
 {
-    int result;
-
-    (void)sscanf(yytext+1, "%o", &result);
-    if (result > 0xff) {
-        PERROR("Escape sequence out of bound");
-    }
-    else {
-        STR_APPEND(result);
-    }
+    PERROR("Bad character escape sequence");
 }
        YY_BREAK
 case 6:
 YY_RULE_SETUP
-#line 183 "util_expr_scan.l"
+#line 266 "util_expr_scan.l"
 {
-    PERROR("Bad escape sequence");
+    int result;
+    (void)sscanf(yytext+1, "%o", &result);
+    STR_APPEND_NOCHECK(result);
 }
        YY_BREAK
 case 7:
 YY_RULE_SETUP
-#line 186 "util_expr_scan.l"
-{ STR_APPEND('\n'); }
+#line 271 "util_expr_scan.l"
+{
+    int result;
+    (void)sscanf(yytext+1, "%x", &result);
+    STR_APPEND_NOCHECK(result);
+}
        YY_BREAK
 case 8:
 YY_RULE_SETUP
-#line 187 "util_expr_scan.l"
-{ STR_APPEND('\r'); }
+#line 276 "util_expr_scan.l"
+{ STR_APPEND_NOCHECK('\n'); }
        YY_BREAK
 case 9:
 YY_RULE_SETUP
-#line 188 "util_expr_scan.l"
-{ STR_APPEND('\t'); }
+#line 277 "util_expr_scan.l"
+{ STR_APPEND_NOCHECK('\r'); }
        YY_BREAK
 case 10:
 YY_RULE_SETUP
-#line 189 "util_expr_scan.l"
-{ STR_APPEND('\b'); }
+#line 278 "util_expr_scan.l"
+{ STR_APPEND_NOCHECK('\t'); }
        YY_BREAK
 case 11:
 YY_RULE_SETUP
-#line 190 "util_expr_scan.l"
-{ STR_APPEND('\f'); }
+#line 279 "util_expr_scan.l"
+{ STR_APPEND_NOCHECK('\b'); }
        YY_BREAK
 case 12:
-/* rule 12 can match eol */
 YY_RULE_SETUP
-#line 191 "util_expr_scan.l"
-{ STR_APPEND(yytext[1]); }
+#line 280 "util_expr_scan.l"
+{ STR_APPEND_NOCHECK('\f'); }
        YY_BREAK
-/* regexp backref inside string/arg */
 case 13:
 YY_RULE_SETUP
-#line 194 "util_expr_scan.l"
-{
-    if (str_ptr != str_buf) {
-        /* return what we have so far and scan '$x' again */
-        *str_ptr = '\0';
-        yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
-        str_ptr = str_buf;
-        yyless(0);
-        return T_STRING;
-    }
-    else {
-        yylval->num = yytext[1] - '0';
-        return T_REGEX_BACKREF;
-    }
-}
+#line 281 "util_expr_scan.l"
+{ STR_APPEND_CHECK(yytext[1], 1); }
        YY_BREAK
 case 14:
+/* rule 14 can match eol */
 YY_RULE_SETUP
-#line 209 "util_expr_scan.l"
+#line 283 "util_expr_scan.l"
 {
-    char *cp = yytext;
-    while (*cp != '\0') {
-        STR_APPEND(*cp);
-        cp++;
-    }
+    PERROR("Unterminated string or variable");
 }
        YY_BREAK
-/* variable inside string/arg */
 case 15:
+/* rule 15 can match eol */
 YY_RULE_SETUP
-#line 218 "util_expr_scan.l"
+#line 287 "util_expr_scan.l"
 {
-    if (str_ptr != str_buf) {
-        /* return what we have so far and scan '%{' again */
-        *str_ptr = '\0';
-        yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
-        yyless(0);
-        str_ptr = str_buf;
-        return T_STRING;
-    }
-    else {
-        yy_push_state(var, yyscanner);
-        return T_VAR_BEGIN;
-    }
+    STR_APPEND_CHECK(yytext[0], 1);
 }
        YY_BREAK
 case 16:
+/* rule 16 can match eol */
 YY_RULE_SETUP
-#line 233 "util_expr_scan.l"
-{
-     STR_APPEND(yytext[0]);
+#line 291 "util_expr_scan.l"
+{ 
+    /* NOP */
 }
        YY_BREAK
 case 17:
 YY_RULE_SETUP
-#line 237 "util_expr_scan.l"
+#line 295 "util_expr_scan.l"
 {
-     STR_APPEND(yytext[0]);
+    STATE_PUSH(str, 1);
+    str_stop = yytext[0];
+    return T_STR_BEGIN;
 }
        YY_BREAK
 case 18:
 YY_RULE_SETUP
-#line 241 "util_expr_scan.l"
+#line 301 "util_expr_scan.l"
 {
-    yy_push_state(var, yyscanner);
-    return T_VAR_BEGIN;
+    STATE_PUSH(expr, 1);
+    return T_VAREXP_BEGIN;
 }
        YY_BREAK
 case 19:
 YY_RULE_SETUP
-#line 246 "util_expr_scan.l"
+#line 305 "util_expr_scan.l"
 {
-    yylval->num = yytext[1] - '0';
-    return T_REGEX_BACKREF;
+    STATE_POP(1); /* <expr> */
+    return T_VAREXP_END;
 }
        YY_BREAK
-/*
-  * fixed name variable expansion %{XXX} and function call in %{func:arg} syntax
-  */
 case 20:
 YY_RULE_SETUP
-#line 254 "util_expr_scan.l"
+#line 311 "util_expr_scan.l"
 {
-    yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
-    return T_ID;
+    STATE_PUSH(var, 1);
+    return T_VAR_BEGIN;
 }
        YY_BREAK
 case 21:
 YY_RULE_SETUP
-#line 259 "util_expr_scan.l"
+#line 315 "util_expr_scan.l"
 {
-    yy_pop_state(yyscanner);
-    return T_VAR_END;
+    yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
+    return T_ID;
 }
        YY_BREAK
 case 22:
 YY_RULE_SETUP
-#line 264 "util_expr_scan.l"
+#line 319 "util_expr_scan.l"
 {
-    BEGIN(vararg);
+    STATE_PUSH(vararg, 0);
     return yytext[0];
 }
        YY_BREAK
 case 23:
-/* rule 23 can match eol */
 YY_RULE_SETUP
-#line 269 "util_expr_scan.l"
+#line 323 "util_expr_scan.l"
 {
-    char *msg = apr_psprintf(yyextra->pool,
-                             "Invalid character in variable name '%c'", yytext[0]);
-    PERROR(msg);
+    yyless(0); /* let <var> handle */
+    yylval->cpVal = STR_RETURN();
+    STATE_POP(0); /* <vararg> */
+    return T_STRING;
 }
        YY_BREAK
 case 24:
+/* rule 24 can match eol */
 YY_RULE_SETUP
-#line 275 "util_expr_scan.l"
+#line 329 "util_expr_scan.l"
 {
-    if (str_ptr != str_buf) {
-        /* return what we have so far and scan '}' again */
-        *str_ptr = '\0';
-        yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
-        str_ptr = str_buf;
-        yyless(0);
-        return T_STRING;
-    }
-    else {
-        yy_pop_state(yyscanner);
-        return T_VAR_END;
-    }
+    STR_APPEND_CHECK(yytext[0], 1);
 }
        YY_BREAK
-/*
-  * Regular Expression
-  */
 case 25:
 YY_RULE_SETUP
-#line 293 "util_expr_scan.l"
+#line 332 "util_expr_scan.l"
 {
-    regex_del = yytext[1];
-    regex_ptr = regex_buf;
-    BEGIN(regex);
+    STATE_POP(1); /* <var> */
+    return T_VAR_END;
 }
        YY_BREAK
 case 26:
+/* rule 26 can match eol */
 YY_RULE_SETUP
-#line 298 "util_expr_scan.l"
+#line 336 "util_expr_scan.l"
 {
-    regex_del = yytext[0];
-    regex_ptr = regex_buf;
-    BEGIN(regex);
+    PERROR_CHAR("Unexpected variable character ", yytext[0]);
 }
        YY_BREAK
+case YY_STATE_EOF(var):
+case YY_STATE_EOF(vararg):
+#line 339 "util_expr_scan.l"
+{
+    PERROR("Unterminated variable");
+}
+       YY_BREAK
+/*
+  * Regular Expression
+  */
 case 27:
-/* rule 27 can match eol */
 YY_RULE_SETUP
-#line 303 "util_expr_scan.l"
+#line 347 "util_expr_scan.l"
 {
-    if (yytext[0] == regex_del) {
-        *regex_ptr = '\0';
-        BEGIN(regex_flags);
-    }
-    else {
-        *regex_ptr++ = yytext[0];
-        if (regex_ptr >= regex_buf + sizeof(regex_buf))
-            PERROR("Regexp too long");
-    }
+    STATE_PUSH(regex, 1);
+    str_stop = yytext[0];
+    str_flag = 'm';
+    return T_REGEX;
 }
        YY_BREAK
 case 28:
 YY_RULE_SETUP
-#line 314 "util_expr_scan.l"
+#line 353 "util_expr_scan.l"
 {
-    yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf);
-    BEGIN(INITIAL);
-    return T_REGEX_I;
+    STATE_PUSH(regex, 1);
+    str_stop = yytext[1];
+    str_flag = yytext[0];
+    return (str_flag == 'm') ? T_REGEX : T_REGSUB;
 }
        YY_BREAK
 case 29:
 /* rule 29 can match eol */
 YY_RULE_SETUP
-#line 319 "util_expr_scan.l"
+#line 359 "util_expr_scan.l"
 {
-    yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf);
-    yyless(0);
-    BEGIN(INITIAL);
-    return T_REGEX;
+    if (yytext[0] == str_stop) {
+        STATE_POP(0); /* <regex> */
+        if (str_flag == 'm') {
+            STATE_PUSH(regflags, 0);
+        }
+        else {
+            STATE_PUSH(regsub, 0);
+        }
+        yylval->cpVal = STR_RETURN();
+        return T_REG_MATCH;
+    }
+    STR_APPEND_CHECK(yytext[0], 1);
 }
        YY_BREAK
-case YY_STATE_EOF(regex_flags):
-#line 325 "util_expr_scan.l"
+case 30:
+/* rule 30 can match eol */
+YY_RULE_SETUP
+#line 373 "util_expr_scan.l"
 {
-    yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf);
-    BEGIN(INITIAL);
-    return T_REGEX;
+    if (yytext[0] == str_stop) {
+        STATE_POP(0); /* <regsub> */
+        STATE_PUSH(regflags, 0);
+    }
+    else {
+        STR_APPEND_CHECK(yytext[0], 1);
+    }
+}
+       YY_BREAK
+case 31:
+/* rule 31 can match eol */
+YY_RULE_SETUP
+#line 382 "util_expr_scan.l"
+{
+    if (ap_strchr_c("ismg", yytext[0])) {
+        STR_APPEND_NOCHECK(yytext[0]);
+    }
+    else if (apr_isalnum(yytext[0])) {
+        PERROR("Invalid regexp flag(s)");
+    }
+    else {
+        yyless(0); /* not a flags, rewind */
+        yylval->cpVal = STR_RETURN();
+        STATE_POP(1); /* <regflags> */
+        return T_REG_FLAGS;
+    }
+}
+       YY_BREAK
+case YY_STATE_EOF(regflags):
+#line 396 "util_expr_scan.l"
+{
+    yylval->cpVal = STR_RETURN();
+    STATE_POP(1); /* <regflags> */
+    return T_REG_FLAGS;
+}
+       YY_BREAK
+case YY_STATE_EOF(regex):
+case YY_STATE_EOF(regsub):
+#line 401 "util_expr_scan.l"
+{
+    PERROR("Unterminated regexp");
+}
+       YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 405 "util_expr_scan.l"
+{
+    yylval->num = yytext[1] - '0';
+    return T_REG_REF;
 }
        YY_BREAK
 /*
   * Operators
   */
-case 30:
+case 33:
 YY_RULE_SETUP
-#line 334 "util_expr_scan.l"
+#line 413 "util_expr_scan.l"
 { return T_OP_STR_EQ; }
        YY_BREAK
-case 31:
+case 34:
 YY_RULE_SETUP
-#line 335 "util_expr_scan.l"
+#line 414 "util_expr_scan.l"
 { return T_OP_STR_NE; }
        YY_BREAK
-case 32:
+case 35:
 YY_RULE_SETUP
-#line 336 "util_expr_scan.l"
+#line 415 "util_expr_scan.l"
 { return T_OP_STR_LT; }
        YY_BREAK
-case 33:
+case 36:
 YY_RULE_SETUP
-#line 337 "util_expr_scan.l"
+#line 416 "util_expr_scan.l"
 { return T_OP_STR_LE; }
        YY_BREAK
-case 34:
+case 37:
 YY_RULE_SETUP
-#line 338 "util_expr_scan.l"
+#line 417 "util_expr_scan.l"
 { return T_OP_STR_GT; }
        YY_BREAK
-case 35:
+case 38:
 YY_RULE_SETUP
-#line 339 "util_expr_scan.l"
+#line 418 "util_expr_scan.l"
 { return T_OP_STR_GE; }
        YY_BREAK
-case 36:
+case 39:
 YY_RULE_SETUP
-#line 340 "util_expr_scan.l"
+#line 419 "util_expr_scan.l"
 { return T_OP_REG; }
        YY_BREAK
-case 37:
+case 40:
 YY_RULE_SETUP
-#line 341 "util_expr_scan.l"
+#line 420 "util_expr_scan.l"
 { return T_OP_NRE; }
        YY_BREAK
-case 38:
+case 41:
 YY_RULE_SETUP
-#line 342 "util_expr_scan.l"
+#line 421 "util_expr_scan.l"
 { return T_OP_AND; }
        YY_BREAK
-case 39:
+case 42:
 YY_RULE_SETUP
-#line 343 "util_expr_scan.l"
+#line 422 "util_expr_scan.l"
 { return T_OP_AND; }
        YY_BREAK
-case 40:
+case 43:
 YY_RULE_SETUP
-#line 344 "util_expr_scan.l"
+#line 423 "util_expr_scan.l"
 { return T_OP_OR; }
        YY_BREAK
-case 41:
+case 44:
 YY_RULE_SETUP
-#line 345 "util_expr_scan.l"
+#line 424 "util_expr_scan.l"
 { return T_OP_OR; }
        YY_BREAK
-case 42:
+case 45:
 YY_RULE_SETUP
-#line 346 "util_expr_scan.l"
+#line 425 "util_expr_scan.l"
 { return T_OP_NOT; }
        YY_BREAK
-case 43:
+case 46:
 YY_RULE_SETUP
-#line 347 "util_expr_scan.l"
+#line 426 "util_expr_scan.l"
 { return T_OP_NOT; }
        YY_BREAK
-case 44:
+case 47:
 YY_RULE_SETUP
-#line 348 "util_expr_scan.l"
+#line 427 "util_expr_scan.l"
 { return T_OP_CONCAT; }
        YY_BREAK
-case 45:
+case 48:
 YY_RULE_SETUP
-#line 349 "util_expr_scan.l"
+#line 428 "util_expr_scan.l"
 { return T_OP_IN; }
        YY_BREAK
-case 46:
+case 49:
 YY_RULE_SETUP
-#line 350 "util_expr_scan.l"
+#line 429 "util_expr_scan.l"
 { return T_OP_EQ; }
        YY_BREAK
-case 47:
+case 50:
 YY_RULE_SETUP
-#line 351 "util_expr_scan.l"
+#line 430 "util_expr_scan.l"
 { return T_OP_NE; }
        YY_BREAK
-case 48:
+case 51:
 YY_RULE_SETUP
-#line 352 "util_expr_scan.l"
+#line 431 "util_expr_scan.l"
 { return T_OP_GE; }
        YY_BREAK
-case 49:
+case 52:
 YY_RULE_SETUP
-#line 353 "util_expr_scan.l"
+#line 432 "util_expr_scan.l"
 { return T_OP_LE; }
        YY_BREAK
-case 50:
+case 53:
 YY_RULE_SETUP
-#line 354 "util_expr_scan.l"
+#line 433 "util_expr_scan.l"
 { return T_OP_GT; }
        YY_BREAK
-case 51:
+case 54:
 YY_RULE_SETUP
-#line 355 "util_expr_scan.l"
+#line 434 "util_expr_scan.l"
 { return T_OP_LT; }
        YY_BREAK
 /* for compatibility with ssl_expr */
-case 52:
+case 55:
 YY_RULE_SETUP
-#line 358 "util_expr_scan.l"
+#line 437 "util_expr_scan.l"
 { return T_OP_LT; }
        YY_BREAK
-case 53:
+case 56:
 YY_RULE_SETUP
-#line 359 "util_expr_scan.l"
+#line 438 "util_expr_scan.l"
 { return T_OP_LE; }
        YY_BREAK
-case 54:
+case 57:
 YY_RULE_SETUP
-#line 360 "util_expr_scan.l"
+#line 439 "util_expr_scan.l"
 { return T_OP_GT; }
        YY_BREAK
-case 55:
+case 58:
 YY_RULE_SETUP
-#line 361 "util_expr_scan.l"
+#line 440 "util_expr_scan.l"
 { return T_OP_GE; }
        YY_BREAK
-case 56:
+case 59:
 YY_RULE_SETUP
-#line 362 "util_expr_scan.l"
+#line 441 "util_expr_scan.l"
 { return T_OP_NE; }
        YY_BREAK
-case 57:
+case 60:
 YY_RULE_SETUP
-#line 363 "util_expr_scan.l"
+#line 442 "util_expr_scan.l"
 { return T_OP_EQ; }
        YY_BREAK
-case 58:
+case 61:
 YY_RULE_SETUP
-#line 364 "util_expr_scan.l"
+#line 443 "util_expr_scan.l"
 { return T_OP_IN; }
        YY_BREAK
-case 59:
+case 62:
 YY_RULE_SETUP
-#line 366 "util_expr_scan.l"
+#line 445 "util_expr_scan.l"
 {
     yylval->cpVal = apr_pstrdup(yyextra->pool, yytext + 1);
-    return T_OP_UNARY;
+    return T_OP_BINARY;
 }
        YY_BREAK
-case 60:
+case 63:
 YY_RULE_SETUP
-#line 371 "util_expr_scan.l"
+#line 450 "util_expr_scan.l"
 {
     yylval->cpVal = apr_pstrdup(yyextra->pool, yytext + 1);
-    return T_OP_BINARY;
+    return T_OP_UNARY;
+}
+       YY_BREAK
+/* Split a string (or list) into a(nother) list */
+case 64:
+YY_RULE_SETUP
+#line 456 "util_expr_scan.l"
+{
+    STATE_PUSH(split, 0);
+    return T_OP_SPLIT;
+}
+       YY_BREAK
+case 65:
+YY_RULE_SETUP
+#line 460 "util_expr_scan.l"
+{
+    STATE_POP(0); /* <split> */
+    STATE_PUSH(regex, 1);
+    str_stop = yytext[0];
+    str_flag = 'S';
+}
+       YY_BREAK
+case 66:
+/* rule 66 can match eol */
+YY_RULE_SETUP
+#line 466 "util_expr_scan.l"
+{
+    PERROR("Expecting split regular expression");
+}
+       YY_BREAK
+case YY_STATE_EOF(split):
+#line 469 "util_expr_scan.l"
+{
+    PERROR("Unterminated split");
+}
+       YY_BREAK
+/* Join a list into a string */
+case 67:
+YY_RULE_SETUP
+#line 474 "util_expr_scan.l"
+{
+    return T_OP_JOIN;
 }
        YY_BREAK
 /*
   * Specials
   */
-case 61:
+case 68:
 YY_RULE_SETUP
-#line 379 "util_expr_scan.l"
+#line 481 "util_expr_scan.l"
 { return T_TRUE; }
        YY_BREAK
-case 62:
+case 69:
 YY_RULE_SETUP
-#line 380 "util_expr_scan.l"
+#line 482 "util_expr_scan.l"
 { return T_FALSE; }
        YY_BREAK
 /*
   * Digits
   */
-case 63:
+case 70:
 YY_RULE_SETUP
-#line 385 "util_expr_scan.l"
+#line 487 "util_expr_scan.l"
 {
     yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
     return T_DIGIT;
@@ -1500,9 +1680,9 @@ YY_RULE_SETUP
 /*
   * Identifiers
   */
-case 64:
+case 71:
 YY_RULE_SETUP
-#line 393 "util_expr_scan.l"
+#line 495 "util_expr_scan.l"
 {
     yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
     return T_ID;
@@ -1511,9 +1691,9 @@ YY_RULE_SETUP
 /*
   * These are parts of the grammar and are returned as is
   */
-case 65:
+case 72:
 YY_RULE_SETUP
-#line 401 "util_expr_scan.l"
+#line 503 "util_expr_scan.l"
 {
     return yytext[0];
 }
@@ -1521,23 +1701,21 @@ YY_RULE_SETUP
 /*
   * Anything else is an error
   */
-case 66:
-/* rule 66 can match eol */
+case 73:
+/* rule 73 can match eol */
 YY_RULE_SETUP
-#line 408 "util_expr_scan.l"
+#line 510 "util_expr_scan.l"
 {
-    char *msg = apr_psprintf(yyextra->pool, "Parse error near '%c'", yytext[0]);
-    PERROR(msg);
+    PERROR_CHAR("Parse error near character ", yytext[0]);
 }
        YY_BREAK
-case 67:
+case 74:
 YY_RULE_SETUP
-#line 413 "util_expr_scan.l"
+#line 514 "util_expr_scan.l"
 YY_FATAL_ERROR( "flex scanner jammed" );
        YY_BREAK
-#line 1538 "util_expr_scan.c"
+#line 1718 "util_expr_scan.c"
 case YY_STATE_EOF(INITIAL):
-case YY_STATE_EOF(regex):
        yyterminate();
 
        case YY_END_OF_BUFFER:
@@ -1668,6 +1846,7 @@ case YY_STATE_EOF(regex):
                        "fatal flex scanner internal error--no action found" );
        } /* end of action switch */
                } /* end of scanning one token */
+       } /* end of user's declarations */
 } /* end of ap_expr_yylex */
 
 /* yy_get_next_buffer - try to read in a new buffer
@@ -1680,9 +1859,9 @@ case YY_STATE_EOF(regex):
 static int yy_get_next_buffer (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-       register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
-       register char *source = yyg->yytext_ptr;
-       register int number_to_move, i;
+       char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+       char *source = yyg->yytext_ptr;
+       int number_to_move, i;
        int ret_val;
 
        if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
@@ -1711,7 +1890,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
        /* Try to read more data. */
 
        /* First move last chars to start of buffer. */
-       number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
+       number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1);
 
        for ( i = 0; i < number_to_move; ++i )
                *(dest++) = *(source++);
@@ -1731,7 +1910,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
                        { /* Not enough room in the buffer - grow it. */
 
                        /* just a shorter name for the current buffer */
-                       YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+                       YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
 
                        int yy_c_buf_p_offset =
                                (int) (yyg->yy_c_buf_p - b->yy_ch_buf);
@@ -1751,7 +1930,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
                                }
                        else
                                /* Can't grow it, we don't own it. */
-                               b->yy_ch_buf = 0;
+                               b->yy_ch_buf = NULL;
 
                        if ( ! b->yy_ch_buf )
                                YY_FATAL_ERROR(
@@ -1769,7 +1948,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 
                /* Read in more data. */
                YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
-                       yyg->yy_n_chars, (size_t) num_to_read );
+                       yyg->yy_n_chars, num_to_read );
 
                YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
                }
@@ -1793,9 +1972,9 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
        else
                ret_val = EOB_ACT_CONTINUE_SCAN;
 
-       if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+       if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
                /* Extend the array by 50%, plus the number we really need. */
-               yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+               int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
                YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) ap_expr_yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
                if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
                        YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
@@ -1814,15 +1993,15 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 
     static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
 {
-       register yy_state_type yy_current_state;
-       register char *yy_cp;
+       yy_state_type yy_current_state;
+       char *yy_cp;
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
        yy_current_state = yyg->yy_start;
 
        for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
                {
-               register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+               YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
                if ( yy_accept[yy_current_state] )
                        {
                        yyg->yy_last_accepting_state = yy_current_state;
@@ -1831,10 +2010,10 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
                while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
                        {
                        yy_current_state = (int) yy_def[yy_current_state];
-                       if ( yy_current_state >= 124 )
+                       if ( yy_current_state >= 157 )
                                yy_c = yy_meta[(unsigned int) yy_c];
                        }
-               yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+               yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c];
                }
 
        return yy_current_state;
@@ -1847,11 +2026,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
  */
     static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state , yyscan_t yyscanner)
 {
-       register int yy_is_jam;
+       int yy_is_jam;
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
-       register char *yy_cp = yyg->yy_c_buf_p;
+       char *yy_cp = yyg->yy_c_buf_p;
 
-       register YY_CHAR yy_c = 1;
+       YY_CHAR yy_c = 1;
        if ( yy_accept[yy_current_state] )
                {
                yyg->yy_last_accepting_state = yy_current_state;
@@ -1860,15 +2039,20 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
        while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
                {
                yy_current_state = (int) yy_def[yy_current_state];
-               if ( yy_current_state >= 124 )
+               if ( yy_current_state >= 157 )
                        yy_c = yy_meta[(unsigned int) yy_c];
                }
-       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-       yy_is_jam = (yy_current_state == 123);
+       yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c];
+       yy_is_jam = (yy_current_state == 156);
 
+       (void)yyg;
        return yy_is_jam ? 0 : yy_current_state;
 }
 
+#ifndef YY_NO_UNPUT
+
+#endif
+
 #ifndef YY_NO_INPUT
 #ifdef __cplusplus
     static int yyinput (yyscan_t yyscanner)
@@ -1918,7 +2102,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
                                case EOB_ACT_END_OF_FILE:
                                        {
                                        if ( ap_expr_yywrap(yyscanner ) )
-                                               return EOF;
+                                               return 0;
 
                                        if ( ! yyg->yy_did_buffer_switch_on_eof )
                                                YY_NEW_FILE;
@@ -2022,7 +2206,7 @@ static void ap_expr_yy_load_buffer_state  (yyscan_t yyscanner)
        if ( ! b )
                YY_FATAL_ERROR( "out of dynamic memory in ap_expr_yy_create_buffer()" );
 
-       b->yy_buf_size = size;
+       b->yy_buf_size = (yy_size_t)size;
 
        /* yy_ch_buf has to be 2 characters longer than the size given because
         * we need to put in 2 end-of-buffer characters.
@@ -2183,15 +2367,15 @@ static void ap_expr_yyensure_buffer_stack (yyscan_t yyscanner)
                 * scanner will even need a stack. We use 2 instead of 1 to avoid an
                 * immediate realloc on the next call.
          */
-               num_to_alloc = 1;
+      num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */
                yyg->yy_buffer_stack = (struct yy_buffer_state**)ap_expr_yyalloc
                                                                (num_to_alloc * sizeof(struct yy_buffer_state*)
                                                                , yyscanner);
                if ( ! yyg->yy_buffer_stack )
                        YY_FATAL_ERROR( "out of dynamic memory in ap_expr_yyensure_buffer_stack()" );
-                                                                 
+
                memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
-                               
+
                yyg->yy_buffer_stack_max = num_to_alloc;
                yyg->yy_buffer_stack_top = 0;
                return;
@@ -2200,7 +2384,7 @@ static void ap_expr_yyensure_buffer_stack (yyscan_t yyscanner)
        if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
 
                /* Increase the buffer to prepare for a possible push. */
-               int grow_size = 8 /* arbitrary grow size */;
+               yy_size_t grow_size = 8 /* arbitrary grow size */;
 
                num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
                yyg->yy_buffer_stack = (struct yy_buffer_state**)ap_expr_yyrealloc
@@ -2220,7 +2404,7 @@ static void ap_expr_yyensure_buffer_stack (yyscan_t yyscanner)
  * @param base the character buffer
  * @param size the size in bytes of the character buffer
  * @param yyscanner The scanner object.
- * @return the newly allocated buffer state object. 
+ * @return the newly allocated buffer state object.
  */
 YY_BUFFER_STATE ap_expr_yy_scan_buffer  (char * base, yy_size_t  size , yyscan_t yyscanner)
 {
@@ -2230,7 +2414,7 @@ YY_BUFFER_STATE ap_expr_yy_scan_buffer  (char * base, yy_size_t  size , yyscan_t
             base[size-2] != YY_END_OF_BUFFER_CHAR ||
             base[size-1] != YY_END_OF_BUFFER_CHAR )
                /* They forgot to leave room for the EOB's. */
-               return 0;
+               return NULL;
 
        b = (YY_BUFFER_STATE) ap_expr_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
        if ( ! b )
@@ -2239,7 +2423,7 @@ YY_BUFFER_STATE ap_expr_yy_scan_buffer  (char * base, yy_size_t  size , yyscan_t
        b->yy_buf_size = size - 2;      /* "- 2" to take care of EOB's */
        b->yy_buf_pos = b->yy_ch_buf = base;
        b->yy_is_our_buffer = 0;
-       b->yy_input_file = 0;
+       b->yy_input_file = NULL;
        b->yy_n_chars = b->yy_buf_size;
        b->yy_is_interactive = 0;
        b->yy_at_bol = 1;
@@ -2262,7 +2446,7 @@ YY_BUFFER_STATE ap_expr_yy_scan_buffer  (char * base, yy_size_t  size , yyscan_t
 YY_BUFFER_STATE ap_expr_yy_scan_string (yyconst char * yystr , yyscan_t yyscanner)
 {
     
-       return ap_expr_yy_scan_bytes(yystr,strlen(yystr) ,yyscanner);
+       return ap_expr_yy_scan_bytes(yystr,(int) strlen(yystr) ,yyscanner);
 }
 
 /** Setup the input buffer state to scan the given bytes. The next call to ap_expr_yylex() will
@@ -2280,7 +2464,7 @@ YY_BUFFER_STATE ap_expr_yy_scan_bytes  (yyconst char * yybytes, int  _yybytes_le
        int i;
     
        /* Get memory for full buffer, including space for trailing EOB's. */
-       n = _yybytes_len + 2;
+       n = (yy_size_t) (_yybytes_len + 2);
        buf = (char *) ap_expr_yyalloc(n ,yyscanner );
        if ( ! buf )
                YY_FATAL_ERROR( "out of dynamic memory in ap_expr_yy_scan_bytes()" );
@@ -2302,7 +2486,7 @@ YY_BUFFER_STATE ap_expr_yy_scan_bytes  (yyconst char * yybytes, int  _yybytes_le
        return b;
 }
 
-    static void yy_push_state (int  new_state , yyscan_t yyscanner)
+    static void yy_push_state (int  _new_state , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
        if ( yyg->yy_start_stack_ptr >= yyg->yy_start_stack_depth )
@@ -2310,7 +2494,7 @@ YY_BUFFER_STATE ap_expr_yy_scan_bytes  (yyconst char * yybytes, int  _yybytes_le
                yy_size_t new_size;
 
                yyg->yy_start_stack_depth += YY_START_STACK_INCR;
-               new_size = yyg->yy_start_stack_depth * sizeof( int );
+               new_size = (yy_size_t) yyg->yy_start_stack_depth * sizeof( int );
 
                if ( ! yyg->yy_start_stack )
                        yyg->yy_start_stack = (int *) ap_expr_yyalloc(new_size ,yyscanner );
@@ -2324,7 +2508,7 @@ YY_BUFFER_STATE ap_expr_yy_scan_bytes  (yyconst char * yybytes, int  _yybytes_le
 
        yyg->yy_start_stack[yyg->yy_start_stack_ptr++] = YY_START;
 
-       BEGIN(new_state);
+       BEGIN(_new_state);
 }
 
     static void yy_pop_state  (yyscan_t yyscanner)
@@ -2340,9 +2524,11 @@ YY_BUFFER_STATE ap_expr_yy_scan_bytes  (yyconst char * yybytes, int  _yybytes_le
 #define YY_EXIT_FAILURE 2
 #endif
 
-static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
+static void yynoreturn yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
 {
-       (void) fprintf( stderr, "%s\n", msg );
+       struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+       (void)yyg;
+       (void) fprintf( stderr, "%s\n", msg );
        exit( YY_EXIT_FAILURE );
 }
 
@@ -2380,7 +2566,7 @@ YY_EXTRA_TYPE ap_expr_yyget_extra  (yyscan_t yyscanner)
 int ap_expr_yyget_lineno  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-    
+
         if (! YY_CURRENT_BUFFER)
             return 0;
     
@@ -2439,41 +2625,41 @@ void ap_expr_yyset_extra (YY_EXTRA_TYPE  user_defined , yyscan_t yyscanner)
 }
 
 /** Set the current line number.
- * @param line_number
+ * @param _line_number line number
  * @param yyscanner The scanner object.
  */
-void ap_expr_yyset_lineno (int  line_number , yyscan_t yyscanner)
+void ap_expr_yyset_lineno (int  _line_number , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
         /* lineno is only valid if an input buffer exists. */
         if (! YY_CURRENT_BUFFER )
-           yy_fatal_error( "ap_expr_yyset_lineno called with no buffer" , yyscanner); 
+           YY_FATAL_ERROR( "ap_expr_yyset_lineno called with no buffer" );
     
-    yylineno = line_number;
+    yylineno = _line_number;
 }
 
 /** Set the current column.
- * @param line_number
+ * @param _column_no column number
  * @param yyscanner The scanner object.
  */
 
 /** Set the input stream. This does not discard the current
  * input buffer.
- * @param in_str A readable stream.
+ * @param _in_str A readable stream.
  * @param yyscanner The scanner object.
  * @see ap_expr_yy_switch_to_buffer
  */
-void ap_expr_yyset_in (FILE *  in_str , yyscan_t yyscanner)
+void ap_expr_yyset_in (FILE *  _in_str , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-    yyin = in_str ;
+    yyin = _in_str ;
 }
 
-void ap_expr_yyset_out (FILE *  out_str , yyscan_t yyscanner)
+void ap_expr_yyset_out (FILE *  _out_str , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-    yyout = out_str ;
+    yyout = _out_str ;
 }
 
 int ap_expr_yyget_debug  (yyscan_t yyscanner)
@@ -2482,10 +2668,10 @@ int ap_expr_yyget_debug  (yyscan_t yyscanner)
     return yy_flex_debug;
 }
 
-void ap_expr_yyset_debug (int  bdebug , yyscan_t yyscanner)
+void ap_expr_yyset_debug (int  _bdebug , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-    yy_flex_debug = bdebug ;
+    yy_flex_debug = _bdebug ;
 }
 
 /* Accessor methods for yylval and yylloc */
@@ -2549,20 +2735,20 @@ int ap_expr_yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_glob
         errno = EINVAL;
         return 1;
     }
-       
+
     *ptr_yy_globals = (yyscan_t) ap_expr_yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
-       
+
     if (*ptr_yy_globals == NULL){
         errno = ENOMEM;
         return 1;
     }
-    
+
     /* By setting to 0xAA, we expose bugs in
     yy_init_globals. Leave at 0x00 for releases. */
     memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
-    
+
     ap_expr_yyset_extra (yy_user_defined, *ptr_yy_globals);
-    
+
     return yy_init_globals ( *ptr_yy_globals );
 }
 
@@ -2573,10 +2759,10 @@ static int yy_init_globals (yyscan_t yyscanner)
      * This function is called from ap_expr_yylex_destroy(), so don't allocate here.
      */
 
-    yyg->yy_buffer_stack = 0;
+    yyg->yy_buffer_stack = NULL;
     yyg->yy_buffer_stack_top = 0;
     yyg->yy_buffer_stack_max = 0;
-    yyg->yy_c_buf_p = (char *) 0;
+    yyg->yy_c_buf_p = NULL;
     yyg->yy_init = 0;
     yyg->yy_start = 0;
 
@@ -2589,8 +2775,8 @@ static int yy_init_globals (yyscan_t yyscanner)
     yyin = stdin;
     yyout = stdout;
 #else
-    yyin = (FILE *) 0;
-    yyout = (FILE *) 0;
+    yyin = NULL;
+    yyout = NULL;
 #endif
 
     /* For future reference: Set errno on error, since we are called by
@@ -2636,7 +2822,10 @@ int ap_expr_yylex_destroy  (yyscan_t yyscanner)
 #ifndef yytext_ptr
 static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
 {
-       register int i;
+       struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+       (void)yyg;
+
+       int i;
        for ( i = 0; i < n; ++i )
                s1[i] = s2[i];
 }
@@ -2645,7 +2834,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yysca
 #ifdef YY_NEED_STRLEN
 static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
 {
-       register int n;
+       int n;
        for ( n = 0; s[n]; ++n )
                ;
 
@@ -2655,11 +2844,16 @@ static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
 
 void *ap_expr_yyalloc (yy_size_t  size , yyscan_t yyscanner)
 {
-       return (void *) malloc( size );
+       struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+       (void)yyg;
+       return malloc(size);
 }
 
 void *ap_expr_yyrealloc  (void * ptr, yy_size_t  size , yyscan_t yyscanner)
 {
+       struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+       (void)yyg;
+
        /* The cast to (char *) in the following accommodates both
         * implementations that use char* generic pointers, and those
         * that use void* generic pointers.  It works with the latter
@@ -2667,17 +2861,19 @@ void *ap_expr_yyrealloc  (void * ptr, yy_size_t  size , yyscan_t yyscanner)
         * any pointer type to void*, and deal with argument conversions
         * as though doing an assignment.
         */
-       return (void *) realloc( (char *) ptr, size );
+       return realloc(ptr, size);
 }
 
 void ap_expr_yyfree (void * ptr , yyscan_t yyscanner)
 {
+       struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+       (void)yyg;
        free( (char *) ptr );   /* see ap_expr_yyrealloc() for (char *) cast */
 }
 
 #define YYTABLES_NAME "yytables"
 
-#line 413 "util_expr_scan.l"
+#line 514 "util_expr_scan.l"
 
 
 
index f048d0dcf5c5d985c6f5ea736ee6a50cdccfcfa8..a7d5e99267ede34745d1b45abc43e9e3c890449c 100644 (file)
 %option warn
 %option noinput nounput noyy_top_state
 %option stack
-%x str
-%x var
-%x vararg
-%x regex regex_flags
+
+%x str expr
+%x var vararg
+%x split regex regsub regflags
 
 %{
 #include "util_expr_private.h"
 #include "util_expr_parse.h"
 #include "http_main.h"
 #include "http_log.h"
+#include "apr_lib.h"
 
 #undef  YY_INPUT
 #define YY_INPUT(buf,result,max_size)                       \
  * XXX: longjmp. It is not clear if the scanner is in any state
  * XXX: to be cleaned up, though.
  */
+static int unreachable = 0;
 #define YY_FATAL_ERROR(msg)                                     \
     do {                                                        \
         ap_log_error(APLOG_MARK, APLOG_CRIT, 0, ap_server_conf, \
                      APLOGNO(03296)                             \
                      "expr parser fatal error (BUG?): "         \
                      "%s, exiting", msg);                       \
-         abort();                                               \
+        if (unreachable) {                                      \
+            /* Not reached, silence [-Wunused-function] */      \
+            yy_fatal_error(msg, yyscanner);                     \
+        }                                                       \
+        else {                                                  \
+            abort();                                            \
+        }                                                       \
     } while (0)
 
 #define YY_EXTRA_TYPE ap_expr_parse_ctx_t*
 
-#define PERROR(msg) do { yyextra->error2 = msg ; return T_ERROR; } while (0)
+#define PERROR(msg) do {    \
+    yyextra->error2 = msg;  \
+    return T_ERROR;         \
+} while (0)
+
+#define PERROR_CHAR(prefix, chr) do {                                       \
+    char *msg;                                                              \
+    if (apr_isprint((chr))) {                                               \
+        msg = apr_psprintf(yyextra->pool, prefix "'%c'", (char)(chr));      \
+    }                                                                       \
+    else {                                                                  \
+        msg = apr_psprintf(yyextra->pool, prefix "'\\x%.2X'", (int)(chr));  \
+    }                                                                       \
+    PERROR(msg);                                                            \
+} while (0)
+
+#define STACK_PUSH() do {                               \
+    ap_expr_parser_stack_t *sk;                         \
+    if (yyextra->spares) {                              \
+        sk = yyextra->spares;                           \
+        yyextra->spares = sk->next;                     \
+    }                                                   \
+    else {                                              \
+        sk = apr_palloc(yyextra->ptemp, sizeof(*sk));   \
+    }                                                   \
+    sk->scan_ptr  = sk->scan_buf;                       \
+    sk->scan_stop = sk->scan_buf[0] = '\0';             \
+    sk->scan_flag = 0;                                  \
+    sk->next = yyextra->current;                        \
+    yyextra->current = sk;                              \
+} while (0)
+
+#define STACK_POP() do {            \
+    ap_expr_parser_stack_t *sk;     \
+    sk = yyextra->current;          \
+    yyextra->current = sk->next;    \
+    sk->next = yyextra->spares;     \
+    yyextra->spares = sk;           \
+} while (0)
+
+#define STATE_PUSH(st, sk) do {     \
+    yy_push_state((st), yyscanner); \
+    if ((sk)) {                     \
+        STACK_PUSH();               \
+    }                               \
+} while (0)
+
+#define STATE_POP(sk) do {          \
+    if ((sk)) {                     \
+        STACK_POP();                \
+    }                               \
+    yy_pop_state(yyscanner);        \
+} while (0)
+
+#define str_ptr  (yyextra->current->scan_ptr)
+#define str_buf  (yyextra->current->scan_buf)
+#define str_stop (yyextra->current->scan_stop)
+#define str_flag (yyextra->current->scan_flag)
+
+#define STR_APPEND_CHECK(chr, chk) do {                     \
+    if ((chk) && apr_iscntrl((chr))) {                      \
+        PERROR_CHAR("Invalid string character ", (chr));    \
+    }                                                       \
+    if (str_ptr >= str_buf + sizeof(str_buf) - 1) {         \
+        PERROR("String too long");                          \
+    }                                                       \
+    *str_ptr++ = (char)(chr);                               \
+} while (0)
 
-#define str_ptr     (yyextra->scan_ptr)
-#define str_buf     (yyextra->scan_buf)
-#define str_del     (yyextra->scan_del)
+#define STR_APPEND_NOCHECK(chr) \
+    STR_APPEND_CHECK((chr), 0)
 
-#define STR_APPEND(c) do {                          \
-        *str_ptr++ = (c);                           \
-        if (str_ptr >= str_buf + sizeof(str_buf))   \
-            PERROR("String too long");              \
-    } while (0)
+#define STR_EMPTY() \
+    (str_ptr == str_buf)
+
+#define STR_RETURN() \
+    (apr_pstrdup(yyextra->pool, (*str_ptr = '\0', str_ptr = str_buf)))
 
 %}
 
+ANY          (.|\n)
+SPACE        [ \t\n]
+QUOTE        ["']
+TOKEN        ([a-zA-Z][a-zA-Z0-9_]*)
+VAR_BEGIN    (\%\{)
+VAR_ARG      (\:)
+VAR_END      (\})
+VAREXP_BEGIN (\%\{\:)
+VAREXP_END   (\:\})
+REG_SEP      [/#$%^|?!'",;:._-]
+REG_REF      (\$[0-9])
 
 %%
 
-  char  regex_buf[MAX_STRING_LEN];
-  char *regex_ptr = NULL;
-  char  regex_del = '\0';
-
 %{
  /*
   * Set initial state for string expressions
   if (yyextra->at_start) {
     yyextra->at_start = 0;
     if (yyextra->flags & AP_EXPR_FLAG_STRING_RESULT) {
-        BEGIN(str);
+        STATE_PUSH(str, 1);
         return T_EXPR_STRING;
     }
     else {
+        STATE_PUSH(expr, 1);
         return T_EXPR_BOOL;
     }
   }
 %}
 
  /*
-  * Whitespaces
+  * Back off INITIAL pushes
   */
-[ \t\n]+ { 
-    /* NOP */
+<str><<EOF>> {
+    STATE_POP(0); /* <str> */
+    if (YY_START != INITIAL) {
+        PERROR("Unterminated string");
+    }
+    yylval->cpVal = STR_RETURN();
+    STACK_POP(); /* ^ after this */
+    return T_STRING;
+}
+<expr><<EOF>> {
+    STATE_POP(1); /* <expr> */
+    if (YY_START != INITIAL) {
+        PERROR("Unterminated expression");
+    }
 }
 
- /*
-  * strings ("..." and '...')
-  */
-["'] {
-    str_ptr = str_buf;
-    str_del = yytext[0];
-    BEGIN(str);
-    return T_STR_BEGIN;
-}
-<str>["'] {
-    if (yytext[0] == str_del) {
-        if (YY_START == var) {
-            PERROR("Unterminated variable in string");
-        }
-        else if (str_ptr == str_buf) {
-            BEGIN(INITIAL);
-            return T_STR_END;
-        }
-        else {
-            /* return what we have so far and scan delimiter again */
-            *str_ptr = '\0';
-            yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
-            yyless(0);
-            str_ptr = str_buf;
+<str>{QUOTE} {
+    if (yytext[0] == str_stop) {
+        if (!STR_EMPTY()) {
+            yyless(0); /* come back below */
+            yylval->cpVal = STR_RETURN();
             return T_STRING;
         }
+        STATE_POP(1); /* <str> */
+        return T_STR_END;
     }
-    else {
-        STR_APPEND(yytext[0]);
-    }
-}
-<str,var,vararg>\n {
-    PERROR("Unterminated string or variable");
+    STR_APPEND_NOCHECK(yytext[0]);
 }
-<var,vararg><<EOF>> {
-    PERROR("Unterminated string or variable");
-}
-<str><<EOF>> {
-    if (!(yyextra->flags & AP_EXPR_FLAG_STRING_RESULT)) {
-        PERROR("Unterminated string or variable");
-    }
-    else {
-        *str_ptr = '\0';
-        yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
-        str_ptr = str_buf;
-        BEGIN(INITIAL);
+
+ /* regexp backref inside string/arg */
+<str,vararg,regsub>{REG_REF} {
+    if (!STR_EMPTY()) {
+        yyless(0); /* come back below */
+        yylval->cpVal = STR_RETURN();
         return T_STRING;
     }
+    yylval->num = yytext[1] - '0';
+    return T_REG_REF;
 }
 
-<str,vararg>\\[0-7]{1,3} {
-    int result;
-
-    (void)sscanf(yytext+1, "%o", &result);
-    if (result > 0xff) {
-        PERROR("Escape sequence out of bound");
-    }
-    else {
-        STR_APPEND(result);
+ /* variable inside string/arg */
+<str,vararg,regsub>{VAR_BEGIN} {
+    if (!STR_EMPTY()) {
+        yyless(0); /* come back below */
+        yylval->cpVal = STR_RETURN();
+        return T_STRING;
     }
+    STATE_PUSH(var, 1);
+    return T_VAR_BEGIN;
 }
-<str,vararg>\\[0-9]+ {
-    PERROR("Bad escape sequence");
-}
-<str,vararg>\\n      { STR_APPEND('\n'); }
-<str,vararg>\\r      { STR_APPEND('\r'); }
-<str,vararg>\\t      { STR_APPEND('\t'); }
-<str,vararg>\\b      { STR_APPEND('\b'); }
-<str,vararg>\\f      { STR_APPEND('\f'); }
-<str,vararg>\\(.|\n) { STR_APPEND(yytext[1]); }
 
- /* regexp backref inside string/arg */
-<str,vararg>[$][0-9] {
-    if (str_ptr != str_buf) {
-        /* return what we have so far and scan '$x' again */
-        *str_ptr = '\0';
-        yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
-        str_ptr = str_buf;
-        yyless(0);
+<str,vararg,regsub>{VAREXP_BEGIN} {
+    if (!STR_EMPTY()) {
+        yyless(0); /* come back below */
+        yylval->cpVal = STR_RETURN();
         return T_STRING;
     }
-    else {
-        yylval->num = yytext[1] - '0';
-        return T_REGEX_BACKREF;
-    }
+    STATE_PUSH(expr, 1);
+    return T_VAREXP_BEGIN;
 }
 
-<str,vararg>[^\\\n"'%}$]+ {
-    char *cp = yytext;
-    while (*cp != '\0') {
-        STR_APPEND(*cp);
-        cp++;
-    }
+ /* Any non-octal or octal higher than 377 (decimal 255) is invalid */
+<str,vararg,regsub>\\([4-9][0-9]{2}|[8-9][0-9]{0,2}) {
+    PERROR("Bad character escape sequence");
 }
+<str,vararg,regsub>\\[0-7]{1,3} {
+    int result;
+    (void)sscanf(yytext+1, "%o", &result);
+    STR_APPEND_NOCHECK(result);
+}
+<str,vararg,regsub>\\x[0-9A-Fa-f]{1,2} {
+    int result;
+    (void)sscanf(yytext+1, "%x", &result);
+    STR_APPEND_NOCHECK(result);
+}
+<str,vararg,regsub>\\n  { STR_APPEND_NOCHECK('\n'); }
+<str,vararg,regsub>\\r  { STR_APPEND_NOCHECK('\r'); }
+<str,vararg,regsub>\\t  { STR_APPEND_NOCHECK('\t'); }
+<str,vararg,regsub>\\b  { STR_APPEND_NOCHECK('\b'); }
+<str,vararg,regsub>\\f  { STR_APPEND_NOCHECK('\f'); }
+<str,vararg,regsub>\\.  { STR_APPEND_CHECK(yytext[1], 1); }
 
- /* variable inside string/arg */
-<str,vararg>%\{ {
-    if (str_ptr != str_buf) {
-        /* return what we have so far and scan '%{' again */
-        *str_ptr = '\0';
-        yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
-        yyless(0);
-        str_ptr = str_buf;
-        return T_STRING;
-    }
-    else {
-        yy_push_state(var, yyscanner);
-        return T_VAR_BEGIN;
-    }
+<str,vararg,regsub>\n {
+    PERROR("Unterminated string or variable");
 }
 
-<vararg>[%$] {
-     STR_APPEND(yytext[0]);
+<str>{ANY} {
+    STR_APPEND_CHECK(yytext[0], 1);
 }
 
-<str>[%}$] {
-     STR_APPEND(yytext[0]);
+<expr>{SPACE}+ { 
+    /* NOP */
 }
 
-%\{ {
-    yy_push_state(var, yyscanner);
-    return T_VAR_BEGIN;
+<expr>{QUOTE} {
+    STATE_PUSH(str, 1);
+    str_stop = yytext[0];
+    return T_STR_BEGIN;
 }
 
-[$][0-9] {
-    yylval->num = yytext[1] - '0';
-    return T_REGEX_BACKREF;
+<expr>{VAREXP_BEGIN} {
+    STATE_PUSH(expr, 1);
+    return T_VAREXP_BEGIN;
+}
+<expr>{VAREXP_END} {
+    STATE_POP(1); /* <expr> */
+    return T_VAREXP_END;
 }
 
- /*
-  * fixed name variable expansion %{XXX} and function call in %{func:arg} syntax
-  */
-<var>[a-ij-rs-zA-IJ-RS-Z][a-ij-rs-zA-IJ-RS-Z0-9_]* {
+
+<expr>{VAR_BEGIN} {
+    STATE_PUSH(var, 1);
+    return T_VAR_BEGIN;
+}
+<var>{TOKEN} {
     yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
     return T_ID;
 }
-
-<var>\} {
-    yy_pop_state(yyscanner);
+<var>{VAR_ARG} {
+    STATE_PUSH(vararg, 0);
+    return yytext[0];
+}
+<vararg>{VAR_END} {
+    yyless(0); /* let <var> handle */
+    yylval->cpVal = STR_RETURN();
+    STATE_POP(0); /* <vararg> */
+    return T_STRING;
+}
+<vararg>{ANY} {
+    STR_APPEND_CHECK(yytext[0], 1);
+}
+<var>{VAR_END} {
+    STATE_POP(1); /* <var> */
     return T_VAR_END;
 }
-
-<var>: {
-    BEGIN(vararg);
-    return yytext[0];
+<var>{ANY} {
+    PERROR_CHAR("Unexpected variable character ", yytext[0]);
 }
-
-<var>.|\n {
-    char *msg = apr_psprintf(yyextra->pool,
-                             "Invalid character in variable name '%c'", yytext[0]);
-    PERROR(msg);
+<var,vararg><<EOF>> {
+    PERROR("Unterminated variable");
 }
 
-<vararg>\} {
-    if (str_ptr != str_buf) {
-        /* return what we have so far and scan '}' again */
-        *str_ptr = '\0';
-        yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
-        str_ptr = str_buf;
-        yyless(0);
-        return T_STRING;
-    }
-    else {
-        yy_pop_state(yyscanner);
-        return T_VAR_END;
-    }
-}
 
  /*
   * Regular Expression
   */
-"m"[/#$%^,;:_\?\|\^\-\!\.\'\"] {
-    regex_del = yytext[1];
-    regex_ptr = regex_buf;
-    BEGIN(regex);
-}
-"/" {
-    regex_del = yytext[0];
-    regex_ptr = regex_buf;
-    BEGIN(regex);
-}
-<regex>.|\n {
-    if (yytext[0] == regex_del) {
-        *regex_ptr = '\0';
-        BEGIN(regex_flags);
+<expr>\/ {
+    STATE_PUSH(regex, 1);
+    str_stop = yytext[0];
+    str_flag = 'm';
+    return T_REGEX;
+}
+<expr>[ms]{REG_SEP} {
+    STATE_PUSH(regex, 1);
+    str_stop = yytext[1];
+    str_flag = yytext[0];
+    return (str_flag == 'm') ? T_REGEX : T_REGSUB;
+}
+<regex>{ANY} {
+    if (yytext[0] == str_stop) {
+        STATE_POP(0); /* <regex> */
+        if (str_flag == 'm') {
+            STATE_PUSH(regflags, 0);
+        }
+        else {
+            STATE_PUSH(regsub, 0);
+        }
+        yylval->cpVal = STR_RETURN();
+        return T_REG_MATCH;
+    }
+    STR_APPEND_CHECK(yytext[0], 1);
+}
+<regsub>{ANY} {
+    if (yytext[0] == str_stop) {
+        STATE_POP(0); /* <regsub> */
+        STATE_PUSH(regflags, 0);
     }
     else {
-        *regex_ptr++ = yytext[0];
-        if (regex_ptr >= regex_buf + sizeof(regex_buf))
-            PERROR("Regexp too long");
+        STR_APPEND_CHECK(yytext[0], 1);
     }
 }
-<regex_flags>i {
-    yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf);
-    BEGIN(INITIAL);
-    return T_REGEX_I;
+<regflags>{ANY} {
+    if (ap_strchr_c("ismg", yytext[0])) {
+        STR_APPEND_NOCHECK(yytext[0]);
+    }
+    else if (apr_isalnum(yytext[0])) {
+        PERROR("Invalid regexp flag(s)");
+    }
+    else {
+        yyless(0); /* not a flags, rewind */
+        yylval->cpVal = STR_RETURN();
+        STATE_POP(1); /* <regflags> */
+        return T_REG_FLAGS;
+    }
 }
-<regex_flags>.|\n {
-    yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf);
-    yyless(0);
-    BEGIN(INITIAL);
-    return T_REGEX;
+<regflags><<EOF>> {
+    yylval->cpVal = STR_RETURN();
+    STATE_POP(1); /* <regflags> */
+    return T_REG_FLAGS;
 }
-<regex_flags><<EOF>> {
-    yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf);
-    BEGIN(INITIAL);
-    return T_REGEX;
+<regex,regsub><<EOF>> {
+    PERROR("Unterminated regexp");
+}
+
+<expr>{REG_REF} {
+    yylval->num = yytext[1] - '0';
+    return T_REG_REF;
 }
 
  /*
   * Operators
   */
-==?   { return T_OP_STR_EQ; }
-"!="  { return T_OP_STR_NE; }
-"<"   { return T_OP_STR_LT; }
-"<="  { return T_OP_STR_LE; }
-">"   { return T_OP_STR_GT; }
-">="  { return T_OP_STR_GE; }
-"=~"  { return T_OP_REG; }
-"!~"  { return T_OP_NRE; }
-"and" { return T_OP_AND; }
-"&&"  { return T_OP_AND; }
-"or"  { return T_OP_OR; }
-"||"  { return T_OP_OR; }
-"not" { return T_OP_NOT; }
-"!"   { return T_OP_NOT; }
-"."   { return T_OP_CONCAT; }
-"-in"  { return T_OP_IN; }
-"-eq"  { return T_OP_EQ; }
-"-ne"  { return T_OP_NE; }
-"-ge"  { return T_OP_GE; }
-"-le"  { return T_OP_LE; }
-"-gt"  { return T_OP_GT; }
-"-lt"  { return T_OP_LT; }
+<expr>==?   { return T_OP_STR_EQ; }
+<expr>"!="  { return T_OP_STR_NE; }
+<expr>"<"   { return T_OP_STR_LT; }
+<expr>"<="  { return T_OP_STR_LE; }
+<expr>">"   { return T_OP_STR_GT; }
+<expr>">="  { return T_OP_STR_GE; }
+<expr>"=~"  { return T_OP_REG; }
+<expr>"!~"  { return T_OP_NRE; }
+<expr>"and" { return T_OP_AND; }
+<expr>"&&"  { return T_OP_AND; }
+<expr>"or"  { return T_OP_OR; }
+<expr>"||"  { return T_OP_OR; }
+<expr>"not" { return T_OP_NOT; }
+<expr>"!"   { return T_OP_NOT; }
+<expr>"."   { return T_OP_CONCAT; }
+<expr>"-in" { return T_OP_IN; }
+<expr>"-eq" { return T_OP_EQ; }
+<expr>"-ne" { return T_OP_NE; }
+<expr>"-ge" { return T_OP_GE; }
+<expr>"-le" { return T_OP_LE; }
+<expr>"-gt" { return T_OP_GT; }
+<expr>"-lt" { return T_OP_LT; }
 
  /* for compatibility with ssl_expr */
-"lt"  { return T_OP_LT; }
-"le"  { return T_OP_LE; }
-"gt"  { return T_OP_GT; }
-"ge"  { return T_OP_GE; }
-"ne"  { return T_OP_NE; }
-"eq"  { return T_OP_EQ; }
-"in"  { return T_OP_IN; }
-
-"-"[a-ij-rs-zA-IJ-RS-Z_] {
+<expr>"lt"  { return T_OP_LT; }
+<expr>"le"  { return T_OP_LE; }
+<expr>"gt"  { return T_OP_GT; }
+<expr>"ge"  { return T_OP_GE; }
+<expr>"ne"  { return T_OP_NE; }
+<expr>"eq"  { return T_OP_EQ; }
+<expr>"in"  { return T_OP_IN; }
+
+<expr>"-"[a-zA-Z_][a-zA-Z_0-9]+ {
     yylval->cpVal = apr_pstrdup(yyextra->pool, yytext + 1);
-    return T_OP_UNARY;
+    return T_OP_BINARY;
 }
 
-"-"[a-ij-rs-zA-IJ-RS-Z_][a-ij-rs-zA-IJ-RS-Z_0-9]+ {
+<expr>"-"[a-zA-Z_] {
     yylval->cpVal = apr_pstrdup(yyextra->pool, yytext + 1);
-    return T_OP_BINARY;
+    return T_OP_UNARY;
+}
+
+ /* Split a string (or list) into a(nother) list */
+<expr>"split" {
+    STATE_PUSH(split, 0);
+    return T_OP_SPLIT;
+}
+<split>{REG_SEP} {
+    STATE_POP(0); /* <split> */
+    STATE_PUSH(regex, 1);
+    str_stop = yytext[0];
+    str_flag = 'S';
+}
+<split>{ANY} {
+    PERROR("Expecting split regular expression");
+}
+<split><<EOF>> {
+    PERROR("Unterminated split");
+}
+
+ /* Join a list into a string */
+<expr>"join"  {
+    return T_OP_JOIN;
 }
 
  /*
   * Specials
   */
-"true"  { return T_TRUE; }
-"false" { return T_FALSE; }
+<expr>"true"  { return T_TRUE; }
+<expr>"false" { return T_FALSE; }
 
  /*
   * Digits
   */
--?[0-9]+ {
+<expr>\-?[0-9]+ {
     yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
     return T_DIGIT;
 }
  /*
   * Identifiers
   */
-[a-ij-rs-zA-IJ-RS-Z][a-ij-rs-zA-IJ-RS-Z0-9_]* {
+<expr>{TOKEN} {
     yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
     return T_ID;
 }
  /*
   * These are parts of the grammar and are returned as is
   */
-[(){},:] {
+<expr>[(){},] {
     return yytext[0];
 }
 
  /*
   * Anything else is an error
   */
-.|\n {
-    char *msg = apr_psprintf(yyextra->pool, "Parse error near '%c'", yytext[0]);
-    PERROR(msg);
+<INITIAL,expr>{ANY} {
+    PERROR_CHAR("Parse error near character ", yytext[0]);
 }
 
 %%
index 40dbf0787fd7e6ac7f3a64c639ec9c640ac9400b..73e7fc6b1fcb7018c590fb1637cf02f256d2cb58 100644 (file)
@@ -246,6 +246,10 @@ AP_DECLARE(int) ap_regexec_len(const ap_regex_t *preg, const char *buff,
         options |= PCREn(NOTBOL);
     if ((eflags & AP_REG_NOTEOL) != 0)
         options |= PCREn(NOTEOL);
+    if ((eflags & AP_REG_NOTEMPTY) != 0)
+        options |= PCREn(NOTEMPTY);
+    if ((eflags & AP_REG_ANCHORED) != 0)
+        options |= PCREn(ANCHORED);
 
 #ifdef HAVE_PCRE2
     /* TODO: create a generic TLS matchdata buffer of some nmatch limit,