3 #include "TPushParser.hh"
4 #include "AMathMLFactory.hh"
6 TPushParser::TPushParser(ALogger& l, const TDictionary& d) : APushParser(l), dictionary(d)
11 TPushParser::TPushParser(ALogger& l, AMathMLFactory& f, const TDictionary& d) : APushParser(l, f), dictionary(d)
20 cursor = doc.create("cursor");
23 doc.root().append(cursor);
26 TPushParser::~TPushParser()
31 TPushParser::PRIME() const
33 const TDictionary::Entry entry = dictionary.find("prime");
34 if (entry.cls == TDictionary::OPERATOR) return entry.value;
39 TPushParser::do_begin()
41 TNode parent = cursor.parent();
42 if (parent.isC() && dictionary.find(parent.nameC()).table)
44 TNode row = doc.create("row");
45 TNode cell = doc.create("cell");
46 TNode g = doc.createG();
54 TNode g = doc.createG(nextId++);
63 TNode parent = cursor.parent();
64 if (parent && parent.isG() && parent.hasId())
66 // normal closing brace for an explicitly open group
70 else if (parent && parent.isG() && parent.parent() && parent.parent().is("cell"))
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();
80 // now we have to pop the associated frame in the stack
83 else if (parent && parent.isG() && !parent.hasId() && parent.parent())
85 // closing brace for a right-open macro (like \over)
87 advance(parent.parent());
98 TPushParser::do_shift()
100 TNode parent = cursor.parent();
102 if (parent.is("tex"))
104 TNode math = doc.create("math", nextId++);
105 TNode g = doc.createG();
106 cursor.replace(math);
110 else if (parent.isG() && !parent.hasId() && parent.parent() && parent.parent().is("math"))
114 // there is something before the cursor, hence this is the
115 // closing math shift
116 if (parent.parent()["display"] != "1")
118 // one math shift is enough to close it
123 // we need two closing math shifts
124 parent.parent().append(cursor);
127 else if (parent.parent()["display"] != "1")
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";
135 parent.parent().append(cursor);
138 else if (parent.is("math"))
144 cerr << "ERROR: math shift" << endl;
149 TPushParser::do_align()
151 TNode parent = cursor.parent();
152 if (parent && parent.isG() && parent.hasId())
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();
160 g.append(parent.first(), cursor);
162 else if (parent && parent.isG() && parent.parent().is("cell"))
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();
178 cerr << "alignment tab used outside matrix" << endl;
183 TPushParser::do_eol()
185 //if (cursor.parent()) cursor.remove();
189 TPushParser::do_parameter(const std::string& p)
195 TPushParser::do_subscript()
197 TNode parent = cursor.parent();
200 TNode prev = cursor.prev();
203 TNode elem = doc.create("sb", nextId++);
204 TNode g = doc.createG();
205 cursor.replace(elem);
211 TNode elem = doc.create("sb", nextId++);
217 else if (parent.isSb() && cursor == parent[1])
219 if (parent["under"] == "1") cerr << "already under" << endl;
220 else parent["under"] = "1";
225 TPushParser::do_superscript()
227 TNode parent = cursor.parent();
230 TNode prev = cursor.prev();
233 TNode elem = doc.create("sp", nextId++);
234 TNode g = doc.createG();
235 cursor.replace(elem);
241 TNode elem = doc.create("sp", nextId++);
247 else if (parent.isSp() && cursor == parent[1])
249 if (parent["over"] == "1") cerr << "already over" << endl;
250 else parent["over"] = "1";
255 TPushParser::do_space(const std::string&)
257 // ? may be used to distinguish tokens in some mode?
261 TPushParser::do_letter(const std::string& s)
263 //TNode parent = cursor.parent();
264 TNode elem = doc.createI(s, nextId++);
265 cursor.replace(elem);
270 TPushParser::do_digit(const std::string& s)
272 TNode parent = cursor.parent();
273 TNode prev = cursor.prev();
274 if (prev && parent.isG() && prev.is("n"))
276 TNode elem = doc.createN(prev.value() + s, nextId++);
281 TNode elem = doc.createN(s, nextId++);
282 cursor.replace(elem);
288 TPushParser::isPrimes(const TNode& node) const
291 return node.isG() && node.last() && node.last().is("o") && node.last()["val"] == PRIME();
295 TPushParser::do_apostrophe()
297 if (cursor.parent() && cursor.parent().isG())
299 if (TNode prev = cursor.prev())
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++));
309 TNode elem = doc.create("sp");
310 TNode g = doc.createG();
314 g.append(doc.createO(PRIME(), nextId++));
329 TPushParser::do_other(const std::string& s)
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);
347 TPushParser::do_active(const std::string&)
353 TPushParser::do_comment()
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"))
366 TNode oldRow = parent.parent().parent();
368 TNode table = oldRow.parent();
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);
382 TPushParser::do_control(const std::string& name)
384 if (name == "cr") do_cr();
387 TNode parent = cursor.parent();
388 const TDictionary::Entry& entry = dictionary.find(name);
391 case TDictionary::IDENTIFIER:
393 TNode t = doc.createI(entry.value, nextId++);
399 case TDictionary::OPERATOR:
401 TNode t = doc.createO(entry.value, nextId++);
407 case TDictionary::NUMBER:
409 TNode t = doc.createN(entry.value, nextId++);
415 case TDictionary::MACRO:
417 TNode m = doc.createC(name, nextId++);
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;
424 if (entry.leftOpen && entry.rightOpen)
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);
432 TNode g2 = doc.createG();
435 frames.push(Frame(entry));
437 else if (entry.leftOpen)
439 assert(parent.isG());
440 TNode g = doc.createG();
441 g["left-open"] = "1";
442 g.append(parent.first(), m);
446 else if (entry.rightOpen)
448 assert(entry.pattern.empty());
449 assert(parent.isG());
450 TNode g = doc.createG();
453 frames.push(Frame(entry));
455 else if (!entry.pattern.empty())
459 frames.push(Frame(entry));
462 cout << "do_control: we have a table" << endl;
464 if (entry.paramDelimited(0))
466 cout << "do_control: it'a MACRO with delimited first argument" << endl;
467 TNode g = doc.createG();
476 // error, but we could handle this very easily
477 cerr << "error, but we could handle this easily" << endl;
483 case TDictionary::UNDEFINED:
485 cerr << "ERROR: using undefined macro `" << name << "'" << endl;
486 TNode m = doc.createC(name, nextId++);
498 TPushParser::gdelete_prev()
500 // if in this function, the prev of cursor does exist, also the parent and we want a graphical deleting.
502 assert(cursor.prev());
503 assert(cursor.parent());
505 TNode prev = cursor.prev();
506 if (prev.is("i") || prev.is("o") || prev.is("n"))
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"))
513 prev.replace(cursor);
515 if (cursor.parent().isC())
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);
528 ucs4val.erase(ucs4val.length() - 1, 1);
529 prev.element().setAttribute(DOM::GdomeString("val"), DOM::GdomeString(ucs4val));
531 } // end of if (prev.is("i") || ...)
532 else if (prev.is("sp") || prev.is("sb"))
537 } // end of if (prev.is("sp") || prev.is("sb"))
544 else if (prev.isC() && dictionary.find(prev["name"]).cls != TDictionary::UNDEFINED)
546 const TDictionary::Entry& entry = dictionary.find(prev["name"]);
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;
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
557 cout << "gdelte_prev(): i have to delete a control rightOpen, so i push an element in the stack" << endl;
562 prev.last().append(cursor);
565 else if (entry.leftOpen)
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();
573 prev.replace(g.first(), TNode());
575 else if (!entry.pattern.empty())
577 // we have to start removing a MACRO which accepts arguments.
578 // a MACRO without child does not exist
580 cout << "gdelete_prev: i have to remove a MACRO with argument" << endl;
582 assert(prev.size() >= 1);
584 if (prev.last().isG() && !prev.last().hasId())
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
590 prev.last().append(cursor);
591 // i have to push a frame with a correct value of pos
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;
597 cout << "gdelete_prev: i have inserted a frame, it's pos is: " << frames.top().pos << endl;
601 // in this case, the last child of the MACRO is
602 // an argument which is NOT delimited, so i try to
604 cout << "gdelete_prev: i try to remove the last argumet of the MACRO" << endl;
606 if (entry.table == 1 && prev.last().is("row"))
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);
613 else prev.append(cursor);
616 frame.pos = entry.pattern.size();
619 if (cursor.prev()) gdelete_prev();
625 else if (dictionary.find(prev["name"]).cls == TDictionary::UNDEFINED)
627 // The user wants to delete an undefined element.
628 // I suppose that he (or she) wants to delete it all
630 prev.replace(cursor);
640 TPushParser::rgreplace_futher(void)
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());
651 TNode parent = cursor.parent();
653 while (parent.isG() && parent.hasId() && (parent.first() == cursor))
655 parent.replace(cursor);
656 parent = cursor.parent();
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);
671 TPushParser::do_gdelete()
673 // this function operates a graphical deleting
675 //if (!frames.empty())
676 // cout << "do_gdelete: c'e' un frame aperto e il suo pos vale: " << frames.top().pos << endl;
678 TNode parent = cursor.parent();
680 // if no parent, do nothing
686 TNode prev = cursor.prev();
689 // i try to delete the preceding element
692 if ((parent.first() == cursor) && parent.isG() && parent.hasId())
696 else // no previous node is present
698 // if here, we are in a gruop whose only child is the cursor.
702 // the parent is a phantom group
703 assert(parent.parent());
704 if (!parent.parent().is("math"))
706 TNode gfuther = parent.parent();
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())
713 parent.replace(cursor);
715 // re-start the process
718 else if (gfuther.isC())
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).
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)
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);
737 TNode ggfuther = gfuther.parent();
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;
747 // now we have the situation preceding the insertion of the MACRO leftOpen and rightOpen
748 // this MACRO no longer exists.
751 else if (frame.entry.rightOpen)
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
762 gfuther.replace(cursor);
764 // now we have the situation preceding the MACRO rightOpen, so i have to pop the frame
767 else if (frame.entry.leftOpen)
769 // it' s an unpredicted situation
770 cout << "it's a bad situation, maybe handlable, but unpredicted" << endl;
772 else if (!frame.entry.pattern.empty())
774 // the MACRO (the cursor's grand futher) accepts arguments.
775 // we have to control if the cursor's uncle does exist.
779 // in this case, we can assert that frame in the stack has
780 // pos greater than 0
781 assert(frame.pos > 0);
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())
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;
801 uncle.append(cursor);
805 // the uncle was a NOT delimited argument. So i try to
808 parent.replace(cursor);
810 parent = cursor.parent(); // i update the parent (it should be the MACRO)
811 assert(parent.isC());
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);
826 gfuther.replace(cursor);
833 else if (gfuther.is("cell"))
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();
846 // in this case the cell has no element, so the user wants to delete this cell.
847 TNode prev_cell = gfuther.prev();
852 // now the cell no longer exists
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();
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();
869 parent_table.append(cursor);
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);
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);
893 else // the grand futher is math
895 // nothing to do...i think
896 assert(frames.empty());
901 // the parent is a group with id and has no elements other than cursor
902 // so we replace it with the cursor.
905 // i have to re-start the process, because it' a graphical delete
910 else if (parent.isC())
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();
919 assert(frame.entry.pattern.size() >= 1);
921 cout << "do_gdelete: frames.top().pos = " << frames.top().pos << endl;
923 TNode prev = cursor.prev();
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);
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())
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);
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;
956 // the prev is an non delimited argument, so we try to
962 else if (parent.is("sp") || parent.is("sb"))
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
968 assert(parent.size() == 2);
969 assert(parent.parent() && !parent.parent().isC());
971 TNode prev = cursor.prev();
973 if (prev.isG() /*&& !prev.hasId()*/ && (prev.size() == 0))
976 parent.replace(cursor);
978 // now, cursor should be the only parent's child
979 assert(cursor.parent().size() == 1);
981 if (cursor.parent().isG() && cursor.parent().hasId()) rgreplace_futher();
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);
994 // not handled: no control for tables, ...
999 // the cursor has no parent!!!
1001 // emit an error? and if we want to emit an error, in which way?
1007 TPushParser::process(const TToken& token)
1009 switch (token.category)
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;
1031 TPushParser::push(const TToken& token)
1033 cerr << "TPushParser::push " << token.value << " (cat: " << token.category << ")" << endl;
1035 if (token.category == TToken::GDELETE)
1037 cout << "push: i have to process a token with category member = GDELETE" << endl;
1040 else if ((doc.root().first() && doc.root().first().is("math")) || token.category == TToken::SHIFT)
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
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())
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())
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)
1066 // The token matches with a delimiter of the argument,
1067 // so we increment the frame.pos
1070 if (frame.entry.lastDelimiter(frame.pos))
1072 // this delimiter is the last one for the argumet,
1073 // so the argument is completed
1077 if (frame.pos == frame.entry.pattern.size())
1079 // This token has completed the entry
1081 advance(parent.parent());
1083 else if (frame.entry.paramDelimited(frame.pos))
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);
1092 parent.parent().append(cursor);
1097 // Delimiter mismatch.
1098 if (frame.entry.pattern[frame.pos].category != TToken::PARAMETER)
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
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;
1113 // in this case, the sequence of delimiters is composed of one
1114 // delimiter. It means that we have to process the token
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
1125 assert(frame.entry.rightOpen);
1129 else if (parent.isC())
1131 // We are parsing a non-delimited argument entry
1133 Frame& frame = frames.top();
1134 assert(frame.pos < frame.entry.pattern.size());
1136 cout << "push: there is a frame with pos " << frame.pos << endl;
1137 if (frame.entry.pattern[frame.pos].category == TToken::PARAMETER)
1139 // As by the TeX parsing rules of undelimited parameters,
1140 // empty spaces are ignored
1141 if (token.category != TToken::SPACE)
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
1152 else if (frame.entry.pattern[frame.pos] == token)
1154 // The token has been accepted
1156 if (frame.pos < frame.entry.pattern.size() &&
1157 frame.entry.paramDelimited(frame.pos))
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();
1170 // There is a mismatch. Emit an error and ignore the token?
1171 cerr << "ERROR: token ignored: " << token.value << " (cat: " << token.category << ")" << endl;
1179 cout << "ignored token" << endl;
1182 //if (listener) listener->callback(doc); //it shoul be repristened if you remove the comment in the else above
1184 } // this end corresponds to the if ((doc.root().first() && doc.root().first().is("math")) || token.category == TToken::SHIFT)
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;
1192 if (factory) factory->documentModified(doc);
1194 if (frames.empty()) cout << "stack vuoto" << endl;
1195 else cout << "stack non vuoto" << endl;
1199 TPushParser::advance(const TNode& node)
1202 TNode parent = node.parent();
1204 ; // nothing to do, the cursor is not in the document any more
1205 else if (parent.isG())
1207 TNode next = node.next();
1208 if (next) next.insert(cursor);
1209 else parent.append(cursor);
1211 else if (parent.isC())
1217 Frame& frame = frames.top();
1218 if (frame.pos == frame.entry.pattern.size())
1224 parent.append(cursor);
1227 else if (parent.is("math"))
1234 TPushParser::setCursorHint(const std::string& c)
1237 if (factory) factory->documentModified(doc);