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