]> git.lyx.org Git - lyx.git/blob - src/mathed/math_parser.C
unsigned char <-> char
[lyx.git] / src / mathed / math_parser.C
1 /*
2  *  File:        math_parser.C
3  *  Purpose:     Parser for mathed
4  *  Author:      Alejandro Aguilar Sierra <asierra@servidor.unam.mx> 
5  *  Created:     January 1996
6  *  Description: Parse LaTeX2e math mode code.
7  *
8  *  Dependencies: Xlib, XForms
9  *
10  *  Copyright: 1996, Alejandro Aguilar Sierra
11  *
12  *   Version: 0.8beta.
13  *
14  *   You are free to use and modify this code under the terms of
15  *   the GNU General Public Licence version 2 or later.
16  */
17
18 #include <config.h>
19
20 #include <cctype>
21
22 #ifdef __GNUG__
23 #pragma implementation
24 #endif
25
26 #include "math_parser.h"
27 #include "array.h"
28 #include "math_inset.h"
29 #include "math_arrayinset.h"
30 #include "math_charinset.h"
31 #include "math_deliminset.h"
32 #include "math_factory.h"
33 #include "math_funcinset.h"
34 #include "math_macro.h"
35 #include "math_macrotable.h"
36 #include "math_macrotemplate.h"
37 #include "math_matrixinset.h"
38 #include "math_rootinset.h"
39 #include "math_scopeinset.h"
40 #include "math_sqrtinset.h"
41 #include "math_scriptinset.h"
42 #include "math_sqrtinset.h"
43 #include "debug.h"
44 #include "support.h"
45 #include "lyxlex.h"
46 #include "support/lstrings.h"
47
48 using std::istream;
49 using std::endl;
50
51
52 namespace {
53
54 bool stared(string const & s)
55 {
56         unsigned n = s.size();
57         return n && s[n - 1] == '*';
58 }
59
60 MathScriptInset * prevScriptInset(MathArray const & array)
61 {
62         MathInset * p = array.back();
63         return (p && p->isScriptInset()) ? static_cast<MathScriptInset *>(p) : 0;
64 }
65
66
67 MathInset * lastScriptInset(MathArray & array, bool up, int limits)
68 {
69         MathScriptInset * p = prevScriptInset(array);
70         if (!p) {
71                 MathInset * b = array.back();
72                 if (b && b->isScriptable()) {
73                         p = new MathScriptInset(up, !up, b->clone());
74                         array.pop_back();       
75                 } else {
76                         p = new MathScriptInset(up, !up);
77                 }
78                 array.push_back(p);
79         }
80         if (up)
81                 p->up(true);
82         else
83                 p->down(true);
84         if (limits)
85                 p->limits(limits);
86         return p;
87 }
88
89
90 // These are TeX's catcodes
91 enum CatCode {
92         catEscape,     // 0    backslash 
93         catBegin,      // 1    {
94         catEnd,        // 2    }
95         catMath,       // 3    $
96         catAlign,      // 4    &
97         catNewline,    // 5    ^^M
98         catParameter,  // 6    #
99         catSuper,      // 7    ^
100         catSub,        // 8    _
101         catIgnore,     // 9       
102         catSpace,      // 10   space
103         catLetter,     // 11   a-zA-Z
104         catOther,      // 12   none of the above
105         catActive,     // 13   ~
106         catComment,    // 14   %
107         catInvalid     // 15   <delete>
108 };
109
110 CatCode theCatcode[256];  
111
112
113 inline CatCode catcode(unsigned char c)
114 {
115         return theCatcode[c];
116 }
117
118
119 const unsigned char LM_TK_OPEN  = '{';
120 const unsigned char LM_TK_CLOSE = '}';
121
122 enum {
123         FLAG_BRACE      = 1 << 0,  //  an opening brace needed
124         FLAG_BRACE_LAST = 1 << 1,  //  last closing brace ends the parsing process
125         FLAG_RIGHT      = 1 << 2,  //  next \\right ends the parsing process
126         FLAG_END        = 1 << 3,  //  next \\end ends the parsing process
127         FLAG_BRACK_END  = 1 << 4,  //  next closing bracket ends the parsing process
128         FLAG_NEWLINE    = 1 << 6,  //  next \\\\ ends the parsing process
129         FLAG_ITEM       = 1 << 7,  //  read a (possibly braced token)
130         FLAG_BLOCK      = 1 << 8,  //  next block ends the parsing process
131         FLAG_LEAVE      = 1 << 9,  //  leave the loop at the end
132 };
133
134
135 void catInit()
136 {
137         for (int i = 0; i <= 255; ++i) 
138                 theCatcode[i] = catOther;
139         for (int i = 'a'; i <= 'z'; ++i) 
140                 theCatcode[i] = catLetter;
141         for (int i = 'A'; i <= 'Z'; ++i) 
142                 theCatcode[i] = catLetter;
143
144         theCatcode['\\'] = catEscape;   
145         theCatcode['{']  = catBegin;    
146         theCatcode['}']  = catEnd;      
147         theCatcode['$']  = catMath;     
148         theCatcode['&']  = catAlign;    
149         theCatcode['\n'] = catNewline;  
150         theCatcode['#']  = catParameter;        
151         theCatcode['^']  = catSuper;    
152         theCatcode['_']  = catSub;      
153         theCatcode['\7f'] = catIgnore;    
154         theCatcode[' ']  = catSpace;    
155         theCatcode['\t'] = catSpace;    
156         theCatcode['\r'] = catSpace;    
157         theCatcode['~']  = catActive;   
158         theCatcode['%']  = catComment;  
159 }
160
161
162
163 //
164 // Helper class for parsing
165 //
166
167 class Token {
168 public:
169         ///
170         Token() : cs_(), char_(0), cat_(catIgnore) {}
171         ///
172         Token(char c, CatCode cat) : cs_(), char_(c), cat_(cat) {}
173         ///
174         Token(const string & cs) : cs_(cs), char_(0), cat_(catIgnore) {}
175
176         ///
177         bool operator==(Token const & t) const;
178         ///
179         string const & cs() const { return cs_; }
180         ///
181         CatCode cat() const { return cat_; }
182         ///
183         char character() const { return char_; }
184         ///
185         string asString() const;
186
187 private:        
188         ///
189         string cs_;
190         ///
191         char char_;
192         ///
193         CatCode cat_;
194 };
195
196 string Token::asString() const
197 {
198         return cs_.size() ? cs_ : string(1, char_);
199 }
200
201 bool Token::operator==(Token const & t) const
202 {
203         return char_ == t.char_ && cat_ == t.cat_ && cs_ == t.cs_; 
204 }
205
206 ostream & operator<<(ostream & os, Token const & t)
207 {
208         if (t.cs().size())
209                 os << "\\" << t.cs();
210         else
211                 os << "[" << t.character() << "," << t.cat() << "]";
212         return os;
213 }
214
215
216 class Parser {
217
218 public:
219         ///
220         Parser(LyXLex & lex);
221         ///
222         Parser(istream & is);
223
224         ///
225         MathMacroTemplate * parse_macro();
226         ///
227         MathMatrixInset * parse_normal();
228         ///
229         void parse_into(MathArray & array, unsigned flags);
230         ///
231         int lineno() const { return lineno_; }
232         ///
233         void putback();
234
235 private:
236         ///
237         string getArg(char lf, char rf);
238         ///
239         char getChar();
240         ///
241         void error(string const & msg);
242         ///
243         void parse_lines(MathGridInset * p, bool numbered, bool outmost);
244         ///
245         latexkeys const * read_delim();
246
247 private:
248         ///
249         void tokenize(istream & is);
250         ///
251         void tokenize(string const & s);
252         ///
253         void push_back(Token const & t);
254         ///
255         void pop_back();
256         ///
257         Token const & prevToken() const;
258         ///
259         Token const & nextToken() const;
260         ///
261         Token const & getToken();
262         ///
263         void lex(string const & s);
264         ///
265         bool good() const;
266
267         ///
268         int lineno_;
269         ///
270         std::vector<Token> tokens_;
271         ///
272         unsigned pos_;
273         ///
274         bool   curr_num_;
275         ///
276         string curr_label_;
277         ///
278         string curr_skip_;
279 };
280
281
282 Parser::Parser(LyXLex & lexer)
283         : lineno_(lexer.getLineNo()), pos_(0)
284 {
285         tokenize(lexer.getStream());
286 }
287
288
289 Parser::Parser(istream & is)
290         : lineno_(0), pos_(0)
291 {
292         tokenize(is);
293 }
294
295
296 void Parser::push_back(Token const & t)
297 {
298         tokens_.push_back(t);
299 }
300
301
302 void Parser::pop_back()
303 {
304         tokens_.pop_back();
305 }
306
307
308 Token const & Parser::prevToken() const
309 {
310         static const Token dummy;
311         return pos_ > 0 ? tokens_[pos_ - 1] : dummy;
312 }
313
314
315 Token const & Parser::nextToken() const
316 {
317         static const Token dummy;
318         return good() ? tokens_[pos_] : dummy;
319 }
320
321
322 Token const & Parser::getToken()
323 {
324         static const Token dummy;
325         return good() ? tokens_[pos_++] : dummy;
326 }
327
328
329 void Parser::putback()
330 {
331         --pos_;
332 }
333
334
335 bool Parser::good() const
336 {
337         return pos_ < tokens_.size();
338 }
339
340
341 char Parser::getChar()
342 {
343         if (!good())
344                 lyxerr << "The input stream is not well..." << endl;
345         return tokens_[pos_++].character();
346 }
347
348
349 string Parser::getArg(char lf, char rg)
350 {
351         string result;
352         char c = getChar();
353
354         if (c != lf)  
355                 putback();
356         else 
357                 while ((c = getChar()) != rg && good())
358                         result += c;
359
360         return result;
361 }
362
363
364 void Parser::tokenize(istream & is)
365 {
366         // eat everything up to the next \end_inset or end of stream
367         // and store it in s for further tokenization
368         string s;
369         char c;
370         while (is.get(c)) {
371                 s += c;
372                 if (s.size() >= 10 && s.substr(s.size() - 10) == "\\end_inset") {
373                         s = s.substr(0, s.size() - 10);
374                         break;
375                 }
376         }
377
378         // tokenize buffer
379         tokenize(s);
380 }
381
382
383 void Parser::tokenize(string const & buffer)
384 {
385         static bool init_done = false;
386         
387         if (!init_done) {
388                 catInit();
389                 init_done = true;
390         }
391
392         istringstream is(buffer, ios::in || ios::binary);
393
394         char c;
395         while (is.get(c)) {
396
397                 switch (catcode(c)) {
398                         case catNewline: {
399                                 ++lineno_; 
400                                 is.get(c);
401                                 if (catcode(c) == catNewline)
402                                         ; //push_back(Token("par"));
403                                 else {
404                                         push_back(Token(' ',catSpace));
405                                         is.putback(c);  
406                                 }
407                                 break;
408                         }
409
410                         case catComment: {
411                                 while (is.get(c) && catcode(c) != catNewline)
412                                         ;
413                                 ++lineno_; 
414                                 break;
415                         }
416
417                         case catEscape: {
418                                 is.get(c);
419                                 string s(1, c);
420                                 if (catcode(c) == catLetter) {
421                                         while (is.get(c) && catcode(c) == catLetter)
422                                                 s += c;
423                                         if (catcode(c) == catSpace)
424                                                 while (is.get(c) && catcode(c) == catSpace)
425                                                         ;
426                                         is.putback(c);
427                                 }       
428                                 push_back(Token(s));
429                                 break;
430                         }
431
432                         default:
433                                 push_back(Token(c, catcode(c)));
434                 }
435         }
436
437         //lyxerr << "\nTokens: ";
438         //for (unsigned i = 0; i < tokens_.size(); ++i)
439         //      lyxerr << tokens_[i];
440         //lyxerr << "\n";
441 }
442
443
444 void Parser::error(string const & msg) 
445 {
446         lyxerr << "Line ~" << lineno_ << ": Math parse error: " << msg << endl;
447 }
448
449
450 void Parser::parse_lines(MathGridInset * p, bool numbered, bool outmost)
451 {
452         const int cols = p->ncols();
453
454         // save global variables
455         bool   const saved_num   = curr_num_;
456         string const saved_label = curr_label_;
457
458         for (int row = 0; true; ++row) {
459                 // reset global variables
460                 curr_num_   = numbered;
461                 curr_label_.erase();
462
463                 // reading a row
464                 for (int col = 0; col < cols; ++col) {
465                         //lyxerr << "reading cell " << row << " " << col << "\n";
466                         parse_into(p->cell(col + row * cols), FLAG_BLOCK);
467
468                         // no ampersand
469                         if (prevToken().cat() != catAlign) {
470                                 //lyxerr << "less cells read than normal in row/col: "
471                                 //      << row << " " << col << "\n";
472                                 break;
473                         }
474                 }
475
476                 if (outmost) {
477                         MathMatrixInset * m = static_cast<MathMatrixInset *>(p);
478                         m->numbered(row, curr_num_);
479                         m->label(row, curr_label_);
480                         if (curr_skip_.size()) {
481                                 m->vskip(LyXLength(curr_skip_), row);
482                                 curr_skip_.erase();
483                         }
484                 }
485
486                 // no newline?
487                 if (prevToken() != Token("\\")) {
488                         //lyxerr << "no newline here\n";
489                         break;
490                 }
491
492                 p->appendRow();
493         }
494
495         // restore "global" variables
496         curr_num_   = saved_num;
497         curr_label_ = saved_label;
498 }
499
500
501 MathMacroTemplate * Parser::parse_macro()
502 {
503         while (nextToken().cat() == catSpace)
504                 getToken();
505
506         if (getToken().cs() != "newcommand") {
507                 lyxerr << "\\newcommand expected\n";
508                 return 0;
509         }
510
511         if (getToken().cat() != catBegin) {
512                 lyxerr << "'{' expected\n";
513                 return 0;
514         }
515
516         string name = getToken().cs();
517
518         if (getToken().cat() != catEnd) {
519                 lyxerr << "'}' expected\n";
520                 return 0;
521         }
522
523         string arg  = getArg('[', ']');
524         int    narg = arg.empty() ? 0 : atoi(arg.c_str()); 
525         //lyxerr << "creating macro " << name << " with " << narg <<  "args\n";
526         MathMacroTemplate * p = new MathMacroTemplate(name, narg);
527         parse_into(p->cell(0), FLAG_BRACE | FLAG_BRACE_LAST);
528         return p;
529 }
530
531
532 MathMatrixInset * Parser::parse_normal()
533 {
534         Token const & t = getToken();
535
536         if (t.cat() == catMath || t.cs() == "(") {
537                 MathMatrixInset * p = new MathMatrixInset(LM_OT_SIMPLE);
538                 parse_into(p->cell(0), 0);
539                 return p;
540         }
541
542         if (!t.cs().size()) {
543                 lyxerr << "start of math expected, got '" << t << "'\n";
544                 return 0;
545         }
546
547         string const & cs = t.cs();
548
549         if (cs == "[") {
550                 curr_num_ = 0;
551                 curr_label_.erase();
552                 MathMatrixInset * p = new MathMatrixInset(LM_OT_EQUATION);
553                 parse_into(p->cell(0), 0);
554                 p->numbered(0, curr_num_);
555                 p->label(0, curr_label_);
556                 return p;
557         }
558
559         if (cs != "begin") {
560                 lyxerr << "'begin' of un-simple math expected, got '" << cs << "'\n";
561                 return 0;
562         }
563
564         string const name = getArg('{', '}');
565
566         if (name == "equation" || name == "equation*") {
567                 curr_num_ = stared(name);
568                 curr_label_.erase();
569                 MathMatrixInset * p = new MathMatrixInset(LM_OT_EQUATION);
570                 parse_into(p->cell(0), FLAG_END);
571                 p->numbered(0, curr_num_);
572                 p->label(0, curr_label_);
573                 return p;
574         }
575
576         if (name == "eqnarray" || name == "eqnarray*") {
577                 MathMatrixInset * p = new MathMatrixInset(LM_OT_EQNARRAY);
578                 parse_lines(p, stared(name), true);
579                 return p;
580         }
581
582         if (name == "align" || name == "align*") {
583                 MathMatrixInset * p = new MathMatrixInset(LM_OT_ALIGN);
584                 p->halign(getArg('{', '}'));
585                 parse_lines(p, stared(name), true);
586                 return p;
587         }
588
589         if (name == "alignat" || name == "alignat*") {
590                 MathMatrixInset * p = new MathMatrixInset(LM_OT_ALIGNAT);
591                 p->halign(getArg('{', '}'));
592                 parse_lines(p, stared(name), true);
593                 return p;
594         }
595
596         lyxerr[Debug::MATHED] << "1: unknown math environment: " << name << "\n";
597         return 0;
598 }
599
600
601 latexkeys const * Parser::read_delim()
602 {
603         Token const & t = getToken();
604         latexkeys const * l = in_word_set(t.asString());
605         return l ? l : in_word_set(".");
606 }
607
608
609 void Parser::parse_into(MathArray & array, unsigned flags)
610 {
611         MathTextCodes yyvarcode = LM_TC_MIN;
612
613         bool panic  = false;
614         int  limits = 0;
615
616         while (good()) {
617                 Token const & t = getToken();
618                 
619                 lyxerr << "t: " << t << " flags: " << flags << "'\n";
620                 //array.dump(lyxerr);
621                 lyxerr << "\n";
622
623                 if (flags & FLAG_ITEM) {
624                         flags &= ~FLAG_ITEM;
625                         if (t.cat() == catBegin) { 
626                                 // skip the brace and collect everything to the next matching
627                                 // closing brace
628                                 flags |= FLAG_BRACE_LAST;
629                                 continue;
630                         } else {
631                                 // handle only this single token, leave the loop if done
632                                 flags |= FLAG_LEAVE;
633                         }
634                 }
635
636                 if (flags & FLAG_BRACE) {
637                         if (t.cat() != catBegin) {
638                                 error("Expected {. Maybe you forgot to enclose an argument in {}");
639                                 panic = true;
640                                 break;
641                         } else {
642                                 flags &= ~FLAG_BRACE;
643                                 continue;
644                         }
645                 }
646
647                 if (flags & FLAG_BLOCK) {
648                         if (t.cat() == catEnd || t.cat() == catAlign || t.cs() == "\\")
649                                 return;
650                         if (t.cs() == "end") {
651                                 getArg('{', '}');
652                                 return;
653                         }
654                 }
655
656                 //
657                 // cat codes
658                 //
659                 if (t.cat() == catMath)
660                         break;
661
662                 else if (t.cat() == catLetter)
663                         array.push_back(new MathCharInset(t.character(), yyvarcode));
664
665                 else if (t.cat() == catSpace && yyvarcode == LM_TC_TEXTRM)
666                         array.push_back(new MathCharInset(' ', yyvarcode));
667
668                 else if (t.cat() == catParameter) {
669                         Token const & n = getToken();
670                         MathMacroArgument * p = new MathMacroArgument(n.character() - '0');
671                         array.push_back(p);
672                 }
673
674                 else if (t.cat() == catBegin) {
675                         //lyxerr << " creating ScopeInset\n";
676                         array.push_back(new MathScopeInset);
677                         parse_into(array.back()->cell(0), FLAG_BRACE_LAST);
678                 }
679
680                 else if (t.cat() == catEnd) {
681                         if (!(flags & FLAG_BRACE_LAST))
682                                 lyxerr << " ##### unexpected end of block\n";
683                         return;
684                 }
685                 
686                 else if (t.cat() == catAlign) {
687                         lyxerr << "found tab unexpectedly, array: '" << array << "'\n";
688                         return;
689                 }
690                 
691                 else if (t.cat() == catSuper)
692                         parse_into(lastScriptInset(array, true, limits)->cell(0), FLAG_ITEM);
693                 
694                 else if (t.cat() == catSub)
695                         parse_into(lastScriptInset(array, false, limits)->cell(1), FLAG_ITEM);
696                 
697                 else if (t.character() == ']' && (flags & FLAG_BRACK_END))
698                         return;
699
700                 else if (t.cat() == catOther)
701                         array.push_back(new MathCharInset(t.character(), yyvarcode));
702                 
703                 //
704                 // codesequences
705                 //      
706                 else if (t.cs() == "protect") 
707                         ;
708
709                 else if (t.cs() == "end")
710                         break;
711
712                 else if (t.cs() == ")")
713                         break;
714
715                 else if (t.cs() == "]")
716                         break;
717
718                 else if (t.cs() == "\\") {
719                         curr_skip_ = getArg('[', ']');
720                         if (!(flags & FLAG_NEWLINE))
721                                 lyxerr[Debug::MATHED]
722                                         << "found newline unexpectedly, array: '" << array << "'\n";
723                         return;
724                 }
725         
726                 else if (t.cs() == "limits") 
727                         limits = 1;
728                 
729                 else if (t.cs() == "nolimits") 
730                         limits = -1;
731                 
732                 else if (t.cs() == "nonumber")
733                         curr_num_ = false;
734
735                 else if (t.cs() == "number")
736                         curr_num_ = true;
737
738                 else if (t.cs() == "sqrt") {
739                         char c = getChar();
740                         if (c == '[') {
741                                 array.push_back(new MathRootInset);
742                                 parse_into(array.back()->cell(0), FLAG_BRACK_END);
743                                 parse_into(array.back()->cell(1), FLAG_ITEM);
744                         } else {
745                                 putback();
746                                 array.push_back(new MathSqrtInset);
747                                 parse_into(array.back()->cell(0), FLAG_ITEM);
748                         }
749                 }
750                 
751                 else if (t.cs() == "left") {
752                         latexkeys const * l = read_delim();
753                         MathArray ar;
754                         parse_into(ar, FLAG_RIGHT);
755                         latexkeys const * r = read_delim();
756                         MathDelimInset * dl = new MathDelimInset(l, r);
757                         dl->cell(0) = ar;
758                         array.push_back(dl);
759                 }
760                 
761                 else if (t.cs() == "right") {
762                         if (!(flags & FLAG_RIGHT))
763                                 error("Unmatched right delimiter");
764                         return;
765                 }
766
767 /*              
768                 case LM_TK_STY:
769                 {
770                         lyxerr[Debug::MATHED] << "LM_TK_STY not implemented\n";
771                         //MathArray tmp = array;
772                         //MathSizeInset * p = new MathSizeInset(MathStyles(lval_->id));
773                         //array.push_back(p);
774                         //parse_into(p->cell(0), FLAG_BRACE_FONT);
775                         break; 
776                 }
777
778                 case LM_TK_UNDEF: 
779                         if (MathMacroTable::hasTemplate(sval_)) {
780                                 MathMacro * m = MathMacroTable::cloneTemplate(sval_);
781                                 for (int i = 0; i < m->nargs(); ++i) 
782                                         parse_into(m->cell(i), FLAG_ITEM);
783                                 array.push_back(m);
784                                 m->metrics(LM_ST_TEXT);
785                         } else
786                                 array.push_back(new MathFuncInset(sval_));
787                         break;
788
789                 else  LM_TK_SPECIAL:
790                         array.push_back(new MathCharInset(ival_, LM_TC_SPECIAL));
791                         break;
792 */
793                 
794                 else if (t.cs() == "begin") {
795                         string const name = getArg('{', '}');   
796                         if (name == "array") {
797                                 string const valign = getArg('[', ']') + 'c';
798                                 string const halign = getArg('{', '}');
799                                 MathArrayInset * m = new MathArrayInset(halign.size(), 1);
800                                 m->valign(valign[0]);
801                                 m->halign(halign);
802                                 parse_lines(m, false, false);
803                                 array.push_back(m);
804                         } else 
805                                 lyxerr[Debug::MATHED] << "unknow math inset begin '" << name << "'\n";  
806                 }
807         
808                 else if (t.cs() == "label") {
809                         MathArray ar;
810                         parse_into(ar, FLAG_ITEM);
811                         ostringstream os;
812                         ar.write(os, true);
813                         curr_label_ = os.str();
814                         // was: 
815                         //curr_label_ = getArg('{', '}');
816                 }
817
818                 else if (t.cs() == "choose" || t.cs() == "over") {
819                         limits = 0;
820                         MathInset * p = createMathInset(t.cs());
821                         p->cell(0).swap(array);
822                         array.push_back(p);
823                         parse_into(p->cell(1), FLAG_BLOCK);
824                 }
825         
826                 else if (t.cs().size()) {
827                         limits = 0;
828                         latexkeys const * l = in_word_set(t.cs());
829                         if (l) {
830                                 if (l->token == LM_TK_FONT) {
831                                         //lyxerr << "starting font\n";
832                                         MathArray ar;
833                                         parse_into(ar, FLAG_ITEM);
834                                         for (MathArray::iterator it = ar.begin(); it != ar.end(); ++it)
835                                                 (*it)->handleFont(static_cast<MathTextCodes>(l->id));
836                                         array.push_back(ar);
837                                         //lyxerr << "ending font\n";
838                                 }
839
840                                 else if (l->token == LM_TK_OLDFONT)
841                                         yyvarcode = static_cast<MathTextCodes>(l->id);
842
843                                 else {
844                                         MathInset * p = createMathInset(t.cs());
845                                         for (int i = 0; i < p->nargs(); ++i) 
846                                                 parse_into(p->cell(i), FLAG_ITEM);
847                                         array.push_back(p);
848                                 }
849                         }
850
851                         else {
852                                 MathInset * p = createMathInset(t.cs());
853                                 if (p) {
854                                         for (int i = 0; i < p->nargs(); ++i)
855                                                 parse_into(p->cell(i), FLAG_ITEM);
856                                         array.push_back(p);
857                                 } else {
858                                         error("Unrecognized token");
859                                         //lyxerr[Debug::MATHED] << "[" << t << "]\n";
860                                         lyxerr << t << "\n";
861                                 }       
862                         }
863                 }
864
865
866                 if (flags & FLAG_LEAVE) {
867                         flags &= ~FLAG_LEAVE;
868                         break;
869                 }
870         }
871
872         if (panic) {
873                 lyxerr << " Math Panic, expect problems!\n";
874                 //   Search for the end command. 
875                 Token t;
876                 do {
877                         t = getToken();
878                 } while (good() && t.cs() != "end");
879         }
880 }
881
882 } // anonymous namespace
883
884
885
886 MathArray mathed_parse_cell(string const & str)
887 {
888         istringstream is(str.c_str());
889         Parser parser(is);
890         MathArray ar;
891         parser.parse_into(ar, 0);
892         return ar;
893 }
894
895
896
897 MathMacroTemplate * mathed_parse_macro(string const & str)
898 {
899         istringstream is(str.c_str());
900         Parser parser(is);
901         return parser.parse_macro();
902 }
903
904 MathMacroTemplate * mathed_parse_macro(istream & is)
905 {
906         Parser parser(is);
907         return parser.parse_macro();
908 }
909
910 MathMacroTemplate * mathed_parse_macro(LyXLex & lex)
911 {
912         Parser parser(lex);
913         return parser.parse_macro();
914 }
915
916
917
918 MathMatrixInset * mathed_parse_normal(string const & str)
919 {
920         istringstream is(str.c_str());
921         Parser parser(is);
922         return parser.parse_normal();
923 }
924
925 MathMatrixInset * mathed_parse_normal(istream & is)
926 {
927         Parser parser(is);
928         return parser.parse_normal();
929 }
930
931 MathMatrixInset * mathed_parse_normal(LyXLex & lex)
932 {
933         Parser parser(lex);
934         return parser.parse_normal();
935 }