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