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