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