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