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