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