Warning, /education/labplot/src/backend/gsl/parser.ypp is written in an unsupported language. File is not indexed.
0001 /* 0002 File : parser.ypp 0003 Project : LabPlot 0004 Description : Parser for mathematical expressions 0005 -------------------------------------------------------------------- 0006 SPDX-FileCopyrightText: 2014 Alexander Semke <alexander.semke@web.de> 0007 SPDX-FileCopyrightText: 2014-2020 Stefan Gerlach <stefan.gerlach@uni.kn> 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 %{ 0012 #include <cstring> 0013 #include <cctype> 0014 #include <cstdlib> 0015 #include <clocale> 0016 #include <cmath> 0017 #ifdef HAVE_XLOCALE 0018 #include <xlocale.h> 0019 #endif 0020 #include "parser.h" 0021 #include "constants.h" 0022 #include "functions.h" 0023 #if defined(_WIN32) 0024 #define locale_t _locale_t 0025 #define strtod_l _strtod_l 0026 #define freelocale _free_locale 0027 #endif 0028 0029 #include <gsl/gsl_sf_gamma.h> 0030 0031 #ifdef PDEBUG 0032 #include <cstdio> 0033 #define pdebug(...) fprintf(stderr, __VA_ARGS__) 0034 #else 0035 #define pdebug(...) {} 0036 #endif 0037 0038 #define YYERROR_VERBOSE 1 0039 0040 /* params passed to yylex (and yyerror) */ 0041 typedef struct param { 0042 size_t pos; /* current position in string */ 0043 char* string; /* the string to parse */ 0044 const char* locale; /* name of locale to convert numbers */ 0045 } param; 0046 0047 int yyerror(param *p, const char *err); 0048 int yylex(param *p); 0049 int _variablesCounter = 0; 0050 bool skipSpecialFunctionEvaluation = false; 0051 0052 int variablesCounter() { 0053 return _variablesCounter; 0054 } 0055 0056 double res; 0057 char _lastErrorMessage[256] = ""; 0058 0059 const char* lastErrorMessage() { 0060 return _lastErrorMessage; 0061 } 0062 0063 static void wrongArgumentNumberMessage(const char* function_name, int provided, int expected) { 0064 snprintf(_lastErrorMessage, sizeof(_lastErrorMessage), "Parsing Error: Wrong argument count for %s. Provided: %d, Expected: %d", function_name, provided, expected); 0065 } 0066 0067 static void wrongArgumentInternalErrorMessage(const char* function_name, int expected) { 0068 snprintf(_lastErrorMessage, sizeof(_lastErrorMessage), "Internal parsing Error: Wrong argument count for %s. Expected: %d , but function does not have this number of arguments", function_name, expected); 0069 } 0070 0071 static void notImplementedError(const char* function_name) { 0072 snprintf(_lastErrorMessage, sizeof(_lastErrorMessage), "Parsing Error: '%s' not implemented.", function_name); 0073 } 0074 0075 static void yyerrorFunction(const char* function_name, const char* msg) { 0076 snprintf(_lastErrorMessage, sizeof(_lastErrorMessage), "Parsing Error: In function '%s': %s", function_name, msg); 0077 } 0078 0079 static void yyerror(const char* msg) { 0080 snprintf(_lastErrorMessage, sizeof(_lastErrorMessage), "Parsing Error: %s", msg); 0081 } 0082 0083 0084 0085 %} 0086 0087 %lex-param {param *p} 0088 %parse-param {param *p} 0089 0090 %union { 0091 double dval; /* For returning numbers */ 0092 symbol *tptr; /* For returning symbol-table pointers */ 0093 } 0094 0095 %token <dval> NUM /* Simple double precision number */ 0096 %token <tptr> VAR FNCT SPECFNCT /* VARiable and FuNCTion and Special functions*/ 0097 /* https://www.gnu.org/software/bison/manual/html_node/Token-Decl.html */ 0098 %token <operator> OR "||" 0099 %token <operator> AND "&&" 0100 %token <operator> LE "<=" 0101 %token <operator> GE ">=" 0102 %type <dval> expr 0103 0104 %right '=' 0105 %left '-' '+' OR LE GE '<' '>' 0106 %left '*' '/' '%' AND 0107 %left NEG /* Negation--unary minus */ 0108 %right '^' '!' 0109 0110 %% 0111 input: /* empty */ 0112 | input line 0113 ; 0114 0115 line: '\n' 0116 | expr '\n' { res=$1; } 0117 | error '\n' { yyerrok; } 0118 ; 0119 0120 expr: NUM { $$ = $1; } 0121 | VAR { $$ = std::get<double>($1->value); _variablesCounter++;} 0122 | VAR '=' expr { $$ = std::get<double>($1->value) = $3; _variablesCounter++; } 0123 | SPECFNCT '(' ')' { 0124 const auto& special_function = std::get<special_function_def>($1->value); 0125 if (!special_function.payload.expired() && !special_function.payload.lock()->constant) 0126 _variablesCounter++; 0127 const int argc = special_function.funsptr->argc; 0128 if (argc != 0) { 0129 wrongArgumentNumberMessage($1->name, 0, argc); 0130 yynerrs++; 0131 return 1; 0132 } 0133 try { 0134 const auto function = std::get<func_tPayload>(special_function.funsptr->fnct); 0135 if (!skipSpecialFunctionEvaluation) { 0136 if (function == nullptr) { 0137 notImplementedError($1->name); 0138 yynerrs++; 0139 return 2; 0140 } 0141 $$ = function(special_function.payload); 0142 } else 0143 $$ = std::nan("0"); 0144 } catch (const std::bad_variant_access& ex) { 0145 wrongArgumentInternalErrorMessage($1->name, 0); 0146 yynerrs++; 0147 return 1; 0148 } 0149 } 0150 | SPECFNCT '(' VAR ')' { 0151 const auto& special_function = std::get<special_function_def>($1->value); 0152 if (!special_function.payload.expired() && !special_function.payload.lock()->constant) 0153 _variablesCounter++; 0154 const int argc = special_function.funsptr->argc; 0155 if (argc != 1) { 0156 wrongArgumentNumberMessage($1->name, 1, argc); 0157 yynerrs++; 0158 return 1; 0159 } 0160 try { 0161 const auto function = std::get<func_t1Payload>(special_function.funsptr->fnct); 0162 if (!skipSpecialFunctionEvaluation) { 0163 if (function == nullptr) { 0164 notImplementedError($1->name); 0165 yynerrs++; 0166 return 2; 0167 } 0168 $$ = function($3->name, special_function.payload); 0169 } else 0170 $$ = std::nan("0"); 0171 } catch (const std::bad_variant_access& ex) { 0172 wrongArgumentInternalErrorMessage($1->name, 1); 0173 yynerrs++; 0174 return 1; 0175 } 0176 } 0177 | SPECFNCT '(' expr ';' VAR ')' { 0178 const auto& special_function = std::get<special_function_def>($1->value); 0179 if (!special_function.payload.expired() && !special_function.payload.lock()->constant) 0180 _variablesCounter++; 0181 const int argc = special_function.funsptr->argc; 0182 if (argc != 2) { 0183 wrongArgumentNumberMessage($1->name, 2, argc); 0184 yynerrs++; 0185 return 1; 0186 } 0187 try { 0188 const auto function = std::get<func_t2Payload>(special_function.funsptr->fnct); 0189 if (!skipSpecialFunctionEvaluation) { 0190 if (function == nullptr) { 0191 notImplementedError($1->name); 0192 yynerrs++; 0193 return 2; 0194 } 0195 $$ = function($3 ,$5->name, special_function.payload); 0196 } else 0197 $$ = std::nan("0"); 0198 } catch (const std::bad_variant_access& ex) { 0199 wrongArgumentInternalErrorMessage($1->name, 2); 0200 yynerrs++; 0201 return 1; 0202 } 0203 } 0204 | SPECFNCT '(' expr ';' expr ';' VAR ')' { 0205 const auto& special_function = std::get<special_function_def>($1->value); 0206 if (!special_function.payload.expired() && !special_function.payload.lock()->constant) 0207 _variablesCounter++; 0208 const int argc = special_function.funsptr->argc; 0209 if (argc != 3) { 0210 wrongArgumentNumberMessage($1->name, 3, argc); 0211 yynerrs++; 0212 return 1; 0213 } 0214 try { 0215 const auto function = std::get<func_t3Payload>(special_function.funsptr->fnct); 0216 if (!skipSpecialFunctionEvaluation) { 0217 if (function == nullptr) { 0218 notImplementedError($1->name); 0219 yynerrs++; 0220 return 2; 0221 } 0222 $$ = function($3, $5, $7->name, special_function.payload); 0223 } else 0224 $$ = std::nan("0"); 0225 } catch (const std::bad_variant_access& ex) { 0226 wrongArgumentInternalErrorMessage($1->name, 3); 0227 yynerrs++; 0228 return 1; 0229 } 0230 } 0231 | SPECFNCT '(' expr ';' expr ';' expr ';' VAR ')' { 0232 const auto& special_function = std::get<special_function_def>($1->value); 0233 if (!special_function.payload.expired() && !special_function.payload.lock()->constant) 0234 _variablesCounter++; 0235 const int argc = special_function.funsptr->argc; 0236 if (argc != 4) { 0237 wrongArgumentNumberMessage($1->name, 4, argc); 0238 yynerrs++; 0239 return 1; 0240 } 0241 try { 0242 const auto function = std::get<func_t4Payload>(special_function.funsptr->fnct); 0243 if (!skipSpecialFunctionEvaluation) { 0244 if (function == nullptr) { 0245 notImplementedError($1->name); 0246 yynerrs++; 0247 return 2; 0248 } 0249 $$ = function($3, $5, $7, $9->name, special_function.payload); 0250 } else 0251 $$ = std::nan("0"); 0252 } catch (const std::bad_variant_access& ex) { 0253 wrongArgumentInternalErrorMessage($1->name, 4); 0254 yynerrs++; 0255 return 1; 0256 } 0257 0258 0259 } 0260 | SPECFNCT '(' expr ')' { yynerrs++; yyerrorFunction($1->name, "Argument must be a variable not an expression");} 0261 | SPECFNCT '(' expr ';' expr ')' { yynerrs++; yyerrorFunction($1->name, "Last argument must be a variable not an expression");} 0262 | SPECFNCT '(' expr ';' expr ';' expr ')' { yynerrs++; yyerrorFunction($1->name, "Last argument must be a variable not an expression");} 0263 | SPECFNCT '(' expr ';' expr ';' expr ';' expr ')' { yynerrs++; yyerrorFunction($1->name, "Last argument must be a variable not an expression");} 0264 | FNCT '(' ')' { 0265 const funs* function = std::get<funs*>($1->value); 0266 const int argc = function->argc; 0267 if (argc != 0) { 0268 wrongArgumentNumberMessage($1->name, 0, argc); 0269 yynerrs++; 0270 return 1; 0271 } else { 0272 try { 0273 const auto fnct_ptr = std::get<func_t>(function->fnct); 0274 $$ = fnct_ptr(); 0275 } catch (const std::bad_variant_access& ex) { 0276 wrongArgumentInternalErrorMessage($1->name, 0); 0277 yynerrs++; 0278 return 1; 0279 } 0280 } 0281 } 0282 | FNCT '(' expr ')' { 0283 const funs* function = std::get<funs*>($1->value); 0284 const int argc = function->argc; 0285 if (argc != 1) { 0286 wrongArgumentNumberMessage($1->name, 1, argc); 0287 yynerrs++; 0288 return 1; 0289 } else { 0290 try { 0291 const auto fnct_ptr = std::get<func_t1>(function->fnct); 0292 $$ = fnct_ptr($3); 0293 } catch (const std::bad_variant_access& ex) { 0294 wrongArgumentInternalErrorMessage($1->name, 1); 0295 yynerrs++; 0296 return 1; 0297 } 0298 } 0299 } 0300 | FNCT '(' expr ',' expr ')' { 0301 const funs* function = std::get<funs*>($1->value); 0302 const int argc = function->argc; 0303 if (argc != 2) { 0304 wrongArgumentNumberMessage($1->name, 2, argc); 0305 yynerrs++; 0306 return 1; 0307 } else { 0308 try { 0309 const auto fnct_ptr = std::get<func_t2>(function->fnct); 0310 $$ = fnct_ptr($3,$5); 0311 } catch (const std::bad_variant_access& ex) { 0312 wrongArgumentInternalErrorMessage($1->name, 2); 0313 yynerrs++; 0314 return 1; 0315 } 0316 } 0317 } 0318 | FNCT '(' expr ',' expr ',' expr ')' { 0319 const funs* function = std::get<funs*>($1->value); 0320 const int argc = function->argc; 0321 if (argc != 3) { 0322 wrongArgumentNumberMessage($1->name, 3, argc); 0323 yynerrs++; 0324 return 1; 0325 } else { 0326 try { 0327 const auto fnct_ptr = std::get<func_t3>(function->fnct); 0328 $$ = fnct_ptr($3,$5,$7); 0329 } catch (const std::bad_variant_access& ex) { 0330 wrongArgumentInternalErrorMessage($1->name, 3); 0331 yynerrs++; 0332 return 1; 0333 } 0334 } 0335 } 0336 | FNCT '(' expr ',' expr ',' expr ',' expr ')' { 0337 const funs* function = std::get<funs*>($1->value); 0338 const int argc = function->argc; 0339 if (argc != 4) { 0340 wrongArgumentNumberMessage($1->name, 4, argc); 0341 yynerrs++; 0342 return 1; 0343 } else { 0344 try { 0345 const auto fnct_ptr = std::get<func_t4>(function->fnct); 0346 $$ = fnct_ptr($3,$5,$7,$9); 0347 } catch (const std::bad_variant_access& ex) { 0348 wrongArgumentInternalErrorMessage($1->name, 4); 0349 yynerrs++; 0350 return 1; 0351 } 0352 } 0353 } 0354 | FNCT '(' expr ';' expr ')' { 0355 const funs* function = std::get<funs*>($1->value); 0356 const int argc = function->argc; 0357 if (argc != 2) { 0358 wrongArgumentNumberMessage($1->name, 2, argc); 0359 yynerrs++; 0360 return 1; 0361 } else { 0362 try { 0363 const auto fnct_ptr = std::get<func_t2>(function->fnct); 0364 $$ = fnct_ptr($3,$5); 0365 } catch (const std::bad_variant_access& ex) { 0366 wrongArgumentInternalErrorMessage($1->name, 2); 0367 yynerrs++; 0368 return 1; 0369 } 0370 } 0371 } 0372 | FNCT '(' expr ';' expr ';' expr ')' { 0373 const funs* function = std::get<funs*>($1->value); 0374 const int argc = function->argc; 0375 if (argc != 3) { 0376 wrongArgumentNumberMessage($1->name, 3, argc); 0377 yynerrs++; 0378 return 1; 0379 } else { 0380 try { 0381 const auto fnct_ptr = std::get<func_t3>(function->fnct); 0382 $$ = fnct_ptr($3,$5,$7); 0383 } catch (const std::bad_variant_access& ex) { 0384 wrongArgumentInternalErrorMessage($1->name, 3); 0385 yynerrs++; 0386 return 1; 0387 } 0388 } 0389 } 0390 | FNCT '(' expr ';' expr ';' expr ';' expr ')' { 0391 const funs* function = std::get<funs*>($1->value); 0392 const int argc = function->argc; 0393 if (argc != 4) { 0394 wrongArgumentNumberMessage($1->name, 4, argc); 0395 yynerrs++; 0396 return 1; 0397 } else { 0398 try { 0399 const auto fnct_ptr = std::get<func_t4>(function->fnct); 0400 $$ = fnct_ptr($3,$5,$7,$9); 0401 } catch (const std::bad_variant_access& ex) { 0402 wrongArgumentInternalErrorMessage($1->name, 4); 0403 yynerrs++; 0404 return 1; 0405 } 0406 } 0407 } 0408 | FNCT '(' expr ';' expr ';' expr ';' expr ';' expr ')' { 0409 const funs* function = std::get<funs*>($1->value); 0410 const int argc = function->argc; 0411 if (argc != 5) { 0412 wrongArgumentNumberMessage($1->name, 5, argc); 0413 yynerrs++; 0414 return 1; 0415 } else { 0416 try { 0417 const auto fnct_ptr = std::get<func_t5>(function->fnct); 0418 $$ = fnct_ptr($3,$5,$7,$9,$11); 0419 } catch (const std::bad_variant_access& ex) { 0420 wrongArgumentInternalErrorMessage($1->name, 5); 0421 yynerrs++; 0422 return 1; 0423 } 0424 } 0425 } 0426 | expr '+' expr { $$ = $1 + $3; } 0427 | expr '-' expr { $$ = $1 - $3; } 0428 | expr OR expr { $$ = orFunction($1, $3); } 0429 | expr '*' expr { $$ = $1 * $3; } 0430 | expr '/' expr { $$ = $1 / $3; } 0431 | expr '%' expr { $$ = (int)($1) % (int)($3); } 0432 | expr AND expr { $$ = andFunction($1, $3); } 0433 | '!' expr { $$ = notFunction($2); } 0434 | expr GE expr { $$ = greaterEqualThan($1, $3); } 0435 | expr LE expr { $$ = lessEqualThan($1, $3); } 0436 | expr '>' expr { $$ = greaterThan($1, $3); } 0437 | expr '<' expr { $$ = lessThan($1, $3); } 0438 | '-' expr %prec NEG{ $$ = -$2; } 0439 | expr '^' expr { $$ = std::pow($1, $3); } 0440 | expr '*' '*' expr { $$ = std::pow($1, $4); } 0441 | '(' expr ')' { $$ = $2; } 0442 | '|' expr '|' { $$ = std::abs($2); } 0443 | expr '!' { $$ = gsl_sf_fact((unsigned int)$1); } 0444 ; 0445 0446 %% 0447 0448 /* global symbol table (as linked list) */ 0449 symbol *symbol_table = nullptr; 0450 0451 int parse_errors(void) { 0452 return yynerrs; 0453 } 0454 0455 int yyerror(param *p, const char *s) { 0456 /* remove trailing newline */ 0457 p->string[strcspn(p->string, "\n")] = 0; 0458 printf("PARSER ERROR: %s @ position %d of string '%s'\n", s, (int)(p->pos), p->string); 0459 0460 return 0; 0461 } 0462 0463 /* save symbol in symbol table (at start of linked list) */ 0464 symbol* put_symbol(const char *symbol_name, int symbol_type) { 0465 /* pdebug("PARSER: put_symbol(): symbol_name = '%s'\n", symbol_name); */ 0466 0467 symbol *ptr = new symbol; 0468 assert(ptr); 0469 ptr->name = (char *)malloc(strlen(symbol_name) + 1); 0470 strcpy(ptr->name, symbol_name); 0471 ptr->type = symbol_type; 0472 switch (symbol_type) { 0473 case VAR: ptr->value = 0.; break; 0474 case FNCT: ptr->value = nullptr; break; 0475 case SPECFNCT: { 0476 special_function_def sfp; 0477 ptr->value = sfp; 0478 break; 0479 } 0480 } 0481 0482 ptr->next = (symbol *)symbol_table; 0483 symbol_table = ptr; 0484 0485 /* pdebug("PARSER: put_symbol() DONE\n"); */ 0486 return ptr; 0487 } 0488 0489 /* remove symbol of name symbol_name from symbol table 0490 removes only variables of value 0 0491 returns 0 on success */ 0492 int remove_symbol(const char *symbol_name) { 0493 symbol* ptr = symbol_table; 0494 0495 /* check if head contains symbol */ 0496 if (ptr && (strcmp(ptr->name, symbol_name) == 0)) { 0497 if (ptr->type == VAR && std::get<double>(ptr->value) == 0) { 0498 pdebug("PARSER: REMOVING symbol '%s'\n", symbol_name); 0499 symbol_table = ptr->next; 0500 free(ptr->name); 0501 free(ptr); 0502 } 0503 return 0; 0504 } 0505 0506 /* search for symbol to be deleted */ 0507 symbol* prev; 0508 while (ptr && (strcmp(ptr->name, symbol_name) != 0)) { 0509 prev = ptr; 0510 ptr = ptr->next; 0511 } 0512 0513 /* symbol not found or is not a variable or is not 0 */ 0514 if (!ptr || ptr->type != VAR || std::get<double>(ptr->value) != 0) 0515 return 1; 0516 0517 /* remove symbol */ 0518 pdebug("PARSER: REMOVING symbol '%s'\n", symbol_name); 0519 prev->next = ptr->next; 0520 free(ptr->name); 0521 free(ptr); 0522 0523 return 0; 0524 } 0525 0526 /* get symbol from symbol table 0527 returns 0 if symbol not found */ 0528 symbol* get_symbol(const char *symbol_name) { 0529 pdebug("PARSER: get_symbol(): symbol_name = '%s'\n", symbol_name); 0530 0531 symbol *ptr; 0532 for (ptr = symbol_table; ptr != nullptr; ptr = (symbol *)ptr->next) { 0533 /* pdebug("%s ", ptr->name); */ 0534 if (strcmp(ptr->name, symbol_name) == 0) { 0535 pdebug("PARSER: SYMBOL FOUND\n"); 0536 return ptr; 0537 } 0538 } 0539 0540 pdebug("PARSER: SYMBOL NOT FOUND\n"); 0541 return nullptr; 0542 } 0543 0544 /* initialize symbol table with all known functions and constants */ 0545 void init_table(void) { 0546 pdebug("PARSER: init_table()\n"); 0547 0548 symbol *ptr = nullptr; 0549 int i; 0550 /* add functions */ 0551 for (i = 0; i < _number_functions; i++) { 0552 ptr = put_symbol(_functions[i].name, FNCT); 0553 ptr->value = &_functions[i]; 0554 } 0555 /* add special functions */ 0556 for (i = 0; i < _number_specialfunctions; i++) { 0557 ptr = put_symbol(_special_functions[i].name, SPECFNCT); 0558 0559 special_function_def sfd; 0560 sfd.funsptr = &_special_functions[i]; 0561 ptr->value = sfd; 0562 } 0563 /* add constants */ 0564 for (i = 0; i < _number_constants; i++) { 0565 ptr = put_symbol(_constants[i].name, VAR); 0566 ptr->value = _constants[i].value; 0567 } 0568 0569 pdebug("PARSER: init_table() DONE. sym_table = %p\n", ptr); 0570 } 0571 0572 bool set_specialfunction0(const char* function_name, func_tPayload function, std::weak_ptr<Payload> payload) { 0573 pdebug("PARSER: set_SpecialFunction0()\n"); 0574 0575 0576 symbol *ptr = get_symbol(function_name); 0577 if (!ptr) // function name not found 0578 return false; 0579 0580 assert(std::get<special_function_def>(ptr->value).funsptr->argc == 0); 0581 std::get<special_function_def>(ptr->value).funsptr->fnct = function; 0582 std::get<special_function_def>(ptr->value).funsptr->name = function_name; 0583 std::get<special_function_def>(ptr->value).payload = payload; 0584 return true; 0585 } 0586 0587 bool set_specialfunction1(const char* function_name, func_t1Payload function, std::shared_ptr<Payload> payload) { 0588 pdebug("PARSER: set_SpecialFunction1()\n"); 0589 0590 0591 symbol *ptr = get_symbol(function_name); 0592 if (!ptr) // function name not found 0593 return false; 0594 assert(std::get<special_function_def>(ptr->value).funsptr->argc == 1); 0595 std::get<special_function_def>(ptr->value).funsptr->fnct = function; 0596 std::get<special_function_def>(ptr->value).funsptr->name = function_name; 0597 std::get<special_function_def>(ptr->value).payload = payload; 0598 return true; 0599 } 0600 0601 bool set_specialfunction2(const char* function_name, func_t2Payload function, std::shared_ptr<Payload> payload) { 0602 pdebug("PARSER: set_SpecialFunction2()\n"); 0603 0604 0605 symbol *ptr = get_symbol(function_name); 0606 if (!ptr) // function name not found 0607 return false; 0608 0609 assert(std::get<special_function_def>(ptr->value).funsptr->argc == 2); 0610 std::get<special_function_def>(ptr->value).funsptr->fnct = function; 0611 std::get<special_function_def>(ptr->value).funsptr->name = function_name; 0612 std::get<special_function_def>(ptr->value).payload = payload; 0613 return true; 0614 } 0615 0616 bool set_specialfunction3(const char* function_name, func_t3Payload function, std::shared_ptr<Payload> payload) { 0617 pdebug("PARSER: set_SpecialFunction3()\n"); 0618 0619 0620 symbol *ptr = get_symbol(function_name); 0621 if (!ptr) // function name not found 0622 return false; 0623 0624 assert(std::get<special_function_def>(ptr->value).funsptr->argc == 3); 0625 std::get<special_function_def>(ptr->value).funsptr->fnct = function; 0626 std::get<special_function_def>(ptr->value).funsptr->name = function_name; 0627 std::get<special_function_def>(ptr->value).payload = payload; 0628 return true; 0629 } 0630 0631 bool set_specialfunction4(const char* function_name, func_t4Payload function, std::shared_ptr<Payload> payload) { 0632 pdebug("PARSER: set_SpecialFunction4()\n"); 0633 0634 0635 symbol *ptr = get_symbol(function_name); 0636 if (!ptr) // function name not found 0637 return false; 0638 0639 assert(std::get<special_function_def>(ptr->value).funsptr->argc == 4); 0640 std::get<special_function_def>(ptr->value).funsptr->fnct = function; 0641 std::get<special_function_def>(ptr->value).funsptr->name = function_name; 0642 std::get<special_function_def>(ptr->value).payload = payload; 0643 return true; 0644 } 0645 0646 void delete_table(void) { 0647 pdebug("PARSER: delete_table()\n"); 0648 while(symbol_table) { 0649 symbol *tmp = symbol_table; 0650 symbol_table = symbol_table->next; 0651 free(tmp->name); 0652 free(tmp); 0653 } 0654 } 0655 0656 /* add new symbol with value or just set value if symbol is a variable */ 0657 symbol* assign_symbol(const char* symbol_name, double value) { 0658 pdebug("PARSER: assign_symbol() : symbol_name = '%s', value = %g\n", symbol_name, value); 0659 0660 /* be sure that the symbol table has been initialized */ 0661 if (!symbol_table) 0662 init_table(); 0663 0664 symbol* ptr = get_symbol(symbol_name); 0665 if (!ptr) { 0666 pdebug("PARSER: calling putsymbol(): symbol_name = '%s'\n", symbol_name); 0667 ptr = put_symbol(symbol_name, VAR); 0668 } else { 0669 pdebug("PARSER: Symbol already assigned\n"); 0670 } 0671 0672 /* do not assign value if symbol already exits as function */ 0673 if (ptr->type == VAR) 0674 ptr->value = value; 0675 0676 return ptr; 0677 } 0678 0679 static int getcharstr(param *p) { 0680 pdebug(" getcharstr() pos = %d\n", (int)(p->pos)); 0681 0682 if (p->string[p->pos] == '\0') 0683 return EOF; 0684 /* pdebug("PARSER: char is %c\n", p->string[p->pos]); */ 0685 return p->string[(p->pos)++]; 0686 } 0687 0688 static void ungetcstr(size_t *pos) { 0689 /* pdebug("PARSER: ungetcstr()\n"); */ 0690 if (*pos > 0) 0691 (*pos)--; 0692 } 0693 0694 double parse(const char* string, const char* locale) { 0695 pdebug("\nPARSER: parse('%s') len = %d\n********************************\n", string, (int)strlen(string)); 0696 0697 /* be sure that the symbol table has been initialized */ 0698 if (!symbol_table) 0699 init_table(); 0700 0701 _variablesCounter = 0; 0702 _lastErrorMessage[0] = 0; 0703 0704 param p; 0705 p.pos = 0; 0706 p.locale = locale; 0707 0708 /* leave space to terminate string by "\n\0" */ 0709 const size_t slen = strlen(string) + 2; 0710 p.string = (char *) malloc(slen * sizeof(char)); 0711 if (p.string == nullptr) { 0712 printf("PARSER ERROR: Out of memory for parsing string\n"); 0713 return 0.; 0714 } 0715 0716 strcpy(p.string, string); 0717 p.string[strlen(string)] = '\n'; // end for parsing 0718 p.string[strlen(string)+1] = '\0'; // end of string 0719 /* pdebug("PARSER: Call yyparse() for \"%s\" (len = %d)\n", p.string, (int)strlen(p.string)); */ 0720 0721 /* parameter for yylex */ 0722 res = NAN; /* default value */ 0723 yynerrs = 0; /* reset error count */ 0724 yyparse(&p); 0725 0726 pdebug("PARSER: parse() DONE (result = %g, errors = %d)\n*******************************\n", res, parse_errors()); 0727 free(p.string); 0728 p.string = nullptr; 0729 0730 return res; 0731 } 0732 0733 double parse_with_vars(const char *str, const parser_var *vars, int nvars, const char* locale) { 0734 pdebug("\nPARSER: parse_with_var(\"%s\") len = %d\n", str, (int)strlen(str)); 0735 0736 int i; 0737 for(i = 0; i < nvars; i++) { /*assign vars */ 0738 pdebug("PARSER: Assign '%s' the value %g\n", vars[i].name, vars[i].value); 0739 assign_symbol(vars[i].name, vars[i].value); 0740 } 0741 0742 return parse(str, locale); 0743 } 0744 0745 int yylex(param *p) { 0746 pdebug("PARSER: YYLEX()"); 0747 0748 /* get char and skip white space */ 0749 int c; 0750 while ((c = getcharstr(p)) == ' ' || c == '\t'); 0751 0752 /* finish if reached EOF */ 0753 if (c == EOF) { 0754 pdebug("PARSER: FINISHED\n"); 0755 return 0; 0756 } 0757 /* check for non-ASCII chars */ 0758 if (!isascii(c)) { 0759 pdebug(" non-ASCII character found. Giving up\n"); 0760 yynerrs++; 0761 return 0; 0762 } 0763 if (c == '\n') { 0764 pdebug("PARSER: Reached EOL\n"); 0765 return c; 0766 } 0767 0768 if (c == '&') { 0769 // Check if the next is also an &, because then it is the AND operator 0770 if (getcharstr(p) == '&') { 0771 return AND; 0772 } 0773 ungetcstr(&(p->pos)); 0774 } else if (c == '|') { 0775 if (getcharstr(p) == '|') { 0776 return OR; 0777 } 0778 ungetcstr(&(p->pos)); 0779 } else if (c == '>') { 0780 if (getcharstr(p) == '=') { // >= 0781 return GE; 0782 } 0783 ungetcstr(&(p->pos)); 0784 } else if (c == '<') { 0785 if (getcharstr(p) == '=') { // <= 0786 return LE; 0787 } 0788 ungetcstr(&(p->pos)); 0789 } 0790 0791 pdebug("PARSER: PROCESSING character '%c'\n", c); 0792 0793 /* process numbers */ 0794 if (isdigit(c)) { 0795 pdebug("PARSER: Found NUMBER (starts with digit)\n"); 0796 ungetcstr(&(p->pos)); 0797 char *s = &(p->string[p->pos]); 0798 0799 /* convert to double */ 0800 char *remain; 0801 #if defined(_WIN32) 0802 locale_t locale = _create_locale(LC_NUMERIC, p->locale); 0803 if (locale == NULL) { 0804 pdebug("PARSER ERROR in newlocale(%s): %s. Trying system locale.\n", p->locale, strerror(errno)); 0805 locale = _create_locale(LC_NUMERIC, ""); 0806 } 0807 #else 0808 locale_t locale = newlocale(LC_NUMERIC_MASK, p->locale, (locale_t)nullptr); 0809 if (locale == (locale_t)nullptr) { 0810 pdebug("PARSER ERROR in newlocale(%s): %s. Trying system locale.\n", p->locale, strerror(errno)); 0811 locale = newlocale(LC_NUMERIC_MASK, "", (locale_t)nullptr); 0812 pdebug("PARSER: Reading: '%s' with system locale\n", s); 0813 } else { 0814 pdebug("PARSER: Reading: '%s' with locale %s\n", s, p->locale); 0815 } 0816 #endif 0817 double result; 0818 if (locale != nullptr) { 0819 #if defined(__OpenBSD__) || defined(__HAIKU__) 0820 result = strtod(s, &remain); 0821 #else 0822 result = strtod_l(s, &remain, locale); 0823 #endif 0824 freelocale(locale); 0825 } else // use C locale 0826 result = strtod(s, &remain); 0827 0828 pdebug("PARSER: Remain: '%s'\n", remain); 0829 0830 /* check conversion */ 0831 if(strlen(s) == strlen(remain)) 0832 return 0; 0833 0834 pdebug("PARSER: Result = %g\n", result); 0835 yylval.dval = result; 0836 0837 p->pos += strlen(s) - strlen(remain); 0838 0839 return NUM; 0840 } 0841 0842 /* process symbol */ 0843 if (isalpha (c) || c == '.') { 0844 pdebug("PARSER: Found SYMBOL (starts with alpha)\n"); 0845 static char *symbol_name = nullptr; 0846 static int length = 0; 0847 int i = 0; 0848 0849 /* Initially make the buffer long enough for a 10-character symbol name */ 0850 if (length == 0) { 0851 length = 10; 0852 symbol_name = (char *) malloc(length + 1); 0853 } 0854 0855 do { 0856 pdebug("PARSER: Reading symbol .. "); 0857 /* If buffer is full, make it bigger */ 0858 if (i == length) { 0859 length *= 2; 0860 symbol_name = (char *) realloc(symbol_name, length + 1); 0861 } 0862 symbol_name[i++] = c; 0863 c = getcharstr(p); 0864 pdebug("PARSER: got '%c'\n", c); 0865 } 0866 while (c != EOF && (isalnum(c) || c == '_' || c == '.')); 0867 pdebug("PARSER: Reading SYMBOL DONE\n"); 0868 0869 if (c != EOF) 0870 ungetcstr(&(p->pos)); 0871 symbol_name[i] = '\0'; 0872 0873 symbol *s = get_symbol(symbol_name); 0874 if(s == nullptr) { /* symbol unknown */ 0875 pdebug("PARSER ERROR: Symbol '%s' UNKNOWN\n", symbol_name); 0876 yynerrs++; 0877 return 0; 0878 /* old behavior: add symbol */ 0879 /* s = put_symbol(symbol_name, VAR); */ 0880 } 0881 0882 yylval.tptr = s; 0883 return s->type; 0884 } 0885 0886 /* else: single operator */ 0887 pdebug("PARSER: Found single operator '%c'\n", c); 0888 return c; 0889 }