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