| /* Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* |
| * ap_expr_scan.l, based on ssl_expr_scan.l from mod_ssl |
| */ |
| |
| /* _________________________________________________________________ |
| ** |
| ** Expression Scanner |
| ** _________________________________________________________________ |
| */ |
| |
| %pointer |
| %option batch |
| %option never-interactive |
| %option nodefault |
| %option noyywrap |
| %option reentrant |
| %option bison-bridge |
| %option warn |
| %option noinput nounput noyy_top_state |
| %option stack |
| %x str |
| %x var |
| %x vararg |
| %x regex regex_flags |
| |
| %{ |
| #include "util_expr_private.h" |
| #include "util_expr_parse.h" |
| |
| #undef YY_INPUT |
| #define YY_INPUT(buf,result,max_size) \ |
| { \ |
| if ((result = MIN(max_size, yyextra->inputbuf \ |
| + yyextra->inputlen \ |
| - yyextra->inputptr)) <= 0) \ |
| { \ |
| result = YY_NULL; \ |
| } \ |
| else { \ |
| memcpy(buf, yyextra->inputptr, result); \ |
| yyextra->inputptr += result; \ |
| } \ |
| } |
| |
| #define YY_EXTRA_TYPE ap_expr_parse_ctx_t* |
| |
| #define PERROR(msg) do { yyextra->error2 = msg ; return T_ERROR; } while (0) |
| |
| #define str_ptr (yyextra->scan_ptr) |
| #define str_buf (yyextra->scan_buf) |
| #define str_del (yyextra->scan_del) |
| |
| #define STR_APPEND(c) do { \ |
| *str_ptr++ = (c); \ |
| if (str_ptr >= str_buf + sizeof(str_buf)) \ |
| PERROR("String too long"); \ |
| } while (0) |
| |
| %} |
| |
| |
| %% |
| |
| 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 |
| */ |
| [ \t\n]+ { |
| /* NOP */ |
| } |
| |
| /* |
| * 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; |
| return T_STRING; |
| } |
| } |
| else { |
| STR_APPEND(yytext[0]); |
| } |
| } |
| <str,var,vararg>\n { |
| PERROR("Unterminated string or variable"); |
| } |
| <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); |
| return T_STRING; |
| } |
| } |
| |
| <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); |
| } |
| } |
| <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); |
| return T_STRING; |
| } |
| else { |
| yylval->num = yytext[1] - '0'; |
| return T_REGEX_BACKREF; |
| } |
| } |
| |
| <str,vararg>[^\\\n"'%}$]+ { |
| char *cp = yytext; |
| while (*cp != '\0') { |
| STR_APPEND(*cp); |
| cp++; |
| } |
| } |
| |
| /* 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; |
| } |
| } |
| |
| <vararg>[%$] { |
| STR_APPEND(yytext[0]); |
| } |
| |
| <str>[%}$] { |
| STR_APPEND(yytext[0]); |
| } |
| |
| %\{ { |
| yy_push_state(var, yyscanner); |
| return T_VAR_BEGIN; |
| } |
| |
| [$][0-9] { |
| yylval->num = yytext[1] - '0'; |
| return T_REGEX_BACKREF; |
| } |
| |
| /* |
| * fixed name variable expansion %{XXX} and function call in %{func:arg} syntax |
| */ |
| <var>[a-zA-Z][a-zA-Z0-9_]* { |
| yylval->cpVal = apr_pstrdup(yyextra->pool, yytext); |
| return T_ID; |
| } |
| |
| <var>\} { |
| yy_pop_state(yyscanner); |
| return T_VAR_END; |
| } |
| |
| <var>: { |
| BEGIN(vararg); |
| return yytext[0]; |
| } |
| |
| <var>.|\n { |
| char *msg = apr_psprintf(yyextra->pool, |
| "Invalid character in variable name '%c'", yytext[0]); |
| PERROR(msg); |
| } |
| |
| <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); |
| } |
| else { |
| *regex_ptr++ = yytext[0]; |
| if (regex_ptr >= regex_buf + sizeof(regex_buf)) |
| PERROR("Regexp too long"); |
| } |
| } |
| <regex_flags>i { |
| yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf); |
| BEGIN(INITIAL); |
| return T_REGEX_I; |
| } |
| <regex_flags>.|\n { |
| yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf); |
| yyless(0); |
| BEGIN(INITIAL); |
| return T_REGEX; |
| } |
| <regex_flags><<EOF>> { |
| yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf); |
| BEGIN(INITIAL); |
| return T_REGEX; |
| } |
| |
| /* |
| * 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; } |
| |
| /* 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-zA-Z_] { |
| yylval->cpVal = apr_pstrdup(yyextra->pool, yytext + 1); |
| return T_OP_UNARY; |
| } |
| |
| "-"[a-zA-Z_][a-zA-Z_0-9]+ { |
| yylval->cpVal = apr_pstrdup(yyextra->pool, yytext + 1); |
| return T_OP_BINARY; |
| } |
| |
| /* |
| * Specials |
| */ |
| "true" { return T_TRUE; } |
| "false" { return T_FALSE; } |
| |
| /* |
| * Digits |
| */ |
| -?[0-9]+ { |
| yylval->cpVal = apr_pstrdup(yyextra->pool, yytext); |
| return T_DIGIT; |
| } |
| |
| /* |
| * Identifiers |
| */ |
| [a-zA-Z][a-zA-Z0-9_]* { |
| yylval->cpVal = apr_pstrdup(yyextra->pool, yytext); |
| return T_ID; |
| } |
| |
| /* |
| * These are parts of the grammar and are returned as is |
| */ |
| [(){},:] { |
| return yytext[0]; |
| } |
| |
| /* |
| * Anything else is an error |
| */ |
| .|\n { |
| char *msg = apr_psprintf(yyextra->pool, "Parse error near '%c'", yytext[0]); |
| PERROR(msg); |
| } |
| |
| %% |
| |
| |