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