]> matita.cs.unibo.it Git - helm.git/blob - helm/DEVEL/mathml_editor/src/TPushParser.cc
* code cleanup
[helm.git] / helm / DEVEL / mathml_editor / src / TPushParser.cc
1
2 #include "ALogger.hh"
3 #include "TPushParser.hh"
4 #include "AMathMLFactory.hh"
5
6 TPushParser::TPushParser(ALogger& l, const TDictionary& d) : APushParser(l), dictionary(d)
7 {
8   init();
9 }
10
11 TPushParser::TPushParser(ALogger& l, AMathMLFactory& f, const TDictionary& d) : APushParser(l, f), dictionary(d)
12 {
13   init();
14 }
15
16 void
17 TPushParser::init()
18 {
19   nextId = 1;
20   cursor = doc.create("cursor");
21   cursor["id"] = "I0";
22   doc.clearDirty();
23   doc.root().append(cursor);
24 }
25
26 TPushParser::~TPushParser()
27 {
28 }
29
30 std::string
31 TPushParser::PRIME() const
32 {
33   const TDictionary::Entry entry = dictionary.find("prime");
34   if (entry.cls == TDictionary::OPERATOR) return entry.value;
35   else return "?";
36 }
37
38 void
39 TPushParser::do_begin()
40 {
41   TNode parent = cursor.parent();
42   if (parent.isC() && dictionary.find(parent.nameC()).table)
43     {
44       TNode row = doc.create("row");
45       TNode cell = doc.create("cell");
46       TNode g = doc.createG();
47       row.append(cell);
48       cell.append(g);
49       g.append(cursor);
50       parent.append(row);
51     }
52   else
53     {
54       TNode g = doc.createG(nextId++);
55       cursor.replace(g);
56       g.append(cursor);
57     }
58 }
59
60 void
61 TPushParser::do_end()
62 {
63   TNode parent = cursor.parent();
64   if (parent && parent.isG() && parent.hasId())
65     {
66       // normal closing brace for an explicitly open group
67       cursor.remove();
68       advance(parent);
69     }
70   else if (parent && parent.isG() && parent.parent() && parent.parent().is("cell"))
71     {
72       assert(!frames.empty());
73       // closing brace for a structure in which & or \cr have been used
74       TNode row = parent.parent().parent();
75       assert(row && row.is("row"));
76       TNode table = row.parent();
77       assert(table);
78       advance(table);
79
80       // now we have to pop the associated frame in the stack
81       frames.pop();
82     }
83   else if (parent && parent.isG() && !parent.hasId() && parent.parent())
84     {
85       // closing brace for a right-open macro (like \over)
86       cursor.remove();
87       advance(parent.parent());
88       frames.pop();
89     }
90   else
91     {
92       // ???
93       assert(0);
94     }
95 }
96
97 void
98 TPushParser::do_shift()
99 {
100   TNode parent = cursor.parent();
101   assert(parent);
102   if (parent.is("tex"))
103     {
104       TNode math = doc.create("math", nextId++);
105       TNode g = doc.createG();
106       cursor.replace(math);
107       math.append(g);
108       g.append(cursor);
109     }
110   else if (parent.isG() && !parent.hasId() && parent.parent() && parent.parent().is("math"))
111     {
112       if (cursor.prev())
113         {
114           // there is something before the cursor, hence this is the
115           // closing math shift
116           if (parent.parent()["display"] != "1")
117             {
118               // one math shift is enough to close it
119               cursor.remove();
120             }
121           else
122             {
123               // we need two closing math shifts
124               parent.parent().append(cursor);
125             }
126         }
127       else if (parent.parent()["display"] != "1")
128         {
129           // there is nothing before the cursor, and the math is not
130           // in display mode, so this must be a double math shift
131           parent.parent()["display"] = "1";
132         }
133       else
134         {
135           parent.parent().append(cursor);
136         }
137     }
138   else if (parent.is("math"))
139     {
140       cursor.remove();
141     }
142   else
143     {
144       cerr << "ERROR: math shift" << endl;
145     }
146 }
147
148 void
149 TPushParser::do_align()
150 {
151   TNode parent = cursor.parent();
152   if (parent && parent.isG() && parent.hasId())
153     {
154       // alignment tab used for the first time inside a group
155       TNode row = doc.create("row");
156       TNode cell = doc.create("cell");
157       TNode g = doc.createG();
158       row.append(cell);
159       cell.append(g);
160       g.append(parent.first(), cursor);
161     }
162   else if (parent && parent.isG() && parent.parent().is("cell"))
163     {
164       // alignment tab used within a cell
165       TNode oldCell = parent.parent();
166       assert(oldCell && oldCell.is("cell"));
167       TNode row = oldCell.parent();
168       assert(row && row.is("row"));
169       TNode cell = doc.create("cell");
170       if (oldCell.next()) oldCell.next().insert(cell);
171       else row.append(cell);
172       TNode g = doc.createG();
173       cell.append(g);
174       g.append(cursor);
175     }
176   else
177     {
178       cerr << "alignment tab used outside matrix" << endl;
179     }
180 }
181
182 void
183 TPushParser::do_eol()
184 {
185   //if (cursor.parent()) cursor.remove();
186 }
187
188 void
189 TPushParser::do_parameter(const std::string& p)
190 {
191   // ???
192 }
193
194 void
195 TPushParser::do_subscript()
196 {
197   TNode parent = cursor.parent();
198   if (parent.isG())
199     {
200       TNode prev = cursor.prev();
201       if (!prev)
202         {
203           TNode elem = doc.create("sb", nextId++);
204           TNode g = doc.createG();
205           cursor.replace(elem);
206           elem.append(g);
207           elem.append(cursor);
208         }
209       else
210         {
211           TNode elem = doc.create("sb", nextId++);
212           prev.replace(elem);
213           elem.append(prev);
214           elem.append(cursor);
215         }
216     }
217   else if (parent.isSb() && cursor == parent[1])
218     {
219       if (parent["under"] == "1") cerr << "already under" << endl;
220       else parent["under"] = "1";
221     }
222 }
223
224 void
225 TPushParser::do_superscript()
226 {
227   TNode parent = cursor.parent();
228   if (parent.isG())
229     {
230       TNode prev = cursor.prev();
231       if (!prev)
232         {
233           TNode elem = doc.create("sp", nextId++);
234           TNode g = doc.createG();
235           cursor.replace(elem);
236           elem.append(g);
237           elem.append(cursor);
238         }
239       else
240         {
241           TNode elem = doc.create("sp", nextId++);
242           prev.replace(elem);
243           elem.append(prev);
244           elem.append(cursor);
245         }
246     }
247   else if (parent.isSp() && cursor == parent[1])
248     {
249       if (parent["over"] == "1") cerr << "already over" << endl;
250       else parent["over"] = "1";
251     }
252 }
253
254 void
255 TPushParser::do_space(const std::string&)
256 {
257   // ? may be used to distinguish tokens in some mode?
258 }
259
260 void
261 TPushParser::do_letter(const std::string& s)
262 {
263   //TNode parent = cursor.parent();
264   TNode elem = doc.createI(s, nextId++);
265   cursor.replace(elem);
266   advance(elem);
267 }
268
269 void
270 TPushParser::do_digit(const std::string& s)
271 {
272   TNode parent = cursor.parent();
273   TNode prev = cursor.prev();
274   if (prev && parent.isG() && prev.is("n"))
275     {
276       TNode elem = doc.createN(prev.value() + s, nextId++);
277       prev.replace(elem);
278     }
279   else
280     {
281       TNode elem = doc.createN(s, nextId++);
282       cursor.replace(elem);
283       advance(elem);
284     }
285 }
286
287 bool
288 TPushParser::isPrimes(const TNode& node) const
289 {
290   assert(node);
291   return node.isG() && node.last() && node.last().is("o") && node.last()["val"] == PRIME();
292 }
293
294 void
295 TPushParser::do_apostrophe()
296 {
297   if (cursor.parent() && cursor.parent().isG())
298     {
299       if (TNode prev = cursor.prev())
300         {
301           if (prev.isSp() && prev[1] && isPrimes(prev[1]))
302             prev[1].append(doc.createO(PRIME(), nextId++));
303           else if (prev.isSb() && prev[0] &&
304                    prev[0].isSp() && prev[0][1] &&
305                    isPrimes(prev[0][1]))
306             prev[0][1].append(doc.createO(PRIME(), nextId++));
307           else
308             {
309               TNode elem = doc.create("sp");
310               TNode g = doc.createG();
311               prev.replace(elem);
312               elem.append(prev);
313               elem.append(g);
314               g.append(doc.createO(PRIME(), nextId++));
315             }
316         }
317       else
318         {
319           // error ???
320         }
321     }
322   else
323     {
324       // error ??
325     }
326 }
327
328 void
329 TPushParser::do_other(const std::string& s)
330 {
331   switch (s[0])
332     {
333     case '\'':
334       do_apostrophe();
335       break;
336     default:
337       cout << "TPushParser::do_other " << s << endl;
338       cout << "DOCUMENT: " << static_cast<GdomeNode*>(cursor.element().get_ownerDocument()) << endl;
339       TNode elem = doc.createT("o", s, nextId++);
340       cursor.replace(elem);
341       advance(elem);  
342       break;
343     }
344 }
345
346 void
347 TPushParser::do_active(const std::string&)
348 {
349   // ??? space?
350 }
351
352 void
353 TPushParser::do_comment()
354 {
355   // ???
356 }
357
358 void
359 TPushParser::do_cr()
360 {
361   TNode parent = cursor.parent();
362   if (parent && parent.isG() &&
363       parent.parent() && parent.parent().is("cell") &&
364       parent.parent().parent() && parent.parent().parent().is("row"))
365     {
366       TNode oldRow = parent.parent().parent();
367       assert(oldRow);
368       TNode table = oldRow.parent();
369       assert(table);
370       TNode row = doc.create("row");
371       TNode cell = doc.create("cell");
372       TNode g = doc.createG();
373       if (oldRow.next()) oldRow.next().insert(row);
374       else table.append(row);
375       row.append(cell);
376       cell.append(g);
377       g.append(cursor);
378     }
379 }
380
381 void
382 TPushParser::do_control(const std::string& name)
383 {
384   if (name == "cr") do_cr();
385   else
386     {
387       TNode parent = cursor.parent();
388       const TDictionary::Entry& entry = dictionary.find(name);
389       switch (entry.cls)
390         {
391         case TDictionary::IDENTIFIER:
392           {
393             TNode t = doc.createI(entry.value, nextId++);
394             t["name"] = name;
395             cursor.replace(t);
396             advance(t);
397           }
398           break;
399         case TDictionary::OPERATOR:
400           {
401             TNode t = doc.createO(entry.value, nextId++);
402             t["name"] = name;
403             cursor.replace(t);
404             advance(t);
405           }
406           break;
407         case TDictionary::NUMBER:
408           {
409             TNode t = doc.createN(entry.value, nextId++);
410             t["name"] = name;
411             cursor.replace(t);
412             advance(t);
413           }
414           break;
415         case TDictionary::MACRO:
416           {
417             TNode m = doc.createC(name, nextId++);
418             cursor.replace(m);
419             
420             cout << "ecco tutti i token del pattern della entry inserita" << endl;
421             for (unsigned i = 0; i < entry.pattern.size(); i++)
422               cout << entry.pattern[i].value << endl;
423             
424             if (entry.leftOpen && entry.rightOpen)
425               {
426                 assert(entry.pattern.empty());
427                 assert(parent.isG());
428                 TNode g1 = doc.createG();
429                 g1["left-open"] = "1";
430                 g1.append(parent.first(), m);
431                 m.append(g1);
432                 TNode g2 = doc.createG();
433                 g2.append(cursor);
434                 m.append(g2);
435                 frames.push(Frame(entry));
436               }
437             else if (entry.leftOpen)
438               {
439                 assert(parent.isG());
440                 TNode g = doc.createG();
441                 g["left-open"] = "1";
442                 g.append(parent.first(), m);
443                 m.append(g);
444                 advance(m);
445               }
446             else if (entry.rightOpen)
447               {
448                 assert(entry.pattern.empty());
449                 assert(parent.isG());
450                 TNode g = doc.createG();
451                 g.append(cursor);
452                 m.append(g);
453                 frames.push(Frame(entry));
454               }
455             else if (!entry.pattern.empty())
456               {
457                 if (parent.isG())
458                   {
459                     frames.push(Frame(entry));
460
461                     if (entry.table)
462                       cout << "do_control: we have a table" << endl;
463                     
464                     if (entry.paramDelimited(0))
465                       {
466                         cout << "do_control: it'a MACRO with delimited first argument" << endl;
467                         TNode g = doc.createG();
468                         m.append(g);
469                         g.append(cursor);
470                       }
471                     else
472                       m.append(cursor);
473                   }
474                 else
475                   {
476                     // error, but we could handle this very easily
477                     cerr << "error, but we could handle this easily" << endl;
478                   }
479               }
480             else advance(m);
481           }
482           break;
483         case TDictionary::UNDEFINED:
484           {
485             cerr << "ERROR: using undefined macro `" << name << "'" << endl;
486             TNode m = doc.createC(name, nextId++);
487             cursor.replace(m);
488             advance(m);
489           }
490           break;
491         default:
492           assert(0);
493         }
494     }
495 }
496
497 void
498 TPushParser::gdelete_prev()
499 {
500   // if in this function, the prev of cursor does exist, also the parent and we want a graphical deleting.
501
502   assert(cursor.prev());
503   assert(cursor.parent());
504
505   TNode prev = cursor.prev();
506   if (prev.is("i") || prev.is("o") || prev.is("n"))
507     {
508       // the control below is designed to handle the case in which val have more than one unicode character
509       DOM::UCS4String ucs4val(prev.element().getAttribute("val"));
510       if ((ucs4val.length() <= 1) || prev.element().hasAttribute("name"))
511         {
512           cursor.remove();
513           prev.replace(cursor);
514
515           if (cursor.parent().isC())
516             {
517               // in this case we have removed an element of a MACRO. 
518               // we can assert that this element was a non delimited argument
519               assert(!frames.empty());
520               Frame& frame = frames.top();
521               assert(frame.pos > 0);
522
523               frame.pos--;
524             }
525         }
526       else
527         {
528           ucs4val.erase(ucs4val.length() - 1, 1);
529           prev.element().setAttribute(DOM::GdomeString("val"), DOM::GdomeString(ucs4val));
530         }
531     } // end of if (prev.is("i") || ...)
532   else if (prev.is("sp") || prev.is("sb"))
533     {
534       cursor.remove();
535       prev.append(cursor);
536       gdelete_prev();
537     } // end of if (prev.is("sp") || prev.is("sb"))
538   else if (prev.isG())
539     {
540       cursor.remove();
541       prev.append(cursor);
542       do_gdelete();
543     }
544   else if (prev.isC() && dictionary.find(prev["name"]).cls != TDictionary::UNDEFINED)
545     {
546       const TDictionary::Entry& entry = dictionary.find(prev["name"]);
547
548       // i start to remove a MACRO. The frame associated to this MACRO was 
549       // popped from the stack (i think). So, i re-push the frame in the stack,
550       // but the pos member should be set correctly
551       cout << "gdelete_prev: i have to start to delete a MACRO" << endl;
552       
553       // if the control element is leftOpen and rightOpen, the cursor should be placed after 
554       // the last child of the control element's last child
555       if (entry.rightOpen)
556         {
557           cout << "gdelte_prev(): i have to delete a control rightOpen, so i push an element in the stack" << endl;
558           Frame frame(entry);
559           frames.push(frame);
560           
561           cursor.remove();
562           prev.last().append(cursor);
563           do_gdelete();
564         }
565       else if (entry.leftOpen)
566         {
567           cout << "gdelete_prev: i have to delete a control element with leftOpen" << endl;
568           assert(prev.first());
569           assert(prev.first().isG());
570           assert(prev.first() == prev.last());
571           TNode g = prev.first();
572           g.remove();
573           prev.replace(g.first(), TNode());
574         }
575       else if (!entry.pattern.empty())
576         { 
577           // we have to start removing a MACRO which accepts arguments.
578           // a MACRO without child does not exist
579           
580           cout << "gdelete_prev: i have to remove a MACRO with argument" << endl;
581
582           assert(prev.size() >= 1);
583
584           if (prev.last().isG() && !prev.last().hasId())
585             {
586               // this means that the last child of the MACRO is a phantom group,
587               // which in turn means that it is a delimited argument
588               // so we have to ideally remove this delimiter
589               cursor.remove();
590               prev.last().append(cursor);
591               // i have to push a frame with a correct value of pos
592               Frame frame(entry);
593               assert(entry.previousParam(entry.pattern.size()) != entry.pattern.size());
594               unsigned sequence_length = entry.pattern.size() - entry.previousParam(entry.pattern.size()) - 1;
595               frame.pos = entry.pattern.size() - sequence_length - 1;
596               frames.push(frame);
597               cout << "gdelete_prev: i have inserted a frame, it's pos is: " << frames.top().pos << endl;
598             }
599           else
600             {
601               // in this case, the last child of the MACRO is 
602               // an argument which is NOT delimited, so i try to 
603               // remove it
604               cout << "gdelete_prev: i try to remove the last argumet of the MACRO" << endl;
605               cursor.remove();
606               if (entry.table == 1 && prev.last().is("row"))
607                 {
608                   // in this case should be appended to the group associated to 
609                   // the last cell of the last row of the table
610                   assert(prev.last().last().is("cell") && prev.last().last().first().isG());
611                   prev.last().last().first().append(cursor);
612                 }
613               else prev.append(cursor);
614
615               Frame frame(entry);
616               frame.pos = entry.pattern.size();
617               frames.push(frame);
618               
619               if (cursor.prev()) gdelete_prev();
620               else do_gdelete();
621
622             }
623         }
624     }
625   else if (dictionary.find(prev["name"]).cls == TDictionary::UNDEFINED)
626     {
627       // The user wants to delete an undefined element.
628       // I suppose that he (or she) wants to delete it all
629       cursor.remove();
630       prev.replace(cursor);
631     }
632   else 
633     {
634       // not handled
635     }
636   
637 } // end of method
638
639 void
640 TPushParser::rgreplace_futher(void)
641 {
642   // this function MUST only be invoked, when the cursor
643   // is the only child of a group with id. This function 
644   // replace the group with the cursor. But if the new parent
645   // is a group with id and the cursor is the only child of the 
646   // group, the new parent is replaced...and so on.
647   // r stands for recursive, g stands for graphical
648   assert(cursor.parent());
649   assert(cursor.parent().isG() && cursor.parent().hasId());
650
651   TNode parent = cursor.parent();
652
653   while (parent.isG() && parent.hasId() && (parent.first() == cursor))
654     {
655       parent.replace(cursor);
656       parent = cursor.parent();
657     }
658
659   if (parent.isC())
660     {
661       // in this case we have removed a MACRO's child. 
662       // I can assert that this MACRO accepts arguments.
663       assert(!frames.empty());
664       Frame& frame = frames.top();
665       assert(frame.pos > 0);
666       frame.pos--;
667     }
668 }
669
670 void
671 TPushParser::do_gdelete()
672 {
673   // this function operates a graphical deleting
674   
675   //if (!frames.empty())
676   //  cout << "do_gdelete: c'e' un frame aperto e il suo pos vale: " << frames.top().pos << endl;
677   
678   TNode parent = cursor.parent();
679
680   // if no parent, do nothing
681   if (parent)
682     {
683       assert(parent);
684       if (parent.isG())
685         {
686           TNode prev = cursor.prev();
687           if (prev)
688             {
689               // i try to delete the preceding element
690               gdelete_prev();
691
692               if ((parent.first() == cursor) && parent.isG() && parent.hasId())
693                 rgreplace_futher();
694
695             }
696           else // no previous node is present
697             {
698               // if here, we are in a gruop whose only child is the cursor.
699               
700               if (!parent.hasId())
701                 {
702                   // the parent is a phantom group
703                   assert(parent.parent());
704                   if (!parent.parent().is("math"))
705                     {
706                       TNode gfuther = parent.parent();
707
708                       // if the grand futher is a group with Id, it should be removed, 
709                       // but i don't know if it will never occur...
710                       if (gfuther.isG() && gfuther.hasId())
711                         {
712                           cursor.remove();
713                           parent.replace(cursor);
714
715                           // re-start the process
716                           do_gdelete();
717                         }
718                       else if (gfuther.isC())
719                         {
720                           // the grand futher is a control element: since the parent is a phantom group, 
721                           // the TML tree should be in a inconsistent state (once removed the parent).
722
723                           // being here means that there is a frame in the stack
724                           assert(!frames.empty());
725                           cout << "do_gdelete: i have to remove a phantom group whuch is a child of a MACRO" << endl;
726                           Frame& frame = frames.top();
727                           if (frame.entry.leftOpen && frame.entry.rightOpen)
728                             {
729                               // in this case, the cursor is in the second and last child 
730                               // of the MACRO. We can assert that the grand futher has two 
731                               // children. which are both phantom group
732                               cout << "do_gdelete: the MACRO is leftOpen and rigthOpen" << endl;
733                               assert(gfuther.size() == 2);
734                               assert((gfuther.last() == parent) && (gfuther.first().isG() && !gfuther.first().hasId()));
735                               assert(frame.pos == 0);
736                             
737                               TNode ggfuther = gfuther.parent();
738                               assert(ggfuther);
739                               cursor.remove();
740                               parent.remove();
741                               // i have to replace the gfuther with the elements of its first child
742                               gfuther.replace(gfuther.first().first(), TNode());
743                               cout << "do_gdelete: i have removed the control element, and replaced it with its first child" << endl;
744                               ggfuther.append(cursor);
745                               cout << "do_gdelete: cursor appended to the grand grand futher" << endl;
746
747                               // now we have the situation preceding the insertion of the MACRO leftOpen and rightOpen
748                               // this MACRO no longer exists.
749                               frames.pop();
750                             }
751                           else if (frame.entry.rightOpen)
752                             {
753                               // the user has inserted a MACRO rightOpen. Since the cursor is the 
754                               // only child of the MACRO, the user want to remove it. 
755                               // We can assert that cursor's parent is the only child of the MACRO
756                               cout << "do_gdelete: the MACRO is rightOpen only" << endl;
757                               assert(gfuther.size() == 1);
758                               assert(frame.pos == 0); // i think this assert has no sense
759                             
760                               cursor.remove();
761                               parent.remove();
762                               gfuther.replace(cursor);
763
764                               // now we have the situation preceding the MACRO rightOpen, so i have to pop the frame
765                               frames.pop();
766                             }
767                           else if (frame.entry.leftOpen)
768                             {
769                               // it' s an unpredicted situation
770                               cout << "it's a bad situation, maybe handlable, but unpredicted" << endl;
771                             }
772                           else if (!frame.entry.pattern.empty())
773                             {
774                               // the MACRO (the cursor's grand futher) accepts arguments.
775                               // we have to control if the cursor's uncle does exist.
776
777                               if (parent.prev())
778                                 {
779                                   // in this case, we can assert that frame in the stack has 
780                                   // pos greater than 0
781                                   assert(frame.pos > 0);
782                                 
783                                   // cursor's uncle does exist. we have to control 
784                                   // its nature (is it a phantom group?)
785                                   TNode uncle = parent.prev();
786                                   if (uncle.isG() && !uncle.hasId())
787                                     {
788                                       // the cursor's uncle is a phantom group, so it was a 
789                                       // delimited argument of the MACRO and the corrisponding sequence of 
790                                       // delimeters is inserted. So, the action of deleting means
791                                       // removing this sequence
792                                       assert(frame.pos > 1);
793                                       unsigned sequence_length = frame.pos - frame.entry.previousParam(frame.pos) - 1;
794                                       assert(frame.entry.previousParam(frame.pos) != frame.entry.pattern.size());
795                                       assert(sequence_length);
796                                       // sequence_length is the length of the delimiters sequence which separates
797                                       // the current parameter and the previous parameter
798                                       frame.pos = frame.pos - sequence_length - 1;
799                                       cursor.remove();
800                                       parent.remove();
801                                       uncle.append(cursor);
802                                     }
803                                   else
804                                     {
805                                       // the uncle was a NOT delimited argument. So i try to 
806                                       // remove it
807                                       cursor.remove();
808                                       parent.replace(cursor);
809                                   
810                                       parent = cursor.parent(); // i update the parent (it should be the MACRO)
811                                       assert(parent.isC());
812                                   
813                                       gdelete_prev();
814
815                                     }
816                                 }
817                               else
818                                 {
819                                   // cursor's parent is the only child of the MACRO, which accepts arguments
820                                   // i can assert that frame.pos == 0.
821                                   // In this case i can replace the MACRO with the cursor
822                                   assert(frame.pos == 0);
823
824                                   cursor.remove();
825                                   parent.remove();
826                                   gfuther.replace(cursor);
827
828                                   frames.pop();
829                                 }
830                             
831                             }
832                         }
833                       else if (gfuther.is("cell"))
834                         {
835                           // being here means that there is a frame in the stack 
836                           // associated to the "table"
837                           cout << "do_gdelete: i have to delete a cell" << endl;
838                           assert(!frames.empty());
839                           assert(frames.top().pos == 1);
840                           assert(frames.top().entry.table == 1);
841                           // a cell MUST be child of row element, which in turn MUST be child of an element 
842                           // havin attribute table.
843                           assert(gfuther.parent() && gfuther.parent().is("row") && gfuther.parent().parent());
844                           TNode row = gfuther.parent();
845
846                           // in this case the cell has no element, so the user wants to delete this cell.
847                           TNode prev_cell = gfuther.prev();
848                           
849                           cursor.remove();
850                           parent.remove();
851                           gfuther.remove();
852                           // now the cell no longer exists
853                           
854                           if (!prev_cell)
855                             {
856                               // i this case, the cell is the only cell in the row.
857                               // So, i assume that the user wants to delete the entire row.
858                               TNode table = row.parent();
859                               TNode prev_row = row.prev();
860                               row.remove();
861                               if (!prev_row)
862                                 {
863                                   // the row was the only child of the table. 
864                                   // I think have to delete the entire table
865                                   assert(table.parent());
866                                   TNode parent_table = table.parent();
867                                   table.remove();
868                                   frames.pop();
869                                   parent_table.append(cursor);
870                                 }
871                               else
872                                 {
873                                   // there are other rows (one at least)
874                                   assert(prev_row.is("row"));
875                                   assert(prev_row.last());
876                                   TNode last_cell = prev_row.last();
877                                   assert(last_cell.is("cell"));
878                                   assert(last_cell.size() == 1);
879                                   assert(last_cell.first().isG() && !last_cell.first().hasId());
880                                   last_cell.first().append(cursor);
881                                 }
882                             }
883                           else
884                             {
885                               // being here means that there is a previous cell,
886                               // so we append the cursor to group.
887                               assert(prev_cell.size() == 1);
888                               assert(prev_cell.first().isG() && !prev_cell.first().hasId());
889                               prev_cell.first().append(cursor);
890                             }
891                         }
892                     }
893                   else // the grand futher is math
894                     {
895                       // nothing to do...i think
896                       assert(frames.empty());
897                     }
898                 }
899               else
900                 { 
901                   // the parent is a group with id and has no elements other than cursor
902                   // so we replace it with the cursor.
903                   rgreplace_futher();
904
905                   // i have to re-start the process, because it' a graphical delete
906                   do_gdelete();
907                 }
908             }
909         }
910       else if (parent.isC())
911         {
912           // being here means that there is an open frame for the control element
913           // and this element is closed at either side (no leftOpen no rightOpen)
914           // and the MACRO was waiting for a non delimited argument, so 
915           // we can assert that frame.entry.pattern.size() >= 1
916           assert(!frames.empty());
917           Frame& frame = frames.top();
918
919           assert(frame.entry.pattern.size() >= 1);
920
921           cout << "do_gdelete: frames.top().pos = " << frames.top().pos << endl;
922
923           TNode prev = cursor.prev();
924
925           if (!prev)
926             {
927               // in this case we can replace the MACRO with the cursor 
928               // and pop the stack and we can assert that frame.pos == 0
929               assert(frame.pos == 0);
930               cursor.remove(); // it should not be necessary, but i'm not shure
931               parent.replace(cursor);
932               frames.pop();
933             }
934           else
935             {
936               // in this case the cursor has a preceding element 
937               // and there are differnt things based on the nature 
938               // of the prev: if it's a phantom group do something,
939               // else do something else
940               if (prev.isG() && !prev.hasId())
941                 {
942                   // in this case we have to append the cursor 
943                   // to the prev and decrement frame.pos of the length of 
944                   // delimiters sequence that delimitates the preceding argument.
945                   // So we ideally remove this sequence
946                   assert(frame.pos > 1);
947                   cursor.remove();
948                   prev.append(cursor);
949                   assert(frame.entry.previousParam(frame.pos) != frame.entry.pattern.size());
950                   unsigned sequence_length = frame.pos - frame.entry.previousParam(frame.pos) - 1;
951                   assert(sequence_length);
952                   frame.pos = frame.pos - sequence_length - 1;
953                 }
954               else
955                 {
956                   // the prev is an non delimited argument, so we try to 
957                   // remove it.
958                   gdelete_prev();
959                 }
960             }
961         }
962       else if (parent.is("sp") || parent.is("sb"))
963         {
964           // being here means that a prev MUST exist 
965           // and that there is only an element preceding the cursor.
966           // The sp's (or sb's) parent MUST NOT be a MACRO
967
968           assert(parent.size() == 2);
969           assert(parent.parent() && !parent.parent().isC());
970           
971           TNode prev = cursor.prev();
972           cursor.remove();
973           if (prev.isG() /*&& !prev.hasId()*/ && (prev.size() == 0))
974             {
975               prev.remove();
976               parent.replace(cursor);
977
978               // now, cursor should be the only parent's child
979               assert(cursor.parent().size() == 1);
980
981               if (cursor.parent().isG() && cursor.parent().hasId()) rgreplace_futher();
982             }
983           else
984             {
985               assert(prev.hasId());
986               parent.replace(prev);
987               prev.parent().append(cursor);
988               // now prev should have a preceding element
989               assert(cursor.parent().size() > 1);
990             } 
991         }
992       else
993         {
994           // not handled: no control for tables, ...
995         }
996     }
997   else
998     {
999       // the cursor has no parent!!!
1000       // do nothing?
1001       // emit an error? and if we want to emit an error, in which way?
1002     }
1003
1004 } // end of method
1005
1006 void
1007 TPushParser::process(const TToken& token)
1008 {
1009   switch (token.category)
1010     {
1011     case TToken::BEGIN: do_begin(); break;
1012     case TToken::END: do_end(); break;
1013     case TToken::SHIFT: do_shift(); break;
1014     case TToken::ALIGN: do_align(); break;
1015     case TToken::EOL: do_eol(); break;
1016     case TToken::PARAMETER: do_parameter(token.value); break;
1017     case TToken::SUPERSCRIPT: do_superscript(); break;
1018     case TToken::SUBSCRIPT: do_subscript(); break;
1019     case TToken::SPACE: do_space(token.value); break;
1020     case TToken::LETTER: do_letter(token.value); break;
1021     case TToken::DIGIT: do_digit(token.value); break;
1022     case TToken::OTHER: do_other(token.value); break;
1023     case TToken::ACTIVE: do_active(token.value); break;
1024     case TToken::COMMENT: do_comment(); break;
1025     case TToken::CONTROL: do_control(token.value); break;
1026     case TToken::GDELETE: do_gdelete(); break;
1027     }
1028 }
1029
1030 void
1031 TPushParser::push(const TToken& token)
1032 {
1033   cerr << "TPushParser::push " << token.value << " (cat: " << token.category << ")" << endl;
1034
1035   if (token.category == TToken::GDELETE)
1036     {
1037       cout << "push: i have to process a token with category member = GDELETE" << endl;
1038       process(token);
1039     }
1040   else if ((doc.root().first() && doc.root().first().is("math")) || token.category == TToken::SHIFT)
1041     {
1042
1043       TNode parent = cursor.parent();
1044       // If the cursor has no parent then it is detached from the editing
1045       // tree, which means this token will be ignored
1046
1047       if (parent)
1048         // If the parent is a phantom group and the grand-parent is a
1049         // control sequence, there are two cases:
1050         // a. we are parsing a delimited argument of a entry
1051         // b. we are parsing a side of a right- or left-open entry
1052         if (parent.isG() && !parent.hasId() && parent.parent().isC())
1053           {
1054             // There must be an open frame, for the grand-parent is a control sequence
1055             assert(!frames.empty());
1056             Frame& frame = frames.top();
1057             if (!frame.entry.pattern.empty())
1058               {
1059                 // The entry pattern is not empty. By our conventions this means
1060                 // the entry cannot be open at either end, hence we are parsing
1061                 // a delimited argument
1062                 assert(frame.pos + 1 < frame.entry.pattern.size());
1063                 assert(frame.entry.pattern[frame.pos + 1].category != TToken::PARAMETER);
1064                 if (frame.entry.pattern[frame.pos + 1] == token)
1065                   {
1066                     // The token matches with a delimiter of the argument, 
1067                     // so we increment the frame.pos
1068                     frame.pos++;
1069
1070                     if (frame.entry.lastDelimiter(frame.pos))
1071                       {
1072                         // this delimiter is the last one for the argumet, 
1073                         // so the argument is completed
1074                         cursor.remove();
1075                         frame.pos++;
1076
1077                         if (frame.pos == frame.entry.pattern.size())
1078                           {
1079                             // This token has completed the entry
1080                             frames.pop();
1081                             advance(parent.parent());
1082                           }
1083                         else if (frame.entry.paramDelimited(frame.pos))
1084                           {
1085                             // For the next is a delimited argument we have to place
1086                             // a suitable phantom group with the cursor inside
1087                             TNode g = doc.createG();
1088                             parent.parent().append(g);
1089                             g.append(cursor);
1090                           }
1091                         else
1092                           parent.parent().append(cursor);
1093                       }
1094                   }
1095                 else
1096                   {
1097                     // Delimiter mismatch.
1098                     if (frame.entry.pattern[frame.pos].category != TToken::PARAMETER)
1099                       {
1100                         // in this case, there is a sequence of delimiters that delimitates
1101                         // the argument, and the user correctly inserted a portion of this 
1102                         // sequence, but has inserted a wrong delimiter.
1103                         // Here, there are some possibilities:
1104                         //   - ignore the token, and wait for the correct delimiter
1105                         //   - ignore the token, wait for the correct delimiter and emit an error
1106                         // If we want to emit an error, we shlould implement a class, that handle 
1107                         // the error.
1108                         // At the moment, the error is printed to screen
1109                         cout << "push: it's not the correct delimiter...you have to type " << frame.entry.pattern[frame.pos + 1].value << endl;
1110                       }
1111                     else
1112                       {
1113                         // in this case, the sequence of delimiters is composed of one 
1114                         // delimiter. It means that we have to process the token
1115                         process(token);
1116                       }
1117                   }
1118               }
1119             else
1120               {
1121                 // The entry pattern is empty, hence we are parsing a right-open
1122                 // entry. What happens if we actually are in the left side?
1123                 // This could happen only when re-editing an entered expression
1124                 // We'll see...
1125                 assert(frame.entry.rightOpen);
1126                 process(token);
1127               }
1128           }
1129         else if (parent.isC())
1130           {
1131             // We are parsing a non-delimited argument entry
1132             // or a fixed token
1133             Frame& frame = frames.top();
1134             assert(frame.pos < frame.entry.pattern.size());
1135
1136             cout << "push: there is a frame with pos " << frame.pos <<  endl;
1137             if (frame.entry.pattern[frame.pos].category == TToken::PARAMETER)
1138               {
1139                 // As by the TeX parsing rules of undelimited parameters,
1140                 // empty spaces are ignored
1141                 if (token.category != TToken::SPACE)
1142                   {
1143                     // We need to increase the frame position here, becase inside
1144                     // process the function advance will be called. At that point
1145                     // it will be important for the parser to know that the entry
1146                     // has been completed in order to place the cursor correctly
1147                     // in the next position
1148                     frame.pos++;
1149                     process(token);
1150                   }
1151               }
1152             else if (frame.entry.pattern[frame.pos] == token)
1153               {
1154                 // The token has been accepted
1155                 frame.pos++;
1156                 if (frame.pos < frame.entry.pattern.size() &&
1157                     frame.entry.paramDelimited(frame.pos))
1158                   {
1159                     // If the next is a delimited argument we have to place
1160                     // the phantom group with the cursor inside
1161                     TNode g = doc.createG();
1162                     cursor.replace(g);
1163                     g.append(cursor);
1164                   }
1165                 else
1166                   advance(parent);
1167               }
1168             else
1169               {
1170                 // There is a mismatch. Emit an error and ignore the token?
1171                 cerr << "ERROR: token ignored: " << token.value << " (cat: " << token.category << ")" << endl;
1172               }
1173
1174           }
1175         else
1176           process(token);
1177       else
1178         {
1179           cout << "ignored token" << endl;
1180         }
1181       
1182       //if (listener) listener->callback(doc); //it shoul be repristened if you remove the comment in the else above
1183
1184     } // this end corresponds to the if ((doc.root().first() && doc.root().first().is("math")) || token.category == TToken::SHIFT)
1185   else
1186     {
1187       // there is no math element
1188       // In this case, i think we have to emit an error
1189       cout << "push: ignored token...you have to enter in math mode...insert $" << endl;
1190     }
1191
1192   if (factory) factory->documentModified(doc);
1193
1194   if (frames.empty()) cout << "stack vuoto" << endl;
1195   else cout << "stack non vuoto" << endl;
1196 }
1197
1198 void
1199 TPushParser::advance(const TNode& node)
1200 {
1201   assert(node);
1202   TNode parent = node.parent();
1203   if (!parent)
1204     ; // nothing to do, the cursor is not in the document any more
1205   else if (parent.isG())
1206     {
1207       TNode next = node.next();
1208       if (next) next.insert(cursor);
1209       else parent.append(cursor);
1210     }
1211   else if (parent.isC())
1212     {
1213       if (node.next())
1214         ; // cursor removed
1215       else
1216         {
1217           Frame& frame = frames.top();
1218           if (frame.pos == frame.entry.pattern.size())
1219             {
1220               frames.pop();
1221               advance(parent);
1222             }
1223           else
1224             parent.append(cursor);
1225         }
1226     }
1227   else if (parent.is("math"))
1228     ; // we are done
1229   else
1230     advance(parent);
1231 }
1232
1233 void
1234 TPushParser::setCursorHint(const std::string& c)
1235 {
1236   cursor["val"] = c;
1237   if (factory) factory->documentModified(doc);
1238 }