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