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