]> git.lyx.org Git - lyx.git/blob - src/mathed/math_parser.C
use more std::functors add some of my own, some change to fl_display etc. read the...
[lyx.git] / src / mathed / math_parser.C
1 /*
2  *  File:        math_parser.C
3  *  Purpose:     Parser for mathed
4  *  Author:      Alejandro Aguilar Sierra <asierra@servidor.unam.mx> 
5  *  Created:     January 1996
6  *  Description: Parse LaTeX2e math mode code.
7  *
8  *  Dependencies: Xlib, XForms
9  *
10  *  Copyright: 1996, Alejandro Aguilar Sierra
11  *
12  *   Version: 0.8beta.
13  *
14  *   You are free to use and modify this code under the terms of
15  *   the GNU General Public Licence version 2 or later.
16  */
17
18 #include <config.h>
19
20 #include <cctype>
21
22 #ifdef __GNUG__
23 #pragma implementation "math_parser.h"
24 #endif
25
26 #include "math_parser.h"
27 #include "math_iter.h"
28 #include "math_inset.h"
29 #include "math_macro.h"
30 #include "math_root.h"
31 #include "debug.h"
32 #include "support/lyxlib.h"
33
34 using std::istream;
35 using std::endl;
36
37 enum {
38         FLAG_BRACE      = 1,    //  A { needed
39         FLAG_BRACE_ARG  = 2,    //  Next { is argument
40         FLAG_BRACE_OPT  = 4,    //  Optional {
41         FLAG_BRACE_LAST = 8,    //  Last } ends the parsing process
42         FLAG_BRACK_ARG  = 16,   //  Optional [
43         FLAG_RIGHT      = 32,      //  Next right ends the parsing process
44         FLAG_END        = 64,      //  Next end ends the parsing process
45         FLAG_BRACE_FONT = 128,  //  Next } closes a font
46         FLAG_BRACK_END  = 256   // Next ] ends the parsing process
47 };
48
49 static
50 YYSTYPE yylval;
51
52
53 static
54 short mathed_env = LM_EN_INTEXT;
55
56 string mathed_label;
57
58
59 char const * latex_mathenv[] = { 
60    "math", 
61    "displaymath", 
62    "equation", 
63    "eqnarray*",
64    "eqnarray",
65    "array"
66 };
67
68
69
70 char const * latex_mathspace[] = {
71    "!", ",", ":", ";", "quad", "qquad"
72 };
73
74
75 char const * latex_special_chars = "#$%&_{}";
76             
77 // These are lexical codes, not semantic
78 enum lexcode_enum {
79    LexNone,
80    LexESC,
81    LexAlpha,
82    LexDigit,
83    LexBOP,         // Binary operators or relations
84    LexMathSpace,
85    LexOpen,
86    LexClose,
87    LexComment,
88    LexArgument,
89    LexSpace,
90    LexNewLine,
91    LexOther,
92    LexSelf
93 };
94
95 static lexcode_enum lexcode[256];  
96 static char yytext[256];
97 static int yylineno;
98 static istream * yyis;
99 static bool yy_mtextmode= false;
100             
101 static
102 void mathPrintError(string const & msg) 
103 {
104         lyxerr << "Line ~" << yylineno << ": Math parse error: "
105                << msg << endl;
106 }
107
108
109 static
110 void LexInitCodes()
111 {
112    for (int i = 0;  i <= 255; ++i)     {
113      if (isalpha(i)) lexcode[i] = LexAlpha;
114      else if (isdigit(i)) lexcode[i] = LexDigit;
115      else if (isspace(i)) lexcode[i] = LexSpace;
116      else lexcode[i] = LexNone;
117    }
118     
119    lexcode['\t'] = lexcode['\f'] = lexcode[' '] = LexSpace;
120    lexcode['\n'] = LexNewLine;
121    lexcode['%'] = LexComment;
122    lexcode['#'] = LexArgument;
123    lexcode['+'] = lexcode['-'] = lexcode['*'] = lexcode['/'] = 
124    lexcode['<'] = lexcode['>'] = lexcode['='] = LexBOP;
125    
126    lexcode['!'] = lexcode[','] = lexcode[':'] = lexcode[';'] = LexMathSpace;
127    
128    lexcode['('] = lexcode[')'] = lexcode['|'] = lexcode['.'] =
129    lexcode['?'] = LexOther; 
130
131    lexcode['\''] = lexcode['@'] = LexAlpha;
132    
133    lexcode['['] = lexcode[']'] = lexcode['^'] = lexcode['_'] = 
134    lexcode['&'] = LexSelf;  
135    
136    lexcode['\\'] = LexESC;
137    lexcode['{'] = LexOpen;
138    lexcode['}'] = LexClose;
139 }
140
141
142 static
143 char LexGetArg(char lf, bool accept_spaces= false)
144 {
145    unsigned char c;
146    char cc;
147    while (yyis->good()) {
148       yyis->get(cc);
149       c = cc;
150       if (c > ' ') {
151          if (!lf) lf = c; else
152          if (c != lf)
153                  lyxerr << "Math parse error: unexpected '"
154                         << c << "'" << endl;
155          break;
156       }
157    }
158    char const rg =
159            (lf == '{') ? '}' : ((lf == '[') ? ']' : ((lf == '(') ? ')' : 0));
160    if (!rg) {
161            lyxerr << "Math parse error: unknown bracket '"
162                   << lf << "'" << endl;
163       return '\0';
164    }
165    char * p = &yytext[0];
166    int bcnt = 1;
167    do {
168       yyis->get(cc);
169       c = cc;
170       if (c == lf) ++bcnt;
171       if (c == rg) --bcnt;
172       if ((c > ' ' || (c == ' ' && accept_spaces)) && bcnt > 0) *(p++) = c;
173    } while (bcnt > 0 && yyis->good());
174    *p = '\0';
175    return rg;
176 }
177
178
179 static
180 int yylex(void)
181 {
182    static int init_done = 0;
183    
184    if (!init_done) LexInitCodes();
185    
186    unsigned char c;
187    char cc;
188    while (yyis->good()) {
189       yyis->get(cc);
190       c = cc;
191        
192       if (yy_mtextmode && c == ' ') {
193           yylval.i= ' ';
194           return LM_TK_ALPHA;
195       } else
196        
197        if (lexcode[c] == LexNewLine) {
198            ++yylineno; 
199            continue;
200        } else
201          
202        if (lexcode[c] == LexComment) {
203         do {
204           yyis->get(cc);
205           c = cc;
206         } while (c != '\n' % yyis->good());  // eat comments
207        } else
208        
209       if (lexcode[c] == LexDigit
210           || lexcode[c] == LexOther
211           || lexcode[c] == LexMathSpace) {
212               yylval.i = c;
213               return LM_TK_STR;
214       } else
215       if (lexcode[c] == LexAlpha) {
216               yylval.i= c;
217               return LM_TK_ALPHA;
218       } else
219       if (lexcode[c] == LexBOP) {
220               yylval.i= c;
221               return LM_TK_BOP;
222       } else
223       if (lexcode[c] == LexSelf) {
224               return c;
225       } else
226       if (lexcode[c] == LexArgument) {
227           yyis->get(cc);
228           c = cc;
229           yylval.i = c - '0';
230           return LM_TK_ARGUMENT; 
231       } else
232       if (lexcode[c] == LexOpen) {
233               return LM_TK_OPEN;
234       } else
235       if (lexcode[c] == LexClose) {
236               return LM_TK_CLOSE;
237       } else
238       if (lexcode[c] == LexESC)   {
239          yyis->get(cc);
240          c = cc;
241          if (c == '\\') {
242                  return LM_TK_NEWLINE;
243          }
244          if (c == '(') {
245                  yylval.i = LM_EN_INTEXT;
246                  return LM_TK_BEGIN;
247          }
248          if (c == ')') {
249                  yylval.i = LM_EN_INTEXT;
250                  return LM_TK_END;
251          }
252          if (c == '[') {
253                  yylval.i = LM_EN_DISPLAY;
254                  return LM_TK_BEGIN;
255          }
256          if (c == ']') {
257                  yylval.i = LM_EN_DISPLAY;
258                  return LM_TK_END;
259          }
260          if (strchr(latex_special_chars, c)) {
261              yylval.i = c;
262              return LM_TK_SPECIAL;
263          } 
264          if (lexcode[c] == LexMathSpace) {
265             int i;
266             for (i = 0; i < 4 && static_cast<int>(c) != latex_mathspace[i][0]; ++i);
267             yylval.i = (i < 4) ? i : 0; 
268             return LM_TK_SPACE; 
269          }
270          if (lexcode[c] == LexAlpha || lexcode[c] == LexDigit) {
271             char * p = &yytext[0];
272             while (lexcode[c] == LexAlpha || lexcode[c] == LexDigit) {
273                *p = c;
274                yyis->get(cc);
275                c = cc;
276                ++p;
277             }
278             *p = '\0';
279             if (yyis->good()) yyis->putback(c);
280             latexkeys * l = in_word_set (yytext, strlen(yytext));
281             if (l) {
282                if (l->token == LM_TK_BEGIN || l->token == LM_TK_END) { 
283                   int i;
284                   LexGetArg('{');
285 //                for (i = 0; i < 5 && strncmp(yytext, latex_mathenv[i],
286 //                              strlen(latex_mathenv[i])); ++i);
287                   
288                   for (i = 0; i < 6 && strcmp(yytext, latex_mathenv[i]); ++i);
289                   yylval.i = i;
290                } else
291                if (l->token == LM_TK_SPACE) 
292                  yylval.i = l->id;
293                else
294                  yylval.l = l;
295                return l->token;
296             } else { 
297                yylval.s = yytext;
298                return LM_TK_UNDEF;
299             }
300          }
301       }
302    }
303    return 0;
304 }
305
306
307 static
308 int parse_align(char * hor, char *)
309 {
310    int nc = 0;
311    for (char * c = hor; c && *c > ' '; ++c) ++nc;
312    return nc;
313 }
314
315
316 // Accent hacks only for 0.12. Stolen from Cursor.
317 static
318 int accent = 0;
319 static
320 int nestaccent[8];
321
322 static
323 void setAccent(int ac)
324 {
325         if (ac > 0 && accent < 8) {
326                 nestaccent[accent++] = ac;
327         } else
328           accent = 0;  // consumed!
329 }
330
331
332 static
333 MathedInset * doAccent(byte c, MathedTextCodes t)
334 {
335         MathedInset * ac = 0;
336         
337         for (int i = accent - 1; i >= 0; --i) {
338                 if (i == accent - 1)
339                   ac = new MathAccentInset(c, t, nestaccent[i]);
340                 else 
341                   ac = new MathAccentInset(ac, nestaccent[i]);
342         }
343         accent = 0;  // consumed!
344         
345         return ac;
346 }
347
348
349 static
350 MathedInset * doAccent(MathedInset * p)
351 {
352         MathedInset * ac = 0;
353         
354         for (int i = accent - 1; i >= 0; --i) {
355                 if (i == accent - 1)
356                   ac = new MathAccentInset(p, nestaccent[i]);
357                 else 
358                   ac = new MathAccentInset(ac, nestaccent[i]);
359         }
360         accent = 0;  // consumed!
361         
362         return ac;
363 }
364
365
366 LyxArrayBase * mathed_parse(unsigned flags, LyxArrayBase * array,
367                             MathParInset ** mtx)
368 {
369    int t = yylex();
370    int tprev = 0;
371    bool panic = false;
372    static int plevel = -1;
373    static int size = LM_ST_TEXT;
374    MathedTextCodes varcode = LM_TC_VAR;
375    MathedInset * binset = 0;
376    static MathMacroTemplate * macro = 0;
377    
378    int brace = 0;
379    int acc_brace = 0;
380    int acc_braces[8];
381    MathParInset * mt = (mtx) ? *mtx : 0;//(MathParInset*)0;
382     MathedRowSt * crow = (mt) ? mt->getRowSt() : 0;
383
384    ++plevel;
385    if (!array) array = new LyxArrayBase;
386    MathedIter data(array);
387    while (t) {
388       if ((flags & FLAG_BRACE) && t != LM_TK_OPEN) {
389          if ((flags & FLAG_BRACK_ARG) && t == '[') {
390          }
391          else {
392              mathPrintError("Expected {. Maybe you forgot to enclose an argument in {}");
393             panic = true;
394             break;
395          }
396       }
397     MathedInsetTypes fractype = LM_OT_FRAC;
398     switch (t) {
399     case LM_TK_ALPHA:
400       {
401          if (accent) {
402              data.Insert(doAccent(yylval.i, varcode));
403          } else
404             data.Insert (yylval.i, varcode);  //LM_TC_VAR);
405          break;
406       }
407     case LM_TK_ARGUMENT:
408       {
409           if (macro) {
410               data.Insert(macro->getMacroPar(yylval.i-1), LM_TC_INSET);
411           } 
412           break;
413       } 
414     case LM_TK_NEWCOMMAND:
415       {
416           int na = 0; 
417
418           LexGetArg('{');
419           string const name(&yytext[1]);
420           
421           // ugly trick to be removed soon (lyx3)
422           char const c = yyis->peek();
423           if (c == '[') {
424               LexGetArg('[');
425               na = lyx::atoi(yytext);
426           }  
427           macro = new MathMacroTemplate(name, na);
428           flags = FLAG_BRACE|FLAG_BRACE_LAST;
429           *mtx = macro;
430           macro->SetData(array);
431           break;
432       }
433     case LM_TK_SPECIAL:
434       {   
435           data.Insert (yylval.i, LM_TC_SPECIAL);
436           break;
437       }
438     case LM_TK_STR:
439       {   
440           if (accent) {
441             data.Insert(doAccent(yylval.i, LM_TC_CONST));
442           } else
443             data.Insert (yylval.i, LM_TC_CONST);
444           break;
445       }
446     case LM_TK_OPEN:
447       {
448         ++brace;
449         if  (accent && tprev == LM_TK_ACCENT) {
450             acc_braces[acc_brace++] = brace;
451             break;
452         }
453         if (flags & FLAG_BRACE_OPT) {
454            flags &= ~FLAG_BRACE_OPT;
455            flags |= FLAG_BRACE;
456         }
457                  
458         if (flags & FLAG_BRACE)
459           flags &= ~FLAG_BRACE;
460          else {
461             data.Insert ('{', LM_TC_TEX);
462          }
463         break;
464       }
465     case LM_TK_CLOSE:
466       {
467          --brace;        
468          if (brace < 0) {
469             mathPrintError("Unmatching braces");
470             panic = true;
471             break;
472          }
473          if (acc_brace && brace == acc_braces[acc_brace-1]-1) {
474              --acc_brace;
475              break;
476          }
477          if (flags & FLAG_BRACE_FONT) {
478             varcode = LM_TC_VAR;
479             yy_mtextmode = false;
480             flags &= ~FLAG_BRACE_FONT;
481             break;
482          }
483          if (brace == 0 && (flags & FLAG_BRACE_LAST)) {
484             --plevel;
485             return array;
486          } else {
487             data.Insert ('}', LM_TC_TEX);
488          }
489          break;
490       }
491
492     case '[':
493       {
494          if (flags & FLAG_BRACK_ARG) {
495            flags &= ~FLAG_BRACK_ARG;
496            char const rg = LexGetArg('[');
497            if (rg != ']') {
498               mathPrintError("Expected ']'");
499               panic = true;
500               break;
501            }       
502 //         if (arg) strcpy(arg, yytext);
503         } else
504           data.Insert ('[');
505         break;
506       }
507     case ']':
508       {
509           if (flags & FLAG_BRACK_END) {
510               --plevel;
511               return array;
512           } else
513             data.Insert (']');
514         break;
515       }
516
517     case '^':
518       {  
519          MathParInset * p = new MathParInset(size, "", LM_OT_SCRIPT);
520          LyxArrayBase * ar = mathed_parse(FLAG_BRACE_OPT|FLAG_BRACE_LAST, 0);
521          p->SetData(ar);
522 //       lyxerr << "UP[" << p->GetStyle() << "]" << endl;
523          data.Insert (p, LM_TC_UP);
524          break;
525       }
526     case '_':
527       {
528          MathParInset * p = new MathParInset(size, "", LM_OT_SCRIPT);
529          LyxArrayBase * ar = mathed_parse(FLAG_BRACE_OPT|FLAG_BRACE_LAST, 0);
530          p->SetData(ar);
531          data.Insert (p, LM_TC_DOWN);
532          break;
533       }
534
535     case LM_TK_LIMIT:
536       {
537          if (binset) {
538             binset->SetLimits(bool(yylval.l->id));
539             binset = 0;
540          }
541          break;
542       }
543       
544     case '&':    // Tab
545       {
546          if ((flags & FLAG_END) && mt && data.getCol()<mt->GetColumns() - 1) {
547              data.setNumCols(mt->GetColumns());
548              data.Insert('T', LM_TC_TAB);
549          } else 
550             mathPrintError("Unexpected tab");
551          // debug info. [made that conditional -JMarc]
552          if (lyxerr.debugging(Debug::MATHED))
553                  lyxerr << data.getCol() << " " << mt->GetColumns() << endl;
554         break;
555       }
556     case LM_TK_NEWLINE:
557       {
558           if (mt && (flags & FLAG_END)) {
559               if (mt->Permit(LMPF_ALLOW_CR)) {
560                   if (crow) {
561                           crow->setNext(new MathedRowSt(mt->GetColumns() + 1)); // this leaks
562                       crow = crow->getNext();
563                   }
564                   data.Insert('K', LM_TC_CR);
565               } else 
566                 mathPrintError("Unexpected newline");
567           }
568           break;
569       }
570     case LM_TK_BIGSYM:  
571       {
572          binset = new MathBigopInset(yylval.l->name, yylval.l->id);
573          data.Insert(binset);   
574          break;
575       }
576     case LM_TK_SYM:
577       {
578          if (yylval.l->id < 256) {
579             MathedTextCodes tc = MathIsBOPS(yylval.l->id) ? LM_TC_BOPS: LM_TC_SYMB;
580             if (accent) {
581                 data.Insert(doAccent(yylval.l->id, tc));
582             } else
583             data.Insert(yylval.l->id, tc);
584          } else {
585             MathFuncInset * bg = new MathFuncInset(yylval.l->name);
586              if (accent) {
587                      data.Insert(doAccent(bg));
588              } else
589              data.Insert(bg, true);     
590          }
591          break;
592       }
593     case LM_TK_BOP:
594       {
595          if (accent) {
596                  data.Insert(doAccent(yylval.i, LM_TC_BOP));
597           } else
598             data.Insert(yylval.i, LM_TC_BOP);
599          break;
600       }
601     case LM_TK_STY:
602       {
603           if (mt) {
604               mt->UserSetSize(yylval.l->id);
605           }
606           break; 
607       }
608     case LM_TK_SPACE:
609       {
610          if (yylval.i >= 0) {
611             MathSpaceInset * sp = new MathSpaceInset(yylval.i);
612             data.Insert(sp);
613          }
614          break;
615       }    
616     case LM_TK_DOTS:
617       {
618          MathDotsInset * p = new MathDotsInset(yylval.l->name, yylval.l->id);
619          data.Insert(p);
620          break;
621       }
622     case LM_TK_STACK:
623        fractype = LM_OT_STACKREL;
624     case LM_TK_FRAC:
625       {
626          MathFracInset * fc = new MathFracInset(fractype);
627          LyxArrayBase * num = mathed_parse(FLAG_BRACE|FLAG_BRACE_LAST);
628          LyxArrayBase * den = mathed_parse(FLAG_BRACE|FLAG_BRACE_LAST);
629          fc->SetData(num, den);
630          data.Insert(fc, LM_TC_ACTIVE_INSET);
631          break;
632       }
633     case LM_TK_SQRT:
634       {     
635          MathParInset * rt;
636           
637          char c; yyis->get(c);
638           
639          if (c == '[') {
640              rt = new MathRootInset(size);
641              rt->setArgumentIdx(0);
642              rt->SetData(mathed_parse(FLAG_BRACK_END, 0, &rt));
643              rt->setArgumentIdx(1);
644          } else {
645                  yyis->putback(c);
646              rt = new MathSqrtInset(size);
647          }
648          rt->SetData(mathed_parse(FLAG_BRACE|FLAG_BRACE_LAST, 0, &rt));
649          data.Insert(rt, LM_TC_ACTIVE_INSET);
650          break;
651       }
652        
653     case LM_TK_LEFT:
654       {
655          int lfd = yylex();
656          if (lfd == LM_TK_SYM || lfd == LM_TK_STR || lfd == LM_TK_BOP|| lfd == LM_TK_SPECIAL)
657            lfd = (lfd == LM_TK_SYM) ? yylval.l->id: yylval.i;
658 //       lyxerr << "L[" << lfd << " " << lfd << "]";
659          LyxArrayBase * a = mathed_parse(FLAG_RIGHT);
660          int rgd = yylex();
661 //       lyxerr << "R[" << rgd << "]";
662          if (rgd == LM_TK_SYM || rgd == LM_TK_STR || rgd == LM_TK_BOP || rgd == LM_TK_SPECIAL)
663            rgd = (rgd == LM_TK_SYM) ? yylval.l->id: yylval.i;    
664          MathDelimInset * dl = new MathDelimInset(lfd, rgd);
665          dl->SetData(a);
666          data.Insert(dl, LM_TC_ACTIVE_INSET);
667 //       lyxerr << "RL[" << lfd << " " << rgd << "]";
668          break;
669       }
670     case LM_TK_RIGHT:
671       {
672          if (flags & FLAG_RIGHT) { 
673             --plevel;
674             return array;
675          } else {
676             mathPrintError("Unmatched right delimiter");
677 //          panic = true;
678          }
679          break;
680       }
681
682     case LM_TK_FONT:
683       {
684          varcode = static_cast<MathedTextCodes>(yylval.l->id);
685           yy_mtextmode = bool(varcode == LM_TC_TEXTRM);
686          flags |= (FLAG_BRACE|FLAG_BRACE_FONT);
687         break;
688       }
689     case LM_TK_WIDE:
690       {  
691          MathDecorationInset * sq = new MathDecorationInset(yylval.l->id,
692                                                             size);
693          sq->SetData(mathed_parse(FLAG_BRACE|FLAG_BRACE_LAST));
694          data.Insert(sq, LM_TC_ACTIVE_INSET);
695          break;
696       }
697       
698     case LM_TK_ACCENT:
699       setAccent(yylval.l->id);
700       break;
701           
702     case LM_TK_NONUM:
703       {
704           if (crow)
705             crow->setNumbered(false);
706           break;
707       }
708
709     case LM_TK_PMOD:
710     case LM_TK_FUNC:
711       {
712           MathedInset * bg = new MathFuncInset(yylval.l->name); 
713           if (accent) {
714               data.Insert(t);
715           } else
716             data.Insert(bg);
717           break;
718       }
719     case LM_TK_FUNCLIM:
720       {
721          data.Insert(new MathFuncInset(yylval.l->name, LM_OT_FUNCLIM));
722          break;
723       }
724     case LM_TK_UNDEF:
725       {
726           
727        MathMacro * p = 
728          MathMacroTable::mathMTable.getMacro(yylval.s);
729        if (p) {
730            if (accent) 
731              data.Insert(doAccent(p), p->getTCode());
732            else
733              data.Insert(p, p->getTCode());
734            for (int i = 0; p->setArgumentIdx(i); ++i)
735              p->SetData(mathed_parse(FLAG_BRACE|FLAG_BRACE_LAST));
736        }
737        else {
738            MathedInset * q = new MathFuncInset(yylval.s, LM_OT_UNDEF);
739            if (accent) {
740                    data.Insert(doAccent(q));
741            } else {
742                data.Insert(q);
743            }
744        }
745          break;
746       }
747     case LM_TK_END:
748       {
749          if (mathed_env != yylval.i && yylval.i!= LM_EN_ARRAY)
750            mathPrintError("Unmatched environment");
751          // debug info [made that conditional -JMarc]
752          if (lyxerr.debugging(Debug::MATHED))
753                  lyxerr << "[" << yylval.i << "]" << endl;
754          --plevel;
755          if (mt) { // && (flags & FLAG_END)) {
756             mt->SetData(array);
757             array = 0;
758          }
759          return array;
760       }
761     case LM_TK_BEGIN:
762       {
763          if (yylval.i == LM_EN_ARRAY) {
764             char ar[120], ar2[8];
765             ar[0] = ar2[0] = '\0'; 
766             char rg = LexGetArg(0);
767             if (rg == ']') {
768                strcpy(ar2, yytext);
769                rg = LexGetArg('{');
770             }
771             strcpy(ar, yytext);
772             int const nc = parse_align(ar, ar2);
773             MathParInset * mm = new MathMatrixInset(nc, 0);
774             mm->SetAlign(ar2[0], ar);
775             data.Insert(mm, LM_TC_ACTIVE_INSET);
776             mathed_parse(FLAG_END, mm->GetData(), &mm);
777          } else if (yylval.i >= LM_EN_INTEXT && yylval.i<= LM_EN_EQNARRAY) {
778              if (plevel!= 0) {
779                  mathPrintError("Misplaced environment");
780                  break;
781              }
782              if (!mt) {
783                  mathPrintError("0 paragraph.");
784                  panic = true;
785              }
786              
787              mathed_env = yylval.i;
788              if (mathed_env>= LM_EN_DISPLAY) {
789                  size = LM_ST_DISPLAY;
790                  if (mathed_env>LM_EN_EQUATION) {
791                      mt = new MathMatrixInset(3, -1);
792                      mt->SetAlign(' ', "rcl");
793                      if (mtx) *mtx = mt;
794                      flags |= FLAG_END;
795 //                   data.Insert(' ', LM_TC_TAB);
796 //                   data.Insert(' ', LM_TC_TAB);
797 //                   data.Reset();
798                  }
799                  mt->SetStyle(size);
800                  mt->SetType(mathed_env);
801                  crow = mt->getRowSt();
802              }
803                                
804 #ifdef DEBUG
805              lyxerr << "MATH BEGIN[" << mathed_env << "]" << endl;
806 #endif
807          } else {
808 //           lyxerr << "MATHCRO[" << yytext << "]";
809              MathMacro * p = 
810                MathMacroTable::mathMTable.getMacro(yytext);
811              if (p) {
812                  data.Insert(p, p->getTCode());
813                  p->setArgumentIdx(0);
814                  mathed_parse(FLAG_END, p->GetData(), reinterpret_cast<MathParInset**>(&p));
815 //               for (int i = 0; p->setArgumentIdx(i); ++i)
816 //                 p->SetData(mathed_parse(FLAG_BRACE|FLAG_BRACE_LAST));
817              } else 
818                mathPrintError("Unrecognized environment");
819          }
820          break;
821       }
822        
823     case LM_TK_MACRO:
824      { 
825           MathedInset * p = 
826             MathMacroTable::mathMTable.getMacro(yylval.l->name);
827          
828           if (p) {
829               if (accent) {
830                 data.Insert(doAccent(p));
831               } else
832                 data.Insert(p, static_cast<MathMacro*>(p)->getTCode());
833           }
834           break;
835       }
836        
837      case LM_TK_LABEL:
838        {           
839           char const rg = LexGetArg('\0', true);
840           if (rg != '}') {
841              mathPrintError("Expected '{'");
842               // debug info
843              lyxerr << "[" << yytext << "]" << endl;
844               panic = true;
845              break;
846           } 
847           if (crow) {
848               crow->setLabel(yytext);
849           } else {
850                   mathed_label = yytext;
851           }
852 #ifdef DEBUG
853           lyxerr << "Label[" << mathed_label << "]" << endl;
854 #endif
855           break;
856         } 
857      default:
858        mathPrintError("Unrecognized token");
859        // debug info
860        lyxerr << "[" << t << " " << yytext << "]" << endl;
861        break;
862     }
863     tprev = t;
864     if (panic) {
865             lyxerr << " Math Panic, expect problems!" << endl;
866        //   Search for the end command. 
867        do {
868                t = yylex ();
869        } while (t != LM_TK_END && t);
870     } else
871      t = yylex ();
872    
873    if ((flags & FLAG_BRACE_OPT)/* && t!= '^' && t!= '_'*/) {
874         flags &= ~FLAG_BRACE_OPT;
875        //data.Insert (LM_TC_CLOSE);
876        break;
877     }
878    }
879    --plevel;
880    return array;
881 }
882
883
884 void mathed_parser_file(istream & is, int lineno)
885 {
886     yyis = &is;
887     yylineno = lineno;
888     if (!MathMacroTable::built)
889         MathMacroTable::mathMTable.builtinMacros();
890 }
891
892
893 int mathed_parser_lineno()
894 {
895     return yylineno;
896 }
897