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