Fix string copy compilation warnings
[fio.git] / exp / expression-parser.y
1 %{
2
3 /*
4  * (C) Copyright 2014, Stephen M. Cameron.
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License version 2 as
8  *  published by the Free Software Foundation.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  *
19  */
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <math.h>
24
25 struct parser_value_type {
26         double dval;
27         long long ival;
28         int has_dval;
29         int has_error;
30 };
31
32 typedef union valtype {
33         struct parser_value_type v;
34 } PARSER_VALUE_TYPE;
35
36 #define YYSTYPE PARSER_VALUE_TYPE
37
38 int yyerror(__attribute__((unused)) long long *result,
39                 __attribute__((unused)) double *dresult,
40                 __attribute__((unused)) int *has_error,
41                 __attribute__((unused)) int *units_specified,
42                 __attribute__((unused)) const char *msg);
43
44 extern int yylex(void);
45 extern void yyrestart(FILE *file);
46 extern int lexer_value_is_time;
47
48 %}
49
50 %union valtype {
51         struct parser_value_type {
52                 double dval;
53                 long long ival;
54                 int has_dval;
55                 int has_error;
56         } v;
57 };
58
59 %token <v> NUMBER
60 %token <v> BYE
61 %token <v> SUFFIX 
62 %left '-' '+'
63 %right SUFFIX
64 %left '*' '/'
65 %right '^'
66 %left '%'
67 %nonassoc UMINUS
68 %parse-param { long long *result }
69 %parse-param { double *dresult }
70 %parse-param { int *has_error }
71 %parse-param { int *units_specified }
72
73 %type <v> expression
74 %%
75
76 top_level:      expression {
77                                 *result = $1.ival;
78                                 *dresult = $1.dval;
79                                 *has_error = $1.has_error;
80                         }
81                 | expression error {
82                                 *result = $1.ival;
83                                 *dresult = $1.dval;
84                                 *has_error = 1;
85                         }
86 expression:     expression '+' expression { 
87                         if (!$1.has_dval && !$3.has_dval)
88                                 $$.ival = $1.ival + $3.ival;
89                         else
90                                 $$.ival = (long long) ($1.dval + $3.dval);
91                         $$.dval = $1.dval + $3.dval;
92                         $$.has_error = $1.has_error || $3.has_error;
93                 }
94         |       expression '-' expression {
95                         if (!$1.has_dval && !$3.has_dval)
96                                 $$.ival = $1.ival - $3.ival; 
97                         else
98                                 $$.ival = (long long) ($1.dval - $3.dval); 
99                         $$.dval = $1.dval - $3.dval; 
100                         $$.has_error = $1.has_error || $3.has_error;
101                 }
102         |       expression '*' expression {
103                         if (!$1.has_dval && !$3.has_dval)
104                                 $$.ival = $1.ival * $3.ival;
105                         else
106                                 $$.ival = (long long) ($1.dval * $3.dval);
107                         $$.dval = $1.dval * $3.dval;
108                         $$.has_error = $1.has_error || $3.has_error;
109                 }
110         |       expression '/' expression {
111                         if ($3.ival == 0)
112                                 yyerror(0, 0, 0, 0, "divide by zero");
113                         else
114                                 $$.ival = $1.ival / $3.ival;
115                         if ($3.dval < 1e-20 && $3.dval > -1e-20)
116                                 yyerror(0, 0, 0, 0, "divide by zero");
117                         else
118                                 $$.dval = $1.dval / $3.dval;
119                         if ($3.has_dval || $1.has_dval)
120                                 $$.ival = (long long) $$.dval;
121                         $$.has_error = $1.has_error || $3.has_error;
122                 }
123         |       '-' expression %prec UMINUS {
124                         $$.ival = -$2.ival;
125                         $$.dval = -$2.dval;
126                         $$.has_error = $2.has_error;
127                 }
128         |       '(' expression ')' { $$ = $2; }
129         |       expression SUFFIX {
130                         if (!$1.has_dval && !$2.has_dval)
131                                 $$.ival = $1.ival * $2.ival;
132                         else
133                                 $$.ival = (long long) $1.dval * $2.dval;
134                         if ($1.has_dval || $2.has_dval)
135                                 $$.dval = $1.dval * $2.dval;
136                         else
137                                 $$.dval = $1.ival * $2.ival;
138                         $$.has_error = $1.has_error || $2.has_error;
139                         *units_specified = 1;
140                 }
141         |       expression '%' expression {
142                         if ($1.has_dval || $3.has_dval)
143                                 yyerror(0, 0, 0, 0, "modulo on floats");
144                         if ($3.ival == 0)
145                                 yyerror(0, 0, 0, 0, "divide by zero");
146                         else {
147                                 $$.ival = $1.ival % $3.ival;
148                                 $$.dval = $$.ival;
149                         }
150                         $$.has_error = $1.has_error || $3.has_error;
151                 }
152         |       expression '^' expression {
153                         $$.has_error = $1.has_error || $3.has_error;
154                         if (!$1.has_dval && !$3.has_dval) {
155                                 int i;
156
157                                 if ($3.ival == 0) {
158                                         $$.ival = 1;
159                                 } else if ($3.ival > 0) {
160                                         long long tmp = $1.ival;
161                                         $$.ival = 1.0;
162                                         for (i = 0; i < $3.ival; i++)
163                                                 $$.ival *= tmp;
164                                 }  else {
165                                         /* integers, 2^-3, ok, we now have doubles */
166                                         double tmp;
167                                         if ($1.ival == 0 && $3.ival == 0) {
168                                                 tmp = 1.0;
169                                                 $$.has_error = 1;
170                                         } else {
171                                                 double x = (double) $1.ival;
172                                                 double y = (double) $3.ival;
173                                                 tmp = pow(x, y);
174                                         }
175                                         $$.ival = (long long) tmp;
176                                 }
177                                 $$.dval = pow($1.dval, $3.dval);
178                         } else {
179                                 $$.dval = pow($1.dval, $3.dval);
180                                 $$.ival = (long long) $$.dval;
181                         }
182                 }
183         |       NUMBER { $$ = $1; };
184 %%
185 #include <stdio.h>
186
187 /* Urgh.  yacc and lex are kind of horrible.  This is not thread safe, obviously. */
188 static int lexer_read_offset = 0;
189 static char lexer_input_buffer[1000];
190
191 int lexer_input(char* buffer, unsigned int *bytes_read, int bytes_requested)
192 {
193         int bytes_left = strlen(lexer_input_buffer) - lexer_read_offset;
194
195         if (bytes_requested > bytes_left )
196                 bytes_requested = bytes_left;
197         memcpy(buffer, &lexer_input_buffer[lexer_read_offset], bytes_requested);
198         *bytes_read = bytes_requested;
199         lexer_read_offset += bytes_requested;
200         return 0;
201 }
202
203 static void setup_to_parse_string(const char *string)
204 {
205         unsigned int len;
206
207         len = sizeof(lexer_input_buffer) - 3;
208         if (len > strlen(string))
209                 len = strlen(string);
210
211         strncpy(lexer_input_buffer, string, len);
212         lexer_input_buffer[len] = '\0'; 
213         lexer_input_buffer[len + 1] = '\0';  /* lex/yacc want string double null terminated! */
214         lexer_read_offset = 0;
215 }
216
217 int evaluate_arithmetic_expression(const char *buffer, long long *ival, double *dval,
218                                         double implied_units, int is_time)
219 {
220         int rc, units_specified = 0, has_error = 0;
221
222         lexer_value_is_time = is_time;
223         setup_to_parse_string(buffer);
224         rc = yyparse(ival, dval, &has_error, &units_specified);
225         yyrestart(NULL);
226         if (rc || has_error) {
227                 *ival = 0;
228                 *dval = 0;
229                 has_error = 1;
230         }
231         if (!units_specified) {
232                 *ival = (int) ((double) *ival * implied_units);
233                 *dval = *dval * implied_units;
234         }
235         return has_error;
236 }
237
238 int yyerror(__attribute__((unused)) long long *result,
239                 __attribute__((unused)) double *dresult,
240                 __attribute__((unused)) int *has_error,
241                 __attribute__((unused)) int *units_specified,
242                 __attribute__((unused)) const char *msg)
243 {
244         /* We do not need to do anything here. */
245         return 0;
246 }
247