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