📄 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 */%x paren semic argg comment curlystate wordstate brackstate/* prefix used for various globally-visible functions and variables. * This renames also yywrap, but since we do not use it, we just * add option noyywrap to remove it. */%option prefix="ael_yy"%option noyywrap 8bit/* I specify this option to suppress flex generating code with ECHO in it. This generates compiler warnings in some systems; We've seen the fwrite generate Unused variable warnings with 4.1.2 gcc. Some systems have tweaked flex ECHO macro to keep the compiler happy. To keep the warning message from getting output, I added a default rule at the end of the patterns section */%option nodefault/* 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%{#include "asterisk.h"ASTERISK_FILE_VERSION(__FILE__, "$Revision: 162272 $")#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <glob.h>#if !defined(GLOB_ABORTED)#define GLOB_ABORTED GLOB_ABEND#endif#include "asterisk/logger.h"#include "asterisk/utils.h"#include "asterisk/lock.h"#include "asterisk/hashtab.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;/* * A similar stack to keep track of matching brackets ( [ { } ] ) in word tokens surrounded by ${ ... } */static char pbcstack2[400]; /* XXX missing size checks */static int pbcpos2 = 0;static void pbcpush2(char x);static int pbcpop2(char x);static int parencount2 = 0;/* * A similar stack to keep track of matching brackets ( [ { } ] ) in word tokens surrounded by $[ ... ] */static char pbcstack3[400]; /* XXX missing size checks */static int pbcpos3 = 0;static void pbcpush3(char x);static int pbcpop3(char x);static int parencount3 = 0;/* * current line, column and filename, updated as we read the input. */static int my_lineno = 1; /* current line in the source */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%}KEYWORD (context|abstract|extend|macro|globals|local|ignorepat|switch|if|ifTime|random|regexten|hint|else|goto|jump|return|break|continue|for|while|case|default|pattern|catch|switches|eswitches|includes)NOPARENS ([^()\[\]\{\}]|\\[()\[\]\{\}])*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); } /* the nice thing about comments is that you know exactly what ends them */\n { my_lineno++; my_col = 1; }[ ]+ { my_col += yyleng; }[\t]+ { my_col += (yyleng*8)-(my_col%8); }({KEYWORD}?[-a-zA-Z0-9'"_/.\<\>\*\+!$#\[\]]|{HIBIT}|(\\.)|(\$\{)|(\$\[)) { /* boy did I open a can of worms when I changed the lexical token "word". all the above keywords can be used as a beginning to a "word".- before, a "word" would match a longer sequence than the above keywords, and all would be well. But now "word" is a single char and feeds into a statemachine sort of sequence from there on. So... I added the {KEYWORD}? to the beginning of the word match sequence */ if (!strcmp(yytext,"${")) { parencount2 = 0; pbcpos2 = 0; pbcpush2('{'); /* push '{' so the last pcbpop (parencount2 = -1) will succeed */ BEGIN(curlystate); yymore(); } else if (!strcmp(yytext,"$[")) { parencount3 = 0; pbcpos3 = 0; pbcpush3('['); /* push '[' so the last pcbpop (parencount3 = -1) will succeed */ BEGIN(brackstate); yymore(); } else { BEGIN(wordstate); yymore(); } }<wordstate>[-a-zA-Z0-9'"_/.\<\>\*\+!$#\[\]] { yymore(); /* Keep going */ }<wordstate>{HIBIT} { yymore(); /* Keep going */ }<wordstate>(\\.) { yymore(); /* Keep Going */ }<wordstate>(\$\{) { /* the beginning of a ${} construct. prepare and pop into curlystate */ parencount2 = 0; pbcpos2 = 0; pbcpush2('{'); /* push '{' so the last pcbpop (parencount2 = -1) will succeed */ BEGIN(curlystate); yymore(); }<wordstate>(\$\[) { /* the beginning of a $[] construct. prepare and pop into brackstate */ parencount3 = 0; pbcpos3 = 0; pbcpush3('['); /* push '[' so the last pcbpop (parencount3 = -1) will succeed */ BEGIN(brackstate); yymore(); }<wordstate>([^a-zA-Z0-9\x80-\xff\x2d'"_/.\<\>\*\+!$#\[\]]) { /* a non-word constituent char, like a space, tab, curly, paren, etc */ char c = yytext[yyleng-1]; STORE_POS; yylval->str = malloc(yyleng); strncpy(yylval->str, yytext, yyleng); yylval->str[yyleng-1] = 0; unput(c); /* put this ending char back in the stream */ BEGIN(0); return word; }<curlystate>{NOPARENS}\} { if ( pbcpop2('}') ) { /* error */ STORE_LOC; ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched ')' in expression: %s !\n", my_file, my_lineno, my_col, yytext); BEGIN(0); yylval->str = malloc(yyleng+1); strncpy(yylval->str, yytext, yyleng); yylval->str[yyleng] = 0; return word; } parencount2--; if ( parencount2 >= 0) { yymore(); } else { BEGIN(wordstate); /* Finished with the current ${} construct. Return to word gathering state */ yymore(); } }<curlystate>{NOPARENS}[\(\[\{] { char c = yytext[yyleng-1]; if (c == '{') parencount2++; pbcpush2(c); yymore(); }<curlystate>{NOPARENS}[\]\)] { char c = yytext[yyleng-1]; if ( pbcpop2(c)) { /* error */ STORE_LOC; ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched '%c' in expression!\n", my_file, my_lineno, my_col, c); BEGIN(0); yylval->str = malloc(yyleng+1); strncpy(yylval->str, yytext, yyleng); yylval->str[yyleng] = 0; return word; } yymore(); }<brackstate>{NOPARENS}\] { if ( pbcpop3(']') ) { /* error */ STORE_LOC; ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched ')' in expression: %s !\n", my_file, my_lineno, my_col, yytext); BEGIN(0); yylval->str = malloc(yyleng+1); strncpy(yylval->str, yytext, yyleng); yylval->str[yyleng] = 0; return word; } parencount3--; if ( parencount3 >= 0) { yymore(); } else { BEGIN(wordstate); /* Finished with the current ${} construct. Return to word gathering state */ yymore(); } }<brackstate>{NOPARENS}[\(\[\{] { char c = yytext[yyleng-1]; if (c == '[') parencount3++; pbcpush3(c); yymore(); }<brackstate>{NOPARENS}[\}\)] { char c = yytext[yyleng-1]; if ( pbcpop3(c)) { /* error */ STORE_LOC; ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched '%c' in expression!\n", my_file, my_lineno, my_col, c); BEGIN(0); yylval->str = malloc(yyleng+1); strncpy(yylval->str, yytext, yyleng); yylval->str[yyleng] = 0; return word; } yymore(); } /* * 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 = malloc(yyleng+1); strncpy(yylval->str, yytext, yyleng); yylval->str[yyleng] = 0; prev_word = 0; return word; } parencount--; if ( parencount >= 0) { yymore(); } else { STORE_LOC; yylval->str = malloc(yyleng); strncpy(yylval->str, yytext, yyleng); yylval->str[yyleng-1] = 0; 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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -