/* 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) yyextra->error2 = msg ; return T_ERROR; #define str_ptr (yyextra->scan_ptr) #define str_buf (yyextra->scan_buf) #define str_del (yyextra->scan_del) %} %% char regex_buf[MAX_STRING_LEN]; char *regex_ptr = NULL; char regex_del = '\0'; /* * Whitespaces */ [ \t\n]+ { /* NOP */ } /* * strings ("..." and '...') */ ["'] { str_ptr = str_buf; str_del = yytext[0]; BEGIN(str); return T_STR_BEGIN; } ["'] { 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_ptr++ = yytext[0]; } } \n { PERROR("Unterminated string or variable"); } <> { PERROR("Unterminated string or variable"); } \\[0-7]{1,3} { int result; (void)sscanf(yytext+1, "%o", &result); if (result > 0xff) { PERROR("Escape sequence out of bound"); } else { *str_ptr++ = result; } } \\[0-9]+ { PERROR("Bad escape sequence"); } \\n { *str_ptr++ = '\n'; } \\r { *str_ptr++ = '\r'; } \\t { *str_ptr++ = '\t'; } \\b { *str_ptr++ = '\b'; } \\f { *str_ptr++ = '\f'; } \\(.|\n) { *str_ptr++ = yytext[1]; } /* regexp backref inside string/arg */ [$][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; } } [^\\\n"'%}$]+ { char *cp = yytext; while (*cp != '\0') *str_ptr++ = *cp++; } /* variable inside string/arg */ %\{ { 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_ptr++ = yytext[0]; } [%}$] { *str_ptr++ = 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 */ [a-zA-Z][a-zA-Z0-9_]* { yylval->cpVal = apr_pstrdup(yyextra->pool, yytext); return T_ID; } \} { yy_pop_state(yyscanner); return T_VAR_END; } : { BEGIN(vararg); return yytext[0]; } .|\n { char *msg = apr_psprintf(yyextra->pool, "Invalid character in variable name '%c'", yytext[0]); PERROR(msg); } \} { 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); } .|\n { if (yytext[0] == regex_del) { *regex_ptr = '\0'; BEGIN(regex_flags); } else { *regex_ptr++ = yytext[0]; } } i { yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf); BEGIN(INITIAL); return T_REGEX_I; } .|\n { yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf); yyless(0); BEGIN(INITIAL); return T_REGEX; } <> { 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); } %%