diff --git a/Common/Views.cpp b/Common/Views.cpp
index 6f0c49efcde4857be62fc09f9385dc3ff313897f..968a3a46d35daf75f40245f86533a6b0b6b9e635 100644
--- a/Common/Views.cpp
+++ b/Common/Views.cpp
@@ -1,4 +1,4 @@
-// $Id: Views.cpp,v 1.115 2004-02-20 17:57:59 geuzaine Exp $
+// $Id: Views.cpp,v 1.116 2004-05-12 02:02:20 geuzaine Exp $
 //
 // Copyright (C) 1997-2004 C. Geuzaine, J.-F. Remacle
 //
@@ -33,8 +33,6 @@ extern Context_T CTX;
 void UpdateViewsInGUI();
 #endif
 
-#define VAL_INF 1.e200
-
 // Static reference view
 
 Post_View *Post_ViewReference = NULL;
diff --git a/Common/Views.h b/Common/Views.h
index 157cd7561cf43ceae3c6f19dcc331e6145371a84..b1965078e538797c0f4df0d3fce459443778d42f 100644
--- a/Common/Views.h
+++ b/Common/Views.h
@@ -25,6 +25,7 @@
 
 #define VIEW_NB_ELEMENT_TYPES  (8*3)
 #define VIEW_MAX_ELEMENT_NODES  8
+#define VAL_INF 1.e200
 
 class smooth_container;
 
diff --git a/Fltk/Callbacks.cpp b/Fltk/Callbacks.cpp
index a82b65ef6d52b1346495f2201f180639975050f1..fa31d38167368faf43ce7a5326a91052a52cea10 100644
--- a/Fltk/Callbacks.cpp
+++ b/Fltk/Callbacks.cpp
@@ -1,4 +1,4 @@
-// $Id: Callbacks.cpp,v 1.224 2004-05-08 00:44:41 geuzaine Exp $
+// $Id: Callbacks.cpp,v 1.225 2004-05-12 02:02:20 geuzaine Exp $
 //
 // Copyright (C) 1997-2004 C. Geuzaine, J.-F. Remacle
 //
@@ -3159,13 +3159,17 @@ void view_plugin_cb(CALLBACK_ARGS)
   p->getName(name);
 
   if(p->dialogBox) {    //Get the values from the GUI
+    int m = p->getNbOptionsStr();
     int n = p->getNbOptions();
-    if(n > 20)
-      Msg(GERROR, "Plugin has too many parameters");
+    if(m > NB_BUTT_MAX) m = NB_BUTT_MAX;
+    if(n > NB_BUTT_MAX) n = NB_BUTT_MAX;
+    for(int i = 0; i < m; i++) {
+      StringXString *sxs = p->getOptionStr(i);
+      sxs->def = p->dialogBox->input[i]->value();
+    }
     for(int i = 0; i < n; i++) {
-      StringXNumber *sxn;
-      sxn = p->getOption(i);
-      sxn->def = p->dialogBox->view_value[i]->value();
+      StringXNumber *sxn = p->getOption(i);
+      sxn->def = p->dialogBox->value[i]->value();
     }
   }
 
diff --git a/Fltk/GUI.cpp b/Fltk/GUI.cpp
index 7ea16af69ff721f500c415076319b9fb637456e2..79f6c35b5a9ff73cd88ab721e873e428967b5df6 100644
--- a/Fltk/GUI.cpp
+++ b/Fltk/GUI.cpp
@@ -1,4 +1,4 @@
-// $Id: GUI.cpp,v 1.294 2004-04-26 19:54:16 geuzaine Exp $
+// $Id: GUI.cpp,v 1.295 2004-05-12 02:02:20 geuzaine Exp $
 //
 // Copyright (C) 1997-2004 C. Geuzaine, J.-F. Remacle
 //
@@ -2788,6 +2788,7 @@ PluginDialogBox *GUI::create_plugin_window(GMSH_Plugin * p)
 
   // get plugin info
 
+  int m = p->getNbOptionsStr();
   int n = p->getNbOptions();
   p->getName(namep);
   p->getInfos(author, copyright, help);
@@ -2795,7 +2796,7 @@ PluginDialogBox *GUI::create_plugin_window(GMSH_Plugin * p)
   // create window
 
   int width = 26 * fontsize;
-  int height = ((n > 8 ? n : 8) + 2) * BH + 5 * WB;
+  int height = ((n+m > 8 ? n+m : 8) + 2) * BH + 5 * WB;
 
   PluginDialogBox *pdb = new PluginDialogBox;
   pdb->main_window = new Fl_Window(width, height);
@@ -2810,15 +2811,23 @@ PluginDialogBox *GUI::create_plugin_window(GMSH_Plugin * p)
     {
       Fl_Group *g = new Fl_Group(WB, WB + BH, width - 2 * WB, height - 3 * WB - 2 * BH, "Options");
 
-      if(n > 20)
-        Msg(GERROR, "Plugin has too many parameters");
+      if(m > NB_BUTT_MAX) m = NB_BUTT_MAX;
+      if(n > NB_BUTT_MAX) n = NB_BUTT_MAX;
 
+      int k = 0;
+      for(int i = 0; i < m; i++) {
+        StringXString *sxs = p->getOptionStr(i);
+        pdb->input[i] = new Fl_Input(2 * WB, 2 * WB + (k + 1) * BH, IW, BH, sxs->str);
+        pdb->input[i]->align(FL_ALIGN_RIGHT);
+        pdb->input[i]->value(sxs->def);
+	k++;
+      }
       for(int i = 0; i < n; i++) {
-        StringXNumber *sxn;
-        sxn = p->getOption(i);
-        pdb->view_value[i] = new Fl_Value_Input(2 * WB, 2 * WB + (i + 1) * BH, IW, BH, sxn->str);
-        pdb->view_value[i]->align(FL_ALIGN_RIGHT);
-        pdb->view_value[i]->value(sxn->def);
+        StringXNumber *sxn = p->getOption(i);
+        pdb->value[i] = new Fl_Value_Input(2 * WB, 2 * WB + (k + 1) * BH, IW, BH, sxn->str);
+        pdb->value[i]->align(FL_ALIGN_RIGHT);
+        pdb->value[i]->value(sxn->def);
+	k++;
       }
 
       g->end();
diff --git a/Fltk/GUI.h b/Fltk/GUI.h
index 5ee62d9cada5d25bef007c0d6bd3dde1076ed166..60a5f596eddb1fab3d2f6062d31662c7713aab06 100644
--- a/Fltk/GUI.h
+++ b/Fltk/GUI.h
@@ -101,8 +101,8 @@ struct PluginDialogBox
 {
   Fl_Window *main_window;
   Fl_Return_Button *run_button;
-  int nb_viewvalue;
-  Fl_Value_Input *view_value[20];
+  Fl_Value_Input *value[NB_BUTT_MAX];
+  Fl_Input *input[NB_BUTT_MAX] ;
 };
 
 // The dialog for solvers
diff --git a/Makefile b/Makefile
index 4e51057f34f8375aed87b1c4ec1d9229c69b5beb..976624ed2f20cc9f1f52e9ee5e7c0f9cae651a17 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.341 2004-05-10 06:35:05 geuzaine Exp $
+# $Id: Makefile,v 1.342 2004-05-12 02:02:19 geuzaine Exp $
 #
 # Copyright (C) 1997-2004 C. Geuzaine, J.-F. Remacle
 #
@@ -142,8 +142,8 @@ source: source-common
 
 source-commercial: source-common
 	cd gmsh-${GMSH_VERSION} && rm -rf CVS */CVS */*/CVS */*/*/CVS */.globalrc\
-          Triangle/triangle.* TODO *.spec doc/gmsh.html doc/FAQ doc/README.cvs\
-          utils/commercial ${GMSH_VERSION_FILE}
+          Triangle/triangle.* MathEval/*.{c,h} TODO *.spec doc/gmsh.html doc/FAQ\
+          doc/README.cvs utils/commercial ${GMSH_VERSION_FILE}
 	cp -f utils/commercial/README gmsh-${GMSH_VERSION}/README
 	cp -f utils/commercial/LICENSE gmsh-${GMSH_VERSION}/doc/LICENSE
 	cp -f utils/commercial/License.cpp gmsh-${GMSH_VERSION}/Common/License.cpp
diff --git a/MathEval/Makefile b/MathEval/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..d1adf7845ff6c9cca607ade923cd1e57951a6306
--- /dev/null
+++ b/MathEval/Makefile
@@ -0,0 +1,72 @@
+# $Id: Makefile,v 1.1 2004-05-12 02:02:21 geuzaine Exp $
+#
+# Copyright (C) 1997-2004 C. Geuzaine, J.-F. Remacle
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA.
+# 
+# Please report all bugs and problems to <gmsh@geuz.org>.
+
+include ../variables
+
+LIB = ../lib/libGmshMathEval.a
+INCLUDE = -I../Common -I../DataStr
+
+CFLAGS  = ${OPTIM} ${FLAGS} ${INCLUDE} 
+
+SRC = matheval.cpp\
+      node.cpp\
+      scanner.cpp\
+      parser.cpp\
+      symbol_table.cpp\
+      xmath.cpp
+
+OBJ = ${SRC:.cpp=.o}
+
+.SUFFIXES: .o .cpp
+
+${LIB}: ${OBJ}
+	${AR} ${LIB} ${OBJ}
+	${RANLIB} ${LIB}
+
+.cpp.o:
+	${CXX} ${CFLAGS} -c $<
+
+parser:
+	bison --output parser.cpp -pme -d parser.y 
+	flex -oscanner.cpp -Pme scanner.l
+	if [ -r parser.cpp.h ]; then mv parser.cpp.h parser.h ; fi
+
+clean:
+	rm -f *.o
+
+depend:
+	(sed '/^# DO NOT DELETE THIS LINE/q' Makefile && \
+	${CC} -MM ${CFLAGS} ${SRC} \
+	) >Makefile.new
+	cp Makefile Makefile.bak
+	cp Makefile.new Makefile
+	rm -f Makefile.new
+
+# DO NOT DELETE THIS LINE
+matheval.o: matheval.cpp common.h ../DataStr/Malloc.h matheval.h node.h \
+  symbol_table.h
+node.o: node.cpp common.h ../DataStr/Malloc.h node.h symbol_table.h
+scanner.o: scanner.cpp common.h ../DataStr/Malloc.h node.h symbol_table.h \
+  parser.h
+parser.o: parser.cpp common.h ../DataStr/Malloc.h node.h symbol_table.h
+symbol_table.o: symbol_table.cpp common.h ../DataStr/Malloc.h \
+  symbol_table.h xmath.h
+xmath.o: xmath.cpp xmath.h
diff --git a/MathEval/README b/MathEval/README
new file mode 100644
index 0000000000000000000000000000000000000000..e06a401d7f15bf9b58a705ff57df9b8b70fc4035
--- /dev/null
+++ b/MathEval/README
@@ -0,0 +1,23 @@
+
+This directory contains a modified version of GNU libmatheval
+
+Copyright (C) 1999, 2002, 2003  Aleksandar B. Samardzic
+
+Copying and distribution of this file, with or without modification, are
+permitted in any medium without royalty provided the copyright notice
+and this notice are preserved.
+
+WHAT IS IT?
+
+GNU libmatheval is a library which contains several procedures that make
+it possible to create an in-memory tree from the string representation
+of a mathematical function over single or multiple variables. This tree
+can be used later to evaluate a function for specified variable values,
+to create a corresponding tree for the function derivative over a
+specified variable, or to write a textual tree representation to a
+specified string. The library exposes C and Fortran 77 interfaces.
+
+BUGS
+
+Please report bugs and eventually send patches to
+<bug-libmatheval@gnu.org> mailing list.
diff --git a/MathEval/common.h b/MathEval/common.h
new file mode 100644
index 0000000000000000000000000000000000000000..781b6df4ad8e2287151a8cdcb7fb8556d4ef8b73
--- /dev/null
+++ b/MathEval/common.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 1999, 2002, 2003  Free Software Foundation, Inc.
+ * 
+ * This file is part of GNU libmatheval
+ * 
+ * GNU libmatheval is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2, or (at your option) any later
+ * version.
+ * 
+ * GNU libmatheval is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef COMMON_H
+#define COMMON_H
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "Malloc.h"
+
+/* Macro definitions to simplify corresponding function calls.  */
+#define XMALLOC(type, num) ((type *) Malloc ((num) * sizeof(type)))
+#define XREALLOC(type, p, num) ((type *) Realloc ((p), (num) * sizeof(type)))
+#define XCALLOC(type, num) ((type *) Calloc ((num), sizeof(type)))
+#define XFREE(stale) Free (stale);
+
+#endif
diff --git a/MathEval/matheval.cpp b/MathEval/matheval.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..43950feee1dc31ccebf357d4ffccc3aa24f53d84
--- /dev/null
+++ b/MathEval/matheval.cpp
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 1999, 2002, 2003  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU libmatheval
+ *
+ * GNU libmatheval is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2, or (at your option) any later
+ * version.
+ *
+ * GNU libmatheval is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* This file was modified for inclusion in Gmsh */
+
+#include "common.h"
+#include "matheval.h"
+#include "node.h"
+#include "symbol_table.h"
+
+/* Minimal length of evaluator symbol table.  */
+#define MIN_TABLE_LENGTH 211
+
+/*
+ * Function used to parse string representing function (this function is
+ * generated by parser generator).
+ */
+extern int meparse();
+
+/*
+ * Following variables are needed for parsing (parser is able to communicate
+ * with program from which it is used through global variables only).
+ */
+char           *matheval_input_string;	/* String representing function.  */
+Node           *matheval_root;		/* Root of tree representation of
+					 * function.  */
+SymbolTable    *matheval_symbol_table;	/* Evaluator symbol table.  */
+int             matheval_ok;		/* Flag determining if parsing went OK.  */
+
+/* Data structure representing evaluator.  */
+typedef struct {
+  Node           *root;	/* Root of tree representation of
+			 * function.  */
+  SymbolTable    *symbol_table;	/* Evalutor symbol table.  */
+} Evaluator;
+
+void           *
+evaluator_create(char *string)
+{
+  Evaluator      *evaluator;	/* Evaluator representing function given
+				 * by string.  */
+  char           *stringn;	/* Copy of string terminated by newline
+				 * character.  */
+  
+  /*
+   * Copy string representing function and terminate it with newline
+   * (this is necessary because parser expect newline character to
+   * terminate its input).
+   */
+  stringn = XMALLOC(char, strlen(string) + 2);
+  
+  strcpy(stringn, string);
+  strcat(stringn, "\n");
+  
+  /*
+   * Initialize global variables used by parser.
+   */
+  matheval_input_string = stringn;
+  matheval_root = NULL;
+  matheval_symbol_table = symbol_table_create(MIN_TABLE_LENGTH);
+  matheval_ok = 1;
+  
+  /*
+   * Do parsing.
+   */
+  meparse();
+  
+  /*
+   * Free copy of string representing function.
+   */
+  XFREE(stringn);
+  
+  /*
+   * Return null pointer as error indicator if parsing error occured.
+   */
+  if (!matheval_ok || !matheval_root){
+    node_destroy(matheval_root);
+    symbol_table_destroy(matheval_symbol_table);
+    return NULL;
+  }
+  
+  /*
+   * Simplify tree represention of function.
+   */
+  matheval_root = node_simplify(matheval_root);
+  
+  /*
+   * Allocate memory for and initialize evaluator data structure.
+   */
+  evaluator = XMALLOC(Evaluator, 1);
+  evaluator->root = matheval_root;
+  evaluator->symbol_table = matheval_symbol_table;
+  
+  return evaluator;
+}
+
+void
+evaluator_destroy(void *evaluator)
+{
+  /*
+   * Destroy tree represention of function, symbol table, as well as
+   * data structure representing evaluator.
+   */
+  node_destroy(((Evaluator *) evaluator)->root);
+  symbol_table_destroy(((Evaluator *) evaluator)->symbol_table);
+  XFREE(evaluator);
+}
+
+double
+evaluator_evaluate(void *evaluator, int count, char **names, double *values)
+{
+  Record         *record;	/* Symbol table record corresponding to
+				 * give variable name.  */
+  int             i;		/* Loop counter.  */
+  
+  /*
+   * Assign values to symbol table records corresponding to variable
+   * names.
+   */
+  for (i = 0; i < count; i++) {
+    record = symbol_table_lookup(((Evaluator *) evaluator)->symbol_table, names[i]);
+    if (record && record->type == 'v')
+      record->data.value = values[i];
+  }
+  
+  /*
+   * Evaluate function value using tree represention of function.
+   */
+  return node_evaluate(((Evaluator *) evaluator)->root);
+}
+
+int
+evaluator_calculate_length(void *evaluator)
+{
+  /*
+   * Calculate length of evaluator textual representation.
+   */
+  return node_calculate_length(((Evaluator *) evaluator)->root);
+}
+
+void
+evaluator_write(void *evaluator, char *string)
+{
+  /*
+   * Write evaluator textual representation to given string.
+   */
+  node_write(((Evaluator *) evaluator)->root, string);
+}
+
+void *
+evaluator_derivative(void *evaluator, char *name)
+{
+  Evaluator      *derivative;	/* Derivative function evaluator.  */
+  
+  /*
+   * Allocate memory for and initalize data structure for evaluator
+   * representing derivative of function given by evaluator.
+   */
+  derivative = XMALLOC(Evaluator, 1);
+  derivative->root = node_simplify(node_derivative(((Evaluator *) evaluator)->root, name,
+						   ((Evaluator *) evaluator)->symbol_table));
+  derivative->symbol_table = symbol_table_assign(((Evaluator *) evaluator)->symbol_table);
+  
+  return derivative;
+}
+
+double
+evaluator_evaluate_x(void *evaluator, double x)
+{
+  char           *names[] = {"x"};	/* Array of variable names.  */
+  double          values[] = {x};	/* Array of variable values.  */
+  
+  /*
+   * Evaluate function for given values of variable "x".
+   */
+  return evaluator_evaluate(evaluator, sizeof(names) / sizeof(names[0]), names, values);
+}
+
+double
+evaluator_evaluate_x_y(void *evaluator, double x, double y)
+{
+  char           *names[] = {"x", "y"};	/* Array of variable
+					 * names.  */
+  double          values[] = {x, y};	/* Array of variable values.  */
+  
+  /*
+   * Evaluate function for given values of variable "x" and "y".
+   */
+  return evaluator_evaluate(evaluator, sizeof(names) / sizeof(names[0]), names, values);
+}
+
+double
+evaluator_evaluate_x_y_z(void *evaluator, double x, double y, double z)
+{
+  char           *names[] = {"x", "y", "z"};	/* Array of variable
+						 * names.  */
+  double          values[] = {x, y, z};	/* Array of variable
+					 * values.  */
+  
+  /*
+   * Evaluate function for given values of variable "x", "y" and "z".
+   */
+  return evaluator_evaluate(evaluator, sizeof(names) / sizeof(names[0]), names, values);
+}
+
+void *
+evaluator_derivative_x(void *evaluator)
+{
+  /*
+   * Differentiate function using derivation variable "x".
+   */
+  return evaluator_derivative(evaluator, "x");
+}
+
+void *
+evaluator_derivative_y(void *evaluator)
+{
+  /*
+   * Differentiate function using derivation variable "y".
+   */
+  return evaluator_derivative(evaluator, "y");
+}
+
+void *
+evaluator_derivative_z(void *evaluator)
+{
+  /*
+   * Differentiate function using derivation variable "z".
+   */
+  return evaluator_derivative(evaluator, "z");
+}
diff --git a/MathEval/matheval.h b/MathEval/matheval.h
new file mode 100644
index 0000000000000000000000000000000000000000..b155f4003c3034bf07baf5fe9aa8ff27c68cf7dc
--- /dev/null
+++ b/MathEval/matheval.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 1999, 2002, 2003  Free Software Foundation, Inc.
+ * 
+ * This file is part of GNU libmatheval
+ * 
+ * GNU libmatheval is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2, or (at your option) any later
+ * version.
+ * 
+ * GNU libmatheval is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* This file was modified for inclusion in Gmsh */
+
+#ifndef EVALUATOR_H
+#define EVALUATOR_H
+
+/*
+ * Create evaluator from string representing function.  Function
+ * returns pointer that should be passed as first argument to all
+ * other library functions.  If an error occurs, function will return
+ * null pointer.
+ */
+void    *evaluator_create(char *string);
+
+/*
+ * Destroy evaluator specified.
+ */
+void     evaluator_destroy(void *evaluator);
+
+/*
+ * Evaluate function represented by evaluator given.  Variable names
+ * and respective values are represented by function third and fourth
+ * argument. Number of variables i.e. length of these two arrays is
+ * given by second argument.  Function returns evaluated function
+ * value.  In case that function contains variables with names not
+ * given through third function argument, value of this variable is
+ * undeterminated.
+ */
+double   evaluator_evaluate(void *evaluator, int count, char **names, double *values);
+
+/*
+ * Calculate length of textual representation of evaluator. This
+ * procedure is inteded to be used along with evaluator_write()
+ * procedure that follows.
+ */
+int      evaluator_calculate_length(void *evaluator);
+
+/*
+ * Write textual representation of evaluator (i.e. corresponding
+ * function) to given string.  No string overflow is checked by this
+ * procedure; string of appropriate length (calculated beforehand
+ * using above evaluator_calculate_length() procedure) is expected to
+ * be allocated beforehand.
+ */
+void     evaluator_write(void *evaluator, char *length);
+
+/*
+ * Create evaluator for first derivative of function represented by
+ * evaluator given as first argument using derivative variable given
+ * as second argument.
+ */
+void    *evaluator_derivative(void *evaluator, char *name);
+
+/*
+ * Helper functions to simplify evaluation when variable names are
+ * "x", "x" and "y" or "x" and "y" and "z" respectively.
+ */
+double   evaluator_evaluate_x(void *evaluator, double x);
+double   evaluator_evaluate_x_y(void *evaluator, double x, double y);
+double   evaluator_evaluate_x_y_z(void *evaluator, double x, double y, double z);
+
+/*
+ * Helper functions to simplify differentiation when variable names
+ * are "x" or "y" or "z" respectively.
+ */
+void    *evaluator_derivative_x(void *evaluator);
+void    *evaluator_derivative_y(void *evaluator);
+void    *evaluator_derivative_z(void *evaluator);
+
+#endif
diff --git a/MathEval/node.cpp b/MathEval/node.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a0f987bf501f1f95fe28388b74dd399da3a5be66
--- /dev/null
+++ b/MathEval/node.cpp
@@ -0,0 +1,651 @@
+/*
+ * Copyright (C) 1999, 2002, 2003  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU libmatheval
+ *
+ * GNU libmatheval is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2, or (at your option) any later
+ * version.
+ *
+ * GNU libmatheval is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+#include "common.h"
+#include "node.h"
+
+Node *
+node_create(char type,...)
+{
+    Node           *node;	/* New node.  */
+    va_list         ap;		/* Variable argument list.  */
+
+    /*
+     * Allocate memory for node and initialize its type.
+     */
+    node = XMALLOC(Node, 1);
+    node->type = type;
+
+    /*
+     * According to node type, initialize rest of the node from variable
+     * argument list.
+     */
+    va_start(ap, type);
+    switch (node->type) {
+    case 'c':
+	/*
+	 * Initialize constant value.
+	 */
+	node->data.constant = va_arg(ap, double);
+
+	break;
+
+    case 'v':
+	/*
+	 * Remember pointer to symbol table record describing
+	 * variable.
+	 */
+	node->data.variable = va_arg(ap, Record *);
+	break;
+
+    case 'f':
+	/*
+	 * Remember pointer to symbol table record describing
+	 * function and initialize function argument.
+	 */
+	node->data.function.record = va_arg(ap, Record *);
+	node->data.function.child = va_arg(ap, Node *);
+	break;
+
+    case 'u':
+	/*
+	 * Initialize operator type and operand.
+	 */
+	node->data.un_op.operato = (char) va_arg(ap, int);
+
+	node->data.un_op.child = va_arg(ap, Node *);
+	break;
+
+    case 'b':
+	/*
+	 * Initialize operator type and operands.
+	 */
+	node->data.un_op.operato = (char) va_arg(ap, int);
+
+	node->data.bin_op.left = va_arg(ap, Node *);
+	node->data.bin_op.right = va_arg(ap, Node *);
+	break;
+
+    default:
+	assert(0);
+    }
+    va_end(ap);
+
+    return node;
+}
+
+void
+node_destroy(Node * node)
+{
+    /*
+     * Skip if node already null (this may occur during simplification).
+     */
+    if (!node)
+	return;
+
+    /*
+     * If necessary, destroy subtree rooted at node.
+     */
+    switch (node->type) {
+    case 'c':
+    case 'v':
+	break;
+
+    case 'f':
+	node_destroy(node->data.function.child);
+	break;
+
+    case 'u':
+	node_destroy(node->data.un_op.child);
+	break;
+
+    case 'b':
+	node_destroy(node->data.bin_op.left);
+	node_destroy(node->data.bin_op.right);
+	break;
+    }
+
+    /*
+     * Deallocate memory used by node.
+     */
+    XFREE(node);
+}
+
+Node *
+node_copy(Node * node)
+{
+    /*
+     * According to node type, create (deep) copy of subtree rooted at
+     * node.
+     */
+    switch (node->type) {
+	case 'c':
+	return node_create('c', node->data.constant);
+
+    case 'v':
+	return node_create('v', node->data.variable);
+
+    case 'f':
+	return node_create('f', node->data.function.record, node_copy(node->data.function.child));
+
+    case 'u':
+	return node_create('u', node->data.un_op.operato, node_copy(node->data.un_op.child));
+
+    case 'b':
+	return node_create('b', node->data.bin_op.operato, node_copy(node->data.bin_op.left), node_copy(node->data.bin_op.right));
+    }
+
+    return NULL;
+}
+
+Node *
+node_simplify(Node * node)
+{
+    /*
+     * According to node type, apply further simplifications.
+     */
+    switch (node->type) {
+	case 'c':
+	case 'v':
+	return node;
+
+    case 'f':
+	/*
+	 * Simplify function argument and if constant evaluate
+	 * function and replace function node with constant node.
+	 */
+	node->data.function.child = node_simplify(node->data.function.child);
+	if (node->data.function.child->type == 'c') {
+	    double          value = node_evaluate(node);
+
+	    node_destroy(node);
+	    return node_create('c', value);
+	} else
+	    return node;
+
+    case 'u':
+	/*
+	 * Simplify unary operator operand and if constant apply
+	 * operator and replace operator node with constant node.
+	 */
+	node->data.un_op.child = node_simplify(node->data.un_op.child);
+	if (node->data.un_op.operato == '-' && node->data.un_op.child->type == 'c') {
+	    double          value = node_evaluate(node);
+
+	    node_destroy(node);
+	    return node_create('c', value);
+	} else
+	    return node;
+
+    case 'b':
+	/*
+	 * Simplify binary operator operands.
+	 */
+	node->data.bin_op.left = node_simplify(node->data.bin_op.left);
+	node->data.bin_op.right = node_simplify(node->data.bin_op.right);
+
+	/*
+	 * If operands constant apply operator and replace operator
+	 * node with constant node.
+	 */
+	if (node->data.bin_op.left->type == 'c' && node->data.bin_op.right->type == 'c') {
+	    double          value = node_evaluate(node);
+
+	    node_destroy(node);
+	    return node_create('c', value);
+	}
+	/*
+	 * Eliminate 0 as neutral addition operand.
+	 */
+	else if (node->data.bin_op.operato == '+')
+	    if (node->data.bin_op.left->type == 'c' && node->data.bin_op.left->data.constant == 0) {
+		Node           *right;
+
+		right = node->data.bin_op.right;
+		node->data.bin_op.right = NULL;
+		node_destroy(node);
+		return right;
+	    } else if (node->data.bin_op.right->type == 'c' && node->data.bin_op.right->data.constant == 0) {
+		Node           *left;
+
+		left = node->data.bin_op.left;
+		node->data.bin_op.left = NULL;
+		node_destroy(node);
+		return left;
+	    } else
+		return node;
+	/*
+	 * Eliminate 0 as neutral subtraction right operand.
+	 */
+	else if (node->data.bin_op.operato == '-')
+	    if (node->data.bin_op.right->type == 'c' && node->data.bin_op.right->data.constant == 0) {
+		Node           *left;
+
+		left = node->data.bin_op.left;
+		node->data.bin_op.left = NULL;
+		node_destroy(node);
+		return left;
+	    } else
+		return node;
+	/*
+	 * Eliminate 1 as neutral multiplication operand.
+	 */
+	else if (node->data.bin_op.operato == '*')
+	    if (node->data.bin_op.left->type == 'c' && node->data.bin_op.left->data.constant == 1) {
+		Node           *right;
+
+		right = node->data.bin_op.right;
+		node->data.bin_op.right = NULL;
+		node_destroy(node);
+		return right;
+	    } else if (node->data.bin_op.right->type == 'c' && node->data.bin_op.right->data.constant == 1) {
+		Node           *left;
+
+		left = node->data.bin_op.left;
+		node->data.bin_op.left = NULL;
+		node_destroy(node);
+		return left;
+	    } else
+		return node;
+	/*
+	 * Eliminate 1 as neutral division right operand.
+	 */
+	else if (node->data.bin_op.operato == '/')
+	    if (node->data.bin_op.right->type == 'c' && node->data.bin_op.right->data.constant == 1) {
+		Node           *left;
+
+		left = node->data.bin_op.left;
+		node->data.bin_op.left = NULL;
+		node_destroy(node);
+		return left;
+	    } else
+		return node;
+	/*
+	 * Eliminate 0 and 1 as both left and right exponentiation
+	 * operands.
+	 */
+	else if (node->data.bin_op.operato == '^')
+	    if (node->data.bin_op.left->type == 'c' && node->data.bin_op.left->data.constant == 0) {
+		node_destroy(node);
+		return node_create('c', 0.0);
+	    } else if (node->data.bin_op.left->type == 'c' && node->data.bin_op.left->data.constant == 1) {
+		node_destroy(node);
+		return node_create('c', 1.0);
+	    } else if (node->data.bin_op.right->type == 'c' && node->data.bin_op.right->data.constant == 0) {
+		node_destroy(node);
+		return node_create('c', 1.0);
+	    } else if (node->data.bin_op.right->type == 'c' && node->data.bin_op.right->data.constant == 1) {
+		Node           *left;
+
+		left = node->data.bin_op.left;
+		node->data.bin_op.left = NULL;
+		node_destroy(node);
+		return left;
+	    } else
+		return node;
+	else
+	    return node;
+    }
+
+    return NULL;
+}
+
+double
+node_evaluate(Node * node)
+{
+    /*
+     * According to node type, evaluate subtree rooted at node.
+     */
+    switch (node->type) {
+	case 'c':
+	return node->data.constant;
+
+    case 'v':
+	/*
+	 * Variable values are used from symbol table.
+	 */
+	return node->data.variable->data.value;
+
+    case 'f':
+	/*
+	 * Functions are evaluated through symbol table.
+	 */
+	return (*node->data.function.record->data.function) (node_evaluate(node->data.function.child));
+
+    case 'u':
+	/*
+	 * Unary operator node is evaluated according to operator
+	 * type.
+	 */
+	switch (node->data.un_op.operato) {
+	case '-':
+	    return -node_evaluate(node->data.un_op.child);
+	}
+
+    case 'b':
+	/*
+	 * Binary operator node is evaluated according to operator
+	 * type.
+	 */
+	switch (node->data.un_op.operato) {
+	case '+':
+	    return node_evaluate(node->data.bin_op.left) + node_evaluate(node->data.bin_op.right);
+
+	case '-':
+	    return node_evaluate(node->data.bin_op.left) - node_evaluate(node->data.bin_op.right);
+
+	case '*':
+	    return node_evaluate(node->data.bin_op.left) * node_evaluate(node->data.bin_op.right);
+
+	case '/':
+	    return node_evaluate(node->data.bin_op.left) / node_evaluate(node->data.bin_op.right);
+
+	case '^':
+	    return pow(node_evaluate(node->data.bin_op.left), node_evaluate(node->data.bin_op.right));
+	}
+    }
+
+    return 0;
+}
+
+Node *
+node_derivative(Node * node, char *name, SymbolTable * symbol_table)
+{
+    /*
+     * According to node type, derivative tree for subtree rooted at node
+     * is created.
+     */
+    switch (node->type) {
+	case 'c':
+	/*
+	 * Derivative of constant equals 0.
+	 */
+	return node_create('c', 0.0);
+
+    case 'v':
+	/*
+	 * Derivative of variable equals 1 if variable is derivative
+	 * variable, 0 otherwise.
+	 */
+	return node_create('c', (!strcmp(name, node->data.variable->name)) ? 1.0 : 0.0);
+
+    case 'f':
+	/*
+	 * Apply rule of exponential function derivative.
+	 */
+	if (!strcmp(node->data.function.record->name, "Exp"))
+	    return node_create('b', '*', node_derivative(node->data.function.child, name, symbol_table), node_copy(node));
+	/*
+	 * Apply rule of logarithmic function derivative.
+	 */
+	else if (!strcmp(node->data.function.record->name, "Log"))
+	    return node_create('b', '/', node_derivative(node->data.function.child, name, symbol_table), node_copy(node->data.function.child));
+	/*
+	 * Apply rule of square root function derivative.
+	 */
+	else if (!strcmp(node->data.function.record->name, "Sqrt"))
+	    return node_create('b', '/', node_derivative(node->data.function.child, name, symbol_table), node_create('b', '*', node_create('c', 2.0), node_copy(node)));
+	/*
+	 * Apply rule of sine function derivative.
+	 */
+	else if (!strcmp(node->data.function.record->name, "Sin"))
+	    return node_create('b', '*', node_derivative(node->data.function.child, name, symbol_table), node_create('f', symbol_table_lookup(symbol_table, "Cos"), node_copy(node->data.function.child)));
+	/*
+	 * Apply rule of cosine function derivative.
+	 */
+	else if (!strcmp(node->data.function.record->name, "Cos"))
+	    return node_create('u', '-', node_create('b', '*', node_derivative(node->data.function.child, name, symbol_table), node_create('f', symbol_table_lookup(symbol_table, "Sin"), node_copy(node->data.function.child))));
+	/*
+	 * Apply rule of tangent function derivative.
+	 */
+	else if (!strcmp(node->data.function.record->name, "Tan"))
+	    return node_create('b', '/', node_derivative(node->data.function.child, name, symbol_table), node_create('b', '^', node_create('f', symbol_table_lookup(symbol_table, "Cos"), node_copy(node->data.function.child)), node_create('c', 2.0)));
+	/*
+	 * Apply rule of cotangent function derivative.
+	 */
+	else if (!strcmp(node->data.function.record->name, "Ctan"))
+	    return node_create('u', '-', node_create('b', '/', node_derivative(node->data.function.child, name, symbol_table), node_create('b', '^', node_create('f', symbol_table_lookup(symbol_table, "Sin"), node_copy(node->data.function.child)), node_create('c', 2.0))));
+	/*
+	 * Apply rule of inverse sine function derivative.
+	 */
+	else if (!strcmp(node->data.function.record->name, "Asin"))
+	    return node_create('b', '/', node_derivative(node->data.function.child, name, symbol_table), node_create('f', symbol_table_lookup(symbol_table, "Sqrt"), node_create('b', '-', node_create('c', 1.0), node_create('b', '^', node_copy(node->data.function.child), node_create('c', 2.0)))));
+	/*
+	 * Apply rule of inverse cosine function derivative.
+	 */
+	else if (!strcmp(node->data.function.record->name, "Acos"))
+	    return node_create('u', '-', node_create('b', '/', node_derivative(node->data.function.child, name, symbol_table), node_create('f', symbol_table_lookup(symbol_table, "Sqrt"), node_create('b', '-', node_create('c', 1.0), node_create('b', '^', node_copy(node->data.function.child), node_create('c', 2.0))))));
+	/*
+	 * Apply rule of inverse tangent function derivative.
+	 */
+	else if (!strcmp(node->data.function.record->name, "Atan"))
+	    return node_create('b', '/', node_derivative(node->data.function.child, name, symbol_table), node_create('b', '+', node_create('c', 1.0), node_create('b', '^', node_copy(node->data.function.child), node_create('c', 2.0))));
+	/*
+	 * Apply rule of inverse cotanget function derivative.
+	 */
+	else if (!strcmp(node->data.function.record->name, "Actan"))
+	    return node_create('u', '-', node_create('b', '/', node_derivative(node->data.function.child, name, symbol_table), node_create('b', '+', node_create('c', 1.0), node_create('b', '^', node_copy(node->data.function.child), node_create('c', 2.0)))));
+	/*
+	 * Apply rule of hyperbolic sine function derivative.
+	 */
+	else if (!strcmp(node->data.function.record->name, "Sinh"))
+	    return node_create('b', '*', node_derivative(node->data.function.child, name, symbol_table), node_create('f', symbol_table_lookup(symbol_table, "Cosh"), node_copy(node->data.function.child)));
+	/*
+	 * Apply rule of hyperbolic cosine function derivative.
+	 */
+	else if (!strcmp(node->data.function.record->name, "Cosh"))
+	    return node_create('b', '*', node_derivative(node->data.function.child, name, symbol_table), node_create('f', symbol_table_lookup(symbol_table, "Sinh"), node_copy(node->data.function.child)));
+	/*
+	 * Apply rule of hyperbolic tangent function derivative.
+	 */
+	else if (!strcmp(node->data.function.record->name, "Tanh"))
+	    return node_create('b', '/', node_derivative(node->data.function.child, name, symbol_table), node_create('b', '^', node_create('f', symbol_table_lookup(symbol_table, "Cosh"), node_copy(node->data.function.child)), node_create('c', 2.0)));
+	/*
+	 * Apply rule of hyperbolic cotangent function derivative.
+	 */
+	else if (!strcmp(node->data.function.record->name, "Ctanh"))
+	    return node_create('u', '-', node_create('b', '/', node_derivative(node->data.function.child, name, symbol_table), node_create('b', '^', node_create('f', symbol_table_lookup(symbol_table, "sinh"), node_copy(node->data.function.child)), node_create('c', 2.0))));
+	/*
+	 * Apply rule of inverse hyperbolic sine function derivative.
+	 */
+	else if (!strcmp(node->data.function.record->name, "Asinh"))
+	    return node_create('b', '/', node_derivative(node->data.function.child, name, symbol_table), node_create('f', symbol_table_lookup(symbol_table, "Sqrt"), node_create('b', '-', node_create('c', 1.0), node_create('b', '^', node_copy(node->data.function.child), node_create('c', 2.0)))));
+	/*
+	 * Apply rule of inverse hyperbolic cosine function
+	 * derivative.
+	 */
+	else if (!strcmp(node->data.function.record->name, "Acosh"))
+	    return node_create('b', '/', node_derivative(node->data.function.child, name, symbol_table), node_create('f', symbol_table_lookup(symbol_table, "Sqrt"), node_create('b', '-', node_create('b', '^', node_copy(node->data.function.child), node_create('c', 2.0)), node_create('c', 1.0))));
+	/*
+	 * Apply rule of inverse hyperbolic tangent function
+	 * derivative.
+	 */
+	else if (!strcmp(node->data.function.record->name, "Atanh"))
+	    return node_create('b', '/', node_derivative(node->data.function.child, name, symbol_table), node_create('b', '-', node_create('c', 1.0), node_create('b', '^', node_copy(node->data.function.child), node_create('c', 2.0))));
+	/*
+	 * Apply rule of inverse hyperbolic cotangent function
+	 * derivative.
+	 */
+	else if (!strcmp(node->data.function.record->name, "Actanh"))
+	    return node_create('b', '/', node_derivative(node->data.function.child, name, symbol_table), node_create('b', '-', node_create('b', '^', node_copy(node->data.function.child), node_create('c', 2.0)), node_create('c', 1.0)));
+	/*
+	 * Apply rule of absolute value function derivative.
+	 */
+	else if (!strcmp(node->data.function.record->name, "Fabs"))
+	    return node_create('b', '/', node_create('b', '*', node_derivative(node->data.function.child, name, symbol_table), node_copy(node->data.function.child)), node_create('f', symbol_table_lookup(symbol_table, "Sqrt"), node_create('b', '^', node_copy(node->data.function.child), node_create('c', 2.0))));
+
+    case 'u':
+	switch (node->data.un_op.operato) {
+	case '-':
+	    /*
+	     * Apply (-f)'=-f' derivative rule.
+	     */
+	    return node_create('u', '-', node_derivative(node->data.un_op.child, name, symbol_table));
+	}
+
+    case 'b':
+	switch (node->data.bin_op.operato) {
+	case '+':
+	    /*
+	     * Apply (f+g)'=f'+g' derivative rule.
+	     */
+	    return node_create('b', '+', node_derivative(node->data.bin_op.left, name, symbol_table), node_derivative(node->data.bin_op.right, name, symbol_table));
+
+	case '-':
+	    /*
+	     * Apply (f-g)'=f'-g' derivative rule.
+	     */
+	    return node_create('b', '-', node_derivative(node->data.bin_op.left, name, symbol_table), node_derivative(node->data.bin_op.right, name, symbol_table));
+
+	case '*':
+	    /*
+	     * Apply (f*g)'=f'*g+f*g' derivative rule.
+	     */
+	    return node_create('b', '+', node_create('b', '*', node_derivative(node->data.bin_op.left, name, symbol_table), node_copy(node->data.bin_op.right)), node_create('b', '*', node_copy(node->data.bin_op.left), node_derivative(node->data.bin_op.right, name, symbol_table)));
+
+	case '/':
+	    /*
+	     * Apply (f/g)'=(f'*g-f*g')/g^2 derivative rule.
+	     */
+	    return node_create('b', '/', node_create('b', '-', node_create('b', '*', node_derivative(node->data.bin_op.left, name, symbol_table), node_copy(node->data.bin_op.right)), node_create('b', '*', node_copy(node->data.bin_op.left), node_derivative(node->data.bin_op.right, name, symbol_table))), node_create('b', '^', node_copy(node->data.bin_op.right), node_create('c', 2.0)));
+
+	case '^':
+	    /*
+	     * If right operand of exponentiation constant apply
+	     * (f^n)'=n*f^(n-1)*f' derivative rule.
+	     */
+	    if (node->data.bin_op.right->type == 'c')
+		return node_create('b', '*', node_create('b', '*', node_create('c', node->data.bin_op.right->data.constant), node_derivative(node->data.bin_op.left, name, symbol_table)), node_create('b', '^', node_copy(node->data.bin_op.left), node_create('c', node->data.bin_op.right->data.constant - 1.0)));
+	    /*
+	     * Otherwise, apply logaritmhic derivative rule:
+	     * (log(f^g))'=(f^g)'/f^g =>
+	     * (f^g)'=f^g*(log(f^g))'=f^g*(g*log(f))'
+	     */
+	    else {
+		Node           *log_node, *derivative;
+
+		log_node = node_create('b', '*', node_copy(node->data.bin_op.right), node_create('f', symbol_table_lookup(symbol_table, "Log"), node_copy(node->data.bin_op.left)));
+		derivative = node_create('b', '*', node_copy(node), node_derivative(log_node, name, symbol_table));
+		node_destroy(log_node);
+		return derivative;
+	    }
+	}
+    }
+
+    return NULL;
+}
+
+int
+node_calculate_length(Node * node)
+{
+    char           *string;	/* String representing constant node
+				 * value. */
+    int             length;	/* Length of above string. */
+
+    /*
+     * According to node type, calculate length of string representing
+     * subtree rooted at node.
+     */
+    switch (node->type) {
+    case 'c':
+	length = 0;
+	if (node->data.constant < 0)
+	    length += 1;
+	if (asprintf(&string, "%g", node->data.constant) != -1)
+	    length += strlen(string);
+	free(string);
+	if (node->data.constant < 0)
+	    length += 1;
+	return length;
+
+    case 'v':
+	return strlen(node->data.variable->name);
+
+    case 'f':
+	return strlen(node->data.function.record->name) + 1 + node_calculate_length(node->data.function.child) + 1;
+	break;
+
+    case 'u':
+	return 1 + 1 + node_calculate_length(node->data.un_op.child) + 1;
+
+    case 'b':
+	return 1 + node_calculate_length(node->data.bin_op.left) + 1 + node_calculate_length(node->data.bin_op.right) + 1;
+    }
+
+    return 0;
+}
+
+void
+node_write(Node * node, char *string)
+{
+    /*
+     * According to node type, write subtree rooted at node to node
+     * string variable.  Always use parenthesis to resolve operator
+     * precedence.
+     */
+    switch (node->type) {
+	case 'c':
+	if (node->data.constant < 0) {
+	    sprintf(string, "%c", '(');
+	    string += strlen(string);
+	}
+	sprintf(string, "%g", node->data.constant);
+	string += strlen(string);
+	if (node->data.constant < 0)
+	    sprintf(string, "%c", ')');
+	break;
+
+    case 'v':
+	sprintf(string, "%s", node->data.variable->name);
+	break;
+
+    case 'f':
+	sprintf(string, "%s%c", node->data.function.record->name, '(');
+	string += strlen(string);
+	node_write(node->data.function.child, string);
+	string += strlen(string);
+	sprintf(string, "%c", ')');
+	break;
+
+    case 'u':
+	sprintf(string, "%c", '(');
+	string += strlen(string);
+	sprintf(string, "%c", node->data.un_op.operato);
+	string += strlen(string);
+	node_write(node->data.un_op.child, string);
+	string += strlen(string);
+	sprintf(string, "%c", ')');
+	break;
+
+    case 'b':
+	sprintf(string, "%c", '(');
+	string += strlen(string);
+	node_write(node->data.bin_op.left, string);
+	string += strlen(string);
+	sprintf(string, "%c", node->data.bin_op.operato);
+	string += strlen(string);
+	node_write(node->data.bin_op.right, string);
+	string += strlen(string);
+	sprintf(string, "%c", ')');
+	break;
+    }
+}
diff --git a/MathEval/node.h b/MathEval/node.h
new file mode 100644
index 0000000000000000000000000000000000000000..f14b301bf13234d03547ea3a7b44efff7476f1a7
--- /dev/null
+++ b/MathEval/node.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 1999, 2002, 2003  Free Software Foundation, Inc.
+ * 
+ * This file is part of GNU libmatheval
+ * 
+ * GNU libmatheval is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2, or (at your option) any later
+ * version.
+ * 
+ * GNU libmatheval is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* This file was modified for inclusion in Gmsh */
+
+#ifndef NODE_H
+#define NODE_H 1
+
+#include "symbol_table.h"
+
+/* Data structure representing function tree node.  */
+typedef struct _Node {
+  char            type;	/* Node type ('c' for constant, 'v' for
+			 * variable, 'f' for function, 'u' for unary
+			 * operator, 'b' for binary operator).  */
+  union {
+    double          constant;	/* Constant value.  */
+    Record         *variable;	/* Symbol table record for
+				 * variable.  */
+    struct {
+      Record         *record;	/* Symbol table record for
+				 * function.  */
+      struct _Node   *child;	/* Function argument node.  */
+    }               function;	/* Structure representing
+				 * function.  */
+    struct {
+      char            operato;	/* Operator type ('-'
+				 * for unary minus).  */
+      struct _Node   *child;	/* Operand node.  */
+    }               un_op;	/* Structure representing unary
+				 * operator.  */
+    struct {
+      char            operato;	/* Operator type ('+'
+				 * for adition, '-' for
+				 * subtraction, '*' for
+				 * multiplication, '/'
+				 * for division and '^'
+				 * for exponentiation).  */
+      struct _Node   *left, *right;	/* Operands nodes.  */
+    }               bin_op;	/* Structure representing binary
+				 * operator.  */
+  }               data;
+}               Node;
+
+/*
+ * Create node of given type and initialize it from optional arguments.
+ * Function returns pointer to node object that should be passed as first
+ * argument to all other node functions.
+ */
+Node           *node_create(char type,...);
+
+/* Destroy subtree rooted at specified node.  */
+void            node_destroy(Node * node);
+
+/*
+ * Make a copy of subtree rooted at given node.  Deep copy operation is
+ * employed.
+ */
+Node           *node_copy(Node * node);
+
+/*
+ * Simplify subtree rooted at given node.  Function returns root of
+ * simplified subtree (that may or may not be original node).
+ */
+Node           *node_simplify(Node * node);
+
+/*
+ * Evaluate subtree rooted at given node.  For variables, values from symbol
+ * table are used.
+ */
+double          node_evaluate(Node * node);
+
+/*
+ * Create derivative tree for subtree rooted at given node.  Second argument
+ * is derivation variable, third argument is symbol table (needed for
+ * functions derivatives).  Function returns root of corresponding derivation
+ * tree.
+ */
+Node           *node_derivative(Node * node, char *name, SymbolTable * symbol_table);
+
+/*
+ * Calculate length of the string representing subtree rooted at specified
+ * node.
+ */
+int             node_calculate_length(Node * node);
+
+/*
+ * Write subtree rooted at specified node to given string variable.  No
+ * checking of string overflow is done by this procedure; it is expected that
+ * string of appropriate length is passed as argument.
+ */
+void            node_write(Node * node, char *string);
+
+#endif
diff --git a/MathEval/parser.cpp b/MathEval/parser.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c75d34ed53934a63b8e4263492e62d5d9bf96a44
--- /dev/null
+++ b/MathEval/parser.cpp
@@ -0,0 +1,1037 @@
+
+/*  A Bison parser, made from parser.y
+    by GNU Bison version 1.28  */
+
+#define YYBISON 1  /* Identify Bison output.  */
+
+#define yyparse meparse
+#define yylex melex
+#define yyerror meerror
+#define yylval melval
+#define yychar mechar
+#define yydebug medebug
+#define yynerrs menerrs
+#define	NUMBER	257
+#define	VARIABLE	258
+#define	FUNCTION	259
+#define	NEG	260
+
+#line 1 "parser.y"
+
+/*
+ * Copyright (C) 1999, 2002, 2003  Free Software Foundation, Inc.
+ * 
+ * This file is part of GNU libmatheval
+ *
+ * GNU libmatheval is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU libmatheval is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+/* This file was modified for inclusion in Gmsh */
+
+#include "common.h"
+#include "node.h"
+
+/* Variables used to communicate with code using parser.  */
+extern Node* matheval_root; /* Root of tree representation of function.  */
+extern int matheval_ok; /* Flag representing success of parsing.  */
+
+/* Report parsing error.  */
+int yyerror (char *s);
+
+/* Function used to tokenize string representing function (this function
+   is generated by scanner generator).  */
+int yylex (void);
+
+#line 41 "parser.y"
+typedef union {
+  Node *node;
+  Record *record;
+} YYSTYPE;
+#include <stdio.h>
+
+#ifndef __cplusplus
+#ifndef __STDC__
+#define const
+#endif
+#endif
+
+
+
+#define	YYFINAL		26
+#define	YYFLAG		-32768
+#define	YYNTBASE	15
+
+#define YYTRANSLATE(x) ((unsigned)(x) <= 260 ? yytranslate[x] : 17)
+
+static const char yytranslate[] = {     0,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,    12,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,    13,
+    14,     8,     7,     2,     6,     2,     9,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,    11,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     1,     3,     4,     5,    10
+};
+
+#if YYDEBUG != 0
+static const short yyprhs[] = {     0,
+     0,     3,     5,     7,    11,    15,    19,    23,    26,    30,
+    35
+};
+
+static const short yyrhs[] = {    16,
+    12,     0,     3,     0,     4,     0,    16,     7,    16,     0,
+    16,     6,    16,     0,    16,     8,    16,     0,    16,     9,
+    16,     0,     6,    16,     0,    16,    11,    16,     0,     5,
+    13,    16,    14,     0,    13,    16,    14,     0
+};
+
+#endif
+
+#if YYDEBUG != 0
+static const short yyrline[] = { 0,
+    64,    72,    75,    78,    82,    86,    90,    94,    98,   102,
+   106
+};
+#endif
+
+
+#if YYDEBUG != 0 || defined (YYERROR_VERBOSE)
+
+static const char * const yytname[] = {   "$","error","$undefined.","NUMBER",
+"VARIABLE","FUNCTION","'-'","'+'","'*'","'/'","NEG","'^'","'\\n'","'('","')'",
+"input","expression", NULL
+};
+#endif
+
+static const short yyr1[] = {     0,
+    15,    16,    16,    16,    16,    16,    16,    16,    16,    16,
+    16
+};
+
+static const short yyr2[] = {     0,
+     2,     1,     1,     3,     3,     3,     3,     2,     3,     4,
+     3
+};
+
+static const short yydefact[] = {     0,
+     2,     3,     0,     0,     0,     0,     0,     8,     0,     0,
+     0,     0,     0,     0,     1,     0,    11,     5,     4,     6,
+     7,     9,    10,     0,     0,     0
+};
+
+static const short yydefgoto[] = {    24,
+     6
+};
+
+static const short yypact[] = {     8,
+-32768,-32768,   -11,     8,     8,    27,     8,    -7,     9,     8,
+     8,     8,     8,     8,-32768,    18,-32768,    32,    32,    -7,
+    -7,-32768,-32768,     5,    19,-32768
+};
+
+static const short yypgoto[] = {-32768,
+    -4
+};
+
+
+#define	YYLAST		43
+
+
+static const short yytable[] = {     8,
+     9,     7,    16,    14,    25,    18,    19,    20,    21,    22,
+     1,     2,     3,     4,    10,    11,    12,    13,    26,    14,
+     5,     0,    17,    10,    11,    12,    13,     0,    14,     0,
+     0,    23,    10,    11,    12,    13,     0,    14,    15,    12,
+    13,     0,    14
+};
+
+static const short yycheck[] = {     4,
+     5,    13,     7,    11,     0,    10,    11,    12,    13,    14,
+     3,     4,     5,     6,     6,     7,     8,     9,     0,    11,
+    13,    -1,    14,     6,     7,     8,     9,    -1,    11,    -1,
+    -1,    14,     6,     7,     8,     9,    -1,    11,    12,     8,
+     9,    -1,    11
+};
+/* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */
+#line 3 "/usr/share/bison.simple"
+/* This file comes from bison-1.28.  */
+
+/* Skeleton output parser for bison,
+   Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, when this file is copied by Bison into a
+   Bison output file, you may use that output file without restriction.
+   This special exception was added by the Free Software Foundation
+   in version 1.24 of Bison.  */
+
+/* This is the parser code that is written into each bison parser
+  when the %semantic_parser declaration is not specified in the grammar.
+  It was written by Richard Stallman by simplifying the hairy parser
+  used when %semantic_parser is specified.  */
+
+#ifndef YYSTACK_USE_ALLOCA
+#ifdef alloca
+#define YYSTACK_USE_ALLOCA
+#else /* alloca not defined */
+#ifdef __GNUC__
+#define YYSTACK_USE_ALLOCA
+#define alloca __builtin_alloca
+#else /* not GNU C.  */
+#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || (defined (__sun) && defined (__i386))
+#define YYSTACK_USE_ALLOCA
+#include <alloca.h>
+#else /* not sparc */
+/* We think this test detects Watcom and Microsoft C.  */
+/* This used to test MSDOS, but that is a bad idea
+   since that symbol is in the user namespace.  */
+#if (defined (_MSDOS) || defined (_MSDOS_)) && !defined (__TURBOC__)
+#if 0 /* No need for malloc.h, which pollutes the namespace;
+	 instead, just don't use alloca.  */
+#include <malloc.h>
+#endif
+#else /* not MSDOS, or __TURBOC__ */
+#if defined(_AIX)
+/* I don't know what this was needed for, but it pollutes the namespace.
+   So I turned it off.   rms, 2 May 1997.  */
+/* #include <malloc.h>  */
+ #pragma alloca
+#define YYSTACK_USE_ALLOCA
+#else /* not MSDOS, or __TURBOC__, or _AIX */
+#if 0
+#ifdef __hpux /* haible@ilog.fr says this works for HPUX 9.05 and up,
+		 and on HPUX 10.  Eventually we can turn this on.  */
+#define YYSTACK_USE_ALLOCA
+#define alloca __builtin_alloca
+#endif /* __hpux */
+#endif
+#endif /* not _AIX */
+#endif /* not MSDOS, or __TURBOC__ */
+#endif /* not sparc */
+#endif /* not GNU C */
+#endif /* alloca not defined */
+#endif /* YYSTACK_USE_ALLOCA not defined */
+
+#ifdef YYSTACK_USE_ALLOCA
+#define YYSTACK_ALLOC alloca
+#else
+#define YYSTACK_ALLOC malloc
+#endif
+
+/* Note: there must be only one dollar sign in this file.
+   It is replaced by the list of actions, each action
+   as one case of the switch.  */
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		-2
+#define YYEOF		0
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT 	goto yyabortlab
+#define YYERROR		goto yyerrlab1
+/* Like YYERROR except do call yyerror.
+   This remains here temporarily to ease the
+   transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  */
+#define YYFAIL		goto yyerrlab
+#define YYRECOVERING()  (!!yyerrstatus)
+#define YYBACKUP(token, value) \
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    { yychar = (token), yylval = (value);			\
+      yychar1 = YYTRANSLATE (yychar);				\
+      YYPOPSTACK;						\
+      goto yybackup;						\
+    }								\
+  else								\
+    { yyerror ("syntax error: cannot back up"); YYERROR; }	\
+while (0)
+
+#define YYTERROR	1
+#define YYERRCODE	256
+
+#ifndef YYPURE
+#define YYLEX		yylex()
+#endif
+
+#ifdef YYPURE
+#ifdef YYLSP_NEEDED
+#ifdef YYLEX_PARAM
+#define YYLEX		yylex(&yylval, &yylloc, YYLEX_PARAM)
+#else
+#define YYLEX		yylex(&yylval, &yylloc)
+#endif
+#else /* not YYLSP_NEEDED */
+#ifdef YYLEX_PARAM
+#define YYLEX		yylex(&yylval, YYLEX_PARAM)
+#else
+#define YYLEX		yylex(&yylval)
+#endif
+#endif /* not YYLSP_NEEDED */
+#endif
+
+/* If nonreentrant, generate the variables here */
+
+#ifndef YYPURE
+
+int	yychar;			/*  the lookahead symbol		*/
+YYSTYPE	yylval;			/*  the semantic value of the		*/
+				/*  lookahead symbol			*/
+
+#ifdef YYLSP_NEEDED
+YYLTYPE yylloc;			/*  location data for the lookahead	*/
+				/*  symbol				*/
+#endif
+
+int yynerrs;			/*  number of parse errors so far       */
+#endif  /* not YYPURE */
+
+#if YYDEBUG != 0
+int yydebug;			/*  nonzero means print parse trace	*/
+/* Since this is uninitialized, it does not stop multiple parsers
+   from coexisting.  */
+#endif
+
+/*  YYINITDEPTH indicates the initial size of the parser's stacks	*/
+
+#ifndef	YYINITDEPTH
+#define YYINITDEPTH 200
+#endif
+
+/*  YYMAXDEPTH is the maximum size the stacks can grow to
+    (effective only if the built-in stack extension method is used).  */
+
+#if YYMAXDEPTH == 0
+#undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+#define YYMAXDEPTH 10000
+#endif
+
+/* Define __yy_memcpy.  Note that the size argument
+   should be passed with type unsigned int, because that is what the non-GCC
+   definitions require.  With GCC, __builtin_memcpy takes an arg
+   of type size_t, but it can handle unsigned int.  */
+
+#if __GNUC__ > 1		/* GNU C and GNU C++ define this.  */
+#define __yy_memcpy(TO,FROM,COUNT)	__builtin_memcpy(TO,FROM,COUNT)
+#else				/* not GNU C or C++ */
+#ifndef __cplusplus
+
+/* This is the most reliable way to avoid incompatibilities
+   in available built-in functions on various systems.  */
+static void
+__yy_memcpy (to, from, count)
+     char *to;
+     char *from;
+     unsigned int count;
+{
+  register char *f = from;
+  register char *t = to;
+  register int i = count;
+
+  while (i-- > 0)
+    *t++ = *f++;
+}
+
+#else /* __cplusplus */
+
+/* This is the most reliable way to avoid incompatibilities
+   in available built-in functions on various systems.  */
+static void
+__yy_memcpy (char *to, char *from, unsigned int count)
+{
+  register char *t = to;
+  register char *f = from;
+  register int i = count;
+
+  while (i-- > 0)
+    *t++ = *f++;
+}
+
+#endif
+#endif
+
+#line 217 "/usr/share/bison.simple"
+
+/* The user can define YYPARSE_PARAM as the name of an argument to be passed
+   into yyparse.  The argument should have type void *.
+   It should actually point to an object.
+   Grammar actions can access the variable by casting it
+   to the proper pointer type.  */
+
+#ifdef YYPARSE_PARAM
+#ifdef __cplusplus
+#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL
+#else /* not __cplusplus */
+#define YYPARSE_PARAM_ARG YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;
+#endif /* not __cplusplus */
+#else /* not YYPARSE_PARAM */
+#define YYPARSE_PARAM_ARG
+#define YYPARSE_PARAM_DECL
+#endif /* not YYPARSE_PARAM */
+
+/* Prevent warning if -Wstrict-prototypes.  */
+#ifdef __GNUC__
+#ifdef YYPARSE_PARAM
+int yyparse (void *);
+#else
+int yyparse (void);
+#endif
+#endif
+
+int
+yyparse(YYPARSE_PARAM_ARG)
+     YYPARSE_PARAM_DECL
+{
+  register int yystate;
+  register int yyn;
+  register short *yyssp;
+  register YYSTYPE *yyvsp;
+  int yyerrstatus;	/*  number of tokens to shift before error messages enabled */
+  int yychar1 = 0;		/*  lookahead token as an internal (translated) token number */
+
+  short	yyssa[YYINITDEPTH];	/*  the state stack			*/
+  YYSTYPE yyvsa[YYINITDEPTH];	/*  the semantic value stack		*/
+
+  short *yyss = yyssa;		/*  refer to the stacks thru separate pointers */
+  YYSTYPE *yyvs = yyvsa;	/*  to allow yyoverflow to reallocate them elsewhere */
+
+#ifdef YYLSP_NEEDED
+  YYLTYPE yylsa[YYINITDEPTH];	/*  the location stack			*/
+  YYLTYPE *yyls = yylsa;
+  YYLTYPE *yylsp;
+
+#define YYPOPSTACK   (yyvsp--, yyssp--, yylsp--)
+#else
+#define YYPOPSTACK   (yyvsp--, yyssp--)
+#endif
+
+  int yystacksize = YYINITDEPTH;
+  int yyfree_stacks = 0;
+
+#ifdef YYPURE
+  int yychar;
+  YYSTYPE yylval;
+  int yynerrs;
+#ifdef YYLSP_NEEDED
+  YYLTYPE yylloc;
+#endif
+#endif
+
+  YYSTYPE yyval;		/*  the variable used to return		*/
+				/*  semantic values from the action	*/
+				/*  routines				*/
+
+  int yylen;
+
+#if YYDEBUG != 0
+  if (yydebug)
+    fprintf(stderr, "Starting parse\n");
+#endif
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY;		/* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+
+  yyssp = yyss - 1;
+  yyvsp = yyvs;
+#ifdef YYLSP_NEEDED
+  yylsp = yyls;
+#endif
+
+/* Push a new state, which is found in  yystate  .  */
+/* In all cases, when you get here, the value and location stacks
+   have just been pushed. so pushing a state here evens the stacks.  */
+yynewstate:
+
+  *++yyssp = yystate;
+
+  if (yyssp >= yyss + yystacksize - 1)
+    {
+      /* Give user a chance to reallocate the stack */
+      /* Use copies of these so that the &'s don't force the real ones into memory. */
+      YYSTYPE *yyvs1 = yyvs;
+      short *yyss1 = yyss;
+#ifdef YYLSP_NEEDED
+      YYLTYPE *yyls1 = yyls;
+#endif
+
+      /* Get the current used size of the three stacks, in elements.  */
+      int size = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      /* Each stack pointer address is followed by the size of
+	 the data in use in that stack, in bytes.  */
+#ifdef YYLSP_NEEDED
+      /* This used to be a conditional around just the two extra args,
+	 but that might be undefined if yyoverflow is a macro.  */
+      yyoverflow("parser stack overflow",
+		 &yyss1, size * sizeof (*yyssp),
+		 &yyvs1, size * sizeof (*yyvsp),
+		 &yyls1, size * sizeof (*yylsp),
+		 &yystacksize);
+#else
+      yyoverflow("parser stack overflow",
+		 &yyss1, size * sizeof (*yyssp),
+		 &yyvs1, size * sizeof (*yyvsp),
+		 &yystacksize);
+#endif
+
+      yyss = yyss1; yyvs = yyvs1;
+#ifdef YYLSP_NEEDED
+      yyls = yyls1;
+#endif
+#else /* no yyoverflow */
+      /* Extend the stack our own way.  */
+      if (yystacksize >= YYMAXDEPTH)
+	{
+	  yyerror("parser stack overflow");
+	  if (yyfree_stacks)
+	    {
+	      free (yyss);
+	      free (yyvs);
+#ifdef YYLSP_NEEDED
+	      free (yyls);
+#endif
+	    }
+	  return 2;
+	}
+      yystacksize *= 2;
+      if (yystacksize > YYMAXDEPTH)
+	yystacksize = YYMAXDEPTH;
+#ifndef YYSTACK_USE_ALLOCA
+      yyfree_stacks = 1;
+#endif
+      yyss = (short *) YYSTACK_ALLOC (yystacksize * sizeof (*yyssp));
+      __yy_memcpy ((char *)yyss, (char *)yyss1,
+		   size * (unsigned int) sizeof (*yyssp));
+      yyvs = (YYSTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yyvsp));
+      __yy_memcpy ((char *)yyvs, (char *)yyvs1,
+		   size * (unsigned int) sizeof (*yyvsp));
+#ifdef YYLSP_NEEDED
+      yyls = (YYLTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yylsp));
+      __yy_memcpy ((char *)yyls, (char *)yyls1,
+		   size * (unsigned int) sizeof (*yylsp));
+#endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + size - 1;
+      yyvsp = yyvs + size - 1;
+#ifdef YYLSP_NEEDED
+      yylsp = yyls + size - 1;
+#endif
+
+#if YYDEBUG != 0
+      if (yydebug)
+	fprintf(stderr, "Stack size increased to %d\n", yystacksize);
+#endif
+
+      if (yyssp >= yyss + yystacksize - 1)
+	YYABORT;
+    }
+
+#if YYDEBUG != 0
+  if (yydebug)
+    fprintf(stderr, "Entering state %d\n", yystate);
+#endif
+
+  goto yybackup;
+ yybackup:
+
+/* Do appropriate processing given the current state.  */
+/* Read a lookahead token if we need one and don't already have one.  */
+/* yyresume: */
+
+  /* First try to decide what to do without reference to lookahead token.  */
+
+  yyn = yypact[yystate];
+  if (yyn == YYFLAG)
+    goto yydefault;
+
+  /* Not known => get a lookahead token if don't already have one.  */
+
+  /* yychar is either YYEMPTY or YYEOF
+     or a valid token in external form.  */
+
+  if (yychar == YYEMPTY)
+    {
+#if YYDEBUG != 0
+      if (yydebug)
+	fprintf(stderr, "Reading a token: ");
+#endif
+      yychar = YYLEX;
+    }
+
+  /* Convert token to internal form (in yychar1) for indexing tables with */
+
+  if (yychar <= 0)		/* This means end of input. */
+    {
+      yychar1 = 0;
+      yychar = YYEOF;		/* Don't call YYLEX any more */
+
+#if YYDEBUG != 0
+      if (yydebug)
+	fprintf(stderr, "Now at end of input.\n");
+#endif
+    }
+  else
+    {
+      yychar1 = YYTRANSLATE(yychar);
+
+#if YYDEBUG != 0
+      if (yydebug)
+	{
+	  fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]);
+	  /* Give the individual parser a way to print the precise meaning
+	     of a token, for further debugging info.  */
+#ifdef YYPRINT
+	  YYPRINT (stderr, yychar, yylval);
+#endif
+	  fprintf (stderr, ")\n");
+	}
+#endif
+    }
+
+  yyn += yychar1;
+  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
+    goto yydefault;
+
+  yyn = yytable[yyn];
+
+  /* yyn is what to do for this token type in this state.
+     Negative => reduce, -yyn is rule number.
+     Positive => shift, yyn is new state.
+       New state is final state => don't bother to shift,
+       just return success.
+     0, or most negative number => error.  */
+
+  if (yyn < 0)
+    {
+      if (yyn == YYFLAG)
+	goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+  else if (yyn == 0)
+    goto yyerrlab;
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  /* Shift the lookahead token.  */
+
+#if YYDEBUG != 0
+  if (yydebug)
+    fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]);
+#endif
+
+  /* Discard the token being shifted unless it is eof.  */
+  if (yychar != YYEOF)
+    yychar = YYEMPTY;
+
+  *++yyvsp = yylval;
+#ifdef YYLSP_NEEDED
+  *++yylsp = yylloc;
+#endif
+
+  /* count tokens shifted since error; after three, turn off error status.  */
+  if (yyerrstatus) yyerrstatus--;
+
+  yystate = yyn;
+  goto yynewstate;
+
+/* Do the default action for the current state.  */
+yydefault:
+
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+
+/* Do a reduction.  yyn is the number of a rule to reduce with.  */
+yyreduce:
+  yylen = yyr2[yyn];
+  if (yylen > 0)
+    yyval = yyvsp[1-yylen]; /* implement default value of the action */
+
+#if YYDEBUG != 0
+  if (yydebug)
+    {
+      int i;
+
+      fprintf (stderr, "Reducing via rule %d (line %d), ",
+	       yyn, yyrline[yyn]);
+
+      /* Print the symbols being reduced, and their result.  */
+      for (i = yyprhs[yyn]; yyrhs[i] > 0; i++)
+	fprintf (stderr, "%s ", yytname[yyrhs[i]]);
+      fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]);
+    }
+#endif
+
+
+  switch (yyn) {
+
+case 1:
+#line 64 "parser.y"
+{
+  matheval_root = yyvsp[-1].node;
+  yyerrok;
+  return 1;
+;
+    break;}
+case 2:
+#line 72 "parser.y"
+{
+  yyval.node = yyvsp[0].node;
+;
+    break;}
+case 3:
+#line 75 "parser.y"
+{
+  yyval.node = yyvsp[0].node;
+;
+    break;}
+case 4:
+#line 78 "parser.y"
+{
+  /* Create addition binary operator node.  */
+  yyval.node = node_create ('b', '+', yyvsp[-2].node, yyvsp[0].node);
+;
+    break;}
+case 5:
+#line 82 "parser.y"
+{
+  /* Create subtraction binary operator node.  */
+  yyval.node = node_create ('b', '-', yyvsp[-2].node, yyvsp[0].node);
+;
+    break;}
+case 6:
+#line 86 "parser.y"
+{
+  /* Create multiplication binary operator node.  */
+  yyval.node = node_create ('b', '*', yyvsp[-2].node, yyvsp[0].node);
+;
+    break;}
+case 7:
+#line 90 "parser.y"
+{
+  /* Create division binary operator node.  */
+  yyval.node = node_create ('b', '/', yyvsp[-2].node, yyvsp[0].node);
+;
+    break;}
+case 8:
+#line 94 "parser.y"
+{
+  /* Create minus unary operator node.  */
+  yyval.node = node_create ('u', '-', yyvsp[0].node);
+;
+    break;}
+case 9:
+#line 98 "parser.y"
+{
+  /* Create exponentiation unary operator node.  */
+  yyval.node = node_create ('b', '^', yyvsp[-2].node, yyvsp[0].node);
+;
+    break;}
+case 10:
+#line 102 "parser.y"
+{
+  /* Create function node.  */
+  yyval.node = node_create ('f', yyvsp[-3].record, yyvsp[-1].node);
+;
+    break;}
+case 11:
+#line 106 "parser.y"
+{
+  yyval.node = yyvsp[-1].node;
+;
+    break;}
+}
+   /* the action file gets copied in in place of this dollarsign */
+#line 543 "/usr/share/bison.simple"
+
+  yyvsp -= yylen;
+  yyssp -= yylen;
+#ifdef YYLSP_NEEDED
+  yylsp -= yylen;
+#endif
+
+#if YYDEBUG != 0
+  if (yydebug)
+    {
+      short *ssp1 = yyss - 1;
+      fprintf (stderr, "state stack now");
+      while (ssp1 != yyssp)
+	fprintf (stderr, " %d", *++ssp1);
+      fprintf (stderr, "\n");
+    }
+#endif
+
+  *++yyvsp = yyval;
+
+#ifdef YYLSP_NEEDED
+  yylsp++;
+  if (yylen == 0)
+    {
+      yylsp->first_line = yylloc.first_line;
+      yylsp->first_column = yylloc.first_column;
+      yylsp->last_line = (yylsp-1)->last_line;
+      yylsp->last_column = (yylsp-1)->last_column;
+      yylsp->text = 0;
+    }
+  else
+    {
+      yylsp->last_line = (yylsp+yylen-1)->last_line;
+      yylsp->last_column = (yylsp+yylen-1)->last_column;
+    }
+#endif
+
+  /* Now "shift" the result of the reduction.
+     Determine what state that goes to,
+     based on the state we popped back to
+     and the rule number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
+  if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTBASE];
+
+  goto yynewstate;
+
+yyerrlab:   /* here on detecting error */
+
+  if (! yyerrstatus)
+    /* If not already recovering from an error, report this error.  */
+    {
+      ++yynerrs;
+
+#ifdef YYERROR_VERBOSE
+      yyn = yypact[yystate];
+
+      if (yyn > YYFLAG && yyn < YYLAST)
+	{
+	  int size = 0;
+	  char *msg;
+	  int x, count;
+
+	  count = 0;
+	  /* Start X at -yyn if nec to avoid negative indexes in yycheck.  */
+	  for (x = (yyn < 0 ? -yyn : 0);
+	       x < (sizeof(yytname) / sizeof(char *)); x++)
+	    if (yycheck[x + yyn] == x)
+	      size += strlen(yytname[x]) + 15, count++;
+	  msg = (char *) malloc(size + 15);
+	  if (msg != 0)
+	    {
+	      strcpy(msg, "parse error");
+
+	      if (count < 5)
+		{
+		  count = 0;
+		  for (x = (yyn < 0 ? -yyn : 0);
+		       x < (sizeof(yytname) / sizeof(char *)); x++)
+		    if (yycheck[x + yyn] == x)
+		      {
+			strcat(msg, count == 0 ? ", expecting `" : " or `");
+			strcat(msg, yytname[x]);
+			strcat(msg, "'");
+			count++;
+		      }
+		}
+	      yyerror(msg);
+	      free(msg);
+	    }
+	  else
+	    yyerror ("parse error; also virtual memory exceeded");
+	}
+      else
+#endif /* YYERROR_VERBOSE */
+	yyerror("parse error");
+    }
+
+  goto yyerrlab1;
+yyerrlab1:   /* here on error raised explicitly by an action */
+
+  if (yyerrstatus == 3)
+    {
+      /* if just tried and failed to reuse lookahead token after an error, discard it.  */
+
+      /* return failure if at end of input */
+      if (yychar == YYEOF)
+	YYABORT;
+
+#if YYDEBUG != 0
+      if (yydebug)
+	fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]);
+#endif
+
+      yychar = YYEMPTY;
+    }
+
+  /* Else will try to reuse lookahead token
+     after shifting the error token.  */
+
+  yyerrstatus = 3;		/* Each real token shifted decrements this */
+
+  goto yyerrhandle;
+
+yyerrdefault:  /* current state does not do anything special for the error token. */
+
+#if 0
+  /* This is wrong; only states that explicitly want error tokens
+     should shift them.  */
+  yyn = yydefact[yystate];  /* If its default is to accept any token, ok.  Otherwise pop it.*/
+  if (yyn) goto yydefault;
+#endif
+
+yyerrpop:   /* pop the current state because it cannot handle the error token */
+
+  if (yyssp == yyss) YYABORT;
+  yyvsp--;
+  yystate = *--yyssp;
+#ifdef YYLSP_NEEDED
+  yylsp--;
+#endif
+
+#if YYDEBUG != 0
+  if (yydebug)
+    {
+      short *ssp1 = yyss - 1;
+      fprintf (stderr, "Error: state stack now");
+      while (ssp1 != yyssp)
+	fprintf (stderr, " %d", *++ssp1);
+      fprintf (stderr, "\n");
+    }
+#endif
+
+yyerrhandle:
+
+  yyn = yypact[yystate];
+  if (yyn == YYFLAG)
+    goto yyerrdefault;
+
+  yyn += YYTERROR;
+  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
+    goto yyerrdefault;
+
+  yyn = yytable[yyn];
+  if (yyn < 0)
+    {
+      if (yyn == YYFLAG)
+	goto yyerrpop;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+  else if (yyn == 0)
+    goto yyerrpop;
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+#if YYDEBUG != 0
+  if (yydebug)
+    fprintf(stderr, "Shifting error token, ");
+#endif
+
+  *++yyvsp = yylval;
+#ifdef YYLSP_NEEDED
+  *++yylsp = yylloc;
+#endif
+
+  yystate = yyn;
+  goto yynewstate;
+
+ yyacceptlab:
+  /* YYACCEPT comes here.  */
+  if (yyfree_stacks)
+    {
+      free (yyss);
+      free (yyvs);
+#ifdef YYLSP_NEEDED
+      free (yyls);
+#endif
+    }
+  return 0;
+
+ yyabortlab:
+  /* YYABORT comes here.  */
+  if (yyfree_stacks)
+    {
+      free (yyss);
+      free (yyvs);
+#ifdef YYLSP_NEEDED
+      free (yyls);
+#endif
+    }
+  return 1;
+}
+#line 111 "parser.y"
+
+
+int yyerror(char* s)
+{
+  /* Indicate parsing error through appropriate flag and stop
+     parsing.  */
+  matheval_ok = 0;
+  return 0;
+}
diff --git a/MathEval/parser.h b/MathEval/parser.h
new file mode 100644
index 0000000000000000000000000000000000000000..561b245ad9315b05eb2b1c21bdfd3edfc23e23fb
--- /dev/null
+++ b/MathEval/parser.h
@@ -0,0 +1,11 @@
+typedef union {
+  Node *node;
+  Record *record;
+} YYSTYPE;
+#define	NUMBER	257
+#define	VARIABLE	258
+#define	FUNCTION	259
+#define	NEG	260
+
+
+extern YYSTYPE melval;
diff --git a/MathEval/scanner.cpp b/MathEval/scanner.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2ccf060af8ef2ff1770412ed8cb5bb855b963c5c
--- /dev/null
+++ b/MathEval/scanner.cpp
@@ -0,0 +1,1710 @@
+#define yy_create_buffer me_create_buffer
+#define yy_delete_buffer me_delete_buffer
+#define yy_scan_buffer me_scan_buffer
+#define yy_scan_string me_scan_string
+#define yy_scan_bytes me_scan_bytes
+#define yy_flex_debug me_flex_debug
+#define yy_init_buffer me_init_buffer
+#define yy_flush_buffer me_flush_buffer
+#define yy_load_buffer_state me_load_buffer_state
+#define yy_switch_to_buffer me_switch_to_buffer
+#define yyin mein
+#define yyleng meleng
+#define yylex melex
+#define yyout meout
+#define yyrestart merestart
+#define yytext metext
+#define yywrap mewrap
+
+#line 20 "scanner.cpp"
+/* A lexical scanner generated by flex */
+
+/* Scanner skeleton version:
+ * $Header: /cvsroot/gmsh/MathEval/scanner.cpp,v 1.1 2004-05-12 02:02:21 geuzaine Exp $
+ */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+
+#include <stdio.h>
+
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Use prototypes in function declarations. */
+#define YY_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif	/* __STDC__ */
+#endif	/* ! __cplusplus */
+
+#ifdef __TURBOC__
+ #pragma warn -rch
+ #pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define YY_USE_CONST
+#define YY_USE_PROTOS
+#endif
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator).  This
+ * avoids problems with code like:
+ *
+ * 	if ( condition_holds )
+ *		yyless( 5 );
+ *	else
+ *		do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the yyless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+		*yy_cp = yy_hold_char; \
+		YY_RESTORE_YY_MORE_OFFSET \
+		yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int yy_size_t;
+
+
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via yyrestart()), so that the user can continue scanning by
+	 * just pointing yyin at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+	};
+
+static YY_BUFFER_STATE yy_current_buffer = 0;
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+
+static int yy_n_chars;		/* number of characters read into yy_ch_buf */
+
+
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 1;		/* whether we need to initialize */
+static int yy_start = 0;	/* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart YY_PROTO(( FILE *input_file ));
+
+void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));
+void yy_load_buffer_state YY_PROTO(( void ));
+YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));
+void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
+void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
+
+YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));
+YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));
+YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));
+
+static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
+static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
+static void yy_flex_free YY_PROTO(( void * ));
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! yy_current_buffer ) \
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+	yy_current_buffer->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! yy_current_buffer ) \
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+	yy_current_buffer->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+
+typedef unsigned char YY_CHAR;
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+typedef int yy_state_type;
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state YY_PROTO(( void ));
+static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));
+static int yy_get_next_buffer YY_PROTO(( void ));
+static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+	yytext_ptr = yy_bp; \
+	yyleng = (int) (yy_cp - yy_bp); \
+	yy_hold_char = *yy_cp; \
+	*yy_cp = '\0'; \
+	yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 13
+#define YY_END_OF_BUFFER 14
+static yyconst short int yy_accept[62] =
+    {   0,
+        0,    0,   14,   13,    1,   12,   10,   11,    7,    5,
+        6,   13,    8,    2,    4,    4,    4,    4,    4,    4,
+        4,    4,    9,    1,    2,    2,    2,    0,    4,    4,
+        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,
+        2,    0,    2,    4,    4,    4,    4,    3,    4,    3,
+        4,    3,    4,    3,    3,    4,    3,    3,    3,    3,
+        0
+    } ;
+
+static yyconst int yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    2,    1,    1,    1,    1,    1,    1,    1,    4,
+        5,    6,    7,    1,    8,    9,   10,   11,   11,   11,
+       11,   11,   11,   11,   11,   11,   11,    1,    1,    1,
+        1,    1,    1,    1,   12,   13,   14,   13,   15,   16,
+       13,   13,   13,   13,   13,   17,   13,   13,   13,   13,
+       13,   13,   18,   19,   13,   13,   13,   13,   13,   13,
+        1,    1,    1,   20,   13,    1,   21,   22,   23,   13,
+
+       24,   13,   25,   26,   27,   13,   13,   13,   13,   28,
+       29,   30,   31,   32,   33,   34,   13,   13,   13,   35,
+       13,   13,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst int yy_meta[36] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        2,    2,    2,    2,    2,    2,    2,    2,    2,    1,
+        2,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+        2,    2,    2,    2,    2
+    } ;
+
+static yyconst short int yy_base[63] =
+    {   0,
+        0,    0,  101,  102,   98,  102,  102,  102,  102,  102,
+      102,   88,  102,   27,   14,    0,   10,   63,   76,   67,
+       14,   74,  102,   92,   35,   38,   43,   49,    0,   32,
+       66,   71,   58,   69,   59,   66,   62,   58,   53,   56,
+       53,   72,   71,   48,   59,   51,   50,   50,   47,    0,
+       41,   47,   38,   45,   44,   41,   39,   37,   29,   17,
+      102,   38
+    } ;
+
+static yyconst short int yy_def[63] =
+    {   0,
+       61,    1,   61,   61,   61,   61,   61,   61,   61,   61,
+       61,   61,   61,   61,   62,   62,   62,   62,   62,   62,
+       62,   62,   61,   61,   61,   61,   61,   61,   62,   62,
+       62,   62,   62,   62,   62,   62,   62,   62,   62,   62,
+       61,   61,   61,   62,   62,   62,   62,   62,   62,   62,
+       62,   62,   62,   62,   62,   62,   62,   62,   62,   62,
+        0,   61
+    } ;
+
+static yyconst short int yy_nxt[138] =
+    {   0,
+        4,    5,    6,    7,    8,    9,   10,   11,   12,   13,
+       14,   15,   16,   17,   18,   19,   20,   21,   22,   23,
+       16,   16,   16,   16,   16,   16,   16,   16,   16,   16,
+       16,   16,   16,   16,   16,   26,   30,   27,   33,   29,
+       38,   28,   50,   34,   39,   25,   31,   32,   41,   28,
+       28,   26,   28,   27,   50,   42,   42,   28,   28,   43,
+       44,   28,   50,   41,   50,   45,   28,   28,   60,   50,
+       50,   50,   50,   50,   59,   50,   28,   58,   57,   56,
+       55,   43,   43,   54,   53,   52,   50,   51,   50,   49,
+       48,   47,   46,   24,   40,   37,   36,   35,   25,   24,
+
+       61,    3,   61,   61,   61,   61,   61,   61,   61,   61,
+       61,   61,   61,   61,   61,   61,   61,   61,   61,   61,
+       61,   61,   61,   61,   61,   61,   61,   61,   61,   61,
+       61,   61,   61,   61,   61,   61,   61
+    } ;
+
+static yyconst short int yy_chk[138] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,   14,   15,   14,   17,   62,
+       21,   14,   60,   17,   21,   25,   15,   15,   26,   25,
+       14,   27,   26,   27,   59,   28,   28,   27,   25,   28,
+       30,   26,   58,   41,   57,   30,   27,   41,   56,   55,
+       54,   53,   52,   51,   49,   48,   41,   47,   46,   45,
+       44,   43,   42,   40,   39,   38,   37,   36,   35,   34,
+       33,   32,   31,   24,   22,   20,   19,   18,   12,    5,
+
+        3,   61,   61,   61,   61,   61,   61,   61,   61,   61,
+       61,   61,   61,   61,   61,   61,   61,   61,   61,   61,
+       61,   61,   61,   61,   61,   61,   61,   61,   61,   61,
+       61,   61,   61,   61,   61,   61,   61
+    } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "scanner.l"
+#define INITIAL 0
+#line 2 "scanner.l"
+/*
+ * Copyright (C) 1999, 2002, 2003  Free Software Foundation, Inc.
+ * 
+ * This file is part of GNU libmatheval
+ *
+ * GNU libmatheval is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU libmatheval is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+/* This file was modified for inclusion in Gmsh */
+
+#include "common.h"
+#include "node.h"
+#include "parser.h"
+#include "symbol_table.h"
+
+/* Redefine macro to redirect scanner input from string instead of
+   standard input.  */
+#define YY_INPUT( buffer, result, max_size ) \
+{ result = input_from_string (buffer, max_size); }
+
+/* Variables used to communicate with code using scanner.  */
+extern SymbolTable *matheval_symbol_table; /* Evaluator symbol table.  */
+extern char *matheval_input_string; /* String representing function.  */
+
+/* Read next max_size character from string into buffer.  */
+static int input_from_string (char *buffer, int max_size);
+/* Token definitions.  */
+#line 472 "scanner.cpp"
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap YY_PROTO(( void ));
+#else
+extern int yywrap YY_PROTO(( void ));
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+static void yyunput YY_PROTO(( int c, char *buf_ptr ));
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen YY_PROTO(( yyconst char * ));
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput YY_PROTO(( void ));
+#else
+static int input YY_PROTO(( void ));
+#endif
+#endif
+
+#if YY_STACK_USED
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+#ifndef YY_NO_PUSH_STATE
+static void yy_push_state YY_PROTO(( int new_state ));
+#endif
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state YY_PROTO(( void ));
+#endif
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state YY_PROTO(( void ));
+#endif
+
+#else
+#define YY_NO_PUSH_STATE 1
+#define YY_NO_POP_STATE 1
+#define YY_NO_TOP_STATE 1
+#endif
+
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines.  This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( yy_current_buffer->yy_is_interactive ) \
+		{ \
+		int c = '*', n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( yyin ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \
+		  && ferror( yyin ) ) \
+		YY_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL int yylex YY_PROTO(( void ))
+#endif
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	YY_USER_ACTION
+
+YY_DECL
+	{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+
+#line 50 "scanner.l"
+
+
+#line 626 "scanner.cpp"
+
+	if ( yy_init )
+		{
+		yy_init = 0;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if ( ! yy_start )
+			yy_start = 1;	/* first start state */
+
+		if ( ! yyin )
+			yyin = stdin;
+
+		if ( ! yyout )
+			yyout = stdout;
+
+		if ( ! yy_current_buffer )
+			yy_current_buffer =
+				yy_create_buffer( yyin, YY_BUF_SIZE );
+
+		yy_load_buffer_state();
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		yy_cp = yy_c_buf_p;
+
+		/* Support of yytext. */
+		*yy_cp = yy_hold_char;
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = yy_start;
+yy_match:
+		do
+			{
+			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			if ( yy_accept[yy_current_state] )
+				{
+				yy_last_accepting_state = yy_current_state;
+				yy_last_accepting_cpos = yy_cp;
+				}
+			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+				{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if ( yy_current_state >= 62 )
+					yy_c = yy_meta[(unsigned int) yy_c];
+				}
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			++yy_cp;
+			}
+		while ( yy_base[yy_current_state] != 102 );
+
+yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+		if ( yy_act == 0 )
+			{ /* have to back up */
+			yy_cp = yy_last_accepting_cpos;
+			yy_current_state = yy_last_accepting_state;
+			yy_act = yy_accept[yy_current_state];
+			}
+
+		YY_DO_BEFORE_ACTION;
+
+
+do_action:	/* This label is used only to access EOF actions. */
+
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+			case 0: /* must back up */
+			/* undo the effects of YY_DO_BEFORE_ACTION */
+			*yy_cp = yy_hold_char;
+			yy_cp = yy_last_accepting_cpos;
+			yy_current_state = yy_last_accepting_state;
+			goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 52 "scanner.l"
+
+	YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 54 "scanner.l"
+{
+  /* Create node representing constant with appropriate value.  */
+  melval.node = node_create ('c', atof (metext));
+  return NUMBER;
+}
+	YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 60 "scanner.l"
+{
+  /* Find symbol table record corresponding to function name.  */
+  melval.record = symbol_table_lookup (matheval_symbol_table, metext);
+  return FUNCTION;
+}
+	YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 66 "scanner.l"
+{
+  Record *record; /* Symbol table record.  */
+  /* Inserty variable into symbol table.  */
+  record = symbol_table_insert (matheval_symbol_table, metext, 'v');
+  melval.node = node_create ('v', record);
+  return VARIABLE;
+}
+	YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 74 "scanner.l"
+{
+  return '+';
+}
+	YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 78 "scanner.l"
+{
+  return '-';
+}
+	YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 82 "scanner.l"
+{
+  return '*';
+}
+	YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 86 "scanner.l"
+{
+  return '/';
+}
+	YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 90 "scanner.l"
+{
+  return '^';
+}
+	YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 94 "scanner.l"
+{
+  return '(';
+}
+	YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 98 "scanner.l"
+{
+  return ')';
+}
+	YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 102 "scanner.l"
+{
+  return '\n';
+}
+	YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 106 "scanner.l"
+ECHO;
+	YY_BREAK
+#line 804 "scanner.cpp"
+case YY_STATE_EOF(INITIAL):
+	yyterminate();
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = yy_hold_char;
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed yyin at a new source and called
+			 * yylex().  If so, then we have to assure
+			 * consistency between yy_current_buffer and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			yy_n_chars = yy_current_buffer->yy_n_chars;
+			yy_current_buffer->yy_input_file = yyin;
+			yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state();
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+			yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++yy_c_buf_p;
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = yy_c_buf_p;
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer() )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				yy_did_buffer_switch_on_eof = 0;
+
+				if ( yywrap() )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * yytext, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				yy_c_buf_p =
+					yytext_ptr + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state();
+
+				yy_cp = yy_c_buf_p;
+				yy_bp = yytext_ptr + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				yy_c_buf_p =
+				&yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+				yy_current_state = yy_get_previous_state();
+
+				yy_cp = yy_c_buf_p;
+				yy_bp = yytext_ptr + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+	} /* end of yylex */
+
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+
+static int yy_get_next_buffer()
+	{
+	register char *dest = yy_current_buffer->yy_ch_buf;
+	register char *source = yytext_ptr;
+	register int number_to_move, i;
+	int ret_val;
+
+	if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( yy_current_buffer->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		yy_current_buffer->yy_n_chars = yy_n_chars = 0;
+
+	else
+		{
+		int num_to_read =
+			yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+			YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+			/* just a shorter name for the current buffer */
+			YY_BUFFER_STATE b = yy_current_buffer;
+
+			int yy_c_buf_p_offset =
+				(int) (yy_c_buf_p - b->yy_ch_buf);
+
+			if ( b->yy_is_our_buffer )
+				{
+				int new_size = b->yy_buf_size * 2;
+
+				if ( new_size <= 0 )
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/* Include room in for 2 EOB chars. */
+					yy_flex_realloc( (void *) b->yy_ch_buf,
+							 b->yy_buf_size + 2 );
+				}
+			else
+				/* Can't grow it, we don't own it. */
+				b->yy_ch_buf = 0;
+
+			if ( ! b->yy_ch_buf )
+				YY_FATAL_ERROR(
+				"fatal error - scanner input buffer overflow" );
+
+			yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = yy_current_buffer->yy_buf_size -
+						number_to_move - 1;
+#endif
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+			yy_n_chars, num_to_read );
+
+		yy_current_buffer->yy_n_chars = yy_n_chars;
+		}
+
+	if ( yy_n_chars == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			yyrestart( yyin );
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			yy_current_buffer->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	yy_n_chars += number_to_move;
+	yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+	yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+	yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+
+	return ret_val;
+	}
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+static yy_state_type yy_get_previous_state()
+	{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+
+	yy_current_state = yy_start;
+
+	for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+		{
+		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+		if ( yy_accept[yy_current_state] )
+			{
+			yy_last_accepting_state = yy_current_state;
+			yy_last_accepting_cpos = yy_cp;
+			}
+		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+			{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if ( yy_current_state >= 62 )
+				yy_c = yy_meta[(unsigned int) yy_c];
+			}
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+		}
+
+	return yy_current_state;
+	}
+
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+
+#ifdef YY_USE_PROTOS
+static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )
+#else
+static yy_state_type yy_try_NUL_trans( yy_current_state )
+yy_state_type yy_current_state;
+#endif
+	{
+	register int yy_is_jam;
+	register char *yy_cp = yy_c_buf_p;
+
+	register YY_CHAR yy_c = 1;
+	if ( yy_accept[yy_current_state] )
+		{
+		yy_last_accepting_state = yy_current_state;
+		yy_last_accepting_cpos = yy_cp;
+		}
+	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+		{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if ( yy_current_state >= 62 )
+			yy_c = yy_meta[(unsigned int) yy_c];
+		}
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_is_jam = (yy_current_state == 61);
+
+	return yy_is_jam ? 0 : yy_current_state;
+	}
+
+
+#ifndef YY_NO_UNPUT
+#ifdef YY_USE_PROTOS
+static void yyunput( int c, register char *yy_bp )
+#else
+static void yyunput( c, yy_bp )
+int c;
+register char *yy_bp;
+#endif
+	{
+	register char *yy_cp = yy_c_buf_p;
+
+	/* undo effects of setting up yytext */
+	*yy_cp = yy_hold_char;
+
+	if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+		{ /* need to shift things up to make room */
+		/* +2 for EOB chars. */
+		register int number_to_move = yy_n_chars + 2;
+		register char *dest = &yy_current_buffer->yy_ch_buf[
+					yy_current_buffer->yy_buf_size + 2];
+		register char *source =
+				&yy_current_buffer->yy_ch_buf[number_to_move];
+
+		while ( source > yy_current_buffer->yy_ch_buf )
+			*--dest = *--source;
+
+		yy_cp += (int) (dest - source);
+		yy_bp += (int) (dest - source);
+		yy_current_buffer->yy_n_chars =
+			yy_n_chars = yy_current_buffer->yy_buf_size;
+
+		if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+			YY_FATAL_ERROR( "flex scanner push-back overflow" );
+		}
+
+	*--yy_cp = (char) c;
+
+
+	yytext_ptr = yy_bp;
+	yy_hold_char = *yy_cp;
+	yy_c_buf_p = yy_cp;
+	}
+#endif	/* ifndef YY_NO_UNPUT */
+
+
+#ifdef __cplusplus
+static int yyinput()
+#else
+static int input()
+#endif
+	{
+	int c;
+
+	*yy_c_buf_p = yy_hold_char;
+
+	if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+			/* This was really a NUL. */
+			*yy_c_buf_p = '\0';
+
+		else
+			{ /* need more input */
+			int offset = yy_c_buf_p - yytext_ptr;
+			++yy_c_buf_p;
+
+			switch ( yy_get_next_buffer() )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					yyrestart( yyin );
+
+					/* fall through */
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( yywrap() )
+						return EOF;
+
+					if ( ! yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput();
+#else
+					return input();
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					yy_c_buf_p = yytext_ptr + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) yy_c_buf_p;	/* cast for 8-bit char's */
+	*yy_c_buf_p = '\0';	/* preserve yytext */
+	yy_hold_char = *++yy_c_buf_p;
+
+
+	return c;
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yyrestart( FILE *input_file )
+#else
+void yyrestart( input_file )
+FILE *input_file;
+#endif
+	{
+	if ( ! yy_current_buffer )
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+
+	yy_init_buffer( yy_current_buffer, input_file );
+	yy_load_buffer_state();
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+#else
+void yy_switch_to_buffer( new_buffer )
+YY_BUFFER_STATE new_buffer;
+#endif
+	{
+	if ( yy_current_buffer == new_buffer )
+		return;
+
+	if ( yy_current_buffer )
+		{
+		/* Flush out information for old buffer. */
+		*yy_c_buf_p = yy_hold_char;
+		yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+		yy_current_buffer->yy_n_chars = yy_n_chars;
+		}
+
+	yy_current_buffer = new_buffer;
+	yy_load_buffer_state();
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (yywrap()) processing, but the only time this flag
+	 * is looked at is after yywrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	yy_did_buffer_switch_on_eof = 1;
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_load_buffer_state( void )
+#else
+void yy_load_buffer_state()
+#endif
+	{
+	yy_n_chars = yy_current_buffer->yy_n_chars;
+	yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+	yyin = yy_current_buffer->yy_input_file;
+	yy_hold_char = *yy_c_buf_p;
+	}
+
+
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
+#else
+YY_BUFFER_STATE yy_create_buffer( file, size )
+FILE *file;
+int size;
+#endif
+	{
+	YY_BUFFER_STATE b;
+
+	b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	yy_init_buffer( b, file );
+
+	return b;
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_delete_buffer( YY_BUFFER_STATE b )
+#else
+void yy_delete_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+	{
+	if ( ! b )
+		return;
+
+	if ( b == yy_current_buffer )
+		yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		yy_flex_free( (void *) b->yy_ch_buf );
+
+	yy_flex_free( (void *) b );
+	}
+
+
+#ifndef YY_ALWAYS_INTERACTIVE
+#ifndef YY_NEVER_INTERACTIVE
+extern int isatty YY_PROTO(( int ));
+#endif
+#endif
+
+#ifdef YY_USE_PROTOS
+void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
+#else
+void yy_init_buffer( b, file )
+YY_BUFFER_STATE b;
+FILE *file;
+#endif
+
+
+	{
+	yy_flush_buffer( b );
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+#if YY_ALWAYS_INTERACTIVE
+	b->yy_is_interactive = 1;
+#else
+#if YY_NEVER_INTERACTIVE
+	b->yy_is_interactive = 0;
+#else
+	b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+#endif
+#endif
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_flush_buffer( YY_BUFFER_STATE b )
+#else
+void yy_flush_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+
+	{
+	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == yy_current_buffer )
+		yy_load_buffer_state();
+	}
+
+
+#ifndef YY_NO_SCAN_BUFFER
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )
+#else
+YY_BUFFER_STATE yy_scan_buffer( base, size )
+char *base;
+yy_size_t size;
+#endif
+	{
+	YY_BUFFER_STATE b;
+
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return 0;
+
+	b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	yy_switch_to_buffer( b );
+
+	return b;
+	}
+#endif
+
+
+#ifndef YY_NO_SCAN_STRING
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )
+#else
+YY_BUFFER_STATE yy_scan_string( yy_str )
+yyconst char *yy_str;
+#endif
+	{
+	int len;
+	for ( len = 0; yy_str[len]; ++len )
+		;
+
+	return yy_scan_bytes( yy_str, len );
+	}
+#endif
+
+
+#ifndef YY_NO_SCAN_BYTES
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )
+#else
+YY_BUFFER_STATE yy_scan_bytes( bytes, len )
+yyconst char *bytes;
+int len;
+#endif
+	{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n;
+	int i;
+
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = len + 2;
+	buf = (char *) yy_flex_alloc( n );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+	for ( i = 0; i < len; ++i )
+		buf[i] = bytes[i];
+
+	buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = yy_scan_buffer( buf, n );
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+	}
+#endif
+
+
+#ifndef YY_NO_PUSH_STATE
+#ifdef YY_USE_PROTOS
+static void yy_push_state( int new_state )
+#else
+static void yy_push_state( new_state )
+int new_state;
+#endif
+	{
+	if ( yy_start_stack_ptr >= yy_start_stack_depth )
+		{
+		yy_size_t new_size;
+
+		yy_start_stack_depth += YY_START_STACK_INCR;
+		new_size = yy_start_stack_depth * sizeof( int );
+
+		if ( ! yy_start_stack )
+			yy_start_stack = (int *) yy_flex_alloc( new_size );
+
+		else
+			yy_start_stack = (int *) yy_flex_realloc(
+					(void *) yy_start_stack, new_size );
+
+		if ( ! yy_start_stack )
+			YY_FATAL_ERROR(
+			"out of memory expanding start-condition stack" );
+		}
+
+	yy_start_stack[yy_start_stack_ptr++] = YY_START;
+
+	BEGIN(new_state);
+	}
+#endif
+
+
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state()
+	{
+	if ( --yy_start_stack_ptr < 0 )
+		YY_FATAL_ERROR( "start-condition stack underflow" );
+
+	BEGIN(yy_start_stack[yy_start_stack_ptr]);
+	}
+#endif
+
+
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state()
+	{
+	return yy_start_stack[yy_start_stack_ptr - 1];
+	}
+#endif
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+#ifdef YY_USE_PROTOS
+static void yy_fatal_error( yyconst char msg[] )
+#else
+static void yy_fatal_error( msg )
+char msg[];
+#endif
+	{
+	(void) fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+	}
+
+
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+		yytext[yyleng] = yy_hold_char; \
+		yy_c_buf_p = yytext + n; \
+		yy_hold_char = *yy_c_buf_p; \
+		*yy_c_buf_p = '\0'; \
+		yyleng = n; \
+		} \
+	while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef yytext_ptr
+#ifdef YY_USE_PROTOS
+static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )
+#else
+static void yy_flex_strncpy( s1, s2, n )
+char *s1;
+yyconst char *s2;
+int n;
+#endif
+	{
+	register int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+	}
+#endif
+
+#ifdef YY_NEED_STRLEN
+#ifdef YY_USE_PROTOS
+static int yy_flex_strlen( yyconst char *s )
+#else
+static int yy_flex_strlen( s )
+yyconst char *s;
+#endif
+	{
+	register int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+	}
+#endif
+
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_alloc( yy_size_t size )
+#else
+static void *yy_flex_alloc( size )
+yy_size_t size;
+#endif
+	{
+	return (void *) malloc( size );
+	}
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_realloc( void *ptr, yy_size_t size )
+#else
+static void *yy_flex_realloc( ptr, size )
+void *ptr;
+yy_size_t size;
+#endif
+	{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+	}
+
+#ifdef YY_USE_PROTOS
+static void yy_flex_free( void *ptr )
+#else
+static void yy_flex_free( ptr )
+void *ptr;
+#endif
+	{
+	free( ptr );
+	}
+
+#if YY_MAIN
+int main()
+	{
+	yylex();
+	return 0;
+	}
+#endif
+#line 106 "scanner.l"
+
+
+#undef mewrap
+
+int mewrap() {return 1;}
+
+static int input_from_string (char *buffer, int max_size)
+{
+  int count; /* Count of characters to copy from input string to buffer.  */
+
+  /* Calculate count of characters to copy.  */
+  count = strlen (matheval_input_string);
+  if (count > max_size)
+    count = max_size;
+
+  /* Perform copy operation and update input string.  */
+  memcpy(buffer, matheval_input_string, count);
+  matheval_input_string += count;
+
+  return count;
+}
diff --git a/MathEval/symbol_table.cpp b/MathEval/symbol_table.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c8081786ad2c0edfc19888713a23ba32de9317f9
--- /dev/null
+++ b/MathEval/symbol_table.cpp
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 1999, 2002, 2003  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU libmatheval
+ *
+ * GNU libmatheval is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2, or (at your option) any later
+ * version.
+ *
+ * GNU libmatheval is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* This file was modified for inclusion in Gmsh */
+
+#include <assert.h>
+#include <stdarg.h>
+
+#include "common.h"
+#include "symbol_table.h"
+#include "xmath.h"
+
+/*
+ * Type definition for function accepting single argument of double type and
+ * returning double value.
+ */
+typedef double  (*function_type) (double);
+
+/* Calculate hash value for given name and hash table length.  */
+static int      hash(char *name, int length);
+
+SymbolTable *
+symbol_table_create(int length)
+{
+  SymbolTable    *symbol_table;	/* Pointer to symbol table.  */
+  static char    *names[] = {"Exp", "Log", "Sqrt", "Sin", "Cos", "Tan", "Ctan", 
+			     "Asin", "Acos", "Atan", "Actan", "Sinh", "Cosh", "Tanh",
+			     "Ctanh", "Asinh", "Acosh", "Atanh", "Actanh", "Fabs" };
+  static double   (*functions[]) (double) = { exp, log, sqrt, sin, cos, tan, ctan, 
+					      asin, acos, atan, actan, sinh, cosh, tanh, 
+					      ctanh, asinh, acosh, atanh, actanh, fabs};
+  unsigned int i;
+  
+  /*
+   * Allocate memory for symbol table data structure as well as for
+   * corresponding hash table.
+   */
+  symbol_table = XMALLOC(SymbolTable, 1);
+  symbol_table->length = length;
+  symbol_table->records = XCALLOC(Record, symbol_table->length);
+  
+  /*
+   * Insert predefined functions into symbol table.
+   */
+  for (i = 0; i < sizeof(names) / sizeof(names[0]); i++)
+    symbol_table_insert(symbol_table, names[i], 'f', functions[i]);
+  
+  /*
+   * Initialize symbol table reference count.
+   */
+  symbol_table->reference_count = 1;
+  
+  return symbol_table;
+}
+
+void
+symbol_table_destroy(SymbolTable * symbol_table)
+{
+  Record         *curr, *next; /* Pointers to current and next record
+				* while traversing hash table bucket.  */
+  int             i;
+
+  if(!symbol_table)
+    return;
+  
+  /*
+   * Decrement refernce count and return if symbol table still used
+   * elsewhere.
+   */
+  if (--symbol_table->reference_count > 0)
+    return;
+  
+  /*
+   * Delete hash table as well as data structure representing symbol
+   * table.
+   */
+  for (i = 0; i < symbol_table->length; i++)
+    for (curr = symbol_table->records[i].next; curr;) {
+      next = curr->next;
+      XFREE(curr->name);
+      XFREE(curr);
+      curr = next;
+    }
+  XFREE(symbol_table->records);
+  XFREE(symbol_table);
+}
+
+Record *
+symbol_table_insert(SymbolTable * symbol_table, char *name, char type,...)
+{
+  Record         *record;	/* Pointer to symbol table record
+				 * corresponding to name given.  */
+  va_list         ap;		/* Function variable argument list.  */
+  int             i;
+  
+  /*
+   * Check if symbol already in table and, if affirmative and record
+   * type same as type given, return corresponding record immediately.
+   */
+  if ((record = symbol_table_lookup(symbol_table, name))) {
+    assert(record->type == type);
+    return record;
+  }
+  /*
+   * Allocate memory for and initialize new record.
+   */
+  record = XMALLOC(Record, 1);
+  record->name = XMALLOC(char, strlen(name) + 1);
+  strcpy(record->name, name);
+  record->type = type;
+  
+  /*
+   * Parse function variable argument list to complete record
+   * initialization.
+   */
+  va_start(ap, type);
+  switch (record->type) {
+  case 'v':
+    record->data.value = 0;
+    break;
+    
+  case 'f':
+    record->data.function = va_arg(ap, function_type);
+    break;
+  }
+  va_end(ap);
+  
+  /*
+   * Calculate hash value and put record in corresponding hash table
+   * bucket.
+   */
+  i = hash(name, symbol_table->length);
+  record->next = symbol_table->records[i].next;
+  symbol_table->records[i].next = record;
+  
+  return record;
+}
+
+Record *
+symbol_table_lookup(SymbolTable * symbol_table, char *name)
+{
+  int             i;	/* Hash value. */
+  Record         *curr;	/* Pointer to current symbol table record.  */
+  
+  /*
+   * Calcuate hash value for name given.
+   */
+  i = hash(name, symbol_table->length);
+  
+  /*
+   * Lookup for name in hash table bucket corresponding to above hash
+   * value.
+   */
+  for (curr = symbol_table->records[i].next; curr; curr = curr->next)
+    if (!strcmp(curr->name, name))
+      return curr;
+  
+  return NULL;
+}
+
+SymbolTable *
+symbol_table_assign(SymbolTable * symbol_table)
+{
+  /*
+   * Increase symbol table reference count and return pointer to data
+   * structure representing table.
+   */
+  symbol_table->reference_count++;
+  return symbol_table;
+}
+
+/*
+ * Function below reused from A.V. Aho, R. Sethi, J.D. Ullman, "Compilers -
+ * Principle, Techniques, and Tools", Addison-Wesley, 1986, pp 435-437, and
+ * in turn from P.J. Weineberger's C compiler.
+ */
+static int
+hash(char *s, int n)
+{
+  char           *p;
+  unsigned        h, g;
+  
+  h = 0;
+  
+  for (p = s; *p; p++) {
+    h = (h << 4) + *p;
+    if ((g = h & 0xf0000000)) {
+      h = h ^ (g >> 24);
+      h = h ^ g;
+    }
+  }
+  
+  return h % n;
+}
diff --git a/MathEval/symbol_table.h b/MathEval/symbol_table.h
new file mode 100644
index 0000000000000000000000000000000000000000..0862c956efbd823a09bf79e7796f8d17ca1eab5a
--- /dev/null
+++ b/MathEval/symbol_table.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 1999, 2002, 2003  Free Software Foundation, Inc.
+ * 
+ * This file is part of GNU libmatheval
+ * 
+ * GNU libmatheval is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2, or (at your option) any later
+ * version.
+ * 
+ * GNU libmatheval is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* This file was modified for inclusion in Gmsh */
+
+#ifndef SYMBOL_TABLE_H
+#define SYMBOL_TABLE_H
+
+/* Data structure representing symbol table record.  */
+typedef struct _Record {
+  struct _Record *next;	/* Pointer to next record.  */
+  char *name; /* Symbol name.  */
+  char type; /* Symbol type ('v' for variable, 'f' for function).  */
+  union {
+    double value; /* Variable value.  */
+    double (*function) (double); /* Pointer to function to calculate
+				  * its value.  */
+  } data;
+} Record;
+
+/*
+ * Data structure representing symbol table (hash table is used for this
+ * purpose).
+ */
+typedef struct {
+  int length; /* Hash table length.  */
+  Record  *records; /* Hash table buckets.  */
+  int reference_count; /* Reference count for symbol table (evaluator
+			* for derivative uses same symbol table as
+			* evaluator for corresponding function).  */
+} SymbolTable;
+
+/* Create symbol table using specified length of hash table.  */
+SymbolTable *symbol_table_create(int length);
+
+/* Destroy symbol table.  */
+void symbol_table_destroy(SymbolTable * symbol_table);
+
+/*
+ * Insert symbol into given symbol table.  Further arguments are symbol name
+ * and its type, as well as additional arguments according to symbol type.
+ * Return value is pointer to symobl table record created to represent
+ * symbol.  If symbol already in symbol table, pointer to its record is
+ * returned immediately.
+ */
+Record *symbol_table_insert(SymbolTable * symbol_table, char *name, char type,...);
+
+/*
+ * Lookup symbol by name from given symbol table.  Pointer to symbol record
+ * is returned if symbol found, null pointer otherwise.
+ */
+Record *symbol_table_lookup(SymbolTable * symbol_table, char *name);
+
+/*
+ * Return symbol table pointer to be assigned to variable.  This function
+ * should be used instead of simple pointer assignement for proper reference
+ * counting.  Users willing to manage reference counts by themselves are free
+ * to ignore this functions.
+ */
+SymbolTable *symbol_table_assign(SymbolTable * symbol_table);
+
+#endif
diff --git a/MathEval/xmath.cpp b/MathEval/xmath.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cb72d782cb7f4a3fe522e0c11988f78cadb8d2ad
--- /dev/null
+++ b/MathEval/xmath.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 1999, 2002, 2003  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU libmatheval
+ *
+ * GNU libmatheval is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2, or (at your option) any later
+ * version.
+ *
+ * GNU libmatheval is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* This file was modified for inclusion in Gmsh */
+
+#include "xmath.h"
+
+double
+ctan(double x)
+{
+  /*
+   * Calculate cotangent value.
+   */
+  return 1 / tan(x);
+}
+
+double
+actan(double x)
+{
+  /*
+   * Calculate inverse cotangent value.
+   */
+  return atan(1 / x);
+}
+
+double
+ctanh(double x)
+{
+  /*
+   * Calculate hyperbolic cotangent value.
+   */
+  return 1 / tanh(x);
+}
+
+double
+asinh(double x)
+{
+  /*
+   * Calculate inverse hyperbolic sine value using relation between
+   * hyperbolic and exponential functions.
+   */
+  return log(x + sqrt(x * x + 1));
+}
+
+double
+acosh(double x)
+{
+  /*
+   * Calculate inverse hyperbolic cosine value using relation between
+   * hyperbolic and exponential functions.
+   */
+  return log(x + sqrt(x * x - 1));
+}
+
+double
+atanh(double x)
+{
+  /*
+   * Calculate inverse hyperbolic tangent value using relation between
+   * hyperbolic and exponential functions.
+   */
+  return 0.5 * log((1 + x) / (1 - x));
+}
+
+double
+actanh(double x)
+{
+  /*
+   * Calculate inverse hyperbolic cotangent value.
+   */
+  return atanh(1 / x);
+}
diff --git a/MathEval/xmath.h b/MathEval/xmath.h
new file mode 100644
index 0000000000000000000000000000000000000000..56ca98ed6d30771cdc0584ad5767c7976da82824
--- /dev/null
+++ b/MathEval/xmath.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 1999, 2002, 2003  Free Software Foundation, Inc.
+ * 
+ * This file is part of GNU libmatheval
+ * 
+ * GNU libmatheval is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2, or (at your option) any later
+ * version.
+ * 
+ * GNU libmatheval is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* This file was modified for inclusion in Gmsh */
+
+#ifndef XMATH_H
+#define XMATH_H
+
+#include <math.h>
+
+/* Calculate cotangent of value x.  */
+double ctan(double x);
+
+/* Calculate inverse cotangent of value x.  */
+double actan(double x);
+
+/* Calculate hyperbolical cotangent of value x.  */
+double ctanh(double x);
+
+/* Calculate inverse hyperbolical sine of value x.  */
+double asinh(double x);
+
+/* Calculate inverse hyperbolical cosine of value x.  */
+double acosh(double x);
+
+/* Calculate inverse hyperbolical tangent of value x.  */
+double atanh(double x);
+
+/* Calculate inverse hyperbolical cotangent of value x.  */
+double actanh(double x);
+
+#endif
diff --git a/Parser/Gmsh.tab.cpp b/Parser/Gmsh.tab.cpp
index 06c10ed8475291c71f04bf125789f50b1c5d63cc..0ccd3c0ddc6163628552c25650ffe37d9010b77a 100644
--- a/Parser/Gmsh.tab.cpp
+++ b/Parser/Gmsh.tab.cpp
@@ -191,7 +191,7 @@
 
 #line 1 "Gmsh.y"
 
-// $Id: Gmsh.tab.cpp,v 1.186 2004-04-19 07:42:24 geuzaine Exp $
+// $Id: Gmsh.tab.cpp,v 1.187 2004-05-12 02:02:21 geuzaine Exp $
 //
 // Copyright (C) 1997-2004 C. Geuzaine, J.-F. Remacle
 //
diff --git a/Parser/Gmsh.yy.cpp b/Parser/Gmsh.yy.cpp
index b38e70bb6eb6178b2148afab6912e8f936ac422a..c110ccc830863bb5dea69a921c88e02e039f14ed 100644
--- a/Parser/Gmsh.yy.cpp
+++ b/Parser/Gmsh.yy.cpp
@@ -2,7 +2,7 @@
 /* A lexical scanner generated by flex */
 
 /* Scanner skeleton version:
- * $Header: /cvsroot/gmsh/Parser/Gmsh.yy.cpp,v 1.185 2004-04-19 07:42:26 geuzaine Exp $
+ * $Header: /cvsroot/gmsh/Parser/Gmsh.yy.cpp,v 1.186 2004-05-12 02:02:29 geuzaine Exp $
  */
 
 #define FLEX_SCANNER
@@ -1014,7 +1014,7 @@ char *yytext;
 #line 1 "Gmsh.l"
 #define INITIAL 0
 #line 2 "Gmsh.l"
-// $Id: Gmsh.yy.cpp,v 1.185 2004-04-19 07:42:26 geuzaine Exp $
+// $Id: Gmsh.yy.cpp,v 1.186 2004-05-12 02:02:29 geuzaine Exp $
 //
 // Copyright (C) 1997-2004 C. Geuzaine, J.-F. Remacle
 //
diff --git a/Parser/Makefile b/Parser/Makefile
index 5666f5dc2d5f9cf3a7b90f20053f5efa05ec0f3e..127f7b662d0fbfaa7139c7610e04bf036cb410ff 100644
--- a/Parser/Makefile
+++ b/Parser/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.56 2004-04-18 03:36:07 geuzaine Exp $
+# $Id: Makefile,v 1.57 2004-05-12 02:02:30 geuzaine Exp $
 #
 # Copyright (C) 1997-2004 C. Geuzaine, J.-F. Remacle
 #
@@ -21,9 +21,6 @@
 
 include ../variables
 
-YACC = bison
-LEX = flex
-
 LIB     = ../lib/libGmshParser.a
 INCLUDE = -I../Common -I../DataStr -I../Geo -I../Graphics\
           -I../Mesh -I../Numeric -I../Fltk -I../Plugin -I../Parallel
@@ -46,8 +43,8 @@ ${LIB}: ${OBJ}
 	${CXX} ${CFLAGS} -c $<
 
 parser:
-	${YACC} --output Gmsh.tab.cpp -d Gmsh.y 
-	${LEX}  -oGmsh.yy.cpp Gmsh.l
+	bison --output Gmsh.tab.cpp -d Gmsh.y 
+	flex  -oGmsh.yy.cpp Gmsh.l
 	if [ -r Gmsh.tab.cpp.h ]; then mv Gmsh.tab.cpp.h Gmsh.tab.hpp ; fi
 
 clean:
diff --git a/Plugin/CutGrid.cpp b/Plugin/CutGrid.cpp
index 085596bf5ff33e4e550f9127bdf465dd93fbf094..d3d9d6110a6636bd4f190ed289b110389df608b1 100644
--- a/Plugin/CutGrid.cpp
+++ b/Plugin/CutGrid.cpp
@@ -1,4 +1,4 @@
-// $Id: CutGrid.cpp,v 1.5 2004-04-24 05:22:50 geuzaine Exp $
+// $Id: CutGrid.cpp,v 1.6 2004-05-12 02:02:30 geuzaine Exp $
 //
 // Copyright (C) 1997-2004 C. Geuzaine, J.-F. Remacle
 //
@@ -199,7 +199,7 @@ Post_View * GMSH_CutGridPlugin::GenerateView(Post_View * v) const
 
   char name[1024], filename[1024];
   sprintf(name, "%s_CutGrid", v->Name);
-  sprintf(filename, "%s_CutGrid", v->FileName);
+  sprintf(filename, "%s_CutGrid.pos", v->Name);
   EndView(View, v->NbTimeStep, filename, name);
 
   delete [] VALUES1;
diff --git a/Plugin/Makefile b/Plugin/Makefile
index 0c35362d7a17644e2dcaea75471880b4a30b501e..e999a9df117c28f16f66c7de1f0fbea94e7c163d 100644
--- a/Plugin/Makefile
+++ b/Plugin/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.46 2004-04-24 03:52:00 geuzaine Exp $
+# $Id: Makefile,v 1.47 2004-05-12 02:02:30 geuzaine Exp $
 #
 # Copyright (C) 1997-2004 C. Geuzaine, J.-F. Remacle
 #
@@ -23,7 +23,7 @@ include ../variables
 
 LIB     = ../lib/libGmshPlugin.a
 INCLUDE = -I../Common -I../Graphics -I../DataStr -I../Geo\
-            -I../Mesh -I../Numeric -I../Triangle
+            -I../Mesh -I../Numeric -I../Triangle -I../MathEval
 CFLAGS  = -DMPICH_SKIP_MPICXX ${OPTIM} ${FLAGS} ${INCLUDE}
 
 SRC = Plugin.cpp\
@@ -39,6 +39,7 @@ SRC = Plugin.cpp\
         Skin.cpp\
         Extract.cpp\
         DecomposeInSimplex.cpp\
+        Evaluate.cpp\
         Harmonic2Time.cpp
 
 OBJ = ${SRC:.cpp=.o}
@@ -69,7 +70,7 @@ Plugin.o: Plugin.cpp Plugin.h ../Common/Options.h ../Common/Message.h \
   PluginManager.h CutMap.h Levelset.h CutGrid.h StreamLines.h CutPlane.h \
   CutSphere.h Skin.h ../DataStr/Tree.h ../DataStr/avl.h Extract.h \
   Harmonic2Time.h DecomposeInSimplex.h Smooth.h Transform.h Triangulate.h \
-  SphericalRaise.h DisplacementRaise.h
+  SphericalRaise.h DisplacementRaise.h Evaluate.h
 Levelset.o: Levelset.cpp Levelset.h Plugin.h ../Common/Options.h \
   ../Common/Message.h ../Common/Views.h ../Common/ColorTable.h \
   ../DataStr/List.h DecomposeInSimplex.h ../DataStr/Tools.h \
@@ -130,6 +131,9 @@ DecomposeInSimplex.o: DecomposeInSimplex.cpp Plugin.h ../Common/Options.h \
   ../Common/Message.h ../Common/Views.h ../Common/ColorTable.h \
   ../DataStr/List.h DecomposeInSimplex.h ../DataStr/Tree.h \
   ../DataStr/avl.h ../Common/Context.h ../DataStr/Malloc.h
+Evaluate.o: Evaluate.cpp Plugin.h ../Common/Options.h ../Common/Message.h \
+  ../Common/Views.h ../Common/ColorTable.h ../DataStr/List.h Evaluate.h \
+  ../Common/Context.h ../Numeric/Numeric.h
 Harmonic2Time.o: Harmonic2Time.cpp Plugin.h ../Common/Options.h \
   ../Common/Message.h ../Common/Views.h ../Common/ColorTable.h \
   ../DataStr/List.h Harmonic2Time.h ../Common/Context.h \
diff --git a/Plugin/Plugin.cpp b/Plugin/Plugin.cpp
index 2431e2f578c0ed8a0164f2953bf56436cde6be4c..2ae0dc8b7b4d15cbbaa0ec75e26c2d25c12834a9 100644
--- a/Plugin/Plugin.cpp
+++ b/Plugin/Plugin.cpp
@@ -1,4 +1,4 @@
-// $Id: Plugin.cpp,v 1.50 2004-04-22 09:35:01 remacle Exp $
+// $Id: Plugin.cpp,v 1.51 2004-05-12 02:02:30 geuzaine Exp $
 //
 // Copyright (C) 1997-2004 C. Geuzaine, J.-F. Remacle
 //
@@ -46,6 +46,7 @@
 #include "Triangulate.h"
 #include "SphericalRaise.h"
 #include "DisplacementRaise.h"
+#include "Evaluate.h"
 
 using namespace std;
 
@@ -79,8 +80,6 @@ void GMSH_PluginManager::action(char *pluginName, char *action, void *data)
 
   if(!strcmp(action, "Run"))
     plugin->run();
-  else if(!strcmp(action, "Save"))
-    plugin->save();
   else
     throw "Unknown plugin action";
 }
@@ -93,12 +92,18 @@ void GMSH_PluginManager::setPluginOption(char *pluginName, char *option,
   if(!plugin)
     throw "Unknown plugin name";
 
-  if(!strcmp(option, "OutputFileName"))
-    strcpy(plugin->outputFileName, value);
-  else if(!strcmp(option, "InputFileName"))
-    strcpy(plugin->inputFileName, value);
-  else
-    throw "Unknown plugin option name";
+  for(int i = 0; i < plugin->getNbOptionsStr(); i++) {
+    StringXString *sxs;
+    // get the ith option of the plugin
+    sxs = plugin->getOptionStr(i);
+    // look if it's the good option name
+    if(!strcmp(sxs->str, option)) {
+      sxs->def = value;
+      return;
+    }
+  }
+
+  throw "Unknown plugin option name";
 }
 
 void GMSH_PluginManager::setPluginOption(char *pluginName, char *option,
@@ -163,6 +168,10 @@ void GMSH_PluginManager::registerDefaultPlugins()
 		    ("SphericalRaise", GMSH_RegisterSphericalRaisePlugin()));
   allPlugins.insert(std::pair < char *, GMSH_Plugin * >
 		    ("DisplacementRaise", GMSH_RegisterDisplacementRaisePlugin()));
+#if defined(HAVE_MATH_EVAL)
+  allPlugins.insert(std::pair < char *, GMSH_Plugin * >
+		    ("Evaluate", GMSH_RegisterEvaluatePlugin()));
+#endif
 
 #if defined(HAVE_FLTK)
   struct dirent **list;
diff --git a/Plugin/Plugin.h b/Plugin/Plugin.h
index f5eb1cc154eb9d5a5ffaecc080706bf846ed09fa..3cbd610a9a1081971eddbad618d24c9558049588 100644
--- a/Plugin/Plugin.h
+++ b/Plugin/Plugin.h
@@ -43,14 +43,9 @@ class PluginDialogBox;
 class GMSH_Plugin
 {
 public :
-  // output file name
-  char outputFileName[256];
-
-  //input file name
-  char inputFileName[256];
-
   // a dialog box for user interface
   PluginDialogBox *dialogBox;
+
   // this is there for internal use, this variable will be used by the
   // PluginManager, just forget it
   void *hlib;
@@ -71,10 +66,15 @@ public :
   // show the message and hopefully continue
   virtual void catchErrorMessage(char *errorMessage) const = 0;
 
-  // gmsh style option, ca be loaded, saved and set
+  // gmsh style numeric options
   virtual int getNbOptions() const = 0;
   virtual StringXNumber *getOption(int iopt) = 0;
-  virtual void save() = 0;
+
+  // gmsh style string options
+  virtual int getNbOptionsStr() const = 0;
+  virtual StringXString *getOptionStr(int iopt) = 0;
+
+  // run the plugin
   virtual void run() = 0;
 };
 
@@ -86,9 +86,8 @@ class GMSH_Post_Plugin : public GMSH_Plugin
 {
 public:
   inline GMSH_PLUGIN_TYPE getType() const { return GMSH_Plugin::GMSH_POST_PLUGIN; }
-  virtual void save(){
-    Msg(WARNING, "Plugin().Save is deprecated: use 'Save View[num]' instead");
-  }
+  virtual int getNbOptionsStr() const { return 0; };
+  virtual StringXString *getOptionStr(int iopt) { return NULL; };
   virtual void run(){ execute(0); }
   // If returned pointer is the same as the argument, then view is
   // simply modified, else, a new view is added in the view list
diff --git a/Plugin/StreamLines.cpp b/Plugin/StreamLines.cpp
index f36431784e710396642c5ea2ee5398e29eeb9cb9..a717787746da27ac9838a00f742b2d069543d336 100644
--- a/Plugin/StreamLines.cpp
+++ b/Plugin/StreamLines.cpp
@@ -1,4 +1,4 @@
-// $Id: StreamLines.cpp,v 1.5 2004-04-24 05:22:50 geuzaine Exp $
+// $Id: StreamLines.cpp,v 1.6 2004-05-12 02:02:30 geuzaine Exp $
 //
 // Copyright (C) 1997-2004 C. Geuzaine, J.-F. Remacle
 //
@@ -195,7 +195,7 @@ Post_View * GMSH_StreamLinesPlugin::GenerateView(Post_View * v) const
 
   char name[1024], filename[1024];
   sprintf(name, "%s_StreamLines", v->Name);
-  sprintf(filename, "%s_StreamLines", v->FileName);
+  sprintf(filename, "%s_StreamLines.pos", v->Name);
   EndView(View, 1, filename, name);
 
   return View;
diff --git a/configure b/configure
index 9bde675907e7b32e98eda5216d60501020a4938b..ce4c31df49d7e47d8b04b2c47d2d03a8cc57996c 100755
--- a/configure
+++ b/configure
@@ -852,6 +852,7 @@ Optional Features:
   --enable-system-menubar use the system menu bar on MacOS X (default=no)
   --enable-parallel       enable parallel version (default=no)
   --enable-triangle       compile Triangle if available (default=yes)
+  --enable-matheval       compile MathEval if available (default=yes)
   --enable-jpeg           enable JPEG support (default=yes)
   --enable-z              enable ZLIB support (default=yes)
   --enable-png            enable PNG support (default=yes)
@@ -1353,6 +1354,11 @@ fi;
 if test "${enable_triangle+set}" = set; then
   enableval="$enable_triangle"
 
+fi;
+# Check whether --enable-matheval or --disable-matheval was given.
+if test "${enable_matheval+set}" = set; then
+  enableval="$enable_matheval"
+
 fi;
 # Check whether --enable-jpeg or --disable-jpeg was given.
 if test "${enable_jpeg+set}" = set; then
@@ -3530,6 +3536,37 @@ else
   fi
 fi
 
+echo "$as_me:$LINENO: checking for ./MathEval/matheval.c" >&5
+echo $ECHO_N "checking for ./MathEval/matheval.c... $ECHO_C" >&6
+if test "${ac_cv_file___MathEval_matheval_c+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  test "$cross_compiling" = yes &&
+  { { echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5
+echo "$as_me: error: cannot check for file existence when cross compiling" >&2;}
+   { (exit 1); exit 1; }; }
+if test -r "./MathEval/matheval.c"; then
+  ac_cv_file___MathEval_matheval_c=yes
+else
+  ac_cv_file___MathEval_matheval_c=no
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_file___MathEval_matheval_c" >&5
+echo "${ECHO_T}$ac_cv_file___MathEval_matheval_c" >&6
+if test $ac_cv_file___MathEval_matheval_c = yes; then
+  MATHEVAL="yes"
+else
+  MATHEVAL="no"
+fi
+
+if test "x${MATHEVAL}" = "xyes"; then
+  if test "x$enable_matheval" != "xno"; then
+     GMSH_DIRS="${GMSH_DIRS} MathEval"
+     GMSH_LIBS="${GMSH_LIBS} -lGmshMathEval"
+     FLAGS="-DHAVE_MATH_EVAL ${FLAGS}"
+  fi
+fi
+
 if test "x$enable_gsl" != "xno"; then
   if test "x${GSL_PREFIX}" != "x"; then
     LDFLAGS="-L${GSL_PREFIX}/lib ${LDFLAGS}"
diff --git a/configure.in b/configure.in
index 1909dc0b429ce5175cc43688f668db0b644f9f2b..c56504112d566dc9703c7c8d0c976b5d1d3d68b1 100644
--- a/configure.in
+++ b/configure.in
@@ -1,4 +1,4 @@
-dnl $Id: configure.in,v 1.50 2004-03-05 01:21:06 geuzaine Exp $
+dnl $Id: configure.in,v 1.51 2004-05-12 02:02:20 geuzaine Exp $
 dnl
 dnl Copyright (C) 1997-2004 C. Geuzaine, J.-F. Remacle
 dnl
@@ -66,6 +66,9 @@ AC_ARG_ENABLE(parallel,
 AC_ARG_ENABLE(triangle,
               AC_HELP_STRING([--enable-triangle],
                              [compile Triangle if available (default=yes)]))
+AC_ARG_ENABLE(matheval,
+              AC_HELP_STRING([--enable-matheval],
+                             [compile MathEval if available (default=yes)]))
 AC_ARG_ENABLE(jpeg,
               AC_HELP_STRING([--enable-jpeg],
                              [enable JPEG support (default=yes)]))
@@ -240,6 +243,16 @@ else
   fi
 fi
 
+dnl Check for MathEval
+AC_CHECK_FILE(./MathEval/matheval.c, MATHEVAL="yes", MATHEVAL="no")
+if test "x${MATHEVAL}" = "xyes"; then
+  if test "x$enable_matheval" != "xno"; then
+     GMSH_DIRS="${GMSH_DIRS} MathEval"
+     GMSH_LIBS="${GMSH_LIBS} -lGmshMathEval"
+     FLAGS="-DHAVE_MATH_EVAL ${FLAGS}"
+  fi
+fi
+
 dnl Check for GSL
 if test "x$enable_gsl" != "xno"; then
   if test "x${GSL_PREFIX}" != "x"; then
diff --git a/doc/VERSIONS b/doc/VERSIONS
index 049af9b9b9bef2d6b5eaff17a9b0490a0ee8e363..683d9d30025f12e98bdb5cb814ba5050fd0efdf5 100644
--- a/doc/VERSIONS
+++ b/doc/VERSIONS
@@ -1,6 +1,7 @@
-$Id: VERSIONS,v 1.200 2004-05-07 18:42:49 geuzaine Exp $
+$Id: VERSIONS,v 1.201 2004-05-12 02:02:30 geuzaine Exp $
 
-New since 1.52: background mesh fixes; 
+New since 1.52: background mesh fixes; new Plugin(Evaluate) to
+evaluate arbitrary expressions on scalar post-processing views;
 
 New in 1.52: new raster ("bitmap") PostScript/EPS/PDF output formats;
 new Plugin(Extract) to extract a given component from a