2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2006, Digium, Inc.
6 * Steve Murphy <murf@parsetree.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
20 * \brief Flex scanner description of tokens used in AEL2 .
25 * Start with flex options:
27 * %x describes the contexts we have: paren, semic and argg, plus INITIAL
31 /* prefix used for various globally-visible functions and variables.
32 * This renames also yywrap, but since we do not use it, we just
33 * add option noyywrap to remove it.
35 %option prefix="ael_yy"
38 /* batch gives a bit more performance if we are using it in
39 * a non-interactive mode. We probably don't care much.
43 /* outfile is the filename to be used instead of lex.yy.c */
44 %option outfile="ael_lex.c"
47 * These are not supported in flex 2.5.4, but we need them
49 * reentrant produces a thread-safe parser. Not 100% sure that
50 * we require it, though.
51 * bison-bridge passes an additional yylval argument to yylex().
52 * bison-locations is probably not needed.
56 %option bison-locations
59 #include <sys/types.h>
64 #include "asterisk/logger.h"
65 #include "ael/ael.tab.h"
66 #include "asterisk/ael_structs.h"
69 * A stack to keep track of matching brackets ( [ { } ] )
71 static char pbcstack[400]; /* XXX missing size checks */
72 static int pbcpos = 0;
74 static int parencount = 0;
75 static int commaout = 0;
78 * current line, column and filename, updated as we read the input.
80 static int my_lineno = 1; /* current line in the source */
81 static int my_col = 1; /* current column in the source */
82 char *my_file = 0; /* used also in the bison code */
83 char *prev_word; /* XXX document it */
85 #define MAX_INCLUDE_DEPTH 50
88 * flex is not too smart, and generates global functions
89 * without prototypes so the compiler may complain.
90 * To avoid that, we declare the prototypes here,
91 * even though these functions are not used.
93 int ael_yyget_column (yyscan_t yyscanner);
94 void ael_yyset_column (int column_no , yyscan_t yyscanner);
96 int ael_yyparse (struct parse_io *);
97 static void pbcpush(char x);
98 static int pbcpop(char x);
101 * A stack to process include files.
102 * As we switch into the new file we need to store the previous
103 * state to restore it later.
105 struct stackelement {
109 YY_BUFFER_STATE bufstate;
112 static struct stackelement include_stack[MAX_INCLUDE_DEPTH];
113 static int include_stack_index = 0;
116 * if we use the @n feature of bison, we must supply the start/end
117 * location of tokens in the structure pointed by yylloc.
118 * Simple tokens are just assumed to be on the same line, so
119 * the line number is constant, and the column is incremented
120 * by the length of the token.
122 #ifdef FLEX_BETA /* set for 2.5.33 */
124 /* compute the total number of lines and columns in the text
125 * passed as argument.
127 static void pbcwhere(const char *text, int *line, int *col )
129 int loc_line = *line;
132 while ( (c = *text++) ) {
143 #define STORE_POS do { \
144 yylloc->first_line = yylloc->last_line = my_lineno; \
145 yylloc->first_column=my_col; \
146 yylloc->last_column=my_col+yyleng-1; \
150 #define STORE_START do { \
151 yylloc->first_line = my_lineno; \
152 yylloc->first_column=my_col; \
155 #define STORE_END do { \
156 pbcwhere(yytext, &my_lineno, &my_col); \
157 yylloc->last_line = my_lineno; \
158 yylloc->last_column = my_col - 1; \
168 NOPARENS [^()\[\]\{\}]*
170 NOARGG [^(),\{\}\[\]]*
172 NOSEMIC [^;()\{\}\[\]]*
176 \{ { STORE_POS; return LC;}
177 \} { STORE_POS; return RC;}
178 \( { STORE_POS; return LP;}
179 \) { STORE_POS; return RP;}
180 \; { STORE_POS; return SEMI;}
181 \= { STORE_POS; return EQ;}
182 \, { STORE_POS; return COMMA;}
183 \: { STORE_POS; return COLON;}
184 \& { STORE_POS; return AMPER;}
185 \| { STORE_POS; return BAR;}
186 \=\> { STORE_POS; return EXTENMARK;}
187 \@ { STORE_POS; return AT;}
188 \/\/[^\n]* {/*comment*/}
189 context { STORE_POS; return KW_CONTEXT;}
190 abstract { STORE_POS; return KW_ABSTRACT;}
191 macro { STORE_POS; return KW_MACRO;};
192 globals { STORE_POS; return KW_GLOBALS;}
193 ignorepat { STORE_POS; return KW_IGNOREPAT;}
194 switch { STORE_POS; return KW_SWITCH;}
195 if { STORE_POS; return KW_IF;}
196 ifTime { STORE_POS; return KW_IFTIME;}
197 random { STORE_POS; return KW_RANDOM;}
198 regexten { STORE_POS; return KW_REGEXTEN;}
199 hint { STORE_POS; return KW_HINT;}
200 else { STORE_POS; return KW_ELSE;}
201 goto { STORE_POS; return KW_GOTO;}
202 jump { STORE_POS; return KW_JUMP;}
203 return { STORE_POS; return KW_RETURN;}
204 break { STORE_POS; return KW_BREAK;}
205 continue { STORE_POS; return KW_CONTINUE;}
206 for { STORE_POS; return KW_FOR;}
207 while { STORE_POS; return KW_WHILE;}
208 case { STORE_POS; return KW_CASE;}
209 default { STORE_POS; return KW_DEFAULT;}
210 pattern { STORE_POS; return KW_PATTERN;}
211 catch { STORE_POS; return KW_CATCH;}
212 switches { STORE_POS; return KW_SWITCHES;}
213 eswitches { STORE_POS; return KW_ESWITCHES;}
214 includes { STORE_POS; return KW_INCLUDES;}
216 \n { my_lineno++; my_col = 1; }
217 [ ]+ { my_col += yyleng; }
218 [\t]+ { my_col += (yyleng*8)-(my_col%8); }
220 [-a-zA-Z0-9'"_/.\<\>\*\+!$#\[\]][-a-zA-Z0-9'"_/.!\*\+\<\>\{\}$#\[\]]* {
222 yylval->str = strdup(yytext);
223 prev_word = yylval->str;
230 <paren>{NOPARENS}\) {
232 if ( pbcpop(')') ) { /* error */
234 ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched ')' in expression: %s !\n", my_file, my_lineno, my_col, yytext);
236 yylval->str = strdup(yytext);
241 if ( parencount >= 0) {
245 yylval->str = strdup(yytext);
246 *(yylval->str+strlen(yylval->str)-1)=0;
247 /* printf("Got paren word %s\n", yylval->str); */
254 <paren>{NOPARENS}[\(\[\{] {
255 char c = yytext[yyleng-1];
263 <paren>{NOPARENS}[\]\}] {
264 char c = yytext[yyleng-1];
266 if ( pbcpop(c)) { /* error */
268 ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched '%c' in expression!\n",
269 my_file, my_lineno, my_col, c);
271 yylval->str = strdup(yytext);
277 <argg>{NOARGG}[\(\[\{] {
278 char c = yytext[yyleng-1];
288 if ( pbcpop(')') ) { /* error */
290 ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched ')' in expression!\n", my_file, my_lineno, my_col);
292 yylval->str = strdup(yytext);
297 if( parencount >= 0){
301 yylval->str = strdup(yytext);
303 *(yylval->str+yyleng-1)=0;
305 if ( !strcmp(yylval->str,")") ) {
308 my_col++; /* XXX why ? */
318 if( parencount != 0) {
319 /* printf("Folding in a comma!\n"); */
325 if( !strcmp(yytext,"," ) ) {
330 yylval->str = strdup(yytext);
331 /* printf("Got argg2 word %s\n", yylval->str); */
335 *(yylval->str+yyleng-1)=0;
345 <argg>{NOARGG}[\]\}] {
346 char c = yytext[yyleng-1];
348 if ( pbcpop(c) ) { /* error */
350 ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched '%c' in expression!\n", my_file, my_lineno, my_col, c);
352 yylval->str = strdup(yytext);
360 <semic>{NOSEMIC}[\(\[\{] {
361 char c = yytext[yyleng-1];
367 <semic>{NOSEMIC}[\)\]\}] {
368 char c = yytext[yyleng-1];
370 if ( pbcpop(c) ) { /* error */
372 ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched '%c' in expression!\n", my_file, my_lineno, my_col, c);
374 yylval->str = strdup(yytext);
383 yylval->str = strdup(yytext);
385 *(yylval->str+yyleng-1)=0;
391 \#include[ \t]+\"[^\"]+\" {
393 char fnamebuf[1024],*p1,*p2;
394 int error = 1; /* don't use the file if set */
395 p1 = strchr(yytext,'"');
396 p2 = strrchr(yytext,'"');
397 if ( include_stack_index >= MAX_INCLUDE_DEPTH ) {
398 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);
399 } else if ( (int)(p2-p1) > sizeof(fnamebuf) - 1 ) {
400 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);
403 strncpy(fnamebuf, p1, p2-p1);
405 for (i=0; i<include_stack_index; i++) {
406 if ( !strcmp(fnamebuf,include_stack[i].fname )) {
407 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",
408 my_file, my_lineno, my_col, fnamebuf);
412 if (i == include_stack_index)
413 error = 0; /* we can use this file */
415 if ( !error ) { /* valid file name */
417 /* relative vs. absolute */
418 if ( *(p1+1) != '/' ) {
419 /* XXX must check overflows */
420 strcpy(fnamebuf,ast_config_AST_CONFIG_DIR);
421 strcat(fnamebuf,"/");
422 strcat(fnamebuf,p1+1);
424 strcpy(fnamebuf,p1+1);
425 in1 = fopen( fnamebuf, "r" );
427 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, fnamebuf);
431 stat(fnamebuf, &stats);
432 buffer = (char*)malloc(stats.st_size+1);
433 fread(buffer, 1, stats.st_size, in1);
434 buffer[stats.st_size] = 0;
435 ast_log(LOG_NOTICE," --Read in included file %s, %d chars\n",fnamebuf, (int)stats.st_size);
438 include_stack[include_stack_index].fname = my_file;
439 my_file = strdup(fnamebuf);
440 include_stack[include_stack_index].lineno = my_lineno;
441 include_stack[include_stack_index].colno = my_col+yyleng;
442 include_stack[include_stack_index++].bufstate = YY_CURRENT_BUFFER;
444 yy_switch_to_buffer(ael_yy_scan_string (buffer ,yyscanner),yyscanner);
454 if ( --include_stack_index < 0 ) {
458 yy_delete_buffer( YY_CURRENT_BUFFER, yyscanner );
459 yy_switch_to_buffer(include_stack[include_stack_index].bufstate, yyscanner );
460 my_lineno = include_stack[include_stack_index].lineno;
461 my_col = include_stack[include_stack_index].colno;
462 my_file = include_stack[include_stack_index].fname;
468 static void pbcpush(char x)
470 pbcstack[pbcpos++] = x;
473 static int pbcpop(char x)
475 if ( ( x == ')' && pbcstack[pbcpos-1] == '(' )
476 || ( x == ']' && pbcstack[pbcpos-1] == '[' )
477 || ( x == '}' && pbcstack[pbcpos-1] == '{' )) {
481 return 1; /* error */
484 static int c_prevword(void)
509 /* used by the bison code */
510 void reset_parencount(yyscan_t yyscanner );
511 void reset_parencount(yyscan_t yyscanner )
513 struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
521 /* used by the bison code */
522 void reset_semicount(yyscan_t yyscanner );
523 void reset_semicount(yyscan_t yyscanner )
525 struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
530 /* used by the bison code */
531 void reset_argcount(yyscan_t yyscanner );
532 void reset_argcount(yyscan_t yyscanner )
534 struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
543 /* used elsewhere, but some local vars */
544 struct pval *ael2_parse(char *filename, int *errors)
552 /* extern int ael_yydebug; */
554 io = calloc(sizeof(struct parse_io),1);
555 /* reset the global counters */
558 include_stack_index=0;
560 /* ael_yydebug = 1; */
561 ael_yylex_init(&io->scanner);
562 fin = fopen(filename,"r");
564 ast_log(LOG_ERROR,"File %s could not be opened\n", filename);
568 my_file = strdup(filename);
569 stat(filename, &stats);
570 buffer = (char*)malloc(stats.st_size+2);
571 fread(buffer, 1, stats.st_size, fin);
572 buffer[stats.st_size]=0;
575 ael_yy_scan_string (buffer ,io->scanner);
576 ael_yyset_lineno(1 , io->scanner);
578 /* ael_yyset_in (fin , io->scanner); OLD WAY */
584 *errors = io->syntax_error_count;
586 ael_yylex_destroy(io->scanner);