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 }