]> granicus.if.org Git - apache/blob - server/util_expr_scan.l
Merge r1741310, r1741461 from trunk:
[apache] / server / util_expr_scan.l
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 /*
18  *  ap_expr_scan.l, based on ssl_expr_scan.l from mod_ssl
19  */
20
21 /*  _________________________________________________________________
22 **
23 **  Expression Scanner
24 **  _________________________________________________________________
25 */
26
27 %pointer
28 %option batch
29 %option never-interactive
30 %option nodefault
31 %option noyywrap
32 %option reentrant
33 %option bison-bridge
34 %option warn
35 %option noinput nounput noyy_top_state
36 %option stack
37 %x str
38 %x var
39 %x vararg
40 %x regex regex_flags
41
42 %{
43 #include "util_expr_private.h"
44 #include "util_expr_parse.h"
45
46 #undef  YY_INPUT
47 #define YY_INPUT(buf,result,max_size)                       \
48 {                                                           \
49     if ((result = MIN(max_size, yyextra->inputbuf           \
50                               + yyextra->inputlen           \
51                               - yyextra->inputptr)) <= 0)   \
52     {                                                       \
53         result = YY_NULL;                                   \
54     }                                                       \
55     else {                                                  \
56         memcpy(buf, yyextra->inputptr, result);             \
57         yyextra->inputptr += result;                        \
58     }                                                       \
59 }
60
61 #define YY_EXTRA_TYPE ap_expr_parse_ctx_t*
62
63 #define PERROR(msg) do { yyextra->error2 = msg ; return T_ERROR; } while (0)
64
65 #define str_ptr     (yyextra->scan_ptr)
66 #define str_buf     (yyextra->scan_buf)
67 #define str_del     (yyextra->scan_del)
68
69 #define STR_APPEND(c) do {                          \
70         *str_ptr++ = (c);                           \
71         if (str_ptr >= str_buf + sizeof(str_buf))   \
72             PERROR("String too long");              \
73     } while (0)
74
75 %}
76
77
78 %%
79
80   char  regex_buf[MAX_STRING_LEN];
81   char *regex_ptr = NULL;
82   char  regex_del = '\0';
83
84 %{
85  /*
86   * Set initial state for string expressions
87   */
88   if (yyextra->at_start) {
89     yyextra->at_start = 0;
90     if (yyextra->flags & AP_EXPR_FLAG_STRING_RESULT) {
91         BEGIN(str);
92         return T_EXPR_STRING;
93     }
94     else {
95         return T_EXPR_BOOL;
96     }
97   }
98 %}
99
100  /*
101   * Whitespaces
102   */
103 [ \t\n]+ { 
104     /* NOP */
105 }
106
107  /*
108   * strings ("..." and '...')
109   */
110 ["'] {
111     str_ptr = str_buf;
112     str_del = yytext[0];
113     BEGIN(str);
114     return T_STR_BEGIN;
115 }
116 <str>["'] {
117     if (yytext[0] == str_del) {
118         if (YY_START == var) {
119             PERROR("Unterminated variable in string");
120         }
121         else if (str_ptr == str_buf) {
122             BEGIN(INITIAL);
123             return T_STR_END;
124         }
125         else {
126             /* return what we have so far and scan delimiter again */
127             *str_ptr = '\0';
128             yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
129             yyless(0);
130             str_ptr = str_buf;
131             return T_STRING;
132         }
133     }
134     else {
135         STR_APPEND(yytext[0]);
136     }
137 }
138 <str,var,vararg>\n {
139     PERROR("Unterminated string or variable");
140 }
141 <var,vararg><<EOF>> {
142     PERROR("Unterminated string or variable");
143 }
144 <str><<EOF>> {
145     if (!(yyextra->flags & AP_EXPR_FLAG_STRING_RESULT)) {
146         PERROR("Unterminated string or variable");
147     }
148     else {
149         *str_ptr = '\0';
150         yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
151         str_ptr = str_buf;
152         BEGIN(INITIAL);
153         return T_STRING;
154     }
155 }
156
157 <str,vararg>\\[0-7]{1,3} {
158     int result;
159
160     (void)sscanf(yytext+1, "%o", &result);
161     if (result > 0xff) {
162         PERROR("Escape sequence out of bound");
163     }
164     else {
165         STR_APPEND(result);
166     }
167 }
168 <str,vararg>\\[0-9]+ {
169     PERROR("Bad escape sequence");
170 }
171 <str,vararg>\\n      { STR_APPEND('\n'); }
172 <str,vararg>\\r      { STR_APPEND('\r'); }
173 <str,vararg>\\t      { STR_APPEND('\t'); }
174 <str,vararg>\\b      { STR_APPEND('\b'); }
175 <str,vararg>\\f      { STR_APPEND('\f'); }
176 <str,vararg>\\(.|\n) { STR_APPEND(yytext[1]); }
177
178  /* regexp backref inside string/arg */
179 <str,vararg>[$][0-9] {
180     if (str_ptr != str_buf) {
181         /* return what we have so far and scan '$x' again */
182         *str_ptr = '\0';
183         yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
184         str_ptr = str_buf;
185         yyless(0);
186         return T_STRING;
187     }
188     else {
189         yylval->num = yytext[1] - '0';
190         return T_REGEX_BACKREF;
191     }
192 }
193
194 <str,vararg>[^\\\n"'%}$]+ {
195     char *cp = yytext;
196     while (*cp != '\0') {
197         STR_APPEND(*cp);
198         cp++;
199     }
200 }
201
202  /* variable inside string/arg */
203 <str,vararg>%\{ {
204     if (str_ptr != str_buf) {
205         /* return what we have so far and scan '%{' again */
206         *str_ptr = '\0';
207         yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
208         yyless(0);
209         str_ptr = str_buf;
210         return T_STRING;
211     }
212     else {
213         yy_push_state(var, yyscanner);
214         return T_VAR_BEGIN;
215     }
216 }
217
218 <vararg>[%$] {
219      STR_APPEND(yytext[0]);
220 }
221
222 <str>[%}$] {
223      STR_APPEND(yytext[0]);
224 }
225
226 %\{ {
227     yy_push_state(var, yyscanner);
228     return T_VAR_BEGIN;
229 }
230
231 [$][0-9] {
232     yylval->num = yytext[1] - '0';
233     return T_REGEX_BACKREF;
234 }
235
236  /*
237   * fixed name variable expansion %{XXX} and function call in %{func:arg} syntax
238   */
239 <var>[a-zA-Z][a-zA-Z0-9_]* {
240     yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
241     return T_ID;
242 }
243
244 <var>\} {
245     yy_pop_state(yyscanner);
246     return T_VAR_END;
247 }
248
249 <var>: {
250     BEGIN(vararg);
251     return yytext[0];
252 }
253
254 <var>.|\n {
255     char *msg = apr_psprintf(yyextra->pool,
256                              "Invalid character in variable name '%c'", yytext[0]);
257     PERROR(msg);
258 }
259
260 <vararg>\} {
261     if (str_ptr != str_buf) {
262         /* return what we have so far and scan '}' again */
263         *str_ptr = '\0';
264         yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
265         str_ptr = str_buf;
266         yyless(0);
267         return T_STRING;
268     }
269     else {
270         yy_pop_state(yyscanner);
271         return T_VAR_END;
272     }
273 }
274
275  /*
276   * Regular Expression
277   */
278 "m"[/#$%^,;:_\?\|\^\-\!\.\'\"] {
279     regex_del = yytext[1];
280     regex_ptr = regex_buf;
281     BEGIN(regex);
282 }
283 "/" {
284     regex_del = yytext[0];
285     regex_ptr = regex_buf;
286     BEGIN(regex);
287 }
288 <regex>.|\n {
289     if (yytext[0] == regex_del) {
290         *regex_ptr = '\0';
291         BEGIN(regex_flags);
292     }
293     else {
294         *regex_ptr++ = yytext[0];
295         if (regex_ptr >= regex_buf + sizeof(regex_buf))
296             PERROR("Regexp too long");
297     }
298 }
299 <regex_flags>i {
300     yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf);
301     BEGIN(INITIAL);
302     return T_REGEX_I;
303 }
304 <regex_flags>.|\n {
305     yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf);
306     yyless(0);
307     BEGIN(INITIAL);
308     return T_REGEX;
309 }
310 <regex_flags><<EOF>> {
311     yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf);
312     BEGIN(INITIAL);
313     return T_REGEX;
314 }
315
316  /*
317   * Operators
318   */
319 ==?   { return T_OP_STR_EQ; }
320 "!="  { return T_OP_STR_NE; }
321 "<"   { return T_OP_STR_LT; }
322 "<="  { return T_OP_STR_LE; }
323 ">"   { return T_OP_STR_GT; }
324 ">="  { return T_OP_STR_GE; }
325 "=~"  { return T_OP_REG; }
326 "!~"  { return T_OP_NRE; }
327 "and" { return T_OP_AND; }
328 "&&"  { return T_OP_AND; }
329 "or"  { return T_OP_OR; }
330 "||"  { return T_OP_OR; }
331 "not" { return T_OP_NOT; }
332 "!"   { return T_OP_NOT; }
333 "."   { return T_OP_CONCAT; }
334 "-in"  { return T_OP_IN; }
335 "-eq"  { return T_OP_EQ; }
336 "-ne"  { return T_OP_NE; }
337 "-ge"  { return T_OP_GE; }
338 "-le"  { return T_OP_LE; }
339 "-gt"  { return T_OP_GT; }
340 "-lt"  { return T_OP_LT; }
341
342  /* for compatibility with ssl_expr */
343 "lt"  { return T_OP_LT; }
344 "le"  { return T_OP_LE; }
345 "gt"  { return T_OP_GT; }
346 "ge"  { return T_OP_GE; }
347 "ne"  { return T_OP_NE; }
348 "eq"  { return T_OP_EQ; }
349 "in"  { return T_OP_IN; }
350
351 "-"[a-zA-Z_] {
352     yylval->cpVal = apr_pstrdup(yyextra->pool, yytext + 1);
353     return T_OP_UNARY;
354 }
355
356 "-"[a-zA-Z_][a-zA-Z_0-9]+ {
357     yylval->cpVal = apr_pstrdup(yyextra->pool, yytext + 1);
358     return T_OP_BINARY;
359 }
360
361  /*
362   * Specials
363   */
364 "true"  { return T_TRUE; }
365 "false" { return T_FALSE; }
366
367  /*
368   * Digits
369   */
370 -?[0-9]+ {
371     yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
372     return T_DIGIT;
373 }
374
375  /*
376   * Identifiers
377   */
378 [a-zA-Z][a-zA-Z0-9_]* {
379     yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
380     return T_ID;
381 }
382
383  /*
384   * These are parts of the grammar and are returned as is
385   */
386 [(){},:] {
387     return yytext[0];
388 }
389
390  /*
391   * Anything else is an error
392   */
393 .|\n {
394     char *msg = apr_psprintf(yyextra->pool, "Parse error near '%c'", yytext[0]);
395     PERROR(msg);
396 }
397
398 %%
399
400