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 }