]> git.lyx.org Git - lyx.git/blob - src/mathed/math_parser.C
re-enabling the "selected text gets converted to math"-feature
[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
320                 //lyxerr << "reading byte: '" << c << "' code: " << lexcode[c] << endl;
321
322                 if (!is_.good())
323                         break;
324                 
325                 if (lexcode[c] == LexNewLine) {
326                         ++lineno_; 
327                         continue;
328                 }
329
330                 if (lexcode[c] == LexComment) {
331                         do {
332                                 c = getuchar();
333                         } while (c != '\n' && is_.good());  // eat comments
334                 }
335
336                 ival_ = c;
337                 if (lexcode[c] == LexOther)
338                         return LM_TK_STR;
339
340                 if (lexcode[c] == LexAlpha || lexcode[c] == LexSpace)
341                         return LM_TK_ALPHA;
342
343                 if (lexcode[c] == LexBOP)
344                         return LM_TK_BOP;
345
346                 if (lexcode[c] == LexMath) {
347                         ival_ = 0;
348                         return LM_TK_MATH;
349                 }
350
351                 if (lexcode[c] == LexSelf)
352                         return c;
353
354                 if (lexcode[c] == LexArgument) {
355                         c = getuchar();
356                         ival_ = c - '0';
357                         return LM_TK_ARGUMENT; 
358                 }
359
360                 if (lexcode[c] == LexESC)   {
361                         c = getuchar();
362                         //lyxerr << "reading second byte: '" << c
363                         // << "' code: " << lexcode[c] << endl;
364                         string s(1, c);
365                         latexkeys const * l = in_word_set(s);
366                         if (l) {
367                                 //lyxerr << "found key: " << l << endl;
368                                 //lyxerr << "found key name: " << l->name << endl;
369                                 //lyxerr << "found key token: " << l->token << endl;
370                                 lval_ = l;
371                                 ival_ = l->id;
372                                 return l->token;
373                         }
374                         if (lexcode[c] == LexAlpha) {
375                                 sval_.erase();
376                                 while (lexcode[c] == LexAlpha && is_.good()) {
377                                         sval_ += c;
378                                         c = getuchar();
379                                 }
380                                 while (lexcode[c] == LexSpace && is_.good()) 
381                                         c = getuchar();
382                                 if (lexcode[c] != LexSpace)
383                                         is_.putback(c);
384                         
385                                 //lyxerr[Debug::MATHED] << "reading: text '" << sval_ << "'\n";
386                                 //lyxerr << "reading: text '" << sval_ << "'\n";
387                                 lval_ = in_word_set(sval_);
388                                 if (!lval_) 
389                                         return LM_TK_UNDEF;
390
391                                 if (lval_->token == LM_TK_BEGIN || lval_->token == LM_TK_END) { 
392                                         string name = lexArg('{');
393                                         int i = 0;
394                                         while (i < latex_mathenv_num && name != latex_mathenv[i].name)
395                                                  ++i;
396                                         ival_ = i;
397                                 }
398                                 return lval_->token;
399                         }
400                 }
401         }
402         return 0;
403 }
404
405
406 void Parser::error(string const & msg) 
407 {
408         lyxerr << "Line ~" << lineno_ << ": Math parse error: " << msg << endl;
409 }
410
411
412 void Parser::parse_lines(MathGridInset * p, int col, bool numbered, bool outmost)
413 {
414         // save global variables
415         bool   const saved_num   = curr_num_;
416         string const saved_label = curr_label_;
417
418         for (int row = 0; true; ++row) {
419                 // reset global variables
420                 curr_num_   = numbered;
421                 curr_label_.erase();
422
423                 // reading a row
424                 int idx = p->nargs() - p->ncols();
425                 for (int i = 0; i < col - 1; ++i, ++idx)
426                         parse_into(p->cell(idx), FLAG_AMPERSAND);
427                 parse_into(p->cell(idx), FLAG_NEWLINE | FLAG_END);
428
429                 if (outmost) {
430                         MathMatrixInset * m = static_cast<MathMatrixInset *>(p);
431                         m->numbered(row, curr_num_);
432                         m->label(row, curr_label_);
433                         if (curr_skip_.size()) {
434                                 m->vskip(LyXLength(curr_skip_), row);
435                                 curr_skip_.erase();
436                         }
437                 }
438
439 #ifdef WITH_WARNINGS
440 #warning Hack!
441 #endif
442                 // no newline
443                 if (ival_ != -1)
444                         break;
445
446                 p->appendRow();
447         }
448
449         // restore "global" variables
450         curr_num_   = saved_num;
451         curr_label_ = saved_label;
452 }
453
454
455 MathMacroTemplate * Parser::parse_macro()
456 {
457         if (yylex() != LM_TK_NEWCOMMAND) {
458                 lyxerr << "\\newcommand expected\n";
459                 return 0;
460         }
461
462         string name = lexArg('{').substr(1);
463         string arg  = lexArg('[');
464         int    narg = arg.empty() ? 0 : atoi(arg.c_str()); 
465         MathMacroTemplate * p = new MathMacroTemplate(name, narg);
466         parse_into(p->cell(0), FLAG_BRACE | FLAG_BRACE_LAST);
467         return p;
468 }
469
470
471 MathMatrixInset * Parser::parse_normal()
472 {
473         MathMatrixInset * p = 0;
474         int t = yylex();
475
476         switch (t) {
477                 case LM_TK_MATH:
478                 case LM_TK_BEGIN: {
479                         int i = ival_;
480                         lyxerr[Debug::MATHED]
481                                 << "reading math environment " << i << " "
482                                 << latex_mathenv[i].name << "\n";
483
484                         MathInsetTypes typ = latex_mathenv[i].typ;
485                         p = new MathMatrixInset(typ);
486
487                         switch (typ) {
488
489                                 case LM_OT_SIMPLE: {
490                                         curr_num_ = latex_mathenv[i].numbered;
491                                         curr_label_.erase();
492                                         parse_into(p->cell(0), 0);
493                                         p->numbered(0, curr_num_);
494                                         p->label(0, curr_label_);
495                                         break;
496                                 }
497
498                                 case LM_OT_EQUATION: {
499                                         curr_num_ = latex_mathenv[i].numbered;
500                                         curr_label_.erase();
501                                         parse_into(p->cell(0), FLAG_END);
502                                         p->numbered(0, curr_num_);
503                                         p->label(0, curr_label_);
504                                         break;
505                                 }
506
507                                 case LM_OT_EQNARRAY: {
508                                         parse_lines(p, 3, latex_mathenv[i].numbered, true);
509                                         break;
510                                 }
511
512                                 case LM_OT_ALIGN: {
513                                         p->halign(lexArg('{'));
514                                         parse_lines(p, 2, latex_mathenv[i].numbered, true);
515                                         break;
516                                 }
517
518                                 case LM_OT_ALIGNAT: {
519                                         p->halign(lexArg('{'));
520                                         parse_lines(p, 2, latex_mathenv[i].numbered, true);
521                                         break;
522                                 }
523
524                                 default: 
525                                         lyxerr[Debug::MATHED]
526                                                 << "1: unknown math environment: " << typ << "\n";
527                         }
528
529                         break;
530                 }
531                 
532                 default:
533                         lyxerr[Debug::MATHED]
534                                 << "2 unknown math environment: " << t << "\n";
535         }
536
537         return p;
538 }
539
540
541 latexkeys const * Parser::read_delim()
542 {
543         int ld = yylex();
544         //lyxerr << "found symbol: " << ld << "\n";
545         latexkeys const * l = in_word_set(".");
546         switch (ld) {
547                 case LM_TK_SYM:
548                 case LM_TK_NOGLYPH:
549                 case LM_TK_SPECIAL:
550                 case LM_TK_BEGIN: {
551                         l = lval_;
552                         //lyxerr << "found key 1: '" << l << "'\n";
553                         //lyxerr << "found key 1: '" << l->name << "'\n";
554                         break;
555                 }
556                 case ']':
557                 case '[': {
558                         string s;
559                         s += ld;
560                         l = in_word_set(s);
561                         //lyxerr << "found key 2: '" << l->name << "'\n";
562                         break;
563                 }
564                 case LM_TK_STR: {
565                         string s;
566                         s += ival_;
567                         l = in_word_set(s);
568                         //lyxerr << "found key 2: '" << l->name << "'\n";
569                 }
570         }
571         return l;
572 }
573
574
575 void Parser::parse_into(MathArray & array, unsigned flags)
576 {
577         MathTextCodes yyvarcode   = LM_TC_VAR;
578
579         bool panic  = false;
580         int  limits = 0;
581
582         while (int t = yylex()) {
583                 
584                 //lyxerr << "t: " << t << " flags: " << flags << " i: " << ival_
585                 //      << " '" << sval_ << "'\n";
586                 //array.dump(lyxerr);
587                 //lyxerr << "\n";
588
589                 if (flags & FLAG_ITEM) {
590                         flags &= ~FLAG_ITEM;
591                         if (t == LM_TK_OPEN) { 
592                                 // skip the brace and collect everything to the next matching
593                                 // closing brace
594                                 flags |= FLAG_BRACE_LAST;
595                                 continue;
596                         } else {
597                                 // handle only this single token, leave the loop if done
598                                 flags |= FLAG_LEAVE;
599                         }
600                 }
601
602                 if (flags & FLAG_BRACE) {
603                         if (t != LM_TK_OPEN) {
604                                 error("Expected {. Maybe you forgot to enclose an argument in {}");
605                                 panic = true;
606                                 break;
607                         } else {
608                                 flags &= ~FLAG_BRACE;
609                                 continue;
610                         }
611                 }
612
613                 if (flags & FLAG_BLOCK) {
614                         if (t == LM_TK_CLOSE || t == '&' || t == LM_TK_NEWLINE || t == LM_TK_END){
615                                 putback(t);
616                                 return;
617                         }
618                 }
619
620
621                 switch (t) {
622                         
623                 case LM_TK_MATH:
624                 case LM_TK_END:
625                         return;
626
627                 case LM_TK_ALPHA:
628                         if (!isspace(ival_) || yyvarcode == LM_TC_TEXTRM)
629                                 array.push_back(new MathCharInset(ival_, yyvarcode));
630                         break;
631
632                 case LM_TK_ARGUMENT: {
633                         MathMacroArgument * p = new MathMacroArgument(ival_);
634                         //p->code(yyvarcode);
635                         array.push_back(p);
636                         break;
637                 }
638
639                 case LM_TK_SPECIAL:
640                         array.push_back(new MathCharInset(ival_, LM_TC_SPECIAL));
641                         break;
642
643                 case LM_TK_STR:
644                         array.push_back(new MathCharInset(ival_, LM_TC_CONST));
645                         break;
646
647                 case '{':
648                         //lyxerr << " creating ScopeInset\n";
649                         array.push_back(new MathScopeInset);
650                         parse_into(array.back()->cell(0), FLAG_BRACE_LAST);
651                         break;
652
653                 case '}':
654                         if (flags & FLAG_BRACE_LAST)
655                                 flags |= FLAG_LEAVE;
656                         break;
657                 
658                 case '[':
659                         array.push_back(new MathCharInset('[', LM_TC_CONST));
660                         break;
661
662                 case ']':
663                         if (flags & FLAG_BRACK_END)
664                                 flags |= FLAG_LEAVE;
665                         else 
666                                 array.push_back(new MathCharInset(']', LM_TC_CONST));
667                         break;
668                 
669                 case '^':
670                         parse_into(
671                                 lastScriptInset(array, true, false, limits)->cell(0), FLAG_ITEM);
672                         break;
673                 
674                 case '_':
675                         parse_into(
676                                 lastScriptInset(array, false, true, limits)->cell(1), FLAG_ITEM);
677                         break;
678                 
679                 case LM_TK_LIMIT:
680                         limits = lval_->id;
681                         //lyxerr << "setting limit to " << limits << "\n";
682                         break;
683                 
684                 case '&':
685                         if (flags & FLAG_AMPERSAND) {
686                                 flags &= ~FLAG_AMPERSAND;
687                                 return;
688                         }
689                         lyxerr[Debug::MATHED]
690                                 << "found tab unexpectedly, array: '" << array << "'\n";
691                         break;
692                 
693                 case LM_TK_NEWLINE:
694                 {
695                         curr_skip_ = lexArg('[');
696                         if (flags & FLAG_NEWLINE) {
697                                 flags &= ~FLAG_NEWLINE;
698                                 return;
699                         }
700                         lyxerr[Debug::MATHED]
701                                 << "found newline unexpectedly, array: '" << array << "'\n";
702                         break;
703                 }
704                 
705                 case LM_TK_PROTECT: 
706                         break;
707
708                 case LM_TK_BOP:
709                         array.push_back(new MathCharInset(ival_, LM_TC_BOP));
710                         break;
711
712                 case LM_TK_SQRT:
713                 {
714                         unsigned char c = getuchar();
715                         if (c == '[') {
716                                 array.push_back(new MathRootInset);
717                                 parse_into(array.back()->cell(0), FLAG_BRACK_END);
718                                 parse_into(array.back()->cell(1), FLAG_ITEM);
719                         } else {
720                                 is_.putback(c);
721                                 array.push_back(new MathSqrtInset);
722                                 parse_into(array.back()->cell(0), FLAG_ITEM);
723                         }
724                         break;
725                 }
726                 
727                 case LM_TK_LEFT:
728                 {
729                         latexkeys const * l = read_delim();
730                         MathArray ar;
731                         parse_into(ar, FLAG_RIGHT);
732                         latexkeys const * r = read_delim();
733                         MathDelimInset * dl = new MathDelimInset(l, r);
734                         dl->cell(0) = ar;
735                         array.push_back(dl);
736                         break;
737                 }
738                 
739                 case LM_TK_RIGHT:
740                         if (flags & FLAG_RIGHT)
741                                 return;
742                         error("Unmatched right delimiter");
743 //        panic = true;
744                         break;
745                 
746                 case LM_TK_FONT:
747                 {
748                         MathTextCodes t = static_cast<MathTextCodes>(lval_->id);
749                         MathArray ar;
750                         parse_into(ar, FLAG_ITEM);
751                         for (MathArray::iterator it = ar.begin(); it != ar.end(); ++it)
752                                 (*it)->handleFont(t);
753                         array.push_back(ar);
754                         break;
755                 }
756
757                 case LM_TK_OLDFONT:
758                         yyvarcode = static_cast<MathTextCodes>(lval_->id);
759                         break;
760
761                 case LM_TK_STY:
762                 {
763                         lyxerr[Debug::MATHED] << "LM_TK_STY not implemented\n";
764                         //MathArray tmp = array;
765                         //MathSizeInset * p = new MathSizeInset(MathStyles(lval_->id));
766                         //array.push_back(p);
767                         //parse_into(p->cell(0), FLAG_BRACE_FONT);
768                         break; 
769                 }
770
771                 case LM_TK_NONUM:
772                         curr_num_ = false;
773                         break;
774                 
775                 case LM_TK_UNDEF: 
776                         if (MathMacroTable::hasTemplate(sval_)) {
777                                 MathMacro * m = MathMacroTable::cloneTemplate(sval_);
778                                 for (int i = 0; i < m->nargs(); ++i) 
779                                         parse_into(m->cell(i), FLAG_ITEM);
780                                 array.push_back(m);
781                                 m->metrics(LM_ST_TEXT);
782                         } else
783                                 array.push_back(new MathFuncInset(sval_));
784                         break;
785                 
786                 case LM_TK_BEGIN:
787                 {
788                         int i = ival_;
789                         MathInsetTypes typ = latex_mathenv[i].typ;
790
791                         if (typ == LM_OT_MATRIX) {
792                                 string const valign = lexArg('[') + 'c';
793                                 string const halign = lexArg('{');
794                                 //lyxerr << "valign: '" << valign << "'\n";
795                                 //lyxerr << "halign: '" << halign << "'\n";
796                                 MathArrayInset * m = new MathArrayInset(halign.size(), 1);
797                                 m->valign(valign[0]);
798                                 m->halign(halign);
799
800                                 parse_lines(m, halign.size(), latex_mathenv[i].numbered, false);
801                                 array.push_back(m);
802                                 //lyxerr << "read matrix " << *m << "\n";       
803                                 break;
804                         } else 
805                                 lyxerr[Debug::MATHED] << "unknow math inset " << typ << "\n";   
806                         break;
807                 }
808         
809                 case LM_TK_LABEL:
810                         curr_label_ = lexArg('{', true);
811                         break;
812
813                 case LM_TK_CHOOSE:
814                 case LM_TK_OVER:
815                 {
816                         limits = 0;
817                         MathInset * p = createMathInset(lval_);
818                         p->cell(0).swap(array);
819                         array.push_back(p);
820                         parse_into(p->cell(1), FLAG_BLOCK);
821                         break;
822                 }
823                 
824                 default:
825                         limits = 0;
826                         MathInset * p = createMathInset(lval_);
827                         if (p) {
828                                 for (int i = 0; i < p->nargs(); ++i)
829                                         parse_into(p->cell(i), FLAG_ITEM);
830                                 array.push_back(p);
831                         } else {
832                                 error("Unrecognized token");
833                                 //lyxerr[Debug::MATHED] << "[" << t << " " << sval_ << "]\n";
834                                 lyxerr << "[" << t << " " << sval_ << "]\n";
835                         }
836
837                 } // end of big switch
838
839                 if (flags & FLAG_LEAVE) {
840                         flags &= ~FLAG_LEAVE;
841                         break;
842                 }
843         }
844
845         if (panic) {
846                 lyxerr << " Math Panic, expect problems!\n";
847                 //   Search for the end command. 
848                 int t;
849                 do {
850                         t = yylex();
851                 } while (is_.good() && t != LM_TK_END && t);
852         }
853 }
854
855
856 void parse_end(LyXLex & lex, int lineno)
857 {
858         // Update line number
859         lex.setLineNo(lineno);
860
861         // reading of end_inset
862         while (lex.isOK()) {
863                 lex.nextToken();
864                 if (lex.getString() == "\\end_inset")
865                         break;
866                 //lyxerr[Debug::MATHED] << "InsetFormula::Read: Garbage before \\end_inset,"
867                 lyxerr << "InsetFormula::Read: Garbage before \\end_inset,"
868                         " or missing \\end_inset!\n";
869         }
870 }
871
872 } // anonymous namespace
873
874
875
876 MathArray mathed_parse_cell(string const & str)
877 {
878         istringstream is(str.c_str());
879         Parser parser(is);
880         MathArray ar;
881         parser.parse_into(ar, 0);
882         return ar;
883 }
884
885
886
887 MathMacroTemplate * mathed_parse_macro(string const & str)
888 {
889         istringstream is(str.c_str());
890         Parser parser(is);
891         return parser.parse_macro();
892 }
893
894 MathMacroTemplate * mathed_parse_macro(istream & is)
895 {
896         Parser parser(is);
897         return parser.parse_macro();
898 }
899
900 MathMacroTemplate * mathed_parse_macro(LyXLex & lex)
901 {
902         Parser parser(lex);
903         MathMacroTemplate * p = parser.parse_macro();
904         parse_end(lex, parser.lineno());
905         return p;
906 }
907
908
909
910 MathMatrixInset * mathed_parse_normal(string const & str)
911 {
912         istringstream is(str.c_str());
913         Parser parser(is);
914         return parser.parse_normal();
915 }
916
917 MathMatrixInset * mathed_parse_normal(istream & is)
918 {
919         Parser parser(is);
920         return parser.parse_normal();
921 }
922
923 MathMatrixInset * mathed_parse_normal(LyXLex & lex)
924 {
925         Parser parser(lex);
926         MathMatrixInset * p = parser.parse_normal();
927         parse_end(lex, parser.lineno());
928         return p;
929 }