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