]> git.lyx.org Git - lyx.git/blobdiff - src/mathed/MathParser.cpp
Fix bug #12772
[lyx.git] / src / mathed / MathParser.cpp
index 0f10aa5ed75c7104c38d94e18e72b7c8dee8d8bd..1958900e3d2f0155e64609f5fa1ab3273b59bd3b 100644 (file)
@@ -51,7 +51,7 @@ following hack as starting point to write some macros:
 #include "InsetMathEnv.h"
 #include "InsetMathFrac.h"
 #include "InsetMathKern.h"
-#include "MathMacro.h"
+#include "InsetMathMacro.h"
 #include "InsetMathPar.h"
 #include "InsetMathRef.h"
 #include "InsetMathRoot.h"
@@ -63,10 +63,10 @@ following hack as starting point to write some macros:
 #include "InsetMathStackrel.h"
 #include "InsetMathString.h"
 #include "InsetMathTabular.h"
-#include "MathMacroTemplate.h"
+#include "InsetMathMacroTemplate.h"
 #include "MathExtern.h"
 #include "MathFactory.h"
-#include "MathMacroArgument.h"
+#include "InsetMathMacroArgument.h"
 #include "MathSupport.h"
 
 #include "Buffer.h"
@@ -74,8 +74,8 @@ following hack as starting point to write some macros:
 #include "Encoding.h"
 #include "Lexer.h"
 
-#include "support/debug.h"
 #include "support/convert.h"
+#include "support/debug.h"
 #include "support/docstream.h"
 
 #include <sstream>
@@ -157,11 +157,11 @@ docstring escapeSpecialChars(docstring const & str, bool textmode)
 
 /*!
  * Add the row \p cellrow to \p grid.
- * \returns wether the row could be added. Adding a row can fail for
+ * \returns whether the row could be added. Adding a row can fail for
  * environments like "equation" that have a fixed number of rows.
  */
-bool addRow(InsetMathGrid & grid, InsetMathGrid::row_type & cellrow,
-           docstring const & vskip, bool allow_newpage_ = true)
+bool addRow(InsetMathGrid & grid, row_type & cellrow,
+           docstring const & vskip, bool allow_newpage = true)
 {
        ++cellrow;
        if (cellrow == grid.nrows()) {
@@ -178,24 +178,24 @@ bool addRow(InsetMathGrid & grid, InsetMathGrid::row_type & cellrow,
                        lyxerr << "ignoring extra row";
                        if (!vskip.empty())
                                lyxerr << " with extra space " << to_utf8(vskip);
-                       if (!allow_newpage_)
+                       if (!allow_newpage)
                                lyxerr << " with no page break allowed";
                        lyxerr << '.' << endl;
                        return false;
                }
        }
        grid.vcrskip(Length(to_utf8(vskip)), cellrow - 1);
-       grid.rowinfo(cellrow - 1).allow_newpage_ = allow_newpage_;
+       grid.rowinfo(cellrow - 1).allow_newpage = allow_newpage;
        return true;
 }
 
 
 /*!
  * Add the column \p cellcol to \p grid.
- * \returns wether the column could be added. Adding a column can fail for
+ * \returns whether the column could be added. Adding a column can fail for
  * environments like "eqnarray" that have a fixed number of columns.
  */
-bool addCol(InsetMathGrid & grid, InsetMathGrid::col_type & cellcol)
+bool addCol(InsetMathGrid & grid, col_type & cellcol)
 {
        ++cellcol;
        if (cellcol == grid.ncols()) {
@@ -229,14 +229,18 @@ bool addCol(InsetMathGrid & grid, InsetMathGrid::col_type & cellcol)
  * \endverbatim
  * will result in a grid with 3 rows (+ the dummy row that is always present),
  * because the last '\\' opens a new row.
+ * Do never delete a row that contains a multicolumn, even if all cells empty,
+ * since the multicolumn information would get lost otherwise.
  * Note that this is only needed for inner-hull grid types, such as array
  * or aligned, but not for outer-hull grid types, such as eqnarray or align.
  */
 void delEmptyLastRow(InsetMathGrid & grid)
 {
-       InsetMathGrid::row_type const row = grid.nrows() - 1;
-       for (InsetMathGrid::col_type col = 0; col < grid.ncols(); ++col) {
-               if (!grid.cell(grid.index(row, col)).empty())
+       row_type const row = grid.nrows() - 1;
+       for (col_type col = 0; col < grid.ncols(); ++col) {
+               idx_type const idx = grid.index(row, col);
+               if (!grid.cell(idx).empty() ||
+                   grid.cellinfo(idx).multi != InsetMathGrid::CELL_NORMAL)
                        return;
        }
        // Copy the row information of the empty row (which would contain the
@@ -355,7 +359,7 @@ ostream & operator<<(ostream & os, Token const & t)
 {
        if (!t.cs().empty()) {
                docstring const & cs = t.cs();
-               // FIXME: For some strange reason, the stream operator instanciate
+               // FIXME: For some strange reason, the stream operator instantiate
                // a new Token before outputting the contents of t.cs().
                // Because of this the line
                //     os << '\\' << cs;
@@ -366,9 +370,9 @@ ostream & operator<<(ostream & os, Token const & t)
                os << '\\' << to_utf8(cs);
        }
        else if (t.cat() == catLetter)
-               os << t.character();
+               os << static_cast<uint32_t>(t.character());
        else
-               os << '[' << t.character() << ',' << t.cat() << ']';
+               os << '[' << static_cast<uint32_t>(t.character()) << ',' << t.cat() << ']';
        return os;
 }
 
@@ -396,8 +400,6 @@ public:
        bool parse1(InsetMathGrid & grid, unsigned flags, mode_type mode,
                bool numbered);
        ///
-       MathData parse(unsigned flags, mode_type mode);
-       ///
        int lineno() const { return lineno_; }
        ///
        void putback();
@@ -430,8 +432,6 @@ private:
        ///
        void push_back(Token const & t);
        ///
-       void pop_back();
-       ///
        Token const & prevToken() const;
        ///
        Token const & nextToken() const;
@@ -496,12 +496,6 @@ void Parser::push_back(Token const & t)
 }
 
 
-void Parser::pop_back()
-{
-       tokens_.pop_back();
-}
-
-
 Token const & Parser::prevToken() const
 {
        static const Token dummy;
@@ -627,7 +621,7 @@ void Parser::tokenize(istream & is)
 
 void Parser::tokenize(docstring const & buffer)
 {
-       idocstringstream is(mode_ & Parse::VERBATIM
+       idocstringstream is((mode_ & Parse::VERBATIM)
                        ? escapeSpecialChars(buffer, mode_ & Parse::TEXTMODE)
                        : buffer, ios::in | ios::binary);
 
@@ -749,7 +743,8 @@ docstring Parser::parse_verbatim_option()
        skipSpaces();
        docstring res;
        if (nextToken().character() == '[') {
-               Token t = getToken();
+               // eat [
+               getToken();
                for (Token t = getToken(); t.character() != ']' && good(); t = getToken()) {
                        if (t.cat() == catBegin) {
                                putback();
@@ -767,7 +762,8 @@ docstring Parser::parse_verbatim_item()
        skipSpaces();
        docstring res;
        if (nextToken().cat() == catBegin) {
-               Token t = getToken();
+               // eat catBegin
+               getToken();
                for (Token t = getToken(); t.cat() != catEnd && good(); t = getToken()) {
                        if (t.cat() == catBegin) {
                                putback();
@@ -781,14 +777,6 @@ docstring Parser::parse_verbatim_item()
 }
 
 
-MathData Parser::parse(unsigned flags, mode_type mode)
-{
-       MathData ar(buffer_);
-       parse(ar, flags, mode);
-       return ar;
-}
-
-
 bool Parser::parse(MathData & array, unsigned flags, mode_type mode)
 {
        InsetMathGrid grid(buffer_, 1, 1);
@@ -808,9 +796,8 @@ void Parser::parse2(MathAtom & at, const unsigned flags, const mode_type mode,
 bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
        const mode_type mode, const bool numbered)
 {
-       int limits = 0;
-       InsetMathGrid::row_type cellrow = 0;
-       InsetMathGrid::col_type cellcol = 0;
+       row_type cellrow = 0;
+       col_type cellcol = 0;
        MathData * cell = &grid.cell(grid.index(cellrow, cellcol));
        Buffer * buf = buffer_;
 
@@ -942,8 +929,13 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                }
 
                else if (t.cat() == catParameter) {
-                       Token const & n = getToken();
-                       cell->push_back(MathAtom(new MathMacroArgument(n.character()-'0')));
+                       Token const & n = nextToken();
+                       char_type c = n.character();
+                       if (c && '0' < c && c <= '9') {
+                               cell->push_back(MathAtom(new InsetMathMacroArgument(c - '0')));
+                               getToken();
+                       } else
+                               cell->push_back(MathAtom(new InsetMathHash()));
                }
 
                else if (t.cat() == catActive)
@@ -1012,10 +1004,6 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                p->nuc().erase(0);
 
                        parse(p->cell(p->idxOfScript(up)), FLAG_ITEM, mode);
-                       if (limits) {
-                               p->limits(limits);
-                               limits = 0;
-                       }
                }
 
                else if (t.character() == ']' && (flags & FLAG_BRACK_LAST)) {
@@ -1025,7 +1013,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
 
                else if (t.cat() == catOther) {
                        char_type c = t.character();
-                       if (isAsciiOrMathAlpha(c)
+                       if (!Encodings::isUnicodeTextOnly(c)
                            || mode_ & Parse::VERBATIM
                            || !(mode_ & Parse::USETEXT)
                            || mode == InsetMath::TEXT_MODE) {
@@ -1034,7 +1022,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                MathAtom at = createInsetMath("text", buf);
                                at.nucleus()->cell(0).push_back(MathAtom(new InsetMathChar(c)));
                                while (nextToken().cat() == catOther
-                                      && !isAsciiOrMathAlpha(nextToken().character())) {
+                                      && Encodings::isUnicodeTextOnly(nextToken().character())) {
                                        c = getToken().character();
                                        at.nucleus()->cell(0).push_back(MathAtom(new InsetMathChar(c)));
                                }
@@ -1045,10 +1033,10 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                else if (t.cat() == catComment) {
                        docstring s;
                        while (good()) {
-                               Token const & t = getToken();
-                               if (t.cat() == catNewline)
+                               Token const & tt = getToken();
+                               if (tt.cat() == catNewline)
                                        break;
-                               s += t.asInput();
+                               s += tt.asInput();
                        }
                        cell->push_back(MathAtom(new InsetMathComment(buf, s)));
                        skipSpaces();
@@ -1090,7 +1078,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                        if (nextToken().cat() == catBegin)
                                parse(display, FLAG_ITEM, InsetMath::MATH_MODE);
 
-                       cell->push_back(MathAtom(new MathMacroTemplate(buf,
+                       cell->push_back(MathAtom(new InsetMathMacroTemplate(buf,
                                name, nargs, 0, MacroTypeDef,
                                vector<MathData>(), def, display)));
 
@@ -1138,7 +1126,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                        if (nextToken().cat() == catBegin)
                                parse(display, FLAG_ITEM, InsetMath::MATH_MODE);
 
-                       cell->push_back(MathAtom(new MathMacroTemplate(buf,
+                       cell->push_back(MathAtom(new InsetMathMacroTemplate(buf,
                                name, nargs, optionals, MacroTypeNewcommand,
                                optionalValues, def, display)));
 
@@ -1259,7 +1247,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                        if (nextToken().cat() == catBegin)
                                parse(display, FLAG_ITEM, InsetMath::MATH_MODE);
 
-                       cell->push_back(MathAtom(new MathMacroTemplate(buf,
+                       cell->push_back(MathAtom(new InsetMathMacroTemplate(buf,
                                name, nargs, optionals, MacroTypeNewcommandx,
                                optionalValues, def, display)));
 
@@ -1375,42 +1363,47 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                        }
                }
 
-               else if (t.cs() == "multicolumn") {
-                       // extract column count and insert dummy cells
+               else if (t.cs() == "multicolumn" && grid.handlesMulticolumn()) {
+                       // if the columns are specified numerically,
+                       // extract column count and insert dummy cells,
+                       // otherwise parse it as an user macro
                        MathData count;
                        parse(count, FLAG_ITEM, mode);
-                       int cols = 1;
-                       if (!extractNumber(count, cols)) {
-                               success_ = false;
-                               error("can't extract number of multicolumn cells");
-                       }
-                       // resize the table if necessary
-                       size_t first = 0;
-                       for (int i = 0; i < cols; ++i) {
-                               if (addCol(grid, cellcol)) {
-                                       size_t const idx = grid.index(cellrow, cellcol);
-                                       if (i == 0)
-                                               first = idx;
-                                       grid.cellinfo(idx).multi_ =
-                                               InsetMathGrid::CELL_PART_OF_MULTICOLUMN;
+                       int cols = 0;
+                       // limit arbitrarily to 100 columns
+                       if (extractNumber(count, cols) && cols > 0 && cols < 100) {
+                               // resize the table if necessary
+                               size_t first = grid.index(cellrow, cellcol);
+                               for (int i = 1; i < cols; ++i) {
+                                       if (addCol(grid, cellcol)) {
+                                               size_t const idx = grid.index(cellrow, cellcol);
+                                               grid.cellinfo(idx).multi =
+                                                       InsetMathGrid::CELL_PART_OF_MULTICOLUMN;
+                                       }
                                }
-                       }
 
-                       // the first cell is the real thing, not a dummy
-                       cell = &grid.cell(first);
-                       grid.cellinfo(first).multi_ = InsetMathGrid::CELL_BEGIN_OF_MULTICOLUMN;
+                               // the first cell is the real thing, not a dummy
+                               cell = &grid.cell(first);
+                               grid.cellinfo(first).multi =
+                                       InsetMathGrid::CELL_BEGIN_OF_MULTICOLUMN;
 
-                       // read special alignment
-                       grid.cellinfo(first).align_ = parse_verbatim_item();
+                               // read special alignment
+                               MathData align;
+                               parse(align, FLAG_ITEM, mode);
+                               grid.cellinfo(first).align = asString(align);
 
-                       // parse the remaining contents into the "real" cell
-                       parse(*cell, FLAG_ITEM, mode);
+                               // parse the remaining contents into the "real" cell
+                               parse(*cell, FLAG_ITEM, mode);
+                       } else {
+                               MathAtom at = MathAtom(new InsetMathMacro(buf, t.cs()));
+                               cell->push_back(at);
+                               cell->push_back(MathAtom(new InsetMathBrace(count)));
+                       }
                }
 
                else if (t.cs() == "limits" || t.cs() == "nolimits") {
-                       CatCode const cat = nextToken().cat();
-                       if (cat == catSuper || cat == catSub)
-                               limits = t.cs() == "limits" ? 1 : -1;
+                       if (!cell->empty())
+                               cell->back()->limits(t.cs() == "limits" ? LIMITS : NO_LIMITS);
                        else {
                                MathAtom at = createInsetMath(t.cs(), buf);
                                cell->push_back(at);
@@ -1426,7 +1419,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                        grid.asHullInset()->numbered(cellrow, true);
 
                else if (t.cs() == "hline") {
-                       grid.rowinfo(cellrow).lines++;
+                       grid.rowinfo(cellrow).lines++;
                }
 
                else if (t.cs() == "sqrt") {
@@ -1434,12 +1427,10 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                        parse(ar, FLAG_OPTION, mode);
                        if (!ar.empty()) {
                                cell->push_back(MathAtom(new InsetMathRoot(buf)));
-                               cell->back().nucleus()->cell(0) = ar;
-                               parse(cell->back().nucleus()->cell(1), FLAG_ITEM, mode);
-                       } else {
+                               cell->back().nucleus()->cell(1) = ar;
+                       } else
                                cell->push_back(MathAtom(new InsetMathSqrt(buf)));
-                               parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode);
-                       }
+                       parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode);
                }
 
                else if (t.cs() == "cancelto") {
@@ -1505,7 +1496,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                if (ar[i].size() == 1)
                                        script[i] = ar[i][0].nucleus()->asScriptInset();
                        }
-                       bool const hasscript[2] = {script[0] ? true : false, script[1] ? true : false};
+                       bool const hasscript[2] = {script[0] != nullptr, script[1] != nullptr};
                        cell->push_back(MathAtom(new InsetMathSideset(buf, hasscript[0], hasscript[1])));
                        if (hasscript[0]) {
                                if (script[0]->hasDown())
@@ -1531,8 +1522,8 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                        cell->push_back(MathAtom(new InsetMathStackrel(buf, !ar.empty())));
                        if (!ar.empty())
                                cell->back().nucleus()->cell(2) = ar;
-                       parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode);
                        parse(cell->back().nucleus()->cell(1), FLAG_ITEM, mode);
+                       parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode);
                }
 
                else if (t.cs() == "xrightarrow" || t.cs() == "xleftarrow") {
@@ -1554,7 +1545,9 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                }
 
                else if (t.cs() == "ref" || t.cs() == "eqref" || t.cs() == "prettyref"
-                         || t.cs() == "pageref" || t.cs() == "vpageref" || t.cs() == "vref") {
+                         || t.cs() == "nameref" || t.cs() == "pageref"
+                         || t.cs() == "vpageref" || t.cs() == "vref" 
+                         || t.cs() == "formatted" || t.cs() == "labelonly") {
                        cell->push_back(MathAtom(new InsetMathRef(buf, t.cs())));
                        docstring const opt = parse_verbatim_option();
                        docstring const ref = parse_verbatim_item();
@@ -1607,7 +1600,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                docstring const halign = parse_verbatim_item();
                                cell->push_back(MathAtom(new InsetMathArray(buf, name,
                                        InsetMathGrid::guessColumns(halign), 1, (char)valign[0], halign)));
-                               parse2(cell->back(), FLAG_END, mode, false);
+                               parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, false);
                        }
 
                        else if (name == "tabular") {
@@ -1759,7 +1752,8 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
 
                        else {
                                success_ = false;
-                               if (!(mode_ & Parse::QUIET)) {
+                               if (!(mode_ & Parse::QUIET) &&
+                                   !(mode_ & Parse::TRACKMACRO)) {
                                        dump();
                                        lyxerr << "found unknown math environment '"
                                               << to_utf8(name) << "'" << endl;
@@ -1770,12 +1764,12 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                        }
                }
 
-               else if (t.cs() == "kern") {
+               else if (t.cs() == "kern" || t.cs() == "mkern") {
                        // FIXME: A hack...
                        docstring s;
                        int num_tokens = 0;
                        while (true) {
-                               Token const & t = getToken();
+                               Token const & tt = getToken();
                                ++num_tokens;
                                if (!good()) {
                                        s.clear();
@@ -1783,12 +1777,12 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                                putback();
                                        break;
                                }
-                               s += t.character();
+                               s += tt.character();
                                if (isValidLength(to_utf8(s)))
                                        break;
                        }
                        if (s.empty())
-                               cell->push_back(MathAtom(new InsetMathKern));
+                               cell->push_back(MathAtom(new InsetMathMacro(buf, t.cs())));
                        else
                                cell->push_back(MathAtom(new InsetMathKern(s)));
                }
@@ -1887,7 +1881,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                        bool const prot =  nextToken().character() == '*';
                        if (prot)
                                getToken();
-                       docstring const name = t.cs();
+                       docstring const name = t.cs();
                        docstring const arg = parse_verbatim_item();
                        Length length;
                        if (prot && arg == "\\fill")
@@ -1897,7 +1891,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                        else {
                                // Since the Length class cannot use length variables
                                // we must not create an InsetMathSpace.
-                               cell->push_back(MathAtom(new MathMacro(buf, name)));
+                               cell->push_back(MathAtom(new InsetMathMacro(buf, name)));
                                MathData ar;
                                mathed_parse_cell(ar, '{' + arg + '}', mode_);
                                cell->append(ar);
@@ -1916,7 +1910,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                        parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode);
                                } else {
                                        docstring const arg = parse_verbatim_item();
-                                       cell->push_back(MathAtom(new MathMacro(buf, t.cs())));
+                                       cell->push_back(MathAtom(new InsetMathMacro(buf, t.cs())));
                                        MathData ar;
                                        mathed_parse_cell(ar, '[' + opt + ']', mode_);
                                        cell->append(ar);
@@ -1938,23 +1932,6 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                        cell->push_back(createInsetMath(t.cs(), buf));
                        parse2(cell->back(), FLAG_ITEM, mode, false);
                }
-
-               // Disabled
-               else if (1 && t.cs() == "ar") {
-                       auto_ptr<InsetMathXYArrow> p(new InsetMathXYArrow);
-                       // try to read target
-                       parse(p->cell(0), FLAG_OTPTION, mode);
-                       // try to read label
-                       if (nextToken().cat() == catSuper || nextToken().cat() == catSub) {
-                               p->up_ = nextToken().cat() == catSuper;
-                               getToken();
-                               parse(p->cell(1), FLAG_ITEM, mode);
-                               //lyxerr << "read label: " << p->cell(1) << endl;
-                       }
-
-                       cell->push_back(MathAtom(p.release()));
-                       //lyxerr << "read cell: " << cell << endl;
-               }
 #endif
 
                else if (t.cs() == "lyxmathsym") {
@@ -1984,8 +1961,8 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                cmd = Encodings::fromLaTeXCommand(cmd,
                                        Encodings::MATH_CMD | Encodings::TEXT_CMD,
                                        termination, rem);
-                               for (size_t i = 0; i < cmd.size(); ++i)
-                                       cell->push_back(MathAtom(new InsetMathChar(cmd[i])));
+                               for (char_type c : cmd)
+                                       cell->push_back(MathAtom(new InsetMathChar(c)));
                                if (!rem.empty()) {
                                        char_type c = rem[0];
                                        cell->push_back(MathAtom(new InsetMathChar(c)));
@@ -2003,7 +1980,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                                BufferParams::package_off;
 
                        bool const is_user_macro = no_mhchem ||
-                               (buf && (mode_ & Parse::TRACKMACRO
+                               (buf && ((mode_ & Parse::TRACKMACRO)
                                         ? buf->usermacros.count(t.cs()) != 0
                                         : buf->getMacro(t.cs(), false) != 0));
 
@@ -2017,7 +1994,10 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                                        new InsetMathBig(t.cs(), delim)));
                                        else {
                                                cell->push_back(createInsetMath(t.cs(), buf));
-                                               putback();
+                                               // For some reason delim.empty()
+                                               // is always false here
+                                               if (delim.at(0))
+                                                       putback();
                                        }
                                }
 
@@ -2047,9 +2027,15 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                        putback();
                                }
 
+                               else if (l->inset == "underset" || l->inset == "overset") {
+                                       cell->push_back(createInsetMath(t.cs(), buf));
+                                       parse(cell->back().nucleus()->cell(1), FLAG_ITEM, mode);
+                                       parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode);
+                               }
+
                                else {
                                        MathAtom at = createInsetMath(t.cs(), buf);
-                                       for (InsetMath::idx_type i = 0; i < at->nargs(); ++i)
+                                       for (idx_type i = 0; i < at->nargs(); ++i)
                                                parse(at.nucleus()->cell(i),
                                                        FLAG_ITEM, asMode(mode, l->extra));
                                        cell->push_back(at);
@@ -2090,19 +2076,17 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                                        Encodings::MATH_CMD | Encodings::TEXT_CMD,
                                                        is_combining, termination);
                                        }
-                                       if (c) {
+                                       if (c && buf && buf->params().encoding().encodable(c)) {
                                                if (termination) {
                                                        if (nextToken().cat() == catBegin) {
                                                                getToken();
                                                                if (nextToken().cat() == catEnd) {
                                                                        getToken();
-                                                                       num_tokens += 2;
                                                                } else
                                                                        putback();
                                                        } else {
                                                                while (nextToken().cat() == catSpace) {
                                                                        getToken();
-                                                                       ++num_tokens;
                                                                }
                                                        }
                                                }
@@ -2115,7 +2099,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                }
                                if (!is_unicode_symbol) {
                                        MathAtom at = is_user_macro ?
-                                               MathAtom(new MathMacro(buf, t.cs()))
+                                               MathAtom(new InsetMathMacro(buf, t.cs()))
                                                : createInsetMath(t.cs(), buf);
                                        InsetMath::mode_type m = mode;
                                        //if (m == InsetMath::UNDECIDED_MODE)
@@ -2123,7 +2107,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                        if (at->currentMode() != InsetMath::UNDECIDED_MODE)
                                                m = at->currentMode();
                                        //lyxerr << "default creation: m2: " << m << endl;
-                                       InsetMath::idx_type start = 0;
+                                       idx_type start = 0;
                                        // this fails on \bigg[...\bigg]
                                        //MathData opt;
                                        //parse(opt, FLAG_OPTION, InsetMath::VERBATIM_MODE);
@@ -2131,7 +2115,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                        //      start = 1;
                                        //      at.nucleus()->cell(0) = opt;
                                        //}
-                                       for (InsetMath::idx_type i = start; i < at->nargs(); ++i) {
+                                       for (idx_type i = start; i < at->nargs(); ++i) {
                                                parse(at.nucleus()->cell(i), FLAG_ITEM, m);
                                                if (mode == InsetMath::MATH_MODE)
                                                        skipSpaces();
@@ -2143,7 +2127,6 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
 
 
                if (flags & FLAG_LEAVE) {
-                       flags &= ~FLAG_LEAVE;
                        break;
                }
        }
@@ -2166,14 +2149,14 @@ char const * latexkeys::MathMLtype() const
 
 bool mathed_parse_cell(MathData & ar, docstring const & str, Parse::flags f)
 {
-       return Parser(str, f, ar.buffer()).parse(ar, 0, f & Parse::TEXTMODE ?
+       return Parser(str, f, ar.buffer()).parse(ar, 0, (f & Parse::TEXTMODE) ?
                                InsetMath::TEXT_MODE : InsetMath::MATH_MODE);
 }
 
 
 bool mathed_parse_cell(MathData & ar, istream & is, Parse::flags f)
 {
-       return Parser(is, f, ar.buffer()).parse(ar, 0, f & Parse::TEXTMODE ?
+       return Parser(is, f, ar.buffer()).parse(ar, 0, (f & Parse::TEXTMODE) ?
                                InsetMath::TEXT_MODE : InsetMath::MATH_MODE);
 }
 
@@ -2195,7 +2178,7 @@ bool mathed_parse_normal(Buffer * buf, MathAtom & t, Lexer & lex,
 bool mathed_parse_normal(InsetMathGrid & grid, docstring const & str,
                         Parse::flags f)
 {
-       return Parser(str, f, &grid.buffer()).parse1(grid, 0, f & Parse::TEXTMODE ?
+       return Parser(str, f, &grid.buffer()).parse1(grid, 0, (f & Parse::TEXTMODE) ?
                        InsetMath::TEXT_MODE : InsetMath::MATH_MODE, false);
 }