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 "common/darktable.h"
26#include <glib.h>
27#include <math.h>
28#include <stdio.h>
29#include <stdlib.h>
30
31typedef enum token_types_t
32{
33 T_NUMBER, // everything will be treated as floats
36
50
51typedef union token_data_t
52{
53 float number;
54 operators_t operator;
56
62
69
72static float read_number(parser_state_t *self)
73{
74 return g_ascii_strtod(self->p, &self->p);
75}
76
78{
79 if(IS_NULL_PTR(self->p)) return NULL;
80
81 dt_calc_token_t *token = (dt_calc_token_t *)malloc(sizeof(dt_calc_token_t));
82
83 for(; *self->p; self->p++)
84 {
85 switch(*self->p)
86 {
87 case ' ':
88 case '\t':
89 continue;
90 case '+':
91 if(self->p[1] == '+')
92 {
93 self->p += 2;
94 token->data.operator= O_INC;
95 }
96 else
97 {
98 self->p++;
99 token->data.operator= O_PLUS;
100 }
101 token->type = T_OPERATOR;
102 return token;
103 case '-':
104 if(self->p[1] == '-')
105 {
106 self->p += 2;
107 token->data.operator= O_DEC;
108 }
109 else
110 {
111 self->p++;
112 token->data.operator= O_MINUS;
113 }
114 token->type = T_OPERATOR;
115 return token;
116 case '*':
117 self->p++;
118 token->type = T_OPERATOR;
119 token->data.operator= O_MULTIPLY;
120 return token;
121 case '/':
122 self->p++;
123 token->type = T_OPERATOR;
124 token->data.operator= O_DIVISION;
125 return token;
126 case '%':
127 self->p++;
128 token->type = T_OPERATOR;
129 token->data.operator= O_MODULO;
130 return token;
131 case '^':
132 self->p++;
133 token->type = T_OPERATOR;
134 token->data.operator= O_POWER;
135 return token;
136 case '(':
137 self->p++;
138 token->type = T_OPERATOR;
139 token->data.operator= O_LEFTROUND;
140 return token;
141 case ')':
142 self->p++;
143 token->type = T_OPERATOR;
144 token->data.operator= O_RIGHTROUND;
145 return token;
146 case 'x':
147 case 'X':
148 self->p++;
149 token->type = T_NUMBER;
150 token->data.number = self->x;
151 return token;
152 case '0':
153 case '1':
154 case '2':
155 case '3':
156 case '4':
157 case '5':
158 case '6':
159 case '7':
160 case '8':
161 case '9':
162 case '.':
163 case ',':
164 {
165 token->data.number = read_number(self);
166 token->type = T_NUMBER;
167 return token;
168 }
169 default:
170 // people complained about the messages when "TRUE" was fed to the calculator
171 // printf("error: %c\n", *self->p);
172 break;
173 }
174 }
175
176 dt_free(token);
177 return NULL;
178}
179
182static float parse_expression(parser_state_t *self);
183static float parse_additive_expression(parser_state_t *self);
185static float parse_power_expression(parser_state_t *self);
186static float parse_unary_expression(parser_state_t *self);
187static float parse_primary_expression(parser_state_t *self);
188
190{
191 return parse_additive_expression(self);
192}
193
195{
196 if(IS_NULL_PTR(self->token)) return NAN;
197
198 float left = parse_multiplicative_expression(self);
199
200 while(self->token && self->token->type == T_OPERATOR)
201 {
202 const operators_t operator= self->token->data.operator;
203
204 if(operator!= O_PLUS &&operator!= O_MINUS) return left;
205
206 dt_free(self->token);
207 self->token = get_token(self);
208
209 const float right = parse_multiplicative_expression(self);
210
211 if(operator== O_PLUS)
212 left += right;
213 else if(operator== O_MINUS)
214 left -= right;
215 }
216
217 return left;
218}
219
221{
222 if(IS_NULL_PTR(self->token)) return NAN;
223
224 float left = parse_power_expression(self);
225
226 while(self->token && self->token->type == T_OPERATOR)
227 {
228 const operators_t operator= self->token->data.operator;
229
230 if(operator!= O_MULTIPLY &&operator!= O_DIVISION &&operator!= O_MODULO) return left;
231
232 dt_free(self->token);
233 self->token = get_token(self);
234
235 float right = parse_power_expression(self);
236
237 if(operator== O_MULTIPLY)
238 left *= right;
239 else if(operator== O_DIVISION)
240 left /= right;
241 else if(operator== O_MODULO)
242 left = fmodf(left, right);
243 }
244
245 return left;
246}
247
249{
250 if(IS_NULL_PTR(self->token)) return NAN;
251
252 float left = parse_unary_expression(self);
253
254 while(self->token && self->token->type == T_OPERATOR)
255 {
256 if(self->token->data.operator!= O_POWER) return left;
257
258 dt_free(self->token);
259 self->token = get_token(self);
260
261 const float right = parse_unary_expression(self);
262
263 left = powf(left, right);
264 }
265
266 return left;
267}
268
270{
271 if(IS_NULL_PTR(self->token)) return NAN;
272
273 if(self->token->type == T_OPERATOR)
274 {
275 if(self->token->data.operator== O_MINUS)
276 {
277 dt_free(self->token);
278 self->token = get_token(self);
279
280 return -1.0 * parse_unary_expression(self);
281 }
282 if(self->token->data.operator== O_PLUS)
283 {
284 dt_free(self->token);
285 self->token = get_token(self);
286
287 return parse_unary_expression(self);
288 }
289 }
290
291 return parse_primary_expression(self);
292}
293
295{
296 if(IS_NULL_PTR(self->token)) return NAN;
297
298 if(self->token->type == T_NUMBER)
299 {
300 const float result = self->token->data.number;
301 dt_free(self->token);
302 self->token = get_token(self);
303 return result;
304 }
305 if(self->token->type == T_OPERATOR && self->token->data.operator== O_LEFTROUND)
306 {
307 dt_free(self->token);
308 self->token = get_token(self);
309 const float result = parse_expression(self);
310 if(IS_NULL_PTR(self->token) || self->token->type != T_OPERATOR || self->token->data.operator!= O_RIGHTROUND)
311 return NAN;
312 dt_free(self->token);
313 self->token = get_token(self);
314 return result;
315 }
316
317 return NAN;
318}
319
322float dt_calculator_solve(const float x, const char *formula)
323{
324 if(IS_NULL_PTR(formula) || *formula == '\0') return NAN;
325
326 gchar *dotformula = g_strdup(formula);
327 parser_state_t *self = (parser_state_t *)malloc(sizeof(parser_state_t));
328
329 self->p = g_strdelimit(dotformula, ",", '.');
330 self->x = x;
331
332 self->token = get_token(self);
333
334 float result = .0f;
335
336 // operators_t operator = -1;
337 if(self->token && self->token->type == T_OPERATOR)
338 {
339 switch(self->token->data.operator)
340 {
341 case O_INC:
342 result = x + 1.0;
343 goto end;
344 case O_DEC:
345 result = x - 1.0;
346 goto end;
347 // case O_PLUS:
348 // case O_MINUS:
349 // case O_MULTIPLY:
350 // case O_DIVISION:
351 // case O_MODULO:
352 // case O_POWER:
353 // operator = self->token->data.operator;
354 // g_free(self->token);
355 // self->token = get_token(self);
356 // break;
357 default:
358 break;
359 }
360 }
361
362 result = parse_expression(self);
363
364 // switch(operator)
365 // {
366 // case O_PLUS: result = x + res; break;
367 // case O_MINUS: result = x - res; break;
368 // case O_MULTIPLY: result = x * res; break;
369 // case O_DIVISION: result = x / res; break;
370 // case O_MODULO: result = fmodf(x, res); break;
371 // case O_POWER: result = powf(x, res); break;
372 // default: break;
373 // }
374
375 if(self->token) result = NAN;
376
377end:
378 dt_free(self->token);
379 dt_free(self);
380 dt_free(dotformula);
381
382 return result;
383}
384
385// int main()
386// {
387// const char *input = "5/0";
388// float x = 3;
389//
390// printf("%s\n", input);
391//
392// float res = dt_calculator_solve(x, input);
393//
394// printf("%f\n", res);
395//
396// return 0;
397// }
398
399// clang-format off
400// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
401// vim: shiftwidth=2 expandtab tabstop=2 cindent
402// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
403// clang-format on
static float parse_expression(parser_state_t *self)
Definition calculator.c:189
static float parse_unary_expression(parser_state_t *self)
Definition calculator.c:269
static float parse_additive_expression(parser_state_t *self)
Definition calculator.c:194
static float read_number(parser_state_t *self)
Definition calculator.c:72
token_types_t
Definition calculator.c:32
@ T_OPERATOR
Definition calculator.c:34
@ T_NUMBER
Definition calculator.c:33
operators_t
Definition calculator.c:38
@ O_INC
Definition calculator.c:40
@ O_DEC
Definition calculator.c:42
@ O_MODULO
Definition calculator.c:45
@ O_DIVISION
Definition calculator.c:44
@ O_MINUS
Definition calculator.c:41
@ O_PLUS
Definition calculator.c:39
@ O_POWER
Definition calculator.c:46
@ O_RIGHTROUND
Definition calculator.c:48
@ O_LEFTROUND
Definition calculator.c:47
@ O_MULTIPLY
Definition calculator.c:43
float dt_calculator_solve(const float x, const char *formula)
Definition calculator.c:322
static float parse_multiplicative_expression(parser_state_t *self)
Definition calculator.c:220
static float parse_power_expression(parser_state_t *self)
Definition calculator.c:248
static float parse_primary_expression(parser_state_t *self)
Definition calculator.c:294
static dt_calc_token_t * get_token(parser_state_t *self)
Definition calculator.c:77
#define dt_free(ptr)
Definition darktable.h:456
#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 darktable.h:281
static const float x
token_types_t type
Definition calculator.c:59
token_data_t data
Definition calculator.c:60
dt_calc_token_t * token
Definition calculator.c:67
operators_t operator
Definition calculator.c:54