]> matita.cs.unibo.it Git - helm.git/commitdiff
Added the special deletion. Pressing backspace, the user has a normal deletion
authorPaolo Marinelli <paolo.marinelli@unibo.it>
Mon, 24 Feb 2003 11:07:47 +0000 (11:07 +0000)
committerPaolo Marinelli <paolo.marinelli@unibo.it>
Mon, 24 Feb 2003 11:07:47 +0000 (11:07 +0000)
(which can be either graphical or textual). Pressing backspace + alt, the user
has a special deletion (which can be either textual or graphical).
To implement this feature, all parser's methods concerning the deletion have
been modified: now, all of them have a boolean parameter, which indicates which
kind of deletion the method has to operate.
All methods' names have been changed: the word gdelete has been substitued with
drop.

helm/DEVEL/mathml_editor/src/APushLexer.hh
helm/DEVEL/mathml_editor/src/APushParser.hh
helm/DEVEL/mathml_editor/src/LPushLexer.cc
helm/DEVEL/mathml_editor/src/LPushLexer.hh
helm/DEVEL/mathml_editor/src/TPushLexer.cc
helm/DEVEL/mathml_editor/src/TPushLexer.hh
helm/DEVEL/mathml_editor/src/TPushParser.cc
helm/DEVEL/mathml_editor/src/TPushParser.hh
helm/DEVEL/mathml_editor/src/TTokenizer.cc
helm/DEVEL/mathml_editor/src/TTokenizer.hh

index 342d18fe919dd4241408f68fc79f00bbbfc8059e..263da199d0311290b6388486da72575336e5b19b 100644 (file)
@@ -9,7 +9,7 @@ public:
   virtual ~APushLexer() { };
 
   virtual void push(char) = 0;
-  virtual void drop(bool = false) = 0;
+  virtual void drop(bool) = 0;
   virtual void reset(void) = 0;
   virtual bool error(void) const = 0;
 
index 5344b7272fdca474f9a79db9a411fa2464c92608..aa0d10a43022996a4f9e5b22df6d0f8dec6ca9d3 100644 (file)
@@ -35,7 +35,7 @@ public:
 
   virtual void reset(void) = 0;
   virtual void push(const class TToken&) = 0;
-  virtual std::string drop(void) = 0;
+  virtual std::string drop(bool) = 0;
   virtual void setCursorHint(const std::string&) = 0;
   virtual bool hideCursor(void) = 0;
   virtual bool showCursor(void) = 0;
index 6ee43b3e9fde2d88b74612465128d9e4736e3e85..a41b016dda89e79fb61fc4236328606023b20138 100644 (file)
@@ -38,11 +38,7 @@ LPushLexer::transaction(char ch, State newState)
     case ' ': parser.push(TToken(TToken::SPACE, ch)); break;
     case '~': parser.push(TToken(TToken::ACTIVE, ch)); break;
     case '%': parser.push(TToken(TToken::COMMENT)); break;     
-    default:
-      if (isalpha(ch)) parser.push(TToken(TToken::LETTER, ch));
-      else if (isdigit(ch)) parser.push(TToken(TToken::DIGIT, ch));
-      else parser.push(TToken(TToken::OTHER, ch));
-      break;
+    default: parser.push(TToken(TToken::OTHER, ch)); break;
     }
   state = newState;
 }
@@ -59,7 +55,17 @@ LPushLexer::push(char ch)
       else if (isalpha(ch))
        {
          buffer.push_back(ch);
-         state = LONG_IDENTIFIER;
+         state = IDENTIFIER;
+       }
+      else if (isspace(ch))
+        {
+         // we translate this space in a macro.
+         parser.push(TToken(TToken::CONTROL, "space"));
+       }
+      else if (isdigit(ch))
+        {
+         buffer.push_back(ch);
+         state = NUMBER;
        }
       else transaction(ch, ACCEPT);
       break;
@@ -70,6 +76,12 @@ LPushLexer::push(char ch)
          state = MACRO;
        }
       else if (ch == -1) error();
+      else if (isdigit(ch))
+        {
+         // in this case, the previous '\' is ignored
+         buffer.push_back(ch);
+         state = NUMBER;
+       }
       else
        {
          parser.push(TToken(TToken::CONTROL, ch));
@@ -97,25 +109,30 @@ LPushLexer::push(char ch)
          buffer.erase();
          state = ACCEPT;
        }
-      else
-       {
+      else if (isspace(ch))
+        {
          parser.push(TToken(TToken::CONTROL, buffer));
          buffer.erase();
-         if (isspace(ch)) state = IGNORE_SPACE;
-         else transaction(ch, ACCEPT);
+         /*
+          * we comment this line, because a space after a macro 
+          * is useful to exit from a macro
+         //parser.push(TToken(TToken::CONTROL, ";"));
+         */
+         state = ACCEPT;
        }
-      break;
-    case IGNORE_SPACE:
-      if (ch == '\\') state = ESCAPE;
-      else if (ch == '#') state = PARAMETER;
-      else if (isspace(ch)) ;
-      else if (ch == -1) state = ACCEPT;
-      else if (isalpha(ch))
+      else if (isdigit(ch))
         {
+         parser.push(TToken(TToken::CONTROL, buffer));
+         buffer.erase();
          buffer.push_back(ch);
-         state = LONG_IDENTIFIER;
+         state = NUMBER;
        }
-      else transaction(ch, ACCEPT);
+      else
+        {
+         parser.push(TToken(TToken::CONTROL, buffer));
+         buffer.erase();
+          transaction(ch, ACCEPT);
+        }
       break;
     case PARAMETER:
       if (ch == -1) error();
@@ -125,7 +142,7 @@ LPushLexer::push(char ch)
          state = ACCEPT;
        }
       break;
-    case LONG_IDENTIFIER:
+    case IDENTIFIER:
       if (ch == -1)
         {
          parser.push(TToken(TToken::LETTER, buffer));
@@ -139,17 +156,9 @@ LPushLexer::push(char ch)
       else if (isspace(ch))
         {
          parser.push(TToken(TToken::LETTER, buffer));
-
-         // the parser ignores spaces. But in this case, the space 
-         // is a significant. So, we transform this space in the MACRO 
-         // \; which will not be ignored. 
-         // This is not a good solution. Having a special token, that will be 
-         // interpreted as "function application" is a better one.
-         buffer.erase();
-         buffer = ";";
-         parser.push(TToken(TToken::CONTROL, buffer));
          buffer.erase();
-         state = IGNORE_SPACE;
+         parser.push(TToken(TToken::CONTROL, "space"));
+         state = ACCEPT;
        }
       else if (ch == '\\')
         {
@@ -157,6 +166,12 @@ LPushLexer::push(char ch)
          buffer.erase();
          state = ESCAPE;
        }
+      else if (ch == '#')
+        {
+         parser.push(TToken(TToken::LETTER, buffer));
+         buffer.erase();
+         state = PARAMETER;
+       }
       else
         {
          parser.push(TToken(TToken::LETTER, buffer));
@@ -164,6 +179,47 @@ LPushLexer::push(char ch)
          transaction(ch, ACCEPT);
        }
       break;
+    case NUMBER:
+      if (isdigit(ch)) buffer.push_back(ch);
+      else if (isspace(ch))
+        {
+         parser.push(TToken(TToken::DIGIT, buffer));
+         buffer.erase();
+         parser.push(TToken(TToken::CONTROL, "space"));
+         state = ACCEPT;
+       }
+      else if (isalpha(ch))
+        {
+         parser.push(TToken(TToken::DIGIT, buffer));
+         buffer.erase();
+         buffer.push_back(ch);
+         state = IDENTIFIER;
+       }
+      else if (ch == -1)
+        {
+         parser.push(TToken(TToken::DIGIT, buffer));
+         buffer.erase();
+         state = ACCEPT;
+       }
+      else if (ch == '\\')
+        {
+         parser.push(TToken(TToken::DIGIT, buffer));
+         buffer.erase();
+         state = ESCAPE;
+       }
+      else if (ch == '#')
+        {
+         parser.push(TToken(TToken::DIGIT, buffer));
+         buffer.erase();
+         state = PARAMETER;
+       }
+      else
+        {
+         parser.push(TToken(TToken::DIGIT, buffer));
+         buffer.erase();
+         transaction(ch, ACCEPT);
+       }
+      break;
     default:
       assert(0);
       break;
@@ -174,7 +230,8 @@ LPushLexer::push(char ch)
     case ESCAPE: parser.setCursorHint("\\"); break;
     case MACRO: parser.setCursorHint("\\" + buffer); break;
     case PARAMETER: parser.setCursorHint("#"); break;
-    case LONG_IDENTIFIER: parser.setCursorHint(buffer); break;
+    case IDENTIFIER: parser.setCursorHint(buffer); break;
+    case NUMBER: parser.setCursorHint(buffer); break;
     default: parser.setCursorHint(""); break;
     }
 }
@@ -187,13 +244,23 @@ LPushLexer::drop(bool alt)
   switch (state)
     {
     case ACCEPT:
-    case IGNORE_SPACE:
-      restore = parser.drop();
+      restore = parser.drop(alt);
       if (restore.length() > 0 && restore[0] == '\\')
        {
+         cout << restore << endl;
          buffer = std::string(restore, 1, restore.length() - 1);
          state = (buffer.length() > 0) ? MACRO : ESCAPE;
        }
+      else if (restore.length() > 0 && isdigit(restore[0]))
+        {
+         buffer = restore;
+         state = NUMBER;
+       }
+      else if (restore.length() > 0 && isalpha(restore[0]))
+        {
+         buffer = restore;
+         state = IDENTIFIER;
+       }
       break;
     case ESCAPE:
       state = ACCEPT;
@@ -203,13 +270,20 @@ LPushLexer::drop(bool alt)
       else buffer.erase(buffer.length() - 1, 1);
       if (buffer.length() == 0) state = ESCAPE;
       break;
-    case LONG_IDENTIFIER:
-      buffer.erase(buffer.length() - 1, 1);
+    case IDENTIFIER:
+      if (alt) buffer.erase(); 
+      else buffer.erase(buffer.length() - 1, 1);
+      if (buffer.length() == 0) state = ACCEPT;
+      break;
+    case NUMBER:
+      if (alt) buffer.erase();
+      else buffer.erase(buffer.length() - 1, 1);
       if (buffer.length() == 0) state = ACCEPT;
       break;
     case PARAMETER:
     default:
-      assert(0);
+      //assert(0);
+      error();
       break;
     }
 
@@ -218,6 +292,8 @@ LPushLexer::drop(bool alt)
     case ESCAPE: parser.setCursorHint("\\"); break;
     case MACRO: parser.setCursorHint("\\" + buffer); break;
     case PARAMETER: parser.setCursorHint("#"); break;
+    case IDENTIFIER: parser.setCursorHint(buffer); break;
+    case NUMBER: parser.setCursorHint(buffer); break;
     default: parser.setCursorHint(""); break;
     }
 }
index 03ba29c0284b475353853a4494d97ee3b4f816e2..db6dfb1bc69528d995075395c052c29fa1c99d41 100644 (file)
@@ -13,7 +13,7 @@ public:
   virtual ~LPushLexer() { };
 
   virtual void push(char);
-  virtual void drop(bool = false);
+  virtual void drop(bool);
   virtual void reset(void);
   virtual void flush(void);
   virtual bool error(void) const;
@@ -24,9 +24,9 @@ private:
       ACCEPT,
       ESCAPE,
       MACRO,
-      IGNORE_SPACE,
       PARAMETER,
-      LONG_IDENTIFIER
+      IDENTIFIER,
+      NUMBER
     };
 
   void transaction(char, State);
index c8d04f1bd4354401a4de38b2b83c18c101d231fb..73ff25c613005785daf9d2284cf7094c9ce8b99b 100644 (file)
@@ -138,7 +138,7 @@ TPushLexer::drop(bool alt)
     {
     case ACCEPT:
     case IGNORE_SPACE:
-      restore = parser.drop();
+      restore = parser.drop(alt);
       if (restore.length() > 0 && restore[0] == '\\')
        {
          buffer = std::string(restore, 1, restore.length() - 1);
index f2f409158b0a71388efc1d8f18bdf4f803eae803..c8a99eddee05ba7a1ea093b9f4a613090e5c053c 100644 (file)
@@ -13,7 +13,7 @@ public:
   virtual ~TPushLexer() { };
 
   virtual void push(char);
-  virtual void drop(bool = false);
+  virtual void drop(bool);
   virtual void reset(void);
   virtual void flush(void);
   virtual bool error(void) const;
index 63206ea7db3475300c2ef68b564cad6cbe5a393a..ad439908c66a036dd5d0767901ace9c8ba39b477 100644 (file)
@@ -44,7 +44,7 @@ TPushParser::PRIME() const
   else return "?";
 }
 
-void
+bool
 TPushParser::do_begin()
 {
   TNode parent = cursor.parent();
@@ -64,6 +64,7 @@ TPushParser::do_begin()
       cursor.replace(g);
       g.append(cursor);
     }
+  return true;
 }
 
 bool
@@ -125,7 +126,7 @@ TPushParser::correctBrace()
   return ok;
 }
 
-void
+bool
 TPushParser::do_end()
 {
   TNode parent = cursor.parent();
@@ -134,6 +135,7 @@ TPushParser::do_end()
       // normal closing brace for an explicitly open group
       cursor.remove();
       advance(parent);
+      return true;
     }
   else if (parent && parent.isG() && parent.parent() && parent.parent().is("cell"))
     {
@@ -143,6 +145,7 @@ TPushParser::do_end()
       assert(row && row.is("row"));
       assert(row.parent());
       advance(row);
+      return true;
     }
   else if (parent && parent.isG() && !parent.hasId() && parent.parent() && !parent.parent().is("math"))
     {
@@ -167,24 +170,27 @@ TPushParser::do_end()
                {
                  // the '}' is not correct
                  logger.warning("nothing to close");
+                 return false;
                }
              else
                {
                  cursor.remove();
                  advance(parent);
+                 return true;
                }
-             
            }
          else
            {
-             logger.error("closing brace ignored");
+             logger.warning("closing brace ignored");
+             return false;
            }
        }
       else
         {
-         // at the moment, a phantom group with cursor can be a MACRO's child or a cell's child, and these cases
+         // at the moment, a phantom group with the cursor inside can be a MACRO's child or a cell's child, and these cases
          // are handled in other blocks of code.
          logger.error("do_end: strange TML tree");
+         return false;
        }
     }
   else
@@ -192,52 +198,12 @@ TPushParser::do_end()
       // In this case, there is a redundant '}', so we can ignore it and 
       // emit an error
       logger.warning("There is so no corresponding'{'");
+      return false;
       //assert(0);
     }
 }
 
-
-/*
-void
-TPushParser::do_end()
-{
-  TNode parent = cursor.parent();
-  if (parent && parent.isG() && parent.hasId())
-    {
-      // normal closing brace for an explicitly open group
-      cursor.remove();
-      advance(parent);
-    }
-  else if (parent && parent.isG() && parent.parent() && parent.parent().is("cell"))
-    {
-      assert(!frames.empty());
-      // closing brace for a structure in which & or \cr have been used
-      TNode row = parent.parent().parent();
-      assert(row && row.is("row"));
-      TNode table = row.parent();
-      assert(table);
-      advance(row);
-    }
-  else if (parent && parent.isG() && !parent.hasId() && parent.parent() && !parent.parent().is("math"))
-    {
-      // 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);
-    }
-  else
-    {
-      // In this case, there is a redundant '}', so I think we can ignore it and 
-      // emit an error
-      logger.warning("There is so no corresponding'{'");
-      //assert(0);
-    }
-}
-*/
-
-void
+bool
 TPushParser::do_shift()
 {
   TNode parent = cursor.parent();
@@ -249,6 +215,7 @@ TPushParser::do_shift()
       cursor.replace(math);
       math.append(g);
       g.append(cursor);
+      return true;
     }
   else if (parent.isG() && !parent.hasId() && parent.parent() && parent.parent().is("math"))
     {
@@ -260,12 +227,14 @@ TPushParser::do_shift()
            {
              // one math shift is enough to close it
              cursor.remove();
+             return true;
            }
          else
            {
              // we need two closing math shifts
              //cursor.remove(); ??
              parent.parent().append(cursor);
+             return true; // ???
            }
        }
       else if (parent.parent()["display"] != "1")
@@ -273,23 +242,27 @@ TPushParser::do_shift()
          // there is nothing before the cursor, and the math is not
          // in display mode, so this must be a double math shift
          parent.parent()["display"] = "1";
+         return true;
        }
       else
        {
          parent.parent().append(cursor);
+         return true;
        }
     }
   else if (parent.is("math"))
     {
       cursor.remove();
+      return true;
     }
   else
     {
-      logger.error("parser: math shift");
+      logger.warning("parser: math shift");
+      return false;
     }
 }
 
-void
+bool
 TPushParser::do_align()
 {
   TNode parent = cursor.parent();
@@ -302,6 +275,7 @@ TPushParser::do_align()
       row.append(cell);
       cell.append(g);
       g.append(parent.first(), cursor);
+      return true;
     }
   else if (parent && parent.isG() && parent.parent().is("cell"))
     {
@@ -316,26 +290,31 @@ TPushParser::do_align()
       TNode g = doc.createG();
       cell.append(g);
       g.append(cursor);
+      return true;
     }
   else
     {
-      logger.error("alignment tab used outside matrix");
+      logger.warning("alignment tab used outside matrix");
+      return false;
     }
 }
 
-void
+bool
 TPushParser::do_eol()
 {
   //if (cursor.parent()) cursor.remove();
+  logger.warning("token ignored");
+  return false;
 }
 
-void
+bool
 TPushParser::do_parameter(const std::string& p)
 {
-  // ???
+  logger.warning("token ignored");
+  return false;
 }
 
-void
+bool
 TPushParser::do_subscript()
 {
   TNode parent = cursor.parent();
@@ -349,6 +328,7 @@ TPushParser::do_subscript()
          cursor.replace(elem);
          elem.append(g);
          elem.append(cursor);
+         return true;
        }
       else
        {
@@ -356,16 +336,30 @@ TPushParser::do_subscript()
          prev.replace(elem);
          elem.append(prev);
          elem.append(cursor);
+         return true;
        }
     }
   else if (parent.isSb() && cursor == parent[1])
     {
-      if (parent["under"] == "1") logger.error("already under");
-      else parent["under"] = "1";
+      if (parent["under"] == "1")
+        {
+         logger.warning("already under");
+         return false;
+       }
+      else
+        {
+         parent["under"] = "1";
+         return true;
+       }
+    }
+  else
+    {
+      logger.warning("token ignored");
+      return false;
     }
 }
 
-void
+bool
 TPushParser::do_superscript()
 {
   TNode parent = cursor.parent();
@@ -379,6 +373,7 @@ TPushParser::do_superscript()
          cursor.replace(elem);
          elem.append(g);
          elem.append(cursor);
+         return true;
        }
       else
        {
@@ -386,46 +381,52 @@ TPushParser::do_superscript()
          prev.replace(elem);
          elem.append(prev);
          elem.append(cursor);
+         return true;
        }
     }
   else if (parent.isSp() && cursor == parent[1])
     {
-      if (parent["over"] == "1") logger.error("already over");
-      else parent["over"] = "1";
+      if (parent["over"] == "1")
+        {
+         logger.warning("token ignored: already over");
+         return false;
+       }
+      else
+        {
+         parent["over"] = "1";
+         return true;
+       }
+    }
+  else
+    {
+      logger.warning("token ignored");
+      return false;
     }
 }
 
-void
+bool
 TPushParser::do_space(const std::string&)
 {
-  logger.debug("do_space");
+  return false;
 }
 
-void
+bool
 TPushParser::do_letter(const std::string& s)
 {
   //TNode parent = cursor.parent();
   TNode elem = doc.createI(s, nextId++);
   cursor.replace(elem);
   advance(elem);
+  return true;
 }
 
-void
+bool
 TPushParser::do_digit(const std::string& s)
 {
-  TNode parent = cursor.parent();
-  TNode prev = cursor.prev();
-  if (prev && parent.isG() && prev.is("n"))
-    {
-      TNode elem = doc.createN(prev.value() + s, nextId++);
-      prev.replace(elem);
-    }
-  else
-    {
-      TNode elem = doc.createN(s, nextId++);
-      cursor.replace(elem);
-      advance(elem);
-    }
+  TNode elem = doc.createN(s, nextId++);
+  cursor.replace(elem);
+  advance(elem);
+  return true;
 }
 
 bool
@@ -435,7 +436,7 @@ TPushParser::isPrimes(const TNode& node) const
   return node.isG() && node.last() && node.last().is("o") && node.last()["val"] == PRIME();
 }
 
-void
+bool
 TPushParser::do_apostrophe()
 {
   if (cursor.parent() && cursor.parent().isG())
@@ -443,11 +444,17 @@ TPushParser::do_apostrophe()
       if (TNode prev = cursor.prev())
        {
          if (prev.isSp() && prev[1] && isPrimes(prev[1]))
-           prev[1].append(doc.createO(PRIME(), nextId++));
+           {
+             prev[1].append(doc.createO(PRIME(), nextId++));
+             return true;
+           }
          else if (prev.isSb() && prev[0] &&
                   prev[0].isSp() && prev[0][1] &&
                   isPrimes(prev[0][1]))
-           prev[0][1].append(doc.createO(PRIME(), nextId++));
+           {
+             prev[0][1].append(doc.createO(PRIME(), nextId++));
+             return true;
+           }
          else
            {
              TNode elem = doc.create("sp");
@@ -456,51 +463,58 @@ TPushParser::do_apostrophe()
              elem.append(prev);
              elem.append(g);
              g.append(doc.createO(PRIME(), nextId++));
+             return true;
            }
        }
       else
        {
          // is it an error?
-         logger.error("parser: you have to type one identifier before the  ''");
+         logger.warning("parser: you have to type an identifier before  ''");
+         return false;
        }
     }
   else
     {
-      // error ??
+      logger.warning("token ignored: you have to be in a group");
+      return false;
     }
 }
 
-void
+bool
 TPushParser::do_other(const std::string& s)
 {
   switch (s[0])
     {
     case '\'':
-      do_apostrophe();
+      return do_apostrophe();
       break;
     default:
       /*cout << "TPushParser::do_other " << s << endl;
       cout << "DOCUMENT: " << static_cast<GdomeNode*>(cursor.element().get_ownerDocument()) << endl;*/
       TNode elem = doc.createT("o", s, nextId++);
       cursor.replace(elem);
-      advance(elem);  
+      advance(elem);
+      return true;
       break;
     }
 }
 
-void
+bool
 TPushParser::do_active(const std::string&)
 {
   // ??? space?
+  logger.warning("token ignorde");
+  return false;
 }
 
-void
+bool
 TPushParser::do_comment()
 {
   // ???
+  return false;
 }
 
-void
+bool
 TPushParser::do_cr()
 {
   TNode parent = cursor.parent();
@@ -520,13 +534,20 @@ TPushParser::do_cr()
       row.append(cell);
       cell.append(g);
       g.append(cursor);
+      return true;
+    }
+  else
+    {
+      // at the moment, \cr can only be used inside a table
+      logger.warning("token ignored: cr used outside a table");
+      return false;
     }
 }
 
-void
+bool
 TPushParser::do_control(const std::string& name)
 {
-  if (name == "cr") do_cr();
+  if (name == "cr") return do_cr();
   else
     {
       TNode parent = cursor.parent();
@@ -539,6 +560,7 @@ TPushParser::do_control(const std::string& name)
            t["name"] = name;
            cursor.replace(t);
            advance(t);
+           return true;
          }
          break;
        case TDictionary::OPERATOR:
@@ -547,6 +569,7 @@ TPushParser::do_control(const std::string& name)
            t["name"] = name;
            cursor.replace(t);
            advance(t);
+           return true;
          }
          break;
        case TDictionary::NUMBER:
@@ -555,50 +578,49 @@ TPushParser::do_control(const std::string& name)
            t["name"] = name;
            cursor.replace(t);
            advance(t);
+           return true;
          }
          break;
        case TDictionary::MACRO:
          {
-           TNode m = doc.createC(name, nextId++);
-           cursor.replace(m);
-           
-           if (entry.leftOpen && entry.rightOpen)
-             {
-               assert(entry.pattern.empty());
-               assert(parent.isG());
-               TNode g1 = doc.createG();
-               g1["left-open"] = "1";
-               g1.append(parent.first(), m);
-               m.append(g1);
-               TNode g2 = doc.createG();
-               g2.append(cursor);
-               m.append(g2);
-               frames.push(Frame(entry));
-             }
-           else if (entry.leftOpen)
+           if (parent.isG())
              {
-               assert(parent.isG());
-               TNode g = doc.createG();
-               g["left-open"] = "1";
-               g.append(parent.first(), m);
-               m.append(g);
-               advance(m);
-             }
-           else if (entry.rightOpen)
-             {
-               assert(entry.pattern.empty());
-               assert(parent.isG());
-               TNode g = doc.createG();
-               g.append(cursor);
-               m.append(g);
-               frames.push(Frame(entry));
-             }
-           else if (!entry.pattern.empty())
-             {
-               if (parent.isG())
-                 {
+               TNode m = doc.createC(name, nextId++);
+               cursor.replace(m);
+               if (entry.leftOpen && entry.rightOpen)
+                 {
+                   assert(entry.pattern.empty());
+                   assert(parent.isG());
+                   TNode g1 = doc.createG();
+                   g1["left-open"] = "1";
+                   g1.append(parent.first(), m);
+                   m.append(g1);
+                   TNode g2 = doc.createG();
+                   g2.append(cursor);
+                   m.append(g2);
+                   frames.push(Frame(entry));
+                 }
+               else if (entry.leftOpen)
+                 {
+                   assert(parent.isG());
+                   TNode g = doc.createG();
+                   g["left-open"] = "1";
+                   g.append(parent.first(), m);
+                   m.append(g);
+                   advance(m);
+                 }
+               else if (entry.rightOpen)
+                 {
+                   assert(entry.pattern.empty());
+                   assert(parent.isG());
+                   TNode g = doc.createG();
+                   g.append(cursor);
+                   m.append(g);
+                   frames.push(Frame(entry));
+                 }
+               else if (!entry.pattern.empty())
+                 {
                    frames.push(Frame(entry));
-
                    if (entry.paramDelimited(0))
                      {
                        TNode g = doc.createG();
@@ -610,63 +632,97 @@ TPushParser::do_control(const std::string& name)
                  }
                else
                  {
-                   // error, but we could handle this very easily
-                   logger.error(" parser:but we could handle this easily");
-                 }
+                   // it's an empty macro
+                   advance(m);
+                 }
+               return true;
+             }
+           else if (!entry.pattern.size() && !entry.rightOpen && !entry.leftOpen)
+             {
+               // a macro with no arguments and no right open and no left open, can be child of anything
+               TNode m = doc.createC(name, nextId++);
+               cursor.replace(m);
+               advance(m);
+               return true;
+             }
+           else
+             {
+               // a macro with arguments or a rightOpen or leftOpen macro must be a group's child
+               logger.warning("token ignored: this macro should be in a group");
+               return false;
              }
-           else advance(m);
          }
          break;
        case TDictionary::UNDEFINED:
          {
-           logger.error("parser: using undefined macro " + name);
+           logger.warning("parser: using undefined macro " + name);
            TNode m = doc.createC(name, nextId++);
            cursor.replace(m);
            advance(m);
+           return true;
          }
          break;
        default:
-         assert(0);
+         {
+           //assert(0);
+           logger.warning("token ignored");
+           return false;
+         }
        }
     }
 }
 
-void
-TPushParser::gdelete_prev_token()
+std::string
+TPushParser::drop_prev_token(bool special)
 {
   assert(cursor.prev());
   assert(cursor.parent());
   TNode prev = cursor.prev();
   assert(prev.is("i") || prev.is("o") || prev.is("n"));
+  DOM::UCS4String ucs4val = prev.element().getAttribute("val");
+  bool macro = prev.element().hasAttribute("name");
+  std::string utf8name;
+  if (macro) utf8name = prev.element().getAttribute("name");
+  
+  cursor.remove();
+  prev.replace(cursor);
   
-  // 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 ((prev.is("i")) || (ucs4val.length() <= 1) || prev.element().hasAttribute("name"))
+  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);
-
-         frame.pos--;
-       }
+      // 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
+
+  if ((ucs4val.length() > 1) && !special)
     {
-      ucs4val.erase(ucs4val.length() - 1, 1);
-      prev.element().setAttribute(DOM::GdomeString("val"), DOM::GdomeString(ucs4val));
+      if (!macro)
+        {
+         // in this case we can return the content of ucs4val, but we have 
+         // to convert it in a utf8
+         DOM::GdomeString gdsval(ucs4val);
+         std::string utf8val(gdsval);
+         utf8val = utf8val.erase(utf8val.length() - 1, 1);
+         return std::string(utf8val);
+       }
+      else
+        {
+         // in this case, the content of val could be in unicode, 
+         // but we have attribute name, which doesn't contain character not representable 
+         // with a byte.
+         return "\\" + utf8name.erase(utf8name.length() - 1, 1);
+       }
     }
-
+  else if ((ucs4val.length() <= 1) && macro && special) return "\\" + utf8name.erase(utf8name.length() - 1, 1);
+  else return "";
 }
 
-void
-TPushParser::gdelete_prev_script()
+std::string
+TPushParser::drop_prev_script(bool special)
 {
   // this method deletes an sp or an sb preceding the cursor
   assert(cursor.prev());
@@ -675,38 +731,72 @@ TPushParser::gdelete_prev_script()
   assert(prev.is("sp") || prev.is("sb"));
   cursor.remove();
   prev.append(cursor);
-  // we can invoke the gdelete_prev, because a sp (sb) MUST have two children
-  gdelete_prev();
+  // we can invoke the drop_prev, because a sp (sb) MUST have two children
+  // but we cannot invoke do_drop_script because it assumes when called, the first 
+  // child has been removed yet.
+  if (cursor.prev().isG() && !prev.hasId())
+    {
+      // in this case, the user has inserted the a sequence of '.
+      // Hence, we force a normal deleting, because the behaviour must be the same 
+      // for the two kind of deleting
+      return drop_prev(false);
+    }
+  else return drop_prev(special);
 }
 
-void
-TPushParser::gdelete_prev_group()
+std::string
+TPushParser::drop_prev_group(bool special)
 {
   assert(cursor.prev() && cursor.prev().isG());
+  TNode parent = cursor.parent();
   TNode prev = cursor.prev();
   cursor.remove();
   prev.append(cursor);
-  
-  // a group could have no children, so the gdelete_prev is not appropriate
-  // so, this method is not equivalent to the one above
-  do_gdelete();
+
+  if (parent.isC() && prev.hasId())
+    {
+      assert(!frames.empty());
+      frames.top().pos--;
+    }
+
+  if (special) return "";
+  else
+    {
+      // a group could have no children, so the drop_prev is not appropriate
+      // so, this method is not equivalent to the one above
+      return do_drop(special);
+    }
 }
 
-void
-TPushParser::gdelete_prev_macro()
+std::string
+TPushParser::drop_prev_macro(bool special)
 {
   assert(cursor.parent());
   assert(cursor.prev());
   TNode prev = cursor.prev();
   assert(prev.isC());
+
+  std::string macro_name = prev.nameC();
+
+  TNode parent = cursor.parent();
   
   const TDictionary::Entry& entry = dictionary.find(prev["name"]);
   
   if (!entry.defined())
     {
-      // We can assume that the user want to completely delete the undefined macro
+      // We can assume that the user wants to completely delete the undefined macro, 
+      // but we can also handle this case as we handle tokens. At the moment, we delete the 
+      // whole macro
       cursor.remove();
       prev.replace(cursor);
+      if (cursor.parent().isC())
+        {
+         // we have removed a macro's child
+         assert(!frames.empty());
+         frames.top().pos--;
+       }
+      if (special) return "\\" + macro_name.erase(macro_name.length() - 1, 1);
+      return "";
     }
   else
     {   
@@ -730,19 +820,22 @@ TPushParser::gdelete_prev_macro()
          
          cursor.remove();
          prev.last().append(cursor);
-         
-         // the gdelete_prev is not appropriate, because the last child of the MACRO could have no children
-         do_gdelete_phantom_group();
+
+         if (special) return "";
+         else
+           {
+             // the drop_prev is not appropriate, because the last child of the MACRO could have no children
+             return do_drop_phantom_group(special);
+           }
        }
       else if (entry.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, we don't remove the last child of the phantom group, but
+         // We could remove the last child of the phantom group, but
          // it's not clear if it's the correct behavior of the graphical deleting.
-         // To delete it, just remove the comment of the last instruction of the 
-         // if (g.size()) block.
+         // At the moment, to give a standard behaviour, we remove the last element.
          assert(prev.first());
          assert(prev.first().isG());
          assert(prev.first() == prev.last());
@@ -754,7 +847,9 @@ TPushParser::gdelete_prev_macro()
              // TNode::replace.
              g.remove();
              prev.replace(g.first(), TNode());
-             //gdelete_prev();
+             parent.append(cursor);
+             if (special) return "\\" + macro_name.erase(macro_name.length() - 1, 1);
+             else return do_drop(special);
            }
          else
            {
@@ -762,6 +857,14 @@ TPushParser::gdelete_prev_macro()
              cursor.remove();
              g.remove();
              prev.replace(cursor);
+             if (special) return "\\" + macro_name.erase(macro_name.length() - 1, 1);
+             else
+               {
+                 // Once removed this empty macro, we could try to remove something else.
+                 // This would be justified by the fact that, generally, an empty macro gives no visual information 
+                 // about it.
+                 return do_drop(special); // special is false
+               }
            }
        }
       else if (!entry.pattern.empty())
@@ -775,17 +878,37 @@ TPushParser::gdelete_prev_macro()
          // frome the one in which it's a not delimited argument.
          if (prev.last().isG() && !prev.last().hasId())
            {
-             // the last argument of the MACRO is a delimited argumet. We ideally remove 
-             // the sequence of delimiters
-             cursor.remove();
-             prev.last().append(cursor);
-             //  we have to push a frame with a correct value of pos
-             assert(entry.previousParam(entry.pattern.size()) != entry.pattern.size());
-             
-             unsigned sequence_length = entry.pattern.size() - entry.previousParam(entry.pattern.size()) - 1;
-             unsigned p = entry.pattern.size() - sequence_length - 1;
-             // now, p is the correct value of pos, and we can push the frame.
-             frames.push(Frame(entry, p));
+             if (special)
+               {
+                 // in this case, we have to start removing the last delimiter
+                 frames.push(Frame(entry, entry.pattern.size() - 2));
+                 
+                 cursor.remove();
+                 prev.last().append(cursor);
+
+                 std::string last_del = entry.pattern[entry.pattern.size() - 1].value;
+
+                 return "\\" + last_del.erase(last_del.length() - 1, 1);
+               }
+             else
+               {
+                 // the last argument of the MACRO is a delimited argumet. We ideally remove 
+                 // the sequence of delimiters
+                 cursor.remove();
+                 prev.last().append(cursor);
+                 //  we have to push a frame with a correct value of pos
+                 assert(entry.previousParam(entry.pattern.size()) != entry.pattern.size());
+                 
+                 unsigned sequence_length = entry.pattern.size() - entry.previousParam(entry.pattern.size()) - 1;
+                 unsigned p = entry.pattern.size() - sequence_length - 1;
+                 // now, p is the correct value of pos, and we can push the frame.
+                 frames.push(Frame(entry, p));
+                 
+                 // To give a standard behaviour to the graphical deleting, we remove the last 
+                 // element of the macro. Since we are in a phantom group, we can invoke the 
+                 // do_drop_phantom_group(special).
+                 return do_drop_phantom_group(special);
+               }
            }
          else
            {
@@ -794,33 +917,36 @@ TPushParser::gdelete_prev_macro()
              cursor.remove();
              if (entry.table == 1 && prev.last().is("row"))
                {
-                 // in this case the cursor should be appended to the group associated to 
+                 // in this case the cursor has to be appended to the group associated to 
                  // the last cell of the last row of the table
                  assert(prev.last().last().is("cell") && prev.last().last().first().isG());
                  prev.last().last().first().append(cursor);
+                 
+                 // we have to push a frame in the stack. Since tables has a pattern size = 1, we have to 
+                 // set pos at 0, because appending the cursor to the last cell means that this argument 
+                 // is not whole inserted.
+                 // We don't call frames.push(Frame(entry)), because it incoditionaly set pos at 0. The 
+                 // following line is more general
+                 frames.push(Frame(entry, entry.pattern.size() - 1));
+                 if (special)
+                   {
+                     // to type a table with rows and cells, the user had typed a 
+                     // "{", and to exit from it, the user had inserted a "}".
+                     // Since we are in a special deleting, we just idealy remove the "}"
+                     return "";
+                   }
+                 else return do_drop_phantom_group(special);
                }
              else
                {
+                 // we push a frame in the stack with a correct value of member pos.
+                 // This correct value is the size of the pattern - 1, because we have been started to delete 
+                 // a MACRO. It means that all of the MACRO's arguments have been inserted, but 
+                 frames.push(Frame(entry, entry.pattern.size()));
                  prev.append(cursor);
+                 return drop_prev(special);
                }
 
-             // we push a frame in the stack with a correct value of member pos.
-             // This correct value is the size of the pattern, because we have to START to delete 
-             // a MACRO. It means that all of the MACRO's arguments have been inserted.
-             frames.push(Frame(entry, entry.pattern.size()));
-
-             if (cursor.prev())
-               {
-                 // in this case we try to remove the last child of the MACRO.
-                 gdelete_prev();
-               }
-             else
-               {
-                 // this block of code will never be executed, because the MACRO accepts arguments, 
-                 // so a MACRO's child MUST exist. But, we can handle this case, emitting a warning
-                 logger.warning("Parser: the TML tree is in a strange state, but a good state will be generated");
-                 do_gdelete();
-               }
            } // end of the else of the if (prev.last().isG() && !prev.last().hasId())
 
        } // end of if (!entry.pattern.empty())
@@ -832,13 +958,28 @@ TPushParser::gdelete_prev_macro()
          assert(prev.size() == 0);
          cursor.remove();
          prev.replace(cursor);
+         if (cursor.parent().isC())
+           {
+             // we have removed an empty macro, which was a non delimited argument of a macro.
+             // We have to decrement pos
+             assert(!frames.empty());
+             frames.top().pos--;
+           }
+
+         if (special) return "\\" + macro_name.erase(macro_name.length() - 1, 1);
+         else return "";
+                 
+         // now we could start to remove something else. This behaviour would be justified by the 
+         // fact that, generally, an empty MACRO gives no visual information about it.
+         // To adopt this behaviour, just remove the comment to the following instruction
+         // return do_drop(special);
        }
     } // end of defined MACRO
 
 }
 
-void
-TPushParser::gdelete_prev()
+std::string
+TPushParser::drop_prev(bool special)
 {
   // if in this function, the prev of cursor does exist, also the parent and we want a graphical deleting.
   
@@ -849,30 +990,31 @@ TPushParser::gdelete_prev()
 
   if (prev.is("i") || prev.is("o") || prev.is("n"))
     {
-      gdelete_prev_token();
+      return drop_prev_token(special);
     }
   else if (prev.isSp() || prev.isSb())
     {
-      gdelete_prev_script();
+      return drop_prev_script(special);
     }
   else if (prev.isG())
     {
-      gdelete_prev_group();
+      return drop_prev_group(special);
     }
   else if (prev.isC())
     {
       // here, we also treat the case in which the MACRO is a table
-      gdelete_prev_macro();
+      return drop_prev_macro(special);
     }
   else 
     {
       // not handled. Future cases...
+      return "";
     }
 
 } // end of method
 
 void
-TPushParser::rgreplace_father(void)
+TPushParser::rgreplace_father()
 {
   // this method MUST only be invoked, when the cursor
   // is the only child of a group with id. This function 
@@ -890,21 +1032,10 @@ TPushParser::rgreplace_father(void)
       parent.replace(cursor);
       parent = cursor.parent();
     }
-
-  if (parent.isC())
-    {
-      // in this case we have removed a MACRO's child. 
-      // So, we have to update the member pos of the frame in the stack
-      // We can assert that this MACRO accepts arguments.
-      assert(!frames.empty());
-      Frame& frame = frames.top();
-      assert(frame.pos > 0);
-      frame.pos--;
-    }
 }
 
-void
-TPushParser::do_gdelete_script()
+std::string
+TPushParser::do_drop_script(bool special)
 {
   // If we are here, the cursor is child of a script (sp or sb) and 
   // this means that a prev does exist and that there is one and only one 
@@ -924,35 +1055,70 @@ TPushParser::do_gdelete_script()
     {
       // in this case, the script's base is a group with no elements, so 
       // we have to remove the entire MACRO, replacing it with the cursor.
-      // This situation occurs when the user type something like this
+      // This situation occurs when the user had typed something like this
       //   $....{}^
       // or this 
       //   $^
       // or this
       //   $...{^
-      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 the group. These controls are made
-      // in the method rgreplace_father().
-      if (cursor.parent().isG() && cursor.parent().hasId()) rgreplace_father();
+      //
+      if (special && prev.hasId())
+        {
+         // in this case, the user has typed: ...{}^
+         // hence we idealy remove the ^
+         parent.replace(prev);
+         prev.parent().append(cursor);
+         return "";
+       }
+      else if (!prev.hasId())
+        {
+         // we idealy remove the ^, but the phantom group 
+         // has to be removed, also
+         prev.remove();
+         parent.replace(cursor);
+         return "";
+       }
+      else
+        {
+         prev.remove();
+         parent.replace(cursor);
+         
+         // since the script had no children, we can try to remove something else.
+         // Since we don't know who is cursor's parent, and who is cursor's preceding 
+         // element, we invoke the do_drop()
+         return do_drop(special);
+         
+         /*
+          * * the following istructions have sense, only if we remove the preceding one.
+          * 
+         // if the new parent is a group with Id and the cursor is the only 
+         // element of this group, we have to remove the group. These controls are made
+         // in the method rgreplace_father().
+         if (cursor.parent().isG() && cursor.parent().hasId()) rgreplace_father();
+         */
+       }
     }
   else
     {
-      // in this case, the prev has to replace the script, 
-      // and the cursor has to be placed after the prev. 
-      assert(prev.hasId());
+      // in this case, the prev has to replace the script.
       parent.replace(prev);
       prev.parent().append(cursor);
       // now prev have a preceding element
       assert(cursor.parent().size() > 1);
+
+      if (special) return "";
+      else
+        {
+         // to give a standard behaviour, we try to remove the element, which was 
+         // the script's base.
+         return do_drop(special);
+       }
     }
   
-} // end of method do_gdelete_script
+} // end of method do_drop_script
 
-void
-TPushParser::do_gdelete_macro()
+std::string
+TPushParser::do_drop_macro(bool special)
 {
   // 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
@@ -961,6 +1127,9 @@ TPushParser::do_gdelete_macro()
   // we can assert that frame.entry.pattern.size() >= 1
   assert(cursor.parent() && cursor.parent().isC());
   TNode parent = cursor.parent();
+
+  // this string is useful iff we have a special deleting
+  std::string macro_name = parent.nameC();
   
   assert(!frames.empty());
   Frame& frame = frames.top();
@@ -973,25 +1142,36 @@ TPushParser::do_gdelete_macro()
     {
       // 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), but we don't mind about it.
       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 can remove it, because it' a graphical deleting
-      if (cursor.parent() && cursor.parent().isG() && cursor.parent().hasId())
-       rgreplace_father();
-      else if (cursor.parent().isC())
+      if (special) return "\\" + macro_name.erase(macro_name.length() - 1, 1);
+      else
         {
-         // We have assumed that a MACRO cannot be a MACRO's child. 
-         // At the moment, this assumption is valid, but in a future 
-         // it might be false.
-         assert(!frames.empty());
-         Frame& frame = frames.top();
-         assert(frame.pos > 0);
-         frame.pos--;
+         // Since the macro hadn't no children and this is a graphical deleting, we try 
+         // to remove something else
+         return do_drop(special);
+
+          /*
+           * the following block of code has sense only if we remove the preceding instruction
+           * 
+           // if the new parent is a group with Id, and has no elements other than the 
+           // cursor, we can remove it, because it' a graphical deleting
+           if (cursor.parent() && cursor.parent().isG() && cursor.parent().hasId())
+            rgreplace_father();
+           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 might be false.
+              assert(!frames.empty());
+              Frame& frame = frames.top();
+              assert(frame.pos > 0);
+              frame.pos--;
+            }
+          */
        }
     }
   else
@@ -1006,25 +1186,42 @@ TPushParser::do_gdelete_macro()
          cursor.remove();
          prev.append(cursor);
          assert(frame.entry.previousParam(frame.pos) != frame.entry.pattern.size());
-         
-         // these 3 lines of code update the member pos.
-         unsigned sequence_length = frame.pos - frame.entry.previousParam(frame.pos) - 1;
-         assert(sequence_length);
-         frame.pos = frame.pos - sequence_length - 1;
+
+         if (special)
+           {
+             // in this case we have to start removing the last delimimeter.
+             // It means that we return in a situation where the user has not entirely 
+             // inserted the delimited argument. So, we have to decrement frame.pos of 
+             // two units: the delimiter and the actual argument
+             std::string last_del = frame.entry.pattern[frame.pos - 1].value;
+             frame.pos = frame.pos - 2;
+             return "\\" + last_del.erase(last_del.length() - 1, 1);
+           }
+         else
+           {
+             // these 3 lines of code update the member pos.
+             unsigned sequence_length = frame.pos - frame.entry.previousParam(frame.pos) - 1;
+             assert(sequence_length);
+             frame.pos = frame.pos - sequence_length - 1;
+             
+             // since it's a graphical deleting, we have to remove the current preceding element.
+             // We don't invoke the drop_prev(), because a do_drop_phantom_group is more general.
+             return do_drop_phantom_group(special);
+           }
        }
       else
         {
          // the prev is not a delimited argument, so we have to try to remove it. 
-         // We "try", because the prev might be something that 
+         // We "try", because the prev might be something that 
          // a simple delete cannot remove completely
-         gdelete_prev();
+         return drop_prev(special);
        }
     }
 
 }
 
-void
-TPushParser::do_gdelete_groupId()
+std::string
+TPushParser::do_drop_groupId(bool special)
 {
   // if we are here, the cursor's parent is a group with Id
   assert(cursor.parent() && cursor.parent().isG() && cursor.parent().hasId());
@@ -1036,28 +1233,43 @@ TPushParser::do_gdelete_groupId()
   if (prev)
     {
       // the cursor has a preceding element, so we try to remove it
-      gdelete_prev();
-
-      // We control if the group has to be removed, because the cursor 
-      // might be the only element of the group.
-      if ((parent.first() == cursor) && parent.isG() && parent.hasId())
-       rgreplace_father();
+      if (special) return drop_prev(special);
+      else
+        {
+          std::string str = drop_prev(special);
+
+          // We control if the group has to be removed, because the cursor 
+          // might be the only element of the group.
+          // But we have to be careful, because drop_prev could change the TML tree 
+          // more than we think...parent could no longer exist! 
+          parent = cursor.parent();
+          if ((parent.first() == cursor) && parent.isG() && parent.hasId())
+           rgreplace_father();
       
+          return str;
+       }
     }
   else
     {
       // the cursor has no preceding elements, so we have to remove the 
       // group.
-      rgreplace_father();
-      
-      // we have to re-start the process, because it' a graphical delete
-      do_gdelete();
+      if (special)
+        {
+         parent.replace(cursor);
+         return "";
+       }
+      else
+        {
+         rgreplace_father();
+         // we have to re-start the process, because it' a graphical deleting
+         return do_drop(special);
+       }
     }
 
-} // end of method do_gdelete_groupId()
+} // end of method do_drop_groupId()
 
-void
-TPushParser::do_gdelete_phantom_group()
+std::string
+TPushParser::do_drop_phantom_group(bool special)
 {
   // if we are here, the cursor MUST be a child of a 
   // phantom group.
@@ -1069,34 +1281,75 @@ TPushParser::do_gdelete_phantom_group()
   TNode prev = cursor.prev();
   if (prev)
     {
+      if (parent.parent() && parent.parent().isC())
+        {
+         // there is a frame in the stack
+         assert(!frames.empty());
+         if (frames.top().entry.pattern.size())
+           {
+             Frame& frame = frames.top();
+             if (special)
+               {
+                 // we are in a delimited argument. If the user has inserted a proper subset of the 
+                 // delimiters'sequence, we start to remove the previous delimiter. Start to remove 
+                 // a delimiter means that that delimiter must be removed from the count of inserted delimiters.
+                 // It means that we have to decrement the member pos.
+                 if (frame.entry.pattern[frame.pos].category != TToken::PARAMETER)
+                   {
+                     std::string del = frame.entry.pattern[frame.pos].value;
+                     frame.pos--;
+                     return "\\" + del.erase(del.length() - 1, 1);
+                   }
+               }
+             else
+               {
+                 // we are in a delimited argument. If the user has inserted a proper subset of the delimiters'sequence, 
+                 // we have to remove the portion the user has inserted.
+                 while (frame.entry.pattern[frame.pos].category != TToken::PARAMETER) frame.pos--;
+               }
+           }
+       }
+      
       // the cursor has a preceding element, so we try to remove it
-      gdelete_prev();
+      std::string str = drop_prev(special);
 
-      if (parent.size() == 1 && parent.parent().isSp())
+      if (special) return str;
+      else
         {
-         // in this case the gdelete_prev has removed the only element preceding the cursor.
-         // If the phantom group is an sp's child, it means that the user has removed all \' in the 
-         // phantom group.
-         // We can remove the phamtom group and the sp element. But we also can only remove the 
-         // phantom group, giving the user the possibility of inserting an exponent.
-         // At the moment, we remove the sp element (and the phantom group), because it may be the correct 
-         // behavior of a graphical deleting.
-         cursor.remove();
-         parent.replace(cursor);
-         // now we have an sp element with two children: the first child (we don't know anything about it)
-         // and the cursror.
-         assert(cursor.parent().size() == 2);
+          // now we have to control the parent, to handle the case of primes. But we have returned from a drop_prev(), which
+          // could change the TML tree. So not asssuming that cursor's parent is unchanged is convenient.
+          parent = cursor.parent();
+          if (parent.isG() && !parent.hasId() && (parent.size() == 1) && parent.parent().isSp())
+            {
+             // in this case the drop_prev has removed the only element preceding the cursor.
+             // Since the phantom group is an sp's child, the user has removed all \' in the 
+             // phantom group.
+             // Now we have some possibilities:
+             //   - we can replace the phantom group with the cursor, giving the user the chance to insert a new 
+             //     exponent
+             //   - we can remove the phantom group and the sp element, recreating the state before the user inserted the first
+             //     prime.
+             // At the moment we implement the second one.
+             assert(parent.parent().size() == 2);
+             TNode gparent = parent.parent();
+             TNode base = gparent.first();
+             cursor.remove();
+             parent.remove();
+             gparent.replace(base);
+             // now base's parent is no more gparent
+             base.parent().append(cursor);
          
-         // to delete the script we can invoke the do_gdelete_script(), which will do all controls we need.
-         // To give the possibility of insetring an exponent, just remove the following istruction.
-         do_gdelete_script();
-       }
-      else if (parent.parent().isSp())
-        {
-         // in this case we have to place the cursor after the sp element
-         cursor.remove();
-         assert(parent.parent().parent());
-         parent.parent().parent().append(cursor);
+             return str;
+           }
+          else if (parent.isG() && !parent.hasId() && parent.parent().isSp())
+            {
+             // in this case we have to place the cursor after the sp element
+             cursor.remove();
+             assert(parent.parent().parent());
+             parent.parent().parent().append(cursor);
+             return str;
+           }
+          else return str;
        }
     }
   else
@@ -1108,7 +1361,8 @@ TPushParser::do_gdelete_phantom_group()
       if (!gfather)
         {
          // If here, the TML tree is in an inconsistent state
-         logger.error("do_gdelete_phantom: TML tree in a inconsistent state");
+         logger.error("TML tree in a inconsistent state");
+         return "";
        }
       else if (gfather.isC())
         {
@@ -1116,6 +1370,9 @@ TPushParser::do_gdelete_phantom_group()
          // We have to control the nature of this MACRO.
          assert(!frames.empty());
           Frame& frame = frames.top();
+
+         // this variable is useful in a special deleting
+         std::string macro_name = gfather.nameC();
          
          if (frame.entry.leftOpen && frame.entry.rightOpen)
            {
@@ -1146,6 +1403,13 @@ TPushParser::do_gdelete_phantom_group()
              // now we have the situation preceding the insertion of the leftOpen and rightOpen MACRO.
              // this MACRO no longer exists.
              frames.pop();
+
+             if (special) return "\\" + macro_name.erase(macro_name.length() - 1, 1);
+             else
+               {
+                 // to give a standard behaviour to the graphical deleting, we call the do_drop.
+                 return do_drop(special);
+               }
            }
          else if (frame.entry.rightOpen)
            {
@@ -1160,16 +1424,25 @@ TPushParser::do_gdelete_phantom_group()
              
              // now we have the situation preceding the rightOpen MACRO, so we have to pop the frame
              frames.pop();
+
+             if (special) return "\\" + macro_name.erase(macro_name.length() - 1, 1);
+             else
+               {
+                 // to give a standard behaviour to the graphical deleting, we call the do_drop.
+                 return do_drop(special);
+               }
+             
            }
          else if (frame.entry.leftOpen)
            {
              // this situation will never occur.
              logger.error("the parser has generated a wrong TML tree");
+             return "";
            }
          else if (!frame.entry.pattern.empty())
            {
              // the MACRO accepts arguments, and the phantom group in which 
-             // the cursor is, rappresents a delimited argument
+             // the cursor is, rappresents a delimited argument.
              // We have to control if the cursor's parent has a preceding element, 
              // or not.
              TNode uncle = parent.prev();
@@ -1183,6 +1456,14 @@ TPushParser::do_gdelete_phantom_group()
                  parent.remove();
                  gfather.replace(cursor);
                  frames.pop();
+
+                 if (special) return "\\" + macro_name.erase(macro_name.length() - 1, 1);
+                 else
+                   {
+                     // once we have replaced the empty macro with the cursor, we can remove
+                     // something else
+                     return do_drop(special);
+                   }
                }
              else
                {
@@ -1190,59 +1471,69 @@ TPushParser::do_gdelete_phantom_group()
                  // 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 sequence 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's uncle is a delimited argument
                      cursor.remove();
                      parent.remove();
                      uncle.append(cursor);
+                     if (special)
+                       {
+                         // we have to start removing the last delimiter of the delimited 
+                         // argument.
+                         std::string last_del = frame.entry.pattern[frame.pos - 1].value;
+                         frame.pos = frame.pos - 2;
+                         return "\\" +  last_del.erase(last_del.length() - 1, 1); 
+                       }
+                     else
+                       {
+                         // the  uncle is a delimited argument. So we have to ideally
+                         // remove the sequence 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;
+
+                         // once removed the sequnce of delimiters, we can start to remove the actual 
+                         // parameter. We can call the do_drop_phantom_group() because a delimited argument
+                         // is always a phantom group's child
+                         return do_drop_phantom_group(special);
+                       }
                    }
                  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)
+                     parent = cursor.parent(); // we update the parent (it should be the MACRO)
                      assert(parent.isC());
 
                      // now we try to remove the uncle (now it' the preceding element)
-                     gdelete_prev();
+                     return drop_prev(special);
                    }
                } // 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("parser: TML tree in a strange state, but we try to recover from it");
-             if (gfather.size() == 1)
-               {
-                 cursor.remove();
-                 parent.remove();
-                 gfather.replace(cursor);
-               }
-             else
-               {
-                 logger.warning("parser: TML tree in a very strange state, but we try to recover from it");
-                 cursor.remove();
-                 gfather.replace(cursor);
-               }
+             logger.error("TML tree in a strange state");
+             return "";
            }
        } // end of if (gfather.isC())
       else if (gfather.is("cell"))
         {
          // A table is a control sequence, so there is a frame in the stack
          assert(!frames.empty());
-         assert(frames.top().pos == 1);
+         assert(frames.top().pos == 0);
          assert(frames.top().entry.table == 1);
          
          // a cell MUST be a row's child, which in turn is a table's child 
          assert(gfather.parent() && gfather.parent().is("row") && gfather.parent().parent());
+
+         // this variable is useful to handle the special deleting
+         std::string table_name = gfather.parent().parent().nameC();
+         
          TNode row = gfather.parent();
          
          // in this case the cell has no element, so the user wants to delete this cell.
@@ -1254,7 +1545,7 @@ TPushParser::do_gdelete_phantom_group()
 
          if (!prev_cell)
            {
-             // in this case, the cell is the only cell in the row.
+             // in this case, the cell was the only cell in the row.
              // So, we assume that the user wants to delete the entire row.
              TNode table = row.parent();
              TNode prev_row = row.prev();
@@ -1262,13 +1553,24 @@ TPushParser::do_gdelete_phantom_group()
              
              if (!prev_row)
                {
-                 // the row was the only child of the table. 
-                 // so we have to delete the entire table
-                 assert(table.parent());
-                 TNode parent_table = table.parent();
-                 table.remove();
-                 frames.pop();
-                 parent_table.append(cursor);
+                 if (special)
+                   {
+                     // Since there was a cell (and a row), the user has typed a "{" to 
+                     // We ideally remove this character.
+                     table.append(cursor);
+                     return "";
+                   }
+                 else
+                   {
+                     // the row was the only child of the table. 
+                     // so we have to delete the entire table
+                     assert(table.parent());
+                     TNode parent_table = table.parent();
+                     table.remove();
+                     frames.pop();
+                     parent_table.append(cursor);
+                     return "";
+                   }
                }
              else
                {
@@ -1280,6 +1582,10 @@ TPushParser::do_gdelete_phantom_group()
                  assert(last_cell.size() == 1);
                  assert(last_cell.first().isG() && !last_cell.first().hasId());
                  last_cell.first().append(cursor);
+                 // Since cells and rows are separated by spaces and CRs 
+                 // (and the user can see this spaces and CRs), a special deleting 
+                 // is equivalent to a normal deleting
+                 return "";
                }
            } // end of if (!prev_cell)
          else
@@ -1289,51 +1595,50 @@ TPushParser::do_gdelete_phantom_group()
              assert(prev_cell.size() == 1);
              assert(prev_cell.first().isG() && !prev_cell.first().hasId());
              prev_cell.first().append(cursor);
+             return "";
            }
        } // end of if (gfather.is("cell"))
       else if (gfather.isSp())
         {
-         // in this case, the user typed 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 possibilities: 
-         //   we can delete the phantom group;
-         //   we can delete the superscript.
-         // At the moment we implement the first solution. To implement the second one, just remove 
-         // the line code after the logger.warning and remove comments from the remaining lines
-         logger.warning("parser: TML tree in a strange state, we try to recover from it");
-         parent.replace(cursor);
-         
-         //cursor.remove();
-         //parent.remove();
-         //gfather.replace(cursor);
+         // we cannot be here because a phantom group can be a Sp child only 
+         // in two cases. If the user has typed somethong like:
+         // $^
+         // the cursor is not phantom group's child.
+         // If the user has typed somethong like
+         // ..''
+         // In this case the sequence of ' is placed in a phantom group, 
+         // which becomes the exponent of the script. But, the cursor is 
+         // always outside the phantom group
+         logger.error("TML tree in a strange state");
+         return "";
        }
       else if (gfather.is("math"))
         {
          // in this case we ignore the user's will of deleting
-         // but we can decide to remove the math mode.
-         logger.info("Parser: nothing to delete");
+         // but we could also decide to remove the math mode.
+         logger.warning("Parser: nothing to delete");
+         return "";
        }
       else
         {
          // cursor's grand father is undefined
          logger.error("parser: TML tree is in a unknown state");
+         return "";
        }
     } // end of the else of the if (prev)
 
 }
 
 
-void
-TPushParser::do_gdelete()
+std::string
+TPushParser::do_drop(bool special)
 {
   // 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");
+      return "";
     }
   else
     {
@@ -1345,51 +1650,52 @@ TPushParser::do_gdelete()
          // we ca do two thing...we can remove the math mode (it implies controlling the display attribute), we can do nothing
          // At the moment, the user's will of deleting is simply ignored
          logger.warning("nothing to delete");
+         return "";
        }
       else if (parent.isG())
         {
          // the cursor's parent is a group. We have to control if it's a phantom group or not
          if (parent.hasId())
            {
-             do_gdelete_groupId();
+             return do_drop_groupId(special);
            }
          else
            {
-             do_gdelete_phantom_group();
+             return do_drop_phantom_group(special);
            }
        } // end of parent is group
       else if (parent.isC())
         {
-         do_gdelete_macro();
+         return do_drop_macro(special);
        } // end of parent is a MACRO
       else if (parent.isSp() || parent.isSb())
         {
-         do_gdelete_script();
+         return do_drop_script(special);
        } // end of parent is sp or sb
     } // end of the else which consider the case in which parent exists
   
-} // end of method do_gdelete
+} // end of method do_drop
 
-void
+bool
 TPushParser::process(const TToken& token)
 {
   switch (token.category)
     {
-    case TToken::BEGIN: do_begin(); break;
-    case TToken::END: do_end(); break;
-    case TToken::SHIFT: do_shift(); break;
-    case TToken::ALIGN: do_align(); break;
-    case TToken::EOL: do_eol(); break;
-    case TToken::PARAMETER: do_parameter(token.value); break;
-    case TToken::SUPERSCRIPT: do_superscript(); break;
-    case TToken::SUBSCRIPT: do_subscript(); break;
-    case TToken::SPACE: do_space(token.value); break;
-    case TToken::LETTER: do_letter(token.value); break;
-    case TToken::DIGIT: do_digit(token.value); break;
-    case TToken::OTHER: do_other(token.value); break;
-    case TToken::ACTIVE: do_active(token.value); break;
-    case TToken::COMMENT: do_comment(); break;
-    case TToken::CONTROL: do_control(token.value); break;
+    case TToken::BEGIN: return do_begin(); break;
+    case TToken::END: return do_end(); break;
+    case TToken::SHIFT: return do_shift(); break;
+    case TToken::ALIGN: return do_align(); break;
+    case TToken::EOL: return do_eol(); break;
+    case TToken::PARAMETER: return do_parameter(token.value); break;
+    case TToken::SUPERSCRIPT: return do_superscript(); break;
+    case TToken::SUBSCRIPT: return do_subscript(); break;
+    case TToken::SPACE: return do_space(token.value); break;
+    case TToken::LETTER: return do_letter(token.value); break;
+    case TToken::DIGIT: return do_digit(token.value); break;
+    case TToken::OTHER: return do_other(token.value); break;
+    case TToken::ACTIVE: return do_active(token.value); break;
+    case TToken::COMMENT: return do_comment(); break;
+    case TToken::CONTROL: return do_control(token.value); break;
     }
 }
 
@@ -1428,23 +1734,7 @@ TPushParser::push(const TToken& token)
                    // this delimiter is the last one for the argumet, 
                    // so the argument is completed
                    cursor.remove();
-                   frame.pos++;
-
-                   if (frame.pos == frame.entry.pattern.size())
-                     {
-                       // This token has completed the entry
-                       advance(parent);
-                     }
-                   else if (frame.entry.paramDelimited(frame.pos))
-                     {
-                       // For the next is a delimited argument we have to place
-                       // a suitable phantom group with the cursor inside
-                       TNode g = doc.createG();
-                       parent.parent().append(g);
-                       g.append(cursor);
-                     }
-                   else
-                     parent.parent().append(cursor);
+                   advance(parent);
                  }
              }
            else
@@ -1459,7 +1749,7 @@ TPushParser::push(const TToken& token)
                    //   - ignore the token, and wait for the correct delimiter
                    //   - ignore the token, wait for the correct delimiter and emit an error
                    // At the moment, we implement the second possibily
-                   logger.error("parser: it's not the correct delimiter...you have to type " + frame.entry.pattern[frame.pos + 1].value);
+                   logger.warning("parser: it's not the correct delimiter...you have to type " + frame.entry.pattern[frame.pos + 1].value);
                  }
                else
                  {
@@ -1490,16 +1780,7 @@ TPushParser::push(const TToken& token)
          {
            // As by the TeX parsing rules of undelimited parameters,
            // empty spaces are ignored
-           if (token.category != TToken::SPACE)
-             {
-               // We need to increase the frame position here, becase inside
-               // process the function advance will be called. At that point
-               // 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
-               frame.pos++;
-               process(token);
-             }
+           if (token.category != TToken::SPACE) process(token);
          }
        else if (frame.entry.pattern[frame.pos] == token)
          {
@@ -1515,14 +1796,16 @@ TPushParser::push(const TToken& token)
                g.append(cursor);
              }
            else
-             advance(parent);
+             {
+               cursor.remove();
+               advance(parent);
+             }
          }
        else
          {
            // There is a mismatch. Emit an error and ignore the token?
-           logger.debug("parser: token ignored: " + token.value);
+           logger.warning("parser: token ignored: " + token.value);
          }
-
       }
     else
       process(token);
@@ -1535,14 +1818,13 @@ TPushParser::push(const TToken& token)
 }
 
 std::string
-TPushParser::drop()
+TPushParser::drop(bool special)
 {
-  do_gdelete();
+  std::string str = do_drop(special);
   if (factory && doc.dirtyNode() && !frozen()) factory->documentModified(doc);
-  return "";
+  return str;
 }
 
-
 void
 TPushParser::advance(const TNode& node)
 {
@@ -1562,8 +1844,9 @@ TPushParser::advance(const TNode& node)
   else if (node.parent().isC())
     {
       assert(!frames.empty());
-      if (frames.top().pos == frames.top().entry.pattern.size())
+      if ((frames.top().pos + 1 == frames.top().entry.pattern.size()) || (frames.top().entry.pattern.empty()))
         {
+         // we are here when we have a right open macro, or the inserted element is the last one
          if (frames.top().entry.rightOpen)
            {
              // we have to remove the frame from the stack
@@ -1576,116 +1859,25 @@ TPushParser::advance(const TNode& node)
              advance(node.parent());
            }
        }
-      else if (frames.top().entry.paramDelimited(frames.top().pos))
+      else if (frames.top().entry.paramDelimited(frames.top().pos + 1))
         {
          // the next argument is delimited, so we have to create a phantom group
          TNode g = doc.createG();
          g.append(cursor);
          node.parent().append(g);
+         frames.top().pos++;
        }
       else
         {
          // the next argumet is not delimited, so we have to append the cursor
          // to the MACRO
          node.parent().append(cursor);
+         frames.top().pos++;
        }
     }
   else advance(node.parent());
 }
 
-
-/*
- * This version handles the case in which we have to 
- * create a delimited argument
-
-void
-TPushParser::advance(const TNode& node)
-{
-  assert(node);
-  TNode parent = node.parent();
-  if (!parent)
-    ; // nothing to do, the cursor is not in the document any more
-  else if (parent.isG())
-    {
-      TNode next = node.next();
-      if (next) next.insert(cursor);
-      else parent.append(cursor);
-    }
-  else if (parent.isC())
-    {
-      if (node.next())
-       ; // cursor removed
-      else
-       {
-         Frame& frame = frames.top();
-         if (frame.pos == frame.entry.pattern.size())
-           {
-             frames.pop();
-             advance(parent);
-           }
-         else if (frame.entry.paramDelimited(frame.pos))
-           {
-             // the next argument is delimited, so we have to create a phantom group
-             // with the cursor inside. We have to remember that, since we are here, 
-             // the cursor has been removed
-             TNode g = doc.createG();
-             g.append(cursor);
-             parent.append(g);
-           }
-         else
-           {
-             // otherwise, the next MACRO's argument is not delimited, so we just 
-             // append the cursor to the MACRO
-             parent.append(cursor);
-           }
-       }
-    }
-  else if (parent.is("math"))
-    ; // we are done
-  else
-    advance(parent);
-}
-*/
-
-/*
- * original advance
-void
-TPushParser::advance(const TNode& node)
-{
-  assert(node);
-  TNode parent = node.parent();
-  if (!parent)
-    ; // nothing to do, the cursor is not in the document any more
-  else if (parent.isG())
-    {
-      TNode next = node.next();
-      if (next) next.insert(cursor);
-      else parent.append(cursor);
-    }
-  else if (parent.isC())
-    {
-      if (node.next())
-       ; // cursor removed
-      else
-       {
-         Frame& frame = frames.top();
-         if (frame.pos == frame.entry.pattern.size())
-           {
-             frames.pop();
-             advance(parent);
-           }
-         else
-           parent.append(cursor);
-       }
-    }
-  else if (parent.is("math"))
-    ; // we are done
-  else
-    advance(parent);
-}
-*/
-
-
 void
 TPushParser::setCursorHint(const std::string& c)
 {
index 06020b52ff6b6b2ca14094a18c9a6ef4afeabb60..04edacb6378c465e483085adec42df4e1ac15acb 100644 (file)
@@ -19,7 +19,7 @@ public:
 
   virtual void reset(void);
   virtual void push(const TToken&);
-  virtual std::string drop(void);
+  virtual std::string drop(bool);
   virtual void setCursorHint(const std::string&);
   virtual bool hideCursor(void);
   virtual bool showCursor(void);
@@ -36,43 +36,41 @@ private:
 
   
   
-  void do_begin(void);
-  void do_end(void);
-  void do_shift(void);
-  void do_align(void);
-  void do_eol(void);
-  void do_parameter(const std::string&);
-  void do_superscript(void);
-  void do_subscript(void);
-  void do_space(const std::string&);
-  void do_letter(const std::string&);
-  void do_digit(const std::string&);
-  void do_other(const std::string&);
-  void do_active(const std::string&);
-  void do_comment(void);
-  void do_control(const std::string&);
+  bool do_begin(void);
+  bool do_end(void);
+  bool do_shift(void);
+  bool do_align(void);
+  bool do_eol(void);
+  bool do_parameter(const std::string&);
+  bool do_superscript(void);
+  bool do_subscript(void);
+  bool do_space(const std::string&);
+  bool do_letter(const std::string&);
+  bool do_digit(const std::string&);
+  bool do_other(const std::string&);
+  bool do_active(const std::string&);
+  bool do_comment(void);
+  bool do_control(const std::string&);
 
   
-  void gdelete_prev_token(void);
-  void gdelete_prev_script(void);
-  void gdelete_prev_group(void);
-  void gdelete_prev_macro(void);
-  void gdelete_prev(void);
-  
+  std::string drop_prev_token(bool);
+  std::string drop_prev_script(bool);
+  std::string drop_prev_group(bool);
+  std::string drop_prev_macro(bool);
+  std::string drop_prev(bool);
   void rgreplace_father(void);
-
-  void do_gdelete_script(void);
-  void do_gdelete_macro(void);
-  void do_gdelete_groupId(void);
-  void do_gdelete_phantom_group(void);
-  void do_gdelete(void);
-
-  void do_cr(void);
-  void do_apostrophe(void);
+  std::string do_drop_script(bool);
+  std::string do_drop_macro(bool);
+  std::string do_drop_groupId(bool);
+  std::string do_drop_phantom_group(bool);
+  std::string do_drop(bool);
+
+  bool do_cr(void);
+  bool do_apostrophe(void);
   void advance(const TNode&);
   bool correctBrace(void);
 
-  void process(const TToken&);
+  bool process(const TToken&);
 
   struct Frame
   {
index a78b7cc5d6c129d25543ef6c6e993c3235fd9a40..7a8736cee0080d6b50805604f81cd595a89aec71 100644 (file)
@@ -37,7 +37,7 @@ TTokenizer::push(const TToken& token)
 }
 
 std::string
-TTokenizer::drop()
+TTokenizer::drop(bool alt)
 {
   assert(0);
   return "";
index da534fed7253c01e9f6f69e421f2bde1a8e89b37..00960207dc34d9f82b6bf89b47afb11b709d5241 100644 (file)
@@ -19,7 +19,7 @@ public:
 private:
   virtual void reset(void);
   virtual void push(const TToken&);
-  virtual std::string drop(void);
+  virtual std::string drop(bool = false);
   virtual void setCursorHint(const std::string&) { };
   virtual bool hideCursor(void) { return false; };
   virtual bool showCursor(void) { return false; };