]> git.lyx.org Git - features.git/blob - src/mathed/math_parser.C
LyX Drinkers United: patch 2
[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->isScriptInset()) {
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, bool numbered, bool outmost)
421 {
422         MathGridInset * p = static_cast<MathGridInset *>(inset);
423         for (int row = 0; true; ++row) {
424                 // reset global variables
425                 curr_num   = numbered;
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                 if (outmost) {
435                         MathMatrixInset * m = static_cast<MathMatrixInset *>(p);
436                         m->numbered(row, curr_num);
437                         m->label(row, curr_label);
438                 }
439
440                 // Hack!
441                 // no newline
442                 if (yylval.i != -1)
443                         break;
444
445                 p->appendRow();
446         }
447 }
448
449
450 MathInset * mathed_parse()
451 {
452         MathInset * p = 0;
453         int t = yylex();
454
455         switch (t) {
456                 case LM_TK_NEWCOMMAND: {
457                         LexGetArg('{');
458                         string name = yytext.substr(1);
459                         
460                         int na = 0; 
461                         char const c = yyis->peek();
462                         if (c == '[') {
463                                 LexGetArg('[');
464                                 na = atoi(yytext.c_str());
465                         } 
466
467                         p = new MathMacroTemplate(name, na);
468                         mathed_parse(p->cell(0), FLAG_BRACE | FLAG_BRACE_LAST);
469                         lyxerr << "LM_TK_NEWCOMMAND: name: " << name << " na: " << na << "\n";
470                         break;
471                 }
472
473                 case LM_TK_BEGIN: {
474                         int i = yylval.i;
475                         lyxerr << "reading math environment " << i << " "
476                                 << latex_mathenv[i].name << "\n";
477
478                         MathInsetTypes typ = latex_mathenv[i].typ;
479                         p = new MathMatrixInset(typ);
480                         switch (typ) {
481
482                                 case LM_OT_SIMPLE: {
483                                         curr_num   = latex_mathenv[i].numbered;
484                                         curr_label = string();
485                                         mathed_parse(p->cell(0), 0);
486                                         MathMatrixInset * m = static_cast<MathMatrixInset *>(p);
487                                         m->numbered(0, curr_num);
488                                         m->label(0, curr_label);
489                                         break;
490                                 }
491
492                                 case LM_OT_EQUATION: {
493                                         curr_num   = latex_mathenv[i].numbered;
494                                         curr_label = string();
495                                         mathed_parse(p->cell(0), FLAG_END);
496                                         MathMatrixInset * m = static_cast<MathMatrixInset *>(p);
497                                         m->numbered(0, curr_num);
498                                         m->label(0, curr_label);
499                                         break;
500                                 }
501
502                                 case LM_OT_EQNARRAY: {
503                                         mathed_parse_lines(p, 3, latex_mathenv[i].numbered, true);
504                                         break;
505                                 }
506
507                                 case LM_OT_ALIGNAT: {
508                                         LexGetArg('{');
509                                         //int c = atoi(yytext.c_str());
510                                         lyxerr << "LM_OT_ALIGNAT: not implemented\n";
511                                         mathed_parse_lines(p, 2, latex_mathenv[i].numbered, true);
512                                         lyxerr << "LM_OT_ALIGNAT: par: " << *p << "\n";
513                                         break;
514                                 }
515
516                                 default: 
517                                         lyxerr << "1: unknown math environment: " << typ << "\n";
518                         }
519
520                         p->SetName(latex_mathenv[i].basename);
521
522                         break;
523                 }
524                 
525                 default:
526                         lyxerr << "2 unknown math environment: " << t << "\n";
527         }
528
529         return p;
530 }
531
532
533 void mathed_parse(MathArray & array, unsigned flags)
534 {
535         int  t = yylex();
536         int  tprev = 0;
537         bool panic = false;
538         static int plevel = -1;
539         MathTextCodes varcode = LM_TC_VAR;
540         
541         int brace = 0;
542         int acc_brace = 0;
543         int acc_braces[8];
544
545         ++plevel;
546         while (t) {
547                 //lyxerr << "t: " << t << " flags: " << flags;
548                 //array.dump(lyxerr);
549                 //lyxerr << "\n";
550
551                 if ((flags & FLAG_BRACE) && t != LM_TK_OPEN) {
552                         if (!(flags & FLAG_BRACK_ARG) || t != '[') {
553                                 mathPrintError(
554                                         "Expected {. Maybe you forgot to enclose an argument in {}");
555                                 panic = true;
556                                 break;
557                         }
558                 }
559
560                 switch (t) {
561                         
562                 case LM_TK_ALPHA:
563                         do_insert(array, yylval.i, varcode);
564                         break;
565
566                 case LM_TK_ARGUMENT:
567                         array.push_back(new MathMacroArgument(yylval.i));
568                         break;
569
570                 case LM_TK_SPECIAL:
571                         array.push_back(yylval.i, LM_TC_SPECIAL);
572                         break;
573
574                 case LM_TK_STR:
575                         do_insert(array, yylval.i, LM_TC_CONST);
576                         break;
577
578                 case LM_TK_OPEN:
579                         ++brace;
580                         if (accent && tprev == LM_TK_ACCENT) {
581                                 acc_braces[acc_brace++] = brace;
582                                 break;
583                         }
584                         if (flags & FLAG_BRACE_OPT) {
585                                 flags &= ~FLAG_BRACE_OPT;
586                                 flags |= FLAG_BRACE;
587                         }
588                         
589                         if (flags & FLAG_BRACE)
590                                 flags &= ~FLAG_BRACE;
591                         else 
592                                 array.push_back('{', LM_TC_TEX);
593                         break;
594
595                 case LM_TK_CLOSE:
596                         --brace;         
597                         if (brace < 0) {
598                                 mathPrintError("Unmatching braces");
599                                 panic = true;
600                                 break;
601                         }
602                         if (acc_brace && brace == acc_braces[acc_brace - 1] - 1) {
603                                 --acc_brace;
604                                 break;
605                         }
606                         if (flags & FLAG_BRACE_FONT) {
607                                 varcode = LM_TC_VAR;
608                                 yy_mtextmode = false;
609                                 flags &= ~FLAG_BRACE_FONT;
610                                 break;
611                         }
612                         if (brace == 0 && (flags & FLAG_BRACE_LAST)) {
613                                 --plevel;
614                                 return;
615                         }
616                         array.push_back('}', LM_TC_TEX);
617                         break;
618                 
619                 case '[':
620                         if (flags & FLAG_BRACK_ARG) {
621                                 flags &= ~FLAG_BRACK_ARG;
622                                 char const rg = LexGetArg('[');
623                                 if (rg != ']') {
624                                         mathPrintError("Expected ']'");
625                                         panic = true;
626                                         break;
627                                 }          
628                         } else
629                                 array.push_back('[', LM_TC_CONST);
630                         break;
631
632                 case ']':
633                         if (flags & FLAG_BRACK_END) {
634                                 --plevel;
635                                 return;
636                         }
637                         array.push_back(']', LM_TC_CONST);
638                         break;
639                 
640                 case '^':
641                 {
642                         MathArray ar;
643                         mathed_parse(ar, FLAG_BRACE_OPT | FLAG_BRACE_LAST);
644                         MathScriptInset * p = lastScriptInset(array);
645                         p->setData(ar, 0);
646                         p->up(true);
647                         break;
648                 }
649                 
650                 case '_':
651                 {
652                         MathArray ar;
653                         mathed_parse(ar, FLAG_BRACE_OPT | FLAG_BRACE_LAST);
654                         MathScriptInset * p = lastScriptInset(array);
655                         p->setData(ar, 1);
656                         p->down(true);
657                         break;
658                 }
659                 
660                 case LM_TK_LIMIT:
661                 {
662                         MathScriptInset * p = lastScriptInset(array);
663                         if (p) 
664                                 p->limits(yylval.l->id ? 1 : -1);
665                         break;
666                 }
667                 
668                 case '&':
669                 {
670                         if (flags & FLAG_AMPERSAND) {
671                                 flags &= ~FLAG_AMPERSAND;
672                                 --plevel;
673                                 return;
674                         }
675                         lyxerr << "found tab unexpectedly, array: '" << array << "'\n";
676                         break;
677                 }
678                 
679                 case LM_TK_NEWLINE:
680                 {
681                         if (flags & FLAG_NEWLINE) {
682                                 flags &= ~FLAG_NEWLINE;
683                                 --plevel;
684                                 return;
685                         }
686                         lyxerr << "found newline unexpectedly, array: '" << array << "'\n";
687                         break;
688                 }
689                 
690                 case LM_TK_BIGSYM:  
691                 {
692                         array.push_back(new MathBigopInset(yylval.l->name, yylval.l->id));
693                         break;
694                 }
695                 
696                 case LM_TK_SYM:
697                         if (yylval.l->id < 256) {
698                                 MathTextCodes tc = MathIsBOPS(yylval.l->id) ? LM_TC_BOPS: LM_TC_SYMB;
699                                 do_insert(array, yylval.l->id, tc);
700                         } else 
701                                 do_insert(array, new MathFuncInset(yylval.l->name));
702                         break;
703
704                 case LM_TK_BOP:
705                         do_insert(array, yylval.i, LM_TC_BOP);
706                         break;
707
708                 case LM_TK_SPACE:
709                         if (yylval.i >= 0) 
710                                 array.push_back(new MathSpaceInset(yylval.i));
711                         break;
712
713                 case LM_TK_DOTS:
714                         array.push_back(new MathDotsInset(yylval.l->name, yylval.l->id));
715                         break;
716                 
717                 case LM_TK_CHOOSE:
718                         handle_frac(array, LM_OT_ATOP); 
719                         break;
720
721                 case LM_TK_STACK:
722                         handle_frac(array, LM_OT_STACKREL);     
723                         break;
724
725                 case LM_TK_FRAC:
726                         handle_frac(array, LM_OT_FRAC); 
727                         break;
728
729                 case LM_TK_SQRT:
730                 {           
731                         char c;
732                         yyis->get(c);
733                         if (c == '[') {
734                                 MathRootInset * rt = new MathRootInset;
735                                 mathed_parse(rt->cell(0), FLAG_BRACK_END);
736                                 mathed_parse(rt->cell(1), FLAG_BRACE | FLAG_BRACE_LAST);
737                                 array.push_back(rt);
738                         } else {
739                                 yyis->putback(c);
740                                 MathSqrtInset * sq = new MathSqrtInset;
741                                 mathed_parse(sq->cell(0), FLAG_BRACE | FLAG_BRACE_LAST);
742                                 array.push_back(sq);
743                         }
744                         break;
745                 }
746                 
747                 case LM_TK_LEFT:
748                 {
749                         int ld = yylex();
750                         if (ld == LM_TK_SYM)
751                                 ld = yylval.l->id;
752                         else if (ld == LM_TK_STR || ld == LM_TK_BOP || ld == LM_TK_SPECIAL)
753                                 ld = yylval.i;
754
755                         MathArray ar;
756                         mathed_parse(ar, FLAG_RIGHT);
757
758                         int rd = yylex();
759                         if (rd == LM_TK_SYM)
760                                 rd = yylval.l->id;
761                         else if (rd == LM_TK_STR || rd == LM_TK_BOP || rd == LM_TK_SPECIAL)
762                                 rd = yylval.i;   
763
764                         MathDelimInset * dl = new MathDelimInset(ld, rd);
765                         dl->setData(ar, 0);
766                         array.push_back(dl);
767                         break;
768                 }
769                 
770                 case LM_TK_RIGHT:
771                         if (flags & FLAG_RIGHT) { 
772                                 --plevel;
773                                 return;
774                         }
775                         mathPrintError("Unmatched right delimiter");
776 //        panic = true;
777                         break;
778                 
779                 case LM_TK_FONT:
780                         yy_mtextmode = (yylval.l->id == LM_TC_TEXTRM);
781                         flags |= (FLAG_BRACE | FLAG_BRACE_FONT);
782                         break;
783
784                 case LM_TK_STY:
785                 {
786                         lyxerr << "LM_TK_STY not implemented\n";
787                         //MathArray tmp = array;
788                         //MathSizeInset * p = new MathSizeInset(MathStyles(yylval.l->id));
789                         //array.push_back(p);
790                         //mathed_parse(p->cell(0), FLAG_BRACE_FONT);
791                         break; 
792                 }
793
794
795                 case LM_TK_WIDE:
796                 {  
797                         MathDecorationInset * sq = new MathDecorationInset(yylval.l->id);
798                         mathed_parse(sq->cell(0), FLAG_BRACE | FLAG_BRACE_LAST);
799                         array.push_back(sq);
800                         break;
801                 }
802                 
803                 case LM_TK_ACCENT:
804                         setAccent(yylval.l->id);
805                         break;
806                         
807                 case LM_TK_NONUM:
808                         curr_num = false;
809                         break;
810                 
811                 case LM_TK_PMOD:
812                 case LM_TK_FUNC:
813                         if (accent) 
814                                 array.push_back(t, LM_TC_CONST);
815                         else 
816                                 array.push_back(new MathFuncInset(yylval.l->name));
817                         break;
818                 
819                 case LM_TK_FUNCLIM:
820                         array.push_back(new MathFuncInset(yylval.l->name, LM_OT_FUNCLIM));
821                         break;
822
823                 case LM_TK_UNDEF: 
824                         if (MathMacroTable::hasTemplate(yytext)) {
825                                 MathMacro * m = MathMacroTable::cloneTemplate(yytext);
826                                 for (int i = 0; i < m->nargs(); ++i) {
827                                         mathed_parse(m->cell(i), FLAG_BRACE_OPT | FLAG_BRACE_LAST);
828                                         lyxerr << "reading cell " << i << " '" << m->cell(i) << "'\n";
829                                 }
830                                 do_insert(array, m);
831                         } else
832                                 do_insert(array, new MathFuncInset(yytext, LM_OT_UNDEF));
833                         break;
834                 
835                 case LM_TK_END:
836                         --plevel;
837                         return;
838
839                 case LM_TK_BEGIN:
840                 {
841                         int i = yylval.i;
842                         MathInsetTypes typ = latex_mathenv[i].typ;
843
844                         if (typ == LM_OT_MATRIX) {
845                                 string valign = "\0";
846                                 char rg = LexGetArg(0);
847                                 if (rg == ']') {
848                                         valign = yytext;
849                                         rg = LexGetArg('{');
850                                 }
851
852                                 string halign = yytext;
853                                 MathArrayInset * mm = new MathArrayInset(halign.size(), 1);
854                                 valign += 'c';
855                                 mm->valign(valign[0]);
856                                 mm->halign(halign);
857
858                                 mathed_parse_lines(mm, halign.size(), latex_mathenv[i].numbered, false);
859                                 do_insert(array, mm);
860                                 //lyxerr << "read matrix " << *mm << "\n";      
861                                 break;
862                         } else 
863                                 lyxerr << "unknow math inset " << typ << "\n";  
864                         break;
865                 }
866         
867                 case LM_TK_MACRO:
868                         do_insert(array, MathMacroTable::cloneTemplate(yylval.l->name));
869                         break;
870                 
871                 case LM_TK_LABEL:
872                 {       
873                         char const rg = LexGetArg('\0', true);
874                         if (rg != '}') {
875                                 mathPrintError("Expected '{'");
876                                 // debug info
877                                 lyxerr << "[" << yytext << "]" << endl;
878                                 panic = true;
879                                 break;
880                         } 
881                         //lyxerr << " setting label to " << yytext << "\n";
882                         curr_label = yytext;
883                         break;
884                 }
885                 
886                 default:
887                         mathPrintError("Unrecognized token");
888                         lyxerr << "[" << t << " " << yytext << "]" << endl;
889                         break;
890
891                 } // end of big switch
892                 
893                 tprev = t;
894                 if (panic) {
895                         lyxerr << " Math Panic, expect problems!" << endl;
896                         //   Search for the end command. 
897                         do {
898                                 t = yylex();
899                         } while (t != LM_TK_END && t);
900                 } else
901                         t = yylex();
902                 
903                 if (flags & FLAG_BRACE_OPT) {
904                         flags &= ~FLAG_BRACE_OPT;
905                         break;
906                 }
907         }
908         --plevel;
909 }
910
911
912 MathInset * mathed_parse(istream & is)
913 {
914         yyis     = &is;
915         yylineno = 0;
916         return mathed_parse();
917 }
918
919
920 MathInset * mathed_parse(LyXLex & lex)
921 {
922         yyis     = &lex.getStream();
923         yylineno = lex.GetLineNo();
924
925         MathInset * p = mathed_parse();
926
927         // Update line number
928         lex.setLineNo(yylineno);
929
930         // reading of end_inset
931         while (lex.IsOK()) {
932                 lex.nextToken();
933                 if (lex.GetString() == "\\end_inset")
934                         break;
935                 lyxerr << "InsetFormula::Read: Garbage before \\end_inset,"
936                         " or missing \\end_inset!" << endl;
937         }
938
939         return p;
940 }
941
942