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