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