]> git.lyx.org Git - lyx.git/blob - src/mathed/math_parser.C
small step to a unified parser for file & interactive input
[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 MathScriptInset * prevScriptInset(MathArray const & array)
55 {
56         MathInset * p = array.back();
57         return (p && p->isScriptInset()) ? static_cast<MathScriptInset *>(p) : 0;
58 }
59
60
61 MathInset * lastScriptInset(MathArray & array, bool up, bool down, int limits)
62 {
63         MathScriptInset * p = prevScriptInset(array);
64         if (!p) {
65                 MathInset * b = array.back();
66                 if (b && b->isScriptable()) {
67                         p = new MathScriptInset(up, down, b->clone());
68                         array.pop_back();       
69                 } else {
70                         p = new MathScriptInset(up, down);
71                 }
72                 array.push_back(p);
73         }
74         if (up)
75                 p->up(true);
76         if (down)
77                 p->down(down);
78         if (limits)
79                 p->limits(limits);
80         return p;
81 }
82
83
84 // These are lexical codes, not semantic
85 enum lexcode_enum {
86         LexESC,
87         LexAlpha,
88         LexBOP,         // Binary operators or relations
89         LexComment,
90         LexArgument,
91         LexSpace,
92         LexNewLine,
93         LexOther,
94         LexMath,
95         LexSelf
96 };
97
98 lexcode_enum lexcode[256];  
99
100
101 const unsigned char LM_TK_OPEN  = '{';
102
103 enum {
104         FLAG_BRACE      = 1 << 0,  //  an opening brace needed
105         FLAG_BRACE_LAST = 1 << 1,  //  last closing brace ends the parsing process
106         FLAG_RIGHT      = 1 << 2,  //  next right ends the parsing process
107         FLAG_END        = 1 << 3,  //  next end ends the parsing process
108         FLAG_BRACK_END  = 1 << 4,  //  next closing bracket ends the parsing process
109         FLAG_AMPERSAND  = 1 << 5,  //  next & ends the parsing process
110         FLAG_NEWLINE    = 1 << 6,  //  next \\ ends the parsing process
111         FLAG_ITEM       = 1 << 7,  //  read a (possibly braced token)
112         FLAG_BLOCK      = 1 << 8,  //  next block ends the parsing process
113         FLAG_LEAVE      = 1 << 9,  //  marker for leaving the 
114 };
115
116
117 struct latex_mathenv_type {
118         char const *      name;
119         char const *      basename;
120         MathInsetTypes    typ;
121         bool              numbered;
122         bool              ams;
123 };
124
125 latex_mathenv_type latex_mathenv[] = { 
126         {"math",         "math",         LM_OT_SIMPLE,   0, 0},
127         {"equation*",    "equation",     LM_OT_EQUATION, 0, 0},
128         {"equation",     "equation",     LM_OT_EQUATION, 1, 0},
129         {"eqnarray*",    "eqnarray",     LM_OT_EQNARRAY, 0, 0},
130         {"eqnarray",     "eqnarray",     LM_OT_EQNARRAY, 1, 0},
131         {"align*",       "align",        LM_OT_ALIGN,    0, 1},
132         {"align",        "align",        LM_OT_ALIGN,    1, 1},
133         {"alignat*",     "alignat",      LM_OT_ALIGNAT,  0, 1},
134         {"alignat",      "alignat",      LM_OT_ALIGNAT,  1, 1},
135         {"multline*",    "multline",     LM_OT_MULTLINE, 0, 1},
136         {"multline",     "multline",     LM_OT_MULTLINE, 1, 1},
137         {"array",        "array",        LM_OT_MATRIX,   0, 1}
138 };
139
140 int const latex_mathenv_num = sizeof(latex_mathenv)/sizeof(latex_mathenv[0]);
141
142
143
144 void lexInit()
145 {
146         for (int i = 0; i <= 255; ++i) {
147                 if (isdigit(i))
148                         lexcode[i] = LexOther;
149                 else if (isspace(i))
150                         lexcode[i] = LexSpace;
151                 else
152                         lexcode[i] = LexAlpha;
153         }
154         
155         lexcode['\t'] = lexcode['\f'] = lexcode[' '] = LexSpace;
156         lexcode['\n'] = LexNewLine;
157         lexcode['%'] = LexComment;
158         lexcode['#'] = LexArgument;
159         lexcode['$'] = LexMath;
160         lexcode['+'] = lexcode['-'] = lexcode['*'] = lexcode['/']
161                 = lexcode['<'] = lexcode['>'] = lexcode['='] = LexBOP;
162         
163         lexcode['('] = lexcode[')'] = lexcode['|'] = lexcode['.'] =
164                 lexcode['?'] = LexOther; 
165         
166         lexcode['\''] = lexcode['@'] = LexAlpha;
167         
168         lexcode['['] = lexcode[']'] = lexcode['^'] = lexcode['_'] = 
169                 lexcode['&'] = LexSelf;  
170         
171         lexcode['{'] = LexSelf;
172         lexcode['}'] = LexSelf;
173
174         lexcode['\\'] = LexESC;
175 }
176
177
178
179 //
180 // Helper class for parsing
181 //
182
183
184 class Parser {
185 public:
186         ///
187         Parser(LyXLex & lex) : is_(lex.getStream()), lineno_(lex.getLineNo()) {}
188         ///
189         Parser(istream & is) : is_(is), lineno_(0) {}
190
191         ///
192         MathMacroTemplate * parse_macro();
193         ///
194         MathMatrixInset * parse_normal();
195         ///
196         void parse_into(MathArray & array, unsigned flags);
197         ///
198         int lineno() const { return lineno_; }
199
200 private:
201         ///
202         int yylex();
203         ///
204         string lexArg(unsigned char lf, bool accept_spaces = false);
205         ///
206         unsigned char getuchar();
207         ///
208         void error(string const & msg);
209         ///
210         void parse_lines(MathGridInset * p, int col, bool numbered, bool outmost);
211         ///
212         latexkeys const * read_delim();
213
214 private:
215         ///
216         istream & is_;
217         ///
218         int lineno_;
219
220         ///
221         int ival_;
222         ///
223         latexkeys const * lval_;
224         ///
225         string sval_;
226
227         ///
228         bool   curr_num_;
229         ///
230         string curr_label_;
231         ///
232         string curr_skip_;
233 };
234
235
236 unsigned char Parser::getuchar()
237 {
238         char c = 0;
239         if (!is_.good())
240                 lyxerr << "The input stream is not well..." << endl;
241         is_.get(c);
242         return static_cast<unsigned char>(c);
243 }
244
245
246 string Parser::lexArg(unsigned char lf, bool accept_spaces = false)
247 {
248         string result;
249         unsigned char c = 0;
250         while (is_.good()) {
251                 c = getuchar();
252                 if (!isspace(c))
253                         break;
254         }
255
256         if (c != lf) {
257                 is_.putback(c);
258                 return result;
259         }
260                 
261         unsigned char rg = 0;
262         if (lf == '{') rg = '}';
263         if (lf == '[') rg = ']';
264         if (lf == '(') rg = ')';
265         if (!rg) {
266                 lyxerr[Debug::MATHED] << "Math parse error: unknown bracket '"
267                         << lf << "'" << endl;
268                 return result;
269         }
270
271         int depth = 1;
272         do {
273                 unsigned char c = getuchar();
274                 if (c == lf)
275                         ++depth;
276                 if (c == rg)
277                         --depth;
278                 if ((!isspace(c) || (c == ' ' && accept_spaces)) && depth > 0)
279                         result += c;
280         } while (depth > 0 && is_.good());
281
282         return result;
283 }
284
285
286 int Parser::yylex()
287 {
288         static bool init_done = false;
289         
290         if (!init_done) {
291                 lexInit();
292                 init_done = true;
293         }
294         
295         while (is_.good()) {
296                 unsigned char c = getuchar();
297                 //lyxerr << "reading byte: '" << c << "' code: " << lexcode[c] << endl;
298                 
299                 if (lexcode[c] == LexNewLine) {
300                         ++lineno_; 
301                         continue;
302                 } else if (lexcode[c] == LexComment) {
303                         do {
304                                 c = getuchar();
305                         } while (c != '\n' && is_.good());  // eat comments
306                 } else if (lexcode[c] == LexOther) {
307                         ival_ = c;
308                         return LM_TK_STR;
309                 } else if (lexcode[c] == LexAlpha || lexcode[c] == LexSpace) {
310                         ival_ = c;
311                         return LM_TK_ALPHA;
312                 } else if (lexcode[c] == LexBOP) {
313                         ival_ = c;
314                         return LM_TK_BOP;
315                 } else if (lexcode[c] == LexMath) {
316                         ival_ = 0;
317                         return LM_TK_MATH;
318                 } else if (lexcode[c] == LexSelf) {
319                         return c;
320                 } else if (lexcode[c] == LexArgument) {
321                         c = getuchar();
322                         ival_ = c - '0';
323                         return LM_TK_ARGUMENT; 
324                 } else if (lexcode[c] == LexESC)   {
325                         c = getuchar();
326                         //lyxerr << "reading second byte: '" << c << "' code: " << lexcode[c] << endl;
327                         string s;
328                         s += c;
329                         latexkeys const * l = in_word_set(s);
330                         if (l) {
331                                 //lyxerr << "found key: " << l << endl;
332                                 //lyxerr << "found key name: " << l->name << endl;
333                                 //lyxerr << "found key token: " << l->token << endl;
334                                 lval_ = l;
335                                 ival_ = l->id;
336                                 return l->token;
337                         }
338                         if (lexcode[c] == LexAlpha) {
339                                 sval_.erase();
340                                 while (lexcode[c] == LexAlpha && is_.good()) {
341                                         sval_ += c;
342                                         c = getuchar();
343                                 }
344                                 while (lexcode[c] == LexSpace && is_.good()) 
345                                         c = getuchar();
346                                 if (lexcode[c] != LexSpace)
347                                         is_.putback(c);
348                         
349                                 //lyxerr[Debug::MATHED] << "reading: text '" << sval_ << "'\n";
350                                 //lyxerr << "reading: text '" << sval_ << "'\n";
351                                 lval_ = in_word_set(sval_);
352                                 if (!lval_) 
353                                         return LM_TK_UNDEF;
354
355                                 if (lval_->token == LM_TK_BEGIN || lval_->token == LM_TK_END) { 
356                                         string name = lexArg('{');
357                                         int i = 0;
358                                         while (i < latex_mathenv_num && name != latex_mathenv[i].name)
359                                                  ++i;
360                                         ival_ = i;
361                                 }
362                                 return lval_->token;
363                         }
364                 }
365         }
366         return 0;
367 }
368
369
370 void Parser::error(string const & msg) 
371 {
372         lyxerr << "Line ~" << lineno_ << ": Math parse error: " << msg << endl;
373 }
374
375
376 void Parser::parse_lines(MathGridInset * p, int col, bool numbered, bool outmost)
377 {
378         // save global variables
379         bool   const saved_num   = curr_num_;
380         string const saved_label = curr_label_;
381
382         for (int row = 0; true; ++row) {
383                 // reset global variables
384                 curr_num_   = numbered;
385                 curr_label_.erase();
386
387                 // reading a row
388                 int idx = p->nargs() - p->ncols();
389                 for (int i = 0; i < col - 1; ++i, ++idx)
390                         parse_into(p->cell(idx), FLAG_AMPERSAND);
391                 parse_into(p->cell(idx), FLAG_NEWLINE | FLAG_END);
392
393                 if (outmost) {
394                         MathMatrixInset * m = static_cast<MathMatrixInset *>(p);
395                         m->numbered(row, curr_num_);
396                         m->label(row, curr_label_);
397                         if (curr_skip_.size()) {
398                                 m->vskip(LyXLength(curr_skip_), row);
399                                 curr_skip_.erase();
400                         }
401                 }
402
403 #ifdef WITH_WARNINGS
404 #warning Hack!
405 #endif
406                 // no newline
407                 if (ival_ != -1)
408                         break;
409
410                 p->appendRow();
411         }
412
413         // restore "global" variables
414         curr_num_   = saved_num;
415         curr_label_ = saved_label;
416 }
417
418
419 MathMacroTemplate * Parser::parse_macro()
420 {
421         if (yylex() != LM_TK_NEWCOMMAND) {
422                 lyxerr << "\\newcommand expected\n";
423                 return 0;
424         }
425
426         string name = lexArg('{').substr(1);
427         string arg  = lexArg('[');
428         int    narg = arg.empty() ? 0 : atoi(arg.c_str()); 
429         MathMacroTemplate * p = new MathMacroTemplate(name, narg);
430         parse_into(p->cell(0), FLAG_BRACE | FLAG_BRACE_LAST);
431         return p;
432 }
433
434
435 MathMatrixInset * Parser::parse_normal()
436 {
437         MathMatrixInset * p = 0;
438         int t = yylex();
439
440         switch (t) {
441                 case LM_TK_MATH:
442                 case LM_TK_BEGIN: {
443                         int i = ival_;
444                         lyxerr[Debug::MATHED]
445                                 << "reading math environment " << i << " "
446                                 << latex_mathenv[i].name << "\n";
447
448                         MathInsetTypes typ = latex_mathenv[i].typ;
449                         p = new MathMatrixInset(typ);
450
451                         switch (typ) {
452
453                                 case LM_OT_SIMPLE: {
454                                         curr_num_ = latex_mathenv[i].numbered;
455                                         curr_label_.erase();
456                                         parse_into(p->cell(0), 0);
457                                         p->numbered(0, curr_num_);
458                                         p->label(0, curr_label_);
459                                         break;
460                                 }
461
462                                 case LM_OT_EQUATION: {
463                                         curr_num_ = latex_mathenv[i].numbered;
464                                         curr_label_.erase();
465                                         parse_into(p->cell(0), FLAG_END);
466                                         p->numbered(0, curr_num_);
467                                         p->label(0, curr_label_);
468                                         break;
469                                 }
470
471                                 case LM_OT_EQNARRAY: {
472                                         parse_lines(p, 3, latex_mathenv[i].numbered, true);
473                                         break;
474                                 }
475
476                                 case LM_OT_ALIGN: {
477                                         p->halign(lexArg('{'));
478                                         parse_lines(p, 2, latex_mathenv[i].numbered, true);
479                                         break;
480                                 }
481
482                                 case LM_OT_ALIGNAT: {
483                                         p->halign(lexArg('{'));
484                                         parse_lines(p, 2, latex_mathenv[i].numbered, true);
485                                         break;
486                                 }
487
488                                 default: 
489                                         lyxerr[Debug::MATHED]
490                                                 << "1: unknown math environment: " << typ << "\n";
491                         }
492
493                         break;
494                 }
495                 
496                 default:
497                         lyxerr[Debug::MATHED]
498                                 << "2 unknown math environment: " << t << "\n";
499         }
500
501         return p;
502 }
503
504
505 latexkeys const * Parser::read_delim()
506 {
507         int ld = yylex();
508         //lyxerr << "found symbol: " << ld << "\n";
509         latexkeys const * l = in_word_set(".");
510         switch (ld) {
511                 case LM_TK_SYM:
512                 case LM_TK_NOGLYPH:
513                 case LM_TK_SPECIAL:
514                 case LM_TK_BEGIN: {
515                         l = lval_;
516                         //lyxerr << "found key 1: '" << l << "'\n";
517                         //lyxerr << "found key 1: '" << l->name << "'\n";
518                         break;
519                 }
520                 case ']':
521                 case '[': {
522                         string s;
523                         s += ld;
524                         l = in_word_set(s);
525                         //lyxerr << "found key 2: '" << l->name << "'\n";
526                         break;
527                 }
528                 case LM_TK_STR: {
529                         string s;
530                         s += ival_;
531                         l = in_word_set(s);
532                         //lyxerr << "found key 2: '" << l->name << "'\n";
533                 }
534         }
535         return l;
536 }
537
538
539 void Parser::parse_into(MathArray & array, unsigned flags)
540 {
541         MathTextCodes yyvarcode   = LM_TC_VAR;
542
543         int  t      = yylex();
544         bool panic  = false;
545         int  limits = 0;
546
547         while (t) {
548                 //lyxerr << "t: " << t << " flags: " << flags << " i: " << ival_
549                 //      << " '" << sval_ << "'\n";
550                 //array.dump(lyxerr);
551                 //lyxerr << "\n";
552
553                 if (flags & FLAG_ITEM) {
554                         flags &= ~FLAG_ITEM;
555                         if (t == LM_TK_OPEN) { 
556                                 // skip the brace and collect everything to the next matching
557                                 // closing brace
558                                 flags |= FLAG_BRACE_LAST;
559                                 t = yylex();
560                         } else {
561                                 // take only this single token
562                                 flags |= FLAG_LEAVE;
563                         }
564                 }
565
566                 if (flags & FLAG_BRACE) {
567                         if (t != LM_TK_OPEN) {
568                                 error("Expected {. Maybe you forgot to enclose an argument in {}");
569                                 panic = true;
570                                 break;
571                         } else {
572                                 flags &= ~FLAG_BRACE;
573                                 t = yylex();
574                                 continue;
575                         }
576                 }
577
578                 switch (t) {
579                         
580                 case LM_TK_MATH:
581                 case LM_TK_END:
582                         return;
583
584                 case LM_TK_ALPHA:
585                         if (!isspace(ival_) || yyvarcode == LM_TC_TEXTRM)
586                                 array.push_back(new MathCharInset(ival_, yyvarcode));
587                         break;
588
589                 case LM_TK_ARGUMENT: {
590                         MathMacroArgument * p = new MathMacroArgument(ival_);
591                         //p->code(yyvarcode);
592                         array.push_back(p);
593                         break;
594                 }
595
596                 case LM_TK_SPECIAL:
597                         array.push_back(new MathCharInset(ival_, LM_TC_SPECIAL));
598                         break;
599
600                 case LM_TK_STR:
601                         array.push_back(new MathCharInset(ival_, LM_TC_CONST));
602                         break;
603
604                 case '{':
605                         //lyxerr << " creating ScopeInset\n";
606                         array.push_back(new MathScopeInset);
607                         parse_into(array.back()->cell(0), FLAG_BRACE_LAST);
608                         break;
609
610                 case '}':
611                         if (flags & FLAG_BRACE_LAST)
612                                 flags |= FLAG_LEAVE;
613                         break;
614                 
615                 case '[':
616                         array.push_back(new MathCharInset('[', LM_TC_CONST));
617                         break;
618
619                 case ']':
620                         if (flags & FLAG_BRACK_END)
621                                 flags |= FLAG_LEAVE;
622                         else 
623                                 array.push_back(new MathCharInset(']', LM_TC_CONST));
624                         break;
625                 
626                 case '^':
627                         parse_into(
628                                 lastScriptInset(array, true, false, limits)->cell(0), FLAG_ITEM);
629                         break;
630                 
631                 case '_':
632                         parse_into(
633                                 lastScriptInset(array, false, true, limits)->cell(1), FLAG_ITEM);
634                         break;
635                 
636                 case LM_TK_LIMIT:
637                         limits = lval_->id;
638                         //lyxerr << "setting limit to " << limits << "\n";
639                         break;
640                 
641                 case '&':
642                         if (flags & FLAG_AMPERSAND) {
643                                 flags &= ~FLAG_AMPERSAND;
644                                 return;
645                         }
646                         lyxerr[Debug::MATHED]
647                                 << "found tab unexpectedly, array: '" << array << "'\n";
648                         break;
649                 
650                 case LM_TK_NEWLINE:
651                 {
652                         curr_skip_ = lexArg('[');
653                         if (flags & FLAG_NEWLINE) {
654                                 flags &= ~FLAG_NEWLINE;
655                                 return;
656                         }
657                         lyxerr[Debug::MATHED]
658                                 << "found newline unexpectedly, array: '" << array << "'\n";
659                         break;
660                 }
661                 
662                 case LM_TK_PROTECT: 
663                         break;
664
665                 case LM_TK_BOP:
666                         array.push_back(new MathCharInset(ival_, LM_TC_BOP));
667                         break;
668
669                 case LM_TK_SQRT:
670                 {
671                         unsigned char c = getuchar();
672                         if (c == '[') {
673                                 array.push_back(new MathRootInset);
674                                 parse_into(array.back()->cell(0), FLAG_BRACK_END);
675                                 parse_into(array.back()->cell(1), FLAG_ITEM);
676                         } else {
677                                 is_.putback(c);
678                                 array.push_back(new MathSqrtInset);
679                                 parse_into(array.back()->cell(0), FLAG_ITEM);
680                         }
681                         break;
682                 }
683                 
684                 case LM_TK_LEFT:
685                 {
686                         latexkeys const * l = read_delim();
687                         MathArray ar;
688                         parse_into(ar, FLAG_RIGHT);
689                         latexkeys const * r = read_delim();
690                         MathDelimInset * dl = new MathDelimInset(l, r);
691                         dl->cell(0) = ar;
692                         array.push_back(dl);
693                         break;
694                 }
695                 
696                 case LM_TK_RIGHT:
697                         if (flags & FLAG_RIGHT)
698                                 return;
699                         error("Unmatched right delimiter");
700 //        panic = true;
701                         break;
702                 
703                 case LM_TK_FONT:
704                 {
705                         MathTextCodes t = static_cast<MathTextCodes>(lval_->id);
706                         MathArray ar;
707                         parse_into(ar, FLAG_ITEM);
708                         for (MathArray::iterator it = ar.begin(); it != ar.end(); ++it)
709                                 (*it)->handleFont(t);
710                         array.push_back(ar);
711                         break;
712                 }
713
714                 case LM_TK_OLDFONT:
715                         yyvarcode = static_cast<MathTextCodes>(lval_->id);
716                         break;
717
718                 case LM_TK_STY:
719                 {
720                         lyxerr[Debug::MATHED] << "LM_TK_STY not implemented\n";
721                         //MathArray tmp = array;
722                         //MathSizeInset * p = new MathSizeInset(MathStyles(lval_->id));
723                         //array.push_back(p);
724                         //parse_into(p->cell(0), FLAG_BRACE_FONT);
725                         break; 
726                 }
727
728                 case LM_TK_NONUM:
729                         curr_num_ = false;
730                         break;
731                 
732                 case LM_TK_UNDEF: 
733                         if (MathMacroTable::hasTemplate(sval_)) {
734                                 MathMacro * m = MathMacroTable::cloneTemplate(sval_);
735                                 for (int i = 0; i < m->nargs(); ++i) 
736                                         parse_into(m->cell(i), FLAG_ITEM);
737                                 array.push_back(m);
738                                 m->metrics(LM_ST_TEXT);
739                         } else
740                                 array.push_back(new MathFuncInset(sval_));
741                         break;
742                 
743                 case LM_TK_BEGIN:
744                 {
745                         int i = ival_;
746                         MathInsetTypes typ = latex_mathenv[i].typ;
747
748                         if (typ == LM_OT_MATRIX) {
749                                 string const valign = lexArg('[') + 'c';
750                                 string const halign = lexArg('{');
751                                 //lyxerr << "valign: '" << valign << "'\n";
752                                 //lyxerr << "halign: '" << halign << "'\n";
753                                 MathArrayInset * m = new MathArrayInset(halign.size(), 1);
754                                 m->valign(valign[0]);
755                                 m->halign(halign);
756
757                                 parse_lines(m, halign.size(), latex_mathenv[i].numbered, false);
758                                 array.push_back(m);
759                                 //lyxerr << "read matrix " << *m << "\n";       
760                                 break;
761                         } else 
762                                 lyxerr[Debug::MATHED] << "unknow math inset " << typ << "\n";   
763                         break;
764                 }
765         
766                 case LM_TK_LABEL:
767                         curr_label_ = lexArg('{', true);
768                         break;
769
770                 case LM_TK_OVER:
771                 {
772                         MathArray ar;
773                         parse_into(ar, FLAG_BLOCK);
774                         break;
775                 }
776                 
777                 default:
778                         limits = 0;
779                         MathInset * p = createMathInset(lval_);
780                         if (p) {
781                                 for (int i = 0; i < p->nargs(); ++i)
782                                         parse_into(p->cell(i), FLAG_ITEM);
783                                 array.push_back(p);
784                         } else {
785                                 error("Unrecognized token");
786                                 //lyxerr[Debug::MATHED] << "[" << t << " " << sval_ << "]\n";
787                                 lyxerr << "[" << t << " " << sval_ << "]\n";
788                         }
789
790                 } // end of big switch
791
792                 if (flags & FLAG_LEAVE) {
793                         flags &= ~FLAG_LEAVE;
794                         break;
795                 }
796
797                 if (panic) {
798                         lyxerr << " Math Panic, expect problems!\n";
799                         //   Search for the end command. 
800                         do {
801                                 t = yylex();
802                         } while (is_.good() && t != LM_TK_END && t);
803                 } else {
804                         t = yylex();
805                 }
806         }
807 }
808
809
810 void parse_end(LyXLex & lex, int lineno)
811 {
812         // Update line number
813         lex.setLineNo(lineno);
814
815         // reading of end_inset
816         while (lex.isOK()) {
817                 lex.nextToken();
818                 if (lex.getString() == "\\end_inset")
819                         break;
820                 //lyxerr[Debug::MATHED] << "InsetFormula::Read: Garbage before \\end_inset,"
821                 lyxerr << "InsetFormula::Read: Garbage before \\end_inset,"
822                         " or missing \\end_inset!\n";
823         }
824 }
825
826 } // anonymous namespace
827
828
829
830 MathArray mathed_parse_cell(string const & str)
831 {
832         istringstream is(str.c_str());
833         Parser parser(is);
834         MathArray ar;
835         parser.parse_into(ar, 0);
836         return ar;
837 }
838
839
840
841 MathMacroTemplate * mathed_parse_macro(string const & str)
842 {
843         istringstream is(str.c_str());
844         Parser parser(is);
845         return parser.parse_macro();
846 }
847
848 MathMacroTemplate * mathed_parse_macro(istream & is)
849 {
850         Parser parser(is);
851         return parser.parse_macro();
852 }
853
854 MathMacroTemplate * mathed_parse_macro(LyXLex & lex)
855 {
856         Parser parser(lex);
857         MathMacroTemplate * p = parser.parse_macro();
858         parse_end(lex, parser.lineno());
859         return p;
860 }
861
862
863
864 MathMatrixInset * mathed_parse_normal(string const & str)
865 {
866         istringstream is(str.c_str());
867         Parser parser(is);
868         return parser.parse_normal();
869 }
870
871 MathMatrixInset * mathed_parse_normal(istream & is)
872 {
873         Parser parser(is);
874         return parser.parse_normal();
875 }
876
877 MathMatrixInset * mathed_parse_normal(LyXLex & lex)
878 {
879         Parser parser(lex);
880         MathMatrixInset * p = parser.parse_normal();
881         parse_end(lex, parser.lineno());
882         return p;
883 }