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