]> git.lyx.org Git - lyx.git/blob - src/mathed/math_parser.C
small cleanup, doxygen, formatting changes
[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 MathedArray * mathed_parse(unsigned flags = 0, MathedArray * array = 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    if (!array) array = new MathedArray;
428    MathedIter data(array);
429    while (t) {
430       if ((flags & FLAG_BRACE) && t != LM_TK_OPEN) {
431          if ((flags & FLAG_BRACK_ARG) && t == '[') {
432          }
433          else {
434              mathPrintError("Expected {. Maybe you forgot to enclose an argument in {}");
435             panic = true;
436             break;
437          }
438       }
439     MathedInsetTypes fractype = LM_OT_FRAC;
440     switch (t) {
441     case LM_TK_ALPHA:
442       {
443          if (accent) {
444              data.Insert(doAccent(yylval.i, varcode));
445          } else
446             data.Insert (yylval.i, varcode);  //LM_TC_VAR);
447          break;
448       }
449     case LM_TK_ARGUMENT:
450       {
451           if (macro) {
452               data.Insert(macro->getMacroPar(yylval.i-1), LM_TC_INSET);
453           } 
454           break;
455       } 
456     case LM_TK_NEWCOMMAND:
457       {
458           int na = 0; 
459
460           LexGetArg('{');
461           string const name(&yytext[1]);
462           
463           // ugly trick to be removed soon (lyx3)
464           char const c = yyis->peek();
465           if (c == '[') {
466               LexGetArg('[');
467               na = lyx::atoi(yytext.data());
468           }  
469           macro = new MathMacroTemplate(name, na);
470           flags = FLAG_BRACE|FLAG_BRACE_LAST;
471           *mtx = macro;
472           macro->setData(array);
473           break;
474       }
475     case LM_TK_SPECIAL:
476       {   
477           data.Insert (yylval.i, LM_TC_SPECIAL);
478           break;
479       }
480     case LM_TK_STR:
481       {   
482           if (accent) {
483             data.Insert(doAccent(yylval.i, LM_TC_CONST));
484           } else
485             data.Insert (yylval.i, LM_TC_CONST);
486           break;
487       }
488     case LM_TK_OPEN:
489       {
490         ++brace;
491         if  (accent && tprev == LM_TK_ACCENT) {
492             acc_braces[acc_brace++] = brace;
493             break;
494         }
495         if (flags & FLAG_BRACE_OPT) {
496            flags &= ~FLAG_BRACE_OPT;
497            flags |= FLAG_BRACE;
498         }
499                  
500         if (flags & FLAG_BRACE)
501           flags &= ~FLAG_BRACE;
502          else {
503             data.Insert ('{', LM_TC_TEX);
504          }
505         break;
506       }
507     case LM_TK_CLOSE:
508       {
509          --brace;        
510          if (brace < 0) {
511             mathPrintError("Unmatching braces");
512             panic = true;
513             break;
514          }
515          if (acc_brace && brace == acc_braces[acc_brace-1]-1) {
516              --acc_brace;
517              break;
518          }
519          if (flags & FLAG_BRACE_FONT) {
520             varcode = LM_TC_VAR;
521             yy_mtextmode = false;
522             flags &= ~FLAG_BRACE_FONT;
523             break;
524          }
525          if (brace == 0 && (flags & FLAG_BRACE_LAST)) {
526             --plevel;
527             return array;
528          } else {
529             data.Insert ('}', LM_TC_TEX);
530          }
531          break;
532       }
533
534     case '[':
535       {
536          if (flags & FLAG_BRACK_ARG) {
537            flags &= ~FLAG_BRACK_ARG;
538            char const rg = LexGetArg('[');
539            if (rg != ']') {
540               mathPrintError("Expected ']'");
541               panic = true;
542               break;
543            }       
544 //         if (arg) strcpy(arg, yytext);
545         } else
546           data.Insert ('[');
547         break;
548       }
549     case ']':
550       {
551           if (flags & FLAG_BRACK_END) {
552               --plevel;
553               return array;
554           } else
555             data.Insert (']');
556         break;
557       }
558
559     case '^':
560       {  
561          MathParInset * p = new MathParInset(size, "", LM_OT_SCRIPT);
562          MathedArray * ar = mathed_parse(FLAG_BRACE_OPT|FLAG_BRACE_LAST, 0);
563          p->setData(ar);
564 //       lyxerr << "UP[" << p->GetStyle() << "]" << endl;
565          data.Insert (p, LM_TC_UP);
566          break;
567       }
568     case '_':
569       {
570          MathParInset * p = new MathParInset(size, "", LM_OT_SCRIPT);
571          MathedArray * ar = mathed_parse(FLAG_BRACE_OPT|FLAG_BRACE_LAST, 0);
572          p->setData(ar);
573          data.Insert (p, LM_TC_DOWN);
574          break;
575       }
576
577     case LM_TK_LIMIT:
578       {
579          if (binset) {
580             binset->SetLimits(bool(yylval.l->id));
581             binset = 0;
582          }
583          break;
584       }
585       
586     case '&':    // Tab
587       {
588          if ((flags & FLAG_END) && mt && data.getCol()<mt->GetColumns() - 1) {
589              data.setNumCols(mt->GetColumns());
590              data.Insert('T', LM_TC_TAB);
591          } else 
592             mathPrintError("Unexpected tab");
593          // debug info. [made that conditional -JMarc]
594          if (lyxerr.debugging(Debug::MATHED))
595                  lyxerr << data.getCol() << " " << mt->GetColumns() << endl;
596         break;
597       }
598     case LM_TK_NEWLINE:
599       {
600           if (mt && (flags & FLAG_END)) {
601               if (mt->Permit(LMPF_ALLOW_CR)) {
602                   if (crow) {
603                           crow->setNext(new MathedRowSt(mt->GetColumns() + 1)); // this leaks
604                       crow = crow->getNext();
605                   }
606                   data.Insert('K', LM_TC_CR);
607               } else 
608                 mathPrintError("Unexpected newline");
609           }
610           break;
611       }
612     case LM_TK_BIGSYM:  
613       {
614          binset = new MathBigopInset(yylval.l->name, yylval.l->id);
615          data.Insert(binset);   
616          break;
617       }
618     case LM_TK_SYM:
619       {
620          if (yylval.l->id < 256) {
621             MathedTextCodes tc = MathIsBOPS(yylval.l->id) ? LM_TC_BOPS: LM_TC_SYMB;
622             if (accent) {
623                 data.Insert(doAccent(yylval.l->id, tc));
624             } else
625             data.Insert(yylval.l->id, tc);
626          } else {
627             MathFuncInset * bg = new MathFuncInset(yylval.l->name);
628              if (accent) {
629                      data.Insert(doAccent(bg));
630              } else
631              data.Insert(bg, true);     
632          }
633          break;
634       }
635     case LM_TK_BOP:
636       {
637          if (accent) {
638                  data.Insert(doAccent(yylval.i, LM_TC_BOP));
639           } else
640             data.Insert(yylval.i, LM_TC_BOP);
641          break;
642       }
643     case LM_TK_STY:
644       {
645           if (mt) {
646               mt->UserSetSize(yylval.l->id);
647           }
648           break; 
649       }
650     case LM_TK_SPACE:
651       {
652          if (yylval.i >= 0) {
653             MathSpaceInset * sp = new MathSpaceInset(yylval.i);
654             data.Insert(sp);
655          }
656          break;
657       }    
658     case LM_TK_DOTS:
659       {
660          MathDotsInset * p = new MathDotsInset(yylval.l->name, yylval.l->id);
661          data.Insert(p);
662          break;
663       }
664     case LM_TK_STACK:
665        fractype = LM_OT_STACKREL;
666     case LM_TK_FRAC:
667       {
668          MathFracInset * fc = new MathFracInset(fractype);
669          MathedArray * num = mathed_parse(FLAG_BRACE|FLAG_BRACE_LAST);
670          MathedArray * den = mathed_parse(FLAG_BRACE|FLAG_BRACE_LAST);
671          fc->SetData(num, den);
672          data.Insert(fc, LM_TC_ACTIVE_INSET);
673          break;
674       }
675     case LM_TK_SQRT:
676       {     
677          MathParInset * rt;
678           
679          char c; yyis->get(c);
680           
681          if (c == '[') {
682              rt = new MathRootInset(size);
683              rt->setArgumentIdx(0);
684              rt->setData(mathed_parse(FLAG_BRACK_END, 0, &rt));
685              rt->setArgumentIdx(1);
686          } else {
687                  yyis->putback(c);
688              rt = new MathSqrtInset(size);
689          }
690          rt->setData(mathed_parse(FLAG_BRACE|FLAG_BRACE_LAST, 0, &rt));
691          data.Insert(rt, LM_TC_ACTIVE_INSET);
692          break;
693       }
694        
695     case LM_TK_LEFT:
696       {
697          int lfd = yylex();
698          if (lfd == LM_TK_SYM || lfd == LM_TK_STR || lfd == LM_TK_BOP|| lfd == LM_TK_SPECIAL)
699            lfd = (lfd == LM_TK_SYM) ? yylval.l->id: yylval.i;
700 //       lyxerr << "L[" << lfd << " " << lfd << "]";
701          MathedArray * a = mathed_parse(FLAG_RIGHT);
702          int rgd = yylex();
703 //       lyxerr << "R[" << rgd << "]";
704          if (rgd == LM_TK_SYM || rgd == LM_TK_STR || rgd == LM_TK_BOP || rgd == LM_TK_SPECIAL)
705            rgd = (rgd == LM_TK_SYM) ? yylval.l->id: yylval.i;    
706          MathDelimInset * dl = new MathDelimInset(lfd, rgd);
707          dl->setData(a);
708          data.Insert(dl, LM_TC_ACTIVE_INSET);
709 //       lyxerr << "RL[" << lfd << " " << rgd << "]";
710          break;
711       }
712     case LM_TK_RIGHT:
713       {
714          if (flags & FLAG_RIGHT) { 
715             --plevel;
716             return array;
717          } else {
718             mathPrintError("Unmatched right delimiter");
719 //          panic = true;
720          }
721          break;
722       }
723
724     case LM_TK_FONT:
725       {
726          varcode = static_cast<MathedTextCodes>(yylval.l->id);
727           yy_mtextmode = bool(varcode == LM_TC_TEXTRM);
728          flags |= (FLAG_BRACE|FLAG_BRACE_FONT);
729         break;
730       }
731     case LM_TK_WIDE:
732       {  
733          MathDecorationInset * sq = new MathDecorationInset(yylval.l->id,
734                                                             size);
735          sq->setData(mathed_parse(FLAG_BRACE|FLAG_BRACE_LAST));
736          data.Insert(sq, LM_TC_ACTIVE_INSET);
737          break;
738       }
739       
740     case LM_TK_ACCENT:
741       setAccent(yylval.l->id);
742       break;
743           
744     case LM_TK_NONUM:
745       {
746           if (crow)
747             crow->setNumbered(false);
748           break;
749       }
750
751     case LM_TK_PMOD:
752     case LM_TK_FUNC:
753       {
754           MathedInset * bg = new MathFuncInset(yylval.l->name); 
755           if (accent) {
756               data.Insert(t);
757           } else
758             data.Insert(bg);
759           break;
760       }
761     case LM_TK_FUNCLIM:
762       {
763          data.Insert(new MathFuncInset(yylval.l->name, LM_OT_FUNCLIM));
764          break;
765       }
766     case LM_TK_UNDEF:
767       {
768           
769        MathMacro * p = 
770          MathMacroTable::mathMTable.getMacro(yylval.s);
771        if (p) {
772            if (accent) 
773              data.Insert(doAccent(p), p->getTCode());
774            else
775              data.Insert(p, p->getTCode());
776            for (int i = 0; p->setArgumentIdx(i); ++i)
777              p->setData(mathed_parse(FLAG_BRACE|FLAG_BRACE_LAST));
778        }
779        else {
780            MathedInset * q = new MathFuncInset(yylval.s, LM_OT_UNDEF);
781            if (accent) {
782                    data.Insert(doAccent(q));
783            } else {
784                data.Insert(q);
785            }
786        }
787          break;
788       }
789     case LM_TK_END:
790       {
791          if (mathed_env != yylval.i && yylval.i != LM_OT_MATRIX)
792            mathPrintError("Unmatched environment");
793          // debug info [made that conditional -JMarc]
794          if (lyxerr.debugging(Debug::MATHED))
795                  lyxerr << "[" << yylval.i << "]" << endl;
796          --plevel;
797          if (mt) { // && (flags & FLAG_END)) {
798             mt->setData(array);
799             array = 0;
800          }
801          return array;
802       }
803     case LM_TK_BEGIN:
804       {
805          if (yylval.i == LM_OT_MATRIX) {
806             char ar[120], ar2[8];
807             ar[0] = ar2[0] = '\0'; 
808             char rg = LexGetArg(0);
809             if (rg == ']') {
810                strcpy(ar2, yytext.data());
811                rg = LexGetArg('{');
812             }
813             strcpy(ar, yytext.data());
814             int const nc = parse_align(ar, ar2);
815             MathParInset * mm = new MathMatrixInset(nc, 0);
816             mm->SetAlign(ar2[0], ar);
817             data.Insert(mm, LM_TC_ACTIVE_INSET);
818             mathed_parse(FLAG_END, mm->GetData(), &mm);
819          } else if (is_eqn_type(yylval.i)) {
820              if (plevel!= 0) {
821                  mathPrintError("Misplaced environment");
822                  break;
823              }
824              if (!mt) {
825                  mathPrintError("0 paragraph.");
826                  panic = true;
827              }
828              
829              mathed_env = static_cast<MathedInsetTypes>(yylval.i);
830              if (mathed_env != LM_OT_MIN) {
831                  size = LM_ST_DISPLAY;
832                  if (is_multiline(mathed_env)) {
833                      int cols = 1;
834                      if (is_multicolumn(mathed_env)) {
835                          if (mathed_env != LM_OT_ALIGNAT &&
836                              mathed_env != LM_OT_ALIGNATN &&
837                              yyis->good()) {
838                              char c;
839                              yyis->get(c);
840                              if (c != '%')
841                                      lyxerr << "Math parse error: unexpected '"
842                                             << c << "'" << endl;
843                          }
844                          LexGetArg('{');
845                          cols = strToInt(string(yytext.data()));
846                      }
847                      mt = create_multiline(mathed_env, cols);
848                      if (mtx) *mtx = mt;
849                      flags |= FLAG_END;
850 //                   data.Insert(' ', LM_TC_TAB);
851 //                   data.Insert(' ', LM_TC_TAB);
852 //                   data.Reset();
853                  }
854                  mt->SetStyle(size);
855                  mt->SetType(mathed_env);
856                  crow = mt->getRowSt();
857              }
858
859 #ifdef DEBUG
860              lyxerr << "MATH BEGIN[" << mathed_env << "]" << endl;
861 #endif
862          } else {
863 //           lyxerr << "MATHCRO[" << yytext << "]";
864              MathMacro * p = 
865                MathMacroTable::mathMTable.getMacro(yytext.data());
866              if (p) {
867                  data.Insert(p, p->getTCode());
868                  p->setArgumentIdx(0);
869                  mathed_parse(FLAG_END, p->GetData(), reinterpret_cast<MathParInset**>(&p));
870 //               for (int i = 0; p->setArgumentIdx(i); ++i)
871 //                 p->SetData(mathed_parse(FLAG_BRACE|FLAG_BRACE_LAST));
872              } else 
873                mathPrintError("Unrecognized environment");
874          }
875          break;
876       }
877        
878     case LM_TK_MACRO:
879      { 
880           MathedInset * p = 
881             MathMacroTable::mathMTable.getMacro(yylval.l->name);
882          
883           if (p) {
884               if (accent) {
885                 data.Insert(doAccent(p));
886               } else
887                 data.Insert(p, static_cast<MathMacro*>(p)->getTCode());
888           }
889           break;
890       }
891        
892      case LM_TK_LABEL:
893        {           
894           char const rg = LexGetArg('\0', true);
895           if (rg != '}') {
896              mathPrintError("Expected '{'");
897               // debug info
898              lyxerr << "[" << yytext.data() << "]" << endl;
899               panic = true;
900              break;
901           } 
902           if (crow) {
903               crow->setLabel(yytext.data());
904           } else {
905                   mathed_label = yytext.data();
906           }
907 #ifdef DEBUG
908           lyxerr << "Label[" << mathed_label << "]" << endl;
909 #endif
910           break;
911         } 
912      default:
913        mathPrintError("Unrecognized token");
914        // debug info
915        lyxerr << "[" << t << " " << yytext.data() << "]" << endl;
916        break;
917     }
918     tprev = t;
919     if (panic) {
920             lyxerr << " Math Panic, expect problems!" << endl;
921        //   Search for the end command. 
922        do {
923                t = yylex ();
924        } while (t != LM_TK_END && t);
925     } else
926      t = yylex ();
927    
928    if ((flags & FLAG_BRACE_OPT)/* && t!= '^' && t!= '_'*/) {
929         flags &= ~FLAG_BRACE_OPT;
930        //data.Insert (LM_TC_CLOSE);
931        break;
932     }
933    }
934    --plevel;
935    return array;
936 }
937
938
939 void mathed_parser_file(istream & is, int lineno)
940 {
941     yyis = &is;
942     yylineno = lineno;
943     if (!MathMacroTable::built)
944         MathMacroTable::mathMTable.builtinMacros();
945 }
946
947
948 int mathed_parser_lineno()
949 {
950     return yylineno;
951 }
952