Warning, /education/labplot/src/backend/gsl/parser_parallel.y is written in an unsupported language. File is not indexed.

0001 /*
0002     File                 : parser.y
0003     Project              : LabPlot
0004     Description          : Parser for mathematical expressions
0005 
0006     SPDX-FileCopyrightText: 2014 Alexander Semke <alexander.semke@web.de>
0007     SPDX-FileCopyrightText: 2014-2016 Stefan Gerlach <stefan.gerlach@uni.kn>
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 /* TODO: not working yet! */
0012 
0013 
0014 %{
0015 #include <string.h>
0016 #include <strings.h>    /* bzero */
0017 #include <ctype.h>
0018 #include <stdlib.h>
0019 #include <locale.h>
0020 #ifndef HAVE_WINDOWS
0021 #include <xlocale.h>
0022 #endif
0023 #include "constants.h"
0024 #include "functions.h"
0025 #include "parser.h"
0026 
0027 /* Enable Parser DEBUGGING */
0028 /*
0029 #define PDEBUG
0030 */
0031 
0032 #ifdef PDEBUG
0033 #define pdebug(...) fprintf(stderr, __VA_ARGS__)
0034 #else
0035 /*#define pdebug(...) do {} while (0)*/
0036 #define pdebug(...) {}
0037 #endif
0038 
0039 #define YYERROR_VERBOSE 1
0040 
0041 /* params passed to yylex (and yyerror) */
0042 typedef struct param {
0043         unsigned int pos;       /* current position in string */
0044         char *string;           /* the string to parse */
0045         symrec *sym_table;      /* the symbol table */
0046 } param;
0047 
0048 int yyerror(param *p, const char *err);
0049 int yylex(param *p);
0050 
0051 double res;
0052 %}
0053 
0054 %lex-param {param *p}
0055 %parse-param {param *p}
0056 
0057 %union {
0058 double dval;  /* For returning numbers */
0059 symrec *tptr;   /* For returning symbol-table pointers */
0060 }
0061 
0062 %token <dval> NUM       /* Simple double precision number */
0063 %token <tptr> VAR FNCT  /* Variable and Function */
0064 %type  <dval> expr
0065 
0066 %right '='
0067 %left '-' '+'
0068 %left '*' '/'
0069 %left NEG     /* Negation--unary minus */
0070 %right '^'    /* Exponential */
0071 
0072 %%
0073 input:   /* empty */
0074         | input line
0075 ;
0076 
0077 line:   '\n'
0078         | expr '\n'   { res=$1; }
0079         | error '\n' { yyerrok; }
0080 ;
0081 
0082 expr:      NUM       { $$ = $1;                         }
0083 | VAR                { $$ = $1->value.var;              }
0084 | VAR '=' expr       { $$ = $3; $1->value.var = $3;     }
0085 | FNCT '(' ')'       { $$ = (*($1->value.fnctptr))();   }
0086 | FNCT '(' expr ')'  { $$ = (*($1->value.fnctptr))($3); }
0087 | FNCT '(' expr ',' expr ')'  { $$ = (*($1->value.fnctptr))($3,$5); }
0088 | FNCT '(' expr ',' expr ','expr ')'  { $$ = (*($1->value.fnctptr))($3,$5,$7); }
0089 | FNCT '(' expr ',' expr ',' expr ','expr ')'  { $$ = (*($1->value.fnctptr))($3,$5,$7,$9); }
0090 | expr '+' expr      { $$ = $1 + $3;                    }
0091 | expr '-' expr      { $$ = $1 - $3;                    }
0092 | expr '*' expr      { $$ = $1 * $3;                    }
0093 | expr '/' expr      { $$ = $1 / $3;                    }
0094 | '-' expr  %prec NEG{ $$ = -$2;                        }
0095 | expr '^' expr      { $$ = pow ($1, $3);               }
0096 | expr '*' '*' expr  { $$ = pow ($1, $4);               }
0097 | '(' expr ')'       { $$ = $2;                         }
0098 ;
0099 
0100 %%
0101 
0102 /* global symbol table */
0103 symrec *symbol_table = 0;
0104 
0105 int parse_errors(void) {
0106         return yynerrs;
0107 }
0108 
0109 int yyerror(param *p, const char *s) {
0110         printf("PARSER ERROR: %s @ position %d of string %s", s, p->pos, p->string);
0111         return 0;
0112 }
0113 
0114 symrec* putsym(symrec *sym_table, const char *sym_name, int sym_type) {
0115         /*pdebug("PARSER: putsym(): sym_name = %s\n", sym_name);*/
0116 
0117         symrec *ptr = (symrec *) malloc(sizeof(symrec));
0118         ptr->name = (char *) malloc(strlen(sym_name) + 1);
0119         strcpy(ptr->name, sym_name);
0120         ptr->type = sym_type;
0121         ptr->value.var = 0;     /* set value to 0 even if fctn. */
0122         ptr->next = (struct symrec *)sym_table;
0123         sym_table = ptr;
0124 
0125         /*pdebug("PARSER: putsym() DONE sym_table = %p\n", sym_table);*/
0126         return ptr;
0127 }
0128 
0129 symrec* getsym(symrec *sym_table, const char *sym_name) {
0130         /*pdebug("PARSER: getsym(): sym_name = %s, sym_table = %p\n", sym_name, sym_table);*/
0131 
0132         symrec *ptr;
0133         for (ptr = sym_table; ptr != 0; ptr = (symrec *)ptr->next) {
0134                 /*pdebug("%s ", ptr->name);*/
0135                 if (strcmp(ptr->name, sym_name) == 0) {
0136                         /*pdebug("PARSER: symbol \'%s\' found\n", sym_name);*/
0137                         return ptr;
0138                 }
0139         }
0140 
0141         /*pdebug("PARSER: symbol \'%s\' not found\n", sym_name);*/
0142         return 0;
0143 }
0144 
0145 /* put arithmetic functions in table. */
0146 symrec* init_table() {
0147         pdebug("PARSER: init_table()\n");
0148 
0149         symrec *ptr = 0;
0150         int i;
0151         /* add functions */
0152         for (i = 0; _functions[i].name != 0; i++) {
0153                 ptr = putsym(ptr, _functions[i].name, FNCT);
0154                 ptr->value.fnctptr = _functions[i].fnct;
0155         }
0156         /* add constants */
0157         for (i = 0; _constants[i].name != 0; i++) {
0158                 ptr = putsym(ptr, _constants[i].name, VAR);
0159                 ptr->value.var = _constants[i].value;
0160         }
0161         pdebug("PARSER: init_table() DONE sym_table = %p\n", ptr);
0162         return ptr;
0163 }
0164 
0165 void delete_table(symrec *sym_table) {
0166         symrec *tmp;
0167         while(sym_table) {
0168                 tmp = sym_table;
0169                 sym_table = sym_table->next;
0170                 free(tmp->name);
0171                 free(tmp);
0172         }
0173 }
0174 
0175 symrec* assign_variable(symrec *sym_table, parser_var var) {
0176         /*pdebug("PARSER: assign_variable(): symb_name = %s value = %g sym_table = %p\n", var.name, var.value, sym_table);*/
0177 
0178         symrec* ptr = getsym(sym_table, var.name);
0179         if (!ptr) {
0180                 /*pdebug("PARSER: calling putsym(): symb_name = %s\n", var.name);*/
0181                 ptr = putsym(sym_table, var.name, VAR);
0182         }
0183         ptr->value.var = var.value;
0184 
0185         return ptr;
0186 };
0187 
0188 static int getcharstr(param *p) {
0189         /*pdebug("PARSER: getcharstr() pos = %d\n", p->pos);*/
0190 
0191         if (p->string[p->pos] == '\0')
0192                 return EOF;
0193         return (int) p->string[(p->pos)++];
0194 }
0195 
0196 static void ungetcstr(unsigned int *pos) {
0197     if (*pos > 0)
0198         (*pos)--;
0199 }
0200 
0201 int init_parser() {
0202         symbol_table = init_table();    
0203         return 0;
0204 }
0205 
0206 int finish_parser() {
0207         if (symbol_table != 0)
0208                 delete_table(symbol_table);
0209         symbol_table = 0;
0210 
0211         return 0;
0212 }
0213 
0214 double parse_with_vars(const char *str, const parser_var *vars, int nvars) {
0215         pdebug("\nPARSER: parse(\"%s\") len=%zu\n", str, strlen(str));
0216         int i;
0217         for(i = 0; i < nvars; i++)      /*assign vars */
0218                 pdebug("var %d of name %s with value %g\n", i, vars[i].name, vars[i].value);
0219 
0220         /* parameter for yylex */
0221         param p;
0222         p.pos = 0;
0223         /* leave space to terminate string by "\n\0" */
0224         size_t slen = strlen(str) + 2;
0225         p.string = (char *)malloc(slen*sizeof(char));
0226         /* If there is no global symbol table: create own */
0227         if (symbol_table == 0)
0228                 p.sym_table = init_table();
0229 
0230         for(i = 0; i < nvars; i++) {    /*assign vars */
0231                 pdebug("assign %s the value %g\n", vars[i].name, vars[i].value);
0232                 if (symbol_table == 0)
0233                         p.sym_table = assign_variable(p.sym_table, vars[i]);
0234                 else
0235                         symbol_table = assign_variable(symbol_table, vars[i]);
0236         }
0237 
0238         strncpy(p.string, str, slen);
0239         p.string[strlen(p.string)] = '\n';
0240         /*pdebug("      slen = %zu, strlen(str) = %zu, strlen(p.string) = %zu\n", slen, strlen(str), strlen(p.string));*/
0241 
0242         yyparse(&p);
0243 
0244         /*pdebug("PARSER: parse() DONE (res = %g, parse errors = %d)\n", res, parse_errors());*/
0245         free(p.string);
0246         if (symbol_table == 0)
0247                 delete_table(p.sym_table);
0248 
0249         return res;
0250 }
0251 
0252 double parse(const char *str) {
0253         return parse_with_vars(str, 0, 0);
0254 }
0255 
0256 int yylex(param *p) {
0257         pdebug("PARSER: yylex()\n");
0258         int c;
0259 
0260         /* skip white spaces */
0261         while ((c = getcharstr(p)) == ' ' || c == '\t');
0262 
0263         /* finish if reached EOF */
0264         if (c == EOF) {
0265                 pdebug("FINISHED\n");
0266                 return 0;
0267         }
0268 
0269         pdebug("PARSER: reading character: %c\n", c);
0270 
0271         /* process numbers */
0272         if (isdigit(c)) {
0273                 pdebug("PARSER: reading number (starts with digit)\n");
0274                 ungetcstr(&(p->pos));
0275                 char *s = &p->string[p->pos];
0276 
0277                 /* convert to double */
0278                 char *remain;
0279 #if defined(_WIN32) || defined(__APPLE__)
0280                 double result = strtod(s, &remain);
0281 #else
0282                 /* use same locale for all languages: '.' as decimal point */
0283                 locale_t locale = newlocale(LC_NUMERIC_MASK, "C", NULL);
0284 
0285                 double result = strtod_l(s, &remain, locale);
0286                 freelocale(locale);
0287 #endif
0288                 pdebug("PARSER: reading: %s", s);
0289                 pdebug("PARSER: remain = %s", remain);
0290 
0291                 /* check conversion */
0292                 if(strlen(s) == strlen(remain))
0293                         return 0;
0294 
0295                 pdebug("PARSER: result = %g\n", result);
0296 
0297                 yylval.dval = result;
0298                 p->pos += strlen(s) - strlen(remain);
0299 
0300                 return NUM;
0301         }
0302 
0303         if (isalpha (c) || c == '.') {
0304                 pdebug("PARSER: reading identifier (starts with alpha)\n");
0305                 static char *symbuf = 0;
0306                 static int length = 0;
0307                 int i=0;
0308 
0309                 /* Initially make the buffer long enough for a 4-character symbol name */
0310                 if (length == 0)
0311                         length = 20, symbuf = (char *)malloc(length + 1);
0312 
0313                 do {
0314                         /* If buffer is full, make it bigger */
0315                         if (i == length) {
0316                                 length *= 2;
0317                                 symbuf = (char *)realloc(symbuf, length + 1);
0318                         }
0319                         /* Add this character to the buffer */
0320                         symbuf[i++] = c;
0321                         /* Get another character */
0322                         c = getcharstr(p);
0323                 }
0324                 while (c != EOF && (isalnum(c) || c == '_' || c == '.'));
0325 
0326                 ungetcstr(&(p->pos));
0327                 symbuf[i] = '\0';
0328 
0329                 /*pdebug("PARSER: search for symbol: sym_table = %p\n", p->sym_table);*/
0330                 symrec *s;
0331                 if (symbol_table != 0)
0332                         s = getsym(symbol_table, symbuf);
0333                 else
0334                         s = getsym(p->sym_table, symbuf);
0335                 if(s == 0) {    /* symbol unknown */
0336                         pdebug("PARSER: ERROR: symbol \"%s\" UNKNOWN\n", symbuf);
0337                         return 0;
0338                 }
0339                 /* old behavior */
0340                 /* if (s == 0)
0341                          s = putsym (symbuf, VAR); */
0342                 yylval.tptr = s;
0343                 return s->type;
0344         }
0345 
0346         /* else: single operator */
0347         pdebug("PARSER: single operator\n");
0348         return c;
0349 }