]> matita.cs.unibo.it Git - helm.git/blobdiff - helm/DEVEL/mathml_editor/src/TPushParser.cc
Added some controls for the graphical deleting of apostrophe.
[helm.git] / helm / DEVEL / mathml_editor / src / TPushParser.cc
index 325b9aa3c129f9a9bd31500aeec01ed6850184f1..870e9f0a707a6b86d05c24ef9b7a4677729d3b40 100644 (file)
@@ -21,6 +21,7 @@ TPushParser::init()
   cursor["id"] = "I0";
   doc.clearDirty();
   doc.root().append(cursor);
+  logger.verbosity(ALogger::Debug);
 }
 
 TPushParser::~TPushParser()
@@ -75,22 +76,23 @@ TPushParser::do_end()
       assert(row && row.is("row"));
       TNode table = row.parent();
       assert(table);
-      advance(table);
-
-      // now we have to pop the associated frame in the stack
-      frames.pop();
+      advance(row);
     }
   else if (parent && parent.isG() && !parent.hasId() && parent.parent())
     {
       // closing brace for a right-open macro (like \over)
+      // It's not sure that we want to exit from a phantom group with a 
+      // '}', because, to enter in the phantom group the user didn't insert a 
+      // '{'.
       cursor.remove();
-      advance(parent.parent());
-      frames.pop();
+      advance(parent);
     }
   else
     {
-      // ???
-      assert(0);
+      // In this case, there is a redundant '}', so I think we can ignore it and 
+      // emit an error
+      logger.error("There so no corresponding'{'");
+      //assert(0);
     }
 }
 
@@ -121,6 +123,7 @@ TPushParser::do_shift()
          else
            {
              // we need two closing math shifts
+             //cursor.remove(); ??
              parent.parent().append(cursor);
            }
        }
@@ -141,7 +144,13 @@ TPushParser::do_shift()
     }
   else
     {
-      cerr << "ERROR: math shift" << endl;
+      // In TeX, the user can type
+      //   $a-b\over2a+b$
+      // In this case, '$' character is correct.
+      // I don't think so, if user types
+      //   $12+{a-b\over2a+b$
+      // because the group is not closed with a '}'
+      logger.error("ERROR: math shift");
     }
 }
 
@@ -175,7 +184,7 @@ TPushParser::do_align()
     }
   else
     {
-      cerr << "alignment tab used outside matrix" << endl;
+      logger.error("alignment tab used outside matrix");
     }
 }
 
@@ -216,7 +225,7 @@ TPushParser::do_subscript()
     }
   else if (parent.isSb() && cursor == parent[1])
     {
-      if (parent["under"] == "1") cerr << "already under" << endl;
+      if (parent["under"] == "1") logger.error("already under");
       else parent["under"] = "1";
     }
 }
@@ -246,7 +255,7 @@ TPushParser::do_superscript()
     }
   else if (parent.isSp() && cursor == parent[1])
     {
-      if (parent["over"] == "1") cerr << "already over" << endl;
+      if (parent["over"] == "1") logger.error("already over");
       else parent["over"] = "1";
     }
 }
@@ -316,7 +325,8 @@ TPushParser::do_apostrophe()
        }
       else
        {
-         // error ???
+         // is it an error?
+         logger.error("you have to type one identifier before the  ''");
        }
     }
   else
@@ -417,9 +427,9 @@ TPushParser::do_control(const std::string& name)
            TNode m = doc.createC(name, nextId++);
            cursor.replace(m);
            
-           cout << "ecco tutti i token del pattern della entry inserita" << endl;
+           logger.debug("do_control: i have pushed a frame in the stack. Here is the pattern of the associated MACRO");
            for (unsigned i = 0; i < entry.pattern.size(); i++)
-             cout << entry.pattern[i].value << endl;
+             logger.debug(entry.pattern[i].value);
            
            if (entry.leftOpen && entry.rightOpen)
              {
@@ -458,12 +468,8 @@ TPushParser::do_control(const std::string& name)
                  {
                    frames.push(Frame(entry));
 
-                   if (entry.table)
-                     cout << "do_control: we have a table" << endl;
-                   
                    if (entry.paramDelimited(0))
                      {
-                       cout << "do_control: it'a MACRO with delimited first argument" << endl;
                        TNode g = doc.createG();
                        m.append(g);
                        g.append(cursor);
@@ -474,7 +480,7 @@ TPushParser::do_control(const std::string& name)
                else
                  {
                    // error, but we could handle this very easily
-                   cerr << "error, but we could handle this easily" << endl;
+                   logger.error("error, but we could handle this easily");
                  }
              }
            else advance(m);
@@ -482,7 +488,7 @@ TPushParser::do_control(const std::string& name)
          break;
        case TDictionary::UNDEFINED:
          {
-           cerr << "ERROR: using undefined macro `" << name << "'" << endl;
+           logger.error("ERROR: using undefined macro ` + name '");
            TNode m = doc.createC(name, nextId++);
            cursor.replace(m);
            advance(m);
@@ -495,145 +501,278 @@ TPushParser::do_control(const std::string& name)
 }
 
 void
-TPushParser::gdelete_prev()
+TPushParser::gdelete_prev_token()
 {
-  // if in this function, the prev of cursor does exist, also the parent and we want a graphical deleting.
-
   assert(cursor.prev());
   assert(cursor.parent());
-
   TNode prev = cursor.prev();
-  if (prev.is("i") || prev.is("o") || prev.is("n"))
+  assert(prev.is("i") || prev.is("o") || prev.is("n"));
+
+  logger.debug("gdelete_prev_token: start");
+  
+  // the control below is designed to handle the case in which val have more than one unicode character
+  DOM::UCS4String ucs4val(prev.element().getAttribute("val"));
+  if ((ucs4val.length() <= 1) || prev.element().hasAttribute("name"))
     {
-      // the control below is designed to handle the case in which val have more than one unicode character
-      DOM::UCS4String ucs4val(prev.element().getAttribute("val"));
-      if ((ucs4val.length() <= 1) || prev.element().hasAttribute("name"))
+      logger.debug("gdelete_prev_token: i have removed an element");
+      cursor.remove();
+      prev.replace(cursor);
+      
+      if (cursor.parent().isC())
         {
-         cursor.remove();
-         prev.replace(cursor);
-
-         if (cursor.parent().isC())
-           {
-             // in this case we have removed an element of a MACRO. 
-             // we can assert that this element was a non delimited argument
-             assert(!frames.empty());
-             Frame& frame = frames.top();
-             assert(frame.pos > 0);
+         // in this case we have removed an element of a MACRO. 
+         // we can assert that this element was a non delimited argument
+         assert(!frames.empty());
+         Frame& frame = frames.top();
+         assert(frame.pos > 0);
 
-             frame.pos--;
-           }
-       }
-      else
-        {
-         ucs4val.erase(ucs4val.length() - 1, 1);
-         prev.element().setAttribute(DOM::GdomeString("val"), DOM::GdomeString(ucs4val));
+         frame.pos--;
+         logger.debug("gdelete_prev_token: it was a MACRO's child so i have decremented the member pos of the associated frame");
        }
-    } // end of if (prev.is("i") || ...)
-  else if (prev.is("sp") || prev.is("sb"))
+    }
+  else
     {
-      cursor.remove();
-      prev.append(cursor);
-      gdelete_prev();
-    } // end of if (prev.is("sp") || prev.is("sb"))
-  else if (prev.isG())
+      ucs4val.erase(ucs4val.length() - 1, 1);
+      prev.element().setAttribute(DOM::GdomeString("val"), DOM::GdomeString(ucs4val));
+    }
+
+  logger.debug("gdelete_prev_token: bye...");
+}
+
+void
+TPushParser::gdelete_prev_script()
+{
+  logger.debug("gdelete_prev_script: start...");
+  // this method delete a sp or an sb preceding the cursor
+  assert(cursor.prev());
+  assert(cursor.parent());
+  TNode prev = cursor.prev();
+  assert(prev.is("sp") || prev.is("sb"));
+  cursor.remove();
+  prev.append(cursor);
+  // i can invoke the gdelet_prev, because a sp (sb) MUST have two child
+  gdelete_prev();
+  logger.debug("gdelete_prev_script: bye...");
+}
+
+void
+TPushParser::gdelete_prev_group()
+{
+  logger.debug("gdelete_prev_group: start");
+  assert(cursor.prev() && cursor.prev().isG());
+  TNode prev = cursor.prev();
+  cursor.remove();
+  prev.append(cursor);
+  logger.debug("gdelete_prev_group: i have to call the do_gdelete()");
+  
+  // a group can have no child, so the gdelete_prev is not appropriate
+  // so this method is not equivalent to the one above
+  do_gdelete();
+  
+  logger.debug("gdelete_prev_group: do_gdelete terminated");
+  logger.debug("gdelete_prev_group: bye...");
+}
+
+void
+TPushParser::gdelete_prev_macro()
+{
+  logger.debug("gdelete_prev_macro: start");
+  assert(cursor.parent());
+  assert(cursor.prev());
+  TNode prev = cursor.prev();
+  assert(prev.isC());
+  
+  const TDictionary::Entry& entry = dictionary.find(prev["name"]);
+  
+  if (!entry.defined())
     {
+      // I assume tha the user want to completely delete the undefined macro
+      logger.debug("gdelete_prev_macro: i have to remove an undefined macro");
       cursor.remove();
-      prev.append(cursor);
-      do_gdelete();
+      prev.replace(cursor);
     }
-  else if (prev.isC() && dictionary.find(prev["name"]).cls != TDictionary::UNDEFINED)
+  else
     {
-      const TDictionary::Entry& entry = dictionary.find(prev["name"]);
-
-      // i start to remove a MACRO. The frame associated to this MACRO was 
-      // popped from the stack (i think). So, i re-push the frame in the stack,
-      // but the pos member should be set correctly
-      cout << "gdelete_prev: i have to start to delete a MACRO" << endl;
+      logger.debug("gdelete_prev_macro: i have to start to delete a defined MACRO");
+      
+      // i start to remove a MACRO. Different actions must be taken, based on the nature 
+      // of the MACRO. In some case, we can't remove the MACRO immediately, in other
+      // case it's correct. In the first case, we have to update the stack, pushing
+      // a frame in the stack with a correct value of pos, in the 
+      // second one, we do not have to push a frame in the stack
       
-      // if the control element is leftOpen and rightOpen, the cursor should be placed after 
-      // the last child of the control element's last child
       if (entry.rightOpen)
         {
-         cout << "gdelte_prev(): i have to delete a control rightOpen, so i push an element in the stack" << endl;
-         Frame frame(entry);
-         frames.push(frame);
+         // if the control element is ightOpen, the cursor should be placed after 
+         // the last child of the control element's last child, and try to remove something
+         // A frame MUST be pushed in the stack, because we dont' know if the following actions 
+         // will remove the MACRO.
+         logger.debug("gdelte_prev_macro: i have to delete a control rightOpen, so i push an element in the stack");
+         
+         frames.push(Frame(entry));
+
+         logger.debug("gdelete_prev_macro: i control the values of the pushed frame");
+         logger.debug("gdelete_prev_macro: rightOpen");
+         cout << frames.top().entry.rightOpen << endl;
+         logger.debug("gdelete_prev_macro: leftOpen");
+         cout << frames.top().entry.leftOpen << endl;
+         logger.debug("gdelete_prev_macro: pattern.empty()");
+         cout << frames.top().entry.pattern.empty() << endl;
+
+         // Since the MACRO is rightOpen, the last child of the MACRO must be a phantom group
+         assert(prev.last().isG() && !prev.last().hasId());
          
          cursor.remove();
          prev.last().append(cursor);
-         do_gdelete();
+         
+         // the gdelete_prev is not appropriate, because the last child of the MACRO could have no child
+         logger.debug("gdelete_prev_macro: i have to call do_gdelete_phantom_group");
+         do_gdelete_phantom_group();
+         
+         if (!frames.empty())
+           {
+             logger.debug("gdelete_prev_macro: after the do_gdelete_phantom_group, the frame in the stack has to be rightOpen");
+             cout << frames.top().entry.rightOpen  << endl;
+             logger.debug("gdelte_prev_macro: after the do_gdelete_phantom_group, the top element's pattern MUST be empty");
+             cout << frames.top().entry.pattern.empty() << endl;
+           }
+         else
+           logger.debug("gdelete_prev_macro: the do_gdelete_phantom_group has removed all frames in the stack");
+         
        }
       else if (entry.leftOpen)
         {
-         cout << "gdelete_prev: i have to delete a control element with leftOpen" << endl;
+         logger.debug("gdelete_prev_macro: i have to delete a control element with leftOpen");
+         // the leftOpen MACRO MUST have one and only one child, which MUST be a phantom group
+         // In this case, we do not have to push a frame in the stack, because we remove the 
+         // MACRO immediately, substituting it with the content of the phantom group.
+         // At the moment, i don't remove the last child of the phantom group, but
+         // i don't know if it's the correct behavior of the graphical deleting.
+         // To delete it, just remove the comment of the last instruction 
          assert(prev.first());
          assert(prev.first().isG());
          assert(prev.first() == prev.last());
+         
          TNode g = prev.first();
          g.remove();
          prev.replace(g.first(), TNode());
+         //do_gdelete();
        }
       else if (!entry.pattern.empty())
-        { 
+        {
          // we have to start removing a MACRO which accepts arguments.
          // a MACRO without child does not exist
          
-         cout << "gdelete_prev: i have to remove a MACRO with argument" << endl;
-
+         logger.debug("gdelete_prev_macro: i have to remove a MACRO with argument");
          assert(prev.size() >= 1);
 
+         // Differnt actions should be taken, based on the nature of the last child
+         // of the MACRO. We have to distinguish the case in which it's a delimited argument
+         // frome the one in which it's a not delimited argument.
          if (prev.last().isG() && !prev.last().hasId())
            {
-             // this means that the last child of the MACRO is a phantom group,
-             // which in turn means that it is a delimited argument
-             // so we have to ideally remove this delimiter
+             // the last argument of the MACRO is a delimited argumet. We ideally remove 
+             // the sequence of delimiters
+             logger.debug("gdelete_prev_macro: the last argument of the MACRO is delimited");
              cursor.remove();
              prev.last().append(cursor);
              // i have to push a frame with a correct value of pos
-             Frame frame(entry);
              assert(entry.previousParam(entry.pattern.size()) != entry.pattern.size());
              unsigned sequence_length = entry.pattern.size() - entry.previousParam(entry.pattern.size()) - 1;
-             frame.pos = entry.pattern.size() - sequence_length - 1;
-             frames.push(frame);
-             cout << "gdelete_prev: i have inserted a frame, it's pos is: " << frames.top().pos << endl;
+             unsigned p = entry.pattern.size() - sequence_length - 1;
+             frames.push(Frame(entry, p));
+             logger.debug("gdelete_prev_macro: i have inserted a frame, it's pos is: ");
+             cout << frames.top().pos << endl;
+             
            }
          else
            {
-             // in this case, the last child of the MACRO is 
-             // an argument which is NOT delimited, so i try to 
-             // remove it
-             cout << "gdelete_prev: i try to remove the last argumet of the MACRO" << endl;
+             // in this case, the last child of the MACRO is not a delimited argument, so we try 
+             // to remove it, but we have to take differnt actions if the MACRO is a table with rows or not. 
+             logger.debug("gdelete_prev_macro: the last argumet of the MACRO is not delimited, so itry to remove it");
              cursor.remove();
              if (entry.table == 1 && prev.last().is("row"))
                {
-                 // in this case should be appended to the group associated to 
+                 // in this case the cursor should be appended to the group associated to 
                  // the last cell of the last row of the table
+                 logger.debug("gdelete_prev_macro: but it is a table with rows, so i append the cursor at the end of the table");
                  assert(prev.last().last().is("cell") && prev.last().last().first().isG());
                  prev.last().last().first().append(cursor);
                }
-             else prev.append(cursor);
+             else
+               {
+                 logger.debug("gdelete_prev_macro: i append the cursor to the MACRO");
+                 prev.append(cursor);
+               }
+
+             frames.push(Frame(entry, entry.pattern.size()));
 
-             Frame frame(entry);
-             frame.pos = entry.pattern.size();
-             frames.push(frame);
+             logger.debug("gdelete_prev_macro: i've pushed a frame in the stack, and it's value of pos is ");
+             cout << frames.top().pos << endl;
              
-             if (cursor.prev()) gdelete_prev();
-             else do_gdelete();
+             if (cursor.prev())
+               {
+                 logger.debug("gdelete_prev_macro: i invoke the gdelete_prev");
+                 gdelete_prev();
+               }
+             else
+               {
+                 logger.debug("gdelete_prev_macro: i invoke the do_gdelete");
+                 do_gdelete();
+               }
+           } // end of the else of the if (prev.last().isG() && !prev.last().hasId())
 
-           }
+       } // end of if (!entry.pattern.empty())
+      else
+        {
+         // if we are here, the MACRO preceding the cursor, is not rightOpen, nor leftOpen,
+         // and has no pattern. It means that it has no childs.
+         // We can replace it with the cursor
+         logger.debug("gdelete_prev_macro: the MACRO is empty, i remove it");
+         assert(prev.size() == 0);
+         cursor.remove();
+         prev.replace(cursor);
        }
+    } // end of defined MACRO
+
+  logger.debug("gdelete_prev_macro: bye...");
+}
+
+void
+TPushParser::gdelete_prev()
+{
+  // if in this function, the prev of cursor does exist, also the parent and we want a graphical deleting.
+  
+  logger.debug("gdelete_prev: start...");
+
+  assert(cursor.prev());
+  assert(cursor.parent());
+
+  TNode prev = cursor.prev();
+
+  if (prev.is("i") || prev.is("o") || prev.is("n"))
+    {
+      gdelete_prev_token();
     }
-  else if (dictionary.find(prev["name"]).cls == TDictionary::UNDEFINED)
+  else if (prev.isSp() || prev.isSb())
     {
-      // The user wants to delete an undefined element.
-      // I suppose that he (or she) wants to delete it all
-      cursor.remove();
-      prev.replace(cursor);
+      gdelete_prev_script();
+    }
+  else if (prev.isG())
+    {
+      gdelete_prev_group();
+    }
+  else if (prev.isC())
+    {
+      // here we also treat the case in which the MACRO is a table
+      gdelete_prev_macro();
     }
   else 
     {
-      // not handled
+      // not handled. Future cases...
     }
-  
+
+  logger.debug("gdelete_prev: bye...");
 } // end of method
 
 void
@@ -667,6 +806,495 @@ TPushParser::rgreplace_futher(void)
     }
 }
 
+void
+TPushParser::do_gdelete_script()
+{
+  // If we are here, the cursor is child of a script and 
+  // means that a prev MUST exist and that there is only an 
+  // element preceding the cursor. The sp's (or sb's) parent 
+  // MUST NOT be a MACRO.
+  // The element preceding the cursor is the base of the script.
+
+  logger.debug("do_gdelete_script: start...");
+
+  assert(cursor.parent() && (cursor.parent().isSp() || cursor.parent().isSb()));
+  TNode parent = cursor.parent();
+         
+  assert(parent.size() == 2);
+  assert(parent.parent() && !parent.parent().isC());
+  
+  TNode prev = cursor.prev();
+  cursor.remove();
+  if (prev.isG() /*&& !prev.hasId()*/ && (prev.size() == 0))
+    {
+      // in this case, the script's base is a group with no elements, so i think 
+      // we have to remove the entire MACRO, replacing it with the cursor
+      prev.remove();
+      parent.replace(cursor);
+      
+      // if the new parent is a group with Id and the cursor is the only 
+      // element of this group, we have to remove it. This controls are made
+      // in the method rgreplace_futher().
+      if (cursor.parent().isG() && cursor.parent().hasId()) rgreplace_futher();
+    }
+  else
+    {
+      // in this case, the prev has to replace the script, 
+      // and the curosor has to be placed after the prev. 
+      assert(prev.hasId());
+      parent.replace(prev);
+      prev.parent().append(cursor);
+      // now prev should have a preceding element
+      assert(cursor.parent().size() > 1);
+    }
+  
+ logger.debug("do_gdelete_script: bye...");
+  
+} // end of method do_gdelet_script
+
+void
+TPushParser::do_gdelete_macro()
+{
+  // If we are here, the cursor is a child of a MACRO and this means
+  // that there is an open frame for the control element
+  // and this element is closed at either side (no leftOpen no rightOpen)
+  // and the MACRO was waiting for a non delimited argument, so 
+  // we can assert that frame.entry.pattern.size() >= 1
+  assert(cursor.parent() && cursor.parent().isC());
+  TNode parent = cursor.parent();
+  
+  assert(!frames.empty());
+  Frame& frame = frames.top();
+  assert(frame.entry.pattern.size() >= 1);
+
+  // we have to take different actions, based on if a preceding element exists 
+  // or not
+  logger.debug("do_gdelete_macro:");
+  TNode prev = cursor.prev();
+  if (!prev)
+    {
+      // in this case, a prev does not exist, so the actions of deleting means 
+      // that we have to remove the MACRO. So we have to pop the stack.
+      // Being here also means that the MACRO is waiting for the first argument
+      // (which is not delimited)
+      assert(frame.pos == 0);
+      parent.replace(cursor);
+      frames.pop();
+
+      // if the new parent is a group with Id, and has no elements other than the 
+      // cursor, we could remove it...but i'm not sure
+      if (cursor.parent() && cursor.parent().isG() && cursor.parent().hasId())
+       rgreplace_futher();
+      else if (cursor.parent().isC())
+        {
+         // We have assumed that a MACRO cannot be a MACRO's child. 
+         // At the moment, this assumption is valid, but in a future 
+         // it could be false.
+         assert(!frames.empty());
+         Frame& frame = frames.top();
+         assert(frame.pos > 0);
+         frame.pos--;
+       }
+    }
+  else
+    {
+      // we have to control if prev is a delimited argument or not.
+      if (prev.isG() && !prev.hasId())
+        {
+         // in this case, prev is a delimited argument, so we have 
+         // to ideally remove the sequence of delimiters
+         Frame& frame = frames.top();
+         assert(frame.pos > 1);
+         logger.debug("do_gdelete_macro: the pos of the frame is: ");
+         cout << frame.pos << endl;
+         logger.debug("do_gdelete_macro: the pattern size of the entry is");
+         cout << frame.entry.pattern.size() << endl;
+         logger.debug("do_gdelete_macro: the prev param is at");
+         cout << frame.entry.previousParam(frame.pos) << endl;
+         cursor.remove();
+         prev.append(cursor);
+         assert(frame.entry.previousParam(frame.pos) != frame.entry.pattern.size());
+         unsigned sequence_length = frame.pos - frame.entry.previousParam(frame.pos) - 1;
+         assert(sequence_length);
+         frame.pos = frame.pos - sequence_length - 1;
+       }
+      else
+        {
+         // the prev is not a delimited argument, so we have to try to remove it. 
+         // I told "try" because the prev can be a group or something that 
+         // a simple delete cannot remove completely
+         gdelete_prev();
+       }
+    }
+
+  logger.debug("do_gdelete_macro: bye...");
+}
+
+void
+TPushParser::do_gdelete_groupId()
+{
+  // if we are here, the cursor's parent is a group with Id
+  assert(cursor.parent() && cursor.parent().isG() && cursor.parent().hasId());
+  TNode parent = cursor.parent();
+
+  // we have to take different actions based on if the cursor has a preceding 
+  // element or not
+  TNode prev = cursor.prev();
+  if (prev)
+    {
+      // the cursor has a preceding element, so we try to remoev it
+      gdelete_prev();
+
+      // We control if the group has to be removed, because the cursor 
+      // could be the only element of the group.
+      if ((parent.first() == cursor) && parent.isG() && parent.hasId())
+       rgreplace_futher();
+      
+    }
+  else
+    {
+      // the cursor has no preceding elements, so we have to remove the 
+      // group.
+      rgreplace_futher();
+      
+      // i have to re-start the process, because it' a graphical delete
+      do_gdelete();
+    }
+
+  logger.debug("do_gdelete_groupId: bye...");
+  
+} // end of method do_gdelete_groupId()
+
+void
+TPushParser::do_gdelete_phantom_group()
+{
+  // if we are here, the cursor MUST be a child of a 
+  // phantom group.
+  logger.debug("do_gdelete_phantom_group: start");
+  assert(cursor.parent() && cursor.parent().isG() && !cursor.parent().hasId());
+
+  TNode parent = cursor.parent();
+
+  // now we have to control if the cursor has a preceding element or not
+  TNode prev = cursor.prev();
+  if (prev)
+    {
+      // the cursor has a preceding element, so we try to remove it
+      logger.debug("do_gdelete_phantom_group: i have to call the gdelete_prev()");
+      gdelete_prev();
+      logger.debug("do_gdelete_phantom_group: gdelete_prev terminated");
+
+      if (parent.size() == 1 && parent.parent().isSp())
+        {
+         logger.debug("do_gdelete_phantom_group: i have to remove a phantom group which is a child of a sp");
+         // in this case the gdelete_prev has removed the only element preceding the cursor.
+         // If the phantom group is a sp's child, it means that the user has removed all \' in the 
+         // phantom group. I think, we can remove the phamtom group and the sp element.
+         cursor.remove();
+         parent.replace(cursor);
+         // now we have a sp element with two children: the first child (we don't know nothing about it)
+         // and the cursror.
+         assert(cursor.parent().size() == 2);
+         
+         // to delete the script we can invoke the do_gdelete_script(), which will do all controls we need
+         do_gdelete_script();
+       }
+      else if (parent.parent().isSp())
+        {
+         // in this case we have to place the cursor after the sp element
+         logger.debug("do_gdelete_phantom_group: the sequence of \' is not terminated, so i place the cursor after the sp element");
+         cursor.remove();
+         assert(parent.parent().parent());
+         parent.parent().parent().append(cursor);
+       }
+    }
+  else
+    {
+      // in this case the cursor is the only element of the phantom group,
+      // so we have to remove it. But, a phantom group has a special role, 
+      // so we have to control the grand futher of the cursor.
+      TNode gfuther = parent.parent();
+      if (!gfuther)
+        {
+         // If here, the TML tree is in an inconsistent state
+         logger.error("do_gdelete_phantom: TML tree in a inconsistent state");
+       }
+      else if (gfuther.isC())
+        {
+         // in this case the phantom group is child of a MACRO.
+         // We have to control the nature of this MACRO.
+         logger.debug("do_gdelete_phantom_group: i have to remove a phantom group which is a child of a MACRO");
+         assert(!frames.empty());
+          Frame& frame = frames.top();
+         
+         if (frame.entry.leftOpen && frame.entry.rightOpen)
+           {
+             // in this case, the cursor is in the second and last child 
+             // of the MACRO. We can assert that the grand futher has two 
+             // children. which are both phantom group
+             logger.debug("do_gdelete_phantom_group: the MACRO is leftOpen and rigthOpen");
+             assert(gfuther.size() == 2);
+             assert((gfuther.last() == parent) && (gfuther.first().isG() && !gfuther.first().hasId()));
+             assert(frame.pos == 0);
+             
+             TNode ggfuther = gfuther.parent();
+             assert(ggfuther);
+             cursor.remove();
+             parent.remove();
+             // i have to replace the gfuther with the elements of its first child
+             gfuther.replace(gfuther.first().first(), TNode());
+             logger.debug("do_gdelete_phantom_group: i have removed the control element, and replaced it with its first child");
+             ggfuther.append(cursor);
+             logger.debug("do_gdelete_phantom_group: cursor appended to the grand grand futher");
+             // now we have the situation preceding the insertion of the MACRO leftOpen and rightOpen
+             // this MACRO no longer exists.
+             frames.pop();
+           }
+         else if (frame.entry.rightOpen)
+           {
+             // the user has inserted a MACRO rightOpen. Since the cursor is the 
+             // only child of the MACRO, the user want to remove it. 
+             // We can assert that cursor's parent is the only child of the MACRO
+             logger.debug("do_gdelete_phantom_group: the MACRO is rightOpen only");
+             assert(gfuther.size() == 1);
+             assert(frame.pos == 0);
+             cursor.remove();
+             parent.remove();
+             gfuther.replace(cursor);
+             
+             // now we have the situation preceding the MACRO rightOpen, so i have to pop the frame
+             frames.pop();
+           }
+         else if (frame.entry.leftOpen)
+           {
+             // i think this situation will never occur
+             // but it can be recovered in some way
+             logger.error("the parser has generated a wrong TML tree");
+           }
+         else if (!frame.entry.pattern.empty())
+           {
+             // the MACRO accepts arguments, and the phantom group in which 
+             // the cursor is, rappresents a delimited argument
+             // We have to control if the cursor's parent has a preceding element, 
+             // or not.
+             logger.debug("do_gdelete_phantom_group: the MACRO accepts arguments");
+             logger.debug("do_gdelete_phantom_group: entry pattern has size:");
+             cout << frame.entry.pattern.size() << endl;
+             TNode uncle = parent.prev();
+             if (!uncle)
+               {
+                 // the parent is the only element of the MACRO. 
+                 // we can assert that frame.pos == 0.
+                 // In this case we can replace the MACRO with the cursor
+                 assert(frame.pos == 0);
+                 cursor.remove();
+                 parent.remove();
+                 gfuther.replace(cursor);
+                 frames.pop();
+               }
+             else
+               {
+                 // the parent has a preceding element. Now we have 
+                 // to control if the uncle is a delimited argument or not.
+                 if (uncle.isG() && !uncle.hasId())
+                   {
+                     // the  uncle is a delimited argument. So we have to ideally
+                     // remove the sequrnce of delimiters.
+                     assert(frame.pos > 1);
+                     unsigned sequence_length = frame.pos - frame.entry.previousParam(frame.pos) - 1;
+                     assert(frame.entry.previousParam(frame.pos) != frame.entry.pattern.size());
+                     assert(sequence_length);
+                     // sequence_length is the length of the delimiters sequence which separates
+                     // the current parameter and the previous parameter
+                     frame.pos = frame.pos - sequence_length - 1;
+                     cursor.remove();
+                     parent.remove();
+                     uncle.append(cursor);
+                   }
+                 else
+                   {
+                     // the uncle is a not delimited argument, so we try to remove it.
+                     cursor.remove();
+                     parent.replace(cursor);
+                     parent = cursor.parent(); // i update the parent (it should be the MACRO)
+                     assert(parent.isC());
+
+                     // now i try to remove the uncle (now it' the preceding element)
+                     gdelete_prev();
+                   }
+               } // this is the else's end, that handles the case in which an uncle exists
+           } // end of if (!frame.entry.pattern.empty())
+         else
+           {
+             // the entry has no arguments, is not rightOpen and is not leftOpen.
+             logger.warning("do_gdelete_phantom_group: TML tree in a strange state");
+             if (gfuther.size() == 1)
+               {
+                 cursor.remove();
+                 parent.remove();
+                 gfuther.replace(cursor);
+               }
+             else
+               {
+                 logger.debug("do_gdelete_phantom_group: TML tree in a very strange state");
+                 cursor.remove();
+                 gfuther.replace(cursor);
+               }
+           }
+       } // end of if (gfuther.isC())
+      else if (gfuther.is("cell"))
+        {
+         // we have to handle the case where cursor'grand futher is a cell element.
+         // The tables are control sequece, so there is a frame in the stack
+         assert(!frames.empty());
+         assert(frames.top().pos == 1);
+         assert(frames.top().entry.table == 1);
+         
+         // a cell MUST be child of row element, which in turn MUST be child of an element 
+         // havin attribute table.
+         assert(gfuther.parent() && gfuther.parent().is("row") && gfuther.parent().parent());
+         TNode row = gfuther.parent();
+         
+         // in this case the cell has no element, so the user wants to delete this cell.
+         TNode prev_cell = gfuther.prev();
+         cursor.remove();
+         parent.remove();
+         gfuther.remove();
+         // now the cell no longer exists
+
+         if (!prev_cell)
+           {
+             // i this case, the cell is the only cell in the row.
+             // So, i assume that the user wants to delete the entire row.
+             TNode table = row.parent();
+             TNode prev_row = row.prev();
+             row.remove();
+             
+             if (!prev_row)
+               {
+                 // the row was the only child of the table. 
+                 // I think have to delete the entire table
+                 assert(table.parent());
+                 TNode parent_table = table.parent();
+                 table.remove();
+                 frames.pop();
+                 parent_table.append(cursor);
+               }
+             else
+               {
+                 // there are other rows (one at least)
+                 assert(prev_row.is("row"));
+                 assert(prev_row.last());
+                 TNode last_cell = prev_row.last();
+                 assert(last_cell.is("cell"));
+                 assert(last_cell.size() == 1);
+                 assert(last_cell.first().isG() && !last_cell.first().hasId());
+                 last_cell.first().append(cursor);
+               }
+           } // end of if (!prev_cell)
+         else
+           {
+             // being here means that there is a previous cell,
+             // so we append the cursor to group.
+             assert(prev_cell.size() == 1);
+             assert(prev_cell.first().isG() && !prev_cell.first().hasId());
+             prev_cell.first().append(cursor);
+           }
+       } // end of if (gfuther.is("cell"))
+      else if (gfuther.isSp())
+        {
+         // in this case, the user pushed a \'. So this phantom group 
+         // contained a sequence of \'. 
+         // Maybe in this part will never be used, because, if we delete last \' in the 
+         // phantom group, we remove the phantom group also
+         //
+         // In any case, if we are here we have two choice: 
+         //   delete the phantom group;
+         //   delete the superscript.
+       }
+      else
+        {
+         // cursor' grand futher is undefined
+         logger.error("do_gdelete_phantom_group: TML tree in a unknown state");
+       }
+    } // end of the else of the if (prev)
+
+  if (!frames.empty())
+    {
+      logger.debug("do_gdelete_phantom_group: the stack is not empty");
+      logger.debug("do_gdelte_phanto_group: is the top element rightOpen?");
+      cout << frames.top().entry.rightOpen << endl;
+      logger.debug("do_gdelte_phanto_group: is the top element'pattern empty?");
+      cout << frames.top().entry.pattern.empty()  << endl;
+    }
+  logger.debug("do_gdelete_phantom_group: bye...");
+}
+
+
+void
+TPushParser::do_gdelete()
+{
+  logger.debug("do_gdelete: start");
+  // we have to handle the case in wich the cursor has a parent or not
+  if (!cursor.parent())
+    {
+      // it's not a good situation...at the moment we do not take actions
+      logger.error("TML tree not well structured");
+    }
+  else
+    {
+      // a parent exists. We have to take differnt actions, based on the nature of 
+      // the parent
+      TNode parent = cursor.parent();
+      if (parent.is("math"))
+        {
+         // we ca do two thing...remove the math mode (it implies controlling the display attribute), do nothing
+         // At the moment, the user's will of deleting is simply ignored
+         logger.error("TML tree not well structured");
+       }
+      else if (parent.isG())
+        {
+         // the cursor's parent is a group. We have to control if it's a phantom group or not
+         logger.debug("do_gdelete: the cursor's parent is a group");
+         if (parent.hasId())
+           {
+             logger.debug("do_gdelete: which has Id");
+             do_gdelete_groupId();
+           }
+         else
+           {
+             logger.debug("do_gdelete: which is a phantom group");
+             do_gdelete_phantom_group();
+           }
+       } // end of parent is group
+      else if (parent.isC())
+        {
+         cout << "the cursor's parent is a MACRO" << endl;
+         do_gdelete_macro();
+       } // end of parent is a MACRO
+      else if (parent.isSp() || parent.isSb())
+        {
+         cout << "the cursor's parent is a script" << endl;
+         do_gdelete_script();
+       } // end of parent is sp or sb
+    } // end of the else which consider the case in which parent exists
+  
+  if (!cursor.parent())
+    logger.debug("do_gdelete: the cursro has no parent -> paolo is stupid");
+
+  if (!frames.empty())
+    {
+      logger.debug("do_gdelete: the stack is not empty");
+      logger.debug("do_gdelete: is the top element rightOpen?");
+      cout << frames.top().entry.rightOpen << endl;
+      logger.debug("do_gdelete: is the top element'pattern empty");
+      cout << frames.top().entry.pattern.empty() << endl;
+    }
+  logger.debug("do_gdelete: bye...");
+  
+} // end of method do_gdelete
+
+/*
 void
 TPushParser::do_gdelete()
 {
@@ -722,8 +1350,9 @@ TPushParser::do_gdelete()
 
                          // being here means that there is a frame in the stack
                          assert(!frames.empty());
-                         cout << "do_gdelete: i have to remove a phantom group whuch is a child of a MACRO" << endl;
+                         cout << "do_gdelete: i have to remove a phantom group which is a child of a MACRO" << endl;
                          Frame& frame = frames.top();
+                         cout << frame.entry.leftOpen << frame.entry.rightOpen << endl;
                          if (frame.entry.leftOpen && frame.entry.rightOpen)
                            {
                              // in this case, the cursor is in the second and last child 
@@ -778,6 +1407,7 @@ TPushParser::do_gdelete()
                                {
                                  // in this case, we can assert that frame in the stack has 
                                  // pos greater than 0
+                                 cout << "this is the assert that fails" << endl;
                                  assert(frame.pos > 0);
                                
                                  // cursor's uncle does exist. we have to control 
@@ -970,7 +1600,7 @@ TPushParser::do_gdelete()
          
          TNode prev = cursor.prev();
          cursor.remove();
-         if (prev.isG() /*&& !prev.hasId()*/ && (prev.size() == 0))
+         if (prev.isG()*/ /*&& !prev.hasId()*/ /* && (prev.size() == 0))
            {
              prev.remove();
              parent.replace(cursor);
@@ -1002,6 +1632,7 @@ TPushParser::do_gdelete()
     }
 
 } // end of method
+*/
 
 void
 TPushParser::process(const TToken& token)
@@ -1030,16 +1661,18 @@ TPushParser::process(const TToken& token)
 void
 TPushParser::push(const TToken& token)
 {
-  cerr << "TPushParser::push " << token.value << " (cat: " << token.category << ")" << endl;
+  logger.debug("TPushParser::push " + token.value + " (cat: ");
+  cout << token.category << ")" << endl;
 
   if (token.category == TToken::GDELETE)
     {
-      cout << "push: i have to process a token with category member = GDELETE" << endl;
+      logger.debug("push: i have to process a token with category member = GDELETE");
       process(token);
     }
-  else if ((doc.root().first() && doc.root().first().is("math")) || token.category == TToken::SHIFT)
+  else
     {
 
+      logger.debug("push: i get the cursor's parent");
       TNode parent = cursor.parent();
       // If the cursor has no parent then it is detached from the editing
       // tree, which means this token will be ignored
@@ -1052,13 +1685,19 @@ TPushParser::push(const TToken& token)
         if (parent.isG() && !parent.hasId() && parent.parent().isC())
           {
            // There must be an open frame, for the grand-parent is a control sequence
+           logger.debug("push: cursor'parent is a phantom group, and this group has a MACRO as parent");
+           logger.debug("push: i assert that !frames.empty()");
            assert(!frames.empty());
+           logger.debug("push: this assert is OK");
+           logger.debug("push: now i take the top element of the stack");
            Frame& frame = frames.top();
+           logger.debug("push: now i've got the top element");
            if (!frame.entry.pattern.empty())
              {
                // The entry pattern is not empty. By our conventions this means
                // the entry cannot be open at either end, hence we are parsing
                // a delimited argument
+               logger.debug("push: the frame.entry accepts arguments");
                assert(frame.pos + 1 < frame.entry.pattern.size());
                assert(frame.entry.pattern[frame.pos + 1].category != TToken::PARAMETER);
                if (frame.entry.pattern[frame.pos + 1] == token)
@@ -1122,8 +1761,11 @@ TPushParser::push(const TToken& token)
                // entry. What happens if we actually are in the left side?
                // This could happen only when re-editing an entered expression
                // We'll see...
+               logger.debug("push: the frame.entry has no arguments, so i assert that i's rightOpne");
                assert(frame.entry.rightOpen);
+               logger.debug("push: this assert is OK, now i process the token");
                process(token);
+               logger.debug("push: the token has been processed");
              }
           }
         else if (parent.isC())
@@ -1145,6 +1787,7 @@ TPushParser::push(const TToken& token)
                    // it will be important for the parser to know that the entry
                    // has been completed in order to place the cursor correctly
                    // in the next position
+                   logger.debug("TPushParser.push: we should be here");
                    frame.pos++;
                    process(token);
                  }
@@ -1178,21 +1821,20 @@ TPushParser::push(const TToken& token)
         {
           cout << "ignored token" << endl;
         }
-      
-      //if (listener) listener->callback(doc); //it shoul be repristened if you remove the comment in the else above
 
-    } // this end corresponds to the if ((doc.root().first() && doc.root().first().is("math")) || token.category == TToken::SHIFT)
-  else
-    {
-      // there is no math element
-      // In this case, i think we have to emit an error
-      cout << "push: ignored token...you have to enter in math mode...insert $" << endl;
-    }
+    } // this end corresponds to the else of the if (token.category == TToken::GDELETE)
 
   if (factory) factory->documentModified(doc);
 
   if (frames.empty()) cout << "stack vuoto" << endl;
-  else cout << "stack non vuoto" << endl;
+  else
+    {
+      logger.debug("push: the stack is not empty");
+      logger.debug("push: is the top element rightOpen?");
+      cout << frames.top().entry.rightOpen << endl;
+      logger.debug("push: is the pattern empty");
+      cout << frames.top().entry.pattern.empty() << endl;
+    }
 }
 
 void