+bool
+TPushParser::correctBrace()
+{
+ // this method MUST be invoked when the cursor is child of a
+ // phantom group, which in turn is the last rightOpen MACRO's child.
+ // The only way to exit from a rightOpen MACRO is opening a group before
+ // inserting the MACRO and, once the MACRO is completely inserted, closing
+ // the group.
+ // This method return true if the condition above is true. False, otherwise.
+ assert(cursor.parent() && cursor.parent().isG() && !cursor.parent().hasId());
+ TNode parent = cursor.parent();
+ assert(parent.parent() && parent.parent().isC());
+ assert(!frames.empty());
+ Frame& frame = frames.top();
+ assert(frame.entry.rightOpen);
+ assert(parent.parent().last() == parent);
+
+ TNode c = parent.parent();
+ bool stop = false;
+ bool ok = false;
+ TNode node = c.parent();
+ do
+ {
+ if (node.isG() && node.hasId())
+ {
+ // in this case, the rightOpen MACRO is a child of a group with id.
+ // So, the '}' is correct
+ ok = true;
+ stop = true;
+ }
+ else if (node.isG())
+ {
+ // the MACRO is a phantom group's child. We have to control why we
+ // have this phantom group
+ TNode nodeParent = node.parent();
+ if (nodeParent && nodeParent.isC())
+ {
+ // we have to control the nature of this MACRO
+ const TDictionary::Entry& entry = dictionary.find(nodeParent.nameC());
+ if (entry.rightOpen && node == nodeParent.last())
+ {
+ // in this case we have to re-iterate the process
+ node = nodeParent.parent();
+ }
+ else stop = true;
+ }
+ else stop = true;
+ }
+ else
+ {
+ // at the moment we assume that a MACRO cannot be child of an element other than a group
+ stop = true;
+ }
+ }
+ while (!stop);
+
+ return ok;
+}
+
+void
+TPushParser::do_end()
+{
+ TNode parent = cursor.parent();
+ if (parent && parent.isG() && parent.hasId())
+ {
+ // normal closing brace for an explicitly open group
+ cursor.remove();
+ advance(parent);
+ }
+ else if (parent && parent.isG() && parent.parent() && parent.parent().is("cell"))
+ {
+ assert(!frames.empty());
+ // closing brace for a structure in which & or \cr have been used
+ TNode row = parent.parent().parent();
+ assert(row && row.is("row"));
+ assert(row.parent());
+ advance(row);
+ }
+ else if (parent && parent.isG() && !parent.hasId() && parent.parent() && !parent.parent().is("math"))
+ {
+ // In this case, we have to control the cursor's grand parent.
+ TNode gparent = parent.parent();
+
+ if (gparent.isC() && gparent.last() == parent)
+ {
+ // a frame MUST be in the stack
+ assert(!frames.empty());
+
+ // we have to control the nature of this macro
+ if (frames.top().entry.rightOpen)
+ {
+ // in this case, the '}' character is the proper way to exit from the phantom group, and
+ // in particular, this character means that the user wants to exit from the MACRO.
+ // A rightOpen MACRO MUST be descendant of a group with Id. This '}' is the closing brace of this
+ // group. So, we have to control if this group exists. This groyp could exist, but this MACRO could
+ // be another MACRO's child, so we have to control this last MACRO recursively. This recurive control
+ // is done by the correctBrace method.
+ if (!correctBrace())
+ {
+ // the '}' is not correct
+ logger.warning("nothing to close");
+ }
+ else
+ {
+ cursor.remove();
+ advance(parent);
+ }
+
+ }
+ else
+ {
+ logger.error("closing brace ignored");
+ }
+ }
+ else
+ {
+ // at the moment, a phantom group with cursor can be a MACRO's child or a cell's child, and these cases
+ // are handled in other blocks of code.
+ logger.error("do_end: strange TML tree");
+ }
+ }
+ else
+ {
+ // In this case, there is a redundant '}', so we can ignore it and
+ // emit an error
+ logger.warning("There is so no corresponding'{'");
+ //assert(0);
+ }
+}
+
+
+/*