fix signed/unsigned result issue on 32-bit platforms (issue #5050)
[asterisk/asterisk.git] / ast_expr2.fl
1 %{
2 #include <sys/types.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <locale.h>
7 #include <ctype.h>
8 #ifndef SOLARIS
9 #include <err.h>
10 #else
11 #define quad_t int64_t
12 #endif
13 #include <errno.h>
14 #include <regex.h>
15 #include <limits.h>
16 #include <asterisk/ast_expr.h>
17 #include <asterisk/logger.h>
18
19 enum valtype {
20         AST_EXPR_integer, AST_EXPR_numeric_string, AST_EXPR_string
21 } ;
22
23 struct val {
24         enum valtype type;
25         union {
26                 char *s;
27                 quad_t i;
28         } u;
29 } ;
30
31 #include "ast_expr2.h" /* the o/p of the bison on ast_expr2.y */
32
33 #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
34 #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);
35 #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);
36
37 struct parse_io
38 {
39         char *string;
40         struct val *val;
41         yyscan_t scanner;
42 };
43  
44
45 %}
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
55 %%
56
57 \|      { SET_COLUMNS; SET_STRING; return TOK_OR;}
58 \&      { SET_COLUMNS; SET_STRING; return TOK_AND;}
59 \=      { SET_COLUMNS; SET_STRING; return TOK_EQ;}
60 \>      { SET_COLUMNS; SET_STRING; return TOK_GT;}
61 \<      { SET_COLUMNS; SET_STRING; return TOK_LT;}
62 \>\=    { SET_COLUMNS; SET_STRING; return TOK_GE;}
63 \<\=    { SET_COLUMNS; SET_STRING; return TOK_LE;}
64 \!\=    { SET_COLUMNS; SET_STRING; return TOK_NE;}
65 \+      { SET_COLUMNS; SET_STRING; return TOK_PLUS;}
66 \-      { SET_COLUMNS; SET_STRING; return TOK_MINUS;}
67 \*      { SET_COLUMNS; SET_STRING; return TOK_MULT;}
68 \/      { SET_COLUMNS; SET_STRING; return TOK_DIV;}
69 \%      { SET_COLUMNS; SET_STRING; return TOK_MOD;}
70 \?      { SET_COLUMNS; SET_STRING; return TOK_COND;}
71 \:      { SET_COLUMNS; SET_STRING; return TOK_COLON;}
72 \:\:    { SET_COLUMNS; SET_STRING; return TOK_COLONCOLON;}
73 \(      { SET_COLUMNS; SET_STRING; return TOK_LP;}
74 \)      { SET_COLUMNS; SET_STRING; return TOK_RP;}
75
76 [       \r]             {}
77 \"[^"]*\"   {SET_COLUMNS; SET_STRING; return TOKEN;}
78
79 [\n]    {/* what to do with eol */}
80 [0-9]+          {   SET_COLUMNS;  /* the original behavior of the expression parser was to bring in numbers as a numeric string */
81                                 SET_NUMERIC_STRING;
82                                 return TOKEN;}
83 [a-zA-Z0-9,.';{}\\_^%$#@!]+     {SET_COLUMNS; SET_STRING; return TOKEN;}
84
85 %%
86
87 /* I'm putting the interface routine to the whole parse here in the flexer input file
88    mainly because of all the flexer initialization that has to be done. Shouldn't matter
89    where it is, as long as it's somewhere. I didn't want to define a prototype for the
90    ast_yy_scan_string in the .y file, because then, I'd have to define YY_BUFFER_STATE there...
91         UGH! that would be inappropriate. */
92
93 int ast_yyparse( void *); /* need to/should define this prototype for the call to yyparse */
94 char *ast_expr(char *arg); /* and this prototype for the following func */
95 int             ast_yyerror(const char *,YYLTYPE *, struct parse_io *); /* likewise */
96
97 char *ast_expr (char *arg)
98 {
99         struct parse_io *io;
100         char *pirouni;
101         
102         io = (struct parse_io *)calloc(sizeof(struct parse_io),1);
103         io->string = arg;  /* to pass to the error routine */
104         
105         ast_yylex_init(&io->scanner);
106         
107         ast_yy_scan_string(arg,io->scanner);
108         
109         ast_yyparse ((void *)io);
110
111         ast_yylex_destroy(io->scanner);
112         
113
114         if (io->val==NULL) {
115                 pirouni=strdup("0");
116                 return(pirouni);
117         } else {
118                 if (io->val->type == AST_EXPR_integer) {
119                         pirouni = malloc(24);
120                         sprintf(pirouni, "%ld", io->val->u.i);
121                 }
122                 else {
123                         pirouni=strdup(io->val->u.s);
124                 }
125                 free(io->val);
126         }
127         free(io);
128         return(pirouni);
129 }
130
131 int ast_yyerror (const char *s,  yyltype *loc, struct parse_io *parseio )
132 {       
133         struct yyguts_t * yyg = (struct yyguts_t*)(parseio->scanner);
134         char spacebuf[8000]; /* best safe than sorry */
135         char spacebuf2[8000]; /* best safe than sorry */
136         int i=0;
137         spacebuf[0] = 0;
138         
139 #ifdef WHEN_LOC_MEANS_SOMETHING
140         if( loc->first_column > 7990 ) /* if things get out of whack, why crash? */
141                 loc->first_column = 7990;
142         if( loc->last_column > 7990 )
143                 loc->last_column = 7990;
144         for(i=0;i<loc->first_column;i++) spacebuf[i] = ' ';
145         for(   ;i<loc->last_column;i++) spacebuf[i] = '^';
146         spacebuf[i] = 0;
147 #endif
148         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,
149                                                                                                         which is the same thing as... get this:
150                                                                                                         yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]->yy_bs_column
151                                                                                                         I was tempted to just use yy_buf_pos in the STATE, but..., well:
152                                                                                                                 a. the yy_buf_pos is the current position in the buffer, which
153                                                                                                                         may not relate to the entire string/buffer because of the
154                                                                                                                         buffering.
155                                                                                                                 b. but, analysis of the situation is that when you use the
156                                                                                                                         yy_scan_string func, it creates a single buffer the size of
157                                                                                                                         string, so the two would be the same... 
158                                                                                                         so, in the end, the yycolumn macro is available, shorter, therefore easier. */
159         spacebuf2[i++]='^';
160         spacebuf2[i]= 0;
161
162 #ifdef STANDALONE3
163         /* easier to read in the standalone version */
164         printf("ast_yyerror(): syntax error: %s; Input:\n%s\n%s\n",  
165                         s, parseio->string,spacebuf2);
166 #else
167         ast_log(LOG_WARNING,"ast_yyerror(): syntax error: %s; Input:\n%s\n%s\n",  
168                         s, parseio->string,spacebuf2);
169 #endif
170 #ifndef STANDALONE
171         ast_log(LOG_WARNING,"If you have questions, please refer to doc/README.variables in the asterisk source.\n");
172 #endif
173         return(0);
174 }