aboutsummaryrefslogtreecommitdiffstats
path: root/pbx/ael/ael.flex
diff options
context:
space:
mode:
Diffstat (limited to 'pbx/ael/ael.flex')
-rw-r--r--pbx/ael/ael.flex180
1 files changed, 176 insertions, 4 deletions
diff --git a/pbx/ael/ael.flex b/pbx/ael/ael.flex
index 866e36170..2bf00695b 100644
--- a/pbx/ael/ael.flex
+++ b/pbx/ael/ael.flex
@@ -26,7 +26,7 @@
*
* %x describes the contexts we have: paren, semic and argg, plus INITIAL
*/
-%x paren semic argg comment
+%x paren semic argg comment curlystate wordstate brackstate
/* prefix used for various globally-visible functions and variables.
* This renames also yywrap, but since we do not use it, we just
@@ -83,10 +83,28 @@ static char pbcstack[400]; /* XXX missing size checks */
static int pbcpos = 0;
static void pbcpush(char x);
static int pbcpop(char x);
-
static int parencount = 0;
/*
+ * A similar stack to keep track of matching brackets ( [ { } ] ) in word tokens surrounded by ${ ... }
+ */
+static char pbcstack2[400]; /* XXX missing size checks */
+static int pbcpos2 = 0;
+static void pbcpush2(char x);
+static int pbcpop2(char x);
+static int parencount2 = 0;
+
+/*
+ * A similar stack to keep track of matching brackets ( [ { } ] ) in word tokens surrounded by $[ ... ]
+ */
+static char pbcstack3[400]; /* XXX missing size checks */
+static int pbcpos3 = 0;
+static void pbcpush3(char x);
+static int pbcpop3(char x);
+static int parencount3 = 0;
+
+
+/*
* current line, column and filename, updated as we read the input.
*/
static int my_lineno = 1; /* current line in the source */
@@ -175,6 +193,7 @@ static void pbcwhere(const char *text, int *line, int *col )
#endif
%}
+KEYWORD (context|abstract|extend|macro|globals|local|ignorepat|switch|if|ifTime|random|regexten|hint|else|goto|jump|return|break|continue|for|while|case|default|pattern|catch|switches|eswitches|includes)
NOPARENS ([^()\[\]\{\}]|\\[()\[\]\{\}])*
@@ -230,19 +249,140 @@ includes { STORE_POS; return KW_INCLUDES;}
<comment>[^*\n]*\n { ++my_lineno; my_col=1;}
<comment>"*"+[^*/\n]* { my_col += yyleng; }
<comment>"*"+[^*/\n]*\n { ++my_lineno; my_col=1;}
-<comment>"*/" { my_col += 2; BEGIN(INITIAL); }
+<comment>"*/" { my_col += 2; BEGIN(INITIAL); } /* the nice thing about comments is that you know exactly what ends them */
\n { my_lineno++; my_col = 1; }
[ ]+ { my_col += yyleng; }
[\t]+ { my_col += (yyleng*8)-(my_col%8); }
-[-a-zA-Z0-9'"_/.\<\>\*\+!$#\[\]][-a-zA-Z0-9'"_/.!\*\+\<\>\{\}$#\[\]]* {
+({KEYWORD}?[-a-zA-Z0-9'"_/.\<\>\*\+!$#\[\]]|(\\.)|(\$\{)|(\$\[)) {
+ /* boy did I open a can of worms when I changed the lexical token "word".
+ all the above keywords can be used as a beginning to a "word".-
+ before, a "word" would match a longer sequence than the above
+ keywords, and all would be well. But now "word" is a single char
+ and feeds into a statemachine sort of sequence from there on. So...
+ I added the {KEYWORD}? to the beginning of the word match sequence */
+
+ if (!strcmp(yytext,"${")) {
+ parencount2 = 0;
+ pbcpos2 = 0;
+ pbcpush2('{'); /* push '{' so the last pcbpop (parencount2 = -1) will succeed */
+ BEGIN(curlystate);
+ yymore();
+ } else if (!strcmp(yytext,"$[")) {
+ parencount3 = 0;
+ pbcpos3 = 0;
+ pbcpush3('['); /* push '[' so the last pcbpop (parencount3 = -1) will succeed */
+ BEGIN(brackstate);
+ yymore();
+ } else {
+ BEGIN(wordstate);
+ yymore();
+ }
+ }
+<wordstate>[-a-zA-Z0-9'"_/.\<\>\*\+!$#\[\]] { yymore(); /* Keep going */ }
+<wordstate>(\\.) { yymore(); /* Keep Going */ }
+<wordstate>(\$\{) { /* the beginning of a ${} construct. prepare and pop into curlystate */
+ parencount2 = 0;
+ pbcpos2 = 0;
+ pbcpush2('{'); /* push '{' so the last pcbpop (parencount2 = -1) will succeed */
+ BEGIN(curlystate);
+ yymore();
+ }
+<wordstate>(\$\[) { /* the beginning of a $[] construct. prepare and pop into brackstate */
+ parencount3 = 0;
+ pbcpos3 = 0;
+ pbcpush3('['); /* push '[' so the last pcbpop (parencount3 = -1) will succeed */
+ BEGIN(brackstate);
+ yymore();
+ }
+<wordstate>([^a-zA-Z0-9\x80-\xff\x2d'"_/.\<\>\*\+!$#\[\]]) {
+ /* a non-word constituent char, like a space, tab, curly, paren, etc */
+ char c = yytext[yyleng-1];
STORE_POS;
yylval->str = strdup(yytext);
+ yylval->str[yyleng-1] = 0;
+ unput(c); /* put this ending char back in the stream */
+ BEGIN(0);
prev_word = yylval->str;
return word;
}
+<curlystate>{NOPARENS}\} {
+ if ( pbcpop2('}') ) { /* error */
+ STORE_LOC;
+ ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched ')' in expression: %s !\n", my_file, my_lineno, my_col, yytext);
+ BEGIN(0);
+ yylval->str = strdup(yytext);
+ return word;
+ }
+ parencount2--;
+ if ( parencount2 >= 0) {
+ yymore();
+ } else {
+ BEGIN(wordstate); /* Finished with the current ${} construct. Return to word gathering state */
+ yymore();
+ }
+ }
+<curlystate>{NOPARENS}[\(\[\{] {
+ char c = yytext[yyleng-1];
+ if (c == '{')
+ parencount2++;
+ pbcpush2(c);
+ yymore();
+ }
+
+<curlystate>{NOPARENS}[\]\)] {
+ char c = yytext[yyleng-1];
+ if ( pbcpop2(c)) { /* error */
+ STORE_LOC;
+ ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched '%c' in expression!\n",
+ my_file, my_lineno, my_col, c);
+ BEGIN(0);
+ yylval->str = strdup(yytext);
+ return word;
+ }
+ yymore();
+ }
+
+
+<brackstate>{NOPARENS}\] {
+ if ( pbcpop3(']') ) { /* error */
+ STORE_LOC;
+ ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched ')' in expression: %s !\n", my_file, my_lineno, my_col, yytext);
+ BEGIN(0);
+ yylval->str = strdup(yytext);
+ return word;
+ }
+ parencount3--;
+ if ( parencount3 >= 0) {
+ yymore();
+ } else {
+ BEGIN(wordstate); /* Finished with the current ${} construct. Return to word gathering state */
+ yymore();
+ }
+ }
+
+<brackstate>{NOPARENS}[\(\[\{] {
+ char c = yytext[yyleng-1];
+ if (c == '[')
+ parencount3++;
+ pbcpush3(c);
+ yymore();
+ }
+
+<brackstate>{NOPARENS}[\}\)] {
+ char c = yytext[yyleng-1];
+ if ( pbcpop3(c)) { /* error */
+ STORE_LOC;
+ ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched '%c' in expression!\n",
+ my_file, my_lineno, my_col, c);
+ BEGIN(0);
+ yylval->str = strdup(yytext);
+ return word;
+ }
+ yymore();
+ }
/*
@@ -491,6 +631,38 @@ static int pbcpop(char x)
return 1; /* error */
}
+static void pbcpush2(char x)
+{
+ pbcstack2[pbcpos2++] = x;
+}
+
+static int pbcpop2(char x)
+{
+ if ( ( x == ')' && pbcstack2[pbcpos2-1] == '(' )
+ || ( x == ']' && pbcstack2[pbcpos2-1] == '[' )
+ || ( x == '}' && pbcstack2[pbcpos2-1] == '{' )) {
+ pbcpos2--;
+ return 0;
+ }
+ return 1; /* error */
+}
+
+static void pbcpush3(char x)
+{
+ pbcstack3[pbcpos3++] = x;
+}
+
+static int pbcpop3(char x)
+{
+ if ( ( x == ')' && pbcstack3[pbcpos3-1] == '(' )
+ || ( x == ']' && pbcstack3[pbcpos3-1] == '[' )
+ || ( x == '}' && pbcstack3[pbcpos3-1] == '{' )) {
+ pbcpos3--;
+ return 0;
+ }
+ return 1; /* error */
+}
+
static int c_prevword(void)
{
char *c = prev_word;