Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
calculator.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2013-2014, 2016 Tobias Ellinghaus.
4 Copyright (C) 2014 parafin.
5 Copyright (C) 2014 Ulrich Pegelow.
6 Copyright (C) 2016 Roman Lebedev.
7 Copyright (C) 2020 Heiko Bauke.
8 Copyright (C) 2020, 2022 Pascal Obry.
9 Copyright (C) 2022 Martin Baƙinka.
10
11 darktable is free software: you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
15
16 darktable is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with darktable. If not, see <http://www.gnu.org/licenses/>.
23*/
24
25#include "system/macros.h"
26#include "system/mem_alloc.h"
27#include <glib.h>
28#include <math.h>
29#include <stdio.h>
30#include <stdlib.h>
31
32typedef enum token_types_t
33{
34 T_NUMBER, // everything will be treated as floats
37
51
52typedef union token_data_t
53{
54 float number;
55 operators_t operator;
57
63
70
73static float read_number(parser_state_t *self)
74{
75 return g_ascii_strtod(self->p, &self->p);
76}
77
79{
80 if(IS_NULL_PTR(self->p)) return NULL;
81
82 dt_calc_token_t *token = (dt_calc_token_t *)malloc(sizeof(dt_calc_token_t));
83
84 for(; *self->p; self->p++)
85 {
86 switch(*self->p)
87 {
88 case ' ':
89 case '\t':
90 continue;
91 case '+':
92 if(self->p[1] == '+')
93 {
94 self->p += 2;
95 token->data.operator= O_INC;
96 }
97 else
98 {
99 self->p++;
100 token->data.operator= O_PLUS;
101 }
102 token->type = T_OPERATOR;
103 return token;
104 case '-':
105 if(self->p[1] == '-')
106 {
107 self->p += 2;
108 token->data.operator= O_DEC;
109 }
110 else
111 {
112 self->p++;
113 token->data.operator= O_MINUS;
114 }
115 token->type = T_OPERATOR;
116 return token;
117 case '*':
118 self->p++;
119 token->type = T_OPERATOR;
120 token->data.operator= O_MULTIPLY;
121 return token;
122 case '/':
123 self->p++;
124 token->type = T_OPERATOR;
125 token->data.operator= O_DIVISION;
126 return token;
127 case '%':
128 self->p++;
129 token->type = T_OPERATOR;
130 token->data.operator= O_MODULO;
131 return token;
132 case '^':
133 self->p++;
134 token->type = T_OPERATOR;
135 token->data.operator= O_POWER;
136 return token;
137 case '(':
138 self->p++;
139 token->type = T_OPERATOR;
140 token->data.operator= O_LEFTROUND;
141 return token;
142 case ')':
143 self->p++;
144 token->type = T_OPERATOR;
145 token->data.operator= O_RIGHTROUND;
146 return token;
147 case 'x':
148 case 'X':
149 self->p++;
150 token->type = T_NUMBER;
151 token->data.number = self->x;
152 return token;
153 case '0':
154 case '1':
155 case '2':
156 case '3':
157 case '4':
158 case '5':
159 case '6':
160 case '7':
161 case '8':
162 case '9':
163 case '.':
164 case ',':
165 {
166 token->data.number = read_number(self);
167 token->type = T_NUMBER;
168 return token;
169 }
170 default:
171 // people complained about the messages when "TRUE" was fed to the calculator
172 // printf("error: %c\n", *self->p);
173 break;
174 }
175 }
176
177 dt_free(token);
178 return NULL;
179}
180
183static float parse_expression(parser_state_t *self);
184static float parse_additive_expression(parser_state_t *self);
186static float parse_power_expression(parser_state_t *self);
187static float parse_unary_expression(parser_state_t *self);
188static float parse_primary_expression(parser_state_t *self);
189
191{
192 return parse_additive_expression(self);
193}
194
196{
197 if(IS_NULL_PTR(self->token)) return NAN;
198
199 float left = parse_multiplicative_expression(self);
200
201 while(self->token && self->token->type == T_OPERATOR)
202 {
203 const operators_t operator= self->token->data.operator;
204
205 if(operator!= O_PLUS &&operator!= O_MINUS) return left;
206
207 dt_free(self->token);
208 self->token = get_token(self);
209
210 const float right = parse_multiplicative_expression(self);
211
212 if(operator== O_PLUS)
213 left += right;
214 else if(operator== O_MINUS)
215 left -= right;
216 }
217
218 return left;
219}
220
222{
223 if(IS_NULL_PTR(self->token)) return NAN;
224
225 float left = parse_power_expression(self);
226
227 while(self->token && self->token->type == T_OPERATOR)
228 {
229 const operators_t operator= self->token->data.operator;
230
231 if(operator!= O_MULTIPLY &&operator!= O_DIVISION &&operator!= O_MODULO) return left;
232
233 dt_free(self->token);
234 self->token = get_token(self);
235
236 float right = parse_power_expression(self);
237
238 if(operator== O_MULTIPLY)
239 left *= right;
240 else if(operator== O_DIVISION)
241 left /= right;
242 else if(operator== O_MODULO)
243 left = fmodf(left, right);
244 }
245
246 return left;
247}
248
250{
251 if(IS_NULL_PTR(self->token)) return NAN;
252
253 float left = parse_unary_expression(self);
254
255 while(self->token && self->token->type == T_OPERATOR)
256 {
257 if(self->token->data.operator!= O_POWER) return left;
258
259 dt_free(self->token);
260 self->token = get_token(self);
261
262 const float right = parse_unary_expression(self);
263
264 left = powf(left, right);
265 }
266
267 return left;
268}
269
271{
272 if(IS_NULL_PTR(self->token)) return NAN;
273
274 if(self->token->type == T_OPERATOR)
275 {
276 if(self->token->data.operator== O_MINUS)
277 {
278 dt_free(self->token);
279 self->token = get_token(self);
280
281 return -1.0 * parse_unary_expression(self);
282 }
283 if(self->token->data.operator== O_PLUS)
284 {
285 dt_free(self->token);
286 self->token = get_token(self);
287
288 return parse_unary_expression(self);
289 }
290 }
291
292 return parse_primary_expression(self);
293}
294
296{
297 if(IS_NULL_PTR(self->token)) return NAN;
298
299 if(self->token->type == T_NUMBER)
300 {
301 const float result = self->token->data.number;
302 dt_free(self->token);
303 self->token = get_token(self);
304 return result;
305 }
306 if(self->token->type == T_OPERATOR && self->token->data.operator== O_LEFTROUND)
307 {
308 dt_free(self->token);
309 self->token = get_token(self);
310 const float result = parse_expression(self);
311 if(IS_NULL_PTR(self->token) || self->token->type != T_OPERATOR || self->token->data.operator!= O_RIGHTROUND)
312 return NAN;
313 dt_free(self->token);
314 self->token = get_token(self);
315 return result;
316 }
317
318 return NAN;
319}
320
323float dt_calculator_solve(const float x, const char *formula)
324{
325 if(IS_NULL_PTR(formula) || *formula == '\0') return NAN;
326
327 gchar *dotformula = g_strdup(formula);
328 parser_state_t *self = (parser_state_t *)malloc(sizeof(parser_state_t));
329
330 self->p = g_strdelimit(dotformula, ",", '.');
331 self->x = x;
332
333 self->token = get_token(self);
334
335 float result = .0f;
336
337 // operators_t operator = -1;
338 if(self->token && self->token->type == T_OPERATOR)
339 {
340 switch(self->token->data.operator)
341 {
342 case O_INC:
343 result = x + 1.0;
344 goto end;
345 case O_DEC:
346 result = x - 1.0;
347 goto end;
348 // case O_PLUS:
349 // case O_MINUS:
350 // case O_MULTIPLY:
351 // case O_DIVISION:
352 // case O_MODULO:
353 // case O_POWER:
354 // operator = self->token->data.operator;
355 // g_free(self->token);
356 // self->token = get_token(self);
357 // break;
358 default:
359 break;
360 }
361 }
362
363 result = parse_expression(self);
364
365 // switch(operator)
366 // {
367 // case O_PLUS: result = x + res; break;
368 // case O_MINUS: result = x - res; break;
369 // case O_MULTIPLY: result = x * res; break;
370 // case O_DIVISION: result = x / res; break;
371 // case O_MODULO: result = fmodf(x, res); break;
372 // case O_POWER: result = powf(x, res); break;
373 // default: break;
374 // }
375
376 if(self->token) result = NAN;
377
378end:
379 dt_free(self->token);
380 dt_free(self);
381 dt_free(dotformula);
382
383 return result;
384}
385
386// int main()
387// {
388// const char *input = "5/0";
389// float x = 3;
390//
391// printf("%s\n", input);
392//
393// float res = dt_calculator_solve(x, input);
394//
395// printf("%f\n", res);
396//
397// return 0;
398// }
399
400// clang-format off
401// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
402// vim: shiftwidth=2 expandtab tabstop=2 cindent
403// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
404// clang-format on
static float parse_expression(parser_state_t *self)
Definition calculator.c:190
static float parse_unary_expression(parser_state_t *self)
Definition calculator.c:270
static float parse_additive_expression(parser_state_t *self)
Definition calculator.c:195
static float read_number(parser_state_t *self)
Definition calculator.c:73
token_types_t
Definition calculator.c:33
@ T_OPERATOR
Definition calculator.c:35
@ T_NUMBER
Definition calculator.c:34
operators_t
Definition calculator.c:39
@ O_INC
Definition calculator.c:41
@ O_DEC
Definition calculator.c:43
@ O_MODULO
Definition calculator.c:46
@ O_DIVISION
Definition calculator.c:45
@ O_MINUS
Definition calculator.c:42
@ O_PLUS
Definition calculator.c:40
@ O_POWER
Definition calculator.c:47
@ O_RIGHTROUND
Definition calculator.c:49
@ O_LEFTROUND
Definition calculator.c:48
@ O_MULTIPLY
Definition calculator.c:44
float dt_calculator_solve(const float x, const char *formula)
Definition calculator.c:323
static float parse_multiplicative_expression(parser_state_t *self)
Definition calculator.c:221
static float parse_power_expression(parser_state_t *self)
Definition calculator.c:249
static float parse_primary_expression(parser_state_t *self)
Definition calculator.c:295
static dt_calc_token_t * get_token(parser_state_t *self)
Definition calculator.c:78
static const float x
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition macros.h:96
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
Definition mem_alloc.h:171
token_types_t type
Definition calculator.c:60
token_data_t data
Definition calculator.c:61
dt_calc_token_t * token
Definition calculator.c:68
operators_t operator
Definition calculator.c:55