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