getfem-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Getfem-commits] (no subject)


From: Yves Renard
Subject: [Getfem-commits] (no subject)
Date: Wed, 2 May 2018 09:59:00 -0400 (EDT)

branch: devel-yves-generic-assembly-modifs
commit ced932d32a5db7a54604e7438884354a199d6bd4
Author: Yves Renard <address@hidden>
Date:   Mon Apr 30 16:13:56 2018 +0200

    better error messages
---
 src/getfem/getfem_generic_assembly_semantic.h      |   2 +-
 src/getfem/getfem_generic_assembly_tree.h          |  52 ++--
 src/getfem_generic_assembly_compile_and_exec.cc    |   4 +-
 ...fem_generic_assembly_functions_and_operators.cc |   5 +-
 src/getfem_generic_assembly_interpolation.cc       |   3 +-
 src/getfem_generic_assembly_semantic.cc            | 279 +++++++++++----------
 src/getfem_generic_assembly_tree.cc                | 247 +++++++++---------
 src/getfem_generic_assembly_workspace.cc           |  18 +-
 src/getfem_models.cc                               |   6 +-
 9 files changed, 326 insertions(+), 290 deletions(-)

diff --git a/src/getfem/getfem_generic_assembly_semantic.h 
b/src/getfem/getfem_generic_assembly_semantic.h
index 78abcfe..a4426bb 100644
--- a/src/getfem/getfem_generic_assembly_semantic.h
+++ b/src/getfem/getfem_generic_assembly_semantic.h
@@ -55,7 +55,7 @@ namespace getfem {
               3 : do not complain about incompatible test functions neither
                   store them.
   */
-  void ga_semantic_analysis(const std::string &expr, ga_tree &tree,
+  void ga_semantic_analysis(ga_tree &tree,
                            const ga_workspace &workspace,
                            size_type meshdim,
                            size_type ref_elt_dim,
diff --git a/src/getfem/getfem_generic_assembly_tree.h 
b/src/getfem/getfem_generic_assembly_tree.h
index 36b6b88..2d05fdc 100644
--- a/src/getfem/getfem_generic_assembly_tree.h
+++ b/src/getfem/getfem_generic_assembly_tree.h
@@ -188,8 +188,9 @@ namespace getfem {
     GA_NODE_XFEM_MINUS_DIVERG_TEST,
     GA_NODE_ZERO};
 
+  typedef std::shared_ptr<std::string> pstring;
   // Print error message indicating the position in the assembly string
-  void ga_throw_error_msg(const std::string &expr, size_type pos,
+  void ga_throw_error_msg(pstring expr, size_type pos,
                          const std::string &msg);
 
 # define ga_throw_error(expr, pos, msg)               \
@@ -282,6 +283,7 @@ namespace getfem {
   struct ga_tree_node;
   typedef ga_tree_node *pga_tree_node;
 
+  
   struct ga_tree_node {
     GA_NODE_TYPE node_type;
     GA_TOKEN_TYPE op_type;
@@ -297,6 +299,7 @@ namespace getfem {
     size_type qdim1, qdim2;       // Qdims when test_function_type > 0.
     size_type nbc1, nbc2, nbc3;   // For explicit matrices, X and macros.
     size_type pos;                // Position of the first character in string
+    pstring expr;                 // Original string, for error messages.
     std::string name;             // variable/constant/function/operator name
     std::string interpolate_name; // For Interpolate : name of transformation
     std::string interpolate_name_der; // For Interpolate derivative:
@@ -335,8 +338,7 @@ namespace getfem {
     { return t.sizes()[nb_test_functions()+i]; }
 
 
-    void mult_test(const pga_tree_node n0, const pga_tree_node n1,
-                   const std::string &expr);
+    void mult_test(const pga_tree_node n0, const pga_tree_node n1);
 
     bool tensor_is_zero() {
       if (node_type == GA_NODE_ZERO) return true;
@@ -375,51 +377,43 @@ namespace getfem {
 
     ga_tree_node()
       : node_type(GA_NODE_VOID), test_function_type(-1), qdim1(0), qdim2(0),
-        nbc1(0), nbc2(0), nbc3(0), pos(0), der1(0), der2(0),
+      nbc1(0), nbc2(0), nbc3(0), pos(0), expr(0), der1(0), der2(0),
         symmetric_op(false), hash_value(0) {}
-    ga_tree_node(GA_NODE_TYPE ty, size_type p)
+  ga_tree_node(GA_NODE_TYPE ty, size_type p, pstring expr_)
       : node_type(ty), test_function_type(-1),
         qdim1(0), qdim2(0), nbc1(0), nbc2(0), nbc3(0),
-        pos(p), der1(0), der2(0), symmetric_op(false), hash_value(0) {}
-    ga_tree_node(scalar_type v, size_type p)
+      pos(p), expr(expr_), der1(0), der2(0), symmetric_op(false),
+      hash_value(0) {}
+    ga_tree_node(scalar_type v, size_type p, pstring expr_)
       : node_type(GA_NODE_CONSTANT), test_function_type(-1),
         qdim1(0), qdim2(0), nbc1(0), nbc2(0), nbc3(0),
-        pos(p), der1(0), der2(0), symmetric_op(false),
+        pos(p), expr(expr_), der1(0), der2(0), symmetric_op(false),
         hash_value(0)
     { init_scalar_tensor(v); }
-    ga_tree_node(const char *n, size_type l, size_type p)
+    ga_tree_node(const char *n, size_type l, size_type p, pstring expr_)
       : node_type(GA_NODE_NAME), test_function_type(-1),
         qdim1(0), qdim2(0), nbc1(0), nbc2(0), nbc3(0),
-        pos(p), name(n, l), der1(0), der2(0), symmetric_op(false),
+        pos(p), expr(expr_), name(n, l), der1(0), der2(0), symmetric_op(false),
         hash_value(0) {}
-    ga_tree_node(GA_TOKEN_TYPE op, size_type p)
+    ga_tree_node(GA_TOKEN_TYPE op, size_type p, pstring expr_)
       : node_type(GA_NODE_OP), op_type(op), test_function_type(-1),
         qdim1(0), qdim2(0), nbc1(0), nbc2(0), nbc3(0),
-        pos(p), der1(0), der2(0), symmetric_op(false),
+        pos(p), expr(expr_), der1(0), der2(0), symmetric_op(false),
         hash_value(0) {}
   };
 
-# define ga_valid_operand(expr, pnode)                        \
-  {                                                          \
-    if (pnode && (pnode->node_type == GA_NODE_PREDEF_FUNC ||  \
-                  pnode->node_type == GA_NODE_SPEC_FUNC ||    \
-                  pnode->node_type == GA_NODE_NAME ||        \
-                  pnode->node_type == GA_NODE_OPERATOR ||     \
-                  pnode->node_type == GA_NODE_ALLINDICES))    \
-      ga_throw_error(expr, pnode->pos, "Invalid term");              \
-  }
-
   struct ga_tree {
     pga_tree_node root, current_node;
 
-    void add_scalar(scalar_type val, size_type pos);
-    void add_allindices(size_type pos);
-    void add_name(const char *name, size_type length, size_type pos);
+    void add_scalar(scalar_type val, size_type pos, pstring expr);
+    void add_allindices(size_type pos, pstring expr);
+    void add_name(const char *name, size_type length, size_type pos,
+                 pstring expr);
     void add_sub_tree(ga_tree &sub_tree);
-    void add_params(size_type pos);
-    void add_matrix(size_type pos);
+    void add_params(size_type pos, pstring expr);
+    void add_matrix(size_type pos, pstring expr);
     void zip_matrix(const pga_tree_node source_node);
-    void add_op(GA_TOKEN_TYPE op_type, size_type pos);
+    void add_op(GA_TOKEN_TYPE op_type, size_type pos, pstring expr);
     void clear_node_rec(pga_tree_node pnode);
     void clear_node(pga_tree_node pnode);
     void clear() { clear_node_rec(root); root = current_node = nullptr; }
@@ -440,7 +434,7 @@ namespace getfem {
 
     ga_tree() : root(nullptr), current_node(nullptr) {}
 
-    ga_tree(const ga_tree &tree) : root(nullptr), current_node(nullptr)
+  ga_tree(const ga_tree &tree) : root(nullptr), current_node(nullptr)
     { if (tree.root) copy_node(tree.root, nullptr, root); }
 
     ga_tree &operator = (const ga_tree &tree)
diff --git a/src/getfem_generic_assembly_compile_and_exec.cc 
b/src/getfem_generic_assembly_compile_and_exec.cc
index 507db9e..a8b0900 100644
--- a/src/getfem_generic_assembly_compile_and_exec.cc
+++ b/src/getfem_generic_assembly_compile_and_exec.cc
@@ -5946,7 +5946,7 @@ namespace getfem {
         // Semantic analysis mainly to evaluate fixed size variables and data
         const mesh *m = td.m;
         GMM_ASSERT1(m, "Internal error");
-        ga_semantic_analysis("", gis.trees.back(), workspace, m->dim(),
+        ga_semantic_analysis(gis.trees.back(), workspace, m->dim(),
                              ref_elt_dim_of_mesh(*m), true, false);
         pga_tree_node root = gis.trees.back().root;
         if (root) {
@@ -5992,7 +5992,7 @@ namespace getfem {
           }
 
           // Semantic analysis mainly to evaluate fixed size variables and data
-          ga_semantic_analysis("", *added_tree, workspace,
+          ga_semantic_analysis(*added_tree, workspace,
                                td.mim->linked_mesh().dim(),
                                ref_elt_dim_of_mesh(td.mim->linked_mesh()),
                                true, false);
diff --git a/src/getfem_generic_assembly_functions_and_operators.cc 
b/src/getfem_generic_assembly_functions_and_operators.cc
index 36abf9b..2a65913 100644
--- a/src/getfem_generic_assembly_functions_and_operators.cc
+++ b/src/getfem_generic_assembly_functions_and_operators.cc
@@ -702,13 +702,12 @@ namespace getfem {
       ga_tree tree = *(local_workspace.tree_info(0).ptree);
       ga_derivative(tree, local_workspace, *((const mesh *)(0)), var, "", 1);
       if (tree.root) {
-        ga_semantic_analysis(expr, tree, local_workspace, 1, 1, false, true);
+        ga_semantic_analysis(tree, local_workspace, 1, 1, false, true);
         // To be improved to suppress test functions in the expression ...
         // ga_replace_test_by_cte do not work in all operations like
         // vector components x(1)
         // ga_replace_test_by_cte(tree.root, false);
-        // ga_semantic_analysis(expr, tree, local_workspace, 1, 1,
-        //                      false, true);
+        // ga_semantic_analysis(tree, local_workspace, 1, 1, false, true);
       }
       expr = ga_tree_to_string(tree);
     }
diff --git a/src/getfem_generic_assembly_interpolation.cc 
b/src/getfem_generic_assembly_interpolation.cc
index b6bde52..c0476be 100644
--- a/src/getfem_generic_assembly_interpolation.cc
+++ b/src/getfem_generic_assembly_interpolation.cc
@@ -568,8 +568,7 @@ namespace getfem {
           ga_derivative(tree, pwi.workspace(), source_mesh,
                         var.varname, var.transname, 1);
           if (tree.root)
-            ga_semantic_analysis(expr, tree, local_workspace, 1, 1,
-                                 false, true);
+            ga_semantic_analysis(tree, local_workspace, 1, 1, false, true);
           ga_compile_interpolation(pwi.workspace(), pwi.gis());
         }
       }
diff --git a/src/getfem_generic_assembly_semantic.cc 
b/src/getfem_generic_assembly_semantic.cc
index 0a589d0..740cc88 100644
--- a/src/getfem_generic_assembly_semantic.cc
+++ b/src/getfem_generic_assembly_semantic.cc
@@ -176,7 +176,17 @@ namespace getfem {
     return c;
   }
 
-  static void ga_node_analysis(const std::string &expr, ga_tree &tree,
+# define ga_valid_operand(pnode)                               \
+  {                                                            \
+    if (pnode && (pnode->node_type == GA_NODE_PREDEF_FUNC ||   \
+                  pnode->node_type == GA_NODE_SPEC_FUNC ||     \
+                  pnode->node_type == GA_NODE_NAME ||          \
+                  pnode->node_type == GA_NODE_OPERATOR ||      \
+                  pnode->node_type == GA_NODE_ALLINDICES))     \
+      ga_throw_error(pnode->expr, pnode->pos, "Invalid term"); \
+  }
+
+  static void ga_node_analysis(ga_tree &tree,
                                const ga_workspace &workspace,
                                pga_tree_node pnode, size_type meshdim,
                                size_type ref_elt_dim, bool eval_fixed_size,
@@ -185,14 +195,14 @@ namespace getfem {
     pnode->symmetric_op = false;
 
     for (size_type i = 0; i < pnode->children.size(); ++i) {
-      ga_node_analysis(expr, tree, workspace, pnode->children[i], meshdim,
+      ga_node_analysis(tree, workspace, pnode->children[i], meshdim,
                        ref_elt_dim, eval_fixed_size, ignore_X, option);
       all_cte = all_cte && (pnode->children[i]->node_type == GA_NODE_CONSTANT);
       all_sc = all_sc && (pnode->children[i]->tensor_proper_size() == 1);
       GMM_ASSERT1(pnode->children[i]->test_function_type != size_type(-1),
                   "internal error on child " << i);
       if (pnode->node_type != GA_NODE_PARAMS)
-        ga_valid_operand(expr, pnode->children[i]);
+        ga_valid_operand(pnode->children[i]);
     }
 
     size_type nbch = pnode->children.size();
@@ -270,7 +280,8 @@ namespace getfem {
               (var_trans_pair(pnode->name_test1,
                               pnode->interpolate_name_test1));
           if (!(pnode->qdim1))
-            ga_throw_error(expr, pnode->pos, "Invalid null size of variable");
+            ga_throw_error(pnode->expr, pnode->pos,
+                          "Invalid null size of variable");
         } else {
           pnode->interpolate_name_test1 = pnode->name_test1 = "";
           pnode->name_test2 = pnode->name;
@@ -282,12 +293,14 @@ namespace getfem {
               (var_trans_pair(pnode->name_test2,
                               pnode->interpolate_name_test2));
           if (!(pnode->qdim2))
-            ga_throw_error(expr, pnode->pos, "Invalid null size of variable");
+            ga_throw_error(pnode->expr, pnode->pos,
+                          "Invalid null size of variable");
         }
         if (!mf) {
           size_type n = workspace.qdim(pnode->name);
           if (!n)
-            ga_throw_error(expr, pnode->pos, "Invalid null size of variable");
+            ga_throw_error(pnode->expr, pnode->pos,
+                          "Invalid null size of variable");
           if (n == 1) {
             pnode->init_vector_tensor(1);
             pnode->tensor()[0] = scalar_type(1);
@@ -337,21 +350,21 @@ namespace getfem {
 
         // Group must be tested and it should be a fem variable
         if (!(workspace.variable_or_group_exists(name)))
-          ga_throw_error(expr, pnode->pos,
+          ga_throw_error(pnode->expr, pnode->pos,
                          "Unknown variable or group of variables");
 
         const mesh_fem *mf = workspace.associated_mf(name);
         if (!mf)
-          ga_throw_error(expr, pnode->pos, op__name
+          ga_throw_error(pnode->expr, pnode->pos, op__name
                          << " can only apply to finite element 
variables/data");
 
         size_type q = workspace.qdim(name), n = mf->linked_mesh().dim();
-        if (!q) ga_throw_error(expr, pnode->pos,
+        if (!q) ga_throw_error(pnode->expr, pnode->pos,
                                "Invalid null size of variable");
 
         bgeot::multi_index mii = workspace.qdims(name);
         if (mii.size() > 6)
-          ga_throw_error(expr, pnode->pos,
+          ga_throw_error(pnode->expr, pnode->pos,
                          "Tensor with too many dimensions. Limited to 6");
 
         if (test == 1) {
@@ -363,7 +376,7 @@ namespace getfem {
                               pnode->interpolate_name_test1));
           pnode->qdim1 = workspace.qdim(name);
           if (!(pnode->qdim1))
-            ga_throw_error(expr, pnode->pos,
+            ga_throw_error(pnode->expr, pnode->pos,
                            "Invalid null size of variable");
         } else if (test == 2) {
           pnode->name_test2 = name;
@@ -374,7 +387,7 @@ namespace getfem {
                               pnode->interpolate_name_test2));
           pnode->qdim2 = workspace.qdim(name);
           if (!(pnode->qdim2))
-            ga_throw_error(expr, pnode->pos,
+            ga_throw_error(pnode->expr, pnode->pos,
                            "Invalid null size of variable");
         }
 
@@ -463,7 +476,7 @@ namespace getfem {
           break;
         case 3: // divergence
           if (q != n)
-            ga_throw_error(expr, pnode->pos,
+            ga_throw_error(pnode->expr, pnode->pos,
                            "Divergence operator requires fem qdim ("
                            << q << ") to be equal to dim (" << n << ")");
           if (!test) {
@@ -495,13 +508,13 @@ namespace getfem {
         if (ndt == 1) {
           if (!(workspace.interpolate_transformation_exists
                 (pnode->interpolate_name)))  {
-            ga_throw_error(expr, pnode->pos,
+            ga_throw_error(pnode->expr, pnode->pos,
                            "Unknown interpolate transformation");
           }
         } else if (ndt == 2) {
           if (!(workspace.elementary_transformation_exists
                 (pnode->elementary_name))) {
-            ga_throw_error(expr, pnode->pos,
+            ga_throw_error(pnode->expr, pnode->pos,
                            "Unknown elementary transformation");
           }
         }
@@ -514,7 +527,7 @@ namespace getfem {
           bool valid = (child1->node_type == GA_NODE_CONSTANT);
           int n = valid ? int(round(child1->tensor()[0])) : -1;
           if (n < 0 || n > 100 || child1->tensor_order() > 0)
-            ga_throw_error(expr, pnode->pos, "The third argument of "
+            ga_throw_error(pnode->expr, pnode->pos, "The third argument of "
                            "Interpolate_filter should be a (small) "
                            "non-negative integer.");
           pnode->nbc1 = size_type(n);
@@ -522,7 +535,7 @@ namespace getfem {
         }
         if (!(workspace.interpolate_transformation_exists
               (pnode->interpolate_name)))
-          ga_throw_error(expr, pnode->pos,
+          ga_throw_error(pnode->expr, pnode->pos,
                          "Unknown interpolate transformation");
         pnode->t = child0->t;
         pnode->test_function_type = child0->test_function_type;
@@ -558,9 +571,9 @@ namespace getfem {
             if (size1[i] != 1) compatible = false;
 
           if (!compatible)
-            ga_throw_error(expr, pnode->pos, "Addition or subtraction of "
-                           "expressions of different sizes: "
-                           << size0 << " != " << size1);
+            ga_throw_error(pnode->expr, pnode->pos,
+                          "Addition or subtraction of expressions of "
+                          "different sizes: " << size0 << " != " << size1);
           if (child0->test_function_type || child1->test_function_type) {
             switch (option) {
             case 0: case 2:
@@ -579,8 +592,8 @@ namespace getfem {
 
           if (child0->test_function_type != child1->test_function_type ||
               (!compatible && option != 2))
-            ga_throw_error(expr, pnode->pos, "Addition or subtraction of "
-                           "incompatible test functions");
+            ga_throw_error(pnode->expr, pnode->pos, "Addition or subtraction "
+                          "of incompatible test functions");
           if (all_cte) {
             pnode->node_type = GA_NODE_CONSTANT;
             pnode->test_function_type = 0;
@@ -676,14 +689,14 @@ namespace getfem {
           }
 
           if (!compatible)
-            ga_throw_error(expr, pnode->pos,
+            ga_throw_error(pnode->expr, pnode->pos,
                            "Arguments of different sizes for .* or ./");
 
           if (pnode->op_type == GA_DOTDIV && child1->test_function_type)
-            ga_throw_error(expr, pnode->pos,
+            ga_throw_error(pnode->expr, pnode->pos,
                            "Division by test functions is not allowed");
 
-          pnode->mult_test(child0, child1, expr);
+          pnode->mult_test(child0, child1);
           mi = pnode->t.sizes();
           for (size_type i = 0; i < child0->tensor_order(); ++i)
             mi.push_back(child0->tensor_proper_size(i));
@@ -698,7 +711,7 @@ namespace getfem {
             } else {
               for (size_type i = 0; i < child0->tensor().size(); ++i) {
                 if (child1->tensor()[i] == scalar_type(0))
-                  ga_throw_error(expr, pnode->pos, "Division by zero.");
+                  ga_throw_error(pnode->expr, pnode->pos, "Division by zero.");
                 pnode->tensor()[i] = child0->tensor()[i] / child1->tensor()[i];
               }
             }
@@ -710,7 +723,7 @@ namespace getfem {
               tree.clear_children(pnode);
             }
             if (child1->tensor_is_zero() && pnode->op_type == GA_DOTDIV)
-              ga_throw_error(expr, pnode->pos, "Division by zero.");
+              ga_throw_error(pnode->expr, pnode->pos, "Division by zero.");
           }
         }
         break;
@@ -737,7 +750,7 @@ namespace getfem {
 
       case GA_QUOTE:
         if (dim0 > 2)
-          ga_throw_error(expr, pnode->pos, "Transpose operator is for "
+          ga_throw_error(pnode->expr, pnode->pos, "Transpose operator is for "
                          "vectors or matrices only.");
         mi = size0;
         if (child0->tensor_proper_size() == 1)
@@ -775,8 +788,8 @@ namespace getfem {
       case GA_SYM: case GA_SKEW:
         if (child0->tensor_proper_size() != 1 &&
             (dim0 != 2 || size0.back() != size0[size0.size()-2]))
-          ga_throw_error(expr, pnode->pos, "Sym and Skew operators are for "
-                         "square matrices only.");
+          ga_throw_error(pnode->expr, pnode->pos, "Sym and Skew operators are "
+                        "for square matrices only.");
         mi = size0;
         if (child0->tensor_proper_size() == 1) {
           if (pnode->op_type == GA_SYM)
@@ -826,7 +839,7 @@ namespace getfem {
 
           if ((dim0 != 2 && child0->tensor_proper_size() != 1) ||
               (dim0 == 2 && mi[mi.size()-2] != N))
-            ga_throw_error(expr, pnode->pos,
+            ga_throw_error(pnode->expr, pnode->pos,
                            "Trace operator is for square matrices only.");
 
           if (dim0 == 2) { mi.pop_back(); mi.pop_back(); }
@@ -864,7 +877,7 @@ namespace getfem {
 
           if ((dim0 != 2 && child0->tensor_proper_size() != 1) ||
               (dim0 == 2 && mi[mi.size()-2] != N))
-            ga_throw_error(expr, pnode->pos,
+            ga_throw_error(pnode->expr, pnode->pos,
                            "Deviator operator is for square matrices only.");
 
           if (child0->tensor_proper_size() == 1) {
@@ -932,16 +945,16 @@ namespace getfem {
 
       case GA_DOT:
         if (dim1 > 1)
-          ga_throw_error(expr, pnode->pos, "The second argument of the dot "
-                         "product has to be a vector.")
+          ga_throw_error(pnode->expr, pnode->pos, "The second argument of the "
+                        "dot product has to be a vector.")
         else {
           size_type s0 = dim0 == 0 ? 1 : size0.back();
           size_type s1 = dim1 == 0 ? 1 : size1.back();
-          if (s0 != s1) ga_throw_error(expr, pnode->pos, "Dot product "
+          if (s0 != s1) ga_throw_error(pnode->expr, pnode->pos, "Dot product "
                                        "of expressions of different sizes ("
                                        << s0 << " != " << s1 << ").");
           if (child0->tensor_order() <= 1) pnode->symmetric_op = true;
-          pnode->mult_test(child0, child1, expr);
+          pnode->mult_test(child0, child1);
           if (dim0 > 1) {
             mi = pnode->t.sizes();
             for (size_type i = 1; i < dim0; ++i)
@@ -971,7 +984,7 @@ namespace getfem {
 
       case GA_COLON:
         if (dim1 > 2)
-          ga_throw_error(expr, pnode->pos,
+          ga_throw_error(pnode->expr, pnode->pos,
                           "Frobenius product acts only on matrices.")
         else {
           size_type s00 = (dim0 == 0) ? 1
@@ -981,12 +994,12 @@ namespace getfem {
             : (dim1 == 1 ? size1.back() : size1[size1.size()-2]);
           size_type s11 = (dim1 >= 2) ? size1.back() : 1;
           if (s00 != s10 || s01 != s11)
-            ga_throw_error(expr, pnode->pos, "Frobenius product "
+            ga_throw_error(pnode->expr, pnode->pos, "Frobenius product "
                            "of expressions of different sizes ("
                            << s00 << "," << s01 << " != " << s10 << ","
                            << s11 << ").");
           if (child0->tensor_order() <= 2) pnode->symmetric_op = true;
-          pnode->mult_test(child0, child1, expr);
+          pnode->mult_test(child0, child1);
           if (dim0 > 2) {
             mi = pnode->t.sizes();
             for (size_type i = 2; i < dim0; ++i)
@@ -1030,7 +1043,7 @@ namespace getfem {
                        scalar_type(child1->tensor()[0]));
           } else {
             if (dim0+dim1 > 6)
-              ga_throw_error(expr, pnode->pos, "Unauthorized "
+              ga_throw_error(pnode->expr, pnode->pos, "Unauthorized "
                               "tensor multiplication.");
             for (size_type i = 0; i < dim0; ++i)
               mi.push_back(child0->tensor().size(i));
@@ -1045,7 +1058,7 @@ namespace getfem {
           }
           tree.clear_children(pnode);
         } else {
-          pnode->mult_test(child0, child1, expr);
+          pnode->mult_test(child0, child1);
           mi = pnode->t.sizes();
           if (child0->tensor_proper_size() != 1
               || child1->tensor_proper_size() != 1) {
@@ -1057,7 +1070,7 @@ namespace getfem {
                 mi.push_back(child0->tensor_proper_size(i));
             } else {
               if (dim0+dim1 > 6)
-                ga_throw_error(expr, pnode->pos, "Unauthorized "
+                ga_throw_error(pnode->expr, pnode->pos, "Unauthorized "
                                 "tensor multiplication.");
               for (size_type i = 0; i < dim0; ++i)
                 mi.push_back(child0->tensor_proper_size(i));
@@ -1090,7 +1103,7 @@ namespace getfem {
           } else if (dim0 == 2 && dim1 == 1) {
             size_type m=child0->tensor().size(0), n=child0->tensor().size(1);
             if (n != child1->tensor().size(0))
-              ga_throw_error(expr, pnode->pos,
+              ga_throw_error(pnode->expr, pnode->pos,
                              "Incompatible sizes in matrix-vector "
                              "multiplication (" << n << " != "
                              << child1->tensor().size(0) << ").");
@@ -1104,7 +1117,7 @@ namespace getfem {
             size_type n = child0->tensor().size(1);
             size_type p = child1->tensor().size(1);
             if (n != child1->tensor().size(0))
-              ga_throw_error(expr, pnode->pos,
+              ga_throw_error(pnode->expr, pnode->pos,
                              "Incompatible sizes in matrix-matrix "
                              "multiplication (" << n << " != "
                              << child1->tensor().size(0) << ").");
@@ -1120,7 +1133,7 @@ namespace getfem {
             size_type m=child0->tensor().size(0), n=child0->tensor().size(1);
             size_type o=child0->tensor().size(2), p=child0->tensor().size(3);
             if (o != child1->tensor().size(0) || p != child1->tensor().size(1))
-              ga_throw_error(expr, pnode->pos,
+              ga_throw_error(pnode->expr, pnode->pos,
                              "Incompatible sizes in tensor-matrix "
                              "multiplication (" << o << "," << p << " != "
                              << child1->tensor().size(0) << ","
@@ -1133,11 +1146,11 @@ namespace getfem {
                   for (size_type l = 0; l < p; ++l)
                     pnode->tensor()(i,j) += child0->tensor()(i,j,k,l)
                                             * child1->tensor()(k,l);
-          } else ga_throw_error(expr, pnode->pos,
+          } else ga_throw_error(pnode->expr, pnode->pos,
                                  "Unauthorized multiplication.");
           tree.clear_children(pnode);
         } else {
-          pnode->mult_test(child0, child1, expr);
+          pnode->mult_test(child0, child1);
           mi = pnode->t.sizes();
 
           if (child0->tensor_proper_size() == 1 &&
@@ -1157,7 +1170,7 @@ namespace getfem {
             size_type n = child0->tensor_proper_size(1);
             mi.push_back(m);
             if (n != child1->tensor_proper_size(0))
-              ga_throw_error(expr, pnode->pos,
+              ga_throw_error(pnode->expr, pnode->pos,
                              "Incompatible sizes in matrix-vector "
                              "multiplication (" << n << " != "
                              << child1->tensor_proper_size(0) << ").");
@@ -1168,7 +1181,7 @@ namespace getfem {
             size_type p = child1->tensor_proper_size(1);
             mi.push_back(m); mi.push_back(p);
             if (n != child1->tensor_proper_size(0))
-              ga_throw_error(expr, pnode->pos,
+              ga_throw_error(pnode->expr, pnode->pos,
                              "Incompatible sizes in matrix-matrix "
                              "multiplication (" << n << " != "
                              << child1->tensor_proper_size(0) << ").");
@@ -1182,12 +1195,12 @@ namespace getfem {
             mi.push_back(m); mi.push_back(n);
             if (o != child1->tensor_proper_size(0) ||
                 p != child1->tensor_proper_size(1))
-              ga_throw_error(expr, pnode->pos,
+              ga_throw_error(pnode->expr, pnode->pos,
                              "Incompatible sizes in tensor-matrix "
                              "multiplication (" << o << "," << p << " != "
                              << child1->tensor_proper_size(0) << ","
                              << child1->tensor_proper_size(1) << ").");
-          } else ga_throw_error(expr, pnode->pos,
+          } else ga_throw_error(pnode->expr, pnode->pos,
                                 "Unauthorized multiplication.");
           pnode->t.adjust_sizes(mi);
           // Simplifications
@@ -1211,15 +1224,16 @@ namespace getfem {
 
       case GA_DIV:
         if (child1->tensor_proper_size() > 1)
-          ga_throw_error(expr, pnode->pos,
+          ga_throw_error(pnode->expr, pnode->pos,
                          "Only the division by a scalar is allowed. "
                          "Got a size of " << child1->tensor_proper_size());
         if (child1->test_function_type)
-          ga_throw_error(expr, pnode->pos,
+          ga_throw_error(pnode->expr, pnode->pos,
                          "Division by test functions is not allowed.");
         if (child1->node_type == GA_NODE_CONSTANT &&
             child1->tensor()[0] == scalar_type(0))
-          ga_throw_error(expr, pnode->children[1]->pos, "Division by zero");
+          ga_throw_error(pnode->expr, pnode->children[1]->pos,
+                        "Division by zero");
 
         pnode->t = child0->t;
         pnode->test_function_type = child0->test_function_type;
@@ -1256,7 +1270,8 @@ namespace getfem {
     case GA_NODE_C_MATRIX:
       {
         if (!all_sc) {
-          ga_throw_error(expr, pnode->pos, "Constant vector/matrix/tensor "
+          ga_throw_error(pnode->expr, pnode->pos,
+                        "Constant vector/matrix/tensor "
                          "components should be scalar valued.");
         }
 
@@ -1285,8 +1300,8 @@ namespace getfem {
                   (pnode->children[i]->interpolate_name_test1) ||
                   pnode->interpolate_name_test2.compare
                   (pnode->children[i]->interpolate_name_test2))
-                ga_throw_error(expr, pnode->pos, "Inconsistent use of test "
-                               "function in constant matrix.");
+                ga_throw_error(pnode->expr, pnode->pos, "Inconsistent use of "
+                              "test function in constant matrix.");
             }
           }
         }
@@ -1389,7 +1404,7 @@ namespace getfem {
               name = name.substr(s+1);
           }
           if (!valid || pnode->der1 == 0)
-            ga_throw_error(expr, pnode->pos, "Invalid derivative format");
+            ga_throw_error(pnode->expr, pnode->pos,"Invalid derivative 
format");
         }
 
         ga_predef_function_tab::const_iterator it=PREDEF_FUNCTIONS.find(name);
@@ -1401,7 +1416,7 @@ namespace getfem {
           if (pnode->der1) {
             if (pnode->der1 > it->second.nbargs()
                 || pnode->der2 > it->second.nbargs())
-              ga_throw_error(expr, pnode->pos, "Invalid derivative.");
+              ga_throw_error(pnode->expr, pnode->pos, "Invalid derivative.");
             const ga_predef_function &F = it->second;
             if ((F.ftype() == 0 || F.dtype() == 2) && !(pnode->der2)) {
               pnode->name = ((pnode->der1 == 1) ?
@@ -1412,7 +1427,7 @@ namespace getfem {
         } else if (SPEC_FUNCTIONS.find(name) != SPEC_FUNCTIONS.end()) {
           // Special function found
           if (pnode->der1)
-            ga_throw_error(expr, pnode->pos, "Special functions do not "
+            ga_throw_error(pnode->expr, pnode->pos, "Special functions do not "
                            "support derivatives.");
           pnode->node_type = GA_NODE_SPEC_FUNC;
           pnode->name = name;
@@ -1441,12 +1456,13 @@ namespace getfem {
           size_type test = ga_parse_prefix_test(name);
 
           if (!(workspace.variable_exists(name)))
-            ga_throw_error(expr, pnode->pos, "Unknown variable, function, "
-                           "operator or data " + name);
+            ga_throw_error(pnode->expr, pnode->pos, "Unknown variable, "
+                          "function, operator or data " + name);
 
           if (pnode->der1)
-            ga_throw_error(expr, pnode->pos, "Derivative is for functions or "
-                           "operators, not for variables. Use Grad instead.");
+            ga_throw_error(pnode->expr, pnode->pos, "Derivative is for "
+                          "functions or operators, not for variables. "
+                          "Use Grad instead.");
           pnode->name = name;
 
           const mesh_fem *mf = workspace.associated_mf(name);
@@ -1454,8 +1470,8 @@ namespace getfem {
 
           if (test && workspace.is_constant(name) &&
               !(workspace.is_disabled_variable(name)))
-            ga_throw_error(expr, pnode->pos, "Test functions of constants "
-                           "are not allowed.");
+            ga_throw_error(pnode->expr, pnode->pos, "Test functions of "
+                          "constants are not allowed.");
           if (test == 1) {
             pnode->name_test1 = name;
             pnode->interpolate_name_test1 = "";
@@ -1466,7 +1482,7 @@ namespace getfem {
             pnode->qdim1 = mf ? workspace.qdim(name)
                               : gmm::vect_size(workspace.value(name));
             if (!(pnode->qdim1))
-              ga_throw_error(expr, pnode->pos,
+              ga_throw_error(pnode->expr, pnode->pos,
                              "Invalid null size of variable");
           } else if (test == 2) {
             pnode->name_test2 = name;
@@ -1478,14 +1494,14 @@ namespace getfem {
             pnode->qdim2 = mf ? workspace.qdim(name)
                               : gmm::vect_size(workspace.value(name));
             if (!(pnode->qdim2))
-              ga_throw_error(expr, pnode->pos,
+              ga_throw_error(pnode->expr, pnode->pos,
                              "Invalid null size of variable");
           }
 
           if (!mf && (test || !imd)) {
             if (prefix_id)
-              ga_throw_error(expr, pnode->pos, "Gradient, Hessian or 
Divergence"
-                             " cannot be evaluated for fixed size data.");
+              ga_throw_error(pnode->expr, pnode->pos, "Gradient, Hessian or "
+                       "Divergence cannot be evaluated for fixed size data.");
             if (test)
               pnode->node_type = GA_NODE_VAL_TEST;
             else if (eval_fixed_size)
@@ -1514,8 +1530,8 @@ namespace getfem {
             }
           } else if (!test && imd) {
             if (prefix_id)
-              ga_throw_error(expr, pnode->pos, "Gradient, Hessian or 
Divergence"
-                              " cannot be evaluated for im data.");
+              ga_throw_error(pnode->expr, pnode->pos, "Gradient, Hessian or "
+                            "Divergence cannot be evaluated for im data.");
             pnode->node_type = GA_NODE_VAL;
             pnode->t.adjust_sizes(workspace.qdims(name));
           } else {
@@ -1523,10 +1539,10 @@ namespace getfem {
             size_type n = mf->linked_mesh().dim();
             bgeot::multi_index mii = workspace.qdims(name);
 
-            if (!q) ga_throw_error(expr, pnode->pos,
+            if (!q) ga_throw_error(pnode->expr, pnode->pos,
                                    "Invalid null size of variable " << name);
             if (mii.size() > 6)
-              ga_throw_error(expr, pnode->pos,
+              ga_throw_error(pnode->expr, pnode->pos,
                             "Tensor with too much dimensions. Limited to 6");
 
             switch (prefix_id) {
@@ -1574,7 +1590,7 @@ namespace getfem {
             case 3: // divergence
               pnode->node_type = test ? GA_NODE_DIVERG_TEST : GA_NODE_DIVERG;
               if (q != n)
-                ga_throw_error(expr, pnode->pos,
+                ga_throw_error(pnode->expr, pnode->pos,
                                "Divergence operator can only be applied to"
                                "Fields with qdim (" << q << ") equal to dim ("
                                << n << ")");
@@ -1593,15 +1609,16 @@ namespace getfem {
       if (child0->node_type == GA_NODE_X) {
         child0->init_scalar_tensor(0);
         if (pnode->children.size() != 2)
-          ga_throw_error(expr, child1->pos, "X stands for the coordinates on "
+          ga_throw_error(pnode->expr, child1->pos,
+                        "X stands for the coordinates on "
                          "the real elements. It accepts only one index.");
         if (!(child1->node_type == GA_NODE_CONSTANT) ||
             child1->tensor().size() != 1)
-          ga_throw_error(expr, child1->pos, "Index for X has to be constant "
-                         "and of size 1.");
+          ga_throw_error(pnode->expr, child1->pos,
+                        "Index for X has to be constant and of size 1.");
         child0->nbc1 = size_type(round(child1->tensor()[0]));
         if (child0->nbc1 == 0 || child0->nbc1 > meshdim)
-          ga_throw_error(expr, child1->pos, "Index for X not convenient. "
+          ga_throw_error(pnode->expr, child1->pos,"Index for X not convenient. 
"
                          "Found " << child0->nbc1 << " with meshdim = "
                          << meshdim);
         tree.replace_node_by_child(pnode, 0);
@@ -1609,10 +1626,10 @@ namespace getfem {
 
       } else if (child0->node_type == GA_NODE_RESHAPE) {
         if (pnode->children.size() < 3)
-          ga_throw_error(expr, child1->pos,
+          ga_throw_error(pnode->expr, child1->pos,
                          "Not enough parameters for Reshape");
         if (pnode->children.size() > 8)
-          ga_throw_error(expr, child1->pos,
+          ga_throw_error(pnode->expr, child1->pos,
                          "Too many parameters for Reshape");
         pnode->t = child1->t;
         pnode->test_function_type = child1->test_function_type;
@@ -1628,18 +1645,18 @@ namespace getfem {
 
         for (size_type i = 2; i < pnode->children.size(); ++i) {
           if (pnode->children[i]->node_type != GA_NODE_CONSTANT)
-            ga_throw_error(expr, pnode->children[i]->pos, "Reshape sizes "
+            ga_throw_error(pnode->expr, pnode->children[i]->pos,"Reshape sizes 
"
                            "should be constant positive integers.");
           mi.push_back(size_type(round(pnode->children[i]->tensor()[0])));
           if (mi.back() == 0)
-            ga_throw_error(expr, pnode->children[i]->pos, "Wrong zero size "
-                           "for Reshape.");
+            ga_throw_error(pnode->expr, pnode->children[i]->pos,
+                          "Wrong zero size for Reshape.");
         }
         size_type total_size(1);
         for (size_type i = 0; i < mi.size(); ++i)
           total_size *= mi[i];
         if (total_size != pnode->tensor().size())
-           ga_throw_error(expr, pnode->pos, "Invalid sizes for reshape.");
+           ga_throw_error(pnode->expr, pnode->pos,"Invalid sizes for 
reshape.");
         pnode->t.adjust_sizes(mi);
 
         if (child1->node_type == GA_NODE_CONSTANT) {
@@ -1654,14 +1671,14 @@ namespace getfem {
         // Evaluation of a predefined function
 
         for (size_type i = 1; i < pnode->children.size(); ++i)
-          ga_valid_operand(expr, pnode->children[i]);
+          ga_valid_operand(pnode->children[i]);
         std::string name = child0->name;
         ga_predef_function_tab::const_iterator it = 
PREDEF_FUNCTIONS.find(name);
         const ga_predef_function &F = it->second;
         size_type nbargs = F.nbargs();
         if (nbargs+1 != pnode->children.size()) {
-            ga_throw_error(expr, pnode->pos, "Bad number of arguments for "
-                "predefined function " << name << ". Found "
+            ga_throw_error(pnode->expr, pnode->pos, "Bad number of arguments "
+                "for predefined function " << name << ". Found "
                  << pnode->children.size()-1 << ", should be "<<nbargs << ".");
         }
         pnode->test_function_type = 0;
@@ -1670,15 +1687,15 @@ namespace getfem {
         if (nbargs == 2)
           all_cte = all_cte && (child2->node_type == GA_NODE_CONSTANT);
         if (child1->test_function_type || child2->test_function_type)
-          ga_throw_error(expr, pnode->pos, "Test functions cannot be passed "
-                         "as argument of a predefined function.");
+          ga_throw_error(pnode->expr, pnode->pos, "Test functions cannot be "
+                        "passed as argument of a predefined function.");
         if (child1->tensor_order() > 2 || child2->tensor_order() > 2)
-          ga_throw_error(expr, pnode->pos, "Sorry, function can be applied "
-                         "to scalar, vector and matrices only.");
+          ga_throw_error(pnode->expr, pnode->pos, "Sorry, function can be "
+                        "applied to scalar, vector and matrices only.");
         size_type s1 = child1->tensor().size();
         size_type s2 = (nbargs == 2) ? child2->tensor().size() : s1;
         if (s1 != s2 && (s1 != 1 || s2 != 1))
-          ga_throw_error(expr, pnode->pos,
+          ga_throw_error(pnode->expr, pnode->pos,
                          "Invalid argument size for a scalar function. "
                          "Size of first argument: " << s1 <<
                          ". Size of second argument: " << s2 << ".");
@@ -1724,32 +1741,32 @@ namespace getfem {
         // Special constant functions: meshdim, qdim(u) ...
 
         for (size_type i = 1; i < pnode->children.size(); ++i)
-          ga_valid_operand(expr, pnode->children[i]);
+          ga_valid_operand(pnode->children[i]);
         if (pnode->children.size() != 2)
-          ga_throw_error(expr, pnode->pos,
+          ga_throw_error(pnode->expr, pnode->pos,
                          "One and only one argument is allowed for function "
                          +child0->name+".");
 
         if (!(child0->name.compare("qdim"))) {
           if (child1->node_type != GA_NODE_VAL)
-            ga_throw_error(expr, pnode->pos, "The argument of qdim "
+            ga_throw_error(pnode->expr, pnode->pos, "The argument of qdim "
                            "function can only be a variable name.");
           pnode->node_type = GA_NODE_CONSTANT;
           pnode->init_scalar_tensor(scalar_type(workspace.qdim(child1->name)));
           if (pnode->tensor()[0] <= 0)
-            ga_throw_error(expr, pnode->pos,
+            ga_throw_error(pnode->expr, pnode->pos,
                            "Invalid null size of variable");
         } else if (!(child0->name.compare("qdims"))) {
           if (child1->node_type != GA_NODE_VAL)
-            ga_throw_error(expr, pnode->pos, "The argument of qdim "
+            ga_throw_error(pnode->expr, pnode->pos, "The argument of qdim "
                            "function can only be a variable name.");
           pnode->node_type = GA_NODE_CONSTANT;
           bgeot::multi_index mii = workspace.qdims(child1->name);
           if (mii.size() > 6)
-            ga_throw_error(expr, pnode->pos,
+            ga_throw_error(pnode->expr, pnode->pos,
                            "Tensor with too much dimensions. Limited to 6");
           if (mii.size() == 0 || scalar_type(mii[0]) <= 0)
-            ga_throw_error(expr, pnode->pos,
+            ga_throw_error(pnode->expr, pnode->pos,
                            "Invalid null size of variable");
           if (mii.size() == 1)
             pnode->init_scalar_tensor(scalar_type(mii[0]));
@@ -1762,7 +1779,7 @@ namespace getfem {
           bool valid = (child1->node_type == GA_NODE_CONSTANT);
           int n = valid ? int(round(child1->tensor()[0])) : -1;
           if (n <= 0 || n > 100 || child1->tensor_order() > 0)
-            ga_throw_error(expr, pnode->pos, "The argument of Id "
+            ga_throw_error(pnode->expr, pnode->pos, "The argument of Id "
                            "should be a (small) positive integer.");
           pnode->node_type = GA_NODE_CONSTANT;
           if (n == 1)
@@ -1771,7 +1788,7 @@ namespace getfem {
             pnode->init_matrix_tensor(n,n);
             for (int i = 0; i < n; ++i) pnode->tensor()(i,i) = scalar_type(1);
           }
-        } else ga_throw_error(expr, pnode->children[0]->pos,
+        } else ga_throw_error(pnode->expr, pnode->children[0]->pos,
                               "Unknown special function.");
         tree.clear_children(pnode);
       } else if (child0->node_type == GA_NODE_OPERATOR) {
@@ -1779,7 +1796,7 @@ namespace getfem {
         // Call to a nonlinear operator
 
         for (size_type i = 1; i < pnode->children.size(); ++i)
-          ga_valid_operand(expr, pnode->children[i]);
+          ga_valid_operand(pnode->children[i]);
         all_cte = true;
         ga_nonlinear_operator::arg_list args;
         for (size_type i = 1; i < pnode->children.size(); ++i) {
@@ -1787,29 +1804,30 @@ namespace getfem {
             && (pnode->children[i]->node_type == GA_NODE_CONSTANT);
           args.push_back(&(pnode->children[i]->tensor()));
           if (pnode->children[i]->node_type == GA_NODE_ALLINDICES)
-            ga_throw_error(expr, pnode->children[i]->pos,
+            ga_throw_error(pnode->expr, pnode->children[i]->pos,
                            "Colon operator is not allowed in nonlinear "
                            "operator call.");
           if (pnode->children[i]->test_function_type)
-            ga_throw_error(expr, pnode->pos, "Test functions cannot be passed "
-                           "as argument of a nonlinear operator.");
+            ga_throw_error(pnode->expr, pnode->pos, "Test functions cannot be "
+                          "passed as argument of a nonlinear operator.");
           if (pnode->children[i]->tensor_order() > 2)
-            ga_throw_error(expr, pnode->pos, "Sorry, arguments to nonlinear "
-                        "operators should only be scalar, vector or matrices");
+            ga_throw_error(pnode->expr, pnode->pos,
+                          "Sorry, arguments to nonlinear operators should "
+                          "only be scalar, vector or matrices");
         }
         ga_predef_operator_tab::T::const_iterator it
           = PREDEF_OPERATORS.tab.find(child0->name);
         const ga_nonlinear_operator &OP = *(it->second);
         mi.resize(0);
         if (!(OP.result_size(args, mi)))
-          ga_throw_error(expr, pnode->pos,
+          ga_throw_error(pnode->expr, pnode->pos,
                          "Wrong number or wrong size of arguments for the "
                          "call of nonlinear operator " + child0->name);
 
         pnode->test_function_type = 0;
 
         if (child0->der1 > args.size() || child0->der2 > args.size())
-           ga_throw_error(expr, child0->pos,
+           ga_throw_error(pnode->expr, child0->pos,
                          "Invalid derivative number for nonlinear operator "
                           + child0->name);
 
@@ -1850,12 +1868,12 @@ namespace getfem {
         // cout << endl << "child0->t.sizes() = "
         //      << child0->t.sizes() << endl;
         if (pnode->children.size() != child0->tensor_order() + 1)
-          ga_throw_error(expr, pnode->pos, "Bad number of indices.");
+          ga_throw_error(pnode->expr, pnode->pos, "Bad number of indices.");
         for (size_type i = 1; i < pnode->children.size(); ++i)
           if (pnode->children[i]->node_type != GA_NODE_ALLINDICES &&
               (pnode->children[i]->node_type != GA_NODE_CONSTANT ||
                pnode->children[i]->tensor().size() != 1))
-            ga_throw_error(expr, pnode->children[i]->pos,
+            ga_throw_error(pnode->expr, pnode->children[i]->pos,
                             "Indices should be constant integers or colon.");
 
         bgeot::multi_index mi1(size0.size()), mi2, indices;
@@ -1867,7 +1885,7 @@ namespace getfem {
           } else {
             mi1[i] = size_type(round(pnode->children[i+1]->tensor()[0])-1);
             if (mi1[i] >= child0->tensor_proper_size(i))
-              ga_throw_error(expr, pnode->children[i+1]->pos,
+              ga_throw_error(pnode->expr, pnode->children[i+1]->pos,
                              "Index out of range, " << mi1[i]+1
                              << ". Should be between 1 and "
                              << child0->tensor_proper_size(i) << ".");
@@ -1921,19 +1939,19 @@ namespace getfem {
   }
 
 
-  void ga_semantic_analysis(const std::string &expr, ga_tree &tree,
-                                   const ga_workspace &workspace,
-                                   size_type meshdim,
-                                   size_type ref_elt_dim,
-                                   bool eval_fixed_size,
-                                   bool ignore_X, int option) {
+  void ga_semantic_analysis(ga_tree &tree,
+                           const ga_workspace &workspace,
+                           size_type meshdim,
+                           size_type ref_elt_dim,
+                           bool eval_fixed_size,
+                           bool ignore_X, int option) {
     GMM_ASSERT1(predef_operators_nonlinear_elasticity_initialized &&
                 predef_operators_plasticity_initialized &&
                 predef_operators_contact_initialized, "Internal error");
     if (!(tree.root)) return;
     if (option == 1) { workspace.test1.clear(); workspace.test2.clear(); }
     // cout << "semantic analysis of " << ga_tree_to_string(tree) << endl;
-    ga_node_analysis(expr, tree, workspace, tree.root, meshdim, ref_elt_dim,
+    ga_node_analysis(tree, workspace, tree.root, meshdim, ref_elt_dim,
                      eval_fixed_size, ignore_X, option);
     if (tree.root && option == 2) {
       if (((tree.root->test_function_type & 1) &&
@@ -1948,7 +1966,7 @@ namespace getfem {
         tree.clear();
     }
     // cout << "semantic analysis done " << endl;
-    ga_valid_operand(expr, tree.root);
+    ga_valid_operand(tree.root);
   }
 
 
@@ -2037,7 +2055,8 @@ namespace getfem {
 
         for (size_type i = 0; i < pnode->children.size(); ++i) {
           if (pnode_child == pnode->children[i]) {
-            pnode->children[i] = new ga_tree_node(GA_NODE_ZERO, pnode->pos);
+            pnode->children[i] = new ga_tree_node(GA_NODE_ZERO, pnode->pos,
+                                                 pnode->expr);
             pnode->children[i]->init_scalar_tensor(scalar_type(0));
             pnode->children[i]->parent = pnode;
           }
@@ -2325,20 +2344,20 @@ namespace getfem {
           for (size_type k = 0; k < meshdim; ++k) {
             if (j == i) {
               pga_tree_node param_node = new_pnode->children[k*N+j]
-                = new ga_tree_node(GA_NODE_PARAMS, pnode->pos);
+                = new ga_tree_node(GA_NODE_PARAMS, pnode->pos, pnode->expr);
               new_pnode->children[k*N+j]->parent = new_pnode;
               param_node->children.resize(2);
-              param_node->children[0] = new ga_tree_node(GA_NODE_NORMAL,
-                                                         pnode->pos);
+              param_node->children[0]
+               = new ga_tree_node(GA_NODE_NORMAL, pnode->pos, pnode->expr);
               param_node->children[0]->parent = param_node;
-              param_node->children[1] = new ga_tree_node(GA_NODE_CONSTANT,
-                                                         pnode->pos);
+              param_node->children[1]
+               = new ga_tree_node(GA_NODE_CONSTANT, pnode->pos, pnode->expr);
               param_node->children[1]->parent = param_node;
               param_node->children[1]->init_scalar_tensor(scalar_type(k));
 
             } else {
-              new_pnode->children[k*N+j] = new ga_tree_node(GA_NODE_ZERO,
-                                                            pnode->pos);
+              new_pnode->children[k*N+j]
+               = new ga_tree_node(GA_NODE_ZERO, pnode->pos, pnode->expr);
               new_pnode->children[k*N+j]->init_scalar_tensor(scalar_type(0));
               new_pnode->children[k*N+j]->parent = new_pnode;
             }
@@ -3083,7 +3102,7 @@ namespace getfem {
       ga_derivative(tree, workspace, *((const mesh *)(0)), var, "", 1);
       if (tree.root) {
         ga_replace_test_by_cte(tree.root, true);
-        ga_semantic_analysis(expr, tree, workspace, 1, 1, false, true);
+        ga_semantic_analysis(tree, workspace, 1, 1, false, true);
       }
       return ga_tree_to_string(tree);
     } else return "0";
diff --git a/src/getfem_generic_assembly_tree.cc 
b/src/getfem_generic_assembly_tree.cc
index e5d23f0..db3a363 100644
--- a/src/getfem_generic_assembly_tree.cc
+++ b/src/getfem_generic_assembly_tree.cc
@@ -182,22 +182,22 @@ namespace getfem {
   // Error handling
   //=========================================================================
 
-  void ga_throw_error_msg(const std::string &expr, size_type pos,
-                                 const std::string &msg) {
+  void ga_throw_error_msg(pstring expr, size_type pos,
+                         const std::string &msg) {
     int length_before = 70, length_after = 70;
-    if (expr.size()) {
+    if (expr && expr->size()) {
       int first = std::max(0, int(pos)-length_before);
-      int last = std::min(int(pos)+length_after, int(expr.size()));
+      int last = std::min(int(pos)+length_after, int(expr->size()));
       if (last - first < length_before+length_after)
       first = std::max(0, int(pos)-length_before
                        -(length_before+length_after-last+first));
       if (last - first < length_before+length_after)
         last = std::min(int(pos)+length_after
                         +(length_before+length_after-last+first),
-                        int(expr.size()));
+                        int(expr->size()));
       if (first > 0) cerr << "...";
-      cerr << expr.substr(first, last-first);
-      if (last < int(expr.size())) cerr << "...";
+      cerr << expr->substr(first, last-first);
+      if (last < int(expr->size())) cerr << "...";
       cerr << endl;
       if (first > 0) cerr << "   ";
       if (int(pos) > first)
@@ -212,8 +212,7 @@ namespace getfem {
   // Tree structure
   //=========================================================================
 
-  void ga_tree_node::mult_test(const pga_tree_node n0, const pga_tree_node n1,
-                              const std::string &expr) {
+  void ga_tree_node::mult_test(const pga_tree_node n0, const pga_tree_node n1) 
{
     
     size_type test0 = n0->test_function_type, test1 = n1->test_function_type;
     if (test0 && test1 && (test0 == test1 ||
@@ -257,44 +256,45 @@ namespace getfem {
     t.adjust_sizes(mi);
   }
 
-  void ga_tree::add_scalar(scalar_type val, size_type pos) {
+  void ga_tree::add_scalar(scalar_type val, size_type pos, pstring expr) {
     while (current_node && current_node->node_type != GA_NODE_OP)
       current_node = current_node->parent;
     if (current_node) {
-      current_node->adopt_child(new ga_tree_node(val, pos));
+      current_node->adopt_child(new ga_tree_node(val, pos, expr));
       current_node = current_node->children.back();
     }
     else {
       GMM_ASSERT1(root == nullptr, "Invalid tree operation");
-      current_node = root = new ga_tree_node(val, pos);
+      current_node = root = new ga_tree_node(val, pos, expr);
       root->parent = nullptr;
     }
   }
 
-  void ga_tree::add_allindices(size_type pos) {
+  void ga_tree::add_allindices(size_type pos, pstring expr) {
     while (current_node && current_node->node_type != GA_NODE_OP)
       current_node = current_node->parent;
     if (current_node) {
-      current_node->adopt_child(new ga_tree_node(GA_NODE_ALLINDICES, pos));
+      current_node->adopt_child(new ga_tree_node(GA_NODE_ALLINDICES, 
pos,expr));
       current_node = current_node->children.back();
     }
     else {
       GMM_ASSERT1(root == nullptr, "Invalid tree operation");
-      current_node = root = new ga_tree_node(GA_NODE_ALLINDICES, pos);
+      current_node = root = new ga_tree_node(GA_NODE_ALLINDICES, pos, expr);
       root->parent = nullptr;
     }
   }
   
-  void ga_tree::add_name(const char *name, size_type length, size_type pos) {
+  void ga_tree::add_name(const char *name, size_type length, size_type pos,
+                        pstring expr) {
     while (current_node && current_node->node_type != GA_NODE_OP)
       current_node = current_node->parent;
     if (current_node) {
-      current_node->adopt_child(new ga_tree_node(name, length, pos));
+      current_node->adopt_child(new ga_tree_node(name, length, pos, expr));
       current_node = current_node->children.back();
     }
     else {
       GMM_ASSERT1(root == nullptr, "Invalid tree operation");
-      current_node = root = new ga_tree_node(name, length, pos);
+      current_node = root = new ga_tree_node(name, length, pos, expr);
       root->parent = nullptr;
     }
   }
@@ -323,13 +323,13 @@ namespace getfem {
     sub_tree.root = sub_tree.current_node = nullptr;
   }
   
-  void ga_tree::add_params(size_type pos) {
+  void ga_tree::add_params(size_type pos, pstring expr) {
     GMM_ASSERT1(current_node, "internal error");
     while (current_node && current_node->parent &&
           current_node->parent->node_type == GA_NODE_OP &&
           ga_operator_priorities[current_node->parent->op_type] >= 4)
       current_node = current_node->parent;
-    pga_tree_node new_node = new ga_tree_node(GA_NODE_PARAMS, pos);
+    pga_tree_node new_node = new ga_tree_node(GA_NODE_PARAMS, pos, expr);
     new_node->parent = current_node->parent;
     if (current_node->parent)
       current_node->parent->replace_child(current_node, new_node);
@@ -339,16 +339,16 @@ namespace getfem {
     current_node = new_node;
   }
   
-  void ga_tree::add_matrix(size_type pos) {
+  void ga_tree::add_matrix(size_type pos, pstring expr) {
     while (current_node && current_node->node_type != GA_NODE_OP)
       current_node = current_node->parent;
     if (current_node) {
-      current_node->adopt_child(new ga_tree_node(GA_NODE_C_MATRIX, pos));
+      current_node->adopt_child(new ga_tree_node(GA_NODE_C_MATRIX, pos, expr));
       current_node = current_node->children.back();
     }
     else {
       GMM_ASSERT1(root == nullptr, "Invalid tree operation");
-      current_node = root = new ga_tree_node(GA_NODE_C_MATRIX, pos);
+      current_node = root = new ga_tree_node(GA_NODE_C_MATRIX, pos, expr);
       root->parent = nullptr;
     }
     current_node->nbc1 = current_node->nbc2 = current_node->nbc3 = 0;
@@ -376,13 +376,14 @@ namespace getfem {
     current_node->children = new_children;
   }
   
-  void ga_tree::add_op(GA_TOKEN_TYPE op_type, size_type pos) {
+  void ga_tree::add_op(GA_TOKEN_TYPE op_type, size_type pos,
+                      pstring expr) {
     while (current_node && current_node->parent &&
           current_node->parent->node_type == GA_NODE_OP &&
           ga_operator_priorities[current_node->parent->op_type]
           >= ga_operator_priorities[op_type])
       current_node = current_node->parent;
-    pga_tree_node new_node = new ga_tree_node(op_type, pos);
+    pga_tree_node new_node = new ga_tree_node(op_type, pos, expr);
     if (current_node) {
       if (op_type == GA_UNARY_MINUS
          || op_type == GA_SYM || op_type == GA_SKEW
@@ -463,7 +464,7 @@ namespace getfem {
   
   void ga_tree::duplicate_with_operation(pga_tree_node pnode,
                                         GA_TOKEN_TYPE op_type) {
-    pga_tree_node newop = new ga_tree_node(op_type, pnode->pos);
+    pga_tree_node newop = new ga_tree_node(op_type, pnode->pos, pnode->expr);
     newop->children.resize(2, nullptr);
     newop->children[0] = pnode;
     newop->parent = pnode->parent;
@@ -1100,7 +1101,6 @@ namespace getfem {
     return str.str();
   }
 
-
   size_type ga_parse_prefix_operator(std::string &name) {
     if (name.size() >= 5 && name.compare(0, 5, "Grad_") == 0)
       { name = name.substr(5); return 1; }
@@ -1200,12 +1200,12 @@ namespace getfem {
     return *this;
   }
 
-  void ga_replace_macro_params(const std::string expr, ga_tree &tree,
-                              pga_tree_node pnode,
-                              const std::vector<pga_tree_node> &children) {
+  static void ga_replace_macro_params
+  (ga_tree &tree, pga_tree_node pnode,
+   const std::vector<pga_tree_node> &children) {
     if (!pnode) return;
     for (size_type i = 0; i < pnode->children.size(); ++i)
-      ga_replace_macro_params(expr, tree, pnode->children[i], children);
+      ga_replace_macro_params(tree, pnode->children[i], children);
     
     if (pnode->node_type == GA_NODE_MACRO_PARAM) {
       size_type po = pnode->nbc2;
@@ -1215,10 +1215,18 @@ namespace getfem {
 
       if (po || pt) {
        if (!(pchild->children.empty()) || pchild->node_type != GA_NODE_NAME)
-         ga_throw_error(expr, pchild->pos, "Error in macro expansion. "
-                        "Only variable name are allowed for macro parameter "
-                        "preceded by Grad_ Hess_ Test_ or Test2_ prefixes.");
-       pnode->node_type = GA_NODE_NAME;
+         ga_throw_error(pchild->expr, pchild->pos, "Error in macro "
+                        "expansion. Only variable name are allowed for macro "
+                        "parameter preceded by Grad_ Hess_ Test_ or Test2_ "
+                        "prefixes.");
+       switch(pnode->op_type) {
+       case GA_NAME : pnode->node_type = GA_NODE_NAME; break;
+       case GA_INTERPOLATE : pnode->node_type = GA_NODE_INTERPOLATE; break;
+       case GA_ELEMENTARY : pnode->node_type = GA_NODE_ELEMENTARY; break;
+       case GA_XFEM_PLUS : pnode->node_type = GA_NODE_XFEM_PLUS; break;
+       case GA_XFEM_MINUS: pnode->node_type = GA_NODE_XFEM_MINUS; break;
+       default:break;
+       }
        pnode->name = pchild->name;
        if (pt == 1) pnode->name = "Test_" + pnode->name;
        if (pt == 2) pnode->name = "Test2_" + pnode->name;
@@ -1239,21 +1247,20 @@ namespace getfem {
     }
   }
   
-  void ga_expand_macro(ga_tree &tree, pga_tree_node pnode,
-                      const ga_macro_dictionnary &macro_dict,
-                      const std::string &expr) {
+  static void ga_expand_macro(ga_tree &tree, pga_tree_node pnode,
+                             const ga_macro_dictionnary &macro_dict) {
     if (!pnode) return;
     
     if (pnode->node_type == GA_NODE_PARAMS) {
       
       for (size_type i = 1; i < pnode->children.size(); ++i)
-       ga_expand_macro(tree, pnode->children[i], macro_dict, expr);
+       ga_expand_macro(tree, pnode->children[i], macro_dict);
 
       if (macro_dict.macro_exists(pnode->children[0]->name)) {
        // Macro with parameters
        const ga_macro &gam = macro_dict.get_macro(pnode->children[0]->name);
        if (gam.nb_params()+1 != pnode->children.size())
-         ga_throw_error(expr, pnode->pos,
+         ga_throw_error(pnode->expr, pnode->pos,
                         "Bad number of parameters in the use of macro '"
                         << gam.name() << "'. Expected " << gam.nb_params()
                         << " found " << pnode->children.size()-1 << ".");
@@ -1265,7 +1272,7 @@ namespace getfem {
          pnode_old->parent->replace_child(pnode_old, pnode);
        else
          tree.root = pnode;
-       ga_replace_macro_params(expr, tree, pnode, pnode_old->children);
+       ga_replace_macro_params(tree, pnode, pnode_old->children);
       }
 
     } else if (pnode->node_type == GA_NODE_NAME &&
@@ -1273,7 +1280,7 @@ namespace getfem {
       // Macro without parameters
       const ga_macro &gam = macro_dict.get_macro(pnode->name);
       if (gam.nb_params() != 0)
-         ga_throw_error(expr, pnode->pos,
+       ga_throw_error(pnode->expr, pnode->pos,
                         "Bad number of parameters in the use of macro '"
                         << gam.name() << "'. Expected " << gam.nb_params()
                         << " none found.");
@@ -1289,7 +1296,7 @@ namespace getfem {
       delete pnode_old;
     } else {
       for (size_type i = 0; i < pnode->children.size(); ++i)
-       ga_expand_macro(tree, pnode->children[i], macro_dict, expr);
+       ga_expand_macro(tree, pnode->children[i], macro_dict);
     }
   }
 
@@ -1299,12 +1306,24 @@ namespace getfem {
     for (size_type i = 0; i < pnode->children.size(); ++i)
       ga_mark_macro_params_rec(pnode->children[i], params);
     
-    if (pnode->node_type == GA_NODE_NAME) {
+    if (pnode->node_type == GA_NODE_NAME ||
+       pnode->node_type == GA_NODE_INTERPOLATE ||
+       pnode->node_type == GA_NODE_ELEMENTARY ||
+       pnode->node_type == GA_NODE_XFEM_PLUS ||
+       pnode->node_type == GA_NODE_XFEM_MINUS) {
       size_type po = ga_parse_prefix_operator(pnode->name);
       size_type pt = ga_parse_prefix_test(pnode->name);
       
       for (size_type i = 0; i < params.size(); ++i)
        if (pnode->name.compare(params[i]) == 0) {
+         switch(pnode->node_type) {
+         case GA_NODE_NAME : pnode->op_type = GA_NAME; break;
+         case GA_NODE_INTERPOLATE : pnode->op_type = GA_INTERPOLATE; break;
+         case GA_NODE_ELEMENTARY : pnode->op_type = GA_ELEMENTARY; break;
+         case GA_NODE_XFEM_PLUS : pnode->op_type = GA_XFEM_PLUS; break;
+         case GA_NODE_XFEM_MINUS: pnode->op_type = GA_XFEM_MINUS; break;
+         default:break;
+         }
          pnode->node_type = GA_NODE_MACRO_PARAM;
          pnode->nbc1 = i; pnode->nbc2 = po; pnode->nbc3 = pt;
        }
@@ -1313,11 +1332,10 @@ namespace getfem {
   
   static void ga_mark_macro_params(ga_macro &gam,
                                   const std::vector<std::string> &params,
-                                  const ga_macro_dictionnary &macro_dict,
-                                  const std::string &expr) {
+                                  const ga_macro_dictionnary &macro_dict) {
     if (gam.tree().root) {
       ga_mark_macro_params_rec(gam.tree().root, params);
-      ga_expand_macro(gam.tree(), gam.tree().root, macro_dict, expr);
+      ga_expand_macro(gam.tree(), gam.tree().root, macro_dict);
     }
   }
 
@@ -1355,7 +1373,7 @@ namespace getfem {
   //=========================================================================
 
   // Read a term with an (implicit) pushdown automaton.
-  static GA_TOKEN_TYPE ga_read_term(const std::string &expr, size_type &pos,
+  static GA_TOKEN_TYPE ga_read_term(pstring expr, size_type &pos,
                                     ga_tree &tree,
                                    ga_macro_dictionnary &macro_dict) {
     size_type token_pos, token_length;
@@ -1364,7 +1382,7 @@ namespace getfem {
 
     for (;;) {
 
-      t_type = ga_get_token(expr, pos, token_pos, token_length);
+      t_type = ga_get_token(*expr, pos, token_pos, token_length);
 
       switch (state) {
 
@@ -1372,82 +1390,83 @@ namespace getfem {
         switch (t_type) {
         case GA_SCALAR:
           {
-            char *endptr; const char *nptr = &(expr[token_pos]);
+            char *endptr; const char *nptr = &((*expr)[token_pos]);
             scalar_type s_read = ::strtod(nptr, &endptr);
             if (endptr == nptr)
               ga_throw_error(expr, token_pos, "Bad numeric format.");
-            tree.add_scalar(s_read, token_pos);
+            tree.add_scalar(s_read, token_pos, expr);
           }
           state = 2; break;
 
         case GA_COLON:
-          tree.add_allindices(token_pos);
+          tree.add_allindices(token_pos, expr);
           state = 2; break;
 
         case GA_NAME:
-          tree.add_name(&(expr[token_pos]), token_length, token_pos);
+          tree.add_name(&((*expr)[token_pos]), token_length, token_pos, expr);
           state = 2; break;
 
         case GA_MINUS: // unary -
-          tree.add_op(GA_UNARY_MINUS, token_pos);
+          tree.add_op(GA_UNARY_MINUS, token_pos, expr);
         case GA_PLUS:  // unary +
           state = 1; break;
 
         case GA_SYM:
-          tree.add_op(GA_SYM, token_pos);
+          tree.add_op(GA_SYM, token_pos, expr);
           state = 1; break;
 
         case GA_SKEW:
-          tree.add_op(GA_SKEW, token_pos);
+          tree.add_op(GA_SKEW, token_pos, expr);
           state = 1; break;
 
         case GA_TRACE:
-          tree.add_op(GA_TRACE, token_pos);
+          tree.add_op(GA_TRACE, token_pos, expr);
           state = 1; break;
 
         case GA_DEVIATOR:
-          tree.add_op(GA_DEVIATOR, token_pos);
+          tree.add_op(GA_DEVIATOR, token_pos, expr);
           state = 1; break;
 
        case GA_DEF:
          {
            ga_macro gam;
-           t_type = ga_get_token(expr, pos, token_pos, token_length);
+           t_type = ga_get_token(*expr, pos, token_pos, token_length);
            if (t_type != GA_NAME)
               ga_throw_error(expr, pos,
                              "Macro definition should begin with macro name");
-           gam.name() = std::string(&(expr[token_pos]), token_length);
+           gam.name() = std::string(&((*expr)[token_pos]), token_length);
            if (ga_check_name_validity(gam.name()))
              ga_throw_error(expr, pos-1, "Invalid macro name.")
-           t_type = ga_get_token(expr, pos, token_pos, token_length);
+           t_type = ga_get_token(*expr, pos, token_pos, token_length);
            std::vector<std::string> params;
             if (t_type == GA_LPAR) {
-             t_type = ga_get_token(expr, pos, token_pos, token_length);
+             t_type = ga_get_token(*expr, pos, token_pos, token_length);
              while (t_type == GA_NAME) {
-               params.push_back(std::string(&(expr[token_pos]), token_length));
+               params.push_back(std::string(&((*expr)[token_pos]),
+                                            token_length));
                if (ga_check_name_validity(params.back()))
                  ga_throw_error(expr, pos-1, "Invalid macro parameter name.");
                for (size_type i = 0; i+1 < params.size(); ++i)
                  if (params.back().compare(params[i]) == 0)
                    ga_throw_error(expr, pos-1,
                                   "Invalid repeated macro parameter name.");
-               t_type = ga_get_token(expr, pos, token_pos, token_length);
+               t_type = ga_get_token(*expr, pos, token_pos, token_length);
                if (t_type == GA_COMMA)
-                 t_type = ga_get_token(expr, pos, token_pos, token_length);
+                 t_type = ga_get_token(*expr, pos, token_pos, token_length);
              }
              if (t_type != GA_RPAR)
                ga_throw_error(expr, pos-1,
                              "Missing right parenthesis in macro definition.");
-             t_type = ga_get_token(expr, pos, token_pos, token_length);
+             t_type = ga_get_token(*expr, pos, token_pos, token_length);
            }
            if (t_type != GA_COLON_EQ)
              ga_throw_error(expr, pos-1, "Missing := for macro definition.");
 
            t_type = ga_read_term(expr, pos, gam.tree(), macro_dict);
-           gam.nb_params() = params.size();
-           ga_mark_macro_params(gam, params, macro_dict, expr);
            if (gam.tree().root)
-             ga_expand_macro(gam.tree(), gam.tree().root, macro_dict, expr);
+             ga_expand_macro(gam.tree(), gam.tree().root, macro_dict);
+           gam.nb_params() = params.size();
+           ga_mark_macro_params(gam, params, macro_dict);
            macro_dict.add_macro(gam);
 
            // cout << "macro \"" << gam.name() << "\" registered with "
@@ -1464,31 +1483,31 @@ namespace getfem {
 
         case GA_INTERPOLATE:
           {
-            tree.add_scalar(scalar_type(0), token_pos);
+            tree.add_scalar(scalar_type(0), token_pos, expr);
             tree.current_node->node_type = GA_NODE_INTERPOLATE;
-            t_type = ga_get_token(expr, pos, token_pos, token_length);
+            t_type = ga_get_token(*expr, pos, token_pos, token_length);
             if (t_type != GA_LPAR)
               ga_throw_error(expr, pos-1, "Missing interpolate arguments.");
-            t_type = ga_get_token(expr, pos, token_pos, token_length);
+            t_type = ga_get_token(*expr, pos, token_pos, token_length);
             if (t_type != GA_NAME)
               ga_throw_error(expr, pos,
                              "First argument of Interpolate should be a "
                              "variable, test function, X or Normal.");
-            tree.current_node->name = std::string(&(expr[token_pos]),
+            tree.current_node->name = std::string(&((*expr)[token_pos]),
                                                   token_length);
 
-            t_type = ga_get_token(expr, pos, token_pos, token_length);
+            t_type = ga_get_token(*expr, pos, token_pos, token_length);
             if (t_type != GA_COMMA)
               ga_throw_error(expr, pos, "Bad format for Interpolate "
                              "arguments.");
-            t_type = ga_get_token(expr, pos, token_pos, token_length);
+            t_type = ga_get_token(*expr, pos, token_pos, token_length);
             if (t_type != GA_NAME)
               ga_throw_error(expr, pos,
                              "Second argument of Interpolate should be a "
                              "transformation name.");
             tree.current_node->interpolate_name
-              = std::string(&(expr[token_pos]), token_length);
-            t_type = ga_get_token(expr, pos, token_pos, token_length);
+              = std::string(&((*expr)[token_pos]), token_length);
+            t_type = ga_get_token(*expr, pos, token_pos, token_length);
             if (t_type != GA_RPAR)
               ga_throw_error(expr, pos-1, "Missing a parenthesis after "
                              "interpolate arguments.");
@@ -1498,32 +1517,32 @@ namespace getfem {
 
         case GA_ELEMENTARY:
           {
-            tree.add_scalar(scalar_type(0), token_pos);
+            tree.add_scalar(scalar_type(0), token_pos, expr);
             tree.current_node->node_type = GA_NODE_ELEMENTARY;
-            t_type = ga_get_token(expr, pos, token_pos, token_length);
+            t_type = ga_get_token(*expr, pos, token_pos, token_length);
             if (t_type != GA_LPAR)
               ga_throw_error(expr, pos-1,
                              "Missing Elementary_transformation arguments.");
-            t_type = ga_get_token(expr, pos, token_pos, token_length);
+            t_type = ga_get_token(*expr, pos, token_pos, token_length);
             if (t_type != GA_NAME)
               ga_throw_error(expr, pos,
                              "First argument of Elementary_transformation "
                              "should be a variable or a test function.");
-            tree.current_node->name = std::string(&(expr[token_pos]),
+            tree.current_node->name = std::string(&((*expr)[token_pos]),
                                                   token_length);
 
-            t_type = ga_get_token(expr, pos, token_pos, token_length);
+            t_type = ga_get_token(*expr, pos, token_pos, token_length);
             if (t_type != GA_COMMA)
               ga_throw_error(expr, pos, "Bad format for "
                              "Elementary_transformation arguments.");
-            t_type = ga_get_token(expr, pos, token_pos, token_length);
+            t_type = ga_get_token(*expr, pos, token_pos, token_length);
             if (t_type != GA_NAME)
               ga_throw_error(expr, pos,
                              "Second argument of Elementary_transformation "
                              "should be a transformation name.");
             tree.current_node->elementary_name
-              = std::string(&(expr[token_pos]), token_length);
-            t_type = ga_get_token(expr, pos, token_pos, token_length);
+              = std::string(&((*expr)[token_pos]), token_length);
+            t_type = ga_get_token(*expr, pos, token_pos, token_length);
             if (t_type != GA_RPAR)
               ga_throw_error(expr, pos-1, "Missing a parenthesis after "
                              "Elementary_transformation arguments.");
@@ -1533,20 +1552,20 @@ namespace getfem {
 
         case GA_XFEM_PLUS:
           {
-            tree.add_scalar(scalar_type(0), token_pos);
+            tree.add_scalar(scalar_type(0), token_pos, expr);
             tree.current_node->node_type = GA_NODE_XFEM_PLUS;
-            t_type = ga_get_token(expr, pos, token_pos, token_length);
+            t_type = ga_get_token(*expr, pos, token_pos, token_length);
             if (t_type != GA_LPAR)
               ga_throw_error(expr, pos-1,
                              "Missing Xfem_plus arguments.");
-            t_type = ga_get_token(expr, pos, token_pos, token_length);
+            t_type = ga_get_token(*expr, pos, token_pos, token_length);
             if (t_type != GA_NAME)
               ga_throw_error(expr, pos,
                              "The argument of Xfem_plus should be a "
                              "variable or a test function.");
-            tree.current_node->name = std::string(&(expr[token_pos]),
+            tree.current_node->name = std::string(&((*expr)[token_pos]),
                                                   token_length);
-            t_type = ga_get_token(expr, pos, token_pos, token_length);
+            t_type = ga_get_token(*expr, pos, token_pos, token_length);
             if (t_type != GA_RPAR)
               ga_throw_error(expr, pos-1, "Missing a parenthesis after "
                              "Xfem_plus argument.");
@@ -1556,20 +1575,20 @@ namespace getfem {
 
         case GA_XFEM_MINUS:
           {
-            tree.add_scalar(scalar_type(0), token_pos);
+            tree.add_scalar(scalar_type(0), token_pos, expr);
             tree.current_node->node_type = GA_NODE_XFEM_MINUS;
-            t_type = ga_get_token(expr, pos, token_pos, token_length);
+            t_type = ga_get_token(*expr, pos, token_pos, token_length);
             if (t_type != GA_LPAR)
               ga_throw_error(expr, pos-1,
                              "Missing Xfem_minus arguments.");
-            t_type = ga_get_token(expr, pos, token_pos, token_length);
+            t_type = ga_get_token(*expr, pos, token_pos, token_length);
             if (t_type != GA_NAME)
               ga_throw_error(expr, pos,
                              "The argument of Xfem_minus should be a "
                              "variable or a test function.");
-            tree.current_node->name = std::string(&(expr[token_pos]),
+            tree.current_node->name = std::string(&((*expr)[token_pos]),
                                                   token_length);
-            t_type = ga_get_token(expr, pos, token_pos, token_length);
+            t_type = ga_get_token(*expr, pos, token_pos, token_length);
             if (t_type != GA_RPAR)
               ga_throw_error(expr, pos-1, "Missing a parenthesis after "
                              "Xfem_minus argument.");
@@ -1579,21 +1598,21 @@ namespace getfem {
 
         case GA_INTERPOLATE_FILTER:
           {
-            tree.add_scalar(scalar_type(0), token_pos);
+            tree.add_scalar(scalar_type(0), token_pos, expr);
             tree.current_node->node_type = GA_NODE_INTERPOLATE_FILTER;
             tree.current_node->nbc1 = size_type(-1);
-            t_type = ga_get_token(expr, pos, token_pos, token_length);
+            t_type = ga_get_token(*expr, pos, token_pos, token_length);
             if (t_type != GA_LPAR)
               ga_throw_error(expr, pos-1, "Missing interpolate arguments.");
-            t_type = ga_get_token(expr, pos, token_pos, token_length);
+            t_type = ga_get_token(*expr, pos, token_pos, token_length);
             if (t_type != GA_NAME)
               ga_throw_error(expr, pos, "First argument of Interpolate_filter "
                              "should be a transformation name.");
             tree.current_node->interpolate_name
-              = std::string(&(expr[token_pos]), token_length);
-            t_type = ga_get_token(expr, pos, token_pos, token_length);
+              = std::string(&((*expr)[token_pos]), token_length);
+            t_type = ga_get_token(*expr, pos, token_pos, token_length);
             if (t_type != GA_COMMA)
-              ga_throw_error(expr,pos,
+              ga_throw_error(expr, pos,
                              "Bad format for Interpolate_filter arguments.");
             ga_tree sub_tree;
             t_type = ga_read_term(expr, pos, sub_tree, macro_dict);
@@ -1613,7 +1632,7 @@ namespace getfem {
           break;
 
         case GA_PRINT:
-          tree.add_op(GA_PRINT, token_pos);
+          tree.add_op(GA_PRINT, token_pos, expr);
           state = 1; break;
 
         case GA_LPAR: // Parenthesed expression
@@ -1636,7 +1655,7 @@ namespace getfem {
             size_type tensor_order(1);
             bool foundcomma(false), foundsemi(false), nested_format(false);
 
-            tree.add_matrix(token_pos);
+            tree.add_matrix(token_pos, expr);
             do {
               r_type = ga_read_term(expr, pos, sub_tree, macro_dict);
 
@@ -1769,10 +1788,10 @@ namespace getfem {
         case GA_PLUS: case GA_MINUS: case GA_MULT: case GA_DIV:
         case GA_COLON: case GA_DOT: case GA_DOTMULT: case GA_DOTDIV:
         case GA_TMULT:
-          tree.add_op(t_type, token_pos);
+          tree.add_op(t_type, token_pos, expr);
           state = 1; break;
         case GA_QUOTE:
-          tree.add_op(t_type, token_pos);
+          tree.add_op(t_type, token_pos, expr);
           state = 2; break;
         case GA_END: case GA_RPAR: case GA_COMMA: case GA_DCOMMA:
         case GA_RBRACKET: case GA_SEMICOLON: case GA_DSEMICOLON:
@@ -1781,7 +1800,7 @@ namespace getfem {
           {
             ga_tree sub_tree;
             GA_TOKEN_TYPE r_type;
-            tree.add_params(token_pos);
+            tree.add_params(token_pos, expr);
             do {
               r_type = ga_read_term(expr, pos, sub_tree, macro_dict);
               if (r_type != GA_RPAR && r_type != GA_COMMA)
@@ -1812,15 +1831,19 @@ namespace getfem {
     GA_TOKEN_TYPE t = ga_get_token(expr, pos, token_pos, token_length);
     if (t == GA_END) return;
     pos = 0;
+    pstring nexpr(new std::string(expr));
     
-    t = ga_read_term(expr, pos, tree, macro_dict);
-    if (tree.root) ga_expand_macro(tree, tree.root, macro_dict, expr);
+    cout << "Original " << expr << endl;
+    t = ga_read_term(nexpr, pos, tree, macro_dict);
+    cout << "Before expand " << ga_tree_to_string(tree) << endl;
+    if (tree.root) ga_expand_macro(tree, tree.root, macro_dict);
+    cout << "After expand " << ga_tree_to_string(tree) << endl;
     
     switch (t) {
-    case GA_RPAR: ga_throw_error(expr, pos-1, "Unbalanced parenthesis.");
-    case GA_RBRACKET: ga_throw_error(expr, pos-1, "Unbalanced braket.");
+    case GA_RPAR: ga_throw_error(nexpr, pos-1, "Unbalanced parenthesis.");
+    case GA_RBRACKET: ga_throw_error(nexpr, pos-1, "Unbalanced braket.");
     case GA_END: break;
-    default: ga_throw_error(expr, pos-1, "Unexpected token.");
+    default: ga_throw_error(nexpr, pos-1, "Unexpected token.");
     }
   }
   
@@ -1831,9 +1854,9 @@ namespace getfem {
     ga_macro_dictionnary macro_dict_loc(true, macro_dict);
     ga_read_string_reg(expr, tree, macro_dict_loc);
   }
-  
 
   // Small tool to make basic substitutions into an assembly string
+  // Should be replaced by macros now.
   std::string ga_substitute(const std::string &expr,
                             const std::map<std::string, std::string> &dict) {
     if (dict.size()) {
diff --git a/src/getfem_generic_assembly_workspace.cc 
b/src/getfem_generic_assembly_workspace.cc
index 018730b..15da368 100644
--- a/src/getfem_generic_assembly_workspace.cc
+++ b/src/getfem_generic_assembly_workspace.cc
@@ -410,7 +410,7 @@ namespace getfem {
           ftree.root->op_type = GA_PLUS;
           ftree.root->children.resize(2, nullptr);
           ftree.copy_node(tree.root, ftree.root, ftree.root->children[1]);
-          ga_semantic_analysis("", ftree, *this, m.dim(),
+          ga_semantic_analysis(ftree, *this, m.dim(),
                                ref_elt_dim_of_mesh(m), false, function_expr);
           found = true;
           break;
@@ -447,7 +447,7 @@ namespace getfem {
             ga_derivative(dtree, *this, m, var.varname, var.transname, 
1+order);
             // cout << "Result : " << ga_tree_to_string(dtree) << endl;
             GA_TOCTIC("Derivative time");
-            ga_semantic_analysis(expr, dtree, *this, m.dim(),
+            ga_semantic_analysis(dtree, *this, m.dim(),
                                  ref_elt_dim_of_mesh(m), false, function_expr);
             GA_TOCTIC("Analysis after Derivative time");
             // cout << "after analysis "  << ga_tree_to_string(dtree) << endl;
@@ -481,7 +481,7 @@ namespace getfem {
     std::vector<ga_tree> ltrees(1);
     ga_read_string(expr, ltrees[0], macro_dictionnary());
     // cout << "read : " << ga_tree_to_string(ltrees[0])  << endl;
-    ga_semantic_analysis(expr, ltrees[0], *this, mim.linked_mesh().dim(),
+    ga_semantic_analysis(ltrees[0], *this, mim.linked_mesh().dim(),
                          ref_elt_dim_of_mesh(mim.linked_mesh()),
                          false, false, 1);
     // cout << "analysed : " << ga_tree_to_string(ltrees[0]) << endl;
@@ -499,7 +499,7 @@ namespace getfem {
             selected_test1 = *it1;
             if (test2.size()) selected_test2 = *it2++;
             // cout << "analysis with " << selected_test1.first << endl;
-            ga_semantic_analysis(expr, ltrees[i*ntest2+j], *this,
+            ga_semantic_analysis(ltrees[i*ntest2+j], *this,
                                  mim.linked_mesh().dim(),
                                  ref_elt_dim_of_mesh(mim.linked_mesh()),
                                  false, false, 2);
@@ -524,7 +524,7 @@ namespace getfem {
   void ga_workspace::add_function_expression(const std::string &expr) {
     ga_tree tree;
     ga_read_string(expr, tree, macro_dictionnary());
-    ga_semantic_analysis(expr, tree, *this, 1, 1, false, true);
+    ga_semantic_analysis(tree, *this, 1, 1, false, true);
     if (tree.root) {
       // GMM_ASSERT1(tree.root->nb_test_functions() == 0,
       //            "Invalid function expression");
@@ -539,7 +539,7 @@ namespace getfem {
     const mesh_region &rg = register_region(m, rg_);
     ga_tree tree;
     ga_read_string(expr, tree, macro_dictionnary());
-    ga_semantic_analysis(expr, tree, *this, m.dim(), ref_elt_dim_of_mesh(m),
+    ga_semantic_analysis(tree, *this, m.dim(), ref_elt_dim_of_mesh(m),
                          false, false);
     if (tree.root) {
       // GMM_ASSERT1(tree.root->nb_test_functions() == 0,
@@ -555,7 +555,7 @@ namespace getfem {
     const mesh_region &rg = register_region(m, rg_);
     ga_tree tree;
     ga_read_string(expr, tree, macro_dictionnary());
-    ga_semantic_analysis(expr, tree, *this, m.dim(), ref_elt_dim_of_mesh(m),
+    ga_semantic_analysis(tree, *this, m.dim(), ref_elt_dim_of_mesh(m),
                          false, false);
     if (tree.root) {
       GMM_ASSERT1(tree.root->nb_test_functions() == 0,
@@ -574,7 +574,7 @@ namespace getfem {
     const mesh_region &rg = register_region(m, rg_);
     ga_tree tree;
     ga_read_string(expr, tree, macro_dictionnary());
-    ga_semantic_analysis(expr, tree, *this, m.dim(), ref_elt_dim_of_mesh(m),
+    ga_semantic_analysis(tree, *this, m.dim(), ref_elt_dim_of_mesh(m),
                          false, false);
     if (tree.root) {
       GMM_ASSERT1(tree.root->nb_test_functions() == 0,
@@ -892,7 +892,7 @@ namespace getfem {
         if (local_tree.root)
           ga_node_extract_constant_term(local_tree, local_tree.root, *this, m);
         if (local_tree.root)
-          ga_semantic_analysis("", local_tree, *this, m.dim(),
+          ga_semantic_analysis(local_tree, *this, m.dim(),
                                ref_elt_dim_of_mesh(m), false, false);
         if (local_tree.root && local_tree.root->node_type != GA_NODE_ZERO) {
           constant_term += "-("+ga_tree_to_string(local_tree)+")";
diff --git a/src/getfem_models.cc b/src/getfem_models.cc
index fd7839b..7e16876 100644
--- a/src/getfem_models.cc
+++ b/src/getfem_models.cc
@@ -984,8 +984,10 @@ namespace getfem {
     return variables.count(no_old_prefix_name(name)) > 0;
   }
 
-  void model::add_macro(const std::string &name, const std::string &expr)
-  { check_name_validity(name); macro_dict.add_macro(name, expr); }
+  void model::add_macro(const std::string &name, const std::string &expr) {
+    check_name_validity(name.substr(0, name.find("(")));
+    macro_dict.add_macro(name, expr);
+  }
 
   void model::del_macro(const std::string &name)
   { macro_dict.del_macro(name); }



reply via email to

[Prev in Thread] Current Thread [Next in Thread]