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