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