ast_expr2.fl 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. %{
  2. /*! \file
  3. *
  4. * \brief Dialplan Expression Parser
  5. */
  6. #include <sys/types.h>
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <locale.h>
  11. #include <ctype.h>
  12. #if !defined(SOLARIS) && !defined(__CYGWIN__)
  13. #include <err.h>
  14. #else
  15. #define quad_t int64_t
  16. #endif
  17. #include <errno.h>
  18. #include <regex.h>
  19. #include <limits.h>
  20. #include <asterisk/ast_expr.h>
  21. #include <asterisk/logger.h>
  22. #include <asterisk/strings.h>
  23. enum valtype {
  24. AST_EXPR_integer, AST_EXPR_numeric_string, AST_EXPR_string
  25. } ;
  26. struct val {
  27. enum valtype type;
  28. union {
  29. char *s;
  30. quad_t i;
  31. } u;
  32. } ;
  33. #include "ast_expr2.h" /* the o/p of the bison on ast_expr2.y */
  34. #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
  35. #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);
  36. #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);
  37. struct parse_io
  38. {
  39. char *string;
  40. struct val *val;
  41. yyscan_t scanner;
  42. };
  43. void ast_yyset_column(int column_no, yyscan_t yyscanner);
  44. int ast_yyget_column(yyscan_t yyscanner);
  45. static int curlycount = 0;
  46. %}
  47. %option prefix="ast_yy"
  48. %option batch
  49. %option outfile="ast_expr2f.c"
  50. %option reentrant
  51. %option bison-bridge
  52. %option bison-locations
  53. %option noyywrap
  54. %x var trail
  55. %%
  56. \| { SET_COLUMNS; SET_STRING; return TOK_OR;}
  57. \& { SET_COLUMNS; SET_STRING; return TOK_AND;}
  58. \= { SET_COLUMNS; SET_STRING; return TOK_EQ;}
  59. \> { SET_COLUMNS; SET_STRING; return TOK_GT;}
  60. \< { SET_COLUMNS; SET_STRING; return TOK_LT;}
  61. \>\= { SET_COLUMNS; SET_STRING; return TOK_GE;}
  62. \<\= { SET_COLUMNS; SET_STRING; return TOK_LE;}
  63. \!\= { SET_COLUMNS; SET_STRING; return TOK_NE;}
  64. \+ { SET_COLUMNS; SET_STRING; return TOK_PLUS;}
  65. \- { SET_COLUMNS; SET_STRING; return TOK_MINUS;}
  66. \* { SET_COLUMNS; SET_STRING; return TOK_MULT;}
  67. \/ { SET_COLUMNS; SET_STRING; return TOK_DIV;}
  68. \% { SET_COLUMNS; SET_STRING; return TOK_MOD;}
  69. \? { SET_COLUMNS; SET_STRING; return TOK_COND;}
  70. \: { SET_COLUMNS; SET_STRING; return TOK_COLON;}
  71. \:\: { SET_COLUMNS; SET_STRING; return TOK_COLONCOLON;}
  72. \( { SET_COLUMNS; SET_STRING; return TOK_LP;}
  73. \) { SET_COLUMNS; SET_STRING; return TOK_RP;}
  74. \$\{ {/* gather the contents of ${} expressions, with trailing stuff, into a single TOKEN. They are much more complex now than they used to be */
  75. curlycount = 0; BEGIN(var); yymore();}
  76. [ \r] {}
  77. \"[^"]*\" {SET_COLUMNS; SET_STRING; return TOKEN;}
  78. [\n] {/* what to do with eol */}
  79. [0-9]+ { SET_COLUMNS; /* the original behavior of the expression parser was to bring in numbers as a numeric string */
  80. SET_NUMERIC_STRING;
  81. return TOKEN;}
  82. [a-zA-Z0-9,.';\\_^%$#@!]+ {SET_COLUMNS; SET_STRING; return TOKEN;}
  83. <var>[^{}]*\} {curlycount--; if(curlycount < 0){ BEGIN(trail); yymore();} else { yymore();}}
  84. <var>[^{}]*\{ {curlycount++; yymore(); }
  85. <trail>[^-\t\r \n$():?%/+=*<>!|&]* {BEGIN(0); SET_COLUMNS; SET_STRING; return TOKEN;}
  86. <trail>[-\t\r \n$():?%/+=*<>!|&] {char c = yytext[yyleng-1]; BEGIN(0); unput(c); SET_COLUMNS; SET_STRING; return TOKEN;}
  87. <trail>\$\{ {curlycount = 0; BEGIN(var); yymore(); }
  88. <trail><<EOF>> {BEGIN(0); SET_COLUMNS; SET_STRING; return TOKEN; /* actually, if an expr is only a variable ref, this could happen a LOT */}
  89. %%
  90. /* I'm putting the interface routine to the whole parse here in the flexer input file
  91. mainly because of all the flexer initialization that has to be done. Shouldn't matter
  92. where it is, as long as it's somewhere. I didn't want to define a prototype for the
  93. ast_yy_scan_string in the .y file, because then, I'd have to define YY_BUFFER_STATE there...
  94. UGH! that would be inappropriate. */
  95. int ast_yyparse(void *); /* need to/should define this prototype for the call to yyparse */
  96. int ast_yyerror(const char *, YYLTYPE *, struct parse_io *); /* likewise */
  97. int ast_expr(char *expr, char *buf, int length)
  98. {
  99. struct parse_io io;
  100. int return_value = 0;
  101. memset(&io, 0, sizeof(io));
  102. io.string = expr; /* to pass to the error routine */
  103. ast_yylex_init(&io.scanner);
  104. ast_yy_scan_string(expr, io.scanner);
  105. ast_yyparse ((void *) &io);
  106. ast_yylex_destroy(io.scanner);
  107. if (!io.val) {
  108. if (length > 1) {
  109. strcpy(buf, "0");
  110. return_value = 1;
  111. }
  112. } else {
  113. if (io.val->type == AST_EXPR_integer) {
  114. int res_length;
  115. res_length = snprintf(buf, length, "%ld", (long int) io.val->u.i);
  116. return_value = (res_length <= length) ? res_length : length;
  117. } else {
  118. #ifdef STANDALONE
  119. strncpy(buf, io.val->u.s, length - 1);
  120. #else /* !STANDALONE */
  121. ast_copy_string(buf, io.val->u.s, length);
  122. #endif /* STANDALONE */
  123. return_value = strlen(buf);
  124. free(io.val->u.s);
  125. }
  126. free(io.val);
  127. }
  128. return return_value;
  129. }
  130. int ast_yyerror (const char *s, yyltype *loc, struct parse_io *parseio )
  131. {
  132. struct yyguts_t * yyg = (struct yyguts_t*)(parseio->scanner);
  133. char spacebuf[8000]; /* best safe than sorry */
  134. char spacebuf2[8000]; /* best safe than sorry */
  135. int i=0;
  136. spacebuf[0] = 0;
  137. 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,
  138. which is the same thing as... get this:
  139. yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]->yy_bs_column
  140. I was tempted to just use yy_buf_pos in the STATE, but..., well:
  141. a. the yy_buf_pos is the current position in the buffer, which
  142. may not relate to the entire string/buffer because of the
  143. buffering.
  144. b. but, analysis of the situation is that when you use the
  145. yy_scan_string func, it creates a single buffer the size of
  146. string, so the two would be the same...
  147. so, in the end, the yycolumn macro is available, shorter, therefore easier. */
  148. spacebuf2[i++]='^';
  149. spacebuf2[i]= 0;
  150. #ifdef STANDALONE3
  151. /* easier to read in the standalone version */
  152. printf("ast_yyerror(): syntax error: %s; Input:\n%s\n%s\n",
  153. s, parseio->string,spacebuf2);
  154. #else
  155. ast_log(LOG_WARNING,"ast_yyerror(): syntax error: %s; Input:\n%s\n%s\n",
  156. s, parseio->string,spacebuf2);
  157. #endif
  158. #ifndef STANDALONE
  159. ast_log(LOG_WARNING,"If you have questions, please refer to doc/README.variables in the asterisk source.\n");
  160. #endif
  161. return(0);
  162. }