1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/* based on ap_expr_parse.y from mod_ssl */
18
19/*  _________________________________________________________________
20**
21**  Expression Parser
22**  _________________________________________________________________
23*/
24
25%pure-parser
26%error-verbose
27%defines
28%lex-param   { void *yyscanner }
29%parse-param { ap_expr_parse_ctx_t *ctx }
30
31%{
32#include "util_expr_private.h"
33%}
34
35%union {
36    char      *cpVal;
37    ap_expr_t *exVal;
38    int        num;
39}
40
41%token  T_TRUE
42%token  T_FALSE
43
44%token  T_EXPR_BOOL
45%token  T_EXPR_STRING
46
47%token  <cpVal> T_ERROR
48
49%token  <cpVal> T_DIGIT
50%token  <cpVal> T_ID
51%token  <cpVal> T_STRING
52%token  <cpVal> T_REGEX
53%token  <cpVal> T_REGEX_I
54%token  <num>   T_REGEX_BACKREF
55%token  <cpVal> T_OP_UNARY
56%token  <cpVal> T_OP_BINARY
57
58%token  T_STR_BEGIN
59%token  T_STR_END
60%token  T_VAR_BEGIN
61%token  T_VAR_END
62
63%token  T_OP_EQ
64%token  T_OP_NE
65%token  T_OP_LT
66%token  T_OP_LE
67%token  T_OP_GT
68%token  T_OP_GE
69%token  T_OP_REG
70%token  T_OP_NRE
71%token  T_OP_IN
72%token  T_OP_STR_EQ
73%token  T_OP_STR_NE
74%token  T_OP_STR_LT
75%token  T_OP_STR_LE
76%token  T_OP_STR_GT
77%token  T_OP_STR_GE
78%token  T_OP_CONCAT
79
80%token  T_OP_OR
81%token  T_OP_AND
82%token  T_OP_NOT
83
84%right  T_OP_OR
85%right  T_OP_AND
86%right  T_OP_NOT
87%right  T_OP_CONCAT
88
89%type   <exVal>   expr
90%type   <exVal>   comparison
91%type   <exVal>   strfunccall
92%type   <exVal>   lstfunccall
93%type   <exVal>   regex
94%type   <exVal>   words
95%type   <exVal>   wordlist
96%type   <exVal>   word
97%type   <exVal>   string
98%type   <exVal>   strpart
99%type   <exVal>   var
100%type   <exVal>   backref
101
102%{
103#include "util_expr_private.h"
104#define yyscanner ctx->scanner
105
106int ap_expr_yylex(YYSTYPE *lvalp, void *scanner);
107%}
108
109
110%%
111
112root      : T_EXPR_BOOL   expr           { ctx->expr = $2; }
113          | T_EXPR_STRING string         { ctx->expr = $2; }
114          | T_ERROR                      { YYABORT; }
115          ;
116
117expr      : T_TRUE                       { $$ = ap_expr_make(op_True,        NULL, NULL, ctx); }
118          | T_FALSE                      { $$ = ap_expr_make(op_False,       NULL, NULL, ctx); }
119          | T_OP_NOT expr                { $$ = ap_expr_make(op_Not,         $2,   NULL, ctx); }
120          | expr T_OP_OR expr            { $$ = ap_expr_make(op_Or,          $1,   $3,   ctx); }
121          | expr T_OP_AND expr           { $$ = ap_expr_make(op_And,         $1,   $3,   ctx); }
122          | comparison                   { $$ = ap_expr_make(op_Comp,        $1,   NULL, ctx); }
123          | T_OP_UNARY word              { $$ = ap_expr_unary_op_make(       $1,   $2,   ctx); }
124          | word T_OP_BINARY word        { $$ = ap_expr_binary_op_make($2,   $1,   $3,   ctx); }
125          | '(' expr ')'                 { $$ = $2; }
126          | T_ERROR                      { YYABORT; }
127          ;
128
129comparison: word T_OP_EQ word            { $$ = ap_expr_make(op_EQ,      $1, $3, ctx); }
130          | word T_OP_NE word            { $$ = ap_expr_make(op_NE,      $1, $3, ctx); }
131          | word T_OP_LT word            { $$ = ap_expr_make(op_LT,      $1, $3, ctx); }
132          | word T_OP_LE word            { $$ = ap_expr_make(op_LE,      $1, $3, ctx); }
133          | word T_OP_GT word            { $$ = ap_expr_make(op_GT,      $1, $3, ctx); }
134          | word T_OP_GE word            { $$ = ap_expr_make(op_GE,      $1, $3, ctx); }
135          | word T_OP_STR_EQ word        { $$ = ap_expr_make(op_STR_EQ,  $1, $3, ctx); }
136          | word T_OP_STR_NE word        { $$ = ap_expr_make(op_STR_NE,  $1, $3, ctx); }
137          | word T_OP_STR_LT word        { $$ = ap_expr_make(op_STR_LT,  $1, $3, ctx); }
138          | word T_OP_STR_LE word        { $$ = ap_expr_make(op_STR_LE,  $1, $3, ctx); }
139          | word T_OP_STR_GT word        { $$ = ap_expr_make(op_STR_GT,  $1, $3, ctx); }
140          | word T_OP_STR_GE word        { $$ = ap_expr_make(op_STR_GE,  $1, $3, ctx); }
141          | word T_OP_IN wordlist        { $$ = ap_expr_make(op_IN,      $1, $3, ctx); }
142          | word T_OP_REG regex          { $$ = ap_expr_make(op_REG,     $1, $3, ctx); }
143          | word T_OP_NRE regex          { $$ = ap_expr_make(op_NRE,     $1, $3, ctx); }
144          ;
145
146wordlist  : lstfunccall                  { $$ = $1; }
147          | '{' words '}'                { $$ = $2; }
148          ;
149
150words     : word                         { $$ = ap_expr_make(op_ListElement, $1, NULL, ctx); }
151          | words ',' word               { $$ = ap_expr_make(op_ListElement, $3, $1,   ctx); }
152          ;
153
154string    : string strpart               { $$ = ap_expr_make(op_Concat, $1, $2, ctx); }
155          | strpart                      { $$ = $1; }
156          | T_ERROR                      { YYABORT; }
157          ;
158
159strpart   : T_STRING                     { $$ = ap_expr_make(op_String, $1, NULL, ctx); }
160          | var                          { $$ = $1; }
161          | backref                      { $$ = $1; }
162          ;
163
164var       : T_VAR_BEGIN T_ID T_VAR_END            { $$ = ap_expr_var_make($2, ctx); }
165          | T_VAR_BEGIN T_ID ':' string T_VAR_END { $$ = ap_expr_str_func_make($2, $4, ctx); }
166          ;
167
168word      : T_DIGIT                      { $$ = ap_expr_make(op_Digit,  $1, NULL, ctx); }
169          | word T_OP_CONCAT word        { $$ = ap_expr_make(op_Concat, $1, $3,   ctx); }
170          | var                          { $$ = $1; }
171          | backref                      { $$ = $1; }
172          | strfunccall                  { $$ = $1; }
173          | T_STR_BEGIN string T_STR_END { $$ = $2; }
174          | T_STR_BEGIN T_STR_END        { $$ = ap_expr_make(op_String, "", NULL, ctx); }
175          ;
176
177regex     : T_REGEX {
178                ap_regex_t *regex;
179                if ((regex = ap_pregcomp(ctx->pool, $1,
180                                         AP_REG_EXTENDED|AP_REG_NOSUB)) == NULL) {
181                    ctx->error = "Failed to compile regular expression";
182                    YYERROR;
183                }
184                $$ = ap_expr_make(op_Regex, regex, NULL, ctx);
185            }
186          | T_REGEX_I {
187                ap_regex_t *regex;
188                if ((regex = ap_pregcomp(ctx->pool, $1,
189                                         AP_REG_EXTENDED|AP_REG_NOSUB|AP_REG_ICASE)) == NULL) {
190                    ctx->error = "Failed to compile regular expression";
191                    YYERROR;
192                }
193                $$ = ap_expr_make(op_Regex, regex, NULL, ctx);
194            }
195          ;
196
197backref     : T_REGEX_BACKREF   {
198                int *n = apr_palloc(ctx->pool, sizeof(int));
199                *n = $1;
200                $$ = ap_expr_make(op_RegexBackref, n, NULL, ctx);
201            }
202            ;
203
204lstfunccall : T_ID '(' word ')' { $$ = ap_expr_list_func_make($1, $3, ctx); }
205            ;
206
207strfunccall : T_ID '(' word ')' { $$ = ap_expr_str_func_make($1, $3, ctx); }
208            ;
209
210%%
211
212void yyerror(ap_expr_parse_ctx_t *ctx, const char *s)
213{
214    /* s is allocated on the stack */
215    ctx->error = apr_pstrdup(ctx->ptemp, s);
216}
217
218