X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Fmathed%2Fmath_parser.C;h=ea289cc82c7a59b4666d47952409c6dd73219218;hb=cd3d0bc0b26f4d92fdfbfaac4adefebcf51f11ff;hp=1f417f7529ef1700360a041038157dfa3a19251a;hpb=12130ed9b1e8dec72920dfc854dce271a82979b3;p=lyx.git diff --git a/src/mathed/math_parser.C b/src/mathed/math_parser.C index 1f417f7529..ea289cc82c 100644 --- a/src/mathed/math_parser.C +++ b/src/mathed/math_parser.C @@ -4,9 +4,9 @@ /* -If someone desperately needs partial "structures" (such as a few cells of -an array inset or similar) (s)he could uses the following hack as starting -point to write some macros: +If someone desperately needs partial "structures" (such as a few +cells of an array inset or similar) (s)he could uses the +following hack as starting point to write some macros: \newif\ifcomment \commentfalse @@ -22,9 +22,9 @@ point to write some macros: ... \[\begin{array}{ccc} - 1 & 2\b & 3^2\\ - 4 & 5\e & 6\\ - 7 & 8 & 9 +1 +& + \end{array}\] */ @@ -32,9 +32,6 @@ point to write some macros: #include -#ifdef __GNUG__ -#pragma implementation -#endif #include "math_parser.h" #include "math_inset.h" @@ -42,55 +39,65 @@ point to write some macros: #include "math_braceinset.h" #include "math_boxinset.h" #include "math_charinset.h" +#include "math_commentinset.h" #include "math_deliminset.h" +#include "math_envinset.h" +#include "math_extern.h" #include "math_factory.h" #include "math_kerninset.h" #include "math_macro.h" -#include "math_macrotable.h" #include "math_macrotemplate.h" #include "math_hullinset.h" +#include "math_parboxinset.h" +#include "math_parinset.h" #include "math_rootinset.h" -#include "math_sizeinset.h" -#include "math_sqrtinset.h" #include "math_scriptinset.h" -#include "math_specialcharinset.h" +#include "math_sizeinset.h" #include "math_sqrtinset.h" +#include "math_stringinset.h" #include "math_support.h" +#include "math_tabularinset.h" #include "math_xyarrowinset.h" +//#include "insets/insetref.h" +#include "ref_inset.h" + #include "lyxlex.h" #include "debug.h" #include "support/LAssert.h" #include "support/lstrings.h" #include -#include #include using std::istream; using std::ostream; using std::ios; using std::endl; -using std::stack; using std::fill; using std::vector; using std::atoi; + //#define FILEDEBUG namespace { -bool stared(string const & s) +MathInset::mode_type asMode(MathInset::mode_type oldmode, string const & str) { - string::size_type const n = s.size(); - return n && s[n - 1] == '*'; + if (str == "mathmode") + return MathInset::MATH_MODE; + if (str == "textmode" || str == "forcetext") + return MathInset::TEXT_MODE; + return oldmode; } -void add(MathArray & ar, char c) +bool stared(string const & s) { - ar.push_back(MathAtom(new MathCharInset(c))); + string::size_type const n = s.size(); + return n && s[n - 1] == '*'; } @@ -124,18 +131,18 @@ inline CatCode catcode(unsigned char c) enum { - FLAG_BRACE_LAST = 1 << 1, // last closing brace ends the parsing process + FLAG_BRACE_LAST = 1 << 1, // last closing brace ends the parsing FLAG_RIGHT = 1 << 2, // next \\right ends the parsing process FLAG_END = 1 << 3, // next \\end ends the parsing process - FLAG_BRACK_END = 1 << 4, // next closing bracket ends the parsing process - FLAG_TEXTMODE = 1 << 5, // we are in a box + FLAG_BRACK_LAST = 1 << 4, // next closing bracket ends the parsing + FLAG_TEXTMODE = 1 << 5, // we are in a box FLAG_ITEM = 1 << 6, // read a (possibly braced token) - FLAG_BLOCK = 1 << 7, // next block ends the parsing process - FLAG_BLOCK2 = 1 << 8, // next block2 ends the parsing process - FLAG_LEAVE = 1 << 9, // leave the loop at the end - FLAG_SIMPLE = 1 << 10, // next $ leaves the loop - FLAG_EQUATION = 1 << 11, // next \] leaves the loop - FLAG_SIMPLE2 = 1 << 12 // next \) leaves the loop + FLAG_LEAVE = 1 << 7, // leave the loop at the end + FLAG_SIMPLE = 1 << 8, // next $ leaves the loop + FLAG_EQUATION = 1 << 9, // next \] leaves the loop + FLAG_SIMPLE2 = 1 << 10, // next \) leaves the loop + FLAG_OPTION = 1 << 11, // read [...] style option + FLAG_BRACED = 1 << 12 // read {...} style argument }; @@ -157,7 +164,7 @@ void catInit() theCatcode[''] = catIgnore; theCatcode[' '] = catSpace; theCatcode['\t'] = catSpace; - theCatcode['\r'] = catSpace; + theCatcode['\r'] = catNewline; theCatcode['~'] = catActive; theCatcode['%'] = catComment; } @@ -184,9 +191,7 @@ public: /// char character() const { return char_; } /// - string asString() const; - /// - bool isCR() const; + string asString() const { return cs_.size() ? cs_ : string(1, char_); } private: /// @@ -197,22 +202,12 @@ private: CatCode cat_; }; -bool Token::isCR() const -{ - return cs_ == "\\" || cs_ == "cr" || cs_ == "crcr"; -} - -string Token::asString() const -{ - return cs_.size() ? cs_ : string(1, char_); -} - ostream & operator<<(ostream & os, Token const & t) { if (t.cs().size()) - os << "\\" << t.cs(); + os << '\\' << t.cs(); else - os << "[" << t.character() << "," << t.cat() << "]"; + os << '[' << t.character() << ',' << t.cat() << ']'; return os; } @@ -220,17 +215,23 @@ ostream & operator<<(ostream & os, Token const & t) class Parser { public: + /// + typedef MathInset::mode_type mode_type; + /// Parser(LyXLex & lex); /// Parser(istream & is); /// - bool parse_macro(string & name); + bool parse(MathAtom & at); /// - bool parse_normal(MathAtom &); + void parse(MathArray & array, unsigned flags, mode_type mode); /// - void parse_into(MathArray & array, unsigned flags); + void parse1(MathGridInset & grid, unsigned flags, mode_type mode, + bool numbered); + /// + MathArray parse(unsigned flags, mode_type mode); /// int lineno() const { return lineno_; } /// @@ -238,9 +239,7 @@ public: private: /// - void parse_into1(MathGridInset & grid, unsigned flags, bool numbered); - /// - void parse_into2(MathAtom & at, unsigned flags, bool numbered); + void parse2(MathAtom & at, unsigned flags, mode_type mode, bool numbered); /// get arg delimited by 'left' and 'right' string getArg(char left, char right); /// @@ -249,8 +248,6 @@ private: void error(string const & msg); /// dump contents to screen void dump() const; - -private: /// void tokenize(istream & is); /// @@ -273,6 +270,10 @@ private: void lex(string const & s); /// bool good() const; + /// + string parse_verbatim_item(); + /// + string parse_verbatim_option(); /// int lineno_; @@ -334,7 +335,7 @@ Token const & Parser::getToken() void Parser::skipSpaces() { - while (nextToken().cat() == catSpace) + while (nextToken().cat() == catSpace || nextToken().cat() == catNewline) getToken(); } @@ -353,10 +354,8 @@ bool Parser::good() const char Parser::getChar() { - if (!good()) { - lyxerr << "The input stream is not well..." << endl; - dump(); - } + if (!good()) + error("The input stream is not well..."); return tokens_[pos_++].character(); } @@ -378,6 +377,17 @@ string Parser::getArg(char left, char right) } +void Parser::skipSpaceTokens(istream & is, char c) +{ + // skip trailing spaces + while (catcode(c) == catSpace || catcode(c) == catNewline) + if (!is.get(c)) + break; + //lyxerr << "putting back: " << c << "\n"; + is.putback(c); +} + + void Parser::tokenize(istream & is) { // eat everything up to the next \end_inset or end of stream @@ -391,23 +401,15 @@ void Parser::tokenize(istream & is) break; } } + // Remove the space after \end_inset + if (is.get(c) && c != ' ') + is.unget(); // tokenize buffer tokenize(s); } -void Parser::skipSpaceTokens(istream & is, char c) -{ - // skip trailing spaces - while (catcode(c) == catSpace || catcode(c) == catNewline) - if (!is.get(c)) - break; - //lyxerr << "putting back: " << c << "\n"; - is.putback(c); -} - - void Parser::tokenize(string const & buffer) { static bool init_done = false; @@ -430,18 +432,20 @@ void Parser::tokenize(string const & buffer) if (catcode(c) == catNewline) ; //push_back(Token("par")); else { - push_back(Token(' ', catSpace)); + push_back(Token('\n', catNewline)); is.putback(c); } break; } +/* case catComment: { while (is.get(c) && catcode(c) != catNewline) ; ++lineno_; break; } +*/ case catEscape: { is.get(c); @@ -492,7 +496,7 @@ void Parser::dump() const lyxerr << " <#> "; lyxerr << tokens_[i]; } - lyxerr << "\n"; + lyxerr << " pos: " << pos_ << "\n"; } @@ -504,223 +508,89 @@ void Parser::error(string const & msg) } -bool Parser::parse_macro(string & name) +bool Parser::parse(MathAtom & at) { - int nargs = 0; - name = "{error}"; skipSpaces(); - - if (nextToken().cs() == "def") { - - getToken(); - name = getToken().cs(); - - string pars; - while (good() && nextToken().cat() != catBegin) - pars += getToken().cs(); - - if (!good()) { - lyxerr << "bad stream in parse_macro\n"; - dump(); - return false; - } - - //lyxerr << "read \\def parameter list '" << pars << "'\n"; - if (!pars.empty()) { - lyxerr << "can't handle non-empty parameter lists\n"; - dump(); - return false; - } - - } else if (nextToken().cs() == "newcommand") { - - getToken(); - - if (getToken().cat() != catBegin) { - lyxerr << "'{' in \\newcommand expected (1) \n"; - dump(); - return false; - } - - name = getToken().cs(); - - if (getToken().cat() != catEnd) { - lyxerr << "'}' expected\n"; - return false; - } - - string arg = getArg('[', ']'); - if (!arg.empty()) - nargs = atoi(arg.c_str()); - - } else { - lyxerr << "\\newcommand or \\def expected\n"; - return false; - } - - - if (getToken().cat() != catBegin) { - lyxerr << "'{' in macro definition expected (2)\n"; - return false; - } - - MathArray ar1; - parse_into(ar1, FLAG_BRACE_LAST); - - // we cannot handle recursive stuff at all - MathArray test; - test.push_back(createMathInset(name)); - if (ar1.contains(test)) { - lyxerr << "we cannot handle recursive macros at all.\n"; - return false; + MathArray ar; + parse(ar, false, MathInset::UNDECIDED_MODE); + if (ar.size() != 1 || ar.front()->getType() == "none") { + lyxerr << "unusual contents found: " << ar << endl; + at = MathAtom(new MathParInset(ar)); + //if (at->nargs() > 0) + // at.nucleus()->cell(0) = ar; + //else + // lyxerr << "unusual contents found: " << ar << endl; + return true; } - - // is a version for display attached? - MathArray ar2; - parse_into(ar2, FLAG_ITEM); - - MathMacroTable::create(name, nargs, ar1, ar2); + at = ar[0]; return true; } - -bool Parser::parse_normal(MathAtom & matrix) + +string Parser::parse_verbatim_option() { skipSpaces(); - Token const & t = getToken(); - - if (t.cs() == "(") { - matrix = MathAtom(new MathHullInset(LM_OT_SIMPLE)); - parse_into2(matrix, FLAG_SIMPLE2, true); - return true; - } - - if (t.cat() == catMath) { - Token const & n = getToken(); - if (n.cat() == catMath) { - // TeX's $$...$$ syntax for displayed math - matrix = MathAtom(new MathHullInset(LM_OT_EQUATION)); - parse_into2(matrix, FLAG_SIMPLE, false); - getToken(); // skip the second '$' token - } else { - // simple $...$ stuff - putback(); - matrix = MathAtom(new MathHullInset(LM_OT_SIMPLE)); - parse_into2(matrix, FLAG_SIMPLE, false); + string res; + if (nextToken().character() == '[') { + Token t = getToken(); + for (Token t = getToken(); t.character() != ']' && good(); t = getToken()) { + if (t.cat() == catBegin) { + putback(); + res += '{' + parse_verbatim_item() + '}'; + } else + res += t.asString(); } - return true; - } - - if (!t.cs().size()) { - lyxerr << "start of math expected, got '" << t << "'\n"; - return false; - } - - string const & cs = t.cs(); - - if (cs == "[") { - matrix = MathAtom(new MathHullInset(LM_OT_EQUATION)); - parse_into2(matrix, FLAG_EQUATION, true); - return true; - } - - if (cs != "begin") { - lyxerr[Debug::MATHED] - << "'begin' of un-simple math expected, got '" << cs << "'\n"; - return false; - } - - string const name = getArg('{', '}'); - - if (name == "math") { - matrix = MathAtom(new MathHullInset(LM_OT_SIMPLE)); - parse_into2(matrix, FLAG_SIMPLE, true); - return true; - } - - if (name == "equation" || name == "equation*" || name == "displaymath") { - matrix = MathAtom(new MathHullInset(LM_OT_EQUATION)); - parse_into2(matrix, FLAG_END, (name == "equation")); - return true; - } - - if (name == "eqnarray" || name == "eqnarray*") { - matrix = MathAtom(new MathHullInset(LM_OT_EQNARRAY)); - parse_into2(matrix, FLAG_END, !stared(name)); - return true; - } - - if (name == "align" || name == "align*") { - matrix = MathAtom(new MathHullInset(LM_OT_ALIGN)); - parse_into2(matrix, FLAG_END, !stared(name)); - return true; - } - - if (name == "alignat" || name == "alignat*") { - // ignore this for a while - getArg('{', '}'); - matrix = MathAtom(new MathHullInset(LM_OT_ALIGNAT)); - parse_into2(matrix, FLAG_END, !stared(name)); - return true; - } - - if (name == "xalignat" || name == "xalignat*") { - // ignore this for a while - getArg('{', '}'); - matrix = MathAtom(new MathHullInset(LM_OT_XALIGNAT)); - parse_into2(matrix, FLAG_END, !stared(name)); - return true; } + return res; +} - if (name == "xxalignat") { - // ignore this for a while - getArg('{', '}'); - matrix = MathAtom(new MathHullInset(LM_OT_XXALIGNAT)); - parse_into2(matrix, FLAG_END, !stared(name)); - return true; - } - if (name == "multline" || name == "multline*") { - matrix = MathAtom(new MathHullInset(LM_OT_MULTLINE)); - parse_into2(matrix, FLAG_END, !stared(name)); - return true; +string Parser::parse_verbatim_item() +{ + skipSpaces(); + string res; + if (nextToken().cat() == catBegin) { + Token t = getToken(); + for (Token t = getToken(); t.cat() != catEnd && good(); t = getToken()) { + if (t.cat() == catBegin) { + putback(); + res += '{' + parse_verbatim_item() + '}'; + } + else + res += t.asString(); + } } + return res; +} - if (name == "gather" || name == "gather*") { - matrix = MathAtom(new MathHullInset(LM_OT_GATHER)); - parse_into2(matrix, FLAG_END, !stared(name)); - return true; - } - lyxerr[Debug::MATHED] << "1: unknown math environment: " << name << "\n"; - lyxerr << "1: unknown math environment: " << name << "\n"; - return false; +MathArray Parser::parse(unsigned flags, mode_type mode) +{ + MathArray ar; + parse(ar, flags, mode); + return ar; } -void Parser::parse_into(MathArray & array, unsigned flags) +void Parser::parse(MathArray & array, unsigned flags, mode_type mode) { MathGridInset grid(1, 1); - parse_into1(grid, flags, false); + parse1(grid, flags, mode, false); array = grid.cell(0); - // remove 'unnecessary' braces: - if (array.size() == 1 && array.back()->asBraceInset()) { - lyxerr << "extra braces removed\n"; - array = array.back()->asBraceInset()->cell(0); - } } -void Parser::parse_into2(MathAtom & at, unsigned flags, bool numbered) +void Parser::parse2(MathAtom & at, const unsigned flags, const mode_type mode, + const bool numbered) { - parse_into1(*(at->asGridInset()), flags, numbered); + parse1(*(at.nucleus()->asGridInset()), flags, mode, numbered); } -void Parser::parse_into1(MathGridInset & grid, unsigned flags, bool numbered) +void Parser::parse1(MathGridInset & grid, unsigned flags, + const mode_type mode, const bool numbered) { - bool panic = false; - int limits = 0; + int limits = 0; MathGridInset::row_type cellrow = 0; MathGridInset::col_type cellcol = 0; MathArray * cell = &grid.cell(grid.index(cellrow, cellcol)); @@ -736,13 +606,12 @@ void Parser::parse_into1(MathGridInset & grid, unsigned flags, bool numbered) #ifdef FILEDEBUG lyxerr << "t: " << t << " flags: " << flags << "\n"; - //cell->dump(); + cell->dump(); lyxerr << "\n"; #endif if (flags & FLAG_ITEM) { - if (t.cat() == catSpace) - continue; + skipSpaces(); flags &= ~FLAG_ITEM; if (t.cat() == catBegin) { @@ -756,78 +625,99 @@ void Parser::parse_into1(MathGridInset & grid, unsigned flags, bool numbered) flags |= FLAG_LEAVE; } - if (flags & FLAG_BLOCK) { - if (t.cat() == catAlign || t.isCR() || t.cs() == "end") { - putback(); + + if (flags & FLAG_BRACED) { + if (t.cat() == catSpace) + continue; + + if (t.cat() != catBegin) { + error("opening brace expected"); return; } + + // skip the brace and collect everything to the next matching + // closing brace + flags = FLAG_BRACE_LAST; } - if (flags & FLAG_BLOCK2) { - if (t.cat() == catAlign || t.isCR() || t.cs() == "end" - || t.cat() == catEnd) { + + if (flags & FLAG_OPTION) { + if (t.cat() == catOther && t.character() == '[') { + MathArray ar; + parse(ar, FLAG_BRACK_LAST, mode); + cell->append(ar); + } else { + // no option found, put back token and we are done putback(); - return; } + return; } // // cat codes // if (t.cat() == catMath) { - if (flags & FLAG_TEXTMODE) { + if (mode != MathInset::MATH_MODE) { // we are inside some text mode thingy, so opening new math is allowed - MathAtom at(new MathHullInset(LM_OT_SIMPLE)); - parse_into2(at, FLAG_SIMPLE, false); - cell->push_back(at); - } else { - dump(); - lyxerr << "something strange in the parser\n"; - break; + Token const & n = getToken(); + if (n.cat() == catMath) { + // TeX's $$...$$ syntax for displayed math + cell->push_back(MathAtom(new MathHullInset("equation"))); + parse2(cell->back(), FLAG_SIMPLE, MathInset::MATH_MODE, false); + getToken(); // skip the second '$' token + } else { + // simple $...$ stuff + putback(); + cell->push_back(MathAtom(new MathHullInset("simple"))); + parse2(cell->back(), FLAG_SIMPLE, MathInset::MATH_MODE, false); + } } - if (flags & FLAG_SIMPLE) { + else if (flags & FLAG_SIMPLE) { // this is the end of the formula return; } + + else { + error("something strange in the parser\n"); + break; + } } else if (t.cat() == catLetter) - add(*cell, t.character()); + cell->push_back(MathAtom(new MathCharInset(t.character()))); + + else if (t.cat() == catSpace && mode != MathInset::MATH_MODE) { + if (cell->empty() || cell->back()->getChar() != ' ') + cell->push_back(MathAtom(new MathCharInset(t.character()))); + } - else if (t.cat() == catSpace) //&& code == LM_TC_TEXTRM - add(*cell, t.character()); + else if (t.cat() == catNewline && mode != MathInset::MATH_MODE) + cell->push_back(MathAtom(new MathCharInset(t.character()))); else if (t.cat() == catParameter) { Token const & n = getToken(); cell->push_back(MathAtom(new MathMacroArgument(n.character()-'0'))); } + else if (t.cat() == catActive) + cell->push_back(MathAtom(new MathCharInset(t.character()))); + else if (t.cat() == catBegin) { MathArray ar; - parse_into(ar, FLAG_BRACE_LAST); -#ifndef WITH_WARNINGS -#warning this might be wrong in general! -#endif - // ignore braces around simple items - if ((ar.size() == 1 && !ar.front()->needsBraces() - || (ar.size() == 2 && !ar.front()->needsBraces() - && ar.back()->asScriptInset())) - || (ar.size() == 0 && cell->size() == 0)) - { - cell->push_back(ar); - } else { - cell->push_back(MathAtom(new MathBraceInset)); - cell->back()->cell(0).swap(ar); - } + parse(ar, FLAG_BRACE_LAST, mode); + // do not create a BraceInset if they were written by LyX + // this helps to keep the annoyance of "a choose b" to a minimum + if (ar.size() == 1 && ar[0]->extraBraces()) + cell->append(ar); + else + cell->push_back(MathAtom(new MathBraceInset(ar))); } else if (t.cat() == catEnd) { if (flags & FLAG_BRACE_LAST) return; - lyxerr << "found '}' unexpectedly, cell: '" << cell << "'\n"; - dump(); - //lyxerr << "found '}' unexpectedly\n"; + error("found '}' unexpectedly"); //lyx::Assert(0); //add(cell, '}', LM_TC_TEX); } @@ -835,8 +725,8 @@ void Parser::parse_into1(MathGridInset & grid, unsigned flags, bool numbered) else if (t.cat() == catAlign) { ++cellcol; //lyxerr << " column now " << cellcol << " max: " << grid.ncols() << "\n"; - if (cellcol == grid.ncols()) { - lyxerr << "adding column " << cellcol << "\n"; + if (cellcol == grid.ncols()) { + //lyxerr << "adding column " << cellcol << "\n"; grid.addCol(cellcol - 1); } cell = &grid.cell(grid.index(cellrow, cellcol)); @@ -844,43 +734,153 @@ void Parser::parse_into1(MathGridInset & grid, unsigned flags, bool numbered) else if (t.cat() == catSuper || t.cat() == catSub) { bool up = (t.cat() == catSuper); - MathScriptInset * p = 0; - if (cell->size()) - p = cell->back()->asScriptInset(); - if (!p || p->has(up)) { + // we need no new script inset if the last thing was a scriptinset, + // which has that script already not the same script already + if (!cell->size()) cell->push_back(MathAtom(new MathScriptInset(up))); - p = cell->back()->asScriptInset(); + else if (cell->back()->asScriptInset() && + !cell->back()->asScriptInset()->has(up)) + cell->back().nucleus()->asScriptInset()->ensure(up); + else if (cell->back()->asScriptInset()) + cell->push_back(MathAtom(new MathScriptInset(up))); + else + cell->back() = MathAtom(new MathScriptInset(cell->back(), up)); + MathScriptInset * p = cell->back().nucleus()->asScriptInset(); + // special handling of {}-bases + // is this always correct? + // It appears that this is wrong (Dekel) + //if (p->nuc().size() == 1 && p->nuc().back()->asNestInset() && + // p->nuc().back()->extraBraces()) + // p->nuc() = p->nuc().back()->asNestInset()->cell(0); + parse(p->cell(up), FLAG_ITEM, mode); + if (limits) { + p->limits(limits); + limits = 0; } - p->ensure(up); - parse_into(p->cell(up), FLAG_ITEM); - p->limits(limits); - limits = 0; } - else if (t.character() == ')' && (flags & FLAG_SIMPLE2)) - return; - - else if (t.character() == ']' && (flags & FLAG_BRACK_END)) + else if (t.character() == ']' && (flags & FLAG_BRACK_LAST)) { + //lyxerr << "finished reading option\n"; return; + } else if (t.cat() == catOther) - add(*cell, t.character()); + cell->push_back(MathAtom(new MathCharInset(t.character()))); + + else if (t.cat() == catComment) { + string s; + while (good()) { + Token const & t = getToken(); + if (t.cat() == catNewline) + break; + s += t.asString(); + } + cell->push_back(MathAtom(new MathCommentInset(s))); + skipSpaces(); + } // // control sequences // + + else if (t.cs() == "lyxlock") { + if (cell->size()) + cell->back().nucleus()->lock(true); + } + + else if (t.cs() == "def" || t.cs() == "newcommand") { + string name; + int nargs = 0; + if (t.cs() == "def") { + // get name + name = getToken().cs(); + + // read parameter + string pars; + while (good() && nextToken().cat() != catBegin) { + pars += getToken().cs(); + ++nargs; + } + nargs /= 2; + //lyxerr << "read \\def parameter list '" << pars << "'\n"; + + } else { // t.cs() == "newcommand" + + if (getToken().cat() != catBegin) { + error("'{' in \\newcommand expected (1) \n"); + return; + } + + name = getToken().cs(); + + if (getToken().cat() != catEnd) { + error("'}' in \\newcommand expected\n"); + return; + } + + string arg = getArg('[', ']'); + if (!arg.empty()) + nargs = atoi(arg.c_str()); + + } + + MathArray ar1; + parse(ar1, FLAG_ITEM, MathInset::UNDECIDED_MODE); + + // we cannot handle recursive stuff at all + //MathArray test; + //test.push_back(createMathInset(name)); + //if (ar1.contains(test)) { + // error("we cannot handle recursive macros at all.\n"); + // return; + //} + + // is a version for display attached? + skipSpaces(); + MathArray ar2; + if (nextToken().cat() == catBegin) { + parse(ar2, FLAG_ITEM, MathInset::MATH_MODE); + } + + cell->push_back(MathAtom(new MathMacroTemplate(name, nargs, ar1, ar2))); + } + + else if (t.cs() == "(") { + cell->push_back(MathAtom(new MathHullInset("simple"))); + parse2(cell->back(), FLAG_SIMPLE2, MathInset::MATH_MODE, false); + } + + else if (t.cs() == "[") { + cell->push_back(MathAtom(new MathHullInset("equation"))); + parse2(cell->back(), FLAG_EQUATION, MathInset::MATH_MODE, false); + } + else if (t.cs() == "protect") - // ignore \\protect, will be re-added during output + // ignore \\protect, will hopefully be re-added during output ; - else if (t.cs() == "end") - break; + else if (t.cs() == "end") { + if (flags & FLAG_END) { + // eat environment name + //string const name = + getArg('{', '}'); + // FIXME: check that we ended the correct environment + return; + } + error("found 'end' unexpectedly"); + } - else if (t.cs() == ")") - break; + else if (t.cs() == ")") { + if (flags & FLAG_SIMPLE2) + return; + error("found '\\)' unexpectedly"); + } - else if (t.cs() == "]") - break; + else if (t.cs() == "]") { + if (flags & FLAG_EQUATION) + return; + error("found '\\]' unexpectedly"); + } else if (t.cs() == "\\") { grid.vcrskip(LyXLength(getArg('[', ']')), cellrow); @@ -893,6 +893,39 @@ void Parser::parse_into1(MathGridInset & grid, unsigned flags, bool numbered) cell = &grid.cell(grid.index(cellrow, cellcol)); } +#if 0 + else if (t.cs() == "multicolumn") { + // extract column count and insert dummy cells + MathArray count; + parse(count, FLAG_ITEM, mode); + int cols = 1; + if (!extractNumber(count, cols)) { + lyxerr << " can't extract number of cells from " << count << "\n"; + } + // resize the table if necessary + for (int i = 0; i < cols; ++i) { + ++cellcol; + if (cellcol == grid.ncols()) { + //lyxerr << "adding column " << cellcol << "\n"; + grid.addCol(cellcol - 1); + } + cell = &grid.cell(grid.index(cellrow, cellcol)); + // mark this as dummy + grid.cellinfo(grid.index(cellrow, cellcol)).dummy_ = true; + } + // the last cell is the real thng, not a dummy + grid.cellinfo(grid.index(cellrow, cellcol)).dummy_ = false; + + // read special alignment + MathArray align; + parse(align, FLAG_ITEM, mode); + //grid.cellinfo(grid.index(cellrow, cellcol)).align_ = extractString(align); + + // parse the remaining contents into the "real" cell + parse(*cell, FLAG_ITEM, mode); + } +#endif + else if (t.cs() == "limits") limits = 1; @@ -910,58 +943,146 @@ void Parser::parse_into1(MathGridInset & grid, unsigned flags, bool numbered) } else if (t.cs() == "hline") { - if (grid.asHullInset()) - grid.asHullInset()->rowinfo(cellrow + 1); + grid.rowinfo(cellrow).lines_ ++; } else if (t.cs() == "sqrt") { - char c = getChar(); - if (c == '[') { + MathArray ar; + parse(ar, FLAG_OPTION, mode); + if (ar.size()) { cell->push_back(MathAtom(new MathRootInset)); - parse_into(cell->back()->cell(0), FLAG_BRACK_END); - parse_into(cell->back()->cell(1), FLAG_ITEM); + cell->back().nucleus()->cell(0) = ar; + parse(cell->back().nucleus()->cell(1), FLAG_ITEM, mode); } else { - putback(); cell->push_back(MathAtom(new MathSqrtInset)); - parse_into(cell->back()->cell(0), FLAG_ITEM); + parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode); } } + else if (t.cs() == "xrightarrow" || t.cs() == "xleftarrow") { + cell->push_back(createMathInset(t.cs())); + parse(cell->back().nucleus()->cell(1), FLAG_OPTION, mode); + parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode); + } + + else if (t.cs() == "ref" || t.cs() == "prettyref" || + t.cs() == "pageref" || t.cs() == "vpageref" || t.cs() == "vref") { + cell->push_back(MathAtom(new RefInset(t.cs()))); + parse(cell->back().nucleus()->cell(1), FLAG_OPTION, mode); + parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode); + } + else if (t.cs() == "left") { + skipSpaces(); string l = getToken().asString(); MathArray ar; - parse_into(ar, FLAG_RIGHT); + parse(ar, FLAG_RIGHT, mode); + skipSpaces(); string r = getToken().asString(); - MathAtom dl(new MathDelimInset(l, r)); - dl->cell(0) = ar; - cell->push_back(dl); + cell->push_back(MathAtom(new MathDelimInset(l, r, ar))); } else if (t.cs() == "right") { - if (!(flags & FLAG_RIGHT)) { - //lyxerr << "got so far: '" << cell << "'\n"; - error("Unmatched right delimiter"); - } + if (flags & FLAG_RIGHT) + return; + //lyxerr << "got so far: '" << cell << "'\n"; + error("Unmatched right delimiter"); return; } else if (t.cs() == "begin") { string const name = getArg('{', '}'); + if (name == "array" || name == "subarray") { - string const valign = getArg('[', ']') + 'c'; - string const halign = getArg('{', '}'); + string const valign = parse_verbatim_option() + 'c'; + string const halign = parse_verbatim_item(); cell->push_back(MathAtom(new MathArrayInset(name, valign[0], halign))); - parse_into2(cell->back(), FLAG_END, false); - } else if (name == "split" || name == "cases" || + parse2(cell->back(), FLAG_END, mode, false); + } + + else if (name == "tabular") { + string const valign = parse_verbatim_option() + 'c'; + string const halign = parse_verbatim_item(); + cell->push_back(MathAtom(new MathTabularInset(name, valign[0], halign))); + parse2(cell->back(), FLAG_END, MathInset::TEXT_MODE, false); + } + + else if (name == "split" || name == "cases" || name == "gathered" || name == "aligned") { cell->push_back(createMathInset(name)); - parse_into2(cell->back(), FLAG_END, false); - } else if (name == "matrix" || name == "pmatrix" || name == "bmatrix" || - name == "vmatrix" || name == "Vmatrix") { - cell->push_back(createMathInset(name)); - parse_into2(cell->back(), FLAG_END, false); - } else - lyxerr << "unknow math inset begin '" << name << "'\n"; + parse2(cell->back(), FLAG_END, mode, false); + } + + else if (name == "math") { + cell->push_back(MathAtom(new MathHullInset("simple"))); + parse2(cell->back(), FLAG_END, MathInset::MATH_MODE, true); + } + + else if (name == "equation" || name == "equation*" + || name == "displaymath") { + cell->push_back(MathAtom(new MathHullInset("equation"))); + parse2(cell->back(), FLAG_END, MathInset::MATH_MODE, (name == "equation")); + } + + else if (name == "eqnarray" || name == "eqnarray*") { + cell->push_back(MathAtom(new MathHullInset("eqnarray"))); + parse2(cell->back(), FLAG_END, MathInset::MATH_MODE, !stared(name)); + } + + else if (name == "align" || name == "align*") { + cell->push_back(MathAtom(new MathHullInset("align"))); + parse2(cell->back(), FLAG_END, MathInset::MATH_MODE, !stared(name)); + } + + else if (name == "flalign" || name == "flalign*") { + cell->push_back(MathAtom(new MathHullInset("flalign"))); + parse2(cell->back(), FLAG_END, MathInset::MATH_MODE, !stared(name)); + } + + else if (name == "alignat" || name == "alignat*") { + // ignore this for a while + getArg('{', '}'); + cell->push_back(MathAtom(new MathHullInset("alignat"))); + parse2(cell->back(), FLAG_END, MathInset::MATH_MODE, !stared(name)); + } + + else if (name == "xalignat" || name == "xalignat*") { + // ignore this for a while + getArg('{', '}'); + cell->push_back(MathAtom(new MathHullInset("xalignat"))); + parse2(cell->back(), FLAG_END, MathInset::MATH_MODE, !stared(name)); + } + + else if (name == "xxalignat") { + // ignore this for a while + getArg('{', '}'); + cell->push_back(MathAtom(new MathHullInset("xxalignat"))); + parse2(cell->back(), FLAG_END, MathInset::MATH_MODE, !stared(name)); + } + + else if (name == "multline" || name == "multline*") { + cell->push_back(MathAtom(new MathHullInset("multline"))); + parse2(cell->back(), FLAG_END, MathInset::MATH_MODE, !stared(name)); + } + + else if (name == "gather" || name == "gather*") { + cell->push_back(MathAtom(new MathHullInset("gather"))); + parse2(cell->back(), FLAG_END, MathInset::MATH_MODE, !stared(name)); + } + + else if (latexkeys const * l = in_word_set(name)) { + if (l->inset == "matrix") { + cell->push_back(createMathInset(name)); + parse2(cell->back(), FLAG_END, mode, false); + } + } + + else { + //lyxerr << "unknow math inset begin '" << name << "'\n"; + // create generic environment inset + cell->push_back(MathAtom(new MathEnvInset(name))); + parse2(cell->back(), FLAG_END, mode, false); + } } else if (t.cs() == "kern") { @@ -969,7 +1090,7 @@ void Parser::parse_into1(MathGridInset & grid, unsigned flags, bool numbered) #warning A hack... #endif string s; - while (1) { + while (true) { Token const & t = getToken(); if (!good()) { putback(); @@ -983,47 +1104,59 @@ void Parser::parse_into1(MathGridInset & grid, unsigned flags, bool numbered) } else if (t.cs() == "label") { - if (grid.asHullInset()) - grid.asHullInset()->label(cellrow, getArg('{', '}')); + string label = parse_verbatim_item(); + if (grid.asHullInset()) { + grid.asHullInset()->label(cellrow, label); + } else { + cell->push_back(createMathInset(t.cs())); + cell->push_back(MathAtom(new MathBraceInset(asArray(label)))); + } } else if (t.cs() == "choose" || t.cs() == "over" || t.cs() == "atop") { - MathAtom p = createMathInset(t.cs()); - cell->swap(p->cell(0)); - parse_into(p->cell(1), flags); - cell->push_back(p); + MathAtom at = createMathInset(t.cs()); + at.nucleus()->cell(0) = *cell; + cell->clear(); + parse(at.nucleus()->cell(1), flags, mode); + cell->push_back(at); return; } else if (t.cs() == "substack") { cell->push_back(createMathInset(t.cs())); - parse_into2(cell->back(), FLAG_ITEM, false); + parse2(cell->back(), FLAG_ITEM, mode, false); } else if (t.cs() == "xymatrix") { cell->push_back(createMathInset(t.cs())); - parse_into2(cell->back(), FLAG_ITEM, false); + parse2(cell->back(), FLAG_ITEM, mode, false); + } + + else if (t.cs() == "framebox") { + cell->push_back(createMathInset(t.cs())); + parse(cell->back().nucleus()->cell(0), FLAG_OPTION, MathInset::TEXT_MODE); + parse(cell->back().nucleus()->cell(1), FLAG_OPTION, MathInset::TEXT_MODE); + parse(cell->back().nucleus()->cell(2), FLAG_ITEM, MathInset::TEXT_MODE); } #if 0 + else if (t.cs() == "infer") { + MathArray ar; + parse(ar, FLAG_OPTION, mode); + cell->push_back(createMathInset(t.cs())); + parse2(cell->back(), FLAG_ITEM, mode, false); + } + // Disabled else if (1 && t.cs() == "ar") { MathXYArrowInset * p = new MathXYArrowInset; - // try to read target - char c = getChar(); - if (c == '[') { - parse_into(p->cell(0), FLAG_BRACK_END); - //lyxerr << "read target: " << p->cell(0) << "\n"; - } else { - putback(); - } - + 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_into(p->cell(1), FLAG_ITEM); + parse(p->cell(1), FLAG_ITEM, mode); //lyxerr << "read label: " << p->cell(1) << "\n"; } @@ -1036,47 +1169,56 @@ void Parser::parse_into1(MathGridInset & grid, unsigned flags, bool numbered) latexkeys const * l = in_word_set(t.cs()); if (l) { if (l->inset == "font") { - lyxerr << "starting font " << t.cs() << "\n"; - MathAtom p = createMathInset(t.cs()); - bool textmode = (t.cs()[0] == 't'); - parse_into(p->cell(0), FLAG_ITEM | (textmode ? FLAG_TEXTMODE : 0)); - cell->push_back(p); - //lyxerr << "ending font\n"; + cell->push_back(createMathInset(t.cs())); + parse(cell->back().nucleus()->cell(0), FLAG_ITEM, asMode(mode, l->extra)); } else if (l->inset == "oldfont") { - MathAtom p = createMathInset(t.cs()); - parse_into(p->cell(0), flags); - cell->push_back(p); + cell->push_back(createMathInset(t.cs())); + parse(cell->back().nucleus()->cell(0), flags, asMode(mode, l->extra)); return; } - else if (l->inset == "box") { - MathAtom p = createMathInset(t.cs()); - parse_into(p->cell(0), FLAG_ITEM | FLAG_TEXTMODE); - cell->push_back(p); - } - else if (l->inset == "style") { - MathAtom p = createMathInset(t.cs()); - parse_into(p->cell(0), flags); - cell->push_back(p); + cell->push_back(createMathInset(t.cs())); + parse(cell->back().nucleus()->cell(0), flags, mode); return; } + else if (l->inset == "parbox") { + // read optional positioning and width + string pos = parse_verbatim_option(); + string width = parse_verbatim_item(); + cell->push_back(createMathInset(t.cs())); + parse(cell->back().nucleus()->cell(0), FLAG_ITEM, MathInset::TEXT_MODE); + cell->back().nucleus()->asParboxInset()->setPosition(pos); + cell->back().nucleus()->asParboxInset()->setWidth(width); + } + else { - MathAtom p = createMathInset(t.cs()); - for (MathInset::idx_type i = 0; i < p->nargs(); ++i) - parse_into(p->cell(i), FLAG_ITEM); - cell->push_back(p); + MathAtom at = createMathInset(t.cs()); + for (MathInset::idx_type i = 0; i < at->nargs(); ++i) + parse(at.nucleus()->cell(i), FLAG_ITEM, asMode(mode, l->extra)); + cell->push_back(at); } } else { - MathAtom p = createMathInset(t.cs()); - for (MathInset::idx_type i = 0; i < p->nargs(); ++i) - parse_into(p->cell(i), FLAG_ITEM); - cell->push_back(p); + MathAtom at = createMathInset(t.cs()); + MathInset::mode_type m = mode; + if (m == MathInset::UNDECIDED_MODE) + m = at->currentMode(); + MathInset::idx_type start = 0; + // this fails on \bigg[...\bigg] + //MathArray opt; + //parse(opt, FLAG_OPTION, MathInset::VERBATIM_MODE); + //if (opt.size()) { + // start = 1; + // at.nucleus()->cell(0) = opt; + //} + for (MathInset::idx_type i = start; i < at->nargs(); ++i) + parse(at.nucleus()->cell(i), FLAG_ITEM, m); + cell->push_back(at); } } @@ -1086,15 +1228,6 @@ void Parser::parse_into1(MathGridInset & grid, unsigned flags, bool numbered) break; } } - - if (panic) { - lyxerr << " Math Panic, expect problems!\n"; - // Search for the end command. - Token t; - do { - t = getToken(); - } while (good() && t.cs() != "end"); - } } @@ -1111,47 +1244,31 @@ void mathed_parse_cell(MathArray & ar, string const & str) void mathed_parse_cell(MathArray & ar, istream & is) { - Parser(is).parse_into(ar, 0); + Parser(is).parse(ar, 0, MathInset::MATH_MODE); } - -bool mathed_parse_macro(string & name, string const & str) +bool mathed_parse_normal(MathAtom & t, string const & str) { istringstream is(str.c_str()); - Parser parser(is); - return parser.parse_macro(name); + return Parser(is).parse(t); } -bool mathed_parse_macro(string & name, istream & is) -{ - Parser parser(is); - return parser.parse_macro(name); -} -bool mathed_parse_macro(string & name, LyXLex & lex) +bool mathed_parse_normal(MathAtom & t, istream & is) { - Parser parser(lex); - return parser.parse_macro(name); + return Parser(is).parse(t); } - -bool mathed_parse_normal(MathAtom & t, string const & str) +bool mathed_parse_normal(MathAtom & t, LyXLex & lex) { - istringstream is(str.c_str()); - Parser parser(is); - return parser.parse_normal(t); + return Parser(lex).parse(t); } -bool mathed_parse_normal(MathAtom & t, istream & is) -{ - Parser parser(is); - return parser.parse_normal(t); -} -bool mathed_parse_normal(MathAtom & t, LyXLex & lex) +void mathed_parse_normal(MathGridInset & grid, string const & str) { - Parser parser(lex); - return parser.parse_normal(t); + istringstream is(str.c_str()); + Parser(is).parse1(grid, 0, MathInset::MATH_MODE, false); }