summaryrefslogtreecommitdiffstats
path: root/server/util_expr_scan.l
diff options
context:
space:
mode:
authorStefan Fritsch <sf@apache.org>2010-11-06 15:31:16 +0100
committerStefan Fritsch <sf@apache.org>2010-11-06 15:31:16 +0100
commit35cdba6976ca6f8a9bde73267340c40d7ae6d496 (patch)
treecc1609882f476369e5edea4aef79a868fef4f7fd /server/util_expr_scan.l
parentPut the expression parser back into mod_include (diff)
downloadapache2-35cdba6976ca6f8a9bde73267340c40d7ae6d496.tar.xz
apache2-35cdba6976ca6f8a9bde73267340c40d7ae6d496.zip
Replace ap_expr with a parser derived from mod_ssl's parser. Make mod_ssl use
the new parser. Rework ap_expr's public interface and provide hooks for modules to add variables and functions. The Netware and Windows build files still need to be adjusted git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1032073 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'server/util_expr_scan.l')
-rw-r--r--server/util_expr_scan.l344
1 files changed, 344 insertions, 0 deletions
diff --git a/server/util_expr_scan.l b/server/util_expr_scan.l
new file mode 100644
index 0000000000..d2840a00b4
--- /dev/null
+++ b/server/util_expr_scan.l
@@ -0,0 +1,344 @@
+/* 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
+%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*
+
+#define PERROR(msg) yyextra->error2 = msg ; return 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;
+}
+<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_ptr++ = yytext[0];
+ }
+}
+<str,var,vararg>\n {
+ PERROR("Unterminated string or variable");
+}
+<str,var,vararg><<EOF>> {
+ PERROR("Unterminated string or variable");
+}
+<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_ptr++ = result;
+ }
+}
+<str,vararg>\\[0-9]+ {
+ PERROR("Bad escape sequence");
+}
+<str,vararg>\\n { *str_ptr++ = '\n'; }
+<str,vararg>\\r { *str_ptr++ = '\r'; }
+<str,vararg>\\t { *str_ptr++ = '\t'; }
+<str,vararg>\\b { *str_ptr++ = '\b'; }
+<str,vararg>\\f { *str_ptr++ = '\f'; }
+<str,vararg>\\(.|\n) {
+ *str_ptr++ = yytext[1];
+}
+
+<str,vararg>[^\\\n"'%}]+ {
+ char *cp = yytext;
+ while (*cp != '\0')
+ *str_ptr++ = *cp++;
+}
+
+ /* variable inside string */
+<str>%\{ {
+ 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_ptr++ = yytext[0];
+}
+
+<str>[%}] {
+ *str_ptr++ = yytext[0];
+}
+
+%\{ {
+ yy_push_state(var, yyscanner);
+ return T_VAR_BEGIN;
+}
+
+ /*
+ * 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 c[2] = { yytext[0], '\0' };
+ char *msg = apr_psprintf(yyextra->pool,
+ "Invalid character in variable name '%s'", c);
+ 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];
+ }
+}
+<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 c[2] = { yytext[0], '\0' };
+ char *msg = apr_psprintf(yyextra->pool, "Parse error near '%s'", c);
+ PERROR(msg);
+}
+
+%%
+
+