From 8b0c007ad990aa27d9868da49215fd1076ac77cc Mon Sep 17 00:00:00 2001 From: kpfleming Date: Mon, 21 Aug 2006 02:11:39 +0000 Subject: merge new_loader_completion branch, including (at least): - restructured build tree and makefiles to eliminate recursion problems - support for embedded modules - support for static builds - simpler cross-compilation support - simpler module/loader interface (no exported symbols) git-svn-id: http://svn.digium.com/svn/asterisk/trunk@40722 f38db490-d61c-443f-a65b-d21fe96a405b --- main/ast_expr2.fl | 405 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 405 insertions(+) create mode 100644 main/ast_expr2.fl (limited to 'main/ast_expr2.fl') diff --git a/main/ast_expr2.fl b/main/ast_expr2.fl new file mode 100644 index 000000000..df9668fe8 --- /dev/null +++ b/main/ast_expr2.fl @@ -0,0 +1,405 @@ +%{ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 1999 - 2006, Digium, Inc. + * + * Mark Spencer + * + * 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 Dialplan Expression Lexical Scanner + */ + +#include "asterisk.h" + +#ifndef STANDALONE +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") +#endif + +#include +#include +#include +#include +#include +#include +#if !defined(SOLARIS) && !defined(__CYGWIN__) +#include +#else +#define quad_t int64_t +#endif +#include +#include +#include + +#include "asterisk/ast_expr.h" +#include "asterisk/logger.h" +#include "asterisk/strings.h" + +enum valtype { + AST_EXPR_integer, AST_EXPR_numeric_string, AST_EXPR_string +} ; + +struct val { + enum valtype type; + union { + char *s; + quad_t i; + } u; +} ; + +#include "ast_expr2.h" /* the o/p of the bison on ast_expr2.y */ + +#define SET_COLUMNS do { \ + yylloc_param->first_column = (int)(yyg->yytext_r - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf); \ + yylloc_param->last_column += yyleng - 1; \ + yylloc_param->first_line = yylloc_param->last_line = 1; \ + } while (0) + +#define SET_STRING do { \ + yylval_param->val = calloc(1, sizeof(struct val)); \ + yylval_param->val->type = AST_EXPR_string; \ + yylval_param->val->u.s = strdup(yytext); \ + } while (0) + +#define SET_NUMERIC_STRING do { \ + yylval_param->val = calloc(1, sizeof(struct val)); \ + yylval_param->val->type = AST_EXPR_numeric_string; \ + yylval_param->val->u.s = strdup(yytext); \ + } while (0) + +struct parse_io +{ + char *string; + struct val *val; + yyscan_t scanner; +}; + +void ast_yyset_column(int column_no, yyscan_t yyscanner); +int ast_yyget_column(yyscan_t yyscanner); +static int curlycount = 0; +static char *expr2_token_subst(char *mess); +%} + +%option prefix="ast_yy" +%option batch +%option outfile="ast_expr2f.c" +%option reentrant +%option bison-bridge +%option bison-locations +%option noyywrap +%x var trail + +%% + +\| { SET_COLUMNS; SET_STRING; return TOK_OR;} +\& { SET_COLUMNS; SET_STRING; return TOK_AND;} +\= { SET_COLUMNS; SET_STRING; return TOK_EQ;} +\|\| { SET_COLUMNS; SET_STRING; return TOK_OR;} +\&\& { SET_COLUMNS; SET_STRING; return TOK_AND;} +\=\= { SET_COLUMNS; SET_STRING; return TOK_EQ;} +\=~ { SET_COLUMNS; SET_STRING; return TOK_EQTILDE;} +\> { SET_COLUMNS; SET_STRING; return TOK_GT;} +\< { SET_COLUMNS; SET_STRING; return TOK_LT;} +\>\= { SET_COLUMNS; SET_STRING; return TOK_GE;} +\<\= { SET_COLUMNS; SET_STRING; return TOK_LE;} +\!\= { SET_COLUMNS; SET_STRING; return TOK_NE;} +\+ { SET_COLUMNS; SET_STRING; return TOK_PLUS;} +\- { SET_COLUMNS; SET_STRING; return TOK_MINUS;} +\* { SET_COLUMNS; SET_STRING; return TOK_MULT;} +\/ { SET_COLUMNS; SET_STRING; return TOK_DIV;} +\% { SET_COLUMNS; SET_STRING; return TOK_MOD;} +\? { SET_COLUMNS; SET_STRING; return TOK_COND;} +\! { SET_COLUMNS; SET_STRING; return TOK_COMPL;} +\: { SET_COLUMNS; SET_STRING; return TOK_COLON;} +\:\: { SET_COLUMNS; SET_STRING; return TOK_COLONCOLON;} +\( { SET_COLUMNS; SET_STRING; return TOK_LP;} +\) { SET_COLUMNS; SET_STRING; return TOK_RP;} +\$\{ { + /* gather the contents of ${} expressions, with trailing stuff, + * into a single TOKEN. + * They are much more complex now than they used to be + */ + curlycount = 0; + BEGIN(var); + yymore(); + } + +[ \t\r] {} +\"[^"]*\" {SET_COLUMNS; SET_STRING; return TOKEN;} + +[\n] {/* what to do with eol */} +[0-9]+ { + SET_COLUMNS; + /* the original behavior of the expression parser was + * to bring in numbers as a numeric string + */ + SET_NUMERIC_STRING; + return TOKEN; + } + +[a-zA-Z0-9,.';\\_^$#@]+ { + SET_COLUMNS; + SET_STRING; + return TOKEN; + } + + +[^{}]*\} { + curlycount--; + if (curlycount < 0) { + BEGIN(trail); + yymore(); + } else { + yymore(); + } + } + +[^{}]*\{ { + curlycount++; + yymore(); + } + + +[^-\t\r \n$():?%/+=*<>!|&]* { + BEGIN(0); + SET_COLUMNS; + SET_STRING; + return TOKEN; + } + +[-\t\r \n$():?%/+=*<>!|&] { + char c = yytext[yyleng-1]; + BEGIN(0); + unput(c); + SET_COLUMNS; + SET_STRING; + return TOKEN; + } + +\$\{ { + curlycount = 0; + BEGIN(var); + yymore(); + } + +<> { + BEGIN(0); + SET_COLUMNS; + SET_STRING; + return TOKEN; + /*actually, if an expr is only a variable ref, this could happen a LOT */ + } + +%% + +/* I'm putting the interface routine to the whole parse here in the flexer input file + mainly because of all the flexer initialization that has to be done. Shouldn't matter + where it is, as long as it's somewhere. I didn't want to define a prototype for the + ast_yy_scan_string in the .y file, because then, I'd have to define YY_BUFFER_STATE there... + UGH! that would be inappropriate. */ + +int ast_yyparse(void *); /* need to/should define this prototype for the call to yyparse */ +int ast_yyerror(const char *, YYLTYPE *, struct parse_io *); /* likewise */ + +int ast_expr(char *expr, char *buf, int length) +{ + struct parse_io io; + int return_value = 0; + + memset(&io, 0, sizeof(io)); + io.string = expr; /* to pass to the error routine */ + + ast_yylex_init(&io.scanner); + + ast_yy_scan_string(expr, io.scanner); + + ast_yyparse ((void *) &io); + + ast_yylex_destroy(io.scanner); + + if (!io.val) { + if (length > 1) { + strcpy(buf, "0"); + return_value = 1; + } + } else { + if (io.val->type == AST_EXPR_integer) { + int res_length; + + res_length = snprintf(buf, length, "%ld", (long int) io.val->u.i); + return_value = (res_length <= length) ? res_length : length; + } else { +#ifdef STANDALONE + strncpy(buf, io.val->u.s, length - 1); +#else /* !STANDALONE */ + ast_copy_string(buf, io.val->u.s, length); +#endif /* STANDALONE */ + return_value = strlen(buf); + free(io.val->u.s); + } + free(io.val); + } + return return_value; +} + + +char extra_error_message[4095]; +int extra_error_message_supplied = 0; +void ast_expr_register_extra_error_info(char *message); +void ast_expr_clear_extra_error_info(void); + +void ast_expr_register_extra_error_info(char *message) +{ + extra_error_message_supplied=1; + strcpy(extra_error_message, message); +} + +void ast_expr_clear_extra_error_info(void) +{ + extra_error_message_supplied=0; + extra_error_message[0] = 0; +} + +static char *expr2_token_equivs1[] = +{ + "TOKEN", + "TOK_COND", + "TOK_COLONCOLON", + "TOK_OR", + "TOK_AND", + "TOK_EQ", + "TOK_GT", + "TOK_LT", + "TOK_GE", + "TOK_LE", + "TOK_NE", + "TOK_PLUS", + "TOK_MINUS", + "TOK_MULT", + "TOK_DIV", + "TOK_MOD", + "TOK_COMPL", + "TOK_COLON", + "TOK_EQTILDE", + "TOK_RP", + "TOK_LP" +}; + +static char *expr2_token_equivs2[] = +{ + "", + "?", + "::", + "|", + "&", + "=", + ">", + "<", + ">=", + "<=", + "!=", + "+", + "-", + "*", + "/", + "%", + "!", + ":", + "=~", + ")", + "(" +}; + + +static char *expr2_token_subst(char *mess) +{ + /* calc a length, malloc, fill, and return; yyerror had better free it! */ + int len=0,i; + char *p; + char *res, *s,*t; + int expr2_token_equivs_entries = sizeof(expr2_token_equivs1)/sizeof(char*); + + for (p=mess; *p; p++) { + for (i=0; iscanner); + char spacebuf[8000]; /* best safe than sorry */ + char spacebuf2[8000]; /* best safe than sorry */ + int i=0; + char *s2 = expr2_token_subst((char *)s); + spacebuf[0] = 0; + + for(i=0;i< (int)(yytext - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf);i++) spacebuf2[i] = ' '; /* uh... assuming yyg is defined, then I can use the yycolumn macro, + which is the same thing as... get this: + yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]->yy_bs_column + I was tempted to just use yy_buf_pos in the STATE, but..., well: + a. the yy_buf_pos is the current position in the buffer, which + may not relate to the entire string/buffer because of the + buffering. + b. but, analysis of the situation is that when you use the + yy_scan_string func, it creates a single buffer the size of + string, so the two would be the same... + so, in the end, the yycolumn macro is available, shorter, therefore easier. */ + spacebuf2[i++]='^'; + spacebuf2[i]= 0; + +#ifdef STANDALONE3 + /* easier to read in the standalone version */ + printf("ast_yyerror(): %s syntax error: %s; Input:\n%s\n%s\n", + (extra_error_message_supplied?extra_error_message:""), s2, parseio->string,spacebuf2); +#else + ast_log(LOG_WARNING,"ast_yyerror(): %s syntax error: %s; Input:\n%s\n%s\n", + (extra_error_message_supplied?extra_error_message:""), s2, parseio->string,spacebuf2); +#endif +#ifndef STANDALONE + ast_log(LOG_WARNING,"If you have questions, please refer to doc/channelvariables.txt in the asterisk source.\n"); +#endif + free(s2); + return(0); +} -- cgit v1.2.3