]> git.lyx.org Git - lyx.git/blobdiff - src/mathed/math_parser.C
further code uglification to make Jean-Marc's compiler happy
[lyx.git] / src / mathed / math_parser.C
index 3f49ad9592a0f14280f214b879c239bfae276229..18766700e37c3bd16dd972b404597f445f137837 100644 (file)
 #include "math_deliminset.h"
 #include "math_factory.h"
 #include "math_funcinset.h"
+#include "math_kerninset.h"
 #include "math_macro.h"
 #include "math_macrotable.h"
 #include "math_macrotemplate.h"
 #include "math_matrixinset.h"
 #include "math_rootinset.h"
-#include "math_scopeinset.h"
 #include "math_sqrtinset.h"
 #include "math_scriptinset.h"
+#include "math_specialcharinset.h"
+#include "math_splitinset.h"
 #include "math_sqrtinset.h"
 #include "debug.h"
 #include "support.h"
@@ -46,6 +48,8 @@
 #include "support/lstrings.h"
 
 using std::istream;
+using std::ostream;
+using std::ios;
 using std::endl;
 
 
@@ -57,34 +61,6 @@ bool stared(string const & s)
        return n && s[n - 1] == '*';
 }
 
-MathScriptInset * prevScriptInset(MathArray const & array)
-{
-       MathInset * p = array.back();
-       return (p && p->isScriptInset()) ? static_cast<MathScriptInset *>(p) : 0;
-}
-
-
-MathInset * lastScriptInset(MathArray & array, bool up, int limits)
-{
-       MathScriptInset * p = prevScriptInset(array);
-       if (!p) {
-               MathInset * b = array.back();
-               if (b && b->isScriptable()) {
-                       p = new MathScriptInset(up, !up, b->clone());
-                       array.pop_back();       
-               } else {
-                       p = new MathScriptInset(up, !up);
-               }
-               array.push_back(p);
-       }
-       if (up)
-               p->up(true);
-       else
-               p->down(true);
-       if (limits)
-               p->limits(limits);
-       return p;
-}
 
 
 // These are TeX's catcodes
@@ -116,9 +92,6 @@ inline CatCode catcode(unsigned char c)
 }
 
 
-const unsigned char LM_TK_OPEN  = '{';
-const unsigned char LM_TK_CLOSE = '}';
-
 enum {
        FLAG_BRACE      = 1 << 0,  //  an opening brace needed
        FLAG_BRACE_LAST = 1 << 1,  //  last closing brace ends the parsing process
@@ -128,7 +101,7 @@ enum {
        FLAG_NEWLINE    = 1 << 6,  //  next \\\\ ends the parsing process
        FLAG_ITEM       = 1 << 7,  //  read a (possibly braced token)
        FLAG_BLOCK      = 1 << 8,  //  next block ends the parsing process
-       FLAG_LEAVE      = 1 << 9,  //  leave the loop at the end
+       FLAG_LEAVE      = 1 << 9   //  leave the loop at the end
 };
 
 
@@ -173,8 +146,6 @@ public:
        ///
        Token(const string & cs) : cs_(cs), char_(0), cat_(catIgnore) {}
 
-       ///
-       bool operator==(Token const & t) const;
        ///
        string const & cs() const { return cs_; }
        ///
@@ -198,9 +169,15 @@ string Token::asString() const
        return cs_.size() ? cs_ : string(1, char_);
 }
 
-bool Token::operator==(Token const & t) const
+bool operator==(Token const & s, Token const & t)
+{
+       return s.character() == t.character()
+               && s.cat() == t.cat() && s.cs() == t.cs(); 
+}
+
+bool operator!=(Token const & s, Token const & t)
 {
-       return char_ == t.char_ && cat_ == t.cat_ && cs_ == t.cs_; 
+       return !(s == t);
 }
 
 ostream & operator<<(ostream & os, Token const & t)
@@ -226,7 +203,7 @@ public:
        ///
        MathMatrixInset * parse_normal();
        ///
-       void parse_into(MathArray & array, unsigned flags);
+       void parse_into(MathArray & array, unsigned flags, MathTextCodes = LM_TC_MIN);
        ///
        int lineno() const { return lineno_; }
        ///
@@ -241,8 +218,6 @@ private:
        void error(string const & msg);
        ///
        void parse_lines(MathGridInset * p, bool numbered, bool outmost);
-       ///
-       latexkeys const * read_delim();
 
 private:
        ///
@@ -280,14 +255,15 @@ private:
 
 
 Parser::Parser(LyXLex & lexer)
-       : lineno_(lexer.getLineNo()), pos_(0)
+       : lineno_(lexer.getLineNo()), pos_(0), curr_num_(false)
 {
        tokenize(lexer.getStream());
+       lexer.eatLine();
 }
 
 
 Parser::Parser(istream & is)
-       : lineno_(0), pos_(0)
+       : lineno_(0), pos_(0), curr_num_(false)
 {
        tokenize(is);
 }
@@ -389,7 +365,7 @@ void Parser::tokenize(string const & buffer)
                init_done = true;
        }
 
-       istringstream is(buffer, ios::in || ios::binary);
+       istringstream is(buffer.c_str(), ios::in | ios::binary);
 
        char c;
        while (is.get(c)) {
@@ -401,7 +377,7 @@ void Parser::tokenize(string const & buffer)
                                if (catcode(c) == catNewline)
                                        ; //push_back(Token("par"));
                                else {
-                                       push_back(Token(' ',catSpace));
+                                       push_back(Token(' ', catSpace));
                                        is.putback(c);  
                                }
                                break;
@@ -434,16 +410,19 @@ void Parser::tokenize(string const & buffer)
                }
        }
 
-       //lyxerr << "\nTokens: ";
-       //for (unsigned i = 0; i < tokens_.size(); ++i)
-       //      lyxerr << tokens_[i];
-       //lyxerr << "\n";
+#if 0
+       lyxerr << "\nTokens: ";
+       for (unsigned i = 0; i < tokens_.size(); ++i)
+               lyxerr << tokens_[i];
+       lyxerr << "\n";
+#endif
 }
 
 
 void Parser::error(string const & msg) 
 {
        lyxerr << "Line ~" << lineno_ << ": Math parse error: " << msg << endl;
+       //exit(1);
 }
 
 
@@ -531,6 +510,9 @@ MathMacroTemplate * Parser::parse_macro()
 
 MathMatrixInset * Parser::parse_normal()
 {
+       while (nextToken().cat() == catSpace)
+               getToken();
+
        Token const & t = getToken();
 
        if (t.cat() == catMath || t.cs() == "(") {
@@ -564,7 +546,7 @@ MathMatrixInset * Parser::parse_normal()
        string const name = getArg('{', '}');
 
        if (name == "equation" || name == "equation*") {
-               curr_num_ = stared(name);
+               curr_num_ = !stared(name);
                curr_label_.erase();
                MathMatrixInset * p = new MathMatrixInset(LM_OT_EQUATION);
                parse_into(p->cell(0), FLAG_END);
@@ -575,50 +557,66 @@ MathMatrixInset * Parser::parse_normal()
 
        if (name == "eqnarray" || name == "eqnarray*") {
                MathMatrixInset * p = new MathMatrixInset(LM_OT_EQNARRAY);
-               parse_lines(p, stared(name), true);
+               parse_lines(p, !stared(name), true);
                return p;
        }
 
        if (name == "align" || name == "align*") {
                MathMatrixInset * p = new MathMatrixInset(LM_OT_ALIGN);
-               p->halign(getArg('{', '}'));
-               parse_lines(p, stared(name), true);
+               parse_lines(p, !stared(name), true);
                return p;
        }
 
        if (name == "alignat" || name == "alignat*") {
-               MathMatrixInset * p = new MathMatrixInset(LM_OT_ALIGNAT);
-               p->halign(getArg('{', '}'));
-               parse_lines(p, stared(name), true);
+               MathMatrixInset * p =
+                       new MathMatrixInset(LM_OT_ALIGNAT, 2 * atoi(getArg('{', '}').c_str()));
+               parse_lines(p, !stared(name), true);
                return p;
        }
 
-       lyxerr[Debug::MATHED] << "1: unknown math environment: " << name << "\n";
-       return 0;
-}
+       if (name == "xalignat" || name == "xalignat*") {
+               MathMatrixInset * p =
+                       new MathMatrixInset(LM_OT_XALIGNAT, 2 * atoi(getArg('{', '}').c_str()));
+               parse_lines(p, !stared(name), true);
+               return p;
+       }
 
+       if (name == "xxalignat") {
+               MathMatrixInset * p =
+                       new MathMatrixInset(LM_OT_XXALIGNAT, 2 * atoi(getArg('{', '}').c_str()));
+               parse_lines(p, !stared(name), true);
+               return p;
+       }
 
-latexkeys const * Parser::read_delim()
-{
-       Token const & t = getToken();
-       latexkeys const * l = in_word_set(t.asString());
-       return l ? l : in_word_set(".");
+       if (name == "multline" || name == "multline*") {
+               MathMatrixInset * p = new MathMatrixInset(LM_OT_MULTLINE);
+               parse_lines(p, !stared(name), true);
+               return p;
+       }
+
+       if (name == "gather" || name == "gather*") {
+               MathMatrixInset * p = new MathMatrixInset(LM_OT_GATHER);
+               parse_lines(p, !stared(name), true);
+               return p;
+       }
+
+       lyxerr[Debug::MATHED] << "1: unknown math environment: " << name << "\n";
+       return 0;
 }
 
 
-void Parser::parse_into(MathArray & array, unsigned flags)
+void Parser::parse_into(MathArray & array, unsigned flags, MathTextCodes code)
 {
        MathTextCodes yyvarcode = LM_TC_MIN;
 
        bool panic  = false;
-       int  limits = 0;
 
        while (good()) {
                Token const & t = getToken();
-               
-               lyxerr << "t: " << t << " flags: " << flags << "'\n";
+       
+               //lyxerr << "t: " << t << " flags: " << flags << "'\n";
                //array.dump(lyxerr);
-               lyxerr << "\n";
+               //lyxerr << "\n";
 
                if (flags & FLAG_ITEM) {
                        flags &= ~FLAG_ITEM;
@@ -645,7 +643,7 @@ void Parser::parse_into(MathArray & array, unsigned flags)
                }
 
                if (flags & FLAG_BLOCK) {
-                       if (t.cat() == catEnd || t.cat() == catAlign || t.cs() == "\\")
+                       if (t.cat() == catAlign || t.cs() == "\\")
                                return;
                        if (t.cs() == "end") {
                                getArg('{', '}');
@@ -662,7 +660,8 @@ void Parser::parse_into(MathArray & array, unsigned flags)
                else if (t.cat() == catLetter)
                        array.push_back(new MathCharInset(t.character(), yyvarcode));
 
-               else if (t.cat() == catSpace && yyvarcode == LM_TC_TEXTRM)
+               else if (t.cat() == catSpace &&
+                               (yyvarcode == LM_TC_TEXTRM || code == LM_TC_TEXTRM))
                        array.push_back(new MathCharInset(' ', yyvarcode));
 
                else if (t.cat() == catParameter) {
@@ -672,28 +671,27 @@ void Parser::parse_into(MathArray & array, unsigned flags)
                }
 
                else if (t.cat() == catBegin) {
-                       //lyxerr << " creating ScopeInset\n";
-                       array.push_back(new MathScopeInset);
-                       parse_into(array.back()->cell(0), FLAG_BRACE_LAST);
+                       array.push_back(new MathCharInset('{', LM_TC_TEX));
                }
 
                else if (t.cat() == catEnd) {
-                       if (!(flags & FLAG_BRACE_LAST))
-                               lyxerr << " ##### unexpected end of block\n";
-                       return;
+                       if (flags & FLAG_BRACE_LAST)
+                               return;
+                       array.push_back(new MathCharInset('}', LM_TC_TEX));
                }
                
                else if (t.cat() == catAlign) {
                        lyxerr << "found tab unexpectedly, array: '" << array << "'\n";
-                       return;
+                       array.push_back(new MathCharInset('&', LM_TC_TEX));
                }
                
-               else if (t.cat() == catSuper)
-                       parse_into(lastScriptInset(array, true, limits)->cell(0), FLAG_ITEM);
-               
-               else if (t.cat() == catSub)
-                       parse_into(lastScriptInset(array, false, limits)->cell(1), FLAG_ITEM);
-               
+               else if (t.cat() == catSuper || t.cat() == catSub) {
+                       bool up = (t.cat() == catSuper);
+                       if (array.empty())
+                               array.push_back(new MathCharInset(' '));
+                       parse_into(array.back().ensure(up)->cell(0), FLAG_ITEM);
+               }
+
                else if (t.character() == ']' && (flags & FLAG_BRACK_END))
                        return;
 
@@ -717,17 +715,18 @@ void Parser::parse_into(MathArray & array, unsigned flags)
 
                else if (t.cs() == "\\") {
                        curr_skip_ = getArg('[', ']');
-                       if (!(flags & FLAG_NEWLINE))
-                               lyxerr[Debug::MATHED]
+                       if (flags & FLAG_NEWLINE)
+                               return;
+                       lyxerr[Debug::MATHED]
                                        << "found newline unexpectedly, array: '" << array << "'\n";
-                       return;
+                       array.push_back(createMathInset("\\"));
                }
        
-               else if (t.cs() == "limits"
-                       limits = 1;
+               else if (t.cs() == "limits" && array.size())
+                       array.back().limits(1);
                
-               else if (t.cs() == "nolimits"
-                       limits = -1;
+               else if (t.cs() == "nolimits" && array.size())
+                       array.back().limits(-1);
                
                else if (t.cs() == "nonumber")
                        curr_num_ = false;
@@ -739,28 +738,30 @@ void Parser::parse_into(MathArray & array, unsigned flags)
                        char c = getChar();
                        if (c == '[') {
                                array.push_back(new MathRootInset);
-                               parse_into(array.back()->cell(0), FLAG_BRACK_END);
-                               parse_into(array.back()->cell(1), FLAG_ITEM);
+                               parse_into(array.back().nucleus()->cell(0), FLAG_BRACK_END);
+                               parse_into(array.back().nucleus()->cell(1), FLAG_ITEM);
                        } else {
                                putback();
                                array.push_back(new MathSqrtInset);
-                               parse_into(array.back()->cell(0), FLAG_ITEM);
+                               parse_into(array.back().nucleus()->cell(0), FLAG_ITEM);
                        }
                }
                
                else if (t.cs() == "left") {
-                       latexkeys const * l = read_delim();
+                       string l = getToken().asString();
                        MathArray ar;
                        parse_into(ar, FLAG_RIGHT);
-                       latexkeys const * r = read_delim();
+                       string r = getToken().asString();
                        MathDelimInset * dl = new MathDelimInset(l, r);
                        dl->cell(0) = ar;
                        array.push_back(dl);
                }
                
                else if (t.cs() == "right") {
-                       if (!(flags & FLAG_RIGHT))
+                       if (!(flags & FLAG_RIGHT)) {
+                               lyxerr << "got so far: '" << array << "'\n";
                                error("Unmatched right delimiter");
+                       }
                        return;
                }
 
@@ -775,20 +776,6 @@ void Parser::parse_into(MathArray & array, unsigned flags)
                        break; 
                }
 
-               case LM_TK_UNDEF: 
-                       if (MathMacroTable::hasTemplate(sval_)) {
-                               MathMacro * m = MathMacroTable::cloneTemplate(sval_);
-                               for (int i = 0; i < m->nargs(); ++i) 
-                                       parse_into(m->cell(i), FLAG_ITEM);
-                               array.push_back(m);
-                               m->metrics(LM_ST_TEXT);
-                       } else
-                               array.push_back(new MathFuncInset(sval_));
-                       break;
-
-               else  LM_TK_SPECIAL:
-                       array.push_back(new MathCharInset(ival_, LM_TC_SPECIAL));
-                       break;
 */
                
                else if (t.cs() == "begin") {
@@ -801,39 +788,90 @@ void Parser::parse_into(MathArray & array, unsigned flags)
                                m->halign(halign);
                                parse_lines(m, false, false);
                                array.push_back(m);
+                       } else if (name == "split") {
+                               MathSplitInset * m = new MathSplitInset(1);
+                               parse_lines(m, false, false);
+                               array.push_back(m);
                        } else 
                                lyxerr[Debug::MATHED] << "unknow math inset begin '" << name << "'\n";  
                }
        
+               else if (t.cs() == "kern") {
+#ifdef WITH_WARNINGS
+#warning A hack...
+#endif
+                       string s;
+                       while (1) {
+                               Token const & t = getToken();
+                               if (!good()) {
+                                       putback();      
+                                       break;
+                               }
+                               s += t.character();
+                               if (isValidLength(s))
+                                       break;
+                       }
+                       array.push_back(new MathKernInset(s));
+               }
+
                else if (t.cs() == "label") {
-                       MathArray ar;
-                       parse_into(ar, FLAG_ITEM);
-                       ostringstream os;
-                       ar.write(os, true);
-                       curr_label_ = os.str();
+                       //MathArray ar;
+                       //parse_into(ar, FLAG_ITEM);
+                       //ostringstream os;
+                       //ar.write(os, true);
+                       //curr_label_ = os.str();
                        // was: 
-                       //curr_label_ = getArg('{', '}');
+                       curr_label_ = getArg('{', '}');
                }
 
-               else if (t.cs() == "choose" || t.cs() == "over") {
-                       limits = 0;
+               else if (t.cs() == "choose" || t.cs() == "over" || t.cs() == "atop") {
                        MathInset * p = createMathInset(t.cs());
-                       p->cell(0).swap(array);
+                       // search backward for position of last '{' if any
+                       int pos;
+                       for (pos = array.size() - 1; pos >= 0; --pos)
+                               if (array.at(pos)->nucleus()->getChar() == '{')
+                                       break;
+                       if (pos >= 0) {
+                               // found it -> use the part after '{' as "numerator"
+                               p->cell(0) = MathArray(array, pos + 1, array.size());
+                               parse_into(p->cell(1), FLAG_BRACE_LAST);
+                               // delete denominator and the '{'
+                               array.erase(pos, array.size());
+                       } else if (flags & FLAG_RIGHT) {
+                               // we are inside a \left ... \right block
+                               //lyxerr << "found '" << t.cs() << "' enclosed by \\left .. \\right\n";
+                               p->cell(0).swap(array);
+                               parse_into(p->cell(1), FLAG_RIGHT);
+                               // handle the right delimiter properly
+                               putback();
+                       } else {
+                               // not found -> use everything as "numerator"
+                               p->cell(0).swap(array);
+                               parse_into(p->cell(1), FLAG_BLOCK);
+                       }
                        array.push_back(p);
-                       parse_into(p->cell(1), FLAG_BLOCK);
                }
        
                else if (t.cs().size()) {
-                       limits = 0;
                        latexkeys const * l = in_word_set(t.cs());
                        if (l) {
                                if (l->token == LM_TK_FONT) {
                                        //lyxerr << "starting font\n";
+                                       //CatCode catSpaceSave = theCatcode[' '];
+                                       //if (l->id == LM_TC_TEXTRM) {
+                                       //      // temporarily change catcode   
+                                       //      theCatcode[' '] = catLetter;    
+                                       //}
+
+                                       MathTextCodes t = static_cast<MathTextCodes>(l->id);
                                        MathArray ar;
-                                       parse_into(ar, FLAG_ITEM);
+                                       parse_into(ar, FLAG_ITEM, t);
                                        for (MathArray::iterator it = ar.begin(); it != ar.end(); ++it)
-                                               (*it)->handleFont(static_cast<MathTextCodes>(l->id));
+                                               it->nucleus()->handleFont(t);
                                        array.push_back(ar);
+
+                                       // undo catcode changes
+                                       ////theCatcode[' '] = catSpaceSave;
                                        //lyxerr << "ending font\n";
                                }
 
@@ -842,7 +880,7 @@ void Parser::parse_into(MathArray & array, unsigned flags)
 
                                else {
                                        MathInset * p = createMathInset(t.cs());
-                                       for (int i = 0; i < p->nargs(); ++i) 
+                                       for (unsigned int i = 0; i < p->nargs(); ++i) 
                                                parse_into(p->cell(i), FLAG_ITEM);
                                        array.push_back(p);
                                }
@@ -851,7 +889,7 @@ void Parser::parse_into(MathArray & array, unsigned flags)
                        else {
                                MathInset * p = createMathInset(t.cs());
                                if (p) {
-                                       for (int i = 0; i < p->nargs(); ++i)
+                                       for (unsigned int i = 0; i < p->nargs(); ++i)
                                                parse_into(p->cell(i), FLAG_ITEM);
                                        array.push_back(p);
                                } else {