]> git.lyx.org Git - lyx.git/blob - src/mathed/math_parser.C
a00cbb681bb6980e97806f2fa68380261614fc89
[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 bool init_done = false;
231         
232         if (!init_done) {
233                 LexInitCodes();
234                 init_done = true;
235         }
236         
237         while (yyis->good()) {
238                 unsigned char c = getuchar(yyis);
239                 //lyxerr << "reading byte: '" << c << "' code: " << lexcode[c] << endl;
240                 
241                 if (yyvarcode == LM_TC_TEXTRM && c == ' ') {
242                         yylval.i = ' ';
243                         return LM_TK_ALPHA;
244                 } else if (lexcode[c] == LexNewLine) {
245                         ++yylineno; 
246                         continue;
247                 } else if (lexcode[c] == LexComment) {
248                         do {
249                                 c = getuchar(yyis);
250                         } while (c != '\n' && yyis->good());  // eat comments
251                 } else if (lexcode[c] == LexDigit
252                            || lexcode[c] == LexOther
253                            || lexcode[c] == LexMathSpace) {
254                         yylval.i = c;
255                         return LM_TK_STR;
256                 } else if (lexcode[c] == LexAlpha) {
257                         yylval.i = c;
258                         return LM_TK_ALPHA;
259                 } else if (lexcode[c] == LexBOP) {
260                         yylval.i = c;
261                         return LM_TK_BOP;
262                 } else if (lexcode[c] == LexSelf) {
263                         return c;
264                 } else if (lexcode[c] == LexArgument) {
265                         c = getuchar(yyis);
266                         yylval.i = c - '0';
267                         return LM_TK_ARGUMENT; 
268                 } else if (lexcode[c] == LexOpen) {
269                         return LM_TK_OPEN;
270                 } else if (lexcode[c] == LexClose) {
271                         return LM_TK_CLOSE;
272                 } else if (lexcode[c] == LexESC)   {
273                         c = getuchar(yyis);
274                         if (c == '\\')  {
275                                 yylval.i = -1;
276                                 return LM_TK_NEWLINE;
277                         }
278                         if (c == '(') {
279                                 yylval.i = LM_OT_SIMPLE;
280                                 return LM_TK_BEGIN;
281                         }
282                         if (c == ')') {
283                                 yylval.i = LM_OT_SIMPLE;
284                                 return LM_TK_END;
285                         }
286                         if (c == '[') {
287                                 yylval.i = LM_OT_EQUATION;
288                                 return LM_TK_BEGIN;
289                         }
290                         if (c == ']') {
291                                 yylval.i = LM_OT_EQUATION;
292                                 return LM_TK_END;
293                         }
294                         if (contains(latex_special_chars, c)) {
295                                 yylval.i = c;
296                                 return LM_TK_SPECIAL;
297                         } 
298                         if (lexcode[c] == LexMathSpace) {
299                                 int i;
300                                 for (i = 0; i < 4 && static_cast<int>(c) != latex_mathspace[i][0]; ++i)
301                                         ;
302                                 yylval.i = (i < 4) ? i : 0; 
303                                 return LM_TK_SPACE; 
304                         }
305                         if (lexcode[c] == LexAlpha || lexcode[c] == LexDigit) {
306                                 yytext.erase();
307                                 while (lexcode[c] == LexAlpha || lexcode[c] == LexDigit) {
308                                         yytext += c;
309                                         c = getuchar(yyis);
310                                 }
311                                 if (yyis->good())
312                                         yyis->putback(c);
313                                 lyxerr[Debug::MATHED] << "reading: text '" << yytext << "'\n";
314                                 latexkeys const * l = in_word_set(yytext);
315                                 if (!l)
316                                         return LM_TK_UNDEF;
317
318                                 if (l->token == LM_TK_BEGIN || l->token == LM_TK_END) { 
319                                         LexGetArg('{');
320                                         int i = 0;
321                                         while (i < latex_mathenv_num && yytext != latex_mathenv[i].name)
322                                                  ++i;
323                                         yylval.i = i;
324                                 } else if (l->token == LM_TK_SPACE) 
325                                         yylval.i = l->id;
326                                 else
327                                         yylval.l = l;
328                                 return l->token;
329                         }
330                 }
331         }
332         return 0;
333 }
334
335
336 void handle_frac(MathArray & dat, string const & name)
337 {
338         MathFracInset * p = new MathFracInset(name);
339         mathed_parse(p->cell(0), FLAG_BRACE | FLAG_BRACE_LAST);
340         mathed_parse(p->cell(1), FLAG_BRACE | FLAG_BRACE_LAST);
341         dat.push_back(p);
342 }
343
344
345 MathScriptInset * lastScriptInset(MathArray & array)
346 {
347         MathInset * p = array.back_inset();
348         if (!p || !p->isScriptInset()) {
349                 p = new MathScriptInset;
350                 array.push_back(p);
351         }
352         return static_cast<MathScriptInset *>(p);
353 }
354
355 }
356
357
358
359 static bool   curr_num;
360 static string curr_label;
361
362 void mathed_parse_lines(MathInset * inset, int col, bool numbered, bool outmost)
363 {
364         // save global variables
365         bool   saved_num   = curr_num;
366         string saved_label = curr_label;
367
368         MathGridInset * p = static_cast<MathGridInset *>(inset);
369         for (int row = 0; true; ++row) {
370                 // reset global variables
371                 curr_num   = numbered;
372                 curr_label = string();
373
374                 // reading a row
375                 int idx = p->nargs() - p->ncols();
376                 for (int i = 0; i < col - 1; ++i, ++idx)
377                         mathed_parse(p->cell(idx), FLAG_AMPERSAND);
378                 mathed_parse(p->cell(idx), FLAG_NEWLINE | FLAG_END);
379
380                 if (outmost) {
381                         MathMatrixInset * m = static_cast<MathMatrixInset *>(p);
382                         m->numbered(row, curr_num);
383                         m->label(row, curr_label);
384                 }
385
386                 // Hack!
387                 // no newline
388                 if (yylval.i != -1)
389                         break;
390
391                 p->appendRow();
392         }
393
394         // restore global variables
395         curr_num   = saved_num;
396         curr_label = saved_label;
397 }
398
399
400 MathInset * mathed_parse()
401 {
402         MathInset * p = 0;
403         int t = yylex();
404
405         switch (t) {
406                 case LM_TK_NEWCOMMAND: {
407                         LexGetArg('{');
408                         string name = yytext.substr(1);
409                         
410                         int na = 0; 
411                         unsigned char const c = yyis->peek();
412                         if (c == '[') {
413                                 LexGetArg('[');
414                                 na = atoi(yytext.c_str());
415                         } 
416
417                         p = new MathMacroTemplate(name, na);
418                         mathed_parse(p->cell(0), FLAG_BRACE | FLAG_BRACE_LAST);
419                         lyxerr[Debug::MATHED] << "LM_TK_NEWCOMMAND: name: " << name << " na: " << na << "\n";
420                         break;
421                 }
422
423                 case LM_TK_BEGIN: {
424                         int i = yylval.i;
425                         lyxerr[Debug::MATHED] << "reading math environment " << i << " "
426                                 << latex_mathenv[i].name << "\n";
427
428                         MathInsetTypes typ = latex_mathenv[i].typ;
429                         p = new MathMatrixInset(typ);
430                         switch (typ) {
431
432                                 case LM_OT_SIMPLE: {
433                                         curr_num   = latex_mathenv[i].numbered;
434                                         curr_label = string();
435                                         mathed_parse(p->cell(0), 0);
436                                         MathMatrixInset * m = static_cast<MathMatrixInset *>(p);
437                                         m->numbered(0, curr_num);
438                                         m->label(0, curr_label);
439                                         break;
440                                 }
441
442                                 case LM_OT_EQUATION: {
443                                         curr_num   = latex_mathenv[i].numbered;
444                                         curr_label = string();
445                                         mathed_parse(p->cell(0), FLAG_END);
446                                         MathMatrixInset * m = static_cast<MathMatrixInset *>(p);
447                                         m->numbered(0, curr_num);
448                                         m->label(0, curr_label);
449                                         break;
450                                 }
451
452                                 case LM_OT_EQNARRAY: {
453                                         mathed_parse_lines(p, 3, latex_mathenv[i].numbered, true);
454                                         break;
455                                 }
456
457                                 case LM_OT_ALIGNAT: {
458                                         LexGetArg('{');
459                                         //int c = atoi(yytext.c_str());
460                                         lyxerr[Debug::MATHED] << "LM_OT_ALIGNAT: not implemented\n";
461                                         mathed_parse_lines(p, 2, latex_mathenv[i].numbered, true);
462                                         lyxerr[Debug::MATHED] << "LM_OT_ALIGNAT: par: " << *p << "\n";
463                                         break;
464                                 }
465
466                                 default: 
467                                         lyxerr[Debug::MATHED] << "1: unknown math environment: " << typ << "\n";
468                         }
469
470                         p->SetName(latex_mathenv[i].basename);
471
472                         break;
473                 }
474                 
475                 default:
476                         lyxerr[Debug::MATHED] << "2 unknown math environment: " << t << "\n";
477         }
478
479         return p;
480 }
481
482
483 void mathed_parse(MathArray & array, unsigned flags)
484 {
485         int  t = yylex();
486         int  tprev = 0;
487         bool panic = false;
488         static int plevel = -1;
489         yyvarcode = LM_TC_VAR;
490         
491         int brace = 0;
492
493         ++plevel;
494         while (t) {
495                 //lyxerr << "t: " << t << " flags: " << flags;
496                 //array.dump(lyxerr);
497                 //lyxerr << "\n";
498
499                 if ((flags & FLAG_BRACE) && t != LM_TK_OPEN) {
500                         if (!(flags & FLAG_BRACK_ARG) || t != '[') {
501                                 mathPrintError(
502                                         "Expected {. Maybe you forgot to enclose an argument in {}");
503                                 panic = true;
504                                 break;
505                         }
506                 }
507
508                 switch (t) {
509                         
510                 case LM_TK_ALPHA:
511                         array.push_back(yylval.i, yyvarcode);
512                         break;
513
514                 case LM_TK_ARGUMENT:
515                         array.push_back(new MathMacroArgument(yylval.i));
516                         break;
517
518                 case LM_TK_SPECIAL:
519                         array.push_back(yylval.i, LM_TC_SPECIAL);
520                         break;
521
522                 case LM_TK_STR:
523                         array.push_back(yylval.i, LM_TC_CONST);
524                         break;
525
526                 case LM_TK_OPEN:
527                         ++brace;
528                         if (flags & FLAG_BRACE_OPT) {
529                                 flags &= ~FLAG_BRACE_OPT;
530                                 flags |= FLAG_BRACE;
531                         }
532                         
533                         if (flags & FLAG_BRACE)
534                                 flags &= ~FLAG_BRACE;
535                         else 
536                                 array.push_back('{', LM_TC_TEX);
537                         break;
538
539                 case LM_TK_CLOSE:
540                         --brace;         
541                         if (brace < 0) {
542                                 mathPrintError("Unmatching braces");
543                                 panic = true;
544                                 break;
545                         }
546                         if (flags & FLAG_BRACE_FONT) {
547                                 yyvarcode = LM_TC_VAR;
548                                 flags &= ~FLAG_BRACE_FONT;
549                                 break;
550                         }
551                         if (brace == 0 && (flags & FLAG_BRACE_LAST)) {
552                                 --plevel;
553                                 return;
554                         }
555                         array.push_back('}', LM_TC_TEX);
556                         break;
557                 
558                 case '[':
559                         if (flags & FLAG_BRACK_ARG) {
560                                 flags &= ~FLAG_BRACK_ARG;
561                                 unsigned char const rg = LexGetArg('[');
562                                 if (rg != ']') {
563                                         mathPrintError("Expected ']'");
564                                         panic = true;
565                                         break;
566                                 }          
567                         } else
568                                 array.push_back('[', LM_TC_CONST);
569                         break;
570
571                 case ']':
572                         if (flags & FLAG_BRACK_END) {
573                                 --plevel;
574                                 return;
575                         }
576                         array.push_back(']', LM_TC_CONST);
577                         break;
578                 
579                 case '^':
580                 {
581                         MathArray ar;
582                         mathed_parse(ar, FLAG_BRACE_OPT | FLAG_BRACE_LAST);
583                         MathScriptInset * p = lastScriptInset(array);
584                         p->setData(ar, 0);
585                         p->up(true);
586                         break;
587                 }
588                 
589                 case '_':
590                 {
591                         MathArray ar;
592                         mathed_parse(ar, FLAG_BRACE_OPT | FLAG_BRACE_LAST);
593                         MathScriptInset * p = lastScriptInset(array);
594                         p->setData(ar, 1);
595                         p->down(true);
596                         break;
597                 }
598                 
599                 case LM_TK_LIMIT:
600                 {
601                         MathScriptInset * p = lastScriptInset(array);
602                         if (p) 
603                                 p->limits(yylval.l->id ? 1 : -1);
604                         break;
605                 }
606                 
607                 case '&':
608                 {
609                         if (flags & FLAG_AMPERSAND) {
610                                 flags &= ~FLAG_AMPERSAND;
611                                 --plevel;
612                                 return;
613                         }
614                         lyxerr[Debug::MATHED] << "found tab unexpectedly, array: '" << array << "'\n";
615                         break;
616                 }
617                 
618                 case LM_TK_NEWLINE:
619                 {
620                         if (flags & FLAG_NEWLINE) {
621                                 flags &= ~FLAG_NEWLINE;
622                                 --plevel;
623                                 return;
624                         }
625                         lyxerr[Debug::MATHED] << "found newline unexpectedly, array: '" << array << "'\n";
626                         break;
627                 }
628                 
629                 case LM_TK_BIGSYM:  
630                 {
631                         array.push_back(new MathBigopInset(yylval.l->name, yylval.l->id));
632                         break;
633                 }
634                 
635                 case LM_TK_SYM:
636                         if (yylval.l->id < 256) {
637                                 MathTextCodes tc = MathIsBOPS(yylval.l->id) ? LM_TC_BOPS: LM_TC_SYMB;
638                                 array.push_back(yylval.l->id, tc);
639                         } else 
640                                 array.push_back(new MathFuncInset(yylval.l->name));
641                         break;
642
643                 case LM_TK_BOP:
644                         array.push_back(yylval.i, LM_TC_BOP);
645                         break;
646
647                 case LM_TK_SPACE:
648                         if (yylval.i >= 0) 
649                                 array.push_back(new MathSpaceInset(yylval.i));
650                         break;
651
652                 case LM_TK_DOTS:
653                         array.push_back(new MathDotsInset(yylval.l->name, yylval.l->id));
654                         break;
655                 
656                 case LM_TK_CHOOSE:
657                         handle_frac(array, "atop");     
658                         break;
659
660                 case LM_TK_STACK:
661                         handle_frac(array, "stackrel"); 
662                         break;
663
664                 case LM_TK_FRAC:
665                         handle_frac(array, "frac");     
666                         break;
667
668                 case LM_TK_SQRT:
669                 {           
670                         unsigned char c = getuchar(yyis);
671                         if (c == '[') {
672                                 MathRootInset * rt = new MathRootInset;
673                                 mathed_parse(rt->cell(0), FLAG_BRACK_END);
674                                 mathed_parse(rt->cell(1), FLAG_BRACE | FLAG_BRACE_LAST);
675                                 array.push_back(rt);
676                         } else {
677                                 yyis->putback(c);
678                                 MathSqrtInset * sq = new MathSqrtInset;
679                                 mathed_parse(sq->cell(0), FLAG_BRACE | FLAG_BRACE_LAST);
680                                 array.push_back(sq);
681                         }
682                         break;
683                 }
684                 
685                 case LM_TK_LEFT:
686                 {
687                         int ld = yylex();
688                         if (ld == LM_TK_SYM)
689                                 ld = yylval.l->id;
690                         else if (ld == LM_TK_STR || ld == LM_TK_BOP || ld == LM_TK_SPECIAL)
691                                 ld = yylval.i;
692
693                         MathArray ar;
694                         mathed_parse(ar, FLAG_RIGHT);
695
696                         int rd = yylex();
697                         if (rd == LM_TK_SYM)
698                                 rd = yylval.l->id;
699                         else if (rd == LM_TK_STR || rd == LM_TK_BOP || rd == LM_TK_SPECIAL)
700                                 rd = yylval.i;   
701
702                         MathDelimInset * dl = new MathDelimInset(ld, rd);
703                         dl->setData(ar, 0);
704                         array.push_back(dl);
705                         break;
706                 }
707                 
708                 case LM_TK_RIGHT:
709                         if (flags & FLAG_RIGHT) { 
710                                 --plevel;
711                                 return;
712                         }
713                         mathPrintError("Unmatched right delimiter");
714 //        panic = true;
715                         break;
716                 
717                 case LM_TK_FONT:
718                         yyvarcode = static_cast<MathTextCodes>(yylval.l->id);
719                         flags |= (FLAG_BRACE | FLAG_BRACE_FONT);
720                         break;
721
722                 case LM_TK_STY:
723                 {
724                         lyxerr[Debug::MATHED] << "LM_TK_STY not implemented\n";
725                         //MathArray tmp = array;
726                         //MathSizeInset * p = new MathSizeInset(MathStyles(yylval.l->id));
727                         //array.push_back(p);
728                         //mathed_parse(p->cell(0), FLAG_BRACE_FONT);
729                         break; 
730                 }
731
732
733                 case LM_TK_WIDE:
734                 {  
735                         MathDecorationInset * p = new MathDecorationInset(yylval.l->id);
736                         mathed_parse(p->cell(0), FLAG_BRACE | FLAG_BRACE_LAST);
737                         array.push_back(p);
738                         break;
739                 }
740                 
741                 case LM_TK_ACCENT:
742                 {
743                         MathAccentInset * p = new MathAccentInset(yylval.l->id);
744                         mathed_parse(p->cell(0), FLAG_BRACE | FLAG_BRACE_LAST);
745                         array.push_back(p);
746                         break;
747                 }
748                         
749                 case LM_TK_NONUM:
750                         curr_num = false;
751                         break;
752                 
753                 case LM_TK_PMOD:
754                 case LM_TK_FUNC:
755                         //if (accent) 
756                         //      array.push_back(t, LM_TC_CONST);
757                         //else 
758                                 array.push_back(new MathFuncInset(yylval.l->name));
759                         break;
760                 
761                 case LM_TK_FUNCLIM:
762                         array.push_back(new MathFuncInset(yylval.l->name, LM_OT_FUNCLIM));
763                         break;
764
765                 case LM_TK_UNDEF: 
766                         if (MathMacroTable::hasTemplate(yytext)) {
767                                 MathMacro * m = MathMacroTable::cloneTemplate(yytext);
768                                 for (int i = 0; i < m->nargs(); ++i) 
769                                         mathed_parse(m->cell(i), FLAG_BRACE_OPT | FLAG_BRACE_LAST);
770                                 array.push_back(m);
771                                 m->Metrics(LM_ST_TEXT);
772                         } else
773                                 array.push_back(new MathFuncInset(yytext, LM_OT_UNDEF));
774                         break;
775                 
776                 case LM_TK_END:
777                         --plevel;
778                         return;
779
780                 case LM_TK_BEGIN:
781                 {
782                         int i = yylval.i;
783                         MathInsetTypes typ = latex_mathenv[i].typ;
784
785                         if (typ == LM_OT_MATRIX) {
786                                 string valign = "\0";
787                                 unsigned char rg = LexGetArg(0);
788                                 if (rg == ']') {
789                                         valign = yytext;
790                                         rg = LexGetArg('{');
791                                 }
792
793                                 string halign = yytext;
794                                 MathArrayInset * mm = new MathArrayInset(halign.size(), 1);
795                                 valign += 'c';
796                                 mm->valign(valign[0]);
797                                 mm->halign(halign);
798
799                                 mathed_parse_lines(mm, halign.size(), latex_mathenv[i].numbered, false);
800                                 array.push_back(mm);
801                                 //lyxerr << "read matrix " << *mm << "\n";      
802                                 break;
803                         } else 
804                                 lyxerr[Debug::MATHED] << "unknow math inset " << typ << "\n";   
805                         break;
806                 }
807         
808                 case LM_TK_MACRO:
809                         array.push_back(MathMacroTable::cloneTemplate(yylval.l->name));
810                         break;
811                 
812                 case LM_TK_LABEL:
813                 {       
814                         unsigned char const rg = LexGetArg('\0', true);
815                         if (rg != '}') {
816                                 mathPrintError("Expected '{'");
817                                 // debug info
818                                 lyxerr[Debug::MATHED] << "[" << yytext << "]" << endl;
819                                 panic = true;
820                                 break;
821                         } 
822                         //lyxerr << " setting label to " << yytext << "\n";
823                         curr_label = yytext;
824                         break;
825                 }
826                 
827                 default:
828                         mathPrintError("Unrecognized token");
829                         lyxerr[Debug::MATHED] << "[" << t << " " << yytext << "]" << endl;
830                         break;
831
832                 } // end of big switch
833                 
834                 tprev = t;
835                 if (panic) {
836                         lyxerr << " Math Panic, expect problems!" << endl;
837                         //   Search for the end command. 
838                         do {
839                                 t = yylex();
840                         } while (t != LM_TK_END && t);
841                 } else
842                         t = yylex();
843                 
844                 if (flags & FLAG_BRACE_OPT) {
845                         flags &= ~FLAG_BRACE_OPT;
846                         break;
847                 }
848         }
849         --plevel;
850 }
851
852
853 MathInset * mathed_parse(istream & is)
854 {
855         yyis     = &is;
856         yylineno = 0;
857         return mathed_parse();
858 }
859
860
861 MathInset * mathed_parse(LyXLex & lex)
862 {
863         yyis     = &lex.getStream();
864         yylineno = lex.GetLineNo();
865
866         MathInset * p = mathed_parse();
867
868         // Update line number
869         lex.setLineNo(yylineno);
870
871         // reading of end_inset
872         while (lex.IsOK()) {
873                 lex.nextToken();
874                 if (lex.GetString() == "\\end_inset")
875                         break;
876                 lyxerr[Debug::MATHED] << "InsetFormula::Read: Garbage before \\end_inset,"
877                         " or missing \\end_inset!" << endl;
878         }
879
880         return p;
881 }