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