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