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