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