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