]> git.lyx.org Git - lyx.git/blob - src/mathed/math_parser.C
09dfc423c21b57d51679467a768bf19eba198d39
[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_symbolinset.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 #include "support/lstrings.h"
51
52 using std::istream;
53 using std::endl;
54
55
56
57 // These are lexical codes, not semantic
58 enum lexcode_enum {
59         LexNone,
60         LexESC,
61         LexAlpha,
62         LexDigit,
63         LexBOP,         // Binary operators or relations
64         LexMathSpace,
65         LexOpen,
66         LexClose,
67         LexComment,
68         LexArgument,
69         LexSpace,
70         LexNewLine,
71         LexOther,
72         LexMath,
73         LexSelf
74 };
75
76 lexcode_enum lexcode[256];  
77
78
79 char const * latex_special_chars = "#$%&_{}";
80
81
82 namespace {
83
84 void mathed_parse_into(MathArray & array, unsigned flags);
85
86 unsigned char getuchar(std::istream * is)
87 {
88         char c = 0;
89         is->get(c);
90         if (!is->good()) {
91                 lyxerr << "The input stream is not well..." << endl;
92         }
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                         if (c == '\\')  {
287                                 yylval.i = -1;
288                                 return LM_TK_NEWLINE;
289                         }
290                         if (c == '(') {
291                                 yylval.i = LM_OT_SIMPLE;
292                                 return LM_TK_BEGIN;
293                         }
294                         if (c == ')') {
295                                 yylval.i = LM_OT_SIMPLE;
296                                 return LM_TK_END;
297                         }
298                         if (c == '[') {
299                                 yylval.i = LM_OT_EQUATION;
300                                 return LM_TK_BEGIN;
301                         }
302                         if (c == ']') {
303                                 yylval.i = LM_OT_EQUATION;
304                                 return LM_TK_END;
305                         }
306                         if (c == '|') {
307                                 yytext = "|";
308                                 return LM_TK_UNDEF;
309                         }
310                         if (contains(latex_special_chars, c)) {
311                                 yylval.i = c;
312                                 return LM_TK_SPECIAL;
313                         } 
314                         if (lexcode[c] == LexMathSpace) {
315                                 int i;
316                                 for (i = 0; i < 4 && static_cast<int>(c) != latex_mathspace[i][0]; ++i)
317                                         ;
318                                 yylval.i = (i < 4) ? i : 0; 
319                                 return LM_TK_SPACE; 
320                         }
321                         if (lexcode[c] == LexAlpha) {
322                                 yytext.erase();
323                                 while (lexcode[c] == LexAlpha && yyis->good()) {
324                                         yytext += c;
325                                         c = getuchar(yyis);
326                                 }
327                                 while (lexcode[c] == LexSpace && yyis->good()) 
328                                         c = getuchar(yyis);
329                                 if (yyis->good() && lexcode[c] != LexSpace)
330                                         yyis->putback(c);
331                         
332                                 //lyxerr[Debug::MATHED] << "reading: text '" << yytext << "'\n";
333                                 latexkeys const * l = in_word_set(yytext);
334                                 if (!l) 
335                                         return LM_TK_UNDEF;
336
337                                 if (l->token == LM_TK_BEGIN || l->token == LM_TK_END) { 
338                                         string name = lexArg('{');
339                                         int i = 0;
340                                         while (i < latex_mathenv_num && name != latex_mathenv[i].name)
341                                                  ++i;
342                                         yylval.i = i;
343                                 } else if (l->token == LM_TK_SPACE) 
344                                         yylval.i = l->id;
345                                 else
346                                         yylval.l = l;
347                                 return l->token;
348                         }
349                 }
350         }
351         return 0;
352 }
353
354
355 MathScriptInset * prevScriptInset(MathArray const & array)
356 {
357         MathInset * p = array.back_inset();
358         return (p && p->isScriptInset()) ? static_cast<MathScriptInset *>(p) : 0;
359 }
360
361
362 MathInset * lastScriptInset(MathArray & array, bool up, bool down, int limits)
363 {
364         MathScriptInset * p = prevScriptInset(array);
365         if (!p) {
366                 MathInset * b = array.back_inset();
367                 if (b && b->isScriptable()) {
368                         p = new MathScriptInset(up, down, b->clone());
369                         array.pop_back();       
370                 } else {
371                         p = new MathScriptInset(up, down);
372                 }
373                 array.push_back(p);
374         }
375         if (up)
376                 p->up(true);
377         if (down)
378                 p->down(down);
379         if (limits)
380                 p->limits(limits);
381         return p;
382 }
383
384
385 static bool   curr_num;
386 static string curr_label;
387
388 void mathed_parse_lines(MathInset * inset, int col,
389                         bool numbered, bool outmost)
390 {
391         // save global variables
392         bool   const saved_num   = curr_num;
393         string const saved_label = curr_label;
394
395         MathGridInset * p = static_cast<MathGridInset *>(inset);
396         for (int row = 0; true; ++row) {
397                 // reset global variables
398                 curr_num   = numbered;
399                 curr_label.erase();
400
401                 // reading a row
402                 int idx = p->nargs() - p->ncols();
403                 for (int i = 0; i < col - 1; ++i, ++idx)
404                         mathed_parse_into(p->cell(idx), FLAG_AMPERSAND);
405                 mathed_parse_into(p->cell(idx), FLAG_NEWLINE | FLAG_END);
406
407                 if (outmost) {
408                         MathMatrixInset * m = static_cast<MathMatrixInset *>(p);
409                         m->numbered(row, curr_num);
410                         m->label(row, curr_label);
411                 }
412
413                 // Hack!
414                 // no newline
415                 if (yylval.i != -1)
416                         break;
417
418                 p->appendRow();
419         }
420
421         // restore global variables
422         curr_num   = saved_num;
423         curr_label = saved_label;
424 }
425
426
427 MathMacroTemplate * mathed_parse_macro()
428 {
429         if (yylex() != LM_TK_NEWCOMMAND) {
430                 lyxerr << "\\newcommand expected\n";
431                 return 0;
432         }
433
434         string name = lexArg('{').substr(1);
435         string arg  = lexArg('[');
436         int    narg = arg.empty() ? 0 : atoi(arg.c_str()); 
437         MathMacroTemplate * p = new MathMacroTemplate(name, narg);
438         mathed_parse_into(p->cell(0), FLAG_BRACE | FLAG_BRACE_LAST);
439         return p;
440 }
441
442
443 MathMatrixInset * mathed_parse_normal()
444 {
445         MathMatrixInset * p = 0;
446         int t = yylex();
447
448         switch (t) {
449                 case LM_TK_MATH:
450                 case LM_TK_BEGIN: {
451                         int i = yylval.i;
452                         lyxerr[Debug::MATHED]
453                                 << "reading math environment " << i << " "
454                                 << latex_mathenv[i].name << "\n";
455
456                         MathInsetTypes typ = latex_mathenv[i].typ;
457                         p = new MathMatrixInset(typ);
458                         MathMatrixInset * m = static_cast<MathMatrixInset *>(p);
459                         switch (typ) {
460
461                                 case LM_OT_SIMPLE: {
462                                         curr_num   = latex_mathenv[i].numbered;
463                                         curr_label.erase();
464                                         mathed_parse_into(m->cell(0), 0);
465                                         m->numbered(0, curr_num);
466                                         m->label(0, curr_label);
467                                         break;
468                                 }
469
470                                 case LM_OT_EQUATION: {
471                                         curr_num   = latex_mathenv[i].numbered;
472                                         curr_label.erase();
473                                         mathed_parse_into(m->cell(0), FLAG_END);
474                                         m->numbered(0, curr_num);
475                                         m->label(0, curr_label);
476                                         break;
477                                 }
478
479                                 case LM_OT_EQNARRAY: {
480                                         mathed_parse_lines(m, 3, latex_mathenv[i].numbered, true);
481                                         break;
482                                 }
483
484                                 case LM_OT_ALIGN: {
485                                         m->halign(lexArg('{'));
486                                         mathed_parse_lines(m, 2, latex_mathenv[i].numbered, true);
487                                         break;
488                                 }
489
490                                 case LM_OT_ALIGNAT: {
491                                         m->halign(lexArg('{'));
492                                         mathed_parse_lines(m, 2, latex_mathenv[i].numbered, true);
493                                         break;
494                                 }
495
496                                 default: 
497                                         lyxerr[Debug::MATHED]
498                                                 << "1: unknown math environment: " << typ << "\n";
499                         }
500
501                         p->setName(latex_mathenv[i].basename);
502
503                         break;
504                 }
505                 
506                 default:
507                         lyxerr[Debug::MATHED]
508                                 << "2 unknown math environment: " << t << "\n";
509         }
510
511         return p;
512 }
513
514
515 void handle_frac(MathArray & array, string const & name)
516 {
517         MathFracInset * p = new MathFracInset(name);
518         mathed_parse_into(p->cell(0), FLAG_ITEM);
519         mathed_parse_into(p->cell(1), FLAG_ITEM);
520         array.push_back(p);
521 }
522
523
524 void mathed_parse_into(MathArray & array, unsigned flags)
525 {
526         static int plevel = -1;
527
528         ++plevel;
529         MathTextCodes yyvarcode   = LM_TC_VAR;
530
531         int  t      = yylex();
532         bool panic  = false;
533         int  brace  = 0;
534         int  limits = 0;
535
536         while (t) {
537                 //lyxerr << "t: " << t << " flags: " << flags << " i: " << yylval.i
538                 //      << " '" << yytext << "'\n";
539                 //array.dump(lyxerr);
540                 //lyxerr << "\n";
541
542                 if (flags & FLAG_ITEM) {
543                         flags &= ~FLAG_ITEM;
544                         if (t == LM_TK_OPEN) { 
545                                 // skip the brace and regard everything to the next matching
546                                 // closing brace
547                                 t = yylex();
548                                 ++brace;
549                                 flags |= FLAG_BRACE_LAST;
550                         } else {
551                                 // regard only this single token
552                                 flags |= FLAG_LEAVE;
553                         }
554                 }
555
556                 if ((flags & FLAG_BRACE) && t != LM_TK_OPEN) {
557                         mathPrintError(
558                                 "Expected {. Maybe you forgot to enclose an argument in {}");
559                         panic = true;
560                         break;
561                 }
562
563                 switch (t) {
564                         
565                 case LM_TK_ALPHA:
566                         if (!isspace(yylval.i) || yyvarcode == LM_TC_TEXTRM)
567                                 array.push_back(yylval.i, yyvarcode);
568                         break;
569
570                 case LM_TK_ARGUMENT: {
571                         MathMacroArgument * p = new MathMacroArgument(yylval.i);
572                         p->code(yyvarcode);
573                         array.push_back(p);
574                         break;
575                 }
576
577                 case LM_TK_SPECIAL:
578                         array.push_back(yylval.i, LM_TC_SPECIAL);
579                         break;
580
581                 case LM_TK_STR:
582                         array.push_back(yylval.i, LM_TC_CONST);
583                         break;
584
585                 case LM_TK_OPEN:
586                         ++brace;
587                         if (flags & FLAG_BRACE)
588                                 flags &= ~FLAG_BRACE;
589                         else 
590                                 array.push_back('{', LM_TC_TEX);
591                         break;
592
593                 case LM_TK_CLOSE:
594                         --brace;
595                         if (brace < 0) {
596                                 mathPrintError("Unmatching braces");
597                                 panic = true;
598                                 break;
599                         }
600                         if (flags & FLAG_BRACE_FONT) {
601                                 yyvarcode = LM_TC_VAR;
602                                 flags &= ~FLAG_BRACE_FONT;
603                                 break;
604                         }
605                         if (brace == 0 && (flags & FLAG_BRACE_LAST))
606                                 flags |= FLAG_LEAVE;
607                         else
608                                 array.push_back('}', LM_TC_TEX);
609                         break;
610                 
611                 case '[':
612                         array.push_back('[', LM_TC_CONST);
613                         break;
614
615                 case ']':
616                         if (flags & FLAG_BRACK_END)
617                                 flags |= FLAG_LEAVE;
618                         else 
619                                 array.push_back(']', LM_TC_CONST);
620                         break;
621                 
622                 case '^':
623                         mathed_parse_into(
624                                 lastScriptInset(array, true, false, limits)->cell(0), FLAG_ITEM);
625                         break;
626                 
627                 case '_':
628                         mathed_parse_into(
629                                 lastScriptInset(array, false, true, limits)->cell(1), FLAG_ITEM);
630                         break;
631                 
632                 case LM_TK_LIMIT:
633                         limits = yylval.l->id;
634                         //lyxerr << "setting limit to " << limits << "\n";
635                         break;
636                 
637                 case '&':
638                         if (flags & FLAG_AMPERSAND) {
639                                 flags &= ~FLAG_AMPERSAND;
640                                 --plevel;
641                                 return;
642                         }
643                         lyxerr[Debug::MATHED]
644                                 << "found tab unexpectedly, array: '" << array << "'\n";
645                         break;
646                 
647                 case LM_TK_NEWLINE:
648                         if (flags & FLAG_NEWLINE) {
649                                 flags &= ~FLAG_NEWLINE;
650                                 --plevel;
651                                 return;
652                         }
653                         lyxerr[Debug::MATHED]
654                                 << "found newline unexpectedly, array: '" << array << "'\n";
655                         break;
656                 
657                 case LM_TK_PROTECT: 
658                         break;
659
660                 case LM_TK_BIGSYM:  
661                 case LM_TK_SYM:
662                 case LM_TK_FUNCLIM:
663                         limits = 0;
664                         array.push_back(new MathSymbolInset(yylval.l));
665                         break;
666
667                 case LM_TK_BOP:
668                         array.push_back(yylval.i, LM_TC_BOP);
669                         break;
670
671                 case LM_TK_SPACE:
672                         if (yylval.i >= 0) 
673                                 array.push_back(new MathSpaceInset(yylval.i));
674                         break;
675
676                 case LM_TK_DOTS:
677                         array.push_back(new MathDotsInset(yylval.l));
678                         break;
679                 
680                 case LM_TK_CHOOSE:
681                         handle_frac(array, "atop");     
682                         break;
683
684                 case LM_TK_STACK:
685                         handle_frac(array, "stackrel"); 
686                         break;
687
688                 case LM_TK_FRAC:
689                         handle_frac(array, "frac");     
690                         break;
691
692                 case LM_TK_SQRT:
693                 {
694                         unsigned char c = getuchar(yyis);
695                         if (c == '[') {
696                                 array.push_back(new MathRootInset);
697                                 mathed_parse_into(array.back_inset()->cell(0), FLAG_BRACK_END);
698                                 mathed_parse_into(array.back_inset()->cell(1), FLAG_ITEM);
699                         } else {
700                                 yyis->putback(c);
701                                 array.push_back(new MathSqrtInset);
702                                 mathed_parse_into(array.back_inset()->cell(0), FLAG_ITEM);
703                         }
704                         break;
705                 }
706                 
707                 case LM_TK_LEFT:
708                 {
709                         int ld = yylex();
710                         if (ld == LM_TK_SYM)
711                                 ld = yylval.l->id;
712                         else if (ld == LM_TK_STR || ld == LM_TK_BOP || ld == LM_TK_SPECIAL)
713                                 ld = yylval.i;
714
715                         MathArray ar;
716                         mathed_parse_into(ar, FLAG_RIGHT);
717
718                         int rd = yylex();
719                         if (rd == LM_TK_SYM)
720                                 rd = yylval.l->id;
721                         else if (rd == LM_TK_STR || rd == LM_TK_BOP || rd == LM_TK_SPECIAL)
722                                 rd = yylval.i;   
723
724                         MathDelimInset * dl = new MathDelimInset(ld, rd);
725                         dl->cell(0) = ar;
726                         array.push_back(dl);
727                         break;
728                 }
729                 
730                 case LM_TK_RIGHT:
731                         if (flags & FLAG_RIGHT) { 
732                                 --plevel;
733                                 return;
734                         }
735                         mathPrintError("Unmatched right delimiter");
736 //        panic = true;
737                         break;
738                 
739                 case LM_TK_FONT:
740                         yyvarcode = static_cast<MathTextCodes>(yylval.l->id);
741                         flags |= (FLAG_BRACE | FLAG_BRACE_FONT);
742                         break;
743
744                 case LM_TK_STY:
745                 {
746                         lyxerr[Debug::MATHED] << "LM_TK_STY not implemented\n";
747                         //MathArray tmp = array;
748                         //MathSizeInset * p = new MathSizeInset(MathStyles(yylval.l->id));
749                         //array.push_back(p);
750                         //mathed_parse_into(p->cell(0), FLAG_BRACE_FONT);
751                         break; 
752                 }
753
754
755                 case LM_TK_DECORATION:
756                 {  
757                         MathDecorationInset * p = new MathDecorationInset(yylval.l);
758                         mathed_parse_into(p->cell(0), FLAG_ITEM);
759                         array.push_back(p);
760                         break;
761                 }
762                         
763                 case LM_TK_NONUM:
764                         curr_num = false;
765                         break;
766                 
767                 case LM_TK_FUNC:
768                         array.push_back(new MathSymbolInset(yylval.l));
769                         break;
770                 
771                 case LM_TK_UNDEF: 
772                         if (MathMacroTable::hasTemplate(yytext)) {
773                                 MathMacro * m = MathMacroTable::cloneTemplate(yytext);
774                                 for (int i = 0; i < m->nargs(); ++i) 
775                                         mathed_parse_into(m->cell(i), FLAG_ITEM);
776                                 array.push_back(m);
777                                 m->metrics(LM_ST_TEXT);
778                         } else
779                                 array.push_back(new MathFuncInset(yytext));
780                         break;
781                 
782                 case LM_TK_MATH:
783                 case LM_TK_END:
784                         --plevel;
785                         return;
786
787                 case LM_TK_BEGIN:
788                 {
789                         int i = yylval.i;
790                         MathInsetTypes typ = latex_mathenv[i].typ;
791
792                         if (typ == LM_OT_MATRIX) {
793                                 string const valign = lexArg('[') + 'c';
794                                 string const halign = lexArg('{');
795                                 //lyxerr << "valign: '" << valign << "'\n";
796                                 //lyxerr << "halign: '" << halign << "'\n";
797                                 MathArrayInset * m = new MathArrayInset(halign.size(), 1);
798                                 m->valign(valign[0]);
799                                 m->halign(halign);
800
801                                 mathed_parse_lines(m, halign.size(), latex_mathenv[i].numbered, false);
802                                 array.push_back(m);
803                                 //lyxerr << "read matrix " << *m << "\n";       
804                                 break;
805                         } else 
806                                 lyxerr[Debug::MATHED] << "unknow math inset " << typ << "\n";   
807                         break;
808                 }
809         
810                 case LM_TK_MACRO:
811                         array.push_back(MathMacroTable::cloneTemplate(yylval.l->name));
812                         break;
813                 
814                 case LM_TK_LABEL:
815                         curr_label = lexArg('{', true);
816                         break;
817                 
818                 default:
819                         mathPrintError("Unrecognized token");
820                         lyxerr[Debug::MATHED] << "[" << t << " " << yytext << "]" << endl;
821                         break;
822
823                 } // end of big switch
824
825                 if (flags & FLAG_LEAVE) {
826                         flags &= ~FLAG_LEAVE;
827                         break;
828                 }
829
830                 if (panic) {
831                         lyxerr << " Math Panic, expect problems!" << endl;
832                         //   Search for the end command. 
833                         do {
834                                 t = yylex();
835                         } while (yyis->good() && t != LM_TK_END && t);
836                 } else {
837                         t = yylex();
838                 }
839         }
840         --plevel;
841 }
842
843 }
844
845
846 MathArray mathed_parse_cell(string const & str)
847 {
848         istringstream is(str.c_str());
849         yyis     = &is;
850         yylineno = 0;
851         MathArray ar;
852         mathed_parse_into(ar, 0);
853         return ar;
854 }
855
856
857 MathMacroTemplate * mathed_parse_macro(string const & str)
858 {
859         istringstream is(str.c_str());
860         return mathed_parse_macro(is);
861 }
862
863
864 MathMatrixInset * mathed_parse_normal(string const & str)
865 {
866         istringstream is(str.c_str());
867         return mathed_parse_normal(is);
868 }
869
870
871
872 MathMatrixInset * mathed_parse_normal(istream & is)
873 {
874         yyis     = &is;
875         yylineno = 0;
876         return mathed_parse_normal();
877 }
878
879
880 MathMacroTemplate * mathed_parse_macro(istream & is)
881 {
882         yyis     = &is;
883         yylineno = 0;
884         return mathed_parse_macro();
885 }
886
887
888
889 MathMatrixInset * mathed_parse_normal(LyXLex & lex)
890 {
891         yyis     = &lex.getStream();
892         yylineno = lex.GetLineNo();
893
894         MathMatrixInset * p = mathed_parse_normal();
895
896         // Update line number
897         lex.setLineNo(yylineno);
898
899         // reading of end_inset
900         while (lex.IsOK()) {
901                 lex.nextToken();
902                 if (lex.GetString() == "\\end_inset")
903                         break;
904                 lyxerr[Debug::MATHED] << "InsetFormula::Read: Garbage before \\end_inset,"
905                         " or missing \\end_inset!" << endl;
906         }
907
908         return p;
909 }
910
911 MathMacroTemplate * mathed_parse_macro(LyXLex & lex)
912 {
913         yyis     = &lex.getStream();
914         yylineno = lex.GetLineNo();
915
916         MathMacroTemplate * p = mathed_parse_macro();
917
918         // Update line number
919         lex.setLineNo(yylineno);
920
921         // reading of end_inset
922         while (lex.IsOK()) {
923                 lex.nextToken();
924                 if (lex.GetString() == "\\end_inset")
925                         break;
926                 lyxerr[Debug::MATHED] << "InsetFormula::Read: Garbage before \\end_inset,"
927                         " or missing \\end_inset!" << endl;
928         }
929
930         return p;
931 }
932 //]})