diff options
author | russell <russell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2008-01-28 23:16:56 +0000 |
---|---|---|
committer | russell <russell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2008-01-28 23:16:56 +0000 |
commit | 669718ba3bb84f8f71f8fa9ebc54c6c7f63a9095 (patch) | |
tree | 0d7f195877da7546ad7274f0f0ab16fecf9105c5 /trunk/res/ael | |
parent | 3fe43295be6074b01ac631d443ac979791b15d72 (diff) |
Creating tag for the release of asterisk-1.6.0-beta2
git-svn-id: http://svn.digium.com/svn/asterisk/tags/1.6.0-beta2@100719 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'trunk/res/ael')
-rw-r--r-- | trunk/res/ael/ael.flex | 694 | ||||
-rw-r--r-- | trunk/res/ael/ael.tab.c | 3413 | ||||
-rw-r--r-- | trunk/res/ael/ael.tab.h | 154 | ||||
-rw-r--r-- | trunk/res/ael/ael.y | 823 | ||||
-rw-r--r-- | trunk/res/ael/ael_lex.c | 3127 | ||||
-rw-r--r-- | trunk/res/ael/pval.c | 5435 |
6 files changed, 13646 insertions, 0 deletions
diff --git a/trunk/res/ael/ael.flex b/trunk/res/ael/ael.flex new file mode 100644 index 000000000..cf2d36a2c --- /dev/null +++ b/trunk/res/ael/ael.flex @@ -0,0 +1,694 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2006, Digium, Inc. + * + * Steve Murphy <murf@parsetree.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ +/*! \file + * + * \brief Flex scanner description of tokens used in AEL2 . + * + */ + +/* + * Start with flex options: + * + * %x describes the contexts we have: paren, semic and argg, plus INITIAL + */ +%x paren semic argg comment + +/* prefix used for various globally-visible functions and variables. + * This renames also yywrap, but since we do not use it, we just + * add option noyywrap to remove it. + */ +%option prefix="ael_yy" +%option noyywrap 8bit + +/* yyfree normally just frees its arg. It can be null sometimes, + which some systems will complain about, so, we'll define our own version */ +%option noyyfree + +/* batch gives a bit more performance if we are using it in + * a non-interactive mode. We probably don't care much. + */ +%option batch + +/* outfile is the filename to be used instead of lex.yy.c */ +%option outfile="ael_lex.c" + +/* + * These are not supported in flex 2.5.4, but we need them + * at the moment: + * reentrant produces a thread-safe parser. Not 100% sure that + * we require it, though. + * bison-bridge passes an additional yylval argument to yylex(). + * bison-locations is probably not needed. + */ +%option reentrant +%option bison-bridge +%option bison-locations + +%{ +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +#if defined(__Darwin__) || defined(__CYGWIN__) +#define GLOB_ABORTED GLOB_ABEND +#endif +# include <glob.h> + +#include "asterisk/logger.h" +#include "asterisk/utils.h" +#include "ael/ael.tab.h" +#include "asterisk/ael_structs.h" + +/* + * A stack to keep track of matching brackets ( [ { } ] ) + */ +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; + +/* + * current line, column and filename, updated as we read the input. + */ +static int my_lineno = 1; /* current line in the source */ +static int my_col = 1; /* current column in the source */ +char *my_file = 0; /* used also in the bison code */ +char *prev_word; /* XXX document it */ + +#define MAX_INCLUDE_DEPTH 50 + +/* + * flex is not too smart, and generates global functions + * without prototypes so the compiler may complain. + * To avoid that, we declare the prototypes here, + * even though these functions are not used. + */ +int ael_yyget_column (yyscan_t yyscanner); +void ael_yyset_column (int column_no , yyscan_t yyscanner); + +int ael_yyparse (struct parse_io *); + +/* + * A stack to process include files. + * As we switch into the new file we need to store the previous + * state to restore it later. + */ +struct stackelement { + char *fname; + int lineno; + int colno; + glob_t globbuf; /* the current globbuf */ + int globbuf_pos; /* where we are in the current globbuf */ + YY_BUFFER_STATE bufstate; +}; + +static struct stackelement include_stack[MAX_INCLUDE_DEPTH]; +static int include_stack_index = 0; +static void setup_filestack(char *fnamebuf, int fnamebuf_siz, glob_t *globbuf, int globpos, yyscan_t xscan, int create); + +/* + * if we use the @n feature of bison, we must supply the start/end + * location of tokens in the structure pointed by yylloc. + * Simple tokens are just assumed to be on the same line, so + * the line number is constant, and the column is incremented + * by the length of the token. + */ +#ifdef FLEX_BETA /* set for 2.5.33 */ + +/* compute the total number of lines and columns in the text + * passed as argument. + */ +static void pbcwhere(const char *text, int *line, int *col ) +{ + int loc_line = *line; + int loc_col = *col; + char c; + while ( (c = *text++) ) { + if ( c == '\t' ) { + loc_col += 8 - (loc_col % 8); + } else if ( c == '\n' ) { + loc_line++; + loc_col = 1; + } else + loc_col++; + } + *line = loc_line; + *col = loc_col; +} + +#define STORE_POS do { \ + yylloc->first_line = yylloc->last_line = my_lineno; \ + yylloc->first_column=my_col; \ + yylloc->last_column=my_col+yyleng-1; \ + my_col+=yyleng; \ + } while (0) + +#define STORE_LOC do { \ + yylloc->first_line = my_lineno; \ + yylloc->first_column=my_col; \ + pbcwhere(yytext, &my_lineno, &my_col); \ + yylloc->last_line = my_lineno; \ + yylloc->last_column = my_col - 1; \ + } while (0) +#else +#define STORE_POS +#define STORE_LOC +#endif +%} + + +NOPARENS ([^()\[\]\{\}]|\\[()\[\]\{\}])* + +NOARGG ([^(),\{\}\[\]]|\\[,()\[\]\{\}])* + +NOSEMIC ([^;()\{\}\[\]]|\\[;()\[\]\{\}])* + +HIBIT [\x80-\xff] + +%% + +\{ { STORE_POS; return LC;} +\} { STORE_POS; return RC;} +\( { STORE_POS; return LP;} +\) { STORE_POS; return RP;} +\; { STORE_POS; return SEMI;} +\= { STORE_POS; return EQ;} +\, { STORE_POS; return COMMA;} +\: { STORE_POS; return COLON;} +\& { STORE_POS; return AMPER;} +\| { STORE_POS; return BAR;} +\=\> { STORE_POS; return EXTENMARK;} +\@ { STORE_POS; return AT;} +\/\/[^\n]* {/*comment*/} +context { STORE_POS; return KW_CONTEXT;} +abstract { STORE_POS; return KW_ABSTRACT;} +extend { STORE_POS; return KW_EXTEND;} +macro { STORE_POS; return KW_MACRO;}; +globals { STORE_POS; return KW_GLOBALS;} +local { STORE_POS; return KW_LOCAL;} +ignorepat { STORE_POS; return KW_IGNOREPAT;} +switch { STORE_POS; return KW_SWITCH;} +if { STORE_POS; return KW_IF;} +ifTime { STORE_POS; return KW_IFTIME;} +random { STORE_POS; return KW_RANDOM;} +regexten { STORE_POS; return KW_REGEXTEN;} +hint { STORE_POS; return KW_HINT;} +else { STORE_POS; return KW_ELSE;} +goto { STORE_POS; return KW_GOTO;} +jump { STORE_POS; return KW_JUMP;} +return { STORE_POS; return KW_RETURN;} +break { STORE_POS; return KW_BREAK;} +continue { STORE_POS; return KW_CONTINUE;} +for { STORE_POS; return KW_FOR;} +while { STORE_POS; return KW_WHILE;} +case { STORE_POS; return KW_CASE;} +default { STORE_POS; return KW_DEFAULT;} +pattern { STORE_POS; return KW_PATTERN;} +catch { STORE_POS; return KW_CATCH;} +switches { STORE_POS; return KW_SWITCHES;} +eswitches { STORE_POS; return KW_ESWITCHES;} +includes { STORE_POS; return KW_INCLUDES;} +"/*" { BEGIN(comment); my_col += 2; } + +<comment>[^*\n]* { my_col += yyleng; } +<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); } + +\n { my_lineno++; my_col = 1; } +[ ]+ { my_col += yyleng; } +[\t]+ { my_col += (yyleng*8)-(my_col%8); } + +([-a-zA-Z0-9'"_/.\<\>\*\\\+!$#\[\]]|{HIBIT})([-a-zA-Z0-9'"_/.!\*\\\+\<\>\{\}$#\[\]]|{HIBIT})* { + STORE_POS; + yylval->str = strdup(yytext); + prev_word = yylval->str; + return word; + } + + + + /* + * context used for arguments of if_head, random_head, switch_head, + * for (last statement), while (XXX why not iftime_head ?). + * End with the matching parentheses. + * A comma at the top level is valid here, unlike in argg where it + * is an argument separator so it must be returned as a token. + */ +<paren>{NOPARENS}\) { + if ( pbcpop(')') ) { /* 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); + prev_word = 0; + return word; + } + parencount--; + if ( parencount >= 0) { + yymore(); + } else { + STORE_LOC; + yylval->str = strdup(yytext); + yylval->str[yyleng-1] = '\0'; /* trim trailing ')' */ + unput(')'); + BEGIN(0); + return word; + } + } + +<paren>{NOPARENS}[\(\[\{] { + char c = yytext[yyleng-1]; + if (c == '(') + parencount++; + pbcpush(c); + yymore(); + } + +<paren>{NOPARENS}[\]\}] { + char c = yytext[yyleng-1]; + if ( pbcpop(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(); + } + + + /* + * handlers for arguments to a macro or application calls. + * We enter this context when we find the initial '(' and + * stay here until we close all matching parentheses, + * and find the comma (argument separator) or the closing ')' + * of the (external) call, which happens when parencount == 0 + * before the decrement. + */ +<argg>{NOARGG}[\(\[\{] { + char c = yytext[yyleng-1]; + if (c == '(') + parencount++; + pbcpush(c); + yymore(); + } + +<argg>{NOARGG}\) { + if ( pbcpop(')') ) { /* error */ + STORE_LOC; + ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched ')' in expression!\n", my_file, my_lineno, my_col); + BEGIN(0); + yylval->str = strdup(yytext); + return word; + } + + parencount--; + if( parencount >= 0){ + yymore(); + } else { + STORE_LOC; + BEGIN(0); + if ( !strcmp(yytext, ")") ) + return RP; + yylval->str = strdup(yytext); + yylval->str[yyleng-1] = '\0'; /* trim trailing ')' */ + unput(')'); + return word; + } + } + +<argg>{NOARGG}\, { + if( parencount != 0) { /* printf("Folding in a comma!\n"); */ + yymore(); + } else { + STORE_LOC; + if( !strcmp(yytext,"," ) ) + return COMMA; + yylval->str = strdup(yytext); + yylval->str[yyleng-1] = '\0'; + unput(','); + return word; + } + } + +<argg>{NOARGG}[\]\}] { + char c = yytext[yyleng-1]; + if ( pbcpop(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(); + } + + /* + * context used to find tokens in the right hand side of assignments, + * or in the first and second operand of a 'for'. As above, match + * commas and use ';' as a separator (hence return it as a separate token). + */ +<semic>{NOSEMIC}[\(\[\{] { + char c = yytext[yyleng-1]; + yymore(); + pbcpush(c); + } + +<semic>{NOSEMIC}[\)\]\}] { + char c = yytext[yyleng-1]; + if ( pbcpop(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(); + } + +<semic>{NOSEMIC}; { + STORE_LOC; + yylval->str = strdup(yytext); + yylval->str[yyleng-1] = '\0'; + unput(';'); + BEGIN(0); + return word; + } + +\#include[ \t]+\"[^\"]+\" { + char fnamebuf[1024],*p1,*p2; + int glob_ret; + glob_t globbuf; /* the current globbuf */ + int globbuf_pos = -1; /* where we are in the current globbuf */ + globbuf.gl_offs = 0; /* initialize it to silence gcc */ + + p1 = strchr(yytext,'"'); + p2 = strrchr(yytext,'"'); + if ( include_stack_index >= MAX_INCLUDE_DEPTH ) { + ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Includes nested too deeply! Wow!!! How did you do that?\n", my_file, my_lineno, my_col); + } else if ( (int)(p2-p1) > sizeof(fnamebuf) - 1 ) { + ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Filename is incredibly way too long (%d chars!). Inclusion ignored!\n", my_file, my_lineno, my_col, yyleng - 10); + } else { + strncpy(fnamebuf, p1+1, p2-p1-1); + fnamebuf[p2-p1-1] = 0; + if (fnamebuf[0] != '/') { + char fnamebuf2[1024]; + snprintf(fnamebuf2,sizeof(fnamebuf2), "%s/%s", (char *)ast_config_AST_CONFIG_DIR, fnamebuf); + ast_copy_string(fnamebuf,fnamebuf2,sizeof(fnamebuf)); + } +#ifdef SOLARIS + glob_ret = glob(fnamebuf, GLOB_NOCHECK, NULL, &globbuf); +#else + glob_ret = glob(fnamebuf, GLOB_NOMAGIC|GLOB_BRACE, NULL, &globbuf); +#endif + if (glob_ret == GLOB_NOSPACE) { + ast_log(LOG_WARNING, + "Glob Expansion of pattern '%s' failed: Not enough memory\n", fnamebuf); + } else if (glob_ret == GLOB_ABORTED) { + ast_log(LOG_WARNING, + "Glob Expansion of pattern '%s' failed: Read error\n", fnamebuf); + } else if (glob_ret == GLOB_NOMATCH) { + ast_log(LOG_WARNING, + "Glob Expansion of pattern '%s' failed: No matches!\n", fnamebuf); + } else { + globbuf_pos = 0; + } + } + if (globbuf_pos > -1) { + setup_filestack(fnamebuf, sizeof(fnamebuf), &globbuf, 0, yyscanner, 1); + } + } + + +<<EOF>> { + char fnamebuf[2048]; + if (include_stack_index > 0 && include_stack[include_stack_index-1].globbuf_pos < include_stack[include_stack_index-1].globbuf.gl_pathc-1) { + free(my_file); + my_file = 0; + yy_delete_buffer( YY_CURRENT_BUFFER, yyscanner ); + include_stack[include_stack_index-1].globbuf_pos++; + setup_filestack(fnamebuf, sizeof(fnamebuf), &include_stack[include_stack_index-1].globbuf, include_stack[include_stack_index-1].globbuf_pos, yyscanner, 0); + /* finish this */ + + } else { + if (include_stack[include_stack_index].fname) { + free(include_stack[include_stack_index].fname); + include_stack[include_stack_index].fname = 0; + } + if ( --include_stack_index < 0 ) { + yyterminate(); + } else { + if (my_file) { + free(my_file); + my_file = 0; + } + globfree(&include_stack[include_stack_index].globbuf); + include_stack[include_stack_index].globbuf_pos = -1; + + yy_delete_buffer( YY_CURRENT_BUFFER, yyscanner ); + yy_switch_to_buffer(include_stack[include_stack_index].bufstate, yyscanner ); + my_lineno = include_stack[include_stack_index].lineno; + my_col = include_stack[include_stack_index].colno; + my_file = strdup(include_stack[include_stack_index].fname); + } + } + } + +%% + +static void pbcpush(char x) +{ + pbcstack[pbcpos++] = x; +} + +void ael_yyfree(void *ptr, yyscan_t yyscanner) +{ + if (ptr) + free( (char*) ptr ); +} + +static int pbcpop(char x) +{ + if ( ( x == ')' && pbcstack[pbcpos-1] == '(' ) + || ( x == ']' && pbcstack[pbcpos-1] == '[' ) + || ( x == '}' && pbcstack[pbcpos-1] == '{' )) { + pbcpos--; + return 0; + } + return 1; /* error */ +} + +static int c_prevword(void) +{ + char *c = prev_word; + if (c == NULL) + return 0; + while ( *c ) { + switch (*c) { + case '{': + case '[': + case '(': + pbcpush(*c); + break; + case '}': + case ']': + case ')': + if (pbcpop(*c)) + return 1; + break; + } + c++; + } + return 0; +} + + +/* + * The following three functions, reset_*, are used in the bison + * code to switch context. As a consequence, we need to + * declare them global and add a prototype so that the + * compiler does not complain. + * + * NOTE: yyg is declared because it is used in the BEGIN macros, + * though that should be hidden as the macro changes + * depending on the flex options that we use - in particular, + * %reentrant changes the way the macro is declared; + * without %reentrant, BEGIN uses yystart instead of yyg + */ + +void reset_parencount(yyscan_t yyscanner ); +void reset_parencount(yyscan_t yyscanner ) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + parencount = 0; + pbcpos = 0; + pbcpush('('); /* push '(' so the last pcbpop (parencount= -1) will succeed */ + c_prevword(); + BEGIN(paren); +} + +void reset_semicount(yyscan_t yyscanner ); +void reset_semicount(yyscan_t yyscanner ) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + pbcpos = 0; + BEGIN(semic); +} + +void reset_argcount(yyscan_t yyscanner ); +void reset_argcount(yyscan_t yyscanner ) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + parencount = 0; + pbcpos = 0; + pbcpush('('); /* push '(' so the last pcbpop (parencount= -1) will succeed */ + c_prevword(); + BEGIN(argg); +} + +/* used elsewhere, but some local vars */ +struct pval *ael2_parse(char *filename, int *errors) +{ + struct pval *pval; + struct parse_io *io; + char *buffer; + struct stat stats; + FILE *fin; + + /* extern int ael_yydebug; */ + + io = calloc(sizeof(struct parse_io),1); + /* reset the global counters */ + prev_word = 0; + my_lineno = 1; + include_stack_index=0; + my_col = 0; + /* ael_yydebug = 1; */ + ael_yylex_init(&io->scanner); + fin = fopen(filename,"r"); + if ( !fin ) { + ast_log(LOG_ERROR,"File %s could not be opened\n", filename); + *errors = 1; + return 0; + } + if (my_file) + free(my_file); + my_file = strdup(filename); + stat(filename, &stats); + buffer = (char*)malloc(stats.st_size+2); + fread(buffer, 1, stats.st_size, fin); + buffer[stats.st_size]=0; + fclose(fin); + + ael_yy_scan_string (buffer ,io->scanner); + ael_yyset_lineno(1 , io->scanner); + + /* ael_yyset_in (fin , io->scanner); OLD WAY */ + + ael_yyparse(io); + + + pval = io->pval; + *errors = io->syntax_error_count; + + ael_yylex_destroy(io->scanner); + free(buffer); + free(io); + + return pval; +} + +static void setup_filestack(char *fnamebuf2, int fnamebuf_siz, glob_t *globbuf, int globpos, yyscan_t yyscanner, int create) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + int error, i; + FILE *in1; + char fnamebuf[2048]; + + if (globbuf && globbuf->gl_pathv && globbuf->gl_pathc > 0) +#if defined(STANDALONE) || defined(LOW_MEMORY) || defined(STANDALONE_AEL) + strncpy(fnamebuf, globbuf->gl_pathv[globpos], fnamebuf_siz); +#else + ast_copy_string(fnamebuf, globbuf->gl_pathv[globpos], fnamebuf_siz); +#endif + else { + ast_log(LOG_ERROR,"Include file name not present!\n"); + return; + } + for (i=0; i<include_stack_index; i++) { + if ( !strcmp(fnamebuf,include_stack[i].fname )) { + ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Nice Try!!! But %s has already been included (perhaps by another file), and would cause an infinite loop of file inclusions!!! Include directive ignored\n", + my_file, my_lineno, my_col, fnamebuf); + break; + } + } + error = 1; + if (i == include_stack_index) + error = 0; /* we can use this file */ + if ( !error ) { /* valid file name */ + /* relative vs. absolute */ + if (fnamebuf[0] != '/') + snprintf(fnamebuf2, fnamebuf_siz, "%s/%s", ast_config_AST_CONFIG_DIR, fnamebuf); + else +#if defined(STANDALONE) || defined(LOW_MEMORY) || defined(STANDALONE_AEL) + strncpy(fnamebuf2, fnamebuf, fnamebuf_siz); +#else + ast_copy_string(fnamebuf2, fnamebuf, fnamebuf_siz); +#endif + in1 = fopen( fnamebuf2, "r" ); + + if ( ! in1 ) { + ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Couldn't find the include file: %s; ignoring the Include directive!\n", my_file, my_lineno, my_col, fnamebuf2); + } else { + char *buffer; + struct stat stats; + stat(fnamebuf2, &stats); + buffer = (char*)malloc(stats.st_size+1); + fread(buffer, 1, stats.st_size, in1); + buffer[stats.st_size] = 0; + ast_log(LOG_NOTICE," --Read in included file %s, %d chars\n",fnamebuf2, (int)stats.st_size); + fclose(in1); + if (my_file) + free(my_file); + my_file = strdup(fnamebuf2); + include_stack[include_stack_index].fname = strdup(my_file); + include_stack[include_stack_index].lineno = my_lineno; + include_stack[include_stack_index].colno = my_col+yyleng; + if (create) + include_stack[include_stack_index].globbuf = *globbuf; + + include_stack[include_stack_index].globbuf_pos = 0; + + include_stack[include_stack_index].bufstate = YY_CURRENT_BUFFER; + if (create) + include_stack_index++; + yy_switch_to_buffer(ael_yy_scan_string (buffer ,yyscanner),yyscanner); + free(buffer); + my_lineno = 1; + my_col = 1; + BEGIN(INITIAL); + } + } +} diff --git a/trunk/res/ael/ael.tab.c b/trunk/res/ael/ael.tab.c new file mode 100644 index 000000000..aa1ec0fad --- /dev/null +++ b/trunk/res/ael/ael.tab.c @@ -0,0 +1,3413 @@ +/* A Bison parser, made by GNU Bison 2.1a. */ + +/* Skeleton parser for Yacc-like parsing with Bison, + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.1a" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Using locations. */ +#define YYLSP_NEEDED 1 + +/* Substitute the variable and function names. */ +#define yyparse ael_yyparse +#define yylex ael_yylex +#define yyerror ael_yyerror +#define yylval ael_yylval +#define yychar ael_yychar +#define yydebug ael_yydebug +#define yynerrs ael_yynerrs +#define yylloc ael_yylloc + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + KW_CONTEXT = 258, + LC = 259, + RC = 260, + LP = 261, + RP = 262, + SEMI = 263, + EQ = 264, + COMMA = 265, + COLON = 266, + AMPER = 267, + BAR = 268, + AT = 269, + KW_MACRO = 270, + KW_GLOBALS = 271, + KW_IGNOREPAT = 272, + KW_SWITCH = 273, + KW_IF = 274, + KW_IFTIME = 275, + KW_ELSE = 276, + KW_RANDOM = 277, + KW_ABSTRACT = 278, + KW_EXTEND = 279, + EXTENMARK = 280, + KW_GOTO = 281, + KW_JUMP = 282, + KW_RETURN = 283, + KW_BREAK = 284, + KW_CONTINUE = 285, + KW_REGEXTEN = 286, + KW_HINT = 287, + KW_FOR = 288, + KW_WHILE = 289, + KW_CASE = 290, + KW_PATTERN = 291, + KW_DEFAULT = 292, + KW_CATCH = 293, + KW_SWITCHES = 294, + KW_ESWITCHES = 295, + KW_INCLUDES = 296, + KW_LOCAL = 297, + word = 298 + }; +#endif +/* Tokens. */ +#define KW_CONTEXT 258 +#define LC 259 +#define RC 260 +#define LP 261 +#define RP 262 +#define SEMI 263 +#define EQ 264 +#define COMMA 265 +#define COLON 266 +#define AMPER 267 +#define BAR 268 +#define AT 269 +#define KW_MACRO 270 +#define KW_GLOBALS 271 +#define KW_IGNOREPAT 272 +#define KW_SWITCH 273 +#define KW_IF 274 +#define KW_IFTIME 275 +#define KW_ELSE 276 +#define KW_RANDOM 277 +#define KW_ABSTRACT 278 +#define KW_EXTEND 279 +#define EXTENMARK 280 +#define KW_GOTO 281 +#define KW_JUMP 282 +#define KW_RETURN 283 +#define KW_BREAK 284 +#define KW_CONTINUE 285 +#define KW_REGEXTEN 286 +#define KW_HINT 287 +#define KW_FOR 288 +#define KW_WHILE 289 +#define KW_CASE 290 +#define KW_PATTERN 291 +#define KW_DEFAULT 292 +#define KW_CATCH 293 +#define KW_SWITCHES 294 +#define KW_ESWITCHES 295 +#define KW_INCLUDES 296 +#define KW_LOCAL 297 +#define word 298 + + + + +/* Copy the first part of user declarations. */ +#line 1 "ael.y" + +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2006, Digium, Inc. + * + * Steve Murphy <murf@parsetree.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ +/*! \file + * + * \brief Bison Grammar description of AEL2. + * + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "asterisk/logger.h" +#include "asterisk/ael_structs.h" + +pval * linku1(pval *head, pval *tail); +static void set_dads(pval *dad, pval *child_list); +void reset_parencount(yyscan_t yyscanner); +void reset_semicount(yyscan_t yyscanner); +void reset_argcount(yyscan_t yyscanner ); + +#define YYLEX_PARAM ((struct parse_io *)parseio)->scanner +#define YYERROR_VERBOSE 1 + +extern char *my_file; +#ifdef AAL_ARGCHECK +int ael_is_funcname(char *name); +#endif +static char *ael_token_subst(const char *mess); + + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 1 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +#line 54 "ael.y" +{ + int intval; /* integer value, typically flags */ + char *str; /* strings */ + struct pval *pval; /* full objects */ +} +/* Line 198 of yacc.c. */ +#line 238 "ael.tab.c" + YYSTYPE; +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + +#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED +typedef struct YYLTYPE +{ + int first_line; + int first_column; + int last_line; + int last_column; +} YYLTYPE; +# define yyltype YYLTYPE /* obsolescent; will be withdrawn */ +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 +#endif + + +/* Copy the second part of user declarations. */ +#line 60 "ael.y" + + /* declaring these AFTER the union makes things a lot simpler! */ +void yyerror(YYLTYPE *locp, struct parse_io *parseio, char const *s); +int ael_yylex (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , void * yyscanner); + +/* create a new object with start-end marker */ +pval *npval(pvaltype type, int first_line, int last_line, + int first_column, int last_column); + +/* create a new object with start-end marker, simplified interface. + * Must be declared here because YYLTYPE is not known before + */ +static pval *npval2(pvaltype type, YYLTYPE *first, YYLTYPE *last); + +/* another frontend for npval, this time for a string */ +static pval *nword(char *string, YYLTYPE *pos); + +/* update end position of an object, return the object */ +static pval *update_last(pval *, YYLTYPE *); + + +/* Line 221 of yacc.c. */ +#line 283 "ael.tab.c" + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if YYENABLE_NLS +# if ENABLE_NLS +# include <libintl.h> /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int i) +#else +static int +YYID (i) + int i; +#endif +{ + return i; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include <alloca.h> /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include <malloc.h> /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# ifdef __cplusplus +extern "C" { +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifdef __cplusplus +} +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ + && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss; + YYSTYPE yyvs; + YYLTYPE yyls; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + + 2 * YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 17 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 327 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 44 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 56 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 142 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 288 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 298 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint16 yyprhs[] = +{ + 0, 0, 3, 5, 7, 10, 13, 15, 17, 19, + 21, 23, 25, 32, 34, 35, 37, 40, 43, 52, + 57, 58, 61, 64, 65, 71, 72, 79, 80, 82, + 86, 89, 90, 93, 96, 98, 100, 102, 104, 106, + 108, 110, 113, 115, 120, 124, 130, 135, 143, 152, + 153, 156, 159, 165, 167, 175, 176, 181, 184, 187, + 192, 194, 197, 199, 202, 206, 210, 212, 215, 219, + 221, 224, 228, 234, 238, 240, 242, 246, 250, 253, + 254, 255, 256, 269, 273, 275, 279, 282, 285, 286, + 292, 295, 298, 301, 305, 307, 310, 311, 313, 317, + 321, 327, 333, 339, 345, 346, 349, 352, 357, 358, + 364, 368, 369, 373, 377, 380, 382, 383, 385, 386, + 390, 391, 394, 399, 403, 408, 409, 412, 414, 416, + 422, 427, 432, 433, 437, 443, 446, 448, 452, 455, + 459, 462, 467 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int8 yyrhs[] = +{ + 45, 0, -1, 46, -1, 47, -1, 46, 47, -1, + 46, 1, -1, 49, -1, 51, -1, 52, -1, 8, + -1, 43, -1, 37, -1, 50, 3, 48, 4, 59, + 5, -1, 23, -1, -1, 24, -1, 24, 23, -1, + 23, 24, -1, 15, 43, 6, 58, 7, 4, 92, + 5, -1, 16, 4, 53, 5, -1, -1, 54, 53, + -1, 1, 53, -1, -1, 43, 9, 55, 43, 8, + -1, -1, 42, 43, 9, 57, 43, 8, -1, -1, + 43, -1, 58, 10, 43, -1, 58, 1, -1, -1, + 60, 59, -1, 1, 59, -1, 62, -1, 99, -1, + 94, -1, 95, -1, 61, -1, 54, -1, 56, -1, + 43, 1, -1, 8, -1, 17, 25, 43, 8, -1, + 43, 25, 74, -1, 43, 14, 43, 25, 74, -1, + 31, 43, 25, 74, -1, 32, 6, 70, 7, 43, + 25, 74, -1, 31, 32, 6, 70, 7, 43, 25, + 74, -1, -1, 74, 63, -1, 1, 63, -1, 71, + 11, 71, 11, 71, -1, 43, -1, 64, 13, 71, + 13, 71, 13, 71, -1, -1, 6, 67, 69, 7, + -1, 19, 66, -1, 22, 66, -1, 20, 6, 65, + 7, -1, 43, -1, 43, 43, -1, 43, -1, 70, + 43, -1, 70, 11, 43, -1, 70, 12, 43, -1, + 43, -1, 43, 43, -1, 43, 43, 43, -1, 43, + -1, 43, 43, -1, 72, 11, 43, -1, 18, 66, + 4, 90, 5, -1, 4, 63, 5, -1, 54, -1, + 56, -1, 26, 80, 8, -1, 27, 82, 8, -1, + 43, 11, -1, -1, -1, -1, 33, 6, 75, 43, + 8, 76, 43, 8, 77, 43, 7, 74, -1, 34, + 66, 74, -1, 73, -1, 12, 83, 8, -1, 87, + 8, -1, 43, 8, -1, -1, 87, 9, 78, 43, + 8, -1, 29, 8, -1, 28, 8, -1, 30, 8, + -1, 68, 74, 79, -1, 8, -1, 21, 74, -1, + -1, 72, -1, 72, 13, 72, -1, 72, 10, 72, + -1, 72, 13, 72, 13, 72, -1, 72, 10, 72, + 10, 72, -1, 37, 13, 72, 13, 72, -1, 37, + 10, 72, 10, 72, -1, -1, 10, 43, -1, 72, + 81, -1, 72, 81, 14, 48, -1, -1, 43, 6, + 84, 89, 7, -1, 43, 6, 7, -1, -1, 43, + 6, 86, -1, 85, 89, 7, -1, 85, 7, -1, + 43, -1, -1, 69, -1, -1, 89, 10, 88, -1, + -1, 91, 90, -1, 35, 43, 11, 63, -1, 37, + 11, 63, -1, 36, 43, 11, 63, -1, -1, 93, + 92, -1, 74, -1, 99, -1, 38, 43, 4, 63, + 5, -1, 39, 4, 96, 5, -1, 40, 4, 96, + 5, -1, -1, 43, 8, 96, -1, 43, 14, 43, + 8, 96, -1, 1, 96, -1, 48, -1, 48, 13, + 65, -1, 97, 8, -1, 98, 97, 8, -1, 98, + 1, -1, 41, 4, 98, 5, -1, 41, 4, 5, + -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 186, 186, 189, 190, 191, 194, 195, 196, 197, + 200, 201, 204, 213, 214, 215, 216, 217, 220, 226, + 232, 233, 234, 237, 237, 243, 243, 250, 251, 252, + 253, 256, 257, 258, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 272, 277, 281, 289, 294, 299, 308, + 309, 310, 316, 321, 325, 333, 333, 337, 340, 343, + 354, 355, 362, 363, 367, 371, 377, 378, 383, 391, + 392, 396, 402, 411, 414, 415, 416, 419, 422, 425, + 426, 427, 425, 433, 437, 438, 439, 440, 443, 443, + 476, 477, 478, 479, 483, 486, 487, 490, 491, 494, + 497, 501, 505, 509, 515, 516, 520, 523, 529, 529, + 534, 542, 542, 553, 560, 563, 564, 567, 568, 571, + 574, 575, 578, 582, 586, 592, 593, 596, 597, 598, + 604, 609, 614, 615, 616, 618, 621, 622, 629, 630, + 631, 634, 637 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "KW_CONTEXT", "LC", "RC", "LP", "RP", + "SEMI", "EQ", "COMMA", "COLON", "AMPER", "BAR", "AT", "KW_MACRO", + "KW_GLOBALS", "KW_IGNOREPAT", "KW_SWITCH", "KW_IF", "KW_IFTIME", + "KW_ELSE", "KW_RANDOM", "KW_ABSTRACT", "KW_EXTEND", "EXTENMARK", + "KW_GOTO", "KW_JUMP", "KW_RETURN", "KW_BREAK", "KW_CONTINUE", + "KW_REGEXTEN", "KW_HINT", "KW_FOR", "KW_WHILE", "KW_CASE", "KW_PATTERN", + "KW_DEFAULT", "KW_CATCH", "KW_SWITCHES", "KW_ESWITCHES", "KW_INCLUDES", + "KW_LOCAL", "word", "$accept", "file", "objects", "object", + "context_name", "context", "opt_abstract", "macro", "globals", + "global_statements", "assignment", "@1", "local_assignment", "@2", + "arglist", "elements", "element", "ignorepat", "extension", "statements", + "timerange", "timespec", "test_expr", "@3", "if_like_head", "word_list", + "hint_word", "word3_list", "goto_word", "switch_statement", "statement", + "@4", "@5", "@6", "@7", "opt_else", "target", "opt_pri", "jumptarget", + "macro_call", "@8", "application_call_head", "@9", "application_call", + "opt_word", "eval_arglist", "case_statements", "case_statement", + "macro_statements", "macro_statement", "switches", "eswitches", + "switchlist", "included_entry", "includeslist", "includes", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 44, 45, 46, 46, 46, 47, 47, 47, 47, + 48, 48, 49, 50, 50, 50, 50, 50, 51, 52, + 53, 53, 53, 55, 54, 57, 56, 58, 58, 58, + 58, 59, 59, 59, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 61, 62, 62, 62, 62, 62, 63, + 63, 63, 64, 64, 65, 67, 66, 68, 68, 68, + 69, 69, 70, 70, 70, 70, 71, 71, 71, 72, + 72, 72, 73, 74, 74, 74, 74, 74, 74, 75, + 76, 77, 74, 74, 74, 74, 74, 74, 78, 74, + 74, 74, 74, 74, 74, 79, 79, 80, 80, 80, + 80, 80, 80, 80, 81, 81, 82, 82, 84, 83, + 83, 86, 85, 87, 87, 88, 88, 89, 89, 89, + 90, 90, 91, 91, 91, 92, 92, 93, 93, 93, + 94, 95, 96, 96, 96, 96, 97, 97, 98, 98, + 98, 99, 99 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 1, 1, 2, 2, 1, 1, 1, 1, + 1, 1, 6, 1, 0, 1, 2, 2, 8, 4, + 0, 2, 2, 0, 5, 0, 6, 0, 1, 3, + 2, 0, 2, 2, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 4, 3, 5, 4, 7, 8, 0, + 2, 2, 5, 1, 7, 0, 4, 2, 2, 4, + 1, 2, 1, 2, 3, 3, 1, 2, 3, 1, + 2, 3, 5, 3, 1, 1, 3, 3, 2, 0, + 0, 0, 12, 3, 1, 3, 2, 2, 0, 5, + 2, 2, 2, 3, 1, 2, 0, 1, 3, 3, + 5, 5, 5, 5, 0, 2, 2, 4, 0, 5, + 3, 0, 3, 3, 2, 1, 0, 1, 0, 3, + 0, 2, 4, 3, 4, 0, 2, 1, 1, 5, + 4, 4, 0, 3, 5, 2, 1, 3, 2, 3, + 2, 4, 3 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 14, 9, 0, 0, 13, 15, 0, 0, 3, 6, + 0, 7, 8, 0, 0, 17, 16, 1, 5, 4, + 0, 27, 0, 0, 0, 0, 11, 10, 0, 28, + 0, 22, 23, 19, 21, 0, 30, 0, 0, 0, + 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, + 39, 40, 0, 0, 38, 34, 36, 37, 35, 125, + 29, 0, 33, 0, 0, 0, 0, 0, 0, 0, + 0, 41, 0, 0, 12, 32, 0, 94, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 74, 75, 0, 84, 127, 118, 0, 0, + 125, 128, 24, 0, 0, 0, 62, 0, 0, 0, + 0, 0, 142, 136, 0, 0, 25, 0, 44, 0, + 0, 0, 0, 0, 55, 0, 57, 0, 58, 0, + 69, 97, 0, 104, 0, 91, 90, 92, 79, 0, + 0, 111, 87, 78, 96, 114, 60, 117, 0, 86, + 88, 18, 126, 43, 0, 46, 0, 0, 0, 63, + 135, 0, 0, 130, 131, 0, 138, 140, 141, 0, + 0, 0, 51, 73, 50, 108, 85, 0, 120, 53, + 0, 0, 0, 0, 0, 70, 0, 0, 0, 76, + 0, 106, 77, 0, 83, 0, 112, 0, 93, 61, + 113, 116, 0, 0, 0, 64, 65, 133, 0, 137, + 139, 0, 45, 110, 118, 0, 0, 0, 0, 0, + 120, 67, 0, 59, 0, 0, 0, 99, 71, 98, + 105, 0, 0, 0, 95, 115, 119, 0, 0, 0, + 0, 26, 0, 56, 0, 0, 0, 72, 121, 68, + 66, 0, 0, 0, 0, 0, 0, 107, 80, 129, + 89, 0, 47, 134, 109, 0, 0, 123, 0, 0, + 103, 102, 101, 100, 0, 48, 122, 124, 0, 52, + 0, 0, 81, 54, 0, 0, 0, 82 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 6, 7, 8, 113, 9, 10, 11, 12, 24, + 92, 39, 93, 170, 30, 52, 53, 54, 55, 120, + 180, 181, 125, 177, 94, 147, 107, 182, 131, 95, + 121, 193, 274, 284, 202, 198, 132, 191, 134, 123, + 214, 97, 196, 98, 236, 148, 219, 220, 99, 100, + 56, 57, 110, 114, 115, 58 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -219 +static const yytype_int16 yypact[] = +{ + 102, -219, -25, 40, 24, 29, 70, 249, -219, -219, + 74, -219, -219, 107, 11, -219, -219, -219, -219, -219, + -6, 65, 11, 137, 148, 11, -219, -219, 152, -219, + 87, -219, -219, -219, -219, 123, -219, 173, 126, 136, + 123, -219, 159, -11, 186, 190, 194, 196, 158, 86, + -219, -219, 203, 123, -219, -219, -219, -219, -219, 177, + -219, 201, -219, 170, 208, 191, 179, 12, 12, 19, + 214, -219, 181, 213, -219, -219, 115, -219, 183, 222, + 222, 223, 222, 36, 187, 226, 228, 229, 232, 222, + 202, 182, -219, -219, 213, -219, -219, 16, 113, 239, + 177, -219, -219, 240, 179, 213, -219, 22, 12, 101, + 246, 248, -219, 241, 250, 10, -219, 234, -219, 56, + 255, 56, 256, 253, -219, 259, -219, 224, -219, 26, + 225, 157, 258, 119, 261, -219, -219, -219, -219, 213, + 266, -219, -219, -219, 254, -219, 231, -219, 59, -219, + -219, -219, -219, -219, 60, -219, 233, 235, 236, -219, + -219, 12, 237, -219, -219, 224, -219, -219, -219, 263, + 238, 213, -219, -219, -219, 270, -219, 242, 124, -1, + 269, 276, 273, 187, 187, -219, 187, 243, 187, -219, + 244, 274, -219, 247, -219, 115, -219, 213, -219, -219, + -219, 251, 252, 257, 264, -219, -219, -219, 283, -219, + -219, 284, -219, -219, 242, 286, 260, 262, 285, 292, + 124, 265, 267, -219, 267, 172, 15, 176, -219, 165, + -219, -6, 290, 294, -219, -219, -219, 293, 277, 213, + 12, -219, 129, -219, 295, 296, 56, -219, -219, -219, + 268, 291, 298, 187, 187, 187, 187, -219, -219, -219, + -219, 213, -219, -219, -219, 56, 56, -219, 267, 267, + 301, 301, 301, 301, 271, -219, -219, -219, 300, -219, + 307, 267, -219, -219, 275, 309, 213, -219 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -219, -219, -219, 310, -19, -219, -219, -219, -219, 125, + 5, -219, -15, -219, -219, -31, -219, -219, -219, -114, + -219, 154, 25, -219, -219, 143, 217, -218, -82, -219, + -59, -219, -219, -219, -219, -219, -219, -219, -219, -219, + -219, -219, -219, -219, -219, 108, 103, -219, 227, -219, + -219, -219, -65, 209, -219, -51 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -133 +static const yytype_int16 yytable[] = +{ + 96, 28, 133, 111, 251, 172, 252, 174, 101, 62, + -66, 167, 22, 108, 118, 168, -20, -132, 13, 25, + 51, 64, 75, 145, 112, 51, 187, 25, 254, 156, + 25, 26, 65, 157, 158, 144, 183, 27, 51, 184, + 50, 96, 221, 160, 14, 50, 155, 26, 15, 101, + 278, 279, 16, 27, 23, 109, 26, 119, 50, 146, + 76, -49, 27, 283, 77, 159, 200, 203, 78, 201, + 17, 157, 158, 129, 79, 80, 81, 20, 82, 130, + 194, 233, 83, 84, 85, 86, 87, 71, 36, 88, + 89, -49, -49, -49, 37, 32, 207, 38, 48, 91, + 72, 225, 226, 159, 227, 126, 229, 128, 29, 161, + 1, 73, 212, 21, 139, 162, 119, 2, 3, 76, + -49, 149, 150, 77, 40, 4, 5, 78, -31, 190, + 187, 41, 267, 79, 80, 81, 264, 82, 234, 201, + 42, 83, 84, 85, 86, 87, 32, 31, 88, 89, + 34, 276, 277, 33, 43, 44, 35, 48, 91, 216, + 217, 218, 45, 46, 47, 48, 49, 186, 187, 60, + 188, 270, 271, 272, 273, 263, 187, 59, 256, 61, + 262, 76, 253, 187, 63, 77, 255, 187, 141, 78, + 142, 32, 66, 143, 67, 79, 80, 81, 68, 82, + 69, 70, 275, 83, 84, 85, 86, 87, 74, 102, + 88, 89, 257, 103, 104, 90, 105, 76, 47, 48, + 91, 77, 106, 116, 117, 78, 122, 287, 124, 127, + 130, 79, 80, 81, 135, 82, 136, 137, 138, 83, + 84, 85, 86, 87, 151, 140, 88, 89, 153, -2, + 18, 163, -14, 164, 165, 48, 91, 1, 166, 171, + 173, 176, 175, 178, 2, 3, 189, 179, 185, 192, + 195, 210, 4, 5, 199, 197, 204, 213, 205, 206, + 208, 211, 222, 223, 224, 146, 228, 230, 231, 239, + 232, 240, 241, 243, 235, 237, 246, 247, 258, 259, + 238, 260, 261, 244, 268, 245, 265, 266, 249, 269, + 250, 221, 187, 281, 280, 282, 286, 19, 285, 209, + 215, 154, 242, 248, 169, 0, 0, 152 +}; + +static const yytype_int16 yycheck[] = +{ + 59, 20, 84, 68, 222, 119, 224, 121, 59, 40, + 11, 1, 1, 1, 73, 5, 5, 5, 43, 14, + 35, 32, 53, 7, 5, 40, 11, 22, 13, 7, + 25, 37, 43, 11, 12, 94, 10, 43, 53, 13, + 35, 100, 43, 108, 4, 40, 105, 37, 24, 100, + 268, 269, 23, 43, 43, 43, 37, 1, 53, 43, + 4, 5, 43, 281, 8, 43, 7, 7, 12, 10, + 0, 11, 12, 37, 18, 19, 20, 3, 22, 43, + 139, 195, 26, 27, 28, 29, 30, 1, 1, 33, + 34, 35, 36, 37, 7, 9, 161, 10, 42, 43, + 14, 183, 184, 43, 186, 80, 188, 82, 43, 8, + 8, 25, 171, 6, 89, 14, 1, 15, 16, 4, + 5, 8, 9, 8, 1, 23, 24, 12, 5, 10, + 11, 8, 246, 18, 19, 20, 7, 22, 197, 10, + 17, 26, 27, 28, 29, 30, 9, 22, 33, 34, + 25, 265, 266, 5, 31, 32, 4, 42, 43, 35, + 36, 37, 39, 40, 41, 42, 43, 10, 11, 43, + 13, 253, 254, 255, 256, 240, 11, 4, 13, 43, + 239, 4, 10, 11, 25, 8, 10, 11, 6, 12, + 8, 9, 6, 11, 4, 18, 19, 20, 4, 22, + 4, 43, 261, 26, 27, 28, 29, 30, 5, 8, + 33, 34, 231, 43, 6, 38, 25, 4, 41, 42, + 43, 8, 43, 9, 43, 12, 43, 286, 6, 6, + 43, 18, 19, 20, 8, 22, 8, 8, 6, 26, + 27, 28, 29, 30, 5, 43, 33, 34, 8, 0, + 1, 5, 3, 5, 13, 42, 43, 8, 8, 25, + 5, 8, 6, 4, 15, 16, 8, 43, 43, 8, + 4, 8, 23, 24, 43, 21, 43, 7, 43, 43, + 43, 43, 13, 7, 11, 43, 43, 43, 14, 25, + 43, 8, 8, 7, 43, 43, 11, 5, 8, 5, + 43, 8, 25, 43, 13, 43, 11, 11, 43, 11, + 43, 43, 11, 13, 43, 8, 7, 7, 43, 165, + 177, 104, 214, 220, 115, -1, -1, 100 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 8, 15, 16, 23, 24, 45, 46, 47, 49, + 50, 51, 52, 43, 4, 24, 23, 0, 1, 47, + 3, 6, 1, 43, 53, 54, 37, 43, 48, 43, + 58, 53, 9, 5, 53, 4, 1, 7, 10, 55, + 1, 8, 17, 31, 32, 39, 40, 41, 42, 43, + 54, 56, 59, 60, 61, 62, 94, 95, 99, 4, + 43, 43, 59, 25, 32, 43, 6, 4, 4, 4, + 43, 1, 14, 25, 5, 59, 4, 8, 12, 18, + 19, 20, 22, 26, 27, 28, 29, 30, 33, 34, + 38, 43, 54, 56, 68, 73, 74, 85, 87, 92, + 93, 99, 8, 43, 6, 25, 43, 70, 1, 43, + 96, 96, 5, 48, 97, 98, 9, 43, 74, 1, + 63, 74, 43, 83, 6, 66, 66, 6, 66, 37, + 43, 72, 80, 72, 82, 8, 8, 8, 6, 66, + 43, 6, 8, 11, 74, 7, 43, 69, 89, 8, + 9, 5, 92, 8, 70, 74, 7, 11, 12, 43, + 96, 8, 14, 5, 5, 13, 8, 1, 5, 97, + 57, 25, 63, 5, 63, 6, 8, 67, 4, 43, + 64, 65, 71, 10, 13, 43, 10, 11, 13, 8, + 10, 81, 8, 75, 74, 4, 86, 21, 79, 43, + 7, 10, 78, 7, 43, 43, 43, 96, 43, 65, + 8, 43, 74, 7, 84, 69, 35, 36, 37, 90, + 91, 43, 13, 7, 11, 72, 72, 72, 43, 72, + 43, 14, 43, 63, 74, 43, 88, 43, 43, 25, + 8, 8, 89, 7, 43, 43, 11, 5, 90, 43, + 43, 71, 71, 10, 13, 10, 13, 48, 8, 5, + 8, 25, 74, 96, 7, 11, 11, 63, 13, 11, + 72, 72, 72, 72, 76, 74, 63, 63, 71, 71, + 43, 13, 8, 71, 77, 43, 7, 74 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (&yylloc, parseio, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM) +#else +# define YYLEX yylex (&yylval, &yylloc) +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value, Location, parseio); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, const YYSTYPE * const yyvaluep, const YYLTYPE * const yylocationp, struct parse_io *parseio) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, parseio) + FILE *yyoutput; + int yytype; + const YYSTYPE * const yyvaluep; + const YYLTYPE * const yylocationp; + struct parse_io *parseio; +#endif +{ + if (!yyvaluep) + return; + YYUSE (yylocationp); + YYUSE (parseio); +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, const YYSTYPE * const yyvaluep, const YYLTYPE * const yylocationp, struct parse_io *parseio) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, parseio) + FILE *yyoutput; + int yytype; + const YYSTYPE * const yyvaluep; + const YYLTYPE * const yylocationp; + struct parse_io *parseio; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + YY_LOCATION_PRINT (yyoutput, *yylocationp); + YYFPRINTF (yyoutput, ": "); + yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, parseio); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) +#else +static void +yy_stack_print (bottom, top) + yytype_int16 *bottom; + yytype_int16 *top; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; bottom <= top; ++bottom) + YYFPRINTF (stderr, " %d", *bottom); + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, struct parse_io *parseio) +#else +static void +yy_reduce_print (yyvsp, yylsp, yyrule, parseio) + YYSTYPE *yyvsp; + YYLTYPE *yylsp; + int yyrule; + struct parse_io *parseio; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + fprintf (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + , &(yylsp[(yyi + 1) - (yynrhs)]) , parseio); + fprintf (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, yylsp, Rule, parseio); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + size_t yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) +{ + int yyn = yypact[yystate]; + + if (! (YYPACT_NINF < yyn && yyn < YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } + + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + + if (yysize_overflow) + return YYSIZE_MAXIMUM; + + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } +} +#endif /* YYERROR_VERBOSE */ + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, struct parse_io *parseio) +#else +static void +yydestruct (yymsg, yytype, yyvaluep, yylocationp, parseio) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; + YYLTYPE *yylocationp; + struct parse_io *parseio; +#endif +{ + YYUSE (yyvaluep); + YYUSE (yylocationp); + YYUSE (parseio); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + case 43: /* "word" */ +#line 178 "ael.y" + { free((yyvaluep->str));}; +#line 1456 "ael.tab.c" + break; + case 46: /* "objects" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1464 "ael.tab.c" + break; + case 47: /* "object" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1472 "ael.tab.c" + break; + case 48: /* "context_name" */ +#line 178 "ael.y" + { free((yyvaluep->str));}; +#line 1477 "ael.tab.c" + break; + case 49: /* "context" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1485 "ael.tab.c" + break; + case 51: /* "macro" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1493 "ael.tab.c" + break; + case 52: /* "globals" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1501 "ael.tab.c" + break; + case 53: /* "global_statements" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1509 "ael.tab.c" + break; + case 54: /* "assignment" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1517 "ael.tab.c" + break; + case 56: /* "local_assignment" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1525 "ael.tab.c" + break; + case 58: /* "arglist" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1533 "ael.tab.c" + break; + case 59: /* "elements" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1541 "ael.tab.c" + break; + case 60: /* "element" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1549 "ael.tab.c" + break; + case 61: /* "ignorepat" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1557 "ael.tab.c" + break; + case 62: /* "extension" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1565 "ael.tab.c" + break; + case 63: /* "statements" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1573 "ael.tab.c" + break; + case 64: /* "timerange" */ +#line 178 "ael.y" + { free((yyvaluep->str));}; +#line 1578 "ael.tab.c" + break; + case 65: /* "timespec" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1586 "ael.tab.c" + break; + case 66: /* "test_expr" */ +#line 178 "ael.y" + { free((yyvaluep->str));}; +#line 1591 "ael.tab.c" + break; + case 68: /* "if_like_head" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1599 "ael.tab.c" + break; + case 69: /* "word_list" */ +#line 178 "ael.y" + { free((yyvaluep->str));}; +#line 1604 "ael.tab.c" + break; + case 71: /* "word3_list" */ +#line 178 "ael.y" + { free((yyvaluep->str));}; +#line 1609 "ael.tab.c" + break; + case 72: /* "goto_word" */ +#line 178 "ael.y" + { free((yyvaluep->str));}; +#line 1614 "ael.tab.c" + break; + case 73: /* "switch_statement" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1622 "ael.tab.c" + break; + case 74: /* "statement" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1630 "ael.tab.c" + break; + case 79: /* "opt_else" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1638 "ael.tab.c" + break; + case 80: /* "target" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1646 "ael.tab.c" + break; + case 81: /* "opt_pri" */ +#line 178 "ael.y" + { free((yyvaluep->str));}; +#line 1651 "ael.tab.c" + break; + case 82: /* "jumptarget" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1659 "ael.tab.c" + break; + case 83: /* "macro_call" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1667 "ael.tab.c" + break; + case 85: /* "application_call_head" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1675 "ael.tab.c" + break; + case 87: /* "application_call" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1683 "ael.tab.c" + break; + case 88: /* "opt_word" */ +#line 178 "ael.y" + { free((yyvaluep->str));}; +#line 1688 "ael.tab.c" + break; + case 89: /* "eval_arglist" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1696 "ael.tab.c" + break; + case 90: /* "case_statements" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1704 "ael.tab.c" + break; + case 91: /* "case_statement" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1712 "ael.tab.c" + break; + case 92: /* "macro_statements" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1720 "ael.tab.c" + break; + case 93: /* "macro_statement" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1728 "ael.tab.c" + break; + case 94: /* "switches" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1736 "ael.tab.c" + break; + case 95: /* "eswitches" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1744 "ael.tab.c" + break; + case 96: /* "switchlist" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1752 "ael.tab.c" + break; + case 97: /* "included_entry" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1760 "ael.tab.c" + break; + case 98: /* "includeslist" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1768 "ael.tab.c" + break; + case 99: /* "includes" */ +#line 165 "ael.y" + { + destroy_pval((yyvaluep->pval)); + prev_word=0; + }; +#line 1776 "ael.tab.c" + break; + + default: + break; + } +} + + +/* Prevent warnings from -Wmissing-prototypes. */ + +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (struct parse_io *parseio); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + + + + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (struct parse_io *parseio) +#else +int +yyparse (parseio) + struct parse_io *parseio; +#endif +#endif +{ + /* The look-ahead symbol. */ +int yychar; + +/* The semantic value of the look-ahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; +/* Location data for the look-ahead symbol. */ +YYLTYPE yylloc; + + int yystate; + int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Look-ahead token as an internal (translated) token number. */ + int yytoken = 0; +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss = yyssa; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + YYSTYPE *yyvsp; + + /* The location stack. */ + YYLTYPE yylsa[YYINITDEPTH]; + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp; + /* The locations where the error started and ended. */ + YYLTYPE yyerror_range[2]; + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) + + YYSIZE_T yystacksize = YYINITDEPTH; + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + YYLTYPE yyloc; + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss; + yyvsp = yyvs; + yylsp = yyls; +#if YYLTYPE_IS_TRIVIAL + /* Initialize the default location before parsing starts. */ + yylloc.first_line = yylloc.last_line = 1; + yylloc.first_column = yylloc.last_column = 0; +#endif + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + YYLTYPE *yyls1 = yyls; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yyls1, yysize * sizeof (*yylsp), + &yystacksize); + yyls = yyls1; + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); + YYSTACK_RELOCATE (yyls); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + yylsp = yyls + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + look-ahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to look-ahead token. */ + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a look-ahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + if (yyn == YYFINAL) + YYACCEPT; + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the look-ahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + *++yylsp = yylloc; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + /* Default location. */ + YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: +#line 186 "ael.y" + { (yyval.pval) = parseio->pval = (yyvsp[(1) - (1)].pval); ;} + break; + + case 3: +#line 189 "ael.y" + {(yyval.pval)=(yyvsp[(1) - (1)].pval);;} + break; + + case 4: +#line 190 "ael.y" + { (yyval.pval) = linku1((yyvsp[(1) - (2)].pval), (yyvsp[(2) - (2)].pval)); ;} + break; + + case 5: +#line 191 "ael.y" + {(yyval.pval)=(yyvsp[(1) - (2)].pval);;} + break; + + case 6: +#line 194 "ael.y" + {(yyval.pval)=(yyvsp[(1) - (1)].pval);;} + break; + + case 7: +#line 195 "ael.y" + {(yyval.pval)=(yyvsp[(1) - (1)].pval);;} + break; + + case 8: +#line 196 "ael.y" + {(yyval.pval)=(yyvsp[(1) - (1)].pval);;} + break; + + case 9: +#line 197 "ael.y" + {(yyval.pval)=0;/* allow older docs to be read */;} + break; + + case 10: +#line 200 "ael.y" + { (yyval.str) = (yyvsp[(1) - (1)].str); ;} + break; + + case 11: +#line 201 "ael.y" + { (yyval.str) = strdup("default"); ;} + break; + + case 12: +#line 204 "ael.y" + { + (yyval.pval) = npval2(PV_CONTEXT, &(yylsp[(1) - (6)]), &(yylsp[(6) - (6)])); + (yyval.pval)->u1.str = (yyvsp[(3) - (6)].str); + (yyval.pval)->u2.statements = (yyvsp[(5) - (6)].pval); + set_dads((yyval.pval),(yyvsp[(5) - (6)].pval)); + (yyval.pval)->u3.abstract = (yyvsp[(1) - (6)].intval);;} + break; + + case 13: +#line 213 "ael.y" + { (yyval.intval) = 1; ;} + break; + + case 14: +#line 214 "ael.y" + { (yyval.intval) = 0; ;} + break; + + case 15: +#line 215 "ael.y" + { (yyval.intval) = 2; ;} + break; + + case 16: +#line 216 "ael.y" + { (yyval.intval)=3; ;} + break; + + case 17: +#line 217 "ael.y" + { (yyval.intval)=3; ;} + break; + + case 18: +#line 220 "ael.y" + { + (yyval.pval) = npval2(PV_MACRO, &(yylsp[(1) - (8)]), &(yylsp[(8) - (8)])); + (yyval.pval)->u1.str = (yyvsp[(2) - (8)].str); (yyval.pval)->u2.arglist = (yyvsp[(4) - (8)].pval); (yyval.pval)->u3.macro_statements = (yyvsp[(7) - (8)].pval); + set_dads((yyval.pval),(yyvsp[(7) - (8)].pval));;} + break; + + case 19: +#line 226 "ael.y" + { + (yyval.pval) = npval2(PV_GLOBALS, &(yylsp[(1) - (4)]), &(yylsp[(4) - (4)])); + (yyval.pval)->u1.statements = (yyvsp[(3) - (4)].pval); + set_dads((yyval.pval),(yyvsp[(3) - (4)].pval));;} + break; + + case 20: +#line 232 "ael.y" + { (yyval.pval) = NULL; ;} + break; + + case 21: +#line 233 "ael.y" + {(yyval.pval) = linku1((yyvsp[(1) - (2)].pval), (yyvsp[(2) - (2)].pval)); ;} + break; + + case 22: +#line 234 "ael.y" + {(yyval.pval)=(yyvsp[(2) - (2)].pval);;} + break; + + case 23: +#line 237 "ael.y" + { reset_semicount(parseio->scanner); ;} + break; + + case 24: +#line 237 "ael.y" + { + (yyval.pval) = npval2(PV_VARDEC, &(yylsp[(1) - (5)]), &(yylsp[(5) - (5)])); + (yyval.pval)->u1.str = (yyvsp[(1) - (5)].str); + (yyval.pval)->u2.val = (yyvsp[(4) - (5)].str); ;} + break; + + case 25: +#line 243 "ael.y" + { reset_semicount(parseio->scanner); ;} + break; + + case 26: +#line 243 "ael.y" + { + (yyval.pval) = npval2(PV_LOCALVARDEC, &(yylsp[(1) - (6)]), &(yylsp[(6) - (6)])); + (yyval.pval)->u1.str = (yyvsp[(2) - (6)].str); + (yyval.pval)->u2.val = (yyvsp[(5) - (6)].str); ;} + break; + + case 27: +#line 250 "ael.y" + { (yyval.pval) = NULL; ;} + break; + + case 28: +#line 251 "ael.y" + { (yyval.pval) = nword((yyvsp[(1) - (1)].str), &(yylsp[(1) - (1)])); ;} + break; + + case 29: +#line 252 "ael.y" + { (yyval.pval) = linku1((yyvsp[(1) - (3)].pval), nword((yyvsp[(3) - (3)].str), &(yylsp[(3) - (3)]))); ;} + break; + + case 30: +#line 253 "ael.y" + {(yyval.pval)=(yyvsp[(1) - (2)].pval);;} + break; + + case 31: +#line 256 "ael.y" + {(yyval.pval)=0;;} + break; + + case 32: +#line 257 "ael.y" + { (yyval.pval) = linku1((yyvsp[(1) - (2)].pval), (yyvsp[(2) - (2)].pval)); ;} + break; + + case 33: +#line 258 "ael.y" + { (yyval.pval)=(yyvsp[(2) - (2)].pval);;} + break; + + case 34: +#line 261 "ael.y" + {(yyval.pval)=(yyvsp[(1) - (1)].pval);;} + break; + + case 35: +#line 262 "ael.y" + {(yyval.pval)=(yyvsp[(1) - (1)].pval);;} + break; + + case 36: +#line 263 "ael.y" + {(yyval.pval)=(yyvsp[(1) - (1)].pval);;} + break; + + case 37: +#line 264 "ael.y" + {(yyval.pval)=(yyvsp[(1) - (1)].pval);;} + break; + + case 38: +#line 265 "ael.y" + {(yyval.pval)=(yyvsp[(1) - (1)].pval);;} + break; + + case 39: +#line 266 "ael.y" + {(yyval.pval)=(yyvsp[(1) - (1)].pval);;} + break; + + case 40: +#line 267 "ael.y" + {(yyval.pval)=(yyvsp[(1) - (1)].pval);;} + break; + + case 41: +#line 268 "ael.y" + {free((yyvsp[(1) - (2)].str)); (yyval.pval)=0;;} + break; + + case 42: +#line 269 "ael.y" + {(yyval.pval)=0;/* allow older docs to be read */;} + break; + + case 43: +#line 272 "ael.y" + { + (yyval.pval) = npval2(PV_IGNOREPAT, &(yylsp[(1) - (4)]), &(yylsp[(4) - (4)])); + (yyval.pval)->u1.str = (yyvsp[(3) - (4)].str);;} + break; + + case 44: +#line 277 "ael.y" + { + (yyval.pval) = npval2(PV_EXTENSION, &(yylsp[(1) - (3)]), &(yylsp[(3) - (3)])); + (yyval.pval)->u1.str = (yyvsp[(1) - (3)].str); + (yyval.pval)->u2.statements = (yyvsp[(3) - (3)].pval); set_dads((yyval.pval),(yyvsp[(3) - (3)].pval));;} + break; + + case 45: +#line 281 "ael.y" + { + (yyval.pval) = npval2(PV_EXTENSION, &(yylsp[(1) - (5)]), &(yylsp[(3) - (5)])); + (yyval.pval)->u1.str = malloc(strlen((yyvsp[(1) - (5)].str))+strlen((yyvsp[(3) - (5)].str))+2); + strcpy((yyval.pval)->u1.str,(yyvsp[(1) - (5)].str)); + strcat((yyval.pval)->u1.str,"@"); + strcat((yyval.pval)->u1.str,(yyvsp[(3) - (5)].str)); + free((yyvsp[(1) - (5)].str)); + (yyval.pval)->u2.statements = (yyvsp[(5) - (5)].pval); set_dads((yyval.pval),(yyvsp[(5) - (5)].pval));;} + break; + + case 46: +#line 289 "ael.y" + { + (yyval.pval) = npval2(PV_EXTENSION, &(yylsp[(1) - (4)]), &(yylsp[(4) - (4)])); + (yyval.pval)->u1.str = (yyvsp[(2) - (4)].str); + (yyval.pval)->u2.statements = (yyvsp[(4) - (4)].pval); set_dads((yyval.pval),(yyvsp[(4) - (4)].pval)); + (yyval.pval)->u4.regexten=1;;} + break; + + case 47: +#line 294 "ael.y" + { + (yyval.pval) = npval2(PV_EXTENSION, &(yylsp[(1) - (7)]), &(yylsp[(7) - (7)])); + (yyval.pval)->u1.str = (yyvsp[(5) - (7)].str); + (yyval.pval)->u2.statements = (yyvsp[(7) - (7)].pval); set_dads((yyval.pval),(yyvsp[(7) - (7)].pval)); + (yyval.pval)->u3.hints = (yyvsp[(3) - (7)].str);;} + break; + + case 48: +#line 299 "ael.y" + { + (yyval.pval) = npval2(PV_EXTENSION, &(yylsp[(1) - (8)]), &(yylsp[(8) - (8)])); + (yyval.pval)->u1.str = (yyvsp[(6) - (8)].str); + (yyval.pval)->u2.statements = (yyvsp[(8) - (8)].pval); set_dads((yyval.pval),(yyvsp[(8) - (8)].pval)); + (yyval.pval)->u4.regexten=1; + (yyval.pval)->u3.hints = (yyvsp[(4) - (8)].str);;} + break; + + case 49: +#line 308 "ael.y" + { (yyval.pval) = NULL; ;} + break; + + case 50: +#line 309 "ael.y" + { (yyval.pval) = linku1((yyvsp[(1) - (2)].pval), (yyvsp[(2) - (2)].pval)); ;} + break; + + case 51: +#line 310 "ael.y" + {(yyval.pval)=(yyvsp[(2) - (2)].pval);;} + break; + + case 52: +#line 316 "ael.y" + { + asprintf(&(yyval.str), "%s:%s:%s", (yyvsp[(1) - (5)].str), (yyvsp[(3) - (5)].str), (yyvsp[(5) - (5)].str)); + free((yyvsp[(1) - (5)].str)); + free((yyvsp[(3) - (5)].str)); + free((yyvsp[(5) - (5)].str)); ;} + break; + + case 53: +#line 321 "ael.y" + { (yyval.str) = (yyvsp[(1) - (1)].str); ;} + break; + + case 54: +#line 325 "ael.y" + { + (yyval.pval) = nword((yyvsp[(1) - (7)].str), &(yylsp[(1) - (7)])); + (yyval.pval)->next = nword((yyvsp[(3) - (7)].str), &(yylsp[(3) - (7)])); + (yyval.pval)->next->next = nword((yyvsp[(5) - (7)].str), &(yylsp[(5) - (7)])); + (yyval.pval)->next->next->next = nword((yyvsp[(7) - (7)].str), &(yylsp[(7) - (7)])); ;} + break; + + case 55: +#line 333 "ael.y" + { reset_parencount(parseio->scanner); ;} + break; + + case 56: +#line 333 "ael.y" + { (yyval.str) = (yyvsp[(3) - (4)].str); ;} + break; + + case 57: +#line 337 "ael.y" + { + (yyval.pval)= npval2(PV_IF, &(yylsp[(1) - (2)]), &(yylsp[(2) - (2)])); + (yyval.pval)->u1.str = (yyvsp[(2) - (2)].str); ;} + break; + + case 58: +#line 340 "ael.y" + { + (yyval.pval) = npval2(PV_RANDOM, &(yylsp[(1) - (2)]), &(yylsp[(2) - (2)])); + (yyval.pval)->u1.str=(yyvsp[(2) - (2)].str);;} + break; + + case 59: +#line 343 "ael.y" + { + (yyval.pval) = npval2(PV_IFTIME, &(yylsp[(1) - (4)]), &(yylsp[(4) - (4)])); + (yyval.pval)->u1.list = (yyvsp[(3) - (4)].pval); + prev_word = 0; ;} + break; + + case 60: +#line 354 "ael.y" + { (yyval.str) = (yyvsp[(1) - (1)].str);;} + break; + + case 61: +#line 355 "ael.y" + { + asprintf(&((yyval.str)), "%s%s", (yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].str)); + free((yyvsp[(1) - (2)].str)); + free((yyvsp[(2) - (2)].str)); + prev_word = (yyval.str);;} + break; + + case 62: +#line 362 "ael.y" + { (yyval.str) = (yyvsp[(1) - (1)].str); ;} + break; + + case 63: +#line 363 "ael.y" + { + asprintf(&((yyval.str)), "%s %s", (yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].str)); + free((yyvsp[(1) - (2)].str)); + free((yyvsp[(2) - (2)].str)); ;} + break; + + case 64: +#line 367 "ael.y" + { + asprintf(&((yyval.str)), "%s:%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); + free((yyvsp[(1) - (3)].str)); + free((yyvsp[(3) - (3)].str)); ;} + break; + + case 65: +#line 371 "ael.y" + { /* there are often '&' in hints */ + asprintf(&((yyval.str)), "%s&%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); + free((yyvsp[(1) - (3)].str)); + free((yyvsp[(3) - (3)].str));;} + break; + + case 66: +#line 377 "ael.y" + { (yyval.str) = (yyvsp[(1) - (1)].str);;} + break; + + case 67: +#line 378 "ael.y" + { + asprintf(&((yyval.str)), "%s%s", (yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].str)); + free((yyvsp[(1) - (2)].str)); + free((yyvsp[(2) - (2)].str)); + prev_word = (yyval.str);;} + break; + + case 68: +#line 383 "ael.y" + { + asprintf(&((yyval.str)), "%s%s%s", (yyvsp[(1) - (3)].str), (yyvsp[(2) - (3)].str), (yyvsp[(3) - (3)].str)); + free((yyvsp[(1) - (3)].str)); + free((yyvsp[(2) - (3)].str)); + free((yyvsp[(3) - (3)].str)); + prev_word=(yyval.str);;} + break; + + case 69: +#line 391 "ael.y" + { (yyval.str) = (yyvsp[(1) - (1)].str);;} + break; + + case 70: +#line 392 "ael.y" + { + asprintf(&((yyval.str)), "%s%s", (yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].str)); + free((yyvsp[(1) - (2)].str)); + free((yyvsp[(2) - (2)].str));;} + break; + + case 71: +#line 396 "ael.y" + { + asprintf(&((yyval.str)), "%s:%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); + free((yyvsp[(1) - (3)].str)); + free((yyvsp[(3) - (3)].str));;} + break; + + case 72: +#line 402 "ael.y" + { + (yyval.pval) = npval2(PV_SWITCH, &(yylsp[(1) - (5)]), &(yylsp[(5) - (5)])); + (yyval.pval)->u1.str = (yyvsp[(2) - (5)].str); + (yyval.pval)->u2.statements = (yyvsp[(4) - (5)].pval); set_dads((yyval.pval),(yyvsp[(4) - (5)].pval));;} + break; + + case 73: +#line 411 "ael.y" + { + (yyval.pval) = npval2(PV_STATEMENTBLOCK, &(yylsp[(1) - (3)]), &(yylsp[(3) - (3)])); + (yyval.pval)->u1.list = (yyvsp[(2) - (3)].pval); set_dads((yyval.pval),(yyvsp[(2) - (3)].pval));;} + break; + + case 74: +#line 414 "ael.y" + { (yyval.pval) = (yyvsp[(1) - (1)].pval); ;} + break; + + case 75: +#line 415 "ael.y" + { (yyval.pval) = (yyvsp[(1) - (1)].pval); ;} + break; + + case 76: +#line 416 "ael.y" + { + (yyval.pval) = npval2(PV_GOTO, &(yylsp[(1) - (3)]), &(yylsp[(3) - (3)])); + (yyval.pval)->u1.list = (yyvsp[(2) - (3)].pval);;} + break; + + case 77: +#line 419 "ael.y" + { + (yyval.pval) = npval2(PV_GOTO, &(yylsp[(1) - (3)]), &(yylsp[(3) - (3)])); + (yyval.pval)->u1.list = (yyvsp[(2) - (3)].pval);;} + break; + + case 78: +#line 422 "ael.y" + { + (yyval.pval) = npval2(PV_LABEL, &(yylsp[(1) - (2)]), &(yylsp[(2) - (2)])); + (yyval.pval)->u1.str = (yyvsp[(1) - (2)].str); ;} + break; + + case 79: +#line 425 "ael.y" + {reset_semicount(parseio->scanner);;} + break; + + case 80: +#line 426 "ael.y" + {reset_semicount(parseio->scanner);;} + break; + + case 81: +#line 427 "ael.y" + {reset_parencount(parseio->scanner);;} + break; + + case 82: +#line 427 "ael.y" + { /* XXX word_list maybe ? */ + (yyval.pval) = npval2(PV_FOR, &(yylsp[(1) - (12)]), &(yylsp[(12) - (12)])); + (yyval.pval)->u1.for_init = (yyvsp[(4) - (12)].str); + (yyval.pval)->u2.for_test=(yyvsp[(7) - (12)].str); + (yyval.pval)->u3.for_inc = (yyvsp[(10) - (12)].str); + (yyval.pval)->u4.for_statements = (yyvsp[(12) - (12)].pval); set_dads((yyval.pval),(yyvsp[(12) - (12)].pval));;} + break; + + case 83: +#line 433 "ael.y" + { + (yyval.pval) = npval2(PV_WHILE, &(yylsp[(1) - (3)]), &(yylsp[(3) - (3)])); + (yyval.pval)->u1.str = (yyvsp[(2) - (3)].str); + (yyval.pval)->u2.statements = (yyvsp[(3) - (3)].pval); set_dads((yyval.pval),(yyvsp[(3) - (3)].pval));;} + break; + + case 84: +#line 437 "ael.y" + { (yyval.pval) = (yyvsp[(1) - (1)].pval); ;} + break; + + case 85: +#line 438 "ael.y" + { (yyval.pval) = update_last((yyvsp[(2) - (3)].pval), &(yylsp[(2) - (3)])); ;} + break; + + case 86: +#line 439 "ael.y" + { (yyval.pval) = update_last((yyvsp[(1) - (2)].pval), &(yylsp[(2) - (2)])); ;} + break; + + case 87: +#line 440 "ael.y" + { + (yyval.pval)= npval2(PV_APPLICATION_CALL, &(yylsp[(1) - (2)]), &(yylsp[(2) - (2)])); + (yyval.pval)->u1.str = (yyvsp[(1) - (2)].str);;} + break; + + case 88: +#line 443 "ael.y" + {reset_semicount(parseio->scanner);;} + break; + + case 89: +#line 443 "ael.y" + { + char *bufx; + int tot=0; + pval *pptr; + (yyval.pval) = npval2(PV_VARDEC, &(yylsp[(1) - (5)]), &(yylsp[(5) - (5)])); + (yyval.pval)->u2.val=(yyvsp[(4) - (5)].str); + /* rebuild the original string-- this is not an app call, it's an unwrapped vardec, with a func call on the LHS */ + /* string to big to fit in the buffer? */ + tot+=strlen((yyvsp[(1) - (5)].pval)->u1.str); + for(pptr=(yyvsp[(1) - (5)].pval)->u2.arglist;pptr;pptr=pptr->next) { + tot+=strlen(pptr->u1.str); + tot++; /* for a sep like a comma */ + } + tot+=4; /* for safety */ + bufx = calloc(1, tot); + strcpy(bufx,(yyvsp[(1) - (5)].pval)->u1.str); + strcat(bufx,"("); + /* XXX need to advance the pointer or the loop is very inefficient */ + for (pptr=(yyvsp[(1) - (5)].pval)->u2.arglist;pptr;pptr=pptr->next) { + if ( pptr != (yyvsp[(1) - (5)].pval)->u2.arglist ) + strcat(bufx,","); + strcat(bufx,pptr->u1.str); + } + strcat(bufx,")"); +#ifdef AAL_ARGCHECK + if ( !ael_is_funcname((yyvsp[(1) - (5)].pval)->u1.str) ) + ast_log(LOG_WARNING, "==== File: %s, Line %d, Cols: %d-%d: Function call? The name %s is not in my internal list of function names\n", + my_file, (yylsp[(1) - (5)]).first_line, (yylsp[(1) - (5)]).first_column, (yylsp[(1) - (5)]).last_column, (yyvsp[(1) - (5)].pval)->u1.str); +#endif + (yyval.pval)->u1.str = bufx; + destroy_pval((yyvsp[(1) - (5)].pval)); /* the app call it is not, get rid of that chain */ + prev_word = 0; + ;} + break; + + case 90: +#line 476 "ael.y" + { (yyval.pval) = npval2(PV_BREAK, &(yylsp[(1) - (2)]), &(yylsp[(2) - (2)])); ;} + break; + + case 91: +#line 477 "ael.y" + { (yyval.pval) = npval2(PV_RETURN, &(yylsp[(1) - (2)]), &(yylsp[(2) - (2)])); ;} + break; + + case 92: +#line 478 "ael.y" + { (yyval.pval) = npval2(PV_CONTINUE, &(yylsp[(1) - (2)]), &(yylsp[(2) - (2)])); ;} + break; + + case 93: +#line 479 "ael.y" + { + (yyval.pval) = update_last((yyvsp[(1) - (3)].pval), &(yylsp[(2) - (3)])); + (yyval.pval)->u2.statements = (yyvsp[(2) - (3)].pval); set_dads((yyval.pval),(yyvsp[(2) - (3)].pval)); + (yyval.pval)->u3.else_statements = (yyvsp[(3) - (3)].pval);set_dads((yyval.pval),(yyvsp[(3) - (3)].pval));;} + break; + + case 94: +#line 483 "ael.y" + { (yyval.pval)=0; ;} + break; + + case 95: +#line 486 "ael.y" + { (yyval.pval) = (yyvsp[(2) - (2)].pval); ;} + break; + + case 96: +#line 487 "ael.y" + { (yyval.pval) = NULL ; ;} + break; + + case 97: +#line 490 "ael.y" + { (yyval.pval) = nword((yyvsp[(1) - (1)].str), &(yylsp[(1) - (1)])); ;} + break; + + case 98: +#line 491 "ael.y" + { + (yyval.pval) = nword((yyvsp[(1) - (3)].str), &(yylsp[(1) - (3)])); + (yyval.pval)->next = nword((yyvsp[(3) - (3)].str), &(yylsp[(3) - (3)])); ;} + break; + + case 99: +#line 494 "ael.y" + { + (yyval.pval) = nword((yyvsp[(1) - (3)].str), &(yylsp[(1) - (3)])); + (yyval.pval)->next = nword((yyvsp[(3) - (3)].str), &(yylsp[(3) - (3)])); ;} + break; + + case 100: +#line 497 "ael.y" + { + (yyval.pval) = nword((yyvsp[(1) - (5)].str), &(yylsp[(1) - (5)])); + (yyval.pval)->next = nword((yyvsp[(3) - (5)].str), &(yylsp[(3) - (5)])); + (yyval.pval)->next->next = nword((yyvsp[(5) - (5)].str), &(yylsp[(5) - (5)])); ;} + break; + + case 101: +#line 501 "ael.y" + { + (yyval.pval) = nword((yyvsp[(1) - (5)].str), &(yylsp[(1) - (5)])); + (yyval.pval)->next = nword((yyvsp[(3) - (5)].str), &(yylsp[(3) - (5)])); + (yyval.pval)->next->next = nword((yyvsp[(5) - (5)].str), &(yylsp[(5) - (5)])); ;} + break; + + case 102: +#line 505 "ael.y" + { + (yyval.pval) = nword(strdup("default"), &(yylsp[(1) - (5)])); + (yyval.pval)->next = nword((yyvsp[(3) - (5)].str), &(yylsp[(3) - (5)])); + (yyval.pval)->next->next = nword((yyvsp[(5) - (5)].str), &(yylsp[(5) - (5)])); ;} + break; + + case 103: +#line 509 "ael.y" + { + (yyval.pval) = nword(strdup("default"), &(yylsp[(1) - (5)])); + (yyval.pval)->next = nword((yyvsp[(3) - (5)].str), &(yylsp[(3) - (5)])); + (yyval.pval)->next->next = nword((yyvsp[(5) - (5)].str), &(yylsp[(5) - (5)])); ;} + break; + + case 104: +#line 515 "ael.y" + { (yyval.str) = strdup("1"); ;} + break; + + case 105: +#line 516 "ael.y" + { (yyval.str) = (yyvsp[(2) - (2)].str); ;} + break; + + case 106: +#line 520 "ael.y" + { /* ext[, pri] default 1 */ + (yyval.pval) = nword((yyvsp[(1) - (2)].str), &(yylsp[(1) - (2)])); + (yyval.pval)->next = nword((yyvsp[(2) - (2)].str), &(yylsp[(2) - (2)])); ;} + break; + + case 107: +#line 523 "ael.y" + { /* context, ext, pri */ + (yyval.pval) = nword((yyvsp[(4) - (4)].str), &(yylsp[(4) - (4)])); + (yyval.pval)->next = nword((yyvsp[(1) - (4)].str), &(yylsp[(1) - (4)])); + (yyval.pval)->next->next = nword((yyvsp[(2) - (4)].str), &(yylsp[(2) - (4)])); ;} + break; + + case 108: +#line 529 "ael.y" + {reset_argcount(parseio->scanner);;} + break; + + case 109: +#line 529 "ael.y" + { + /* XXX original code had @2 but i think we need @5 */ + (yyval.pval) = npval2(PV_MACRO_CALL, &(yylsp[(1) - (5)]), &(yylsp[(5) - (5)])); + (yyval.pval)->u1.str = (yyvsp[(1) - (5)].str); + (yyval.pval)->u2.arglist = (yyvsp[(4) - (5)].pval);;} + break; + + case 110: +#line 534 "ael.y" + { + (yyval.pval)= npval2(PV_MACRO_CALL, &(yylsp[(1) - (3)]), &(yylsp[(3) - (3)])); + (yyval.pval)->u1.str = (yyvsp[(1) - (3)].str); ;} + break; + + case 111: +#line 542 "ael.y" + {reset_argcount(parseio->scanner);;} + break; + + case 112: +#line 542 "ael.y" + { + if (strcasecmp((yyvsp[(1) - (3)].str),"goto") == 0) { + (yyval.pval) = npval2(PV_GOTO, &(yylsp[(1) - (3)]), &(yylsp[(2) - (3)])); + free((yyvsp[(1) - (3)].str)); /* won't be using this */ + ast_log(LOG_WARNING, "==== File: %s, Line %d, Cols: %d-%d: Suggestion: Use the goto statement instead of the Goto() application call in AEL.\n", my_file, (yylsp[(1) - (3)]).first_line, (yylsp[(1) - (3)]).first_column, (yylsp[(1) - (3)]).last_column ); + } else { + (yyval.pval)= npval2(PV_APPLICATION_CALL, &(yylsp[(1) - (3)]), &(yylsp[(2) - (3)])); + (yyval.pval)->u1.str = (yyvsp[(1) - (3)].str); + } ;} + break; + + case 113: +#line 553 "ael.y" + { + (yyval.pval) = update_last((yyvsp[(1) - (3)].pval), &(yylsp[(3) - (3)])); + if( (yyval.pval)->type == PV_GOTO ) + (yyval.pval)->u1.list = (yyvsp[(2) - (3)].pval); + else + (yyval.pval)->u2.arglist = (yyvsp[(2) - (3)].pval); + ;} + break; + + case 114: +#line 560 "ael.y" + { (yyval.pval) = update_last((yyvsp[(1) - (2)].pval), &(yylsp[(2) - (2)])); ;} + break; + + case 115: +#line 563 "ael.y" + { (yyval.str) = (yyvsp[(1) - (1)].str) ;} + break; + + case 116: +#line 564 "ael.y" + { (yyval.str) = strdup(""); ;} + break; + + case 117: +#line 567 "ael.y" + { (yyval.pval) = nword((yyvsp[(1) - (1)].str), &(yylsp[(1) - (1)])); ;} + break; + + case 118: +#line 568 "ael.y" + { + (yyval.pval)= npval(PV_WORD,0/*@1.first_line*/,0/*@1.last_line*/,0/* @1.first_column*/, 0/*@1.last_column*/); + (yyval.pval)->u1.str = strdup(""); ;} + break; + + case 119: +#line 571 "ael.y" + { (yyval.pval) = linku1((yyvsp[(1) - (3)].pval), nword((yyvsp[(3) - (3)].str), &(yylsp[(3) - (3)]))); ;} + break; + + case 120: +#line 574 "ael.y" + { (yyval.pval) = NULL; ;} + break; + + case 121: +#line 575 "ael.y" + { (yyval.pval) = linku1((yyvsp[(1) - (2)].pval), (yyvsp[(2) - (2)].pval)); ;} + break; + + case 122: +#line 578 "ael.y" + { + (yyval.pval) = npval2(PV_CASE, &(yylsp[(1) - (4)]), &(yylsp[(3) - (4)])); /* XXX 3 or 4 ? */ + (yyval.pval)->u1.str = (yyvsp[(2) - (4)].str); + (yyval.pval)->u2.statements = (yyvsp[(4) - (4)].pval); set_dads((yyval.pval),(yyvsp[(4) - (4)].pval));;} + break; + + case 123: +#line 582 "ael.y" + { + (yyval.pval) = npval2(PV_DEFAULT, &(yylsp[(1) - (3)]), &(yylsp[(3) - (3)])); + (yyval.pval)->u1.str = NULL; + (yyval.pval)->u2.statements = (yyvsp[(3) - (3)].pval);set_dads((yyval.pval),(yyvsp[(3) - (3)].pval));;} + break; + + case 124: +#line 586 "ael.y" + { + (yyval.pval) = npval2(PV_PATTERN, &(yylsp[(1) - (4)]), &(yylsp[(4) - (4)])); /* XXX@3 or @4 ? */ + (yyval.pval)->u1.str = (yyvsp[(2) - (4)].str); + (yyval.pval)->u2.statements = (yyvsp[(4) - (4)].pval);set_dads((yyval.pval),(yyvsp[(4) - (4)].pval));;} + break; + + case 125: +#line 592 "ael.y" + { (yyval.pval) = NULL; ;} + break; + + case 126: +#line 593 "ael.y" + { (yyval.pval) = linku1((yyvsp[(1) - (2)].pval), (yyvsp[(2) - (2)].pval)); ;} + break; + + case 127: +#line 596 "ael.y" + {(yyval.pval)=(yyvsp[(1) - (1)].pval);;} + break; + + case 128: +#line 597 "ael.y" + { (yyval.pval)=(yyvsp[(1) - (1)].pval);;} + break; + + case 129: +#line 598 "ael.y" + { + (yyval.pval) = npval2(PV_CATCH, &(yylsp[(1) - (5)]), &(yylsp[(5) - (5)])); + (yyval.pval)->u1.str = (yyvsp[(2) - (5)].str); + (yyval.pval)->u2.statements = (yyvsp[(4) - (5)].pval); set_dads((yyval.pval),(yyvsp[(4) - (5)].pval));;} + break; + + case 130: +#line 604 "ael.y" + { + (yyval.pval) = npval2(PV_SWITCHES, &(yylsp[(1) - (4)]), &(yylsp[(2) - (4)])); + (yyval.pval)->u1.list = (yyvsp[(3) - (4)].pval); set_dads((yyval.pval),(yyvsp[(3) - (4)].pval));;} + break; + + case 131: +#line 609 "ael.y" + { + (yyval.pval) = npval2(PV_ESWITCHES, &(yylsp[(1) - (4)]), &(yylsp[(2) - (4)])); + (yyval.pval)->u1.list = (yyvsp[(3) - (4)].pval); set_dads((yyval.pval),(yyvsp[(3) - (4)].pval));;} + break; + + case 132: +#line 614 "ael.y" + { (yyval.pval) = NULL; ;} + break; + + case 133: +#line 615 "ael.y" + { (yyval.pval) = linku1(nword((yyvsp[(1) - (3)].str), &(yylsp[(1) - (3)])), (yyvsp[(3) - (3)].pval)); ;} + break; + + case 134: +#line 616 "ael.y" + { char *x; asprintf(&x,"%s@%s", (yyvsp[(1) - (5)].str),(yyvsp[(3) - (5)].str)); free((yyvsp[(1) - (5)].str)); free((yyvsp[(3) - (5)].str)); + (yyval.pval) = linku1(nword(x, &(yylsp[(1) - (5)])), (yyvsp[(5) - (5)].pval));;} + break; + + case 135: +#line 618 "ael.y" + {(yyval.pval)=(yyvsp[(2) - (2)].pval);;} + break; + + case 136: +#line 621 "ael.y" + { (yyval.pval) = nword((yyvsp[(1) - (1)].str), &(yylsp[(1) - (1)])); ;} + break; + + case 137: +#line 622 "ael.y" + { + (yyval.pval) = nword((yyvsp[(1) - (3)].str), &(yylsp[(1) - (3)])); + (yyval.pval)->u2.arglist = (yyvsp[(3) - (3)].pval); + prev_word=0; /* XXX sure ? */ ;} + break; + + case 138: +#line 629 "ael.y" + { (yyval.pval) = (yyvsp[(1) - (2)].pval); ;} + break; + + case 139: +#line 630 "ael.y" + { (yyval.pval) = linku1((yyvsp[(1) - (3)].pval), (yyvsp[(2) - (3)].pval)); ;} + break; + + case 140: +#line 631 "ael.y" + {(yyval.pval)=(yyvsp[(1) - (2)].pval);;} + break; + + case 141: +#line 634 "ael.y" + { + (yyval.pval) = npval2(PV_INCLUDES, &(yylsp[(1) - (4)]), &(yylsp[(4) - (4)])); + (yyval.pval)->u1.list = (yyvsp[(3) - (4)].pval);set_dads((yyval.pval),(yyvsp[(3) - (4)].pval));;} + break; + + case 142: +#line 637 "ael.y" + { + (yyval.pval) = npval2(PV_INCLUDES, &(yylsp[(1) - (3)]), &(yylsp[(3) - (3)]));;} + break; + + +/* Line 1270 of yacc.c. */ +#line 3012 "ael.tab.c" + default: break; + } + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + *++yylsp = yyloc; + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (&yylloc, parseio, YY_("syntax error")); +#else + { + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (&yylloc, parseio, yymsg); + } + else + { + yyerror (&yylloc, parseio, YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } + } +#endif + } + + yyerror_range[0] = yylloc; + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse look-ahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, &yylloc, parseio); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse look-ahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + yyerror_range[0] = yylsp[1-yylen]; + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + yyerror_range[0] = *yylsp; + yydestruct ("Error: popping", + yystos[yystate], yyvsp, yylsp, parseio); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + if (yyn == YYFINAL) + YYACCEPT; + + *++yyvsp = yylval; + + yyerror_range[1] = yylloc; + /* Using YYLLOC is tempting, but would change the location of + the look-ahead. YYLOC is available though. */ + YYLLOC_DEFAULT (yyloc, (yyerror_range - 1), 2); + *++yylsp = yyloc; + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#ifndef yyoverflow +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (&yylloc, parseio, YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEOF && yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, &yylloc, parseio); + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp, yylsp, parseio); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + return yyresult; +} + + +#line 642 "ael.y" + + +static char *token_equivs1[] = +{ + "AMPER", + "AT", + "BAR", + "COLON", + "COMMA", + "EQ", + "EXTENMARK", + "KW_BREAK", + "KW_CASE", + "KW_CATCH", + "KW_CONTEXT", + "KW_CONTINUE", + "KW_DEFAULT", + "KW_ELSE", + "KW_ESWITCHES", + "KW_FOR", + "KW_GLOBALS", + "KW_GOTO", + "KW_HINT", + "KW_IFTIME", + "KW_IF", + "KW_IGNOREPAT", + "KW_INCLUDES" + "KW_JUMP", + "KW_MACRO", + "KW_PATTERN", + "KW_REGEXTEN", + "KW_RETURN", + "KW_SWITCHES", + "KW_SWITCH", + "KW_WHILE", + "LC", + "LP", + "RC", + "RP", + "SEMI", +}; + +static char *token_equivs2[] = +{ + "&", + "@", + "|", + ":", + ",", + "=", + "=>", + "break", + "case", + "catch", + "context", + "continue", + "default", + "else", + "eswitches", + "for", + "globals", + "goto", + "hint", + "ifTime", + "if", + "ignorepat", + "includes" + "jump", + "macro", + "pattern", + "regexten", + "return", + "switches", + "switch", + "while", + "{", + "(", + "}", + ")", + ";", +}; + + +static char *ael_token_subst(const char *mess) +{ + /* calc a length, malloc, fill, and return; yyerror had better free it! */ + int len=0,i; + const char *p; + char *res, *s,*t; + int token_equivs_entries = sizeof(token_equivs1)/sizeof(char*); + + for (p=mess; *p; p++) { + for (i=0; i<token_equivs_entries; i++) { + if ( strncmp(p,token_equivs1[i],strlen(token_equivs1[i])) == 0 ) + { + len+=strlen(token_equivs2[i])+2; + p += strlen(token_equivs1[i])-1; + break; + } + } + len++; + } + res = calloc(1, len+1); + res[0] = 0; + s = res; + for (p=mess; *p;) { + int found = 0; + for (i=0; i<token_equivs_entries; i++) { + if ( strncmp(p,token_equivs1[i],strlen(token_equivs1[i])) == 0 ) { + *s++ = '\''; + for (t=token_equivs2[i]; *t;) { + *s++ = *t++; + } + *s++ = '\''; + p += strlen(token_equivs1[i]); + found = 1; + break; + } + } + if( !found ) + *s++ = *p++; + } + *s++ = 0; + return res; +} + +void yyerror(YYLTYPE *locp, struct parse_io *parseio, char const *s) +{ + char *s2 = ael_token_subst((char *)s); + if (locp->first_line == locp->last_line) { + ast_log(LOG_ERROR, "==== File: %s, Line %d, Cols: %d-%d: Error: %s\n", my_file, locp->first_line, locp->first_column, locp->last_column, s2); + } else { + ast_log(LOG_ERROR, "==== File: %s, Line %d Col %d to Line %d Col %d: Error: %s\n", my_file, locp->first_line, locp->first_column, locp->last_line, locp->last_column, s2); + } + free(s2); + parseio->syntax_error_count++; +} + +struct pval *npval(pvaltype type, int first_line, int last_line, + int first_column, int last_column) +{ + pval *z = calloc(1, sizeof(struct pval)); + z->type = type; + z->startline = first_line; + z->endline = last_line; + z->startcol = first_column; + z->endcol = last_column; + z->filename = strdup(my_file); + return z; +} + +static struct pval *npval2(pvaltype type, YYLTYPE *first, YYLTYPE *last) +{ + return npval(type, first->first_line, last->last_line, + first->first_column, last->last_column); +} + +static struct pval *update_last(pval *obj, YYLTYPE *last) +{ + obj->endline = last->last_line; + obj->endcol = last->last_column; + return obj; +} + +/* frontend for npval to create a PV_WORD string from the given token */ +static pval *nword(char *string, YYLTYPE *pos) +{ + pval *p = npval2(PV_WORD, pos, pos); + if (p) + p->u1.str = string; + return p; +} + +/* this routine adds a dad ptr to each element in the list */ +static void set_dads(struct pval *dad, struct pval *child_list) +{ + struct pval *t; + + for(t=child_list;t;t=t->next) /* simple stuff */ + t->dad = dad; +} + + diff --git a/trunk/res/ael/ael.tab.h b/trunk/res/ael/ael.tab.h new file mode 100644 index 000000000..95b011852 --- /dev/null +++ b/trunk/res/ael/ael.tab.h @@ -0,0 +1,154 @@ +/* A Bison parser, made by GNU Bison 2.1a. */ + +/* Skeleton parser for Yacc-like parsing with Bison, + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + KW_CONTEXT = 258, + LC = 259, + RC = 260, + LP = 261, + RP = 262, + SEMI = 263, + EQ = 264, + COMMA = 265, + COLON = 266, + AMPER = 267, + BAR = 268, + AT = 269, + KW_MACRO = 270, + KW_GLOBALS = 271, + KW_IGNOREPAT = 272, + KW_SWITCH = 273, + KW_IF = 274, + KW_IFTIME = 275, + KW_ELSE = 276, + KW_RANDOM = 277, + KW_ABSTRACT = 278, + KW_EXTEND = 279, + EXTENMARK = 280, + KW_GOTO = 281, + KW_JUMP = 282, + KW_RETURN = 283, + KW_BREAK = 284, + KW_CONTINUE = 285, + KW_REGEXTEN = 286, + KW_HINT = 287, + KW_FOR = 288, + KW_WHILE = 289, + KW_CASE = 290, + KW_PATTERN = 291, + KW_DEFAULT = 292, + KW_CATCH = 293, + KW_SWITCHES = 294, + KW_ESWITCHES = 295, + KW_INCLUDES = 296, + KW_LOCAL = 297, + word = 298 + }; +#endif +/* Tokens. */ +#define KW_CONTEXT 258 +#define LC 259 +#define RC 260 +#define LP 261 +#define RP 262 +#define SEMI 263 +#define EQ 264 +#define COMMA 265 +#define COLON 266 +#define AMPER 267 +#define BAR 268 +#define AT 269 +#define KW_MACRO 270 +#define KW_GLOBALS 271 +#define KW_IGNOREPAT 272 +#define KW_SWITCH 273 +#define KW_IF 274 +#define KW_IFTIME 275 +#define KW_ELSE 276 +#define KW_RANDOM 277 +#define KW_ABSTRACT 278 +#define KW_EXTEND 279 +#define EXTENMARK 280 +#define KW_GOTO 281 +#define KW_JUMP 282 +#define KW_RETURN 283 +#define KW_BREAK 284 +#define KW_CONTINUE 285 +#define KW_REGEXTEN 286 +#define KW_HINT 287 +#define KW_FOR 288 +#define KW_WHILE 289 +#define KW_CASE 290 +#define KW_PATTERN 291 +#define KW_DEFAULT 292 +#define KW_CATCH 293 +#define KW_SWITCHES 294 +#define KW_ESWITCHES 295 +#define KW_INCLUDES 296 +#define KW_LOCAL 297 +#define word 298 + + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +#line 54 "ael.y" +{ + int intval; /* integer value, typically flags */ + char *str; /* strings */ + struct pval *pval; /* full objects */ +} +/* Line 1536 of yacc.c. */ +#line 131 "ael.tab.h" + YYSTYPE; +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + + + +#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED +typedef struct YYLTYPE +{ + int first_line; + int first_column; + int last_line; + int last_column; +} YYLTYPE; +# define yyltype YYLTYPE /* obsolescent; will be withdrawn */ +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 +#endif + + + + diff --git a/trunk/res/ael/ael.y b/trunk/res/ael/ael.y new file mode 100644 index 000000000..a8df1cb51 --- /dev/null +++ b/trunk/res/ael/ael.y @@ -0,0 +1,823 @@ +%{ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2006, Digium, Inc. + * + * Steve Murphy <murf@parsetree.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ +/*! \file + * + * \brief Bison Grammar description of AEL2. + * + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "asterisk/logger.h" +#include "asterisk/ael_structs.h" + +pval * linku1(pval *head, pval *tail); +static void set_dads(pval *dad, pval *child_list); +void reset_parencount(yyscan_t yyscanner); +void reset_semicount(yyscan_t yyscanner); +void reset_argcount(yyscan_t yyscanner ); + +#define YYLEX_PARAM ((struct parse_io *)parseio)->scanner +#define YYERROR_VERBOSE 1 + +extern char *my_file; +#ifdef AAL_ARGCHECK +int ael_is_funcname(char *name); +#endif +static char *ael_token_subst(const char *mess); + +%} + + +%union { + int intval; /* integer value, typically flags */ + char *str; /* strings */ + struct pval *pval; /* full objects */ +} + +%{ + /* declaring these AFTER the union makes things a lot simpler! */ +void yyerror(YYLTYPE *locp, struct parse_io *parseio, char const *s); +int ael_yylex (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , void * yyscanner); + +/* create a new object with start-end marker */ +pval *npval(pvaltype type, int first_line, int last_line, + int first_column, int last_column); + +/* create a new object with start-end marker, simplified interface. + * Must be declared here because YYLTYPE is not known before + */ +static pval *npval2(pvaltype type, YYLTYPE *first, YYLTYPE *last); + +/* another frontend for npval, this time for a string */ +static pval *nword(char *string, YYLTYPE *pos); + +/* update end position of an object, return the object */ +static pval *update_last(pval *, YYLTYPE *); +%} + + +%token KW_CONTEXT LC RC LP RP SEMI EQ COMMA COLON AMPER BAR AT +%token KW_MACRO KW_GLOBALS KW_IGNOREPAT KW_SWITCH KW_IF KW_IFTIME KW_ELSE KW_RANDOM KW_ABSTRACT KW_EXTEND +%token EXTENMARK KW_GOTO KW_JUMP KW_RETURN KW_BREAK KW_CONTINUE KW_REGEXTEN KW_HINT +%token KW_FOR KW_WHILE KW_CASE KW_PATTERN KW_DEFAULT KW_CATCH KW_SWITCHES KW_ESWITCHES +%token KW_INCLUDES KW_LOCAL + +%right BAR COMMA + +%token <str> word + +%type <pval>includes +%type <pval>includeslist +%type <pval>switchlist +%type <pval>eswitches +%type <pval>switches +%type <pval>macro_statement +%type <pval>macro_statements +%type <pval>case_statement +%type <pval>case_statements +%type <pval>eval_arglist +%type <pval>application_call +%type <pval>application_call_head +%type <pval>macro_call +%type <pval>target jumptarget +%type <pval>statement +%type <pval>switch_statement + +%type <pval>if_like_head +%type <pval>statements +%type <pval>extension +%type <pval>ignorepat +%type <pval>element +%type <pval>elements +%type <pval>arglist +%type <pval>assignment +%type <pval>local_assignment +%type <pval>global_statements +%type <pval>globals +%type <pval>macro +%type <pval>context +%type <pval>object +%type <pval>objects +%type <pval>file +/* XXX lr changes */ +%type <pval>opt_else +%type <pval>timespec +%type <pval>included_entry + +%type <str>opt_word +%type <str>context_name +%type <str>timerange + +%type <str>goto_word +%type <str>word_list +%type <str>word3_list hint_word +%type <str>test_expr +%type <str>opt_pri + +%type <intval>opt_abstract + +/* + * OPTIONS + */ + +%locations /* track source location using @n variables (yylloc in flex) */ +%pure-parser /* pass yylval and yylloc as arguments to yylex(). */ +%name-prefix="ael_yy" +/* + * add an additional argument, parseio, to yyparse(), + * which is then accessible in the grammar actions + */ +%parse-param {struct parse_io *parseio} + +/* there will be two shift/reduce conflicts, they involve the if statement, where a single statement occurs not wrapped in curlies in the "true" section + the default action to shift will attach the else to the preceeding if. */ +%expect 3 +%error-verbose + +/* + * declare destructors for objects. + * The former is for pval, the latter for strings. + * NOTE: we must not have a destructor for a 'file' object. + */ +%destructor { + destroy_pval($$); + prev_word=0; + } includes includeslist switchlist eswitches switches + macro_statement macro_statements case_statement case_statements + eval_arglist application_call application_call_head + macro_call target jumptarget statement switch_statement + if_like_head statements extension + ignorepat element elements arglist assignment local_assignment + global_statements globals macro context object objects + opt_else + timespec included_entry + +%destructor { free($$);} word word_list goto_word word3_list opt_word context_name + timerange + test_expr + opt_pri + + +%% + +file : objects { $$ = parseio->pval = $1; } + ; + +objects : object {$$=$1;} + | objects object { $$ = linku1($1, $2); } + | objects error {$$=$1;} + ; + +object : context {$$=$1;} + | macro {$$=$1;} + | globals {$$=$1;} + | SEMI {$$=0;/* allow older docs to be read */} + ; + +context_name : word { $$ = $1; } + | KW_DEFAULT { $$ = strdup("default"); } + ; + +context : opt_abstract KW_CONTEXT context_name LC elements RC { + $$ = npval2(PV_CONTEXT, &@1, &@6); + $$->u1.str = $3; + $$->u2.statements = $5; + set_dads($$,$5); + $$->u3.abstract = $1;} + ; + +/* optional "abstract" keyword XXX there is no regression test for this */ +opt_abstract: KW_ABSTRACT { $$ = 1; } + | /* nothing */ { $$ = 0; } + | KW_EXTEND { $$ = 2; } + | KW_EXTEND KW_ABSTRACT { $$=3; } + | KW_ABSTRACT KW_EXTEND { $$=3; } + ; + +macro : KW_MACRO word LP arglist RP LC macro_statements RC { + $$ = npval2(PV_MACRO, &@1, &@8); + $$->u1.str = $2; $$->u2.arglist = $4; $$->u3.macro_statements = $7; + set_dads($$,$7);} + ; + +globals : KW_GLOBALS LC global_statements RC { + $$ = npval2(PV_GLOBALS, &@1, &@4); + $$->u1.statements = $3; + set_dads($$,$3);} + ; + +global_statements : { $$ = NULL; } + | assignment global_statements {$$ = linku1($1, $2); } + | error global_statements {$$=$2;} + ; + +assignment : word EQ { reset_semicount(parseio->scanner); } word SEMI { + $$ = npval2(PV_VARDEC, &@1, &@5); + $$->u1.str = $1; + $$->u2.val = $4; } + ; + +local_assignment : KW_LOCAL word EQ { reset_semicount(parseio->scanner); } word SEMI { + $$ = npval2(PV_LOCALVARDEC, &@1, &@6); + $$->u1.str = $2; + $$->u2.val = $5; } + ; + +/* XXX this matches missing arguments, is this desired ? */ +arglist : /* empty */ { $$ = NULL; } + | word { $$ = nword($1, &@1); } + | arglist COMMA word { $$ = linku1($1, nword($3, &@3)); } + | arglist error {$$=$1;} + ; + +elements : {$$=0;} + | element elements { $$ = linku1($1, $2); } + | error elements { $$=$2;} + ; + +element : extension {$$=$1;} + | includes {$$=$1;} + | switches {$$=$1;} + | eswitches {$$=$1;} + | ignorepat {$$=$1;} + | assignment {$$=$1;} + | local_assignment {$$=$1;} + | word error {free($1); $$=0;} + | SEMI {$$=0;/* allow older docs to be read */} + ; + +ignorepat : KW_IGNOREPAT EXTENMARK word SEMI { + $$ = npval2(PV_IGNOREPAT, &@1, &@4); + $$->u1.str = $3;} + ; + +extension : word EXTENMARK statement { + $$ = npval2(PV_EXTENSION, &@1, &@3); + $$->u1.str = $1; + $$->u2.statements = $3; set_dads($$,$3);} + | word AT word EXTENMARK statement { + $$ = npval2(PV_EXTENSION, &@1, &@3); + $$->u1.str = malloc(strlen($1)+strlen($3)+2); + strcpy($$->u1.str,$1); + strcat($$->u1.str,"@"); + strcat($$->u1.str,$3); + free($1); + $$->u2.statements = $5; set_dads($$,$5);} + | KW_REGEXTEN word EXTENMARK statement { + $$ = npval2(PV_EXTENSION, &@1, &@4); + $$->u1.str = $2; + $$->u2.statements = $4; set_dads($$,$4); + $$->u4.regexten=1;} + | KW_HINT LP hint_word RP word EXTENMARK statement { + $$ = npval2(PV_EXTENSION, &@1, &@7); + $$->u1.str = $5; + $$->u2.statements = $7; set_dads($$,$7); + $$->u3.hints = $3;} + | KW_REGEXTEN KW_HINT LP hint_word RP word EXTENMARK statement { + $$ = npval2(PV_EXTENSION, &@1, &@8); + $$->u1.str = $6; + $$->u2.statements = $8; set_dads($$,$8); + $$->u4.regexten=1; + $$->u3.hints = $4;} + ; + +/* list of statements in a block or after a case label - can be empty */ +statements : /* empty */ { $$ = NULL; } + | statement statements { $$ = linku1($1, $2); } + | error statements {$$=$2;} + ; + +/* hh:mm-hh:mm, due to the way the parser works we do not + * detect the '-' but only the ':' as separator + */ +timerange: word3_list COLON word3_list COLON word3_list { + asprintf(&$$, "%s:%s:%s", $1, $3, $5); + free($1); + free($3); + free($5); } + | word { $$ = $1; } + ; + +/* full time specification range|dow|*|* */ +timespec : timerange BAR word3_list BAR word3_list BAR word3_list { + $$ = nword($1, &@1); + $$->next = nword($3, &@3); + $$->next->next = nword($5, &@5); + $$->next->next->next = nword($7, &@7); } + ; + +/* expression used in if, random, while, switch */ +test_expr : LP { reset_parencount(parseio->scanner); } word_list RP { $$ = $3; } + ; + +/* 'if' like statements: if, iftime, random */ +if_like_head : KW_IF test_expr { + $$= npval2(PV_IF, &@1, &@2); + $$->u1.str = $2; } + | KW_RANDOM test_expr { + $$ = npval2(PV_RANDOM, &@1, &@2); + $$->u1.str=$2;} + | KW_IFTIME LP timespec RP { + $$ = npval2(PV_IFTIME, &@1, &@4); + $$->u1.list = $3; + prev_word = 0; } + ; + +/* word_list is a hack to fix a problem with context switching between bison and flex; + by the time you register a new context with flex, you've already got a look-ahead token + from the old context, with no way to put it back and start afresh. So, we kludge this + and merge the words back together. */ + +word_list : word { $$ = $1;} + | word word { + asprintf(&($$), "%s%s", $1, $2); + free($1); + free($2); + prev_word = $$;} + ; + +hint_word : word { $$ = $1; } + | hint_word word { + asprintf(&($$), "%s %s", $1, $2); + free($1); + free($2); } + | hint_word COLON word { + asprintf(&($$), "%s:%s", $1, $3); + free($1); + free($3); } + | hint_word AMPER word { /* there are often '&' in hints */ + asprintf(&($$), "%s&%s", $1, $3); + free($1); + free($3);} + + +word3_list : word { $$ = $1;} + | word word { + asprintf(&($$), "%s%s", $1, $2); + free($1); + free($2); + prev_word = $$;} + | word word word { + asprintf(&($$), "%s%s%s", $1, $2, $3); + free($1); + free($2); + free($3); + prev_word=$$;} + ; + +goto_word : word { $$ = $1;} + | word word { + asprintf(&($$), "%s%s", $1, $2); + free($1); + free($2);} + | goto_word COLON word { + asprintf(&($$), "%s:%s", $1, $3); + free($1); + free($3);} + ; + +switch_statement : KW_SWITCH test_expr LC case_statements RC { + $$ = npval2(PV_SWITCH, &@1, &@5); + $$->u1.str = $2; + $$->u2.statements = $4; set_dads($$,$4);} + ; + +/* + * Definition of a statememt in our language + */ +statement : LC statements RC { + $$ = npval2(PV_STATEMENTBLOCK, &@1, &@3); + $$->u1.list = $2; set_dads($$,$2);} + | assignment { $$ = $1; } + | local_assignment { $$ = $1; } + | KW_GOTO target SEMI { + $$ = npval2(PV_GOTO, &@1, &@3); + $$->u1.list = $2;} + | KW_JUMP jumptarget SEMI { + $$ = npval2(PV_GOTO, &@1, &@3); + $$->u1.list = $2;} + | word COLON { + $$ = npval2(PV_LABEL, &@1, &@2); + $$->u1.str = $1; } + | KW_FOR LP {reset_semicount(parseio->scanner);} word SEMI + {reset_semicount(parseio->scanner);} word SEMI + {reset_parencount(parseio->scanner);} word RP statement { /* XXX word_list maybe ? */ + $$ = npval2(PV_FOR, &@1, &@12); + $$->u1.for_init = $4; + $$->u2.for_test=$7; + $$->u3.for_inc = $10; + $$->u4.for_statements = $12; set_dads($$,$12);} + | KW_WHILE test_expr statement { + $$ = npval2(PV_WHILE, &@1, &@3); + $$->u1.str = $2; + $$->u2.statements = $3; set_dads($$,$3);} + | switch_statement { $$ = $1; } + | AMPER macro_call SEMI { $$ = update_last($2, &@2); } + | application_call SEMI { $$ = update_last($1, &@2); } + | word SEMI { + $$= npval2(PV_APPLICATION_CALL, &@1, &@2); + $$->u1.str = $1;} + | application_call EQ {reset_semicount(parseio->scanner);} word SEMI { + char *bufx; + int tot=0; + pval *pptr; + $$ = npval2(PV_VARDEC, &@1, &@5); + $$->u2.val=$4; + /* rebuild the original string-- this is not an app call, it's an unwrapped vardec, with a func call on the LHS */ + /* string to big to fit in the buffer? */ + tot+=strlen($1->u1.str); + for(pptr=$1->u2.arglist;pptr;pptr=pptr->next) { + tot+=strlen(pptr->u1.str); + tot++; /* for a sep like a comma */ + } + tot+=4; /* for safety */ + bufx = calloc(1, tot); + strcpy(bufx,$1->u1.str); + strcat(bufx,"("); + /* XXX need to advance the pointer or the loop is very inefficient */ + for (pptr=$1->u2.arglist;pptr;pptr=pptr->next) { + if ( pptr != $1->u2.arglist ) + strcat(bufx,","); + strcat(bufx,pptr->u1.str); + } + strcat(bufx,")"); +#ifdef AAL_ARGCHECK + if ( !ael_is_funcname($1->u1.str) ) + ast_log(LOG_WARNING, "==== File: %s, Line %d, Cols: %d-%d: Function call? The name %s is not in my internal list of function names\n", + my_file, @1.first_line, @1.first_column, @1.last_column, $1->u1.str); +#endif + $$->u1.str = bufx; + destroy_pval($1); /* the app call it is not, get rid of that chain */ + prev_word = 0; + } + | KW_BREAK SEMI { $$ = npval2(PV_BREAK, &@1, &@2); } + | KW_RETURN SEMI { $$ = npval2(PV_RETURN, &@1, &@2); } + | KW_CONTINUE SEMI { $$ = npval2(PV_CONTINUE, &@1, &@2); } + | if_like_head statement opt_else { + $$ = update_last($1, &@2); + $$->u2.statements = $2; set_dads($$,$2); + $$->u3.else_statements = $3;set_dads($$,$3);} + | SEMI { $$=0; } + ; + +opt_else : KW_ELSE statement { $$ = $2; } + | { $$ = NULL ; } + + +target : goto_word { $$ = nword($1, &@1); } + | goto_word BAR goto_word { + $$ = nword($1, &@1); + $$->next = nword($3, &@3); } + | goto_word COMMA goto_word { + $$ = nword($1, &@1); + $$->next = nword($3, &@3); } + | goto_word BAR goto_word BAR goto_word { + $$ = nword($1, &@1); + $$->next = nword($3, &@3); + $$->next->next = nword($5, &@5); } + | goto_word COMMA goto_word COMMA goto_word { + $$ = nword($1, &@1); + $$->next = nword($3, &@3); + $$->next->next = nword($5, &@5); } + | KW_DEFAULT BAR goto_word BAR goto_word { + $$ = nword(strdup("default"), &@1); + $$->next = nword($3, &@3); + $$->next->next = nword($5, &@5); } + | KW_DEFAULT COMMA goto_word COMMA goto_word { + $$ = nword(strdup("default"), &@1); + $$->next = nword($3, &@3); + $$->next->next = nword($5, &@5); } + ; + +opt_pri : /* empty */ { $$ = strdup("1"); } + | COMMA word { $$ = $2; } + ; + +/* XXX please document the form of jumptarget */ +jumptarget : goto_word opt_pri { /* ext[, pri] default 1 */ + $$ = nword($1, &@1); + $$->next = nword($2, &@2); } /* jump extension[,priority][@context] */ + | goto_word opt_pri AT context_name { /* context, ext, pri */ + $$ = nword($4, &@4); + $$->next = nword($1, &@1); + $$->next->next = nword($2, &@2); } + ; + +macro_call : word LP {reset_argcount(parseio->scanner);} eval_arglist RP { + /* XXX original code had @2 but i think we need @5 */ + $$ = npval2(PV_MACRO_CALL, &@1, &@5); + $$->u1.str = $1; + $$->u2.arglist = $4;} + | word LP RP { + $$= npval2(PV_MACRO_CALL, &@1, &@3); + $$->u1.str = $1; } + ; + +/* XXX application_call_head must be revised. Having 'word LP { ...' + * just as above should work fine, however it gives a different result. + */ +application_call_head: word LP {reset_argcount(parseio->scanner);} { + if (strcasecmp($1,"goto") == 0) { + $$ = npval2(PV_GOTO, &@1, &@2); + free($1); /* won't be using this */ + ast_log(LOG_WARNING, "==== File: %s, Line %d, Cols: %d-%d: Suggestion: Use the goto statement instead of the Goto() application call in AEL.\n", my_file, @1.first_line, @1.first_column, @1.last_column ); + } else { + $$= npval2(PV_APPLICATION_CALL, &@1, &@2); + $$->u1.str = $1; + } } + ; + +application_call : application_call_head eval_arglist RP { + $$ = update_last($1, &@3); + if( $$->type == PV_GOTO ) + $$->u1.list = $2; + else + $$->u2.arglist = $2; + } + | application_call_head RP { $$ = update_last($1, &@2); } + ; + +opt_word : word { $$ = $1 } + | { $$ = strdup(""); } + ; + +eval_arglist : word_list { $$ = nword($1, &@1); } + | /*nothing! */ { + $$= npval(PV_WORD,0/*@1.first_line*/,0/*@1.last_line*/,0/* @1.first_column*/, 0/*@1.last_column*/); + $$->u1.str = strdup(""); } + | eval_arglist COMMA opt_word { $$ = linku1($1, nword($3, &@3)); } + ; + +case_statements: /* empty */ { $$ = NULL; } + | case_statement case_statements { $$ = linku1($1, $2); } + ; + +case_statement: KW_CASE word COLON statements { + $$ = npval2(PV_CASE, &@1, &@3); /* XXX 3 or 4 ? */ + $$->u1.str = $2; + $$->u2.statements = $4; set_dads($$,$4);} + | KW_DEFAULT COLON statements { + $$ = npval2(PV_DEFAULT, &@1, &@3); + $$->u1.str = NULL; + $$->u2.statements = $3;set_dads($$,$3);} + | KW_PATTERN word COLON statements { + $$ = npval2(PV_PATTERN, &@1, &@4); /* XXX@3 or @4 ? */ + $$->u1.str = $2; + $$->u2.statements = $4;set_dads($$,$4);} + ; + +macro_statements: /* empty */ { $$ = NULL; } + | macro_statement macro_statements { $$ = linku1($1, $2); } + ; + +macro_statement : statement {$$=$1;} + | includes { $$=$1;} + | KW_CATCH word LC statements RC { + $$ = npval2(PV_CATCH, &@1, &@5); + $$->u1.str = $2; + $$->u2.statements = $4; set_dads($$,$4);} + ; + +switches : KW_SWITCHES LC switchlist RC { + $$ = npval2(PV_SWITCHES, &@1, &@2); + $$->u1.list = $3; set_dads($$,$3);} + ; + +eswitches : KW_ESWITCHES LC switchlist RC { + $$ = npval2(PV_ESWITCHES, &@1, &@2); + $$->u1.list = $3; set_dads($$,$3);} + ; + +switchlist : /* empty */ { $$ = NULL; } + | word SEMI switchlist { $$ = linku1(nword($1, &@1), $3); } + | word AT word SEMI switchlist { char *x; asprintf(&x,"%s@%s", $1,$3); free($1); free($3); + $$ = linku1(nword(x, &@1), $5);} + | error switchlist {$$=$2;} + ; + +included_entry : context_name { $$ = nword($1, &@1); } + | context_name BAR timespec { + $$ = nword($1, &@1); + $$->u2.arglist = $3; + prev_word=0; /* XXX sure ? */ } + ; + +/* list of ';' separated context names followed by optional timespec */ +includeslist : included_entry SEMI { $$ = $1; } + | includeslist included_entry SEMI { $$ = linku1($1, $2); } + | includeslist error {$$=$1;} + ; + +includes : KW_INCLUDES LC includeslist RC { + $$ = npval2(PV_INCLUDES, &@1, &@4); + $$->u1.list = $3;set_dads($$,$3);} + | KW_INCLUDES LC RC { + $$ = npval2(PV_INCLUDES, &@1, &@3);} + ; + + +%% + +static char *token_equivs1[] = +{ + "AMPER", + "AT", + "BAR", + "COLON", + "COMMA", + "EQ", + "EXTENMARK", + "KW_BREAK", + "KW_CASE", + "KW_CATCH", + "KW_CONTEXT", + "KW_CONTINUE", + "KW_DEFAULT", + "KW_ELSE", + "KW_ESWITCHES", + "KW_FOR", + "KW_GLOBALS", + "KW_GOTO", + "KW_HINT", + "KW_IFTIME", + "KW_IF", + "KW_IGNOREPAT", + "KW_INCLUDES" + "KW_JUMP", + "KW_MACRO", + "KW_PATTERN", + "KW_REGEXTEN", + "KW_RETURN", + "KW_SWITCHES", + "KW_SWITCH", + "KW_WHILE", + "LC", + "LP", + "RC", + "RP", + "SEMI", +}; + +static char *token_equivs2[] = +{ + "&", + "@", + "|", + ":", + ",", + "=", + "=>", + "break", + "case", + "catch", + "context", + "continue", + "default", + "else", + "eswitches", + "for", + "globals", + "goto", + "hint", + "ifTime", + "if", + "ignorepat", + "includes" + "jump", + "macro", + "pattern", + "regexten", + "return", + "switches", + "switch", + "while", + "{", + "(", + "}", + ")", + ";", +}; + + +static char *ael_token_subst(const char *mess) +{ + /* calc a length, malloc, fill, and return; yyerror had better free it! */ + int len=0,i; + const char *p; + char *res, *s,*t; + int token_equivs_entries = sizeof(token_equivs1)/sizeof(char*); + + for (p=mess; *p; p++) { + for (i=0; i<token_equivs_entries; i++) { + if ( strncmp(p,token_equivs1[i],strlen(token_equivs1[i])) == 0 ) + { + len+=strlen(token_equivs2[i])+2; + p += strlen(token_equivs1[i])-1; + break; + } + } + len++; + } + res = calloc(1, len+1); + res[0] = 0; + s = res; + for (p=mess; *p;) { + int found = 0; + for (i=0; i<token_equivs_entries; i++) { + if ( strncmp(p,token_equivs1[i],strlen(token_equivs1[i])) == 0 ) { + *s++ = '\''; + for (t=token_equivs2[i]; *t;) { + *s++ = *t++; + } + *s++ = '\''; + p += strlen(token_equivs1[i]); + found = 1; + break; + } + } + if( !found ) + *s++ = *p++; + } + *s++ = 0; + return res; +} + +void yyerror(YYLTYPE *locp, struct parse_io *parseio, char const *s) +{ + char *s2 = ael_token_subst((char *)s); + if (locp->first_line == locp->last_line) { + ast_log(LOG_ERROR, "==== File: %s, Line %d, Cols: %d-%d: Error: %s\n", my_file, locp->first_line, locp->first_column, locp->last_column, s2); + } else { + ast_log(LOG_ERROR, "==== File: %s, Line %d Col %d to Line %d Col %d: Error: %s\n", my_file, locp->first_line, locp->first_column, locp->last_line, locp->last_column, s2); + } + free(s2); + parseio->syntax_error_count++; +} + +struct pval *npval(pvaltype type, int first_line, int last_line, + int first_column, int last_column) +{ + pval *z = calloc(1, sizeof(struct pval)); + z->type = type; + z->startline = first_line; + z->endline = last_line; + z->startcol = first_column; + z->endcol = last_column; + z->filename = strdup(my_file); + return z; +} + +static struct pval *npval2(pvaltype type, YYLTYPE *first, YYLTYPE *last) +{ + return npval(type, first->first_line, last->last_line, + first->first_column, last->last_column); +} + +static struct pval *update_last(pval *obj, YYLTYPE *last) +{ + obj->endline = last->last_line; + obj->endcol = last->last_column; + return obj; +} + +/* frontend for npval to create a PV_WORD string from the given token */ +static pval *nword(char *string, YYLTYPE *pos) +{ + pval *p = npval2(PV_WORD, pos, pos); + if (p) + p->u1.str = string; + return p; +} + +/* this routine adds a dad ptr to each element in the list */ +static void set_dads(struct pval *dad, struct pval *child_list) +{ + struct pval *t; + + for(t=child_list;t;t=t->next) /* simple stuff */ + t->dad = dad; +} + diff --git a/trunk/res/ael/ael_lex.c b/trunk/res/ael/ael_lex.c new file mode 100644 index 000000000..26206af5d --- /dev/null +++ b/trunk/res/ael/ael_lex.c @@ -0,0 +1,3127 @@ +#line 2 "ael_lex.c" + +#line 4 "ael_lex.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 33 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +#include "asterisk.h" +/* begin standard C headers. */ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ + +#if !defined __STDC_VERSION__ || __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include <inttypes.h> +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; +#endif /* ! C99 */ + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#if __STDC__ + +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +int ael_yylex_init (yyscan_t* scanner); + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yyg->yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yyg->yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE ael_yyrestart(yyin ,yyscanner ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#define YY_BUF_SIZE 16384 +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = yyg->yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) + +/* The following is because we cannot portably get our hands on size_t + * (without autoconf's help, which isn't available because we want + * flex-generated scanners to compile on their own). + */ + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef unsigned int yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via ael_yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ + ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] + +void ael_yyrestart (FILE *input_file ,yyscan_t yyscanner ); +void ael_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +YY_BUFFER_STATE ael_yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner ); +void ael_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void ael_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void ael_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +void ael_yypop_buffer_state (yyscan_t yyscanner ); + +static void ael_yyensure_buffer_stack (yyscan_t yyscanner ); +static void ael_yy_load_buffer_state (yyscan_t yyscanner ); +static void ael_yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner ); + +#define YY_FLUSH_BUFFER ael_yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner) + +YY_BUFFER_STATE ael_yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); +YY_BUFFER_STATE ael_yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); +YY_BUFFER_STATE ael_yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); + +void *ael_yyalloc (yy_size_t ,yyscan_t yyscanner ); +void *ael_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner ); +void ael_yyfree (void * ,yyscan_t yyscanner ); + +#define yy_new_buffer ael_yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + ael_yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + ael_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + ael_yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + ael_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define ael_yywrap(n) 1 +#define YY_SKIP_YYWRAP + +typedef unsigned char YY_CHAR; + +typedef int yy_state_type; + +#define yytext_ptr yytext_r + +static yy_state_type yy_get_previous_state (yyscan_t yyscanner ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner); +static int yy_get_next_buffer (yyscan_t yyscanner ); +static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ + yyg->yytext_ptr -= yyg->yy_more_len; \ + yyleng = (size_t) (yy_cp - yyg->yytext_ptr); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yyg->yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 63 +#define YY_END_OF_BUFFER 64 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[244] = + { 0, + 0, 0, 0, 0, 0, 0, 0, 0, 43, 43, + 64, 63, 50, 48, 49, 51, 51, 9, 3, 4, + 7, 51, 8, 5, 6, 12, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 1, 10, 2, 63, 53, 52, 63, 54, + 63, 59, 60, 61, 63, 63, 55, 56, 57, 63, + 58, 43, 44, 45, 50, 49, 51, 51, 42, 13, + 11, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 22, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 0, 53, 52, 0, 54, 53, + + 52, 54, 0, 59, 60, 61, 0, 59, 60, 61, + 0, 55, 56, 57, 0, 58, 55, 56, 57, 58, + 43, 44, 45, 46, 45, 47, 51, 13, 13, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 33, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 35, 51, 51, + 51, 27, 51, 51, 51, 28, 26, 51, 51, 51, + 29, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 31, 38, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 19, 17, 51, 51, 51, 51, 51, 34, + + 51, 51, 51, 51, 51, 51, 16, 51, 23, 51, + 51, 51, 24, 51, 30, 21, 51, 51, 14, 51, + 36, 51, 18, 51, 51, 37, 51, 51, 51, 15, + 32, 51, 51, 41, 25, 39, 0, 40, 20, 0, + 0, 62, 0 + } ; + +static yyconst flex_int32_t yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 4, 5, 6, 7, 5, 1, 8, 5, 9, + 10, 11, 5, 12, 5, 5, 13, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 14, 15, 5, + 16, 17, 1, 18, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 19, 5, 5, 5, 5, 5, 5, + 20, 21, 22, 1, 5, 1, 23, 24, 25, 26, + + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 5, 39, 40, 41, 42, 5, 43, 44, + 5, 5, 45, 46, 47, 1, 1, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48 + } ; + +static yyconst flex_int32_t yy_meta[49] = + { 0, + 1, 1, 2, 1, 3, 4, 3, 1, 1, 1, + 5, 1, 3, 1, 1, 1, 3, 1, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 1, 3, 3 + } ; + +static yyconst flex_int16_t yy_base[257] = + { 0, + 0, 0, 40, 43, 82, 121, 160, 199, 48, 55, + 320, 986, 317, 986, 314, 0, 286, 986, 986, 986, + 986, 43, 986, 986, 299, 986, 291, 275, 32, 286, + 33, 275, 34, 280, 46, 268, 272, 285, 284, 49, + 263, 275, 986, 986, 986, 74, 986, 986, 90, 986, + 238, 986, 986, 986, 277, 316, 986, 986, 986, 355, + 986, 301, 986, 67, 301, 298, 0, 265, 0, 402, + 986, 260, 269, 65, 259, 266, 253, 248, 249, 250, + 251, 243, 246, 262, 244, 254, 243, 252, 251, 234, + 238, 52, 242, 241, 104, 986, 986, 138, 986, 143, + + 177, 182, 440, 986, 986, 986, 479, 518, 557, 596, + 635, 986, 986, 986, 674, 986, 713, 752, 791, 830, + 268, 986, 104, 986, 105, 986, 245, 0, 877, 228, + 245, 240, 241, 224, 241, 236, 231, 234, 0, 233, + 219, 214, 223, 215, 217, 212, 226, 206, 202, 216, + 214, 198, 198, 204, 203, 197, 202, 0, 204, 101, + 191, 0, 191, 195, 207, 0, 0, 193, 187, 183, + 0, 189, 181, 190, 179, 171, 175, 188, 185, 168, + 183, 0, 0, 157, 164, 162, 170, 168, 159, 162, + 157, 153, 0, 0, 139, 142, 135, 138, 137, 0, + + 136, 136, 116, 114, 114, 124, 0, 110, 0, 108, + 118, 108, 0, 113, 0, 112, 111, 93, 0, 106, + 0, 96, 0, 86, 61, 0, 62, 49, 118, 0, + 0, 46, 38, 0, 0, 0, 169, 0, 0, 0, + 51, 986, 986, 923, 928, 933, 938, 941, 946, 951, + 956, 961, 965, 970, 975, 980 + } ; + +static yyconst flex_int16_t yy_def[257] = + { 0, + 243, 1, 244, 244, 245, 245, 246, 246, 247, 247, + 243, 243, 243, 243, 243, 248, 248, 243, 243, 243, + 243, 248, 243, 243, 243, 243, 248, 248, 248, 248, + 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, + 248, 248, 243, 243, 243, 249, 243, 243, 249, 243, + 250, 243, 243, 243, 250, 251, 243, 243, 243, 251, + 243, 252, 243, 253, 243, 243, 248, 248, 248, 254, + 243, 248, 248, 248, 248, 248, 248, 248, 248, 248, + 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, + 248, 248, 248, 248, 249, 243, 243, 249, 243, 249, + + 249, 249, 250, 243, 243, 243, 250, 250, 250, 250, + 251, 243, 243, 243, 251, 243, 251, 251, 251, 251, + 252, 243, 253, 243, 253, 243, 248, 255, 254, 248, + 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, + 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, + 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, + 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, + 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, + 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, + 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, + + 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, + 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, + 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, + 248, 248, 248, 248, 248, 248, 243, 248, 248, 256, + 256, 243, 0, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243 + } ; + +static yyconst flex_int16_t yy_nxt[1035] = + { 0, + 12, 13, 14, 15, 16, 16, 17, 18, 19, 20, + 16, 21, 22, 23, 24, 25, 16, 26, 16, 16, + 16, 16, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 16, 37, 38, 16, 16, 39, 40, 41, + 16, 16, 42, 16, 43, 44, 45, 16, 47, 48, + 63, 47, 48, 69, 74, 70, 242, 63, 64, 47, + 49, 50, 47, 49, 50, 64, 77, 81, 75, 124, + 82, 91, 78, 84, 85, 92, 79, 125, 239, 126, + 151, 86, 96, 97, 47, 238, 50, 47, 236, 50, + 52, 53, 152, 96, 98, 99, 54, 235, 100, 101, + + 234, 52, 55, 53, 132, 133, 124, 124, 233, 100, + 98, 102, 96, 97, 243, 125, 243, 243, 96, 237, + 99, 237, 232, 96, 98, 99, 52, 184, 53, 52, + 53, 185, 231, 230, 100, 54, 102, 229, 228, 227, + 52, 55, 53, 226, 225, 224, 100, 101, 96, 223, + 99, 96, 97, 222, 221, 220, 219, 100, 98, 102, + 218, 217, 96, 98, 99, 52, 216, 53, 57, 58, + 237, 59, 237, 215, 240, 214, 213, 212, 211, 57, + 60, 61, 100, 210, 102, 96, 97, 96, 209, 99, + 96, 97, 208, 207, 206, 205, 96, 98, 99, 204, + + 203, 96, 98, 99, 57, 202, 61, 57, 58, 201, + 59, 200, 199, 198, 197, 196, 195, 194, 57, 60, + 61, 96, 193, 99, 192, 191, 96, 190, 99, 189, + 188, 187, 186, 183, 182, 181, 180, 179, 178, 177, + 176, 175, 174, 57, 173, 61, 104, 105, 172, 171, + 170, 169, 106, 168, 167, 166, 165, 104, 107, 105, + 164, 163, 162, 161, 160, 159, 158, 157, 156, 155, + 122, 154, 153, 150, 149, 148, 147, 146, 145, 144, + 143, 142, 104, 141, 105, 108, 109, 140, 139, 138, + 137, 110, 136, 135, 134, 131, 108, 107, 109, 130, + + 127, 66, 65, 122, 94, 93, 90, 89, 88, 87, + 83, 80, 76, 73, 72, 71, 68, 66, 65, 243, + 243, 108, 243, 109, 112, 113, 243, 114, 243, 243, + 243, 243, 243, 243, 243, 112, 115, 116, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 112, 243, 116, 117, 118, 243, 119, 243, 243, 243, + 243, 243, 243, 243, 117, 115, 120, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 117, + + 243, 120, 128, 128, 243, 128, 243, 243, 243, 128, + 128, 128, 243, 128, 243, 128, 128, 128, 243, 128, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 128, 104, 105, + 243, 243, 243, 243, 106, 243, 243, 243, 243, 104, + 107, 105, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 104, 243, 105, 108, 109, 243, + 243, 243, 243, 110, 243, 243, 243, 243, 108, 107, + + 109, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 108, 243, 109, 104, 105, 243, 243, + 243, 243, 106, 243, 243, 243, 243, 104, 107, 105, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 104, 243, 105, 104, 105, 243, 243, 243, + 243, 106, 243, 243, 243, 243, 104, 107, 105, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + + 243, 104, 243, 105, 104, 105, 243, 243, 243, 243, + 106, 243, 243, 243, 243, 104, 107, 105, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 104, 243, 105, 112, 113, 243, 114, 243, 243, 243, + 243, 243, 243, 243, 112, 115, 116, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 112, + 243, 116, 117, 118, 243, 119, 243, 243, 243, 243, + 243, 243, 243, 117, 115, 120, 243, 243, 243, 243, + + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 117, 243, + 120, 112, 113, 243, 114, 243, 243, 243, 243, 243, + 243, 243, 112, 115, 116, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 112, 243, 116, + 112, 113, 243, 114, 243, 243, 243, 243, 243, 243, + 243, 112, 115, 116, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 112, 243, 116, 112, + + 113, 243, 114, 243, 243, 243, 243, 243, 243, 243, + 112, 115, 116, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 112, 243, 116, 112, 113, + 243, 114, 243, 243, 243, 243, 243, 243, 243, 112, + 115, 116, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 112, 243, 116, 128, 128, 243, + 128, 243, 243, 243, 128, 128, 128, 243, 128, 243, + 128, 128, 128, 243, 128, 243, 243, 243, 243, 243, + + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 128, 46, 46, 46, 46, 46, 51, 51, + 51, 51, 51, 56, 56, 56, 56, 56, 62, 62, + 62, 62, 62, 67, 67, 67, 95, 95, 95, 95, + 95, 103, 103, 103, 103, 103, 111, 111, 111, 111, + 111, 121, 121, 121, 121, 123, 123, 123, 123, 123, + 129, 243, 129, 129, 129, 128, 243, 128, 128, 128, + 241, 241, 241, 243, 241, 11, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243 + } ; + +static yyconst flex_int16_t yy_chk[1035] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, + 9, 4, 4, 22, 29, 22, 241, 10, 9, 3, + 3, 3, 4, 4, 4, 10, 31, 33, 29, 64, + 33, 40, 31, 35, 35, 40, 31, 64, 233, 64, + 92, 35, 46, 46, 3, 232, 3, 4, 228, 4, + 5, 5, 92, 46, 46, 46, 5, 227, 49, 49, + + 225, 5, 5, 5, 74, 74, 123, 125, 224, 49, + 49, 49, 95, 95, 123, 125, 123, 125, 46, 229, + 46, 229, 222, 95, 95, 95, 5, 160, 5, 6, + 6, 160, 220, 218, 49, 6, 49, 217, 216, 214, + 6, 6, 6, 212, 211, 210, 98, 98, 95, 208, + 95, 100, 100, 206, 205, 204, 203, 98, 98, 98, + 202, 201, 100, 100, 100, 6, 199, 6, 7, 7, + 237, 7, 237, 198, 237, 197, 196, 195, 192, 7, + 7, 7, 98, 191, 98, 101, 101, 100, 190, 100, + 102, 102, 189, 188, 187, 186, 101, 101, 101, 185, + + 184, 102, 102, 102, 7, 181, 7, 8, 8, 180, + 8, 179, 178, 177, 176, 175, 174, 173, 8, 8, + 8, 101, 172, 101, 170, 169, 102, 168, 102, 165, + 164, 163, 161, 159, 157, 156, 155, 154, 153, 152, + 151, 150, 149, 8, 148, 8, 51, 51, 147, 146, + 145, 144, 51, 143, 142, 141, 140, 51, 51, 51, + 138, 137, 136, 135, 134, 133, 132, 131, 130, 127, + 121, 94, 93, 91, 90, 89, 88, 87, 86, 85, + 84, 83, 51, 82, 51, 55, 55, 81, 80, 79, + 78, 55, 77, 76, 75, 73, 55, 55, 55, 72, + + 68, 66, 65, 62, 42, 41, 39, 38, 37, 36, + 34, 32, 30, 28, 27, 25, 17, 15, 13, 11, + 0, 55, 0, 55, 56, 56, 0, 56, 0, 0, + 0, 0, 0, 0, 0, 56, 56, 56, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 56, 0, 56, 60, 60, 0, 60, 0, 0, 0, + 0, 0, 0, 0, 60, 60, 60, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, + + 0, 60, 70, 70, 0, 70, 0, 0, 0, 70, + 70, 70, 0, 70, 0, 70, 70, 70, 0, 70, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 70, 103, 103, + 0, 0, 0, 0, 103, 0, 0, 0, 0, 103, + 103, 103, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 103, 0, 103, 107, 107, 0, + 0, 0, 0, 107, 0, 0, 0, 0, 107, 107, + + 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 107, 0, 107, 108, 108, 0, 0, + 0, 0, 108, 0, 0, 0, 0, 108, 108, 108, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 108, 0, 108, 109, 109, 0, 0, 0, + 0, 109, 0, 0, 0, 0, 109, 109, 109, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 109, 0, 109, 110, 110, 0, 0, 0, 0, + 110, 0, 0, 0, 0, 110, 110, 110, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 110, 0, 110, 111, 111, 0, 111, 0, 0, 0, + 0, 0, 0, 0, 111, 111, 111, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 111, + 0, 111, 115, 115, 0, 115, 0, 0, 0, 0, + 0, 0, 0, 115, 115, 115, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 115, 0, + 115, 117, 117, 0, 117, 0, 0, 0, 0, 0, + 0, 0, 117, 117, 117, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 117, 0, 117, + 118, 118, 0, 118, 0, 0, 0, 0, 0, 0, + 0, 118, 118, 118, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 118, 0, 118, 119, + + 119, 0, 119, 0, 0, 0, 0, 0, 0, 0, + 119, 119, 119, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 119, 0, 119, 120, 120, + 0, 120, 0, 0, 0, 0, 0, 0, 0, 120, + 120, 120, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 120, 0, 120, 129, 129, 0, + 129, 0, 0, 0, 129, 129, 129, 0, 129, 0, + 129, 129, 129, 0, 129, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 129, 244, 244, 244, 244, 244, 245, 245, + 245, 245, 245, 246, 246, 246, 246, 246, 247, 247, + 247, 247, 247, 248, 248, 248, 249, 249, 249, 249, + 249, 250, 250, 250, 250, 250, 251, 251, 251, 251, + 251, 252, 252, 252, 252, 253, 253, 253, 253, 253, + 254, 0, 254, 254, 254, 255, 0, 255, 255, 255, + 256, 256, 256, 0, 256, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243 + } ; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() (yyg->yy_more_flag = 1) +#define YY_MORE_ADJ yyg->yy_more_len +#define YY_RESTORE_YY_MORE_OFFSET +#line 1 "ael.flex" +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2006, Digium, Inc. + * + * Steve Murphy <murf@parsetree.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ +/*! \file + * + * \brief Flex scanner description of tokens used in AEL2 . + * + */ +/* + * Start with flex options: + * + * %x describes the contexts we have: paren, semic and argg, plus INITIAL + */ + +/* prefix used for various globally-visible functions and variables. + * This renames also ael_yywrap, but since we do not use it, we just + * add option noyywrap to remove it. + */ +/* ael_yyfree normally just frees its arg. It can be null sometimes, + which some systems will complain about, so, we'll define our own version */ +/* batch gives a bit more performance if we are using it in + * a non-interactive mode. We probably don't care much. + */ +/* outfile is the filename to be used instead of lex.yy.c */ +/* + * These are not supported in flex 2.5.4, but we need them + * at the moment: + * reentrant produces a thread-safe parser. Not 100% sure that + * we require it, though. + * bison-bridge passes an additional yylval argument to ael_yylex(). + * bison-locations is probably not needed. + */ +#line 63 "ael.flex" +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +#if defined(__Darwin__) || defined(__CYGWIN__) +#define GLOB_ABORTED GLOB_ABEND +#endif +# include <glob.h> + +#include "asterisk/logger.h" +#include "asterisk/utils.h" +#include "ael/ael.tab.h" +#include "asterisk/ael_structs.h" + +/* + * A stack to keep track of matching brackets ( [ { } ] ) + */ +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; + +/* + * current line, column and filename, updated as we read the input. + */ +static int my_lineno = 1; /* current line in the source */ +static int my_col = 1; /* current column in the source */ +char *my_file = 0; /* used also in the bison code */ +char *prev_word; /* XXX document it */ + +#define MAX_INCLUDE_DEPTH 50 + +/* + * flex is not too smart, and generates global functions + * without prototypes so the compiler may complain. + * To avoid that, we declare the prototypes here, + * even though these functions are not used. + */ +int ael_yyget_column (yyscan_t yyscanner); +void ael_yyset_column (int column_no , yyscan_t yyscanner); + +int ael_yyparse (struct parse_io *); + +/* + * A stack to process include files. + * As we switch into the new file we need to store the previous + * state to restore it later. + */ +struct stackelement { + char *fname; + int lineno; + int colno; + glob_t globbuf; /* the current globbuf */ + int globbuf_pos; /* where we are in the current globbuf */ + YY_BUFFER_STATE bufstate; +}; + +static struct stackelement include_stack[MAX_INCLUDE_DEPTH]; +static int include_stack_index = 0; +static void setup_filestack(char *fnamebuf, int fnamebuf_siz, glob_t *globbuf, int globpos, yyscan_t xscan, int create); + +/* + * if we use the @n feature of bison, we must supply the start/end + * location of tokens in the structure pointed by yylloc. + * Simple tokens are just assumed to be on the same line, so + * the line number is constant, and the column is incremented + * by the length of the token. + */ +#ifdef FLEX_BETA /* set for 2.5.33 */ + +/* compute the total number of lines and columns in the text + * passed as argument. + */ +static void pbcwhere(const char *text, int *line, int *col ) +{ + int loc_line = *line; + int loc_col = *col; + char c; + while ( (c = *text++) ) { + if ( c == '\t' ) { + loc_col += 8 - (loc_col % 8); + } else if ( c == '\n' ) { + loc_line++; + loc_col = 1; + } else + loc_col++; + } + *line = loc_line; + *col = loc_col; +} + +#define STORE_POS do { \ + yylloc->first_line = yylloc->last_line = my_lineno; \ + yylloc->first_column=my_col; \ + yylloc->last_column=my_col+yyleng-1; \ + my_col+=yyleng; \ + } while (0) + +#define STORE_LOC do { \ + yylloc->first_line = my_lineno; \ + yylloc->first_column=my_col; \ + pbcwhere(yytext, &my_lineno, &my_col); \ + yylloc->last_line = my_lineno; \ + yylloc->last_column = my_col - 1; \ + } while (0) +#else +#define STORE_POS +#define STORE_LOC +#endif +#line 909 "ael_lex.c" + +#define INITIAL 0 +#define paren 1 +#define semic 2 +#define argg 3 +#define comment 4 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include <unistd.h> +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +/* Holds the entire state of the reentrant scanner. */ +struct yyguts_t + { + + /* User-defined. Not touched by flex. */ + YY_EXTRA_TYPE yyextra_r; + + /* The rest are the same as the globals declared in the non-reentrant scanner. */ + FILE *yyin_r, *yyout_r; + size_t yy_buffer_stack_top; /**< index of top of stack. */ + size_t yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ + char yy_hold_char; + int yy_n_chars; + int yyleng_r; + char *yy_c_buf_p; + int yy_init; + int yy_start; + int yy_did_buffer_switch_on_eof; + int yy_start_stack_ptr; + int yy_start_stack_depth; + int *yy_start_stack; + yy_state_type yy_last_accepting_state; + char* yy_last_accepting_cpos; + + int yylineno_r; + int yy_flex_debug_r; + + char *yytext_r; + int yy_more_flag; + int yy_more_len; + + YYSTYPE * yylval_r; + + YYLTYPE * yylloc_r; + + }; /* end struct yyguts_t */ + +static int yy_init_globals (yyscan_t yyscanner ); + + /* This must go here because YYSTYPE and YYLTYPE are included + * from bison output in section 1.*/ + # define yylval yyg->yylval_r + + # define yylloc yyg->yylloc_r + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int ael_yylex_destroy (yyscan_t yyscanner ); + +int ael_yyget_debug (yyscan_t yyscanner ); + +void ael_yyset_debug (int debug_flag ,yyscan_t yyscanner ); + +YY_EXTRA_TYPE ael_yyget_extra (yyscan_t yyscanner ); + +void ael_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); + +FILE *ael_yyget_in (yyscan_t yyscanner ); + +void ael_yyset_in (FILE * in_str ,yyscan_t yyscanner ); + +FILE *ael_yyget_out (yyscan_t yyscanner ); + +void ael_yyset_out (FILE * out_str ,yyscan_t yyscanner ); + +int ael_yyget_leng (yyscan_t yyscanner ); + +char *ael_yyget_text (yyscan_t yyscanner ); + +int ael_yyget_lineno (yyscan_t yyscanner ); + +void ael_yyset_lineno (int line_number ,yyscan_t yyscanner ); + +YYSTYPE * ael_yyget_lval (yyscan_t yyscanner ); + +void ael_yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner ); + + YYLTYPE *ael_yyget_lloc (yyscan_t yyscanner ); + + void ael_yyset_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int ael_yywrap (yyscan_t yyscanner ); +#else +extern int ael_yywrap (yyscan_t yyscanner ); +#endif +#endif + + static void yyunput (int c,char *buf_ptr ,yyscan_t yyscanner); + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (yyscan_t yyscanner ); +#else +static int input (yyscan_t yyscanner ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + size_t n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int ael_yylex (YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner); + +#define YY_DECL int ael_yylex (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + +#line 187 "ael.flex" + + +#line 1151 "ael_lex.c" + + yylval = yylval_param; + + yylloc = yylloc_param; + + if ( !yyg->yy_init ) + { + yyg->yy_init = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yyg->yy_start ) + yyg->yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + ael_yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + ael_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + ael_yy_load_buffer_state(yyscanner ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yyg->yy_more_len = 0; + if ( yyg->yy_more_flag ) + { + yyg->yy_more_len = yyg->yy_c_buf_p - yyg->yytext_ptr; + yyg->yy_more_flag = 0; + } + yy_cp = yyg->yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yyg->yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yyg->yy_start; +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 244 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_current_state != 243 ); + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yyg->yy_hold_char; + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 189 "ael.flex" +{ STORE_POS; return LC;} + YY_BREAK +case 2: +YY_RULE_SETUP +#line 190 "ael.flex" +{ STORE_POS; return RC;} + YY_BREAK +case 3: +YY_RULE_SETUP +#line 191 "ael.flex" +{ STORE_POS; return LP;} + YY_BREAK +case 4: +YY_RULE_SETUP +#line 192 "ael.flex" +{ STORE_POS; return RP;} + YY_BREAK +case 5: +YY_RULE_SETUP +#line 193 "ael.flex" +{ STORE_POS; return SEMI;} + YY_BREAK +case 6: +YY_RULE_SETUP +#line 194 "ael.flex" +{ STORE_POS; return EQ;} + YY_BREAK +case 7: +YY_RULE_SETUP +#line 195 "ael.flex" +{ STORE_POS; return COMMA;} + YY_BREAK +case 8: +YY_RULE_SETUP +#line 196 "ael.flex" +{ STORE_POS; return COLON;} + YY_BREAK +case 9: +YY_RULE_SETUP +#line 197 "ael.flex" +{ STORE_POS; return AMPER;} + YY_BREAK +case 10: +YY_RULE_SETUP +#line 198 "ael.flex" +{ STORE_POS; return BAR;} + YY_BREAK +case 11: +YY_RULE_SETUP +#line 199 "ael.flex" +{ STORE_POS; return EXTENMARK;} + YY_BREAK +case 12: +YY_RULE_SETUP +#line 200 "ael.flex" +{ STORE_POS; return AT;} + YY_BREAK +case 13: +YY_RULE_SETUP +#line 201 "ael.flex" +{/*comment*/} + YY_BREAK +case 14: +YY_RULE_SETUP +#line 202 "ael.flex" +{ STORE_POS; return KW_CONTEXT;} + YY_BREAK +case 15: +YY_RULE_SETUP +#line 203 "ael.flex" +{ STORE_POS; return KW_ABSTRACT;} + YY_BREAK +case 16: +YY_RULE_SETUP +#line 204 "ael.flex" +{ STORE_POS; return KW_EXTEND;} + YY_BREAK +case 17: +YY_RULE_SETUP +#line 205 "ael.flex" +{ STORE_POS; return KW_MACRO;}; + YY_BREAK +case 18: +YY_RULE_SETUP +#line 206 "ael.flex" +{ STORE_POS; return KW_GLOBALS;} + YY_BREAK +case 19: +YY_RULE_SETUP +#line 207 "ael.flex" +{ STORE_POS; return KW_LOCAL;} + YY_BREAK +case 20: +YY_RULE_SETUP +#line 208 "ael.flex" +{ STORE_POS; return KW_IGNOREPAT;} + YY_BREAK +case 21: +YY_RULE_SETUP +#line 209 "ael.flex" +{ STORE_POS; return KW_SWITCH;} + YY_BREAK +case 22: +YY_RULE_SETUP +#line 210 "ael.flex" +{ STORE_POS; return KW_IF;} + YY_BREAK +case 23: +YY_RULE_SETUP +#line 211 "ael.flex" +{ STORE_POS; return KW_IFTIME;} + YY_BREAK +case 24: +YY_RULE_SETUP +#line 212 "ael.flex" +{ STORE_POS; return KW_RANDOM;} + YY_BREAK +case 25: +YY_RULE_SETUP +#line 213 "ael.flex" +{ STORE_POS; return KW_REGEXTEN;} + YY_BREAK +case 26: +YY_RULE_SETUP +#line 214 "ael.flex" +{ STORE_POS; return KW_HINT;} + YY_BREAK +case 27: +YY_RULE_SETUP +#line 215 "ael.flex" +{ STORE_POS; return KW_ELSE;} + YY_BREAK +case 28: +YY_RULE_SETUP +#line 216 "ael.flex" +{ STORE_POS; return KW_GOTO;} + YY_BREAK +case 29: +YY_RULE_SETUP +#line 217 "ael.flex" +{ STORE_POS; return KW_JUMP;} + YY_BREAK +case 30: +YY_RULE_SETUP +#line 218 "ael.flex" +{ STORE_POS; return KW_RETURN;} + YY_BREAK +case 31: +YY_RULE_SETUP +#line 219 "ael.flex" +{ STORE_POS; return KW_BREAK;} + YY_BREAK +case 32: +YY_RULE_SETUP +#line 220 "ael.flex" +{ STORE_POS; return KW_CONTINUE;} + YY_BREAK +case 33: +YY_RULE_SETUP +#line 221 "ael.flex" +{ STORE_POS; return KW_FOR;} + YY_BREAK +case 34: +YY_RULE_SETUP +#line 222 "ael.flex" +{ STORE_POS; return KW_WHILE;} + YY_BREAK +case 35: +YY_RULE_SETUP +#line 223 "ael.flex" +{ STORE_POS; return KW_CASE;} + YY_BREAK +case 36: +YY_RULE_SETUP +#line 224 "ael.flex" +{ STORE_POS; return KW_DEFAULT;} + YY_BREAK +case 37: +YY_RULE_SETUP +#line 225 "ael.flex" +{ STORE_POS; return KW_PATTERN;} + YY_BREAK +case 38: +YY_RULE_SETUP +#line 226 "ael.flex" +{ STORE_POS; return KW_CATCH;} + YY_BREAK +case 39: +YY_RULE_SETUP +#line 227 "ael.flex" +{ STORE_POS; return KW_SWITCHES;} + YY_BREAK +case 40: +YY_RULE_SETUP +#line 228 "ael.flex" +{ STORE_POS; return KW_ESWITCHES;} + YY_BREAK +case 41: +YY_RULE_SETUP +#line 229 "ael.flex" +{ STORE_POS; return KW_INCLUDES;} + YY_BREAK +case 42: +YY_RULE_SETUP +#line 230 "ael.flex" +{ BEGIN(comment); my_col += 2; } + YY_BREAK +case 43: +YY_RULE_SETUP +#line 232 "ael.flex" +{ my_col += yyleng; } + YY_BREAK +case 44: +/* rule 44 can match eol */ +YY_RULE_SETUP +#line 233 "ael.flex" +{ ++my_lineno; my_col=1;} + YY_BREAK +case 45: +YY_RULE_SETUP +#line 234 "ael.flex" +{ my_col += yyleng; } + YY_BREAK +case 46: +/* rule 46 can match eol */ +YY_RULE_SETUP +#line 235 "ael.flex" +{ ++my_lineno; my_col=1;} + YY_BREAK +case 47: +YY_RULE_SETUP +#line 236 "ael.flex" +{ my_col += 2; BEGIN(INITIAL); } + YY_BREAK +case 48: +/* rule 48 can match eol */ +YY_RULE_SETUP +#line 238 "ael.flex" +{ my_lineno++; my_col = 1; } + YY_BREAK +case 49: +YY_RULE_SETUP +#line 239 "ael.flex" +{ my_col += yyleng; } + YY_BREAK +case 50: +YY_RULE_SETUP +#line 240 "ael.flex" +{ my_col += (yyleng*8)-(my_col%8); } + YY_BREAK +case 51: +YY_RULE_SETUP +#line 242 "ael.flex" +{ + STORE_POS; + yylval->str = strdup(yytext); + prev_word = yylval->str; + return word; + } + YY_BREAK +/* + * context used for arguments of if_head, random_head, switch_head, + * for (last statement), while (XXX why not iftime_head ?). + * End with the matching parentheses. + * A comma at the top level is valid here, unlike in argg where it + * is an argument separator so it must be returned as a token. + */ +case 52: +/* rule 52 can match eol */ +YY_RULE_SETUP +#line 258 "ael.flex" +{ + if ( pbcpop(')') ) { /* 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); + prev_word = 0; + return word; + } + parencount--; + if ( parencount >= 0) { + yymore(); + } else { + STORE_LOC; + yylval->str = strdup(yytext); + yylval->str[yyleng-1] = '\0'; /* trim trailing ')' */ + unput(')'); + BEGIN(0); + return word; + } + } + YY_BREAK +case 53: +/* rule 53 can match eol */ +YY_RULE_SETUP +#line 280 "ael.flex" +{ + char c = yytext[yyleng-1]; + if (c == '(') + parencount++; + pbcpush(c); + yymore(); + } + YY_BREAK +case 54: +/* rule 54 can match eol */ +YY_RULE_SETUP +#line 288 "ael.flex" +{ + char c = yytext[yyleng-1]; + if ( pbcpop(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(); + } + YY_BREAK +/* + * handlers for arguments to a macro or application calls. + * We enter this context when we find the initial '(' and + * stay here until we close all matching parentheses, + * and find the comma (argument separator) or the closing ')' + * of the (external) call, which happens when parencount == 0 + * before the decrement. + */ +case 55: +/* rule 55 can match eol */ +YY_RULE_SETUP +#line 310 "ael.flex" +{ + char c = yytext[yyleng-1]; + if (c == '(') + parencount++; + pbcpush(c); + yymore(); + } + YY_BREAK +case 56: +/* rule 56 can match eol */ +YY_RULE_SETUP +#line 318 "ael.flex" +{ + if ( pbcpop(')') ) { /* error */ + STORE_LOC; + ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched ')' in expression!\n", my_file, my_lineno, my_col); + BEGIN(0); + yylval->str = strdup(yytext); + return word; + } + + parencount--; + if( parencount >= 0){ + yymore(); + } else { + STORE_LOC; + BEGIN(0); + if ( !strcmp(yytext, ")") ) + return RP; + yylval->str = strdup(yytext); + yylval->str[yyleng-1] = '\0'; /* trim trailing ')' */ + unput(')'); + return word; + } + } + YY_BREAK +case 57: +/* rule 57 can match eol */ +YY_RULE_SETUP +#line 342 "ael.flex" +{ + if( parencount != 0) { /* printf("Folding in a comma!\n"); */ + yymore(); + } else { + STORE_LOC; + if( !strcmp(yytext,"," ) ) + return COMMA; + yylval->str = strdup(yytext); + yylval->str[yyleng-1] = '\0'; + unput(','); + return word; + } + } + YY_BREAK +case 58: +/* rule 58 can match eol */ +YY_RULE_SETUP +#line 356 "ael.flex" +{ + char c = yytext[yyleng-1]; + if ( pbcpop(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(); + } + YY_BREAK +/* + * context used to find tokens in the right hand side of assignments, + * or in the first and second operand of a 'for'. As above, match + * commas and use ';' as a separator (hence return it as a separate token). + */ +case 59: +/* rule 59 can match eol */ +YY_RULE_SETUP +#line 373 "ael.flex" +{ + char c = yytext[yyleng-1]; + yymore(); + pbcpush(c); + } + YY_BREAK +case 60: +/* rule 60 can match eol */ +YY_RULE_SETUP +#line 379 "ael.flex" +{ + char c = yytext[yyleng-1]; + if ( pbcpop(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(); + } + YY_BREAK +case 61: +/* rule 61 can match eol */ +YY_RULE_SETUP +#line 391 "ael.flex" +{ + STORE_LOC; + yylval->str = strdup(yytext); + yylval->str[yyleng-1] = '\0'; + unput(';'); + BEGIN(0); + return word; + } + YY_BREAK +case 62: +/* rule 62 can match eol */ +YY_RULE_SETUP +#line 400 "ael.flex" +{ + char fnamebuf[1024],*p1,*p2; + int glob_ret; + glob_t globbuf; /* the current globbuf */ + int globbuf_pos = -1; /* where we are in the current globbuf */ + globbuf.gl_offs = 0; /* initialize it to silence gcc */ + + p1 = strchr(yytext,'"'); + p2 = strrchr(yytext,'"'); + if ( include_stack_index >= MAX_INCLUDE_DEPTH ) { + ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Includes nested too deeply! Wow!!! How did you do that?\n", my_file, my_lineno, my_col); + } else if ( (int)(p2-p1) > sizeof(fnamebuf) - 1 ) { + ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Filename is incredibly way too long (%d chars!). Inclusion ignored!\n", my_file, my_lineno, my_col, yyleng - 10); + } else { + strncpy(fnamebuf, p1+1, p2-p1-1); + fnamebuf[p2-p1-1] = 0; + if (fnamebuf[0] != '/') { + char fnamebuf2[1024]; + snprintf(fnamebuf2,sizeof(fnamebuf2), "%s/%s", (char *)ast_config_AST_CONFIG_DIR, fnamebuf); + ast_copy_string(fnamebuf,fnamebuf2,sizeof(fnamebuf)); + } +#ifdef SOLARIS + glob_ret = glob(fnamebuf, GLOB_NOCHECK, NULL, &globbuf); +#else + glob_ret = glob(fnamebuf, GLOB_NOMAGIC|GLOB_BRACE, NULL, &globbuf); +#endif + if (glob_ret == GLOB_NOSPACE) { + ast_log(LOG_WARNING, + "Glob Expansion of pattern '%s' failed: Not enough memory\n", fnamebuf); + } else if (glob_ret == GLOB_ABORTED) { + ast_log(LOG_WARNING, + "Glob Expansion of pattern '%s' failed: Read error\n", fnamebuf); + } else if (glob_ret == GLOB_NOMATCH) { + ast_log(LOG_WARNING, + "Glob Expansion of pattern '%s' failed: No matches!\n", fnamebuf); + } else { + globbuf_pos = 0; + } + } + if (globbuf_pos > -1) { + setup_filestack(fnamebuf, sizeof(fnamebuf), &globbuf, 0, yyscanner, 1); + } + } + YY_BREAK +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(paren): +case YY_STATE_EOF(semic): +case YY_STATE_EOF(argg): +case YY_STATE_EOF(comment): +#line 445 "ael.flex" +{ + char fnamebuf[2048]; + if (include_stack_index > 0 && include_stack[include_stack_index-1].globbuf_pos < include_stack[include_stack_index-1].globbuf.gl_pathc-1) { + free(my_file); + my_file = 0; + ael_yy_delete_buffer(YY_CURRENT_BUFFER,yyscanner ); + include_stack[include_stack_index-1].globbuf_pos++; + setup_filestack(fnamebuf, sizeof(fnamebuf), &include_stack[include_stack_index-1].globbuf, include_stack[include_stack_index-1].globbuf_pos, yyscanner, 0); + /* finish this */ + + } else { + if (include_stack[include_stack_index].fname) { + free(include_stack[include_stack_index].fname); + include_stack[include_stack_index].fname = 0; + } + if ( --include_stack_index < 0 ) { + yyterminate(); + } else { + if (my_file) { + free(my_file); + my_file = 0; + } + globfree(&include_stack[include_stack_index].globbuf); + include_stack[include_stack_index].globbuf_pos = -1; + + ael_yy_delete_buffer(YY_CURRENT_BUFFER,yyscanner ); + ael_yy_switch_to_buffer(include_stack[include_stack_index].bufstate,yyscanner ); + my_lineno = include_stack[include_stack_index].lineno; + my_col = include_stack[include_stack_index].colno; + my_file = strdup(include_stack[include_stack_index].fname); + } + } + } + YY_BREAK +case 63: +YY_RULE_SETUP +#line 479 "ael.flex" +ECHO; + YY_BREAK +#line 1784 "ael_lex.c" + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yyg->yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * ael_yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); + + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yyg->yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_END_OF_FILE: + { + yyg->yy_did_buffer_switch_on_eof = 0; + + if ( ael_yywrap(yyscanner ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = + yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ +} /* end of ael_yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = yyg->yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER; + + int yy_c_buf_p_offset = + (int) (yyg->yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + ael_yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + yyg->yy_n_chars, num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + if ( yyg->yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + ael_yyrestart(yyin ,yyscanner); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + yyg->yy_n_chars += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (yyscan_t yyscanner) +{ + register yy_state_type yy_current_state; + register char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_current_state = yyg->yy_start; + + for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 244 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) +{ + register int yy_is_jam; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ + register char *yy_cp = yyg->yy_c_buf_p; + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 244 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 243); + + return yy_is_jam ? 0 : yy_current_state; +} + + static void yyunput (int c, register char * yy_bp , yyscan_t yyscanner) +{ + register char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_cp = yyg->yy_c_buf_p; + + /* undo effects of setting up yytext */ + *yy_cp = yyg->yy_hold_char; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = yyg->yy_n_chars + 2; + register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; + register char *source = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; + + while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + yyg->yytext_ptr = yy_bp; + yyg->yy_hold_char = *yy_cp; + yyg->yy_c_buf_p = yy_cp; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (yyscan_t yyscanner) +#else + static int input (yyscan_t yyscanner) +#endif + +{ + int c; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + *yyg->yy_c_buf_p = yyg->yy_hold_char; + + if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + /* This was really a NUL. */ + *yyg->yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = yyg->yy_c_buf_p - yyg->yytext_ptr; + ++yyg->yy_c_buf_p; + + switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + ael_yyrestart(yyin ,yyscanner); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( ael_yywrap(yyscanner ) ) + return EOF; + + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(yyscanner); +#else + return input(yyscanner); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ + *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ + yyg->yy_hold_char = *++yyg->yy_c_buf_p; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * @param yyscanner The scanner object. + * @note This function does not reset the start condition to @c INITIAL . + */ + void ael_yyrestart (FILE * input_file , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! YY_CURRENT_BUFFER ){ + ael_yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + ael_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + ael_yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner); + ael_yy_load_buffer_state(yyscanner ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * @param yyscanner The scanner object. + */ + void ael_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* TODO. We should be able to replace this entire function body + * with + * ael_yypop_buffer_state(); + * ael_yypush_buffer_state(new_buffer); + */ + ael_yyensure_buffer_stack (yyscanner); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + ael_yy_load_buffer_state(yyscanner ); + + /* We don't actually know whether we did this switch during + * EOF (ael_yywrap()) processing, but the only time this flag + * is looked at is after ael_yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yyg->yy_did_buffer_switch_on_eof = 1; +} + +static void ael_yy_load_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + yyg->yy_hold_char = *yyg->yy_c_buf_p; +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * @param yyscanner The scanner object. + * @return the allocated buffer state. + */ + YY_BUFFER_STATE ael_yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) ael_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in ael_yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) ael_yyalloc(b->yy_buf_size + 2 ,yyscanner ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in ael_yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + ael_yy_init_buffer(b,file ,yyscanner); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with ael_yy_create_buffer() + * @param yyscanner The scanner object. + */ + void ael_yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + ael_yyfree((void *) b->yy_ch_buf ,yyscanner ); + + ael_yyfree((void *) b ,yyscanner ); +} + +#ifndef __cplusplus +extern int isatty (int ); +#endif /* __cplusplus */ + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a ael_yyrestart() or at EOF. + */ + static void ael_yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) + +{ + int oerrno = errno; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + ael_yy_flush_buffer(b ,yyscanner); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then ael_yy_init_buffer was _probably_ + * called from ael_yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * @param yyscanner The scanner object. + */ + void ael_yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + ael_yy_load_buffer_state(yyscanner ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * @param yyscanner The scanner object. + */ +void ael_yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (new_buffer == NULL) + return; + + ael_yyensure_buffer_stack(yyscanner); + + /* This block is copied from ael_yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + yyg->yy_buffer_stack_top++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from ael_yy_switch_to_buffer. */ + ael_yy_load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * @param yyscanner The scanner object. + */ +void ael_yypop_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (!YY_CURRENT_BUFFER) + return; + + ael_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + if (yyg->yy_buffer_stack_top > 0) + --yyg->yy_buffer_stack_top; + + if (YY_CURRENT_BUFFER) { + ael_yy_load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void ael_yyensure_buffer_stack (yyscan_t yyscanner) +{ + int num_to_alloc; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (!yyg->yy_buffer_stack) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + yyg->yy_buffer_stack = (struct yy_buffer_state**)ael_yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + yyg->yy_buffer_stack_max = num_to_alloc; + yyg->yy_buffer_stack_top = 0; + return; + } + + if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = yyg->yy_buffer_stack_max + grow_size; + yyg->yy_buffer_stack = (struct yy_buffer_state**)ael_yyrealloc + (yyg->yy_buffer_stack, + num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + + /* zero only the new slots.*/ + memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); + yyg->yy_buffer_stack_max = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE ael_yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) ael_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in ael_yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + ael_yy_switch_to_buffer(b ,yyscanner ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to ael_yylex() will + * scan from a @e copy of @a str. + * @param str a NUL-terminated string to scan + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * ael_yy_scan_bytes() instead. + */ +YY_BUFFER_STATE ael_yy_scan_string (yyconst char * yystr , yyscan_t yyscanner) +{ + + return ael_yy_scan_bytes(yystr,strlen(yystr) ,yyscanner); +} + +/** Setup the input buffer state to scan the given bytes. The next call to ael_yylex() will + * scan from a @e copy of @a bytes. + * @param bytes the byte buffer to scan + * @param len the number of bytes in the buffer pointed to by @a bytes. + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE ael_yy_scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; + buf = (char *) ael_yyalloc(n ,yyscanner ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in ael_yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = ael_yy_scan_buffer(buf,n ,yyscanner); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in ael_yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = yyg->yy_hold_char; \ + yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ + yyg->yy_hold_char = *yyg->yy_c_buf_p; \ + *yyg->yy_c_buf_p = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the user-defined data for this scanner. + * @param yyscanner The scanner object. + */ +YY_EXTRA_TYPE ael_yyget_extra (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyextra; +} + +/** Get the current line number. + * @param yyscanner The scanner object. + */ +int ael_yyget_lineno (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yylineno; +} + +/** Get the current column number. + * @param yyscanner The scanner object. + */ +int ael_yyget_column (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yycolumn; +} + +/** Get the input stream. + * @param yyscanner The scanner object. + */ +FILE *ael_yyget_in (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyin; +} + +/** Get the output stream. + * @param yyscanner The scanner object. + */ +FILE *ael_yyget_out (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyout; +} + +/** Get the length of the current token. + * @param yyscanner The scanner object. + */ +int ael_yyget_leng (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyleng; +} + +/** Get the current token. + * @param yyscanner The scanner object. + */ + +char *ael_yyget_text (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yytext; +} + +/** Set the user-defined data. This data is never touched by the scanner. + * @param user_defined The data to be associated with this scanner. + * @param yyscanner The scanner object. + */ +void ael_yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyextra = user_defined ; +} + +/** Set the current line number. + * @param line_number + * @param yyscanner The scanner object. + */ +void ael_yyset_lineno (int line_number , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* lineno is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + yy_fatal_error( "ael_yyset_lineno called with no buffer" , yyscanner); + + yylineno = line_number; +} + +/** Set the current column. + * @param line_number + * @param yyscanner The scanner object. + */ +void ael_yyset_column (int column_no , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* column is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + yy_fatal_error( "ael_yyset_column called with no buffer" , yyscanner); + + yycolumn = column_no; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * @param yyscanner The scanner object. + * @see ael_yy_switch_to_buffer + */ +void ael_yyset_in (FILE * in_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyin = in_str ; +} + +void ael_yyset_out (FILE * out_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyout = out_str ; +} + +int ael_yyget_debug (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yy_flex_debug; +} + +void ael_yyset_debug (int bdebug , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yy_flex_debug = bdebug ; +} + +/* Accessor methods for yylval and yylloc */ + +YYSTYPE * ael_yyget_lval (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylval; +} + +void ael_yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylval = yylval_param; +} + +YYLTYPE *ael_yyget_lloc (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylloc; +} + +void ael_yyset_lloc (YYLTYPE * yylloc_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylloc = yylloc_param; +} + +/* User-visible API */ + +/* ael_yylex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ + +int ael_yylex_init(yyscan_t* ptr_yy_globals) + +{ + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) ael_yyalloc ( sizeof( struct yyguts_t ), NULL ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + return yy_init_globals ( *ptr_yy_globals ); +} + +static int yy_init_globals (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from ael_yylex_destroy(), so don't allocate here. + */ + + yyg->yy_buffer_stack = 0; + yyg->yy_buffer_stack_top = 0; + yyg->yy_buffer_stack_max = 0; + yyg->yy_c_buf_p = (char *) 0; + yyg->yy_init = 0; + yyg->yy_start = 0; + + yyg->yy_start_stack_ptr = 0; + yyg->yy_start_stack_depth = 0; + yyg->yy_start_stack = NULL; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = (FILE *) 0; + yyout = (FILE *) 0; +#endif + + /* For future reference: Set errno on error, since we are called by + * ael_yylex_init() + */ + return 0; +} + +/* ael_yylex_destroy is for both reentrant and non-reentrant scanners. */ +int ael_yylex_destroy (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + ael_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner ); + YY_CURRENT_BUFFER_LVALUE = NULL; + ael_yypop_buffer_state(yyscanner); + } + + /* Destroy the stack itself. */ + ael_yyfree(yyg->yy_buffer_stack ,yyscanner); + yyg->yy_buffer_stack = NULL; + + /* Destroy the start condition stack. */ + ael_yyfree(yyg->yy_start_stack ,yyscanner ); + yyg->yy_start_stack = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * ael_yylex() is called, initialization will occur. */ + yy_init_globals( yyscanner); + + /* Destroy the main struct (reentrant only). */ + ael_yyfree ( yyscanner , yyscanner ); + yyscanner = NULL; + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *ael_yyalloc (yy_size_t size , yyscan_t yyscanner) +{ + return (void *) malloc( size ); +} + +void *ael_yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) +{ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +#define YYTABLES_NAME "yytables" + +#line 479 "ael.flex" + + + +static void pbcpush(char x) +{ + pbcstack[pbcpos++] = x; +} + +void ael_yyfree(void *ptr, yyscan_t yyscanner) +{ + if (ptr) + free( (char*) ptr ); +} + +static int pbcpop(char x) +{ + if ( ( x == ')' && pbcstack[pbcpos-1] == '(' ) + || ( x == ']' && pbcstack[pbcpos-1] == '[' ) + || ( x == '}' && pbcstack[pbcpos-1] == '{' )) { + pbcpos--; + return 0; + } + return 1; /* error */ +} + +static int c_prevword(void) +{ + char *c = prev_word; + if (c == NULL) + return 0; + while ( *c ) { + switch (*c) { + case '{': + case '[': + case '(': + pbcpush(*c); + break; + case '}': + case ']': + case ')': + if (pbcpop(*c)) + return 1; + break; + } + c++; + } + return 0; +} + + +/* + * The following three functions, reset_*, are used in the bison + * code to switch context. As a consequence, we need to + * declare them global and add a prototype so that the + * compiler does not complain. + * + * NOTE: yyg is declared because it is used in the BEGIN macros, + * though that should be hidden as the macro changes + * depending on the flex options that we use - in particular, + * %reentrant changes the way the macro is declared; + * without %reentrant, BEGIN uses yystart instead of yyg + */ + +void reset_parencount(yyscan_t yyscanner ); +void reset_parencount(yyscan_t yyscanner ) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + parencount = 0; + pbcpos = 0; + pbcpush('('); /* push '(' so the last pcbpop (parencount= -1) will succeed */ + c_prevword(); + BEGIN(paren); +} + +void reset_semicount(yyscan_t yyscanner ); +void reset_semicount(yyscan_t yyscanner ) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + pbcpos = 0; + BEGIN(semic); +} + +void reset_argcount(yyscan_t yyscanner ); +void reset_argcount(yyscan_t yyscanner ) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + parencount = 0; + pbcpos = 0; + pbcpush('('); /* push '(' so the last pcbpop (parencount= -1) will succeed */ + c_prevword(); + BEGIN(argg); +} + +/* used elsewhere, but some local vars */ +struct pval *ael2_parse(char *filename, int *errors) +{ + struct pval *pval; + struct parse_io *io; + char *buffer; + struct stat stats; + FILE *fin; + + /* extern int ael_yydebug; */ + + io = calloc(sizeof(struct parse_io),1); + /* reset the global counters */ + prev_word = 0; + my_lineno = 1; + include_stack_index=0; + my_col = 0; + /* ael_yydebug = 1; */ + ael_yylex_init(&io->scanner); + fin = fopen(filename,"r"); + if ( !fin ) { + ast_log(LOG_ERROR,"File %s could not be opened\n", filename); + *errors = 1; + return 0; + } + if (my_file) + free(my_file); + my_file = strdup(filename); + stat(filename, &stats); + buffer = (char*)malloc(stats.st_size+2); + fread(buffer, 1, stats.st_size, fin); + buffer[stats.st_size]=0; + fclose(fin); + + ael_yy_scan_string (buffer ,io->scanner); + ael_yyset_lineno(1 , io->scanner); + + /* ael_yyset_in (fin , io->scanner); OLD WAY */ + + ael_yyparse(io); + + + pval = io->pval; + *errors = io->syntax_error_count; + + ael_yylex_destroy(io->scanner); + free(buffer); + free(io); + + return pval; +} + +static void setup_filestack(char *fnamebuf2, int fnamebuf_siz, glob_t *globbuf, int globpos, yyscan_t yyscanner, int create) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + int error, i; + FILE *in1; + char fnamebuf[2048]; + + if (globbuf && globbuf->gl_pathv && globbuf->gl_pathc > 0) +#if defined(STANDALONE) || defined(LOW_MEMORY) || defined(STANDALONE_AEL) + strncpy(fnamebuf, globbuf->gl_pathv[globpos], fnamebuf_siz); +#else + ast_copy_string(fnamebuf, globbuf->gl_pathv[globpos], fnamebuf_siz); +#endif + else { + ast_log(LOG_ERROR,"Include file name not present!\n"); + return; + } + for (i=0; i<include_stack_index; i++) { + if ( !strcmp(fnamebuf,include_stack[i].fname )) { + ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Nice Try!!! But %s has already been included (perhaps by another file), and would cause an infinite loop of file inclusions!!! Include directive ignored\n", + my_file, my_lineno, my_col, fnamebuf); + break; + } + } + error = 1; + if (i == include_stack_index) + error = 0; /* we can use this file */ + if ( !error ) { /* valid file name */ + /* relative vs. absolute */ + if (fnamebuf[0] != '/') + snprintf(fnamebuf2, fnamebuf_siz, "%s/%s", ast_config_AST_CONFIG_DIR, fnamebuf); + else +#if defined(STANDALONE) || defined(LOW_MEMORY) || defined(STANDALONE_AEL) + strncpy(fnamebuf2, fnamebuf, fnamebuf_siz); +#else + ast_copy_string(fnamebuf2, fnamebuf, fnamebuf_siz); +#endif + in1 = fopen( fnamebuf2, "r" ); + + if ( ! in1 ) { + ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Couldn't find the include file: %s; ignoring the Include directive!\n", my_file, my_lineno, my_col, fnamebuf2); + } else { + char *buffer; + struct stat stats; + stat(fnamebuf2, &stats); + buffer = (char*)malloc(stats.st_size+1); + fread(buffer, 1, stats.st_size, in1); + buffer[stats.st_size] = 0; + ast_log(LOG_NOTICE," --Read in included file %s, %d chars\n",fnamebuf2, (int)stats.st_size); + fclose(in1); + if (my_file) + free(my_file); + my_file = strdup(fnamebuf2); + include_stack[include_stack_index].fname = strdup(my_file); + include_stack[include_stack_index].lineno = my_lineno; + include_stack[include_stack_index].colno = my_col+yyleng; + if (create) + include_stack[include_stack_index].globbuf = *globbuf; + + include_stack[include_stack_index].globbuf_pos = 0; + + include_stack[include_stack_index].bufstate = YY_CURRENT_BUFFER; + if (create) + include_stack_index++; + ael_yy_switch_to_buffer(ael_yy_scan_string (buffer ,yyscanner),yyscanner); + free(buffer); + my_lineno = 1; + my_col = 1; + BEGIN(INITIAL); + } + } +} + diff --git a/trunk/res/ael/pval.c b/trunk/res/ael/pval.c new file mode 100644 index 000000000..56794041d --- /dev/null +++ b/trunk/res/ael/pval.c @@ -0,0 +1,5435 @@ + +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2006, Digium, Inc. + * + * Steve Murphy <murf@parsetree.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Compile symbolic Asterisk Extension Logic into Asterisk extensions, version 2. + * + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <sys/types.h> +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <regex.h> +#include <sys/stat.h> + +#include "asterisk/pbx.h" +#include "asterisk/config.h" +#include "asterisk/module.h" +#include "asterisk/logger.h" +#include "asterisk/cli.h" +#include "asterisk/app.h" +#include "asterisk/channel.h" +#include "asterisk/callerid.h" +#include "asterisk/pval.h" +#include "asterisk/ael_structs.h" +#ifdef AAL_ARGCHECK +#include "asterisk/argdesc.h" +#endif +#include "asterisk/utils.h" + +extern int localized_pbx_load_module(void); + +static char expr_output[2096]; +#define AST_PBX_MAX_STACK 128 + +/* these functions are in ../ast_expr2.fl */ + +static int errs, warns; +static int notes; +#ifdef STANDALONE +static int extensions_dot_conf_loaded = 0; +#endif +static char *registrar = "pbx_ael"; + +static pval *current_db; +static pval *current_context; +static pval *current_extension; + +static const char *match_context; +static const char *match_exten; +static const char *match_label; +static int in_abstract_context; +static int count_labels; /* true, put matcher in label counting mode */ +static int label_count; /* labels are only meant to be counted in a context or exten */ +static int return_on_context_match; +static pval *last_matched_label; +struct pval *match_pval(pval *item); +static void check_timerange(pval *p); +static void check_dow(pval *DOW); +static void check_day(pval *DAY); +static void check_month(pval *MON); +static void check_expr2_input(pval *expr, char *str); +static int extension_matches(pval *here, const char *exten, const char *pattern); +static void check_goto(pval *item); +static void find_pval_goto_item(pval *item, int lev); +static void find_pval_gotos(pval *item, int lev); +static int check_break(pval *item); +static int check_continue(pval *item); +static void check_label(pval *item); +static void check_macro_returns(pval *macro); + +static struct pval *find_label_in_current_context(char *exten, char *label, pval *curr_cont); +static struct pval *find_first_label_in_current_context(char *label, pval *curr_cont); +static void print_pval_list(FILE *fin, pval *item, int depth); + +static struct pval *find_label_in_current_extension(const char *label, pval *curr_ext); +static struct pval *find_label_in_current_db(const char *context, const char *exten, const char *label); +static pval *get_goto_target(pval *item); +static int label_inside_case(pval *label); +static void attach_exten(struct ael_extension **list, struct ael_extension *newmem); +static void fix_gotos_in_extensions(struct ael_extension *exten); +static pval *get_extension_or_contxt(pval *p); +static pval *get_contxt(pval *p); +static void remove_spaces_before_equals(char *str); + +/* PRETTY PRINTER FOR AEL: ============================================================================= */ + +static void print_pval(FILE *fin, pval *item, int depth) +{ + int i; + pval *lp; + + for (i=0; i<depth; i++) { + fprintf(fin, "\t"); /* depth == indentation */ + } + + switch ( item->type ) { + case PV_WORD: + fprintf(fin,"%s;\n", item->u1.str); /* usually, words are encapsulated in something else */ + break; + + case PV_MACRO: + fprintf(fin,"macro %s(", item->u1.str); + for (lp=item->u2.arglist; lp; lp=lp->next) { + if (lp != item->u2.arglist ) + fprintf(fin,", "); + fprintf(fin,"%s", lp->u1.str); + } + fprintf(fin,") {\n"); + print_pval_list(fin,item->u3.macro_statements,depth+1); + for (i=0; i<depth; i++) { + fprintf(fin,"\t"); /* depth == indentation */ + } + fprintf(fin,"};\n\n"); + break; + + case PV_CONTEXT: + if ( item->u3.abstract ) + fprintf(fin,"abstract context %s {\n", item->u1.str); + else + fprintf(fin,"context %s {\n", item->u1.str); + print_pval_list(fin,item->u2.statements,depth+1); + for (i=0; i<depth; i++) { + fprintf(fin,"\t"); /* depth == indentation */ + } + fprintf(fin,"};\n\n"); + break; + + case PV_MACRO_CALL: + fprintf(fin,"&%s(", item->u1.str); + for (lp=item->u2.arglist; lp; lp=lp->next) { + if ( lp != item->u2.arglist ) + fprintf(fin,", "); + fprintf(fin,"%s", lp->u1.str); + } + fprintf(fin,");\n"); + break; + + case PV_APPLICATION_CALL: + fprintf(fin,"%s(", item->u1.str); + for (lp=item->u2.arglist; lp; lp=lp->next) { + if ( lp != item->u2.arglist ) + fprintf(fin,","); + fprintf(fin,"%s", lp->u1.str); + } + fprintf(fin,");\n"); + break; + + case PV_CASE: + fprintf(fin,"case %s:\n", item->u1.str); + print_pval_list(fin,item->u2.statements, depth+1); + break; + + case PV_PATTERN: + fprintf(fin,"pattern %s:\n", item->u1.str); + print_pval_list(fin,item->u2.statements, depth+1); + break; + + case PV_DEFAULT: + fprintf(fin,"default:\n"); + print_pval_list(fin,item->u2.statements, depth+1); + break; + + case PV_CATCH: + fprintf(fin,"catch %s {\n", item->u1.str); + print_pval_list(fin,item->u2.statements, depth+1); + for (i=0; i<depth; i++) { + fprintf(fin,"\t"); /* depth == indentation */ + } + fprintf(fin,"};\n"); + break; + + case PV_SWITCHES: + fprintf(fin,"switches {\n"); + print_pval_list(fin,item->u1.list,depth+1); + for (i=0; i<depth; i++) { + fprintf(fin,"\t"); /* depth == indentation */ + } + fprintf(fin,"};\n"); + break; + + case PV_ESWITCHES: + fprintf(fin,"eswitches {\n"); + print_pval_list(fin,item->u1.list,depth+1); + for (i=0; i<depth; i++) { + fprintf(fin,"\t"); /* depth == indentation */ + } + fprintf(fin,"};\n"); + break; + + case PV_INCLUDES: + fprintf(fin,"includes {\n"); + for (lp=item->u1.list; lp; lp=lp->next) { + for (i=0; i<depth+1; i++) { + fprintf(fin,"\t"); /* depth == indentation */ + } + fprintf(fin,"%s", lp->u1.str); /* usually, words are encapsulated in something else */ + if (lp->u2.arglist) + fprintf(fin,"|%s|%s|%s|%s", + lp->u2.arglist->u1.str, + lp->u2.arglist->next->u1.str, + lp->u2.arglist->next->next->u1.str, + lp->u2.arglist->next->next->next->u1.str + ); + fprintf(fin,";\n"); /* usually, words are encapsulated in something else */ + } + + for (i=0; i<depth; i++) { + fprintf(fin,"\t"); /* depth == indentation */ + } + fprintf(fin,"};\n"); + break; + + case PV_STATEMENTBLOCK: + fprintf(fin,"{\n"); + print_pval_list(fin,item->u1.list, depth+1); + for (i=0; i<depth; i++) { + fprintf(fin,"\t"); /* depth == indentation */ + } + fprintf(fin,"}\n"); + break; + + case PV_VARDEC: + fprintf(fin,"%s=%s;\n", item->u1.str, item->u2.val); + break; + + case PV_LOCALVARDEC: + fprintf(fin,"local %s=%s;\n", item->u1.str, item->u2.val); + break; + + case PV_GOTO: + fprintf(fin,"goto %s", item->u1.list->u1.str); + if ( item->u1.list->next ) + fprintf(fin,",%s", item->u1.list->next->u1.str); + if ( item->u1.list->next && item->u1.list->next->next ) + fprintf(fin,",%s", item->u1.list->next->next->u1.str); + fprintf(fin,"\n"); + break; + + case PV_LABEL: + fprintf(fin,"%s:\n", item->u1.str); + break; + + case PV_FOR: + fprintf(fin,"for (%s; %s; %s)\n", item->u1.for_init, item->u2.for_test, item->u3.for_inc); + print_pval_list(fin,item->u4.for_statements,depth+1); + break; + + case PV_WHILE: + fprintf(fin,"while (%s)\n", item->u1.str); + print_pval_list(fin,item->u2.statements,depth+1); + break; + + case PV_BREAK: + fprintf(fin,"break;\n"); + break; + + case PV_RETURN: + fprintf(fin,"return;\n"); + break; + + case PV_CONTINUE: + fprintf(fin,"continue;\n"); + break; + + case PV_RANDOM: + case PV_IFTIME: + case PV_IF: + if ( item->type == PV_IFTIME ) { + + fprintf(fin,"ifTime ( %s|%s|%s|%s )\n", + item->u1.list->u1.str, + item->u1.list->next->u1.str, + item->u1.list->next->next->u1.str, + item->u1.list->next->next->next->u1.str + ); + } else if ( item->type == PV_RANDOM ) { + fprintf(fin,"random ( %s )\n", item->u1.str ); + } else + fprintf(fin,"if ( %s )\n", item->u1.str); + if ( item->u2.statements && item->u2.statements->next ) { + for (i=0; i<depth; i++) { + fprintf(fin,"\t"); /* depth == indentation */ + } + fprintf(fin,"{\n"); + print_pval_list(fin,item->u2.statements,depth+1); + for (i=0; i<depth; i++) { + fprintf(fin,"\t"); /* depth == indentation */ + } + if ( item->u3.else_statements ) + fprintf(fin,"}\n"); + else + fprintf(fin,"};\n"); + } else if (item->u2.statements ) { + print_pval_list(fin,item->u2.statements,depth+1); + } else { + if (item->u3.else_statements ) + fprintf(fin, " {} "); + else + fprintf(fin, " {}; "); + } + if ( item->u3.else_statements ) { + for (i=0; i<depth; i++) { + fprintf(fin,"\t"); /* depth == indentation */ + } + fprintf(fin,"else\n"); + print_pval_list(fin,item->u3.else_statements, depth); + } + break; + + case PV_SWITCH: + fprintf(fin,"switch( %s ) {\n", item->u1.str); + print_pval_list(fin,item->u2.statements,depth+1); + for (i=0; i<depth; i++) { + fprintf(fin,"\t"); /* depth == indentation */ + } + fprintf(fin,"}\n"); + break; + + case PV_EXTENSION: + if ( item->u4.regexten ) + fprintf(fin, "regexten "); + if ( item->u3.hints ) + fprintf(fin,"hints(%s) ", item->u3.hints); + + fprintf(fin,"%s => ", item->u1.str); + print_pval_list(fin,item->u2.statements,depth+1); + fprintf(fin,"\n"); + break; + + case PV_IGNOREPAT: + fprintf(fin,"ignorepat => %s;\n", item->u1.str); + break; + + case PV_GLOBALS: + fprintf(fin,"globals {\n"); + print_pval_list(fin,item->u1.statements,depth+1); + for (i=0; i<depth; i++) { + fprintf(fin,"\t"); /* depth == indentation */ + } + fprintf(fin,"}\n"); + break; + } +} + +static void print_pval_list(FILE *fin, pval *item, int depth) +{ + pval *i; + + for (i=item; i; i=i->next) { + print_pval(fin, i, depth); + } +} + +void ael2_print(char *fname, pval *tree) +{ + FILE *fin = fopen(fname,"w"); + if ( !fin ) { + ast_log(LOG_ERROR, "Couldn't open %s for writing.\n", fname); + return; + } + print_pval_list(fin, tree, 0); + fclose(fin); +} + + +/* EMPTY TEMPLATE FUNCS FOR AEL TRAVERSAL: ============================================================================= */ + +void traverse_pval_template(pval *item, int depth); +void traverse_pval_item_template(pval *item, int depth); + + +void traverse_pval_item_template(pval *item, int depth)/* depth comes in handy for a pretty print (indentation), + but you may not need it */ +{ + pval *lp; + + switch ( item->type ) { + case PV_WORD: + /* fields: item->u1.str == string associated with this (word). */ + break; + + case PV_MACRO: + /* fields: item->u1.str == name of macro + item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user + item->u2.arglist->u1.str == argument + item->u2.arglist->next == next arg + + item->u3.macro_statements == pval list of statements in macro body. + */ + for (lp=item->u2.arglist; lp; lp=lp->next) { + + } + traverse_pval_item_template(item->u3.macro_statements,depth+1); + break; + + case PV_CONTEXT: + /* fields: item->u1.str == name of context + item->u2.statements == pval list of statements in context body + item->u3.abstract == int 1 if an abstract keyword were present + */ + traverse_pval_item_template(item->u2.statements,depth+1); + break; + + case PV_MACRO_CALL: + /* fields: item->u1.str == name of macro to call + item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user + item->u2.arglist->u1.str == argument + item->u2.arglist->next == next arg + */ + for (lp=item->u2.arglist; lp; lp=lp->next) { + } + break; + + case PV_APPLICATION_CALL: + /* fields: item->u1.str == name of application to call + item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user + item->u2.arglist->u1.str == argument + item->u2.arglist->next == next arg + */ + for (lp=item->u2.arglist; lp; lp=lp->next) { + } + break; + + case PV_CASE: + /* fields: item->u1.str == value of case + item->u2.statements == pval list of statements under the case + */ + traverse_pval_item_template(item->u2.statements,depth+1); + break; + + case PV_PATTERN: + /* fields: item->u1.str == value of case + item->u2.statements == pval list of statements under the case + */ + traverse_pval_item_template(item->u2.statements,depth+1); + break; + + case PV_DEFAULT: + /* fields: + item->u2.statements == pval list of statements under the case + */ + traverse_pval_item_template(item->u2.statements,depth+1); + break; + + case PV_CATCH: + /* fields: item->u1.str == name of extension to catch + item->u2.statements == pval list of statements in context body + */ + traverse_pval_item_template(item->u2.statements,depth+1); + break; + + case PV_SWITCHES: + /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list + */ + traverse_pval_item_template(item->u1.list,depth+1); + break; + + case PV_ESWITCHES: + /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list + */ + traverse_pval_item_template(item->u1.list,depth+1); + break; + + case PV_INCLUDES: + /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list + item->u2.arglist == pval list of 4 PV_WORD elements for time values + */ + traverse_pval_item_template(item->u1.list,depth+1); + traverse_pval_item_template(item->u2.arglist,depth+1); + break; + + case PV_STATEMENTBLOCK: + /* fields: item->u1.list == pval list of statements in block, one per entry in the list + */ + traverse_pval_item_template(item->u1.list,depth+1); + break; + + case PV_LOCALVARDEC: + case PV_VARDEC: + /* fields: item->u1.str == variable name + item->u2.val == variable value to assign + */ + break; + + case PV_GOTO: + /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user. + item->u1.list->u1.str == where the data on a PV_WORD will always be. + */ + + if ( item->u1.list->next ) + ; + if ( item->u1.list->next && item->u1.list->next->next ) + ; + + break; + + case PV_LABEL: + /* fields: item->u1.str == label name + */ + break; + + case PV_FOR: + /* fields: item->u1.for_init == a string containing the initalizer + item->u2.for_test == a string containing the loop test + item->u3.for_inc == a string containing the loop increment + + item->u4.for_statements == a pval list of statements in the for () + */ + traverse_pval_item_template(item->u4.for_statements,depth+1); + break; + + case PV_WHILE: + /* fields: item->u1.str == the while conditional, as supplied by user + + item->u2.statements == a pval list of statements in the while () + */ + traverse_pval_item_template(item->u2.statements,depth+1); + break; + + case PV_BREAK: + /* fields: none + */ + break; + + case PV_RETURN: + /* fields: none + */ + break; + + case PV_CONTINUE: + /* fields: none + */ + break; + + case PV_IFTIME: + /* fields: item->u1.list == there are 4 linked PV_WORDs here. + + item->u2.statements == a pval list of statements in the if () + item->u3.else_statements == a pval list of statements in the else + (could be zero) + */ + traverse_pval_item_template(item->u2.statements,depth+1); + if ( item->u3.else_statements ) { + traverse_pval_item_template(item->u3.else_statements,depth+1); + } + break; + + case PV_RANDOM: + /* fields: item->u1.str == the random number expression, as supplied by user + + item->u2.statements == a pval list of statements in the if () + item->u3.else_statements == a pval list of statements in the else + (could be zero) + */ + traverse_pval_item_template(item->u2.statements,depth+1); + if ( item->u3.else_statements ) { + traverse_pval_item_template(item->u3.else_statements,depth+1); + } + break; + + case PV_IF: + /* fields: item->u1.str == the if conditional, as supplied by user + + item->u2.statements == a pval list of statements in the if () + item->u3.else_statements == a pval list of statements in the else + (could be zero) + */ + traverse_pval_item_template(item->u2.statements,depth+1); + if ( item->u3.else_statements ) { + traverse_pval_item_template(item->u3.else_statements,depth+1); + } + break; + + case PV_SWITCH: + /* fields: item->u1.str == the switch expression + + item->u2.statements == a pval list of statements in the switch, + (will be case statements, most likely!) + */ + traverse_pval_item_template(item->u2.statements,depth+1); + break; + + case PV_EXTENSION: + /* fields: item->u1.str == the extension name, label, whatever it's called + + item->u2.statements == a pval list of statements in the extension + item->u3.hints == a char * hint argument + item->u4.regexten == an int boolean. non-zero says that regexten was specified + */ + traverse_pval_item_template(item->u2.statements,depth+1); + break; + + case PV_IGNOREPAT: + /* fields: item->u1.str == the ignorepat data + */ + break; + + case PV_GLOBALS: + /* fields: item->u1.statements == pval list of statements, usually vardecs + */ + traverse_pval_item_template(item->u1.statements,depth+1); + break; + } +} + +void traverse_pval_template(pval *item, int depth) /* depth comes in handy for a pretty print (indentation), + but you may not need it */ +{ + pval *i; + + for (i=item; i; i=i->next) { + traverse_pval_item_template(i, depth); + } +} + + +/* SEMANTIC CHECKING FOR AEL: ============================================================================= */ + +/* (not all that is syntactically legal is good! */ + + +static void check_macro_returns(pval *macro) +{ + pval *i; + if (!macro->u3.macro_statements) + { + pval *z = calloc(1, sizeof(struct pval)); + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The macro %s is empty! I will insert a return.\n", + macro->filename, macro->startline, macro->endline, macro->u1.str); + + z->type = PV_RETURN; + z->startline = macro->startline; + z->endline = macro->endline; + z->startcol = macro->startcol; + z->endcol = macro->endcol; + z->filename = strdup(macro->filename); + + macro->u3.macro_statements = z; + return; + } + for (i=macro->u3.macro_statements; i; i=i->next) { + /* if the last statement in the list is not return, then insert a return there */ + if (i->next == NULL) { + if (i->type != PV_RETURN) { + pval *z = calloc(1, sizeof(struct pval)); + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The macro %s does not end with a return; I will insert one.\n", + macro->filename, macro->startline, macro->endline, macro->u1.str); + + z->type = PV_RETURN; + z->startline = macro->startline; + z->endline = macro->endline; + z->startcol = macro->startcol; + z->endcol = macro->endcol; + z->filename = strdup(macro->filename); + + i->next = z; + return; + } + } + } + return; +} + + + +static int extension_matches(pval *here, const char *exten, const char *pattern) +{ + int err1; + regex_t preg; + + /* simple case, they match exactly, the pattern and exten name */ + if (!strcmp(pattern,exten) == 0) + return 1; + + if (pattern[0] == '_') { + char reg1[2000]; + const char *p; + char *r = reg1; + + if ( strlen(pattern)*5 >= 2000 ) /* safety valve */ { + ast_log(LOG_ERROR,"Error: The pattern %s is way too big. Pattern matching cancelled.\n", + pattern); + return 0; + } + /* form a regular expression from the pattern, and then match it against exten */ + *r++ = '^'; /* what if the extension is a pattern ?? */ + *r++ = '_'; /* what if the extension is a pattern ?? */ + *r++ = '?'; + for (p=pattern+1; *p; p++) { + switch ( *p ) { + case 'X': + *r++ = '['; + *r++ = '0'; + *r++ = '-'; + *r++ = '9'; + *r++ = 'X'; + *r++ = ']'; + break; + + case 'Z': + *r++ = '['; + *r++ = '1'; + *r++ = '-'; + *r++ = '9'; + *r++ = 'Z'; + *r++ = ']'; + break; + + case 'N': + *r++ = '['; + *r++ = '2'; + *r++ = '-'; + *r++ = '9'; + *r++ = 'N'; + *r++ = ']'; + break; + + case '[': + while ( *p && *p != ']' ) { + *r++ = *p++; + } + if ( *p != ']') { + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The extension pattern '%s' is missing a closing bracket \n", + here->filename, here->startline, here->endline, pattern); + } + break; + + case '.': + case '!': + *r++ = '.'; + *r++ = '*'; + break; + case '*': + *r++ = '\\'; + *r++ = '*'; + break; + default: + *r++ = *p; + break; + + } + } + *r++ = '$'; /* what if the extension is a pattern ?? */ + *r++ = *p++; /* put in the closing null */ + err1 = regcomp(&preg, reg1, REG_NOSUB|REG_EXTENDED); + if ( err1 ) { + char errmess[500]; + regerror(err1,&preg,errmess,sizeof(errmess)); + regfree(&preg); + ast_log(LOG_WARNING, "Regcomp of %s failed, error code %d\n", + reg1, err1); + return 0; + } + err1 = regexec(&preg, exten, 0, 0, 0); + regfree(&preg); + + if ( err1 ) { + /* ast_log(LOG_NOTICE,"*****************************[%d]Extension %s did not match %s(%s)\n", + err1,exten, pattern, reg1); */ + return 0; /* no match */ + } else { + /* ast_log(LOG_NOTICE,"*****************************Extension %s matched %s\n", + exten, pattern); */ + return 1; + } + + + } else { + if ( strcmp(exten,pattern) == 0 ) { + return 1; + } else + return 0; + } +} + + +static void check_expr2_input(pval *expr, char *str) +{ + int spaces = strspn(str,"\t \n"); + if ( !strncmp(str+spaces,"$[",2) ) { + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The expression '%s' is redundantly wrapped in '$[ ]'. \n", + expr->filename, expr->startline, expr->endline, str); + warns++; + } +} + +static void check_includes(pval *includes) +{ + struct pval *p4; + for (p4=includes->u1.list; p4; p4=p4->next) { + /* for each context pointed to, find it, then find a context/label that matches the + target here! */ + char *incl_context = p4->u1.str; + /* find a matching context name */ + struct pval *that_other_context = find_context(incl_context); + if (!that_other_context && strcmp(incl_context, "parkedcalls") != 0) { + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The included context '%s' cannot be found.\n\ + (You may ignore this warning if '%s' exists in extensions.conf, or is created by another module. I cannot check for those.)\n", + includes->filename, includes->startline, includes->endline, incl_context, incl_context); + warns++; + } + } +} + + +static void check_timerange(pval *p) +{ + char *times; + char *e; + int s1, s2; + int e1, e2; + + times = ast_strdupa(p->u1.str); + + /* Star is all times */ + if (ast_strlen_zero(times) || !strcmp(times, "*")) { + return; + } + /* Otherwise expect a range */ + e = strchr(times, '-'); + if (!e) { + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The time range format (%s) requires a '-' surrounded by two 24-hour times of day!\n", + p->filename, p->startline, p->endline, times); + warns++; + return; + } + *e = '\0'; + e++; + while (*e && !isdigit(*e)) + e++; + if (!*e) { + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The time range format (%s) is missing the end time!\n", + p->filename, p->startline, p->endline, p->u1.str); + warns++; + } + if (sscanf(times, "%d:%d", &s1, &s2) != 2) { + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start time (%s) isn't quite right!\n", + p->filename, p->startline, p->endline, times); + warns++; + } + if (sscanf(e, "%d:%d", &e1, &e2) != 2) { + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end time (%s) isn't quite right!\n", + p->filename, p->startline, p->endline, times); + warns++; + } + + s1 = s1 * 30 + s2/2; + if ((s1 < 0) || (s1 >= 24*30)) { + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start time (%s) is out of range!\n", + p->filename, p->startline, p->endline, times); + warns++; + } + e1 = e1 * 30 + e2/2; + if ((e1 < 0) || (e1 >= 24*30)) { + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end time (%s) is out of range!\n", + p->filename, p->startline, p->endline, e); + warns++; + } + return; +} + +static char *days[] = +{ + "sun", + "mon", + "tue", + "wed", + "thu", + "fri", + "sat", +}; + +/*! \brief get_dow: Get day of week */ +static void check_dow(pval *DOW) +{ + char *dow; + char *c; + /* The following line is coincidence, really! */ + int s, e; + + dow = ast_strdupa(DOW->u1.str); + + /* Check for all days */ + if (ast_strlen_zero(dow) || !strcmp(dow, "*")) + return; + /* Get start and ending days */ + c = strchr(dow, '-'); + if (c) { + *c = '\0'; + c++; + } else + c = NULL; + /* Find the start */ + s = 0; + while ((s < 7) && strcasecmp(dow, days[s])) s++; + if (s >= 7) { + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The day (%s) must be one of 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', or 'sat'!\n", + DOW->filename, DOW->startline, DOW->endline, dow); + warns++; + } + if (c) { + e = 0; + while ((e < 7) && strcasecmp(c, days[e])) e++; + if (e >= 7) { + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end day (%s) must be one of 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', or 'sat'!\n", + DOW->filename, DOW->startline, DOW->endline, c); + warns++; + } + } else + e = s; +} + +static void check_day(pval *DAY) +{ + char *day; + char *c; + /* The following line is coincidence, really! */ + int s, e; + + day = ast_strdupa(DAY->u1.str); + + /* Check for all days */ + if (ast_strlen_zero(day) || !strcmp(day, "*")) { + return; + } + /* Get start and ending days */ + c = strchr(day, '-'); + if (c) { + *c = '\0'; + c++; + } + /* Find the start */ + if (sscanf(day, "%d", &s) != 1) { + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start day of month (%s) must be a number!\n", + DAY->filename, DAY->startline, DAY->endline, day); + warns++; + } + else if ((s < 1) || (s > 31)) { + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start day of month (%s) must be a number in the range [1-31]!\n", + DAY->filename, DAY->startline, DAY->endline, day); + warns++; + } + s--; + if (c) { + if (sscanf(c, "%d", &e) != 1) { + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end day of month (%s) must be a number!\n", + DAY->filename, DAY->startline, DAY->endline, c); + warns++; + } + else if ((e < 1) || (e > 31)) { + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end day of month (%s) must be a number in the range [1-31]!\n", + DAY->filename, DAY->startline, DAY->endline, day); + warns++; + } + e--; + } else + e = s; +} + +static char *months[] = +{ + "jan", + "feb", + "mar", + "apr", + "may", + "jun", + "jul", + "aug", + "sep", + "oct", + "nov", + "dec", +}; + +static void check_month(pval *MON) +{ + char *mon; + char *c; + /* The following line is coincidence, really! */ + int s, e; + + mon = ast_strdupa(MON->u1.str); + + /* Check for all days */ + if (ast_strlen_zero(mon) || !strcmp(mon, "*")) + return ; + /* Get start and ending days */ + c = strchr(mon, '-'); + if (c) { + *c = '\0'; + c++; + } + /* Find the start */ + s = 0; + while ((s < 12) && strcasecmp(mon, months[s])) s++; + if (s >= 12) { + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start month (%s) must be a one of: 'jan', 'feb', ..., 'dec'!\n", + MON->filename, MON->startline, MON->endline, mon); + warns++; + } + if (c) { + e = 0; + while ((e < 12) && strcasecmp(mon, months[e])) e++; + if (e >= 12) { + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end month (%s) must be a one of: 'jan', 'feb', ..., 'dec'!\n", + MON->filename, MON->startline, MON->endline, c); + warns++; + } + } else + e = s; +} + +static int check_break(pval *item) +{ + pval *p = item; + + while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) /* early cutout, sort of */ { + /* a break is allowed in WHILE, FOR, CASE, DEFAULT, PATTERN; otherwise, it don't make + no sense */ + if( p->type == PV_CASE || p->type == PV_DEFAULT || p->type == PV_PATTERN + || p->type == PV_WHILE || p->type == PV_FOR ) { + return 1; + } + p = p->dad; + } + ast_log(LOG_ERROR,"Error: file %s, line %d-%d: 'break' not in switch, for, or while statement!\n", + item->filename, item->startline, item->endline); + errs++; + + return 0; +} + +static int check_continue(pval *item) +{ + pval *p = item; + + while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) /* early cutout, sort of */ { + /* a break is allowed in WHILE, FOR, CASE, DEFAULT, PATTERN; otherwise, it don't make + no sense */ + if( p->type == PV_WHILE || p->type == PV_FOR ) { + return 1; + } + p = p->dad; + } + ast_log(LOG_ERROR,"Error: file %s, line %d-%d: 'continue' not in 'for' or 'while' statement!\n", + item->filename, item->startline, item->endline); + errs++; + + return 0; +} + +static struct pval *in_macro(pval *item) +{ + struct pval *curr; + curr = item; + while( curr ) { + if( curr->type == PV_MACRO ) { + return curr; + } + curr = curr->dad; + } + return 0; +} + +static struct pval *in_context(pval *item) +{ + struct pval *curr; + curr = item; + while( curr ) { + if( curr->type == PV_MACRO || curr->type == PV_CONTEXT ) { + return curr; + } + curr = curr->dad; + } + return 0; +} + + +/* general purpose goto finder */ + +static void check_label(pval *item) +{ + struct pval *curr; + struct pval *x; + int alright = 0; + + /* A label outside an extension just plain does not make sense! */ + + curr = item; + + while( curr ) { + if( curr->type == PV_MACRO || curr->type == PV_EXTENSION ) { + alright = 1; + break; + } + curr = curr->dad; + } + if( !alright ) + { + ast_log(LOG_ERROR,"Error: file %s, line %d-%d: Label %s is not within an extension or macro!\n", + item->filename, item->startline, item->endline, item->u1.str); + errs++; + } + + + /* basically, ensure that a label is not repeated in a context. Period. + The method: well, for each label, find the first label in the context + with the same name. If it's not the current label, then throw an error. */ + + + /* printf("==== check_label: ====\n"); */ + if( !current_extension ) + curr = current_context; + else + curr = current_extension; + + x = find_first_label_in_current_context((char *)item->u1.str, curr); + /* printf("Hey, check_label found with item = %x, and x is %x, and currcont is %x, label name is %s\n", item,x, current_context, (char *)item->u1.str); */ + if( x && x != item ) + { + ast_log(LOG_ERROR,"Error: file %s, line %d-%d: Duplicate label %s! Previously defined at file %s, line %d.\n", + item->filename, item->startline, item->endline, item->u1.str, x->filename, x->startline); + errs++; + } + /* printf("<<<<< check_label: ====\n"); */ +} + +static pval *get_goto_target(pval *item) +{ + /* just one item-- the label should be in the current extension */ + pval *curr_ext = get_extension_or_contxt(item); /* containing exten, or macro */ + pval *curr_cont; + + if (item->u1.list && !item->u1.list->next && !strstr((item->u1.list)->u1.str,"${")) { + struct pval *x = find_label_in_current_extension((char*)((item->u1.list)->u1.str), curr_ext); + return x; + } + + curr_cont = get_contxt(item); + + /* TWO items */ + if (item->u1.list->next && !item->u1.list->next->next) { + if (!strstr((item->u1.list)->u1.str,"${") + && !strstr(item->u1.list->next->u1.str,"${") ) /* Don't try to match variables */ { + struct pval *x = find_label_in_current_context((char *)item->u1.list->u1.str, (char *)item->u1.list->next->u1.str, curr_cont); + return x; + } + } + + /* All 3 items! */ + if (item->u1.list->next && item->u1.list->next->next) { + /* all three */ + pval *first = item->u1.list; + pval *second = item->u1.list->next; + pval *third = item->u1.list->next->next; + + if (!strstr((item->u1.list)->u1.str,"${") + && !strstr(item->u1.list->next->u1.str,"${") + && !strstr(item->u1.list->next->next->u1.str,"${")) /* Don't try to match variables */ { + struct pval *x = find_label_in_current_db((char*)first->u1.str, (char*)second->u1.str, (char*)third->u1.str); + if (!x) { + + struct pval *p3; + struct pval *that_context = find_context(item->u1.list->u1.str); + + /* the target of the goto could be in an included context!! Fancy that!! */ + /* look for includes in the current context */ + if (that_context) { + for (p3=that_context->u2.statements; p3; p3=p3->next) { + if (p3->type == PV_INCLUDES) { + struct pval *p4; + for (p4=p3->u1.list; p4; p4=p4->next) { + /* for each context pointed to, find it, then find a context/label that matches the + target here! */ + char *incl_context = p4->u1.str; + /* find a matching context name */ + struct pval *that_other_context = find_context(incl_context); + if (that_other_context) { + struct pval *x3; + x3 = find_label_in_current_context((char *)item->u1.list->next->u1.str, (char *)item->u1.list->next->next->u1.str, that_other_context); + if (x3) { + return x3; + } + } + } + } + } + } + } + return x; + } + } + return 0; +} + +static void check_goto(pval *item) +{ + /* check for the target of the goto-- does it exist? */ + if ( !(item->u1.list)->next && !(item->u1.list)->u1.str ) { + ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto: empty label reference found!\n", + item->filename, item->startline, item->endline); + errs++; + } + + /* just one item-- the label should be in the current extension */ + + if (item->u1.list && !item->u1.list->next && !strstr((item->u1.list)->u1.str,"${")) { + struct pval *z = get_extension_or_contxt(item); + struct pval *x = 0; + if (z) + x = find_label_in_current_extension((char*)((item->u1.list)->u1.str), z); /* if in macro, use current context instead */ + /* printf("Called find_label_in_current_extension with arg %s; current_extension is %x: %d\n", + (char*)((item->u1.list)->u1.str), current_extension?current_extension:current_context, current_extension?current_extension->type:current_context->type); */ + if (!x) { + ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto: no label %s exists in the current extension!\n", + item->filename, item->startline, item->endline, item->u1.list->u1.str); + errs++; + } + else + return; + } + + /* TWO items */ + if (item->u1.list->next && !item->u1.list->next->next) { + /* two items */ + /* printf("Calling find_label_in_current_context with args %s, %s\n", + (char*)((item->u1.list)->u1.str), (char *)item->u1.list->next->u1.str); */ + if (!strstr((item->u1.list)->u1.str,"${") + && !strstr(item->u1.list->next->u1.str,"${") ) /* Don't try to match variables */ { + struct pval *z = get_contxt(item); + struct pval *x = 0; + + if (z) + x = find_label_in_current_context((char *)item->u1.list->u1.str, (char *)item->u1.list->next->u1.str, z); + + if (!x) { + ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto: no label '%s,%s' exists in the current context, or any of its inclusions!\n", + item->filename, item->startline, item->endline, item->u1.list->u1.str, item->u1.list->next->u1.str ); + errs++; + } + else + return; + } + } + + /* All 3 items! */ + if (item->u1.list->next && item->u1.list->next->next) { + /* all three */ + pval *first = item->u1.list; + pval *second = item->u1.list->next; + pval *third = item->u1.list->next->next; + + /* printf("Calling find_label_in_current_db with args %s, %s, %s\n", + (char*)first->u1.str, (char*)second->u1.str, (char*)third->u1.str); */ + if (!strstr((item->u1.list)->u1.str,"${") + && !strstr(item->u1.list->next->u1.str,"${") + && !strstr(item->u1.list->next->next->u1.str,"${")) /* Don't try to match variables */ { + struct pval *x = find_label_in_current_db((char*)first->u1.str, (char*)second->u1.str, (char*)third->u1.str); + if (!x) { + struct pval *p3; + struct pval *found = 0; + struct pval *that_context = find_context(item->u1.list->u1.str); + + /* the target of the goto could be in an included context!! Fancy that!! */ + /* look for includes in the current context */ + if (that_context) { + for (p3=that_context->u2.statements; p3; p3=p3->next) { + if (p3->type == PV_INCLUDES) { + struct pval *p4; + for (p4=p3->u1.list; p4; p4=p4->next) { + /* for each context pointed to, find it, then find a context/label that matches the + target here! */ + char *incl_context = p4->u1.str; + /* find a matching context name */ + struct pval *that_other_context = find_context(incl_context); + if (that_other_context) { + struct pval *x3; + x3 = find_label_in_current_context((char *)item->u1.list->next->u1.str, (char *)item->u1.list->next->next->u1.str, that_other_context); + if (x3) { + found = x3; + break; + } + } + } + } + } + if (!found) { + ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto: no label %s|%s exists in the context %s or its inclusions!\n", + item->filename, item->startline, item->endline, item->u1.list->next->u1.str, item->u1.list->next->next->u1.str, item->u1.list->u1.str ); + errs++; + } else { + struct pval *mac = in_macro(item); /* is this goto inside a macro? */ + if( mac ) { /* yes! */ + struct pval *targ = in_context(found); + if( mac != targ ) + { + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: It's bad form to have a goto in a macro to a target outside the macro!\n", + item->filename, item->startline, item->endline); + warns++; + } + } + } + } else { + /* here is where code would go to check for target existence in extensions.conf files */ +#ifdef STANDALONE + struct pbx_find_info pfiq = {.stacklen = 0 }; + extern int localized_pbx_load_module(void); + /* if this is a standalone, we will need to make sure the + localized load of extensions.conf is done */ + if (!extensions_dot_conf_loaded) { + localized_pbx_load_module(); + extensions_dot_conf_loaded++; + } + + pbx_find_extension(NULL, NULL, &pfiq, first->u1.str, second->u1.str, atoi(third->u1.str), + atoi(third->u1.str) ? NULL : third->u1.str, NULL, + atoi(third->u1.str) ? E_MATCH : E_FINDLABEL); + + if (pfiq.status != STATUS_SUCCESS) { + ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: goto: Couldn't find goto target %s|%s|%s, not even in extensions.conf!\n", + item->filename, item->startline, item->endline, first->u1.str, second->u1.str, third->u1.str); + warns++; + } +#else + ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: goto: Couldn't find goto target %s|%s|%s in the AEL code!\n", + item->filename, item->startline, item->endline, first->u1.str, second->u1.str, third->u1.str); + warns++; +#endif + } + } else { + struct pval *mac = in_macro(item); /* is this goto inside a macro? */ + if( mac ) { /* yes! */ + struct pval *targ = in_context(x); + if( mac != targ ) + { + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: It's bad form to have a goto in a macro to a target outside the macro!\n", + item->filename, item->startline, item->endline); + warns++; + } + } + } + } + } +} + + +static void find_pval_goto_item(pval *item, int lev) +{ + struct pval *p4; + if (lev>100) { + ast_log(LOG_ERROR,"find_pval_goto in infinite loop!\n\n"); + return; + } + + switch ( item->type ) { + case PV_MACRO: + /* fields: item->u1.str == name of macro + item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user + item->u2.arglist->u1.str == argument + item->u2.arglist->next == next arg + + item->u3.macro_statements == pval list of statements in macro body. + */ + + /* printf("Descending into matching macro %s\n", match_context); */ + find_pval_gotos(item->u3.macro_statements,lev+1); /* if we're just searching for a context, don't bother descending into them */ + + break; + + case PV_CONTEXT: + /* fields: item->u1.str == name of context + item->u2.statements == pval list of statements in context body + item->u3.abstract == int 1 if an abstract keyword were present + */ + break; + + case PV_CASE: + /* fields: item->u1.str == value of case + item->u2.statements == pval list of statements under the case + */ + find_pval_gotos(item->u2.statements,lev+1); + break; + + case PV_PATTERN: + /* fields: item->u1.str == value of case + item->u2.statements == pval list of statements under the case + */ + find_pval_gotos(item->u2.statements,lev+1); + break; + + case PV_DEFAULT: + /* fields: + item->u2.statements == pval list of statements under the case + */ + find_pval_gotos(item->u2.statements,lev+1); + break; + + case PV_CATCH: + /* fields: item->u1.str == name of extension to catch + item->u2.statements == pval list of statements in context body + */ + find_pval_gotos(item->u2.statements,lev+1); + break; + + case PV_STATEMENTBLOCK: + /* fields: item->u1.list == pval list of statements in block, one per entry in the list + */ + find_pval_gotos(item->u1.list,lev+1); + break; + + case PV_GOTO: + /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user. + item->u1.list->u1.str == where the data on a PV_WORD will always be. + */ + check_goto(item); /* THE WHOLE FUNCTION OF THIS ENTIRE ROUTINE!!!! */ + break; + + case PV_INCLUDES: + /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list + */ + for (p4=item->u1.list; p4; p4=p4->next) { + /* for each context pointed to, find it, then find a context/label that matches the + target here! */ + char *incl_context = p4->u1.str; + /* find a matching context name */ + struct pval *that_context = find_context(incl_context); + if (that_context) { + find_pval_gotos(that_context,lev+1); /* keep working up the includes */ + } + } + break; + + case PV_FOR: + /* fields: item->u1.for_init == a string containing the initalizer + item->u2.for_test == a string containing the loop test + item->u3.for_inc == a string containing the loop increment + + item->u4.for_statements == a pval list of statements in the for () + */ + find_pval_gotos(item->u4.for_statements,lev+1); + break; + + case PV_WHILE: + /* fields: item->u1.str == the while conditional, as supplied by user + + item->u2.statements == a pval list of statements in the while () + */ + find_pval_gotos(item->u2.statements,lev+1); + break; + + case PV_RANDOM: + /* fields: item->u1.str == the random number expression, as supplied by user + + item->u2.statements == a pval list of statements in the if () + item->u3.else_statements == a pval list of statements in the else + (could be zero) + fall thru to PV_IF */ + + case PV_IFTIME: + /* fields: item->u1.list == the time values, 4 of them, as PV_WORD structs in a list + + item->u2.statements == a pval list of statements in the if () + item->u3.else_statements == a pval list of statements in the else + (could be zero) + fall thru to PV_IF*/ + case PV_IF: + /* fields: item->u1.str == the if conditional, as supplied by user + + item->u2.statements == a pval list of statements in the if () + item->u3.else_statements == a pval list of statements in the else + (could be zero) + */ + find_pval_gotos(item->u2.statements,lev+1); + + if (item->u3.else_statements) { + find_pval_gotos(item->u3.else_statements,lev+1); + } + break; + + case PV_SWITCH: + /* fields: item->u1.str == the switch expression + + item->u2.statements == a pval list of statements in the switch, + (will be case statements, most likely!) + */ + find_pval_gotos(item->u3.else_statements,lev+1); + break; + + case PV_EXTENSION: + /* fields: item->u1.str == the extension name, label, whatever it's called + + item->u2.statements == a pval list of statements in the extension + item->u3.hints == a char * hint argument + item->u4.regexten == an int boolean. non-zero says that regexten was specified + */ + + find_pval_gotos(item->u2.statements,lev+1); + break; + + default: + break; + } +} + +static void find_pval_gotos(pval *item,int lev) +{ + pval *i; + + for (i=item; i; i=i->next) { + + find_pval_goto_item(i, lev); + } +} + + + +/* general purpose label finder */ +static struct pval *match_pval_item(pval *item) +{ + pval *x; + + switch ( item->type ) { + case PV_MACRO: + /* fields: item->u1.str == name of macro + item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user + item->u2.arglist->u1.str == argument + item->u2.arglist->next == next arg + + item->u3.macro_statements == pval list of statements in macro body. + */ + /* printf(" matching in MACRO %s, match_context=%s; retoncontmtch=%d; \n", item->u1.str, match_context, return_on_context_match); */ + if (!strcmp(match_context,"*") || !strcmp(item->u1.str, match_context)) { + + /* printf("MACRO: match context is: %s\n", match_context); */ + + if (return_on_context_match && !strcmp(item->u1.str, match_context)) /* if we're just searching for a context, don't bother descending into them */ { + /* printf("Returning on matching macro %s\n", match_context); */ + return item; + } + + + if (!return_on_context_match) { + /* printf("Descending into matching macro %s/%s\n", match_context, item->u1.str); */ + if ((x=match_pval(item->u3.macro_statements))) { + /* printf("Responded with pval match %x\n", x); */ + return x; + } + } + } else { + /* printf("Skipping context/macro %s\n", item->u1.str); */ + } + + break; + + case PV_CONTEXT: + /* fields: item->u1.str == name of context + item->u2.statements == pval list of statements in context body + item->u3.abstract == int 1 if an abstract keyword were present + */ + /* printf(" matching in CONTEXT\n"); */ + if (!strcmp(match_context,"*") || !strcmp(item->u1.str, match_context)) { + if (return_on_context_match && !strcmp(item->u1.str, match_context)) { + /* printf("Returning on matching context %s\n", match_context); */ + /* printf("non-CONTEXT: Responded with pval match %x\n", x); */ + return item; + } + + if (!return_on_context_match ) { + /* printf("Descending into matching context %s\n", match_context); */ + if ((x=match_pval(item->u2.statements))) /* if we're just searching for a context, don't bother descending into them */ { + /* printf("CONTEXT: Responded with pval match %x\n", x); */ + return x; + } + } + } else { + /* printf("Skipping context/macro %s\n", item->u1.str); */ + } + break; + + case PV_CASE: + /* fields: item->u1.str == value of case + item->u2.statements == pval list of statements under the case + */ + /* printf(" matching in CASE\n"); */ + if ((x=match_pval(item->u2.statements))) { + /* printf("CASE: Responded with pval match %x\n", x); */ + return x; + } + break; + + case PV_PATTERN: + /* fields: item->u1.str == value of case + item->u2.statements == pval list of statements under the case + */ + /* printf(" matching in PATTERN\n"); */ + if ((x=match_pval(item->u2.statements))) { + /* printf("PATTERN: Responded with pval match %x\n", x); */ + return x; + } + break; + + case PV_DEFAULT: + /* fields: + item->u2.statements == pval list of statements under the case + */ + /* printf(" matching in DEFAULT\n"); */ + if ((x=match_pval(item->u2.statements))) { + /* printf("DEFAULT: Responded with pval match %x\n", x); */ + return x; + } + break; + + case PV_CATCH: + /* fields: item->u1.str == name of extension to catch + item->u2.statements == pval list of statements in context body + */ + /* printf(" matching in CATCH\n"); */ + if ((x=match_pval(item->u2.statements))) { + /* printf("CATCH: Responded with pval match %x\n", x); */ + return x; + } + break; + + case PV_STATEMENTBLOCK: + /* fields: item->u1.list == pval list of statements in block, one per entry in the list + */ + /* printf(" matching in STATEMENTBLOCK\n"); */ + if ((x=match_pval(item->u1.list))) { + /* printf("STATEMENTBLOCK: Responded with pval match %x\n", x); */ + return x; + } + break; + + case PV_LABEL: + /* fields: item->u1.str == label name + */ + /* printf("PV_LABEL %s (cont=%s, exten=%s\n", + item->u1.str, current_context->u1.str, (current_extension?current_extension->u1.str:"<macro>"));*/ + + if (count_labels) { + if (!strcmp(match_label, item->u1.str)) { + label_count++; + last_matched_label = item; + } + + } else { + if (!strcmp(match_label, item->u1.str)) { + /* printf("LABEL: Responded with pval match %x\n", x); */ + return item; + } + } + break; + + case PV_FOR: + /* fields: item->u1.for_init == a string containing the initalizer + item->u2.for_test == a string containing the loop test + item->u3.for_inc == a string containing the loop increment + + item->u4.for_statements == a pval list of statements in the for () + */ + /* printf(" matching in FOR\n"); */ + if ((x=match_pval(item->u4.for_statements))) { + /* printf("FOR: Responded with pval match %x\n", x);*/ + return x; + } + break; + + case PV_WHILE: + /* fields: item->u1.str == the while conditional, as supplied by user + + item->u2.statements == a pval list of statements in the while () + */ + /* printf(" matching in WHILE\n"); */ + if ((x=match_pval(item->u2.statements))) { + /* printf("WHILE: Responded with pval match %x\n", x); */ + return x; + } + break; + + case PV_RANDOM: + /* fields: item->u1.str == the random number expression, as supplied by user + + item->u2.statements == a pval list of statements in the if () + item->u3.else_statements == a pval list of statements in the else + (could be zero) + fall thru to PV_IF */ + + case PV_IFTIME: + /* fields: item->u1.list == the time values, 4 of them, as PV_WORD structs in a list + + item->u2.statements == a pval list of statements in the if () + item->u3.else_statements == a pval list of statements in the else + (could be zero) + fall thru to PV_IF*/ + case PV_IF: + /* fields: item->u1.str == the if conditional, as supplied by user + + item->u2.statements == a pval list of statements in the if () + item->u3.else_statements == a pval list of statements in the else + (could be zero) + */ + /* printf(" matching in IF/IFTIME/RANDOM\n"); */ + if ((x=match_pval(item->u2.statements))) { + return x; + } + if (item->u3.else_statements) { + if ((x=match_pval(item->u3.else_statements))) { + /* printf("IF/IFTIME/RANDOM: Responded with pval match %x\n", x); */ + return x; + } + } + break; + + case PV_SWITCH: + /* fields: item->u1.str == the switch expression + + item->u2.statements == a pval list of statements in the switch, + (will be case statements, most likely!) + */ + /* printf(" matching in SWITCH\n"); */ + if ((x=match_pval(item->u2.statements))) { + /* printf("SWITCH: Responded with pval match %x\n", x); */ + return x; + } + break; + + case PV_EXTENSION: + /* fields: item->u1.str == the extension name, label, whatever it's called + + item->u2.statements == a pval list of statements in the extension + item->u3.hints == a char * hint argument + item->u4.regexten == an int boolean. non-zero says that regexten was specified + */ + /* printf(" matching in EXTENSION\n"); */ + if (!strcmp(match_exten,"*") || extension_matches(item, match_exten, item->u1.str) ) { + /* printf("Descending into matching exten %s => %s\n", match_exten, item->u1.str); */ + if (strcmp(match_label,"1") == 0) { + if (item->u2.statements) { + struct pval *p5 = item->u2.statements; + while (p5 && p5->type == PV_LABEL) /* find the first non-label statement in this context. If it exists, there's a "1" */ + p5 = p5->next; + if (p5) + return p5; + else + return 0; + } + else + return 0; + } + + if ((x=match_pval(item->u2.statements))) { + /* printf("EXTENSION: Responded with pval match %x\n", x); */ + return x; + } + } else { + /* printf("Skipping exten %s\n", item->u1.str); */ + } + break; + default: + /* printf(" matching in default = %d\n", item->type); */ + break; + } + return 0; +} + +struct pval *match_pval(pval *item) +{ + pval *i; + + for (i=item; i; i=i->next) { + pval *x; + /* printf(" -- match pval: item %d\n", i->type); */ + + if ((x = match_pval_item(i))) { + /* printf("match_pval: returning x=%x\n", (int)x); */ + return x; /* cut the search short */ + } + } + return 0; +} + +#if 0 +int count_labels_in_current_context(char *label) +{ + label_count = 0; + count_labels = 1; + return_on_context_match = 0; + match_pval(current_context->u2.statements); + + return label_count; +} +#endif + +struct pval *find_first_label_in_current_context(char *label, pval *curr_cont) +{ + /* printf(" --- Got args %s, %s\n", exten, label); */ + struct pval *ret; + struct pval *p3; + + count_labels = 0; + return_on_context_match = 0; + match_context = "*"; + match_exten = "*"; + match_label = label; + + ret = match_pval(curr_cont); + if (ret) + return ret; + + /* the target of the goto could be in an included context!! Fancy that!! */ + /* look for includes in the current context */ + for (p3=curr_cont->u2.statements; p3; p3=p3->next) { + if (p3->type == PV_INCLUDES) { + struct pval *p4; + for (p4=p3->u1.list; p4; p4=p4->next) { + /* for each context pointed to, find it, then find a context/label that matches the + target here! */ + char *incl_context = p4->u1.str; + /* find a matching context name */ + struct pval *that_context = find_context(incl_context); + if (that_context) { + struct pval *x3; + x3 = find_first_label_in_current_context(label, that_context); + if (x3) { + return x3; + } + } + } + } + } + return 0; +} + +struct pval *find_label_in_current_context(char *exten, char *label, pval *curr_cont) +{ + /* printf(" --- Got args %s, %s\n", exten, label); */ + struct pval *ret; + struct pval *p3; + + count_labels = 0; + return_on_context_match = 0; + match_context = "*"; + match_exten = exten; + match_label = label; + ret = match_pval(curr_cont->u2.statements); + if (ret) + return ret; + + /* the target of the goto could be in an included context!! Fancy that!! */ + /* look for includes in the current context */ + for (p3=curr_cont->u2.statements; p3; p3=p3->next) { + if (p3->type == PV_INCLUDES) { + struct pval *p4; + for (p4=p3->u1.list; p4; p4=p4->next) { + /* for each context pointed to, find it, then find a context/label that matches the + target here! */ + char *incl_context = p4->u1.str; + /* find a matching context name */ + struct pval *that_context = find_context(incl_context); + if (that_context) { + struct pval *x3; + x3 = find_label_in_current_context(exten, label, that_context); + if (x3) { + return x3; + } + } + } + } + } + return 0; +} + +static struct pval *find_label_in_current_extension(const char *label, pval *curr_ext) +{ + /* printf(" --- Got args %s\n", label); */ + count_labels = 0; + return_on_context_match = 0; + match_context = "*"; + match_exten = "*"; + match_label = label; + return match_pval(curr_ext); +} + +static struct pval *find_label_in_current_db(const char *context, const char *exten, const char *label) +{ + /* printf(" --- Got args %s, %s, %s\n", context, exten, label); */ + count_labels = 0; + return_on_context_match = 0; + + match_context = context; + match_exten = exten; + match_label = label; + + return match_pval(current_db); +} + + +struct pval *find_macro(char *name) +{ + return_on_context_match = 1; + count_labels = 0; + match_context = name; + match_exten = "*"; /* don't really need to set these, shouldn't be reached */ + match_label = "*"; + return match_pval(current_db); +} + +struct pval *find_context(char *name) +{ + return_on_context_match = 1; + count_labels = 0; + match_context = name; + match_exten = "*"; /* don't really need to set these, shouldn't be reached */ + match_label = "*"; + return match_pval(current_db); +} + +int is_float(char *arg ) +{ + char *s; + for (s=arg; *s; s++) { + if (*s != '.' && (*s < '0' || *s > '9')) + return 0; + } + return 1; +} +int is_int(char *arg ) +{ + char *s; + for (s=arg; *s; s++) { + if (*s < '0' || *s > '9') + return 0; + } + return 1; +} +int is_empty(char *arg) +{ + if (!arg) + return 1; + if (*arg == 0) + return 1; + while (*arg) { + if (*arg != ' ' && *arg != '\t') + return 0; + arg++; + } + return 1; +} + +#ifdef AAL_ARGCHECK +int option_matches_j( struct argdesc *should, pval *is, struct argapp *app) +{ + struct argchoice *ac; + char *opcop,*q,*p; + + switch (should->dtype) { + case ARGD_OPTIONSET: + if ( strstr(is->u1.str,"${") ) + return 0; /* no checking anything if there's a var reference in there! */ + + opcop = ast_strdupa(is->u1.str); + + for (q=opcop;*q;q++) { /* erase the innards of X(innard) type arguments, so we don't get confused later */ + if ( *q == '(' ) { + p = q+1; + while (*p && *p != ')' ) + *p++ = '+'; + q = p+1; + } + } + + for (ac=app->opts; ac; ac=ac->next) { + if (strlen(ac->name)>1 && strchr(ac->name,'(') == 0 && strcmp(ac->name,is->u1.str) == 0) /* multichar option, no parens, and a match? */ + return 0; + } + for (ac=app->opts; ac; ac=ac->next) { + if (strlen(ac->name)==1 || strchr(ac->name,'(')) { + char *p = strchr(opcop,ac->name[0]); /* wipe out all matched options in the user-supplied string */ + + if (p && *p == 'j') { + ast_log(LOG_ERROR, "Error: file %s, line %d-%d: The j option in the %s application call is not appropriate for AEL!\n", + is->filename, is->startline, is->endline, app->name); + errs++; + } + + if (p) { + *p = '+'; + if (ac->name[1] == '(') { + if (*(p+1) != '(') { + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The %c option in the %s application call should have an (argument), but doesn't!\n", + is->filename, is->startline, is->endline, ac->name[0], app->name); + warns++; + } + } + } + } + } + for (q=opcop; *q; q++) { + if ( *q != '+' && *q != '(' && *q != ')') { + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The %c option in the %s application call is not available as an option!\n", + is->filename, is->startline, is->endline, *q, app->name); + warns++; + } + } + return 1; + break; + default: + return 0; + } + +} + +int option_matches( struct argdesc *should, pval *is, struct argapp *app) +{ + struct argchoice *ac; + char *opcop; + + switch (should->dtype) { + case ARGD_STRING: + if (is_empty(is->u1.str) && should->type == ARGD_REQUIRED) + return 0; + if (is->u1.str && strlen(is->u1.str) > 0) /* most will match */ + return 1; + break; + + case ARGD_INT: + if (is_int(is->u1.str)) + return 1; + else + return 0; + break; + + case ARGD_FLOAT: + if (is_float(is->u1.str)) + return 1; + else + return 0; + break; + + case ARGD_ENUM: + if( !is->u1.str || strlen(is->u1.str) == 0 ) + return 1; /* a null arg in the call will match an enum, I guess! */ + for (ac=should->choices; ac; ac=ac->next) { + if (strcmp(ac->name,is->u1.str) == 0) + return 1; + } + return 0; + break; + + case ARGD_OPTIONSET: + opcop = ast_strdupa(is->u1.str); + + for (ac=app->opts; ac; ac=ac->next) { + if (strlen(ac->name)>1 && strchr(ac->name,'(') == 0 && strcmp(ac->name,is->u1.str) == 0) /* multichar option, no parens, and a match? */ + return 1; + } + for (ac=app->opts; ac; ac=ac->next) { + if (strlen(ac->name)==1 || strchr(ac->name,'(')) { + char *p = strchr(opcop,ac->name[0]); /* wipe out all matched options in the user-supplied string */ + + if (p) { + *p = '+'; + if (ac->name[1] == '(') { + if (*(p+1) == '(') { + char *q = p+1; + while (*q && *q != ')') { + *q++ = '+'; + } + *q = '+'; + } + } + } + } + } + return 1; + break; + case ARGD_VARARG: + return 1; /* matches anything */ + break; + } + return 1; /* unless some for-sure match or non-match returns, then it must be close enough ... */ +} +#endif + +int check_app_args(pval* appcall, pval *arglist, struct argapp *app) +{ +#ifdef AAL_ARGCHECK + struct argdesc *ad = app->args; + pval *pa; + int z; + + for (pa = arglist; pa; pa=pa->next) { + if (!ad) { + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Extra argument %s not in application call to %s !\n", + arglist->filename, arglist->startline, arglist->endline, pa->u1.str, app->name); + warns++; + return 1; + } else { + /* find the first entry in the ad list that will match */ + do { + if ( ad->dtype == ARGD_VARARG ) /* once we hit the VARARG, all bets are off. Discontinue the comparisons */ + break; + + z= option_matches( ad, pa, app); + if (!z) { + if ( !arglist ) + arglist=appcall; + + if (ad->type == ARGD_REQUIRED) { + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n", + arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name); + warns++; + return 1; + } + } else if (z && ad->dtype == ARGD_OPTIONSET) { + option_matches_j( ad, pa, app); + } + ad = ad->next; + } while (ad && !z); + } + } + /* any app nodes left, that are not optional? */ + for ( ; ad; ad=ad->next) { + if (ad->type == ARGD_REQUIRED && ad->dtype != ARGD_VARARG) { + if ( !arglist ) + arglist=appcall; + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n", + arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name); + warns++; + return 1; + } + } + return 0; +#else + return 0; +#endif +} + +void check_switch_expr(pval *item, struct argapp *apps) +{ +#ifdef AAL_ARGCHECK + /* get and clean the variable name */ + char *buff1, *p; + struct argapp *a,*a2; + struct appsetvar *v,*v2; + struct argchoice *c; + pval *t; + + p = item->u1.str; + while (p && *p && (*p == ' ' || *p == '\t' || *p == '$' || *p == '{' ) ) + p++; + + buff1 = ast_strdupa(p); + + while (strlen(buff1) > 0 && ( buff1[strlen(buff1)-1] == '}' || buff1[strlen(buff1)-1] == ' ' || buff1[strlen(buff1)-1] == '\t')) + buff1[strlen(buff1)-1] = 0; + /* buff1 now contains the variable name */ + v = 0; + for (a=apps; a; a=a->next) { + for (v=a->setvars;v;v=v->next) { + if (strcmp(v->name,buff1) == 0) { + break; + } + } + if ( v ) + break; + } + if (v && v->vals) { + /* we have a match, to a variable that has a set of determined values */ + int def= 0; + int pat = 0; + int f1 = 0; + + /* first of all, does this switch have a default case ? */ + for (t=item->u2.statements; t; t=t->next) { + if (t->type == PV_DEFAULT) { + def =1; + break; + } + if (t->type == PV_PATTERN) { + pat++; + } + } + if (def || pat) /* nothing to check. All cases accounted for! */ + return; + for (c=v->vals; c; c=c->next) { + f1 = 0; + for (t=item->u2.statements; t; t=t->next) { + if (t->type == PV_CASE || t->type == PV_PATTERN) { + if (!strcmp(t->u1.str,c->name)) { + f1 = 1; + break; + } + } + } + if (!f1) { + ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: switch with expression(%s) does not handle the case of %s !\n", + item->filename, item->startline, item->endline, item->u1.str, c->name); + warns++; + } + } + /* next, is there an app call in the current exten, that would set this var? */ + f1 = 0; + t = current_extension->u2.statements; + if ( t && t->type == PV_STATEMENTBLOCK ) + t = t->u1.statements; + for (; t && t != item; t=t->next) { + if (t->type == PV_APPLICATION_CALL) { + /* find the application that matches the u1.str */ + for (a2=apps; a2; a2=a2->next) { + if (strcasecmp(a2->name, t->u1.str)==0) { + for (v2=a2->setvars; v2; v2=v2->next) { + if (strcmp(v2->name, buff1) == 0) { + /* found an app that sets the var */ + f1 = 1; + break; + } + } + } + if (f1) + break; + } + } + if (f1) + break; + } + + /* see if it sets the var */ + if (!f1) { + ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: Couldn't find an application call in this extension that sets the expression (%s) value!\n", + item->filename, item->startline, item->endline, item->u1.str); + warns++; + } + } +#else + pval *t,*tl=0,*p2; + int def= 0; + + /* first of all, does this switch have a default case ? */ + for (t=item->u2.statements; t; t=t->next) { + if (t->type == PV_DEFAULT) { + def =1; + break; + } + tl = t; + } + if (def) /* nothing to check. All cases accounted for! */ + return; + /* if no default, warn and insert a default case at the end */ + p2 = tl->next = calloc(1, sizeof(struct pval)); + + p2->type = PV_DEFAULT; + p2->startline = tl->startline; + p2->endline = tl->endline; + p2->startcol = tl->startcol; + p2->endcol = tl->endcol; + p2->filename = strdup(tl->filename); + ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: A default case was automatically added to the switch.\n", + p2->filename, p2->startline, p2->endline); + warns++; + +#endif +} + +static void check_context_names(void) +{ + pval *i,*j; + for (i=current_db; i; i=i->next) { + if (i->type == PV_CONTEXT || i->type == PV_MACRO) { + for (j=i->next; j; j=j->next) { + if ( j->type == PV_CONTEXT || j->type == PV_MACRO ) { + if ( !strcmp(i->u1.str, j->u1.str) && !(i->u3.abstract&2) && !(j->u3.abstract&2) ) + { + ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: The context name (%s) is also declared in file %s, line %d-%d! (and neither is marked 'extend')\n", + i->filename, i->startline, i->endline, i->u1.str, j->filename, j->startline, j->endline); + warns++; + } + } + } + } + } +} + +static void check_abstract_reference(pval *abstract_context) +{ + pval *i,*j; + /* find some context includes that reference this context */ + + + /* otherwise, print out a warning */ + for (i=current_db; i; i=i->next) { + if (i->type == PV_CONTEXT) { + for (j=i->u2. statements; j; j=j->next) { + if ( j->type == PV_INCLUDES ) { + struct pval *p4; + for (p4=j->u1.list; p4; p4=p4->next) { + /* for each context pointed to, find it, then find a context/label that matches the + target here! */ + if ( !strcmp(p4->u1.str, abstract_context->u1.str) ) + return; /* found a match! */ + } + } + } + } + } + ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: Couldn't find a reference to this abstract context (%s) in any other context!\n", + abstract_context->filename, abstract_context->startline, abstract_context->endline, abstract_context->u1.str); + warns++; +} + + +void check_pval_item(pval *item, struct argapp *apps, int in_globals) +{ + pval *lp; +#ifdef AAL_ARGCHECK + struct argapp *app, *found; +#endif + struct pval *macro_def; + struct pval *app_def; + + char errmsg[4096]; + char *strp; + + switch (item->type) { + case PV_WORD: + /* fields: item->u1.str == string associated with this (word). + item->u2.arglist == pval list of 4 PV_WORD elements for time values (only in PV_INCLUDES) */ + break; + + case PV_MACRO: + /* fields: item->u1.str == name of macro + item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user + item->u2.arglist->u1.str == argument + item->u2.arglist->next == next arg + + item->u3.macro_statements == pval list of statements in macro body. + */ + in_abstract_context = 0; + current_context = item; + current_extension = 0; + + check_macro_returns(item); + + for (lp=item->u2.arglist; lp; lp=lp->next) { + + } + check_pval(item->u3.macro_statements, apps,in_globals); + break; + + case PV_CONTEXT: + /* fields: item->u1.str == name of context + item->u2.statements == pval list of statements in context body + item->u3.abstract == int 1 if an abstract keyword were present + */ + current_context = item; + current_extension = 0; + if ( item->u3.abstract ) { + in_abstract_context = 1; + check_abstract_reference(item); + } else + in_abstract_context = 0; + check_pval(item->u2.statements, apps,in_globals); + break; + + case PV_MACRO_CALL: + /* fields: item->u1.str == name of macro to call + item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user + item->u2.arglist->u1.str == argument + item->u2.arglist->next == next arg + */ +#ifdef STANDALONE + /* if this is a standalone, we will need to make sure the + localized load of extensions.conf is done */ + if (!extensions_dot_conf_loaded) { + localized_pbx_load_module(); + extensions_dot_conf_loaded++; + } +#endif + macro_def = find_macro(item->u1.str); + if (!macro_def) { +#ifdef STANDALONE + struct pbx_find_info pfiq = {.stacklen = 0 }; + struct pbx_find_info pfiq2 = {.stacklen = 0 }; + + /* look for the macro in the extensions.conf world */ + pbx_find_extension(NULL, NULL, &pfiq, item->u1.str, "s", 1, NULL, NULL, E_MATCH); + + if (pfiq.status != STATUS_SUCCESS) { + char namebuf2[256]; + snprintf(namebuf2, 256, "macro-%s", item->u1.str); + + /* look for the macro in the extensions.conf world */ + pbx_find_extension(NULL, NULL, &pfiq2, namebuf2, "s", 1, NULL, NULL, E_MATCH); + + if (pfiq2.status == STATUS_SUCCESS) { + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to non-existent %s! (macro-%s was found in the extensions.conf stuff, but we are using gosubs!)\n", + item->filename, item->startline, item->endline, item->u1.str, item->u1.str); + warns++; + } else { + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to non-existent %s! (Not even in the extensions.conf stuff!)\n", + item->filename, item->startline, item->endline, item->u1.str); + warns++; + } + } +#else + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to %s cannot be found in the AEL code!\n", + item->filename, item->startline, item->endline, item->u1.str); + warns++; + +#endif +#ifdef THIS_IS_1DOT4 + char namebuf2[256]; + snprintf(namebuf2, 256, "macro-%s", item->u1.str); + + /* look for the macro in the extensions.conf world */ + pbx_find_extension(NULL, NULL, &pfiq, namebuf2, "s", 1, NULL, NULL, E_MATCH); + + if (pfiq.status != STATUS_SUCCESS) { + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to %s was not found in the AEL, nor the extensions.conf !\n", + item->filename, item->startline, item->endline, item->u1.str); + warns++; + } + +#endif + + } else if (macro_def->type != PV_MACRO) { + ast_log(LOG_ERROR,"Error: file %s, line %d-%d: macro call to %s references a context, not a macro!\n", + item->filename, item->startline, item->endline, item->u1.str); + errs++; + } else { + /* macro_def is a MACRO, so do the args match in number? */ + int hereargs = 0; + int thereargs = 0; + + for (lp=item->u2.arglist; lp; lp=lp->next) { + hereargs++; + } + for (lp=macro_def->u2.arglist; lp; lp=lp->next) { + thereargs++; + } + if (hereargs != thereargs ) { + ast_log(LOG_ERROR, "Error: file %s, line %d-%d: The macro call to %s has %d arguments, but the macro definition has %d arguments\n", + item->filename, item->startline, item->endline, item->u1.str, hereargs, thereargs); + errs++; + } + } + break; + + case PV_APPLICATION_CALL: + /* fields: item->u1.str == name of application to call + item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user + item->u2.arglist->u1.str == argument + item->u2.arglist->next == next arg + */ + /* Need to check to see if the application is available! */ + app_def = find_context(item->u1.str); + if (app_def && app_def->type == PV_MACRO) { + ast_log(LOG_ERROR,"Error: file %s, line %d-%d: application call to %s references an existing macro, but had no & preceding it!\n", + item->filename, item->startline, item->endline, item->u1.str); + errs++; + } + if (strcasecmp(item->u1.str,"GotoIf") == 0 + || strcasecmp(item->u1.str,"GotoIfTime") == 0 + || strcasecmp(item->u1.str,"while") == 0 + || strcasecmp(item->u1.str,"endwhile") == 0 + || strcasecmp(item->u1.str,"random") == 0 + || strcasecmp(item->u1.str,"gosub") == 0 + || strcasecmp(item->u1.str,"return") == 0 + || strcasecmp(item->u1.str,"gosubif") == 0 + || strcasecmp(item->u1.str,"continuewhile") == 0 + || strcasecmp(item->u1.str,"endwhile") == 0 + || strcasecmp(item->u1.str,"execif") == 0 + || strcasecmp(item->u1.str,"execiftime") == 0 + || strcasecmp(item->u1.str,"exitwhile") == 0 + || strcasecmp(item->u1.str,"goto") == 0 + || strcasecmp(item->u1.str,"macro") == 0 + || strcasecmp(item->u1.str,"macroexclusive") == 0 + || strcasecmp(item->u1.str,"macroif") == 0 + || strcasecmp(item->u1.str,"stackpop") == 0 + || strcasecmp(item->u1.str,"execIf") == 0 ) { + ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: application call to %s affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!\n", + item->filename, item->startline, item->endline, item->u1.str); + warns++; + } + if (strcasecmp(item->u1.str,"macroexit") == 0) { + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: I am converting the MacroExit call here to a return statement.\n", + item->filename, item->startline, item->endline); + item->type = PV_RETURN; + free(item->u1.str); + item->u1.str = 0; + } + +#ifdef AAL_ARGCHECK + found = 0; + for (app=apps; app; app=app->next) { + if (strcasecmp(app->name, item->u1.str) == 0) { + found =app; + break; + } + } + if (!found) { + ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: application call to %s not listed in applist database!\n", + item->filename, item->startline, item->endline, item->u1.str); + warns++; + } else + check_app_args(item, item->u2.arglist, app); +#endif + break; + + case PV_CASE: + /* fields: item->u1.str == value of case + item->u2.statements == pval list of statements under the case + */ + /* Make sure sequence of statements under case is terminated with goto, return, or break */ + /* find the last statement */ + check_pval(item->u2.statements, apps,in_globals); + break; + + case PV_PATTERN: + /* fields: item->u1.str == value of case + item->u2.statements == pval list of statements under the case + */ + /* Make sure sequence of statements under case is terminated with goto, return, or break */ + /* find the last statement */ + + check_pval(item->u2.statements, apps,in_globals); + break; + + case PV_DEFAULT: + /* fields: + item->u2.statements == pval list of statements under the case + */ + + check_pval(item->u2.statements, apps,in_globals); + break; + + case PV_CATCH: + /* fields: item->u1.str == name of extension to catch + item->u2.statements == pval list of statements in context body + */ + check_pval(item->u2.statements, apps,in_globals); + break; + + case PV_SWITCHES: + /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list + */ + check_pval(item->u1.list, apps,in_globals); + break; + + case PV_ESWITCHES: + /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list + */ + check_pval(item->u1.list, apps,in_globals); + break; + + case PV_INCLUDES: + /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list + */ + check_pval(item->u1.list, apps,in_globals); + check_includes(item); + for (lp=item->u1.list; lp; lp=lp->next){ + char *incl_context = lp->u1.str; + struct pval *that_context = find_context(incl_context); + + if ( lp->u2.arglist ) { + check_timerange(lp->u2.arglist); + check_dow(lp->u2.arglist->next); + check_day(lp->u2.arglist->next->next); + check_month(lp->u2.arglist->next->next->next); + } + + if (that_context) { + find_pval_gotos(that_context->u2.statements,0); + + } + } + break; + + case PV_STATEMENTBLOCK: + /* fields: item->u1.list == pval list of statements in block, one per entry in the list + */ + check_pval(item->u1.list, apps,in_globals); + break; + + case PV_VARDEC: + /* fields: item->u1.str == variable name + item->u2.val == variable value to assign + */ + /* the RHS of a vardec is encapsulated in a $[] expr. Is it legal? */ + if( !in_globals ) { /* don't check stuff inside the globals context; no wrapping in $[ ] there... */ + snprintf(errmsg,sizeof(errmsg), "file %s, line %d, columns %d-%d, variable declaration expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u2.val); + ast_expr_register_extra_error_info(errmsg); + ast_expr(item->u2.val, expr_output, sizeof(expr_output),NULL); + ast_expr_clear_extra_error_info(); + if ( strpbrk(item->u2.val,"~!-+<>=*/&^") && !strstr(item->u2.val,"${") ) { + ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n", + item->filename, item->startline, item->endline, item->u2.val); + warns++; + } + check_expr2_input(item,item->u2.val); + } + break; + + case PV_LOCALVARDEC: + /* fields: item->u1.str == variable name + item->u2.val == variable value to assign + */ + /* the RHS of a vardec is encapsulated in a $[] expr. Is it legal? */ + snprintf(errmsg,sizeof(errmsg), "file %s, line %d, columns %d-%d, variable declaration expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u2.val); + ast_expr_register_extra_error_info(errmsg); + ast_expr(item->u2.val, expr_output, sizeof(expr_output),NULL); + ast_expr_clear_extra_error_info(); + if ( strpbrk(item->u2.val,"~!-+<>=*/&^") && !strstr(item->u2.val,"${") ) { + ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n", + item->filename, item->startline, item->endline, item->u2.val); + warns++; + } + check_expr2_input(item,item->u2.val); + break; + + case PV_GOTO: + /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user. + item->u1.list->u1.str == where the data on a PV_WORD will always be. + */ + /* don't check goto's in abstract contexts */ + if ( in_abstract_context ) + break; + + check_goto(item); + break; + + case PV_LABEL: + /* fields: item->u1.str == label name + */ + if ( strspn(item->u1.str, "0123456789") == strlen(item->u1.str) ) { + ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: label '%s' is numeric, this is bad practice!\n", + item->filename, item->startline, item->endline, item->u1.str); + warns++; + } + + check_label(item); + break; + + case PV_FOR: + /* fields: item->u1.for_init == a string containing the initalizer + item->u2.for_test == a string containing the loop test + item->u3.for_inc == a string containing the loop increment + + item->u4.for_statements == a pval list of statements in the for () + */ + snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, for test expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u2.for_test); + ast_expr_register_extra_error_info(errmsg); + + strp = strchr(item->u1.for_init, '='); + if (strp) { + ast_expr(strp+1, expr_output, sizeof(expr_output),NULL); + } + ast_expr(item->u2.for_test, expr_output, sizeof(expr_output),NULL); + strp = strchr(item->u3.for_inc, '='); + if (strp) { + ast_expr(strp+1, expr_output, sizeof(expr_output),NULL); + } + if ( strpbrk(item->u2.for_test,"~!-+<>=*/&^") && !strstr(item->u2.for_test,"${") ) { + ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n", + item->filename, item->startline, item->endline, item->u2.for_test); + warns++; + } + if ( strpbrk(item->u3.for_inc,"~!-+<>=*/&^") && !strstr(item->u3.for_inc,"${") ) { + ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n", + item->filename, item->startline, item->endline, item->u3.for_inc); + warns++; + } + check_expr2_input(item,item->u2.for_test); + check_expr2_input(item,item->u3.for_inc); + + ast_expr_clear_extra_error_info(); + check_pval(item->u4.for_statements, apps,in_globals); + break; + + case PV_WHILE: + /* fields: item->u1.str == the while conditional, as supplied by user + + item->u2.statements == a pval list of statements in the while () + */ + snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, while expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u1.str); + ast_expr_register_extra_error_info(errmsg); + ast_expr(item->u1.str, expr_output, sizeof(expr_output),NULL); + ast_expr_clear_extra_error_info(); + if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) { + ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n", + item->filename, item->startline, item->endline, item->u1.str); + warns++; + } + check_expr2_input(item,item->u1.str); + check_pval(item->u2.statements, apps,in_globals); + break; + + case PV_BREAK: + /* fields: none + */ + check_break(item); + break; + + case PV_RETURN: + /* fields: none + */ + break; + + case PV_CONTINUE: + /* fields: none + */ + check_continue(item); + break; + + case PV_RANDOM: + /* fields: item->u1.str == the random number expression, as supplied by user + + item->u2.statements == a pval list of statements in the if () + item->u3.else_statements == a pval list of statements in the else + (could be zero) + */ + snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, random expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u1.str); + ast_expr_register_extra_error_info(errmsg); + ast_expr(item->u1.str, expr_output, sizeof(expr_output),NULL); + ast_expr_clear_extra_error_info(); + if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) { + ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: random expression '%s' has operators, but no variables. Interesting...\n", + item->filename, item->startline, item->endline, item->u1.str); + warns++; + } + check_expr2_input(item,item->u1.str); + check_pval(item->u2.statements, apps,in_globals); + if (item->u3.else_statements) { + check_pval(item->u3.else_statements, apps,in_globals); + } + break; + + case PV_IFTIME: + /* fields: item->u1.list == the if time values, 4 of them, each in PV_WORD, linked list + + item->u2.statements == a pval list of statements in the if () + item->u3.else_statements == a pval list of statements in the else + (could be zero) + */ + if ( item->u2.arglist ) { + check_timerange(item->u1.list); + check_dow(item->u1.list->next); + check_day(item->u1.list->next->next); + check_month(item->u1.list->next->next->next); + } + + check_pval(item->u2.statements, apps,in_globals); + if (item->u3.else_statements) { + check_pval(item->u3.else_statements, apps,in_globals); + } + break; + + case PV_IF: + /* fields: item->u1.str == the if conditional, as supplied by user + + item->u2.statements == a pval list of statements in the if () + item->u3.else_statements == a pval list of statements in the else + (could be zero) + */ + snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, if expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u1.str); + ast_expr_register_extra_error_info(errmsg); + ast_expr(item->u1.str, expr_output, sizeof(expr_output),NULL); + ast_expr_clear_extra_error_info(); + if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) { + ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression '%s' has operators, but no variables. Interesting...\n", + item->filename, item->startline, item->endline, item->u1.str); + warns++; + } + check_expr2_input(item,item->u1.str); + check_pval(item->u2.statements, apps,in_globals); + if (item->u3.else_statements) { + check_pval(item->u3.else_statements, apps,in_globals); + } + break; + + case PV_SWITCH: + /* fields: item->u1.str == the switch expression + + item->u2.statements == a pval list of statements in the switch, + (will be case statements, most likely!) + */ + /* we can check the switch expression, see if it matches any of the app variables... + if it does, then, are all the possible cases accounted for? */ + check_switch_expr(item, apps); + check_pval(item->u2.statements, apps,in_globals); + break; + + case PV_EXTENSION: + /* fields: item->u1.str == the extension name, label, whatever it's called + + item->u2.statements == a pval list of statements in the extension + item->u3.hints == a char * hint argument + item->u4.regexten == an int boolean. non-zero says that regexten was specified + */ + current_extension = item ; + + check_pval(item->u2.statements, apps,in_globals); + break; + + case PV_IGNOREPAT: + /* fields: item->u1.str == the ignorepat data + */ + break; + + case PV_GLOBALS: + /* fields: item->u1.statements == pval list of statements, usually vardecs + */ + in_abstract_context = 0; + check_pval(item->u1.statements, apps, 1); + break; + default: + break; + } +} + +void check_pval(pval *item, struct argapp *apps, int in_globals) +{ + pval *i; + + /* checks to do: + 1. Do goto's point to actual labels? + 2. Do macro calls reference a macro? + 3. Does the number of macro args match the definition? + 4. Is a macro call missing its & at the front? + 5. Application calls-- we could check syntax for existing applications, + but I need some some sort of universal description bnf for a general + sort of method for checking arguments, in number, maybe even type, at least. + Don't want to hand code checks for hundreds of applications. + */ + + for (i=item; i; i=i->next) { + check_pval_item(i,apps,in_globals); + } +} + +void ael2_semantic_check(pval *item, int *arg_errs, int *arg_warns, int *arg_notes) +{ + +#ifdef AAL_ARGCHECK + int argapp_errs =0; + char *rfilename; +#endif + struct argapp *apps=0; + + if (!item) + return; /* don't check an empty tree */ +#ifdef AAL_ARGCHECK + rfilename = alloca(10 + strlen(ast_config_AST_VAR_DIR)); + sprintf(rfilename, "%s/applist", ast_config_AST_VAR_DIR); + + apps = argdesc_parse(rfilename, &argapp_errs); /* giveth */ +#endif + current_db = item; + errs = warns = notes = 0; + + check_context_names(); + check_pval(item, apps, 0); + +#ifdef AAL_ARGCHECK + argdesc_destroy(apps); /* taketh away */ +#endif + current_db = 0; + + *arg_errs = errs; + *arg_warns = warns; + *arg_notes = notes; +} + +/* =============================================================================================== */ +/* "CODE" GENERATOR -- Convert the AEL representation to asterisk extension language */ +/* =============================================================================================== */ + +static int control_statement_count = 0; + +struct ael_priority *new_prio(void) +{ + struct ael_priority *x = (struct ael_priority *)calloc(sizeof(struct ael_priority),1); + return x; +} + +struct ael_extension *new_exten(void) +{ + struct ael_extension *x = (struct ael_extension *)calloc(sizeof(struct ael_extension),1); + return x; +} + +void linkprio(struct ael_extension *exten, struct ael_priority *prio) +{ + if (!exten->plist) { + exten->plist = prio; + exten->plist_last = prio; + } else { + exten->plist_last->next = prio; + exten->plist_last = prio; + } + if( !prio->exten ) + prio->exten = exten; /* don't override the switch value */ +} + +void destroy_extensions(struct ael_extension *exten) +{ + struct ael_extension *ne, *nen; + for (ne=exten; ne; ne=nen) { + struct ael_priority *pe, *pen; + + if (ne->name) + free(ne->name); + + /* cidmatch fields are allocated with name, and freed when + the name field is freed. Don't do a free for this field, + unless you LIKE to see a crash! */ + + if (ne->hints) + free(ne->hints); + + for (pe=ne->plist; pe; pe=pen) { + pen = pe->next; + if (pe->app) + free(pe->app); + pe->app = 0; + if (pe->appargs) + free(pe->appargs); + pe->appargs = 0; + pe->origin = 0; + pe->goto_true = 0; + pe->goto_false = 0; + free(pe); + } + nen = ne->next_exten; + ne->next_exten = 0; + ne->plist =0; + ne->plist_last = 0; + ne->next_exten = 0; + ne->loop_break = 0; + ne->loop_continue = 0; + free(ne); + } +} + +static int label_inside_case(pval *label) +{ + pval *p = label; + + while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) /* early cutout, sort of */ { + if( p->type == PV_CASE || p->type == PV_DEFAULT || p->type == PV_PATTERN ) { + return 1; + } + + p = p->dad; + } + return 0; +} + +static void linkexten(struct ael_extension *exten, struct ael_extension *add) +{ + add->next_exten = exten->next_exten; /* this will reverse the order. Big deal. */ + exten->next_exten = add; +} + +static void remove_spaces_before_equals(char *str) +{ + char *p; + while( str && *str && *str != '=' ) + { + if( *str == ' ' || *str == '\n' || *str == '\r' || *str == '\t' ) + { + p = str; + while( *p ) + { + *p = *(p+1); + p++; + } + } + else + str++; + } +} + +/* =============================================================================================== */ +/* "CODE" GENERATOR -- Convert the AEL representation to asterisk extension language */ +/* =============================================================================================== */ + +static void gen_match_to_pattern(char *pattern, char *result) +{ + /* the result will be a string that will be matched by pattern */ + char *p=pattern, *t=result; + while (*p) { + if (*p == 'x' || *p == 'n' || *p == 'z' || *p == 'X' || *p == 'N' || *p == 'Z') + *t++ = '9'; + else if (*p == '[') { + char *z = p+1; + while (*z != ']') + z++; + if (*(z+1)== ']') + z++; + *t++=*(p+1); /* use the first char in the set */ + p = z; + } else { + *t++ = *p; + } + p++; + } + *t++ = 0; /* cap it off */ +} + +static void gen_prios(struct ael_extension *exten, char *label, pval *statement, struct ael_extension *mother_exten, struct ast_context *this_context ) +{ + pval *p,*p2,*p3; + struct ael_priority *pr; + struct ael_priority *for_init, *for_test, *for_inc, *for_loop, *for_end; + struct ael_priority *while_test, *while_loop, *while_end; + struct ael_priority *switch_test, *switch_end, *fall_thru, *switch_empty; + struct ael_priority *if_test, *if_end, *if_skip, *if_false; +#ifdef OLD_RAND_ACTION + struct ael_priority *rand_test, *rand_end, *rand_skip; +#endif + char buf1[2000]; + char buf2[2000]; + char *strp, *strp2; + char new_label[2000]; + int default_exists; + int local_control_statement_count; + int first; + struct ael_priority *loop_break_save; + struct ael_priority *loop_continue_save; + struct ael_extension *switch_case,*switch_null; + + for (p=statement; p; p=p->next) { + switch (p->type) { + case PV_VARDEC: + pr = new_prio(); + pr->type = AEL_APPCALL; + snprintf(buf1,sizeof(buf1),"%s=$[%s]", p->u1.str, p->u2.val); + pr->app = strdup("Set"); + remove_spaces_before_equals(buf1); + pr->appargs = strdup(buf1); + pr->origin = p; + linkprio(exten, pr); + break; + + case PV_LOCALVARDEC: + pr = new_prio(); + pr->type = AEL_APPCALL; + snprintf(buf1,sizeof(buf1),"LOCAL(%s)=$[%s]", p->u1.str, p->u2.val); + pr->app = strdup("Set"); + remove_spaces_before_equals(buf1); + pr->appargs = strdup(buf1); + pr->origin = p; + linkprio(exten, pr); + break; + + case PV_GOTO: + pr = new_prio(); + pr->type = AEL_APPCALL; + p->u2.goto_target = get_goto_target(p); + if( p->u2.goto_target ) { + p->u3.goto_target_in_case = p->u2.goto_target->u2.label_in_case = label_inside_case(p->u2.goto_target); + } + + if (!p->u1.list->next) /* just one */ { + pr->app = strdup("Goto"); + if (!mother_exten) + pr->appargs = strdup(p->u1.list->u1.str); + else { /* for the case of simple within-extension gotos in case/pattern/default statement blocks: */ + snprintf(buf1,sizeof(buf1),"%s,%s", mother_exten->name, p->u1.list->u1.str); + pr->appargs = strdup(buf1); + } + + } else if (p->u1.list->next && !p->u1.list->next->next) /* two */ { + snprintf(buf1,sizeof(buf1),"%s,%s", p->u1.list->u1.str, p->u1.list->next->u1.str); + pr->app = strdup("Goto"); + pr->appargs = strdup(buf1); + } else if (p->u1.list->next && p->u1.list->next->next) { + snprintf(buf1,sizeof(buf1),"%s,%s,%s", p->u1.list->u1.str, + p->u1.list->next->u1.str, + p->u1.list->next->next->u1.str); + pr->app = strdup("Goto"); + pr->appargs = strdup(buf1); + } + pr->origin = p; + linkprio(exten, pr); + break; + + case PV_LABEL: + pr = new_prio(); + pr->type = AEL_LABEL; + pr->origin = p; + p->u3.compiled_label = exten; + linkprio(exten, pr); + break; + + case PV_FOR: + control_statement_count++; + loop_break_save = exten->loop_break; /* save them, then restore before leaving */ + loop_continue_save = exten->loop_continue; + snprintf(new_label,sizeof(new_label),"for-%s-%d", label, control_statement_count); + for_init = new_prio(); + for_inc = new_prio(); + for_test = new_prio(); + for_loop = new_prio(); + for_end = new_prio(); + for_init->type = AEL_APPCALL; + for_inc->type = AEL_APPCALL; + for_test->type = AEL_FOR_CONTROL; + for_test->goto_false = for_end; + for_loop->type = AEL_CONTROL1; /* simple goto */ + for_end->type = AEL_APPCALL; + for_init->app = strdup("Set"); + + strcpy(buf2,p->u1.for_init); + remove_spaces_before_equals(buf2); + strp = strchr(buf2, '='); + if (strp) { + strp2 = strchr(p->u1.for_init, '='); + *(strp+1) = 0; + strcat(buf2,"$["); + strncat(buf2,strp2+1, sizeof(buf2)-strlen(strp2+1)-2); + strcat(buf2,"]"); + for_init->appargs = strdup(buf2); + } else { + strp2 = p->u1.for_init; + while (*strp2 && isspace(*strp2)) + strp2++; + if (*strp2 == '&') { /* itsa macro call */ + char *strp3 = strp2+1; + while (*strp3 && isspace(*strp3)) + strp3++; + strcpy(buf2, strp3); + strp3 = strchr(buf2,'('); + if (strp3) { + *strp3 = '|'; + } + while ((strp3=strchr(buf2,','))) { + *strp3 = '|'; + } + strp3 = strrchr(buf2, ')'); + if (strp3) + *strp3 = 0; /* remove the closing paren */ + + for_init->appargs = strdup(buf2); + free(for_init->app); + for_init->app = strdup("Macro"); + } else { /* must be a regular app call */ + char *strp3; + strcpy(buf2, strp2); + strp3 = strchr(buf2,'('); + if (strp3) { + *strp3 = 0; + free(for_init->app); + for_init->app = strdup(buf2); + for_init->appargs = strdup(strp3+1); + strp3 = strrchr(for_init->appargs, ')'); + if (strp3) + *strp3 = 0; /* remove the closing paren */ + } + } + } + + strcpy(buf2,p->u3.for_inc); + remove_spaces_before_equals(buf2); + strp = strchr(buf2, '='); + if (strp) { /* there's an = in this part; that means an assignment. set it up */ + strp2 = strchr(p->u3.for_inc, '='); + *(strp+1) = 0; + strcat(buf2,"$["); + strncat(buf2,strp2+1, sizeof(buf2)-strlen(strp2+1)-2); + strcat(buf2,"]"); + for_inc->appargs = strdup(buf2); + for_inc->app = strdup("Set"); + } else { + strp2 = p->u3.for_inc; + while (*strp2 && isspace(*strp2)) + strp2++; + if (*strp2 == '&') { /* itsa macro call */ + char *strp3 = strp2+1; + while (*strp3 && isspace(*strp3)) + strp3++; + strcpy(buf2, strp3); + strp3 = strchr(buf2,'('); + if (strp3) { + *strp3 = ','; + } + strp3 = strrchr(buf2, ')'); + if (strp3) + *strp3 = 0; /* remove the closing paren */ + + for_inc->appargs = strdup(buf2); + + for_inc->app = strdup("Macro"); + } else { /* must be a regular app call */ + char *strp3; + strcpy(buf2, strp2); + strp3 = strchr(buf2,'('); + if (strp3) { + *strp3 = 0; + for_inc->app = strdup(buf2); + for_inc->appargs = strdup(strp3+1); + strp3 = strrchr(for_inc->appargs, ')'); + if (strp3) + *strp3 = 0; /* remove the closing paren */ + } + } + } + snprintf(buf1,sizeof(buf1),"$[%s]",p->u2.for_test); + for_test->app = 0; + for_test->appargs = strdup(buf1); + for_loop->goto_true = for_test; + snprintf(buf1,sizeof(buf1),"Finish for-%s-%d", label, control_statement_count); + for_end->app = strdup("NoOp"); + for_end->appargs = strdup(buf1); + /* link & load! */ + linkprio(exten, for_init); + linkprio(exten, for_test); + + /* now, put the body of the for loop here */ + exten->loop_break = for_end; + exten->loop_continue = for_inc; + + gen_prios(exten, new_label, p->u4.for_statements, mother_exten, this_context); /* this will link in all the statements here */ + + linkprio(exten, for_inc); + linkprio(exten, for_loop); + linkprio(exten, for_end); + + + exten->loop_break = loop_break_save; + exten->loop_continue = loop_continue_save; + for_loop->origin = p; + break; + + case PV_WHILE: + control_statement_count++; + loop_break_save = exten->loop_break; /* save them, then restore before leaving */ + loop_continue_save = exten->loop_continue; + snprintf(new_label,sizeof(new_label),"while-%s-%d", label, control_statement_count); + while_test = new_prio(); + while_loop = new_prio(); + while_end = new_prio(); + while_test->type = AEL_FOR_CONTROL; + while_test->goto_false = while_end; + while_loop->type = AEL_CONTROL1; /* simple goto */ + while_end->type = AEL_APPCALL; + snprintf(buf1,sizeof(buf1),"$[%s]",p->u1.str); + while_test->app = 0; + while_test->appargs = strdup(buf1); + while_loop->goto_true = while_test; + snprintf(buf1,sizeof(buf1),"Finish while-%s-%d", label, control_statement_count); + while_end->app = strdup("NoOp"); + while_end->appargs = strdup(buf1); + + linkprio(exten, while_test); + + /* now, put the body of the for loop here */ + exten->loop_break = while_end; + exten->loop_continue = while_test; + + gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context); /* this will link in all the while body statements here */ + + linkprio(exten, while_loop); + linkprio(exten, while_end); + + + exten->loop_break = loop_break_save; + exten->loop_continue = loop_continue_save; + while_loop->origin = p; + break; + + case PV_SWITCH: + control_statement_count++; + local_control_statement_count = control_statement_count; + loop_break_save = exten->loop_break; /* save them, then restore before leaving */ + loop_continue_save = exten->loop_continue; + snprintf(new_label,sizeof(new_label),"sw-%s-%d", label, control_statement_count); + + switch_test = new_prio(); + switch_end = new_prio(); + switch_test->type = AEL_APPCALL; + switch_end->type = AEL_APPCALL; + snprintf(buf1,sizeof(buf1),"sw-%d-%s,10",control_statement_count, p->u1.str); + switch_test->app = strdup("Goto"); + switch_test->appargs = strdup(buf1); + snprintf(buf1,sizeof(buf1),"Finish switch-%s-%d", label, control_statement_count); + switch_end->app = strdup("NoOp"); + switch_end->appargs = strdup(buf1); + switch_end->origin = p; + switch_end->exten = exten; + + linkprio(exten, switch_test); + linkprio(exten, switch_end); + + exten->loop_break = switch_end; + exten->loop_continue = 0; + default_exists = 0; + + for (p2=p->u2.statements; p2; p2=p2->next) { + /* now, for each case/default put the body of the for loop here */ + if (p2->type == PV_CASE) { + /* ok, generate a extension and link it in */ + switch_case = new_exten(); + switch_case->context = this_context; + switch_case->is_switch = 1; + /* the break/continue locations are inherited from parent */ + switch_case->loop_break = exten->loop_break; + switch_case->loop_continue = exten->loop_continue; + + linkexten(exten,switch_case); + snprintf(buf1,sizeof(buf1),"sw-%d-%s", local_control_statement_count, p2->u1.str); + switch_case->name = strdup(buf1); + snprintf(new_label,sizeof(new_label),"sw-%s-%s-%d", label, p2->u1.str, local_control_statement_count); + + gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context); /* this will link in all the case body statements here */ + + /* here is where we write code to "fall thru" to the next case... if there is one... */ + for (p3=p2->u2.statements; p3; p3=p3->next) { + if (!p3->next) + break; + } + /* p3 now points the last statement... */ + if (!p3 || ( p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN) ) { + /* is there a following CASE/PATTERN/DEFAULT? */ + if (p2->next && p2->next->type == PV_CASE) { + fall_thru = new_prio(); + fall_thru->type = AEL_APPCALL; + fall_thru->app = strdup("Goto"); + snprintf(buf1,sizeof(buf1),"sw-%d-%s,10",local_control_statement_count, p2->next->u1.str); + fall_thru->appargs = strdup(buf1); + linkprio(switch_case, fall_thru); + } else if (p2->next && p2->next->type == PV_PATTERN) { + fall_thru = new_prio(); + fall_thru->type = AEL_APPCALL; + fall_thru->app = strdup("Goto"); + gen_match_to_pattern(p2->next->u1.str, buf2); + snprintf(buf1,sizeof(buf1),"sw-%d-%s,10", local_control_statement_count, buf2); + fall_thru->appargs = strdup(buf1); + linkprio(switch_case, fall_thru); + } else if (p2->next && p2->next->type == PV_DEFAULT) { + fall_thru = new_prio(); + fall_thru->type = AEL_APPCALL; + fall_thru->app = strdup("Goto"); + snprintf(buf1,sizeof(buf1),"sw-%d-.,10",local_control_statement_count); + fall_thru->appargs = strdup(buf1); + linkprio(switch_case, fall_thru); + } else if (!p2->next) { + fall_thru = new_prio(); + fall_thru->type = AEL_CONTROL1; + fall_thru->goto_true = switch_end; + fall_thru->app = strdup("Goto"); + linkprio(switch_case, fall_thru); + } + } + if (switch_case->return_needed) { /* returns don't generate a goto eoe (end of extension) any more, just a Return() app call) */ + char buf[2000]; + struct ael_priority *np2 = new_prio(); + np2->type = AEL_APPCALL; + np2->app = strdup("NoOp"); + snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name); + np2->appargs = strdup(buf); + linkprio(switch_case, np2); + switch_case-> return_target = np2; + } + } else if (p2->type == PV_PATTERN) { + /* ok, generate a extension and link it in */ + switch_case = new_exten(); + switch_case->context = this_context; + switch_case->is_switch = 1; + /* the break/continue locations are inherited from parent */ + switch_case->loop_break = exten->loop_break; + switch_case->loop_continue = exten->loop_continue; + + linkexten(exten,switch_case); + snprintf(buf1,sizeof(buf1),"_sw-%d-%s", local_control_statement_count, p2->u1.str); + switch_case->name = strdup(buf1); + snprintf(new_label,sizeof(new_label),"sw-%s-%s-%d", label, p2->u1.str, local_control_statement_count); + + gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context); /* this will link in all the while body statements here */ + /* here is where we write code to "fall thru" to the next case... if there is one... */ + for (p3=p2->u2.statements; p3; p3=p3->next) { + if (!p3->next) + break; + } + /* p3 now points the last statement... */ + if (!p3 || ( p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN)) { + /* is there a following CASE/PATTERN/DEFAULT? */ + if (p2->next && p2->next->type == PV_CASE) { + fall_thru = new_prio(); + fall_thru->type = AEL_APPCALL; + fall_thru->app = strdup("Goto"); + snprintf(buf1,sizeof(buf1),"sw-%d-%s,10",local_control_statement_count, p2->next->u1.str); + fall_thru->appargs = strdup(buf1); + linkprio(switch_case, fall_thru); + } else if (p2->next && p2->next->type == PV_PATTERN) { + fall_thru = new_prio(); + fall_thru->type = AEL_APPCALL; + fall_thru->app = strdup("Goto"); + gen_match_to_pattern(p2->next->u1.str, buf2); + snprintf(buf1,sizeof(buf1),"sw-%d-%s,10",local_control_statement_count, buf2); + fall_thru->appargs = strdup(buf1); + linkprio(switch_case, fall_thru); + } else if (p2->next && p2->next->type == PV_DEFAULT) { + fall_thru = new_prio(); + fall_thru->type = AEL_APPCALL; + fall_thru->app = strdup("Goto"); + snprintf(buf1,sizeof(buf1),"sw-%d-.,10",local_control_statement_count); + fall_thru->appargs = strdup(buf1); + linkprio(switch_case, fall_thru); + } else if (!p2->next) { + fall_thru = new_prio(); + fall_thru->type = AEL_CONTROL1; + fall_thru->goto_true = switch_end; + fall_thru->app = strdup("Goto"); + linkprio(switch_case, fall_thru); + } + } + if (switch_case->return_needed) { /* returns don't generate a goto eoe (end of extension) any more, just a Return() app call) */ + char buf[2000]; + struct ael_priority *np2 = new_prio(); + np2->type = AEL_APPCALL; + np2->app = strdup("NoOp"); + snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name); + np2->appargs = strdup(buf); + linkprio(switch_case, np2); + switch_case-> return_target = np2; + } + } else if (p2->type == PV_DEFAULT) { + /* ok, generate a extension and link it in */ + switch_case = new_exten(); + switch_case->context = this_context; + switch_case->is_switch = 1; + + /* new: the default case intros a pattern with ., which covers ALMOST everything. + but it doesn't cover a NULL pattern. So, we'll define a null extension to match + that goto's the default extension. */ + + default_exists++; + switch_null = new_exten(); + switch_null->context = this_context; + switch_null->is_switch = 1; + switch_empty = new_prio(); + snprintf(buf1,sizeof(buf1),"sw-%d-.|10",local_control_statement_count); + switch_empty->app = strdup("Goto"); + switch_empty->appargs = strdup(buf1); + linkprio(switch_null, switch_empty); + snprintf(buf1,sizeof(buf1),"sw-%d-", local_control_statement_count); + switch_null->name = strdup(buf1); + switch_null->loop_break = exten->loop_break; + switch_null->loop_continue = exten->loop_continue; + linkexten(exten,switch_null); + + /* the break/continue locations are inherited from parent */ + switch_case->loop_break = exten->loop_break; + switch_case->loop_continue = exten->loop_continue; + linkexten(exten,switch_case); + snprintf(buf1,sizeof(buf1),"_sw-%d-.", local_control_statement_count); + switch_case->name = strdup(buf1); + + snprintf(new_label,sizeof(new_label),"sw-%s-default-%d", label, local_control_statement_count); + + gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context); /* this will link in all the default: body statements here */ + + /* here is where we write code to "fall thru" to the next case... if there is one... */ + for (p3=p2->u2.statements; p3; p3=p3->next) { + if (!p3->next) + break; + } + /* p3 now points the last statement... */ + if (!p3 || (p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN)) { + /* is there a following CASE/PATTERN/DEFAULT? */ + if (p2->next && p2->next->type == PV_CASE) { + fall_thru = new_prio(); + fall_thru->type = AEL_APPCALL; + fall_thru->app = strdup("Goto"); + snprintf(buf1,sizeof(buf1),"sw-%d-%s,10",local_control_statement_count, p2->next->u1.str); + fall_thru->appargs = strdup(buf1); + linkprio(switch_case, fall_thru); + } else if (p2->next && p2->next->type == PV_PATTERN) { + fall_thru = new_prio(); + fall_thru->type = AEL_APPCALL; + fall_thru->app = strdup("Goto"); + gen_match_to_pattern(p2->next->u1.str, buf2); + snprintf(buf1,sizeof(buf1),"sw-%d-%s,10",local_control_statement_count, buf2); + fall_thru->appargs = strdup(buf1); + linkprio(switch_case, fall_thru); + } else if (p2->next && p2->next->type == PV_DEFAULT) { + fall_thru = new_prio(); + fall_thru->type = AEL_APPCALL; + fall_thru->app = strdup("Goto"); + snprintf(buf1,sizeof(buf1),"sw-%d-.,10",local_control_statement_count); + fall_thru->appargs = strdup(buf1); + linkprio(switch_case, fall_thru); + } else if (!p2->next) { + fall_thru = new_prio(); + fall_thru->type = AEL_CONTROL1; + fall_thru->goto_true = switch_end; + fall_thru->app = strdup("Goto"); + linkprio(switch_case, fall_thru); + } + } + if (switch_case->return_needed) { /* returns don't generate a goto eoe (end of extension) any more, just a Return() app call) */ + char buf[2000]; + struct ael_priority *np2 = new_prio(); + np2->type = AEL_APPCALL; + np2->app = strdup("NoOp"); + snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name); + np2->appargs = strdup(buf); + linkprio(switch_case, np2); + switch_case-> return_target = np2; + } + } else { + /* what could it be??? */ + } + } + + exten->loop_break = loop_break_save; + exten->loop_continue = loop_continue_save; + switch_test->origin = p; + switch_end->origin = p; + break; + + case PV_MACRO_CALL: + pr = new_prio(); + pr->type = AEL_APPCALL; + snprintf(buf1,sizeof(buf1),"%s,s,1", p->u1.str); + first = 1; + for (p2 = p->u2.arglist; p2; p2 = p2->next) { + if (first) + { + strcat(buf1,"("); + first = 0; + } + else + strcat(buf1,","); + strcat(buf1,p2->u1.str); + } + if (!first) + strcat(buf1,")"); + + pr->app = strdup("Gosub"); + pr->appargs = strdup(buf1); + pr->origin = p; + linkprio(exten, pr); + break; + + case PV_APPLICATION_CALL: + pr = new_prio(); + pr->type = AEL_APPCALL; + buf1[0] = 0; + for (p2 = p->u2.arglist; p2; p2 = p2->next) { + if (p2 != p->u2.arglist ) + strcat(buf1,","); + strcat(buf1,p2->u1.str); + } + pr->app = strdup(p->u1.str); + pr->appargs = strdup(buf1); + pr->origin = p; + linkprio(exten, pr); + break; + + case PV_BREAK: + pr = new_prio(); + pr->type = AEL_CONTROL1; /* simple goto */ + pr->goto_true = exten->loop_break; + pr->origin = p; + linkprio(exten, pr); + break; + + case PV_RETURN: /* hmmmm */ + pr = new_prio(); + pr->type = AEL_RETURN; /* simple Return */ + /* exten->return_needed++; */ + pr->app = strdup("Return"); + pr->appargs = strdup(""); + pr->origin = p; + linkprio(exten, pr); + break; + + case PV_CONTINUE: + pr = new_prio(); + pr->type = AEL_CONTROL1; /* simple goto */ + pr->goto_true = exten->loop_continue; + pr->origin = p; + linkprio(exten, pr); + break; + + case PV_IFTIME: + control_statement_count++; + snprintf(new_label,sizeof(new_label),"iftime-%s-%d", label, control_statement_count); + + if_test = new_prio(); + if_test->type = AEL_IFTIME_CONTROL; + snprintf(buf1,sizeof(buf1),"%s,%s,%s,%s", + p->u1.list->u1.str, + p->u1.list->next->u1.str, + p->u1.list->next->next->u1.str, + p->u1.list->next->next->next->u1.str); + if_test->app = 0; + if_test->appargs = strdup(buf1); + if_test->origin = p; + + if_end = new_prio(); + if_end->type = AEL_APPCALL; + snprintf(buf1,sizeof(buf1),"Finish iftime-%s-%d", label, control_statement_count); + if_end->app = strdup("NoOp"); + if_end->appargs = strdup(buf1); + + if (p->u3.else_statements) { + if_skip = new_prio(); + if_skip->type = AEL_CONTROL1; /* simple goto */ + if_skip->goto_true = if_end; + if_skip->origin = p; + + } else { + if_skip = 0; + + if_test->goto_false = if_end; + } + + if_false = new_prio(); + if_false->type = AEL_CONTROL1; + if (p->u3.else_statements) { + if_false->goto_true = if_skip; /* +1 */ + } else { + if_false->goto_true = if_end; + } + + /* link & load! */ + linkprio(exten, if_test); + linkprio(exten, if_false); + + /* now, put the body of the if here */ + + gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context); /* this will link in all the statements here */ + + if (p->u3.else_statements) { + linkprio(exten, if_skip); + gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context); /* this will link in all the statements here */ + + } + + linkprio(exten, if_end); + + break; + + case PV_RANDOM: + case PV_IF: + control_statement_count++; + snprintf(new_label,sizeof(new_label),"if-%s-%d", label, control_statement_count); + + if_test = new_prio(); + if_end = new_prio(); + if_test->type = AEL_IF_CONTROL; + if_end->type = AEL_APPCALL; + if ( p->type == PV_RANDOM ) + snprintf(buf1,sizeof(buf1),"$[${RAND(0,99)} < (%s)]",p->u1.str); + else + snprintf(buf1,sizeof(buf1),"$[%s]",p->u1.str); + if_test->app = 0; + if_test->appargs = strdup(buf1); + snprintf(buf1,sizeof(buf1),"Finish if-%s-%d", label, control_statement_count); + if_end->app = strdup("NoOp"); + if_end->appargs = strdup(buf1); + if_test->origin = p; + + if (p->u3.else_statements) { + if_skip = new_prio(); + if_skip->type = AEL_CONTROL1; /* simple goto */ + if_skip->goto_true = if_end; + if_test->goto_false = if_skip;; + } else { + if_skip = 0; + if_test->goto_false = if_end;; + } + + /* link & load! */ + linkprio(exten, if_test); + + /* now, put the body of the if here */ + + gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context); /* this will link in all the statements here */ + + if (p->u3.else_statements) { + linkprio(exten, if_skip); + gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context); /* this will link in all the statements here */ + + } + + linkprio(exten, if_end); + + break; + + case PV_STATEMENTBLOCK: + gen_prios(exten, label, p->u1.list, mother_exten, this_context ); /* recurse into the block */ + break; + + case PV_CATCH: + control_statement_count++; + /* generate an extension with name of catch, put all catch stats + into this exten! */ + switch_case = new_exten(); + switch_case->context = this_context; + linkexten(exten,switch_case); + switch_case->name = strdup(p->u1.str); + snprintf(new_label,sizeof(new_label),"catch-%s-%d",p->u1.str, control_statement_count); + + gen_prios(switch_case, new_label, p->u2.statements,mother_exten,this_context); /* this will link in all the catch body statements here */ + if (switch_case->return_needed) { /* returns now generate a Return() app call, no longer a goto to the end of the exten */ + char buf[2000]; + struct ael_priority *np2 = new_prio(); + np2->type = AEL_APPCALL; + np2->app = strdup("NoOp"); + snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name); + np2->appargs = strdup(buf); + linkprio(switch_case, np2); + switch_case-> return_target = np2; + } + + break; + default: + break; + } + } +} + +void set_priorities(struct ael_extension *exten) +{ + int i; + struct ael_priority *pr; + do { + if (exten->is_switch) + i = 10; + else if (exten->regexten) + i=2; + else + i=1; + + for (pr=exten->plist; pr; pr=pr->next) { + pr->priority_num = i; + + if (!pr->origin || (pr->origin && pr->origin->type != PV_LABEL) ) /* Labels don't show up in the dialplan, + but we want them to point to the right + priority, which would be the next line + after the label; */ + i++; + } + + exten = exten->next_exten; + } while ( exten ); +} + +void add_extensions(struct ael_extension *exten) +{ + struct ael_priority *pr; + char *label=0; + char realext[AST_MAX_EXTENSION]; + if (!exten) { + ast_log(LOG_WARNING, "This file is Empty!\n" ); + return; + } + do { + struct ael_priority *last = 0; + + pbx_substitute_variables_helper(NULL, exten->name, realext, sizeof(realext) - 1); + if (exten->hints) { + if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, PRIORITY_HINT, NULL, exten->cidmatch, + exten->hints, NULL, ast_free_ptr, registrar)) { + ast_log(LOG_WARNING, "Unable to add step at priority 'hint' of extension '%s'\n", + exten->name); + } + } + + for (pr=exten->plist; pr; pr=pr->next) { + char app[2000]; + char appargs[2000]; + + /* before we can add the extension, we need to prep the app/appargs; + the CONTROL types need to be done after the priority numbers are calculated. + */ + if (pr->type == AEL_LABEL) /* don't try to put labels in the dialplan! */ { + last = pr; + continue; + } + + if (pr->app) + strcpy(app, pr->app); + else + app[0] = 0; + if (pr->appargs ) + strcpy(appargs, pr->appargs); + else + appargs[0] = 0; + switch( pr->type ) { + case AEL_APPCALL: + /* easy case. Everything is all set up */ + break; + + case AEL_CONTROL1: /* FOR loop, WHILE loop, BREAK, CONTINUE, IF, IFTIME */ + /* simple, unconditional goto. */ + strcpy(app,"Goto"); + if (pr->goto_true->origin && pr->goto_true->origin->type == PV_SWITCH ) { + snprintf(appargs,sizeof(appargs),"%s,%d", pr->goto_true->exten->name, pr->goto_true->priority_num); + } else if (pr->goto_true->origin && pr->goto_true->origin->type == PV_IFTIME && pr->goto_true->origin->u3.else_statements ) { + snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num+1); + } else + snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num); + break; + + case AEL_FOR_CONTROL: /* WHILE loop test, FOR loop test */ + strcpy(app,"GotoIf"); + snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num); + break; + + case AEL_IF_CONTROL: + strcpy(app,"GotoIf"); + if (pr->origin->u3.else_statements ) + snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num+1); + else + snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num); + break; + + case AEL_RAND_CONTROL: + strcpy(app,"Random"); + snprintf(appargs,sizeof(appargs),"%s:%d", pr->appargs, pr->goto_true->priority_num+1); + break; + + case AEL_IFTIME_CONTROL: + strcpy(app,"GotoIfTime"); + snprintf(appargs,sizeof(appargs),"%s?%d", pr->appargs, pr->priority_num+2); + break; + + case AEL_RETURN: + strcpy(app,"Return"); + appargs[0] = 0; + break; + + default: + break; + } + if (last && last->type == AEL_LABEL ) { + label = last->origin->u1.str; + } + else + label = 0; + + if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, pr->priority_num, (label?label:NULL), exten->cidmatch, + app, strdup(appargs), ast_free_ptr, registrar)) { + ast_log(LOG_WARNING, "Unable to add step at priority '%d' of extension '%s'\n", pr->priority_num, + exten->name); + } + last = pr; + } + exten = exten->next_exten; + } while ( exten ); +} + +static void attach_exten(struct ael_extension **list, struct ael_extension *newmem) +{ + /* travel to the end of the list... */ + struct ael_extension *lptr; + if( !*list ) { + *list = newmem; + return; + } + lptr = *list; + + while( lptr->next_exten ) { + lptr = lptr->next_exten; + } + /* lptr should now pointing to the last element in the list; it has a null next_exten pointer */ + lptr->next_exten = newmem; +} + +static pval *get_extension_or_contxt(pval *p) +{ + while( p && p->type != PV_EXTENSION && p->type != PV_CONTEXT && p->type != PV_MACRO ) { + + p = p->dad; + } + + return p; +} + +static pval *get_contxt(pval *p) +{ + while( p && p->type != PV_CONTEXT && p->type != PV_MACRO ) { + + p = p->dad; + } + + return p; +} + +static void fix_gotos_in_extensions(struct ael_extension *exten) +{ + struct ael_extension *e; + for(e=exten;e;e=e->next_exten) { + + struct ael_priority *p; + for(p=e->plist;p;p=p->next) { + + if( p->origin && p->origin->type == PV_GOTO && p->origin->u3.goto_target_in_case ) { + + /* fix the extension of the goto target to the actual extension in the post-compiled dialplan */ + + pval *target = p->origin->u2.goto_target; + struct ael_extension *z = target->u3.compiled_label; + pval *pv2 = p->origin; + char buf1[500]; + char *apparg_save = p->appargs; + + p->appargs = 0; + if (!pv2->u1.list->next) /* just one -- it won't hurt to repeat the extension */ { + snprintf(buf1,sizeof(buf1),"%s,%s", z->name, pv2->u1.list->u1.str); + p->appargs = strdup(buf1); + + } else if (pv2->u1.list->next && !pv2->u1.list->next->next) /* two */ { + snprintf(buf1,sizeof(buf1),"%s,%s", z->name, pv2->u1.list->next->u1.str); + p->appargs = strdup(buf1); + } else if (pv2->u1.list->next && pv2->u1.list->next->next) { + snprintf(buf1,sizeof(buf1),"%s,%s,%s", pv2->u1.list->u1.str, + z->name, + pv2->u1.list->next->next->u1.str); + p->appargs = strdup(buf1); + } + else + printf("WHAT? The goto doesn't fall into one of three cases for GOTO????\n"); + + if( apparg_save ) { + free(apparg_save); + } + } + } + } +} + + +void ast_compile_ael2(struct ast_context **local_contexts, struct pval *root) +{ + pval *p,*p2; + struct ast_context *context; + char buf[2000]; + struct ael_extension *exten; + struct ael_extension *exten_list = 0; + + for (p=root; p; p=p->next ) { /* do the globals first, so they'll be there + when we try to eval them */ + switch (p->type) { + case PV_GLOBALS: + /* just VARDEC elements */ + for (p2=p->u1.list; p2; p2=p2->next) { + char buf2[2000]; + snprintf(buf2,sizeof(buf2),"%s=%s", p2->u1.str, p2->u2.val); + pbx_builtin_setvar(NULL, buf2); + } + break; + default: + break; + } + } + + for (p=root; p; p=p->next ) { + pval *lp; + int argc; + + switch (p->type) { + case PV_MACRO: + + context = ast_context_create(local_contexts, p->u1.str, registrar); + + exten = new_exten(); + exten->context = context; + exten->name = strdup("s"); + argc = 1; + for (lp=p->u2.arglist; lp; lp=lp->next) { + /* for each arg, set up a "Set" command */ + struct ael_priority *np2 = new_prio(); + np2->type = AEL_APPCALL; + np2->app = strdup("Set"); + snprintf(buf,sizeof(buf),"LOCAL(%s)=${ARG%d}", lp->u1.str, argc++); + remove_spaces_before_equals(buf); + np2->appargs = strdup(buf); + linkprio(exten, np2); + } + + /* CONTAINS APPCALLS, CATCH, just like extensions... */ + gen_prios(exten, p->u1.str, p->u3.macro_statements, 0, context ); + if (exten->return_needed) { /* most likely, this will go away */ + struct ael_priority *np2 = new_prio(); + np2->type = AEL_APPCALL; + np2->app = strdup("NoOp"); + snprintf(buf,sizeof(buf),"End of Macro %s-%s",p->u1.str, exten->name); + np2->appargs = strdup(buf); + linkprio(exten, np2); + exten-> return_target = np2; + } + + set_priorities(exten); + attach_exten(&exten_list, exten); + break; + + case PV_GLOBALS: + /* already done */ + break; + + case PV_CONTEXT: + context = ast_context_find_or_create(local_contexts, p->u1.str, registrar); + + /* contexts contain: ignorepat, includes, switches, eswitches, extensions, */ + for (p2=p->u2.statements; p2; p2=p2->next) { + pval *p3; + char *s3; + + switch (p2->type) { + case PV_EXTENSION: + exten = new_exten(); + exten->name = strdup(p2->u1.str); + exten->context = context; + + if( (s3=strchr(exten->name, '/') ) != 0 ) + { + *s3 = 0; + exten->cidmatch = s3+1; + } + + if ( p2->u3.hints ) + exten->hints = strdup(p2->u3.hints); + exten->regexten = p2->u4.regexten; + gen_prios(exten, p->u1.str, p2->u2.statements, 0, context ); + if (exten->return_needed) { /* returns don't generate a goto eoe (end of extension) any more, just a Return() app call) */ + struct ael_priority *np2 = new_prio(); + np2->type = AEL_APPCALL; + np2->app = strdup("NoOp"); + snprintf(buf,sizeof(buf),"End of Extension %s", exten->name); + np2->appargs = strdup(buf); + linkprio(exten, np2); + exten-> return_target = np2; + } + /* is the last priority in the extension a label? Then add a trailing no-op */ + if( !exten->plist_last ) + { + ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Empty Extension!\n", + p2->filename, p2->startline, p2->endline); + } + + if ( exten->plist_last && exten->plist_last->type == AEL_LABEL ) { + struct ael_priority *np2 = new_prio(); + np2->type = AEL_APPCALL; + np2->app = strdup("NoOp"); + snprintf(buf,sizeof(buf),"A NoOp to follow a trailing label %s", exten->plist_last->origin->u1.str); + np2->appargs = strdup(buf); + linkprio(exten, np2); + } + + set_priorities(exten); + attach_exten(&exten_list, exten); + break; + + case PV_IGNOREPAT: + ast_context_add_ignorepat2(context, p2->u1.str, registrar); + break; + + case PV_INCLUDES: + for (p3 = p2->u1.list; p3 ;p3=p3->next) { + if ( p3->u2.arglist ) { + snprintf(buf,sizeof(buf), "%s,%s,%s,%s,%s", + p3->u1.str, + p3->u2.arglist->u1.str, + p3->u2.arglist->next->u1.str, + p3->u2.arglist->next->next->u1.str, + p3->u2.arglist->next->next->next->u1.str); + ast_context_add_include2(context, buf, registrar); + } else + ast_context_add_include2(context, p3->u1.str, registrar); + } + break; + + case PV_SWITCHES: + for (p3 = p2->u1.list; p3 ;p3=p3->next) { + char *c = strchr(p3->u1.str, '/'); + if (c) { + *c = '\0'; + c++; + } else + c = ""; + + ast_context_add_switch2(context, p3->u1.str, c, 0, registrar); + } + break; + + case PV_ESWITCHES: + for (p3 = p2->u1.list; p3 ;p3=p3->next) { + char *c = strchr(p3->u1.str, '/'); + if (c) { + *c = '\0'; + c++; + } else + c = ""; + + ast_context_add_switch2(context, p3->u1.str, c, 1, registrar); + } + break; + default: + break; + } + } + + break; + + default: + /* huh? what? */ + break; + + } + } + /* moved these from being done after a macro or extension were processed, + to after all processing is done, for the sake of fixing gotos to labels inside cases... */ + /* I guess this would be considered 2nd pass of compiler now... */ + fix_gotos_in_extensions(exten_list); /* find and fix extension ref in gotos to labels that are in case statements */ + add_extensions(exten_list); /* actually makes calls to create priorities in ast_contexts -- feeds dialplan to asterisk */ + destroy_extensions(exten_list); /* all that remains is an empty husk, discard of it as is proper */ + +} + + +/* DESTROY the PVAL tree ============================================================================ */ + + + +void destroy_pval_item(pval *item) +{ + if (item == NULL) { + ast_log(LOG_WARNING, "null item\n"); + return; + } + + if (item->filename) + free(item->filename); + + switch (item->type) { + case PV_WORD: + /* fields: item->u1.str == string associated with this (word). */ + if (item->u1.str ) + free(item->u1.str); + if ( item->u2.arglist ) + destroy_pval(item->u2.arglist); + break; + + case PV_MACRO: + /* fields: item->u1.str == name of macro + item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user + item->u2.arglist->u1.str == argument + item->u2.arglist->next == next arg + + item->u3.macro_statements == pval list of statements in macro body. + */ + destroy_pval(item->u2.arglist); + if (item->u1.str ) + free(item->u1.str); + destroy_pval(item->u3.macro_statements); + break; + + case PV_CONTEXT: + /* fields: item->u1.str == name of context + item->u2.statements == pval list of statements in context body + item->u3.abstract == int 1 if an abstract keyword were present + */ + if (item->u1.str) + free(item->u1.str); + destroy_pval(item->u2.statements); + break; + + case PV_MACRO_CALL: + /* fields: item->u1.str == name of macro to call + item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user + item->u2.arglist->u1.str == argument + item->u2.arglist->next == next arg + */ + if (item->u1.str) + free(item->u1.str); + destroy_pval(item->u2.arglist); + break; + + case PV_APPLICATION_CALL: + /* fields: item->u1.str == name of application to call + item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user + item->u2.arglist->u1.str == argument + item->u2.arglist->next == next arg + */ + if (item->u1.str) + free(item->u1.str); + destroy_pval(item->u2.arglist); + break; + + case PV_CASE: + /* fields: item->u1.str == value of case + item->u2.statements == pval list of statements under the case + */ + if (item->u1.str) + free(item->u1.str); + destroy_pval(item->u2.statements); + break; + + case PV_PATTERN: + /* fields: item->u1.str == value of case + item->u2.statements == pval list of statements under the case + */ + if (item->u1.str) + free(item->u1.str); + destroy_pval(item->u2.statements); + break; + + case PV_DEFAULT: + /* fields: + item->u2.statements == pval list of statements under the case + */ + destroy_pval(item->u2.statements); + break; + + case PV_CATCH: + /* fields: item->u1.str == name of extension to catch + item->u2.statements == pval list of statements in context body + */ + if (item->u1.str) + free(item->u1.str); + destroy_pval(item->u2.statements); + break; + + case PV_SWITCHES: + /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list + */ + destroy_pval(item->u1.list); + break; + + case PV_ESWITCHES: + /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list + */ + destroy_pval(item->u1.list); + break; + + case PV_INCLUDES: + /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list + item->u2.arglist == pval list of 4 PV_WORD elements for time values + */ + destroy_pval(item->u1.list); + break; + + case PV_STATEMENTBLOCK: + /* fields: item->u1.list == pval list of statements in block, one per entry in the list + */ + destroy_pval(item->u1.list); + break; + + case PV_LOCALVARDEC: + case PV_VARDEC: + /* fields: item->u1.str == variable name + item->u2.val == variable value to assign + */ + if (item->u1.str) + free(item->u1.str); + if (item->u2.val) + free(item->u2.val); + break; + + case PV_GOTO: + /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user. + item->u1.list->u1.str == where the data on a PV_WORD will always be. + */ + + destroy_pval(item->u1.list); + break; + + case PV_LABEL: + /* fields: item->u1.str == label name + */ + if (item->u1.str) + free(item->u1.str); + break; + + case PV_FOR: + /* fields: item->u1.for_init == a string containing the initalizer + item->u2.for_test == a string containing the loop test + item->u3.for_inc == a string containing the loop increment + + item->u4.for_statements == a pval list of statements in the for () + */ + if (item->u1.for_init) + free(item->u1.for_init); + if (item->u2.for_test) + free(item->u2.for_test); + if (item->u3.for_inc) + free(item->u3.for_inc); + destroy_pval(item->u4.for_statements); + break; + + case PV_WHILE: + /* fields: item->u1.str == the while conditional, as supplied by user + + item->u2.statements == a pval list of statements in the while () + */ + if (item->u1.str) + free(item->u1.str); + destroy_pval(item->u2.statements); + break; + + case PV_BREAK: + /* fields: none + */ + break; + + case PV_RETURN: + /* fields: none + */ + break; + + case PV_CONTINUE: + /* fields: none + */ + break; + + case PV_IFTIME: + /* fields: item->u1.list == the 4 time values, in PV_WORD structs, linked list + + item->u2.statements == a pval list of statements in the if () + item->u3.else_statements == a pval list of statements in the else + (could be zero) + */ + destroy_pval(item->u1.list); + destroy_pval(item->u2.statements); + if (item->u3.else_statements) { + destroy_pval(item->u3.else_statements); + } + break; + + case PV_RANDOM: + /* fields: item->u1.str == the random percentage, as supplied by user + + item->u2.statements == a pval list of statements in the true part () + item->u3.else_statements == a pval list of statements in the else + (could be zero) + fall thru to If */ + case PV_IF: + /* fields: item->u1.str == the if conditional, as supplied by user + + item->u2.statements == a pval list of statements in the if () + item->u3.else_statements == a pval list of statements in the else + (could be zero) + */ + if (item->u1.str) + free(item->u1.str); + destroy_pval(item->u2.statements); + if (item->u3.else_statements) { + destroy_pval(item->u3.else_statements); + } + break; + + case PV_SWITCH: + /* fields: item->u1.str == the switch expression + + item->u2.statements == a pval list of statements in the switch, + (will be case statements, most likely!) + */ + if (item->u1.str) + free(item->u1.str); + destroy_pval(item->u2.statements); + break; + + case PV_EXTENSION: + /* fields: item->u1.str == the extension name, label, whatever it's called + + item->u2.statements == a pval list of statements in the extension + item->u3.hints == a char * hint argument + item->u4.regexten == an int boolean. non-zero says that regexten was specified + */ + if (item->u1.str) + free(item->u1.str); + if (item->u3.hints) + free(item->u3.hints); + destroy_pval(item->u2.statements); + break; + + case PV_IGNOREPAT: + /* fields: item->u1.str == the ignorepat data + */ + if (item->u1.str) + free(item->u1.str); + break; + + case PV_GLOBALS: + /* fields: item->u1.statements == pval list of statements, usually vardecs + */ + destroy_pval(item->u1.statements); + break; + } + free(item); +} + +void destroy_pval(pval *item) +{ + pval *i,*nxt; + + for (i=item; i; i=nxt) { + nxt = i->next; + + destroy_pval_item(i); + } +} + +#ifdef AAL_ARGCHECK +static char *ael_funclist[] = +{ + "AGENT", + "ARRAY", + "BASE64_DECODE", + "BASE64_ENCODE", + "CALLERID", + "CDR", + "CHANNEL", + "CHECKSIPDOMAIN", + "CHECK_MD5", + "CURL", + "CUT", + "DB", + "DB_EXISTS", + "DUNDILOOKUP", + "ENUMLOOKUP", + "ENV", + "EVAL", + "EXISTS", + "FIELDQTY", + "FILTER", + "GROUP", + "GROUP_COUNT", + "GROUP_LIST", + "GROUP_MATCH_COUNT", + "IAXPEER", + "IF", + "IFTIME", + "ISNULL", + "KEYPADHASH", + "LANGUAGE", + "LEN", + "MATH", + "MD5", + "MUSICCLASS", + "QUEUEAGENTCOUNT", + "QUEUE_MEMBER_COUNT", + "QUEUE_MEMBER_LIST", + "QUOTE", + "RAND", + "REGEX", + "SET", + "SHA1", + "SIPCHANINFO", + "SIPPEER", + "SIP_HEADER", + "SORT", + "STAT", + "STRFTIME", + "STRPTIME", + "TIMEOUT", + "TXTCIDNAME", + "URIDECODE", + "URIENCODE", + "VMCOUNT" +}; + + +int ael_is_funcname(char *name) +{ + int s,t; + t = sizeof(ael_funclist)/sizeof(char*); + s = 0; + while ((s < t) && strcasecmp(name, ael_funclist[s])) + s++; + if ( s < t ) + return 1; + else + return 0; +} +#endif + + +/* PVAL PI */ + +/* ----------------- implementation ------------------- */ + + +int pvalCheckType( pval *p, char *funcname, pvaltype type ) +{ + if (p->type != type) + { + ast_log(LOG_ERROR, "Func: %s the pval passed is not appropriate for this function!\n", funcname); + return 0; + } + return 1; +} + + +pval *pvalCreateNode( pvaltype type ) +{ + pval *p = calloc(1,sizeof(pval)); /* why, oh why, don't I use ast_calloc? Way, way, way too messy if I do! */ + p->type = type; /* remember, this can be used externally or internally to asterisk */ + return p; +} + +pvaltype pvalObjectGetType( pval *p ) +{ + return p->type; +} + + +void pvalWordSetString( pval *p, char *str) +{ + if (!pvalCheckType(p, "pvalWordSetString", PV_WORD)) + return; + p->u1.str = str; +} + +char *pvalWordGetString( pval *p ) +{ + if (!pvalCheckType(p, "pvalWordGetString", PV_WORD)) + return 0; + return p->u1.str; +} + + +void pvalMacroSetName( pval *p, char *name) +{ + if (!pvalCheckType(p, "pvalMacroSetName", PV_MACRO)) + return; + p->u1.str = name; +} + +char *pvalMacroGetName( pval *p ) +{ + if (!pvalCheckType(p, "pvalMacroGetName", PV_MACRO)) + return 0; + return p->u1.str; +} + +void pvalMacroSetArglist( pval *p, pval *arglist ) +{ + if (!pvalCheckType(p, "pvalMacroSetArglist", PV_MACRO)) + return; + p->u2.arglist = arglist; +} + +void pvalMacroAddArg( pval *p, pval *arg ) /* single arg only! */ +{ + if (!pvalCheckType(p, "pvalMacroAddArg", PV_MACRO)) + return; + if (!p->u2.arglist) + p->u2.arglist = arg; + else + linku1(p->u2.arglist, arg); + +} + +pval *pvalMacroWalkArgs( pval *p, pval **arg ) +{ + if (!pvalCheckType(p, "pvalMacroWalkArgs", PV_MACRO)) + return 0; + if (!(*arg)) + *arg = p->u2.arglist; + else { + *arg = (*arg)->next; + } + return *arg; +} + +void pvalMacroAddStatement( pval *p, pval *statement ) +{ + if (!pvalCheckType(p, "pvalMacroAddStatement", PV_MACRO)) + return; + if (!p->u3.macro_statements) + p->u3.macro_statements = statement; + else + linku1(p->u3.macro_statements, statement); + + +} + +pval *pvalMacroWalkStatements( pval *p, pval **next_statement ) +{ + if (!pvalCheckType(p, "pvalMacroWalkStatements", PV_MACRO)) + return 0; + if (!(*next_statement)) + *next_statement = p->u3.macro_statements; + else { + *next_statement = (*next_statement)->next; + } + return *next_statement; +} + + + +void pvalContextSetName( pval *p, char *name) +{ + if (!pvalCheckType(p, "pvalContextSetName", PV_CONTEXT)) + return; + p->u1.str = name; +} + +char *pvalContextGetName( pval *p ) +{ + if (!pvalCheckType(p, "pvalContextGetName", PV_CONTEXT)) + return 0; + return p->u1.str; +} + +void pvalContextSetAbstract( pval *p ) +{ + if (!pvalCheckType(p, "pvalContextSetAbstract", PV_CONTEXT)) + return; + p->u3.abstract = 1; +} + +void pvalContextUnsetAbstract( pval *p ) +{ + if (!pvalCheckType(p, "pvalContextUnsetAbstract", PV_CONTEXT)) + return; + p->u3.abstract = 0; +} + +int pvalContextGetAbstract( pval *p ) +{ + if (!pvalCheckType(p, "pvalContextGetAbstract", PV_CONTEXT)) + return 0; + return p->u3.abstract; +} + + + +void pvalContextAddStatement( pval *p, pval *statement) /* this includes SWITCHES, INCLUDES, IGNOREPAT, etc */ +{ + if (!pvalCheckType(p, "pvalContextAddStatement", PV_CONTEXT)) + return; + if (!p->u2.statements) + p->u2.statements = statement; + else + linku1(p->u2.statements, statement); +} + +pval *pvalContextWalkStatements( pval *p, pval **statements ) +{ + if (!pvalCheckType(p, "pvalContextWalkStatements", PV_CONTEXT)) + return 0; + if (!(*statements)) + *statements = p->u2.statements; + else { + *statements = (*statements)->next; + } + return *statements; +} + + +void pvalMacroCallSetMacroName( pval *p, char *name ) +{ + if (!pvalCheckType(p, "pvalMacroCallSetMacroName", PV_MACRO_CALL)) + return; + p->u1.str = name; +} + +char* pvalMacroCallGetMacroName( pval *p ) +{ + if (!pvalCheckType(p, "pvalMacroCallGetMacroName", PV_MACRO_CALL)) + return 0; + return p->u1.str; +} + +void pvalMacroCallSetArglist( pval *p, pval *arglist ) +{ + if (!pvalCheckType(p, "pvalMacroCallSetArglist", PV_MACRO_CALL)) + return; + p->u2.arglist = arglist; +} + +void pvalMacroCallAddArg( pval *p, pval *arg ) +{ + if (!pvalCheckType(p, "pvalMacroCallGetAddArg", PV_MACRO_CALL)) + return; + if (!p->u2.arglist) + p->u2.arglist = arg; + else + linku1(p->u2.arglist, arg); +} + +pval *pvalMacroCallWalkArgs( pval *p, pval **args ) +{ + if (!pvalCheckType(p, "pvalMacroCallWalkArgs", PV_MACRO_CALL)) + return 0; + if (!(*args)) + *args = p->u2.arglist; + else { + *args = (*args)->next; + } + return *args; +} + + +void pvalAppCallSetAppName( pval *p, char *name ) +{ + if (!pvalCheckType(p, "pvalAppCallSetAppName", PV_APPLICATION_CALL)) + return; + p->u1.str = name; +} + +char* pvalAppCallGetAppName( pval *p ) +{ + if (!pvalCheckType(p, "pvalAppCallGetAppName", PV_APPLICATION_CALL)) + return 0; + return p->u1.str; +} + +void pvalAppCallSetArglist( pval *p, pval *arglist ) +{ + if (!pvalCheckType(p, "pvalAppCallSetArglist", PV_APPLICATION_CALL)) + return; + p->u2.arglist = arglist; +} + +void pvalAppCallAddArg( pval *p, pval *arg ) +{ + if (!pvalCheckType(p, "pvalAppCallAddArg", PV_APPLICATION_CALL)) + return; + if (!p->u2.arglist) + p->u2.arglist = arg; + else + linku1(p->u2.arglist, arg); +} + +pval *pvalAppCallWalkArgs( pval *p, pval **args ) +{ + if (!pvalCheckType(p, "pvalAppCallWalkArgs", PV_APPLICATION_CALL)) + return 0; + if (!(*args)) + *args = p->u2.arglist; + else { + *args = (*args)->next; + } + return *args; +} + + +void pvalCasePatSetVal( pval *p, char *val ) +{ + if (!pvalCheckType(p, "pvalAppCallWalkArgs", PV_APPLICATION_CALL)) + return; + p->u1.str = val; +} + +char* pvalCasePatGetVal( pval *p ) +{ + return p->u1.str; +} + +void pvalCasePatDefAddStatement( pval *p, pval *statement ) +{ + if (!p->u2.arglist) + p->u2.statements = statement; + else + linku1(p->u2.statements, statement); +} + +pval *pvalCasePatDefWalkStatements( pval *p, pval **statement ) +{ + if (!(*statement)) + *statement = p->u2.statements; + else { + *statement = (*statement)->next; + } + return *statement; +} + + +void pvalCatchSetExtName( pval *p, char *name ) +{ + if (!pvalCheckType(p, "pvalCatchSetExtName", PV_CATCH)) + return; + p->u1.str = name; +} + +char* pvalCatchGetExtName( pval *p ) +{ + if (!pvalCheckType(p, "pvalCatchGetExtName", PV_CATCH)) + return 0; + return p->u1.str; +} + +void pvalCatchSetStatement( pval *p, pval *statement ) +{ + if (!pvalCheckType(p, "pvalCatchSetStatement", PV_CATCH)) + return; + p->u2.statements = statement; +} + +pval *pvalCatchGetStatement( pval *p ) +{ + if (!pvalCheckType(p, "pvalCatchGetStatement", PV_CATCH)) + return 0; + return p->u2.statements; +} + + +void pvalSwitchesAddSwitch( pval *p, char *name ) +{ + pval *s; + if (!pvalCheckType(p, "pvalSwitchesAddSwitch", PV_SWITCHES)) + return; + s = pvalCreateNode(PV_WORD); + s->u1.str = name; + p->u1.list = linku1(p->u1.list, s); +} + +char* pvalSwitchesWalkNames( pval *p, pval **next_item ) +{ + if (!pvalCheckType(p, "pvalSwitchesWalkNames", PV_SWITCHES)) + return 0; + if (!(*next_item)) + *next_item = p->u1.list; + else { + *next_item = (*next_item)->next; + } + return (*next_item)->u1.str; +} + +void pvalESwitchesAddSwitch( pval *p, char *name ) +{ + pval *s; + if (!pvalCheckType(p, "pvalESwitchesAddSwitch", PV_ESWITCHES)) + return; + s = pvalCreateNode(PV_WORD); + s->u1.str = name; + p->u1.list = linku1(p->u1.list, s); +} + +char* pvalESwitchesWalkNames( pval *p, pval **next_item ) +{ + if (!pvalCheckType(p, "pvalESwitchesWalkNames", PV_ESWITCHES)) + return 0; + if (!(*next_item)) + *next_item = p->u1.list; + else { + *next_item = (*next_item)->next; + } + return (*next_item)->u1.str; +} + + +void pvalIncludesAddInclude( pval *p, const char *include ) +{ + pval *s; + if (!pvalCheckType(p, "pvalIncludesAddSwitch", PV_INCLUDES)) + return; + s = pvalCreateNode(PV_WORD); + s->u1.str = (char *)include; + p->u1.list = linku1(p->u1.list, s); +} + /* an include is a WORD with string set to path */ + +void pvalIncludesAddIncludeWithTimeConstraints( pval *p, const char *include, char *hour_range, char *dom_range, char *dow_range, char *month_range ) +{ + pval *hr = pvalCreateNode(PV_WORD); + pval *dom = pvalCreateNode(PV_WORD); + pval *dow = pvalCreateNode(PV_WORD); + pval *mon = pvalCreateNode(PV_WORD); + pval *s = pvalCreateNode(PV_WORD); + + if (!pvalCheckType(p, "pvalIncludeAddIncludeWithTimeConstraints", PV_INCLUDES)) + return; + + s->u1.str = (char *)include; + p->u1.list = linku1(p->u1.list, s); + + hr->u1.str = hour_range; + dom->u1.str = dom_range; + dow->u1.str = dow_range; + mon->u1.str = month_range; + + s->u2.arglist = hr; + + hr->next = dom; + dom->next = dow; + dow->next = mon; + mon->next = 0; +} + /* is this right??? come back and correct it */ /*the ptr is to the WORD */ +void pvalIncludeGetTimeConstraints( pval *p, char **hour_range, char **dom_range, char **dow_range, char **month_range ) +{ + if (!pvalCheckType(p, "pvalIncludeGetTimeConstraints", PV_WORD)) + return; + if (p->u2.arglist) { + *hour_range = p->u2.arglist->u1.str; + *dom_range = p->u2.arglist->next->u1.str; + *dow_range = p->u2.arglist->next->next->u1.str; + *month_range = p->u2.arglist->next->next->next->u1.str; + } else { + *hour_range = 0; + *dom_range = 0; + *dow_range = 0; + *month_range = 0; + } +} + /* is this right??? come back and correct it */ /*the ptr is to the WORD */ +char* pvalIncludesWalk( pval *p, pval **next_item ) +{ + if (!pvalCheckType(p, "pvalIncludesWalk", PV_INCLUDES)) + return 0; + if (!(*next_item)) + *next_item = p->u1.list; + else { + *next_item = (*next_item)->next; + } + return (*next_item)->u1.str; +} + + +void pvalStatementBlockAddStatement( pval *p, pval *statement) +{ + if (!pvalCheckType(p, "pvalStatementBlockAddStatement", PV_STATEMENTBLOCK)) + return; + p->u1.list = linku1(p->u1.list, statement); +} + +pval *pvalStatementBlockWalkStatements( pval *p, pval **next_statement) +{ + if (!pvalCheckType(p, "pvalStatementBlockWalkStatements", PV_STATEMENTBLOCK)) + return 0; + if (!(*next_statement)) + *next_statement = p->u1.list; + else { + *next_statement = (*next_statement)->next; + } + return *next_statement; +} + +void pvalVarDecSetVarname( pval *p, char *name ) +{ + if (!pvalCheckType(p, "pvalVarDecSetVarname", PV_VARDEC)) + return; + p->u1.str = name; +} + +void pvalVarDecSetValue( pval *p, char *value ) +{ + if (!pvalCheckType(p, "pvalVarDecSetValue", PV_VARDEC)) + return; + p->u2.val = value; +} + +char* pvalVarDecGetVarname( pval *p ) +{ + if (!pvalCheckType(p, "pvalVarDecGetVarname", PV_VARDEC)) + return 0; + return p->u1.str; +} + +char* pvalVarDecGetValue( pval *p ) +{ + if (!pvalCheckType(p, "pvalVarDecGetValue", PV_VARDEC)) + return 0; + return p->u2.val; +} + +void pvalGotoSetTarget( pval *p, char *context, char *exten, char *label ) +{ + pval *con, *ext, *pri; + + if (!pvalCheckType(p, "pvalGotoSetTarget", PV_GOTO)) + return; + if (context && strlen(context)) { + con = pvalCreateNode(PV_WORD); + ext = pvalCreateNode(PV_WORD); + pri = pvalCreateNode(PV_WORD); + + con->u1.str = context; + ext->u1.str = exten; + pri->u1.str = label; + + con->next = ext; + ext->next = pri; + p->u1.list = con; + } else if (exten && strlen(exten)) { + ext = pvalCreateNode(PV_WORD); + pri = pvalCreateNode(PV_WORD); + + ext->u1.str = exten; + pri->u1.str = label; + + ext->next = pri; + p->u1.list = ext; + } else { + pri = pvalCreateNode(PV_WORD); + + pri->u1.str = label; + + p->u1.list = pri; + } +} + +void pvalGotoGetTarget( pval *p, char **context, char **exten, char **label ) +{ + if (!pvalCheckType(p, "pvalGotoGetTarget", PV_GOTO)) + return; + if (p->u1.list && p->u1.list->next && p->u1.list->next->next) { + *context = p->u1.list->u1.str; + *exten = p->u1.list->next->u1.str; + *label = p->u1.list->next->next->u1.str; + + } else if (p->u1.list && p->u1.list->next ) { + *exten = p->u1.list->u1.str; + *label = p->u1.list->next->u1.str; + *context = 0; + + } else if (p->u1.list) { + *label = p->u1.list->u1.str; + *context = 0; + *exten = 0; + + } else { + *context = 0; + *exten = 0; + *label = 0; + } +} + + +void pvalLabelSetName( pval *p, char *name ) +{ + if (!pvalCheckType(p, "pvalLabelSetName", PV_LABEL)) + return; + p->u1.str = name; +} + +char* pvalLabelGetName( pval *p ) +{ + if (!pvalCheckType(p, "pvalLabelGetName", PV_LABEL)) + return 0; + return p->u1.str; +} + + +void pvalForSetInit( pval *p, char *init ) +{ + if (!pvalCheckType(p, "pvalForSetInit", PV_FOR)) + return; + p->u1.for_init = init; +} + +void pvalForSetTest( pval *p, char *test ) +{ + if (!pvalCheckType(p, "pvalForSetTest", PV_FOR)) + return; + p->u2.for_test = test; +} + +void pvalForSetInc( pval *p, char *inc ) +{ + if (!pvalCheckType(p, "pvalForSetInc", PV_FOR)) + return; + p->u3.for_inc = inc; +} + +void pvalForSetStatement( pval *p, pval *statement ) +{ + if (!pvalCheckType(p, "pvalForSetStatement", PV_FOR)) + return; + p->u4.for_statements = statement; +} + +char* pvalForGetInit( pval *p ) +{ + if (!pvalCheckType(p, "pvalForGetInit", PV_FOR)) + return 0; + return p->u1.for_init; +} + +char* pvalForGetTest( pval *p ) +{ + if (!pvalCheckType(p, "pvalForGetTest", PV_FOR)) + return 0; + return p->u2.for_test; +} + +char* pvalForGetInc( pval *p ) +{ + if (!pvalCheckType(p, "pvalForGetInc", PV_FOR)) + return 0; + return p->u3.for_inc; +} + +pval* pvalForGetStatement( pval *p ) +{ + if (!pvalCheckType(p, "pvalForGetStatement", PV_FOR)) + return 0; + return p->u4.for_statements; +} + + + +void pvalIfSetCondition( pval *p, char *expr ) +{ + if (!pvalCheckType(p, "pvalIfSetCondition", PV_IF)) + return; + p->u1.str = expr; +} + +char* pvalIfGetCondition( pval *p ) +{ + if (!pvalCheckType(p, "pvalIfGetCondition", PV_IFTIME)) + return 0; + return p->u1.str; +} + +void pvalIfTimeSetCondition( pval *p, char *hour_range, char *dow_range, char *dom_range, char *mon_range ) /* time range format: 24-hour format begin-end|dow range|dom range|month range */ +{ + pval *hr = pvalCreateNode(PV_WORD); + pval *dow = pvalCreateNode(PV_WORD); + pval *dom = pvalCreateNode(PV_WORD); + pval *mon = pvalCreateNode(PV_WORD); + if (!pvalCheckType(p, "pvalIfTimeSetCondition", PV_IFTIME)) + return; + pvalWordSetString(hr, hour_range); + pvalWordSetString(dow, dow_range); + pvalWordSetString(dom, dom_range); + pvalWordSetString(mon, mon_range); + dom->next = mon; + dow->next = dom; + hr->next = dow; + p->u1.list = hr; +} + + /* is this right??? come back and correct it */ +void pvalIfTimeGetCondition( pval *p, char **hour_range, char **dow_range, char **dom_range, char **month_range ) +{ + if (!pvalCheckType(p, "pvalIfTimeGetCondition", PV_IFTIME)) + return; + *hour_range = p->u1.list->u1.str; + *dow_range = p->u1.list->next->u1.str; + *dom_range = p->u1.list->next->next->u1.str; + *month_range = p->u1.list->next->next->next->u1.str; +} + +void pvalRandomSetCondition( pval *p, char *percent ) +{ + if (!pvalCheckType(p, "pvalRandomSetCondition", PV_RANDOM)) + return; + p->u1.str = percent; +} + +char* pvalRandomGetCondition( pval *p ) +{ + if (!pvalCheckType(p, "pvalRandomGetCondition", PV_RANDOM)) + return 0; + return p->u1.str; +} + +void pvalConditionalSetThenStatement( pval *p, pval *statement ) +{ + p->u2.statements = statement; +} + +void pvalConditionalSetElseStatement( pval *p, pval *statement ) +{ + p->u3.else_statements = statement; +} + +pval* pvalConditionalGetThenStatement( pval *p ) +{ + return p->u2.statements; +} + +pval* pvalConditionalGetElseStatement( pval *p ) +{ + return p->u3.else_statements; +} + +void pvalSwitchSetTestexpr( pval *p, char *expr ) +{ + if (!pvalCheckType(p, "pvalSwitchSetTestexpr", PV_SWITCH)) + return; + p->u1.str = expr; +} + +char* pvalSwitchGetTestexpr( pval *p ) +{ + if (!pvalCheckType(p, "pvalSwitchGetTestexpr", PV_SWITCH)) + return 0; + return p->u1.str; +} + +void pvalSwitchAddCase( pval *p, pval *Case ) +{ + if (!pvalCheckType(p, "pvalSwitchAddCase", PV_SWITCH)) + return; + if (!pvalCheckType(Case, "pvalSwitchAddCase", PV_CASE)) + return; + if (!p->u2.statements) + p->u2.statements = Case; + else + linku1(p->u2.statements, Case); +} + +pval* pvalSwitchWalkCases( pval *p, pval **next_case ) +{ + if (!pvalCheckType(p, "pvalSwitchWalkCases", PV_SWITCH)) + return 0; + if (!(*next_case)) + *next_case = p->u2.statements; + else { + *next_case = (*next_case)->next; + } + return *next_case; +} + + +void pvalExtenSetName( pval *p, char *name ) +{ + if (!pvalCheckType(p, "pvalExtenSetName", PV_EXTENSION)) + return; + p->u1.str = name; +} + +char* pvalExtenGetName( pval *p ) +{ + if (!pvalCheckType(p, "pvalExtenGetName", PV_EXTENSION)) + return 0; + return p->u1.str; +} + +void pvalExtenSetRegexten( pval *p ) +{ + if (!pvalCheckType(p, "pvalExtenSetRegexten", PV_EXTENSION)) + return; + p->u4.regexten = 1; +} + +void pvalExtenUnSetRegexten( pval *p ) +{ + if (!pvalCheckType(p, "pvalExtenUnSetRegexten", PV_EXTENSION)) + return; + p->u4.regexten = 0; +} + +int pvalExtenGetRegexten( pval *p ) +{ + if (!pvalCheckType(p, "pvalExtenGetRegexten", PV_EXTENSION)) + return 0; + return p->u4.regexten; +} + +void pvalExtenSetHints( pval *p, char *hints ) +{ + if (!pvalCheckType(p, "pvalExtenSetHints", PV_EXTENSION)) + return; + p->u3.hints = hints; +} + +char* pvalExtenGetHints( pval *p ) +{ + if (!pvalCheckType(p, "pvalExtenGetHints", PV_EXTENSION)) + return 0; + return p->u3.hints; +} + +void pvalExtenSetStatement( pval *p, pval *statement ) +{ + if (!pvalCheckType(p, "pvalExtenSetStatement", PV_EXTENSION)) + return; + p->u2.statements = statement; +} + +pval* pvalExtenGetStatement( pval *p ) +{ + if (!pvalCheckType(p, "pvalExtenGetStatement", PV_EXTENSION)) + return 0; + return p->u2.statements; +} + + +void pvalIgnorePatSetPattern( pval *p, char *pat ) +{ + if (!pvalCheckType(p, "pvalIgnorePatSetPattern", PV_IGNOREPAT)) + return; + p->u1.str = pat; +} + +char* pvalIgnorePatGetPattern( pval *p ) +{ + if (!pvalCheckType(p, "pvalIgnorePatGetPattern", PV_IGNOREPAT)) + return 0; + return p->u1.str; +} + + +void pvalGlobalsAddStatement( pval *p, pval *statement ) +{ + if (p->type != PV_GLOBALS) { + ast_log(LOG_ERROR, "pvalGlobalsAddStatement called where first arg is not a Globals!\n"); + } else { + if (!p->u1.statements) { + p->u1.statements = statement; + } else { + p->u1.statements = linku1(p->u1.statements,statement); + } + } +} + +pval* pvalGlobalsWalkStatements( pval *p, pval **next_statement ) +{ + if (!pvalCheckType(p, "pvalGlobalsWalkStatements", PV_GLOBALS)) + return 0; + if (!next_statement) { + *next_statement = p; + return p; + } else { + *next_statement = (*next_statement)->next; + return (*next_statement)->next; + } +} + + +void pvalTopLevAddObject( pval *p, pval *contextOrObj ) +{ + if (p) { + linku1(p,contextOrObj); + } else { + ast_log(LOG_ERROR, "First arg to pvalTopLevel is NULL!\n"); + } +} + +pval *pvalTopLevWalkObjects(pval *p, pval **next_obj ) +{ + if (!next_obj) { + *next_obj = p; + return p; + } else { + *next_obj = (*next_obj)->next; + return (*next_obj)->next; + } +} + +/* append second element to the list in the first one via next pointers */ +pval * linku1(pval *head, pval *tail) +{ + if (!head) + return tail; + if (tail) { + if (!head->next) { + head->next = tail; + } else { + head->u1_last->next = tail; + } + head->u1_last = tail; + tail->prev = head; /* the dad link only points to containers */ + } + return head; +} + +#ifdef HERE_BY_MISTAKE_I_THINK +static char *config = "extensions.ael"; +int do_pbx_load_module(void) +{ + int errs, sem_err, sem_warn, sem_note; + char *rfilename; + struct ast_context *local_contexts=NULL, *con; + struct pval *parse_tree; + + ast_log(LOG_NOTICE, "Starting AEL load process.\n"); + if (config[0] == '/') + rfilename = (char *)config; + else { + rfilename = alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2); + sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config); + } + ast_log(LOG_NOTICE, "AEL load process: calculated config file name '%s'.\n", rfilename); + + if (access(rfilename,R_OK) != 0) { + ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename); + return AST_MODULE_LOAD_DECLINE; + } + + parse_tree = ael2_parse(rfilename, &errs); + ast_log(LOG_DEBUG, "AEL load process: parsed config file name '%s'.\n", rfilename); + ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note); + if (errs == 0 && sem_err == 0) { + ast_log(LOG_DEBUG, "AEL load process: checked config file name '%s'.\n", rfilename); + ast_compile_ael2(&local_contexts, parse_tree); + ast_log(LOG_DEBUG, "AEL load process: compiled config file name '%s'.\n", rfilename); + + ast_merge_contexts_and_delete(&local_contexts, registrar); + ast_log(LOG_DEBUG, "AEL load process: merged config file name '%s'.\n", rfilename); + for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con)) + ast_context_verify_includes(con); + ast_log(LOG_DEBUG, "AEL load process: verified config file name '%s'.\n", rfilename); + } else { + ast_log(LOG_ERROR, "Sorry, but %d syntax errors and %d semantic errors were detected. It doesn't make sense to compile.\n", errs, sem_err); + destroy_pval(parse_tree); /* free up the memory */ + return AST_MODULE_LOAD_FAILURE; + } + destroy_pval(parse_tree); /* free up the memory */ + + return AST_MODULE_LOAD_SUCCESS; +} +#endif + |