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