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 }