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