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