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