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