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