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