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