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