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