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