git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@12544 65c4cc65-6c06-0410-ace0-fbb531ad65f3
208 lines
7 KiB
Text
208 lines
7 KiB
Text
%{
|
|
/*
|
|
* Asterisk -- An open source telephony toolkit.
|
|
*
|
|
* Copyright (C) 1999 - 2006, Digium, Inc.
|
|
*
|
|
* Mark Spencer <markster@digium.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 Dialplan Expression Parser
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <locale.h>
|
|
#include <ctype.h>
|
|
#if !defined(SOLARIS) && !defined(__CYGWIN__)
|
|
#include <err.h>
|
|
#else
|
|
#define quad_t int64_t
|
|
#endif
|
|
#include <errno.h>
|
|
#include <regex.h>
|
|
#include <limits.h>
|
|
#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 yylloc_param->first_column = (int)(yyg->yytext_r - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf);yylloc_param->last_column = yylloc_param->last_column + yyleng - 1; yylloc_param->first_line = yylloc_param->last_line = 1
|
|
#define SET_STRING yylval_param->val = (struct val *)calloc(sizeof(struct val),1); yylval_param->val->type = AST_EXPR_string; yylval_param->val->u.s = strdup(yytext);
|
|
#define SET_NUMERIC_STRING yylval_param->val = (struct val *)calloc(sizeof(struct val),1); yylval_param->val->type = AST_EXPR_numeric_string; yylval_param->val->u.s = strdup(yytext);
|
|
|
|
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;
|
|
%}
|
|
|
|
%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_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_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();}
|
|
|
|
[ \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;}
|
|
|
|
<var>[^{}]*\} {curlycount--; if(curlycount < 0){ BEGIN(trail); yymore();} else { yymore();}}
|
|
<var>[^{}]*\{ {curlycount++; yymore(); }
|
|
<trail>[^-\t\r \n$():?%/+=*<>!|&]* {BEGIN(0); SET_COLUMNS; SET_STRING; return TOKEN;}
|
|
<trail>[-\t\r \n$():?%/+=*<>!|&] {char c = yytext[yyleng-1]; BEGIN(0); unput(c); SET_COLUMNS; SET_STRING; return TOKEN;}
|
|
<trail>\$\{ {curlycount = 0; BEGIN(var); yymore(); }
|
|
<trail><<EOF>> {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;
|
|
}
|
|
|
|
int ast_yyerror (const char *s, yyltype *loc, struct parse_io *parseio )
|
|
{
|
|
struct yyguts_t * yyg = (struct yyguts_t*)(parseio->scanner);
|
|
char spacebuf[8000]; /* best safe than sorry */
|
|
char spacebuf2[8000]; /* best safe than sorry */
|
|
int i=0;
|
|
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(): syntax error: %s; Input:\n%s\n%s\n",
|
|
s, parseio->string,spacebuf2);
|
|
#else
|
|
ast_log(LOG_WARNING,"ast_yyerror(): syntax error: %s; Input:\n%s\n%s\n",
|
|
s, 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
|
|
return(0);
|
|
}
|