3 * Asterisk -- An open source telephony toolkit.
5 * Copyright (C) 1999 - 2006, Digium, Inc.
7 * Mark Spencer <markster@digium.com>
9 * See http://www.asterisk.org for more information about
10 * the Asterisk project. Please do not directly contact
11 * any of the maintainers of this project for assistance;
12 * the project provides a web site, mailing lists and IRC
13 * channels for your use.
15 * This program is free software, distributed under the terms of
16 * the GNU General Public License Version 2. See the LICENSE file
17 * at the top of the source tree.
22 * \brief Dialplan Expression Lexical Scanner
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
31 #include <sys/types.h>
37 #if !defined(SOLARIS) && !defined(__CYGWIN__)
38 /* #include <err.h> */
40 #define quad_t int64_t
46 #include "asterisk/ast_expr.h"
47 #include "asterisk/logger.h"
48 #include "asterisk/strings.h"
51 AST_EXPR_integer, AST_EXPR_numeric_string, AST_EXPR_string
62 #include "ast_expr2.h" /* the o/p of the bison on ast_expr2.y */
64 #define SET_COLUMNS do { \
65 yylloc_param->first_column = (int)(yyg->yytext_r - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf); \
66 yylloc_param->last_column += yyleng - 1; \
67 yylloc_param->first_line = yylloc_param->last_line = 1; \
70 #define SET_STRING do { \
71 yylval_param->val = calloc(1, sizeof(struct val)); \
72 yylval_param->val->type = AST_EXPR_string; \
73 yylval_param->val->u.s = strdup(yytext); \
76 #define SET_NUMERIC_STRING do { \
77 yylval_param->val = calloc(1, sizeof(struct val)); \
78 yylval_param->val->type = AST_EXPR_numeric_string; \
79 yylval_param->val->u.s = strdup(yytext); \
89 void ast_yyset_column(int column_no, yyscan_t yyscanner);
90 int ast_yyget_column(yyscan_t yyscanner);
91 static int curlycount = 0;
92 static char *expr2_token_subst(const char *mess);
95 %option prefix="ast_yy"
97 %option outfile="ast_expr2f.c"
100 %option bison-locations
107 \| { SET_COLUMNS; SET_STRING; return TOK_OR;}
108 \& { SET_COLUMNS; SET_STRING; return TOK_AND;}
109 \= { SET_COLUMNS; SET_STRING; return TOK_EQ;}
110 \|\| { SET_COLUMNS; SET_STRING; return TOK_OR;}
111 \&\& { SET_COLUMNS; SET_STRING; return TOK_AND;}
112 \=\= { SET_COLUMNS; SET_STRING; return TOK_EQ;}
113 \=~ { SET_COLUMNS; SET_STRING; return TOK_EQTILDE;}
114 \> { SET_COLUMNS; SET_STRING; return TOK_GT;}
115 \< { SET_COLUMNS; SET_STRING; return TOK_LT;}
116 \>\= { SET_COLUMNS; SET_STRING; return TOK_GE;}
117 \<\= { SET_COLUMNS; SET_STRING; return TOK_LE;}
118 \!\= { SET_COLUMNS; SET_STRING; return TOK_NE;}
119 \+ { SET_COLUMNS; SET_STRING; return TOK_PLUS;}
120 \- { SET_COLUMNS; SET_STRING; return TOK_MINUS;}
121 \* { SET_COLUMNS; SET_STRING; return TOK_MULT;}
122 \/ { SET_COLUMNS; SET_STRING; return TOK_DIV;}
123 \% { SET_COLUMNS; SET_STRING; return TOK_MOD;}
124 \? { SET_COLUMNS; SET_STRING; return TOK_COND;}
125 \! { SET_COLUMNS; SET_STRING; return TOK_COMPL;}
126 \: { SET_COLUMNS; SET_STRING; return TOK_COLON;}
127 \:\: { SET_COLUMNS; SET_STRING; return TOK_COLONCOLON;}
128 \( { SET_COLUMNS; SET_STRING; return TOK_LP;}
129 \) { SET_COLUMNS; SET_STRING; return TOK_RP;}
131 /* gather the contents of ${} expressions, with trailing stuff,
132 * into a single TOKEN.
133 * They are much more complex now than they used to be
141 \"[^"]*\" {SET_COLUMNS; SET_STRING; return TOKEN;}
143 [\n] {/* what to do with eol */}
146 /* the original behavior of the expression parser was
147 * to bring in numbers as a numeric string
153 [a-zA-Z0-9,.';\\_^$#@]+ {
162 if (curlycount < 0) {
176 <trail>[^-\t\r \n$():?%/+=*<>!|&]* {
183 <trail>[-\t\r \n$():?%/+=*<>!|&] {
184 char c = yytext[yyleng-1];
203 /*actually, if an expr is only a variable ref, this could happen a LOT */
208 /* I'm putting the interface routine to the whole parse here in the flexer input file
209 mainly because of all the flexer initialization that has to be done. Shouldn't matter
210 where it is, as long as it's somewhere. I didn't want to define a prototype for the
211 ast_yy_scan_string in the .y file, because then, I'd have to define YY_BUFFER_STATE there...
212 UGH! that would be inappropriate. */
214 int ast_yyparse(void *); /* need to/should define this prototype for the call to yyparse */
215 int ast_yyerror(const char *, YYLTYPE *, struct parse_io *); /* likewise */
217 void ast_yyfree(void *ptr, yyscan_t yyscanner)
219 if (ptr) /* the normal generated yyfree func just frees its first arg;
220 this get complaints on some systems, as sometimes this
221 arg is a nil ptr! It's usually not fatal, but is irritating! */
222 free( (char *) ptr );
225 int ast_expr(char *expr, char *buf, int length)
228 int return_value = 0;
230 memset(&io, 0, sizeof(io));
231 io.string = expr; /* to pass to the error routine */
233 ast_yylex_init(&io.scanner);
235 ast_yy_scan_string(expr, io.scanner);
237 ast_yyparse ((void *) &io);
239 ast_yylex_destroy(io.scanner);
247 if (io.val->type == AST_EXPR_integer) {
250 res_length = snprintf(buf, length, "%ld", (long int) io.val->u.i);
251 return_value = (res_length <= length) ? res_length : length;
253 #if defined(STANDALONE) || defined(LOW_MEMORY) || defined(STANDALONE_AEL)
254 strncpy(buf, io.val->u.s, length - 1);
255 #else /* !STANDALONE && !LOW_MEMORY */
256 ast_copy_string(buf, io.val->u.s, length);
257 #endif /* STANDALONE || LOW_MEMORY */
258 return_value = strlen(buf);
267 char extra_error_message[4095];
268 int extra_error_message_supplied = 0;
269 void ast_expr_register_extra_error_info(char *message);
270 void ast_expr_clear_extra_error_info(void);
272 void ast_expr_register_extra_error_info(char *message)
274 extra_error_message_supplied=1;
275 strcpy(extra_error_message, message);
278 void ast_expr_clear_extra_error_info(void)
280 extra_error_message_supplied=0;
281 extra_error_message[0] = 0;
284 static char *expr2_token_equivs1[] =
309 static char *expr2_token_equivs2[] =
335 static char *expr2_token_subst(const char *mess)
337 /* calc a length, malloc, fill, and return; yyerror had better free it! */
341 int expr2_token_equivs_entries = sizeof(expr2_token_equivs1)/sizeof(char*);
343 for (p=mess; *p; p++) {
344 for (i=0; i<expr2_token_equivs_entries; i++) {
345 if ( strncmp(p,expr2_token_equivs1[i],strlen(expr2_token_equivs1[i])) == 0 )
347 len+=strlen(expr2_token_equivs2[i])+2;
348 p += strlen(expr2_token_equivs1[i])-1;
354 res = (char*)malloc(len+1);
359 for (i=0; i<expr2_token_equivs_entries; i++) {
360 if ( strncmp(p,expr2_token_equivs1[i],strlen(expr2_token_equivs1[i])) == 0 ) {
362 for (t=expr2_token_equivs2[i]; *t;) {
366 p += strlen(expr2_token_equivs1[i]);
378 int ast_yyerror (const char *s, yyltype *loc, struct parse_io *parseio )
380 struct yyguts_t * yyg = (struct yyguts_t*)(parseio->scanner);
381 char spacebuf[8000]; /* best safe than sorry */
382 char spacebuf2[8000]; /* best safe than sorry */
384 char *s2 = expr2_token_subst(s);
387 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,
388 which is the same thing as... get this:
389 yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]->yy_bs_column
390 I was tempted to just use yy_buf_pos in the STATE, but..., well:
391 a. the yy_buf_pos is the current position in the buffer, which
392 may not relate to the entire string/buffer because of the
394 b. but, analysis of the situation is that when you use the
395 yy_scan_string func, it creates a single buffer the size of
396 string, so the two would be the same...
397 so, in the end, the yycolumn macro is available, shorter, therefore easier. */
402 /* easier to read in the standalone version */
403 printf("ast_yyerror(): %s syntax error: %s; Input:\n%s\n%s\n",
404 (extra_error_message_supplied?extra_error_message:""), s2, parseio->string,spacebuf2);
406 ast_log(LOG_WARNING,"ast_yyerror(): %s syntax error: %s; Input:\n%s\n%s\n",
407 (extra_error_message_supplied?extra_error_message:""), s2, parseio->string,spacebuf2);
410 ast_log(LOG_WARNING,"If you have questions, please refer to doc/channelvariables.txt in the asterisk source.\n");