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 401